Skip to content

chore: use caret constraints for internal package dependencies - #1717

Open
spydon wants to merge 1 commit into
mainfrom
chore/caret-internal-deps
Open

chore: use caret constraints for internal package dependencies#1717
spydon wants to merge 1 commit into
mainfrom
chore/caret-internal-deps

Conversation

@spydon

@spydon spydon commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What

Every internal package dependency in this repo now uses a caret constraint instead of an exact pin.

Package Dependencies changed
supabase functions_client, postgrest, realtime_client, storage_client, supabase_auth, supabase_common, yet_another_json_isolate
supabase_flutter supabase, supabase_common
functions_client supabase_common, yet_another_json_isolate
postgrest yet_another_json_isolate, supabase_common
supabase_auth supabase_common
storage_client supabase_common
realtime_client supabase_common

Why

Exact pins meant a patch release of any leaf package required republishing every package above it in the tree just to let users pick the fix up. With carets, a patch or minor release of an internal package flows through to consumers without a coordinated bump across the workspace.

Notes

  • supabase_common: ^0.1.2 resolves to >=0.1.2 <0.2.0 under pub's pre-1.0 caret rules, so a 0.2.0 release still requires bumping dependents. That is the standard convention for a pre-1.0 package.
  • supabase_auth: ^3.0.0-dev.1 resolves to >=3.0.0-dev.1 <4.0.0, which admits later dev prereleases and the eventual stable 3.0.0.
  • supabase_lints dev dependencies and the example apps already used carets, so they are untouched.

Testing

dart pub get resolves the workspace cleanly.

Internal packages were pinned to exact versions, which forced every
dependent to be republished for any patch release. Use caret constraints
so patch and minor releases of an internal package flow through without
a coordinated bump.
@spydon
spydon requested a review from a team as a code owner August 14, 2026 13:26
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@spydon, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 4 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6429b044-aa6b-41eb-83dd-fb724e4b06f1

📥 Commits

Reviewing files that changed from the base of the PR and between 29286f4 and f5efed0.

📒 Files selected for processing (7)
  • packages/functions_client/pubspec.yaml
  • packages/postgrest/pubspec.yaml
  • packages/realtime_client/pubspec.yaml
  • packages/storage_client/pubspec.yaml
  • packages/supabase/pubspec.yaml
  • packages/supabase_auth/pubspec.yaml
  • packages/supabase_flutter/pubspec.yaml

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@grdsdev grdsdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discourage this in the SDKs for the reason that when someone opens a support ticket with the supabase-flutter version, we can't know which sub package version they have if ^ is used.

@spydon

spydon commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

We discourage this in the SDKs for the reason that when someone opens a support ticket with the supabase-flutter version, we can't know which sub package version they have if ^ is used.

That is seen as extremely bad practice in the Dart ecosystem (I'm pretty sure that's the case in other ecosystems too), because if you use community libraries that use our packages together then you won't be able to resolve the the dependencies without everything being pinned to the same version or using pubspec_overrides.

If there is an issue opened where this is unclear (usually quite uncommon) we usually just ask for the lockfile, and we'll get all information that we need.

EDIT: Here is the best practices link for Dart: https://dart.dev/tools/pub/dependencies#use-caret-syntax

@spydon

spydon commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@grdsdev Furthermore, that leads to that we always have to release all packages, even if a fix only is needed in one package. Like in this case where we only would have had to release gotrue.

spydon added a commit that referenced this pull request Aug 14, 2026
## What

Hotfix for the `gotrue` 2.27.x line, backporting the Wasm
`Session.fromJson` crash fix from #1716.

The base is `release/gotrue-2.27.x`, a maintenance branch cut at the
`gotrue-v2.27.1` tag. It cannot target `main`, because `main` has since
renamed the package to `supabase_auth` (#1697) and renamed the public
API (#1712), so a PR against `main` would read as reverting everything
merged since the tag.

Resolves #1687 for the 2.x line.

## The bug

`Session.fromJson` cast `json['expires_in']` straight to `int?`. That
map does not always come from `jsonDecode`.
`GoTrueClient._mayStartBroadcastChannel` also feeds it payloads that
crossed the JavaScript interop boundary through `dartify()` in
`broadcast_web.dart`, where every JavaScript number arrives as a
`double`.

Under `dart2js` this was invisible, because Dart `int` and `double`
share a JavaScript `Number` at runtime, so `3600.0 as int?` succeeded.
Under `dart2wasm` they are distinct runtime types and the cast throws:

```
TypeError: type 'double' is not a subtype of type 'int?' in type cast
```

The `json.decode(json.encode(dataMap))` round trip in
`broadcast_web.dart` does not rescue this: `3600.0` encodes to
`"3600.0"` and decodes back to a `double`.

Because the throw happened inside the `BroadcastChannel` message
listener, outside the setup `try`/`catch`, the rest of the listener was
skipped. No `_saveSession` or `_removeSession` ran, and
`notifyAllSubscribers` never fired, so receiving tabs silently failed to
synchronize login, logout, and token refresh.

## The fix

`expires_in` is now parsed as `(json['expires_in'] as num?)?.toInt()`,
which accepts `int`, `double`, and `null`. `JwtPayload.fromJson` (`exp`,
`nbf`, `iat`) and `OAuthClientListResponse.fromJson` (`nextPage`,
`lastPage`, `total`) get the same treatment for their numeric fields.

I traced the rest of the reachable surface. `dartify()` is called in
exactly one place in the repository, and the only types built from that
data are `Session`, `User`, `UserIdentity`, and `Factor`.
`User.fromJson` has no numeric fields, its timestamps are ISO 8601
strings, so after this change nothing reachable from the interop
boundary casts to `int`. Everything else in the workspace decodes from a
string through `dart:convert`, where integer literals stay `int` on
every backend.

## Pipeline fixes

The tag this branch is frozen at no longer builds against the current
toolchain, so the second commit carries three unrelated fixes needed to
get a green run. All three were verified to be pre-existing drift rather
than fallout from this change, by comparing against #1717, an equivalent
change on `main` whose run passed minutes apart.

- Flutter stable now ships AGP 9, which rejects the example app's old
Gradle DSL. The example's Gradle configuration is ported from `main`
(AGP 8.13.1 to 9.1.0, Gradle 8.13 to 9.3.1, Kotlin 2.1.20 to 2.4.0). The
example is `publish_to: none`, so nothing published changes.
- `dart analyze --fatal-infos` now reports `use_super_parameters` on
`SupabaseStorageClient`. `main` resolved this as part of the fetch layer
refactor in #1647, which gave `StorageBucketApi` a stored client field.
At this tag the superclass stores nothing, so the local field is still
needed and the lint is suppressed instead of backporting that refactor.
- The compliance workflow validates against `supabase/sdk@main`, whose
canonical capability identifiers keep moving, so a branch frozen at an
old release can never satisfy them. Its `pull_request` trigger is now
scoped to pull requests that target `main`.

## Release notes

`melos version` on this branch proposes `gotrue` 2.27.2, plus `supabase`
2.16.1 and `supabase_flutter` 2.17.2 as dependency cascades. Those
cascades are required, not incidental: the published `supabase` 2.16.0
pins `gotrue: 2.27.1` exactly and `supabase_flutter` 2.17.1 pins
`supabase: 2.16.0` exactly, so publishing `gotrue` alone would reach
nobody using the higher level packages.

Note that `release-tag.yml` only triggers on pushes to `main`, so
merging the version pull request into this maintenance branch will not
create the tags. They need to be pushed manually, or that workflow needs
a `workflow_dispatch` trigger, before `release-publish.yml` can run
against `gotrue-v2.27.2`.

## Testing

- `dart pub get` resolves the workspace cleanly.
- `dart analyze lib test` in `packages/gotrue`: no issues.
- `dart analyze --fatal-infos packages/storage_client`: no issues.
- `dart test test/src/types/session_test.dart
test/src/helper_test.dart`: 57 passing, including two new tests covering
a `double` `expires_in` and `double` `exp`, `nbf`, and `iat`.
- `dart format`: clean.
- The Android build is verified by CI only, it was not built locally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants