Version Packages - #28
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
11 times, most recently
from
June 20, 2026 01:13
67dcf90 to
1dccb2c
Compare
2bTwist
added a commit
that referenced
this pull request
Jun 20, 2026
From the 2026-06-20 repo snapshot's drift report: - changeset: migrate stamps 'migratedFrom' not '_migratedFrom' (pre-#34 name) would ship a self-contradictory CHANGELOG when PR #28 merges. - supabase migration: 'notes' table gains created_at, so list() on it no longer fails at runtime under the default timestampColumn. - adapter-supabase README: drop the stale 'filtered watches not yet supported' (they ship + are tested) and the hardcoded '15/15' count. - adapter-convex README: drop the 'in progress / client adapter lands next' status; the client adapter shipped. - demo: Supabase 'open table' link no longer hardcodes a table OID that a fresh supabase start reassigns. - add @baas/migrate to the README status table + packages list, CONTRIBUTING workspace layout (also adds adapter-convex), RELEASING publishable packages, and typedoc entryPoints.
github-actions
Bot
force-pushed
the
changeset-release/main
branch
15 times, most recently
from
June 20, 2026 21:37
8db5515 to
757844d
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
June 20, 2026 21:42
757844d to
a784516
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@baas/adapter-convex@0.1.0
Minor Changes
b0ddc5c: Add the client-side Convex adapter (the
.entry):createConvexBackend/convexAdapterwithConvexDocumentStore(named ops via FunctionReferences,direct CRUD + reactive
subscribevia the deployed helpers),ConvexAuth(verify-only,
managesCredentials: false,forceRefreshTokenadapted), andConvexFileStore(the upload-URL-then-POST dance). Passes the full conformancesuite against a live deployment. The deployable helpers now normalize Convex's
throw-on-missing/foreign-id into the portable contract (idempotent
remove,not_foundpatch,nullget).6079e6e: Add
@baas/adapter-convexwith its deployable server helpers (the./convexentry): schemaless, table-name-first CRUD (
insert/get/list/patch/remove), file storage (generateUploadUrl/getFileUrl/deleteFile), and anauth
whoami, built on Convex's genericqueryGeneric/mutationGenericbuilders so they ship from npm with no codegen dependency. Proven hermetically
with
convex-test. The client-side adapter follows.e3abea8: Extend
listwith theinoperator and field ordering.inoperator:where: [["status", "in", ["open", "pending"]]]. Maps toSupabase
.in(), memoryArray.includes, and an OR-of-eq expansion on Convex(which has no native
in).WhereConditionis now a discriminated tuple union(
intakes an array; the other six operators take a scalar).orderaccepts{ field, direction }in addition to thebare
"asc"/"desc"creation-order shorthand. Supabase and memory order by anyfield directly (keyset on
(field, pk)). On Convex, field ordering uses aby_<field>index; ordering by an unindexed field returns anunsupported_capabilityerror rather than silently falling back to creationorder. Page size still defaults to 50, clamped to 200.
8d97270: Add a portable
listprimitive toDocumentStore: cursor-paginated,creation-ordered listing with a small filter set.
store.list(collection, { where, order, limit, cursor })returns{ items, nextCursor }, where each item carries aportable
_id. Filters use six comparison operators (eq/neq/gt/gte/lt/lte,AND-combined); ordering is creation-order direction only (
asc/desc); paginationis keyset/cursor (never offset). Implemented identically across memory, Supabase
(keyset on a configurable
timestampColumn, defaultcreated_at), and Convex(
.paginate()over the deployed helper), and asserted by the conformance suite.Contract note: loop until
nextCursorisnull; a non-null cursor may yield anempty trailing page on a scan-based backend (Convex with a filter). Arbitrary-field
sorting,
in/text/array operators, joins, and aggregation remain out of scope vianative().Patch Changes
@baas/adapter-memory@0.1.0
Minor Changes
f59ded2: Initial port layer (
@baas/core) and in-memory reference adapter(
@baas/adapter-memory), validated against the parameterized conformance suite.e3abea8: Extend
listwith theinoperator and field ordering.inoperator:where: [["status", "in", ["open", "pending"]]]. Maps toSupabase
.in(), memoryArray.includes, and an OR-of-eq expansion on Convex(which has no native
in).WhereConditionis now a discriminated tuple union(
intakes an array; the other six operators take a scalar).orderaccepts{ field, direction }in addition to thebare
"asc"/"desc"creation-order shorthand. Supabase and memory order by anyfield directly (keyset on
(field, pk)). On Convex, field ordering uses aby_<field>index; ordering by an unindexed field returns anunsupported_capabilityerror rather than silently falling back to creationorder. Page size still defaults to 50, clamped to 200.
8d97270: Add a portable
listprimitive toDocumentStore: cursor-paginated,creation-ordered listing with a small filter set.
store.list(collection, { where, order, limit, cursor })returns{ items, nextCursor }, where each item carries aportable
_id. Filters use six comparison operators (eq/neq/gt/gte/lt/lte,AND-combined); ordering is creation-order direction only (
asc/desc); paginationis keyset/cursor (never offset). Implemented identically across memory, Supabase
(keyset on a configurable
timestampColumn, defaultcreated_at), and Convex(
.paginate()over the deployed helper), and asserted by the conformance suite.Contract note: loop until
nextCursorisnull; a non-null cursor may yield anempty trailing page on a scan-based backend (Convex with a filter). Arbitrary-field
sorting,
in/text/array operators, joins, and aggregation remain out of scope vianative().Patch Changes
remove()of a non-existent id is now idempotent (returnsok) instead of erroring, establishing the portable contract the conformance suite enforces.remove()reaches a desired end state, so a redundant remove succeeds;patch()still requires an existing document and reportsnot_found.@baas/adapter-supabase@0.1.0
Minor Changes
e3abea8: Extend
listwith theinoperator and field ordering.inoperator:where: [["status", "in", ["open", "pending"]]]. Maps toSupabase
.in(), memoryArray.includes, and an OR-of-eq expansion on Convex(which has no native
in).WhereConditionis now a discriminated tuple union(
intakes an array; the other six operators take a scalar).orderaccepts{ field, direction }in addition to thebare
"asc"/"desc"creation-order shorthand. Supabase and memory order by anyfield directly (keyset on
(field, pk)). On Convex, field ordering uses aby_<field>index; ordering by an unindexed field returns anunsupported_capabilityerror rather than silently falling back to creationorder. Page size still defaults to 50, clamped to 200.
8d97270: Add a portable
listprimitive toDocumentStore: cursor-paginated,creation-ordered listing with a small filter set.
store.list(collection, { where, order, limit, cursor })returns{ items, nextCursor }, where each item carries aportable
_id. Filters use six comparison operators (eq/neq/gt/gte/lt/lte,AND-combined); ordering is creation-order direction only (
asc/desc); paginationis keyset/cursor (never offset). Implemented identically across memory, Supabase
(keyset on a configurable
timestampColumn, defaultcreated_at), and Convex(
.paginate()over the deployed helper), and asserted by the conformance suite.Contract note: loop until
nextCursorisnull; a non-null cursor may yield anempty trailing page on a scan-based backend (Convex with a filter). Arbitrary-field
sorting,
in/text/array operators, joins, and aggregation remain out of scope vianative().f59ded2: Add the Supabase adapter (PostgREST document store, Supabase Auth credential
management, Supabase Storage), passing the conformance suite 15/15 against a live
local stack.
c33fc22: Realtime watches can now be filtered. A
realtimewatch entry accepts{ table, filter }(a Supabase Realtime filter string like"room_id=eq.42")in place of a bare table name, narrowing the subscription to matching rows to cut
fan-out on high-write tables. Bare table names still watch the whole table (the
safe default). Filters are unsafe for columns whose value changes after insert (a
row leaving the filtered set fires no event), so they are opt-in and documented
for append-mostly tables.
81039a5: Add opt-in live
subscribe()via arealtimewatch map. Declaringrealtime: { <query>: { tables: [...] } }flipsreactiveQuerieson and makessubscribe()deliver live updates: a change to a watched table re-runs the queryand delivers the full fresh result (the same shape Convex delivers), coalesced
over a short debounce. Channel failures and subscribing to a query with no
declared watch surface as loud error
Results rather than silently degrading toone-shot. Requires the watched tables in the
supabase_realtimepublication. Thedefault (no
realtimeconfig) is unchanged:reactiveQueries: false, one-shot.Patch Changes
patch()of a non-existent id now returnserr(not_found)instead of silently succeeding, matching the portable conformance contract. PostgREST reports no error for an update that affects 0 rows, so the adapter now adds.select(pk)and treats an empty result asnot_found.remove()remains an idempotent no-op. (Caveat: under RLS, an update permitted but a select denied would also surface asnot_found.)surfaces as the same
ErrorCodeit does on the other adapters. Notably42501(insufficient_privilege, the SQLSTATE an RLS denial reaches the client as) now maps
to
unauthorizedinstead of falling through tounknown; also23503(foreign_key_violation) ->
conflict, and23502/23514/22P02(not_null / check / invalid_text_representation) ->
validation. The normalizermoved to
src/errors.ts(internal, not part of the public surface) and is nowunit-tested against the full mapping table; the Convex normalizer gained matching
unit tests for parity.
store.get()now surfaces the portable_idlikestore.list()does. Previouslyget()returned the raw PostgREST row keyed only by the primary-key column, so a fetched document had no_id(an inconsistency withlist(), and with the Convex adapter whose documents carry_idnatively). A document fetched viaget()can now be passed straight topatch()/remove(). Found by the Marquee dogfood.subscribe()andfiles.upload()no longer crash in a non-secure browser context. Both usedcrypto.randomUUID()(for the Realtime channel name and the default Storage path), butcrypto.randomUUIDis defined ONLY in secure contexts (https, or http onlocalhost). On a plain-http origin such as a LAN-IP dev server (http://192.168.x.x) or any non-https deployment it isundefined, so opening a live subscription threwTypeError: crypto.randomUUID is not a functionand unmounted the React tree. Both now use an internal id helper that preferscrypto.randomUUID()and falls back to a time + counter +Math.random()id when it is unavailable. Found by the Marquee dogfood (the realtime UI smoke over a LAN IP).signUp()now detects a duplicate registration reliably. It maps by the stableerror.code === "user_already_exists"instead of regex-matching the (localized, version-dependent) error message, and it surfaces the enumeration-protection obfuscated success (a user with an emptyidentitiesarray and no session, returned when email confirmation is ON) asconflictrather than a misleadingok(null). A genuine confirmation-pending signup (one identity, no session) is stillok(null).@baas/core@0.1.0
Minor Changes
e2d32fe: Add
CAPABILITY_KEYS, the runtime list of everyCapabilitieskey, kept exhaustive against the interface by a type-level test (as constliteral tuple). It is a trustworthy source of truth for iterating capabilities, used by the conformance suite's new capability-coverage meta-test to guard against a newly added flag silently going untested.f59ded2: Initial port layer (
@baas/core) and in-memory reference adapter(
@baas/adapter-memory), validated against the parameterized conformance suite.e3abea8: Extend
listwith theinoperator and field ordering.inoperator:where: [["status", "in", ["open", "pending"]]]. Maps toSupabase
.in(), memoryArray.includes, and an OR-of-eq expansion on Convex(which has no native
in).WhereConditionis now a discriminated tuple union(
intakes an array; the other six operators take a scalar).orderaccepts{ field, direction }in addition to thebare
"asc"/"desc"creation-order shorthand. Supabase and memory order by anyfield directly (keyset on
(field, pk)). On Convex, field ordering uses aby_<field>index; ordering by an unindexed field returns anunsupported_capabilityerror rather than silently falling back to creationorder. Page size still defaults to 50, clamped to 200.
8d97270: Add a portable
listprimitive toDocumentStore: cursor-paginated,creation-ordered listing with a small filter set.
store.list(collection, { where, order, limit, cursor })returns{ items, nextCursor }, where each item carries aportable
_id. Filters use six comparison operators (eq/neq/gt/gte/lt/lte,AND-combined); ordering is creation-order direction only (
asc/desc); paginationis keyset/cursor (never offset). Implemented identically across memory, Supabase
(keyset on a configurable
timestampColumn, defaultcreated_at), and Convex(
.paginate()over the deployed helper), and asserted by the conformance suite.Contract note: loop until
nextCursorisnull; a non-null cursor may yield anempty trailing page on a scan-based backend (Convex with a filter). Arbitrary-field
sorting,
in/text/array operators, joins, and aggregation remain out of scope vianative().Patch Changes
@baas/migrate@0.1.0
Minor Changes
dryRunMigrate(source, target, opts): project a cutover WITHOUT writinganything. It reads the source and the target's resume index and returns a
MigratePlan— per collection, how many rows would be copied vs skipped — plusthe first
validationissue (missing_id, or a payload overmaxValueBytes)the real run would fail-fast on, computed with the SAME per-row checks
migrate()uses (extracted into shared helpers so the preview can't drift from reality). It
is reads-only and honest about its limits: it does not project the relink pass
(relinking needs ids the target mints during the real copy) nor exercise the
read-after-write precondition (nothing is inserted). New exports:
dryRunMigrate,MigratePlan,MigratePlanCollection.@baas/migrate: a one-time portable data cutover between any twoBackends, built on the core
list/insert/patchprimitives (no provider SDK).migrate(source, target, { collections, relations?, stripFields?, batchSize?, onProgress? })pages the source, re-inserts each row into the target (stampingmigratedFrom: <oldId>and stripping backend system fields), and optionallyremaps foreign keys to the target's re-minted ids in a second pass. It is
idempotent/resumable (re-runs skip rows already stamped on the target) and
fail-fast (the first backend error stops the run and is returned with the partial
idMapintact, never thrown). Proven memory → memory in the test suite; the liveSupabase → Convex cutover is a manual smoke. Explicitly NOT live sync, NOT atomic
across backends, and NOT a schema/DDL tool, a deliberate cutover documented as
such.
maxValueBytesoption and document migrate's size/scan boundsagainst Convex's hard limits (16 MiB/mutation, 32k docs scanned, ~1 MiB/value).
When set, a row whose copied payload serializes to more than
maxValueBytesUTF-8 bytes aborts with a clear
validationerror BEFORE the insert, instead ofletting a size-capped target reject it with a provider-specific message
mid-insert;
maxValueBytes: 1_000_000is a sensible bound for a Convex target.Off by default, so the abstraction bakes in no backend's limit. Size is measured
portably (UTF-8 length of the JSON encoding via
TextEncoder, so it works in thebrowser too); a
bigint(a legitimate Convexint64) is measured as its decimalstring rather than throwing, and a value that still cannot serialize (a circular
reference) skips the check rather than crashing the run. The README gains a
"Size and scan bounds" section noting that
reads page at ≤ 200 rows (under the 32k docs-scanned limit) and writes are one
mutation per row.
Patch Changes
5cd6692: Fix: use a portable resume marker
migratedFrom(no leading underscore) insteadof
_migratedFrom. Convex rejects any user field whose name starts with_("only allowed for system fields like
_id"), so the old marker made Convexunusable as a migration target. The new name is accepted by Convex, Supabase, and
the in-memory adapter alike. Caught by driving a real Supabase -> Convex cutover
against live stacks (the memory -> memory suite could not surface it); a guard test
now asserts the marker carries no leading underscore.
a813527: Enforce the read-after-write precondition and document migration preconditions.
After the first row it copies into each collection,
migrate()now reads thatrow back and aborts with a
validationerror if it is invisible ("inserted a rowbut could not read it back"). This converts a silent footgun into a loud, early
failure: a Supabase target reached without a service-role key can have RLS that
allows the insert but denies the select, in which case the resume scan would
silently see an empty target and re-copy everything (duplicates) on a re-run. The
check is portable (it asserts only "what I just wrote, I can read back" and never
inspects RLS) and costs one extra read per collection.
MigrateEndpointnow requiresgeton itsstore(alongsidelist/insert/patch); any wholeBackendalready satisfies this. The README gains aPreconditions section: Supabase targets need a service-role key (or RLS granting
read + write); Convex targets re-mint
_id, soreport.idMapis the onlyold-to-new link and id stability is never promised.
5fec07e: Docs: spell out two requirements a STRICT-SCHEMA target (Postgres/Supabase) has that a schemaless target (Convex) does not, both surfaced by the Marquee dogfood's reverse Convex->Supabase cutover. (1) Every migrated table needs a nullable
migratedFromtext column — the resume marker is stamped on each row and read back to resume, and it is NOT part of the source schema, so it is easy to miss; without it the first insert fails with "Could not find the 'migratedFrom' column …". (2) The two-pass copy inserts each row's foreign keys with the source id first and rewrites them in the relink pass, so FK columns on a relational target must be permissive during the copy (plaintext, no FK constraint); auuid-typed or FK-constrained column rejects the transient source id before relink can fix it. Both are inherent to copy-then-relink. The docstring also notes the resulting tension on Postgres: a FK constraint is what PostgREST needs for a server-side embedded join (theserverSideJoinscapability) but is exactly what blocks the same table from being a migration target, so a schema tuned for native joins is not automatically a clean migration target. Documented in the module docstring.Updated dependencies [e2d32fe]
Updated dependencies [f59ded2]
Updated dependencies [e3abea8]
Updated dependencies [e367b83]
Updated dependencies [8d97270]
marquee@0.0.1
Patch Changes