chore: use caret constraints for internal package dependencies - #1717
chore: use caret constraints for internal package dependencies#1717spydon wants to merge 1 commit into
Conversation
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.
|
Warning Review limit reached
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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
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. Comment |
grdsdev
left a comment
There was a problem hiding this comment.
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 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 |
|
@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. |
## 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.
What
Every internal package dependency in this repo now uses a caret constraint instead of an exact pin.
supabasefunctions_client,postgrest,realtime_client,storage_client,supabase_auth,supabase_common,yet_another_json_isolatesupabase_fluttersupabase,supabase_commonfunctions_clientsupabase_common,yet_another_json_isolatepostgrestyet_another_json_isolate,supabase_commonsupabase_authsupabase_commonstorage_clientsupabase_commonrealtime_clientsupabase_commonWhy
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.2resolves to>=0.1.2 <0.2.0under pub's pre-1.0 caret rules, so a0.2.0release still requires bumping dependents. That is the standard convention for a pre-1.0 package.supabase_auth: ^3.0.0-dev.1resolves to>=3.0.0-dev.1 <4.0.0, which admits later dev prereleases and the eventual stable3.0.0.supabase_lintsdev dependencies and the example apps already used carets, so they are untouched.Testing
dart pub getresolves the workspace cleanly.