feat(stack): Bigint domains + Supabase support (i64-bounded) — CIP-3291 [gated on protect-ffi release]#557
feat(stack): Bigint domains + Supabase support (i64-bounded) — CIP-3291 [gated on protect-ffi release]#557freshtonic wants to merge 3 commits into
Conversation
…plaintext) Add BIGINT/BIGINT_EQ/BIGINT_ORD_ORE/BIGINT_ORD domain definitions, the EncryptedBigint*Column classes, types.Bigint* factories, barrel exports, and union membership, following the existing per-domain pattern. The SDK-wide Plaintext union gains bigint, and PlaintextKind/PlaintextFromKind map cast_as 'bigint' to the JS bigint type (bigint columns always decrypt to a JS bigint). Index emission follows the non-text numeric rule automatically: bigint_eq -> unique (hm); bigint_ord/bigint_ord_ore -> ore only (equality answered via ob). Bounds are the full i64 range, enforced at the protect-ffi boundary. GATED: live encrypt/decrypt requires the next protect-ffi release — the pinned 0.27.0 JsPlaintext cannot marshal a JS bigint across the Neon boundary (throws at runtime). No reconstruction is needed on the decrypt paths: the model decrypt helpers pass FFI-returned values through with no JSON round-trip. Part of CIP-3291 (bigint work stream); *_ord_ope is out of scope (CIP-3403).
- catalog: add the four bigint domain rows with BIGINT_S samples covering i64::MAX (9223372036854775807n), i64::MIN (-9223372036854775808n), 0n, and a mid value beyond Number.MAX_SAFE_INTEGER; widen DomainSpec.samples to include bigint; add an optional liveGate field naming the skip reason. - matrix-live / matrix-live-pg: exclude liveGate'd domains from the mega tables, seed rows, and term encryption (a bigint through protect-ffi 0.27.0 throws at RUNTIME, which would fail the shared beforeAll and take every other domain's proof down); emit explicit reason-bearing skips instead. Gating lifts by removing liveGate when the protect-ffi pin bumps. - matrix.test-d: bigint_ord column infers plaintext bigint and the equality|orderAndRange queryType union. - schema-v3: bigint_ord/bigint_ord_ore join the equality-via-ORE and ore-only (no unique) regression lists. - supabase-v3-builder (mock-based): bigint insert reaches encrypt as a real bigint, eq/gte filter operands JSON-encode safely (envelopes never carry raw bigint), and decrypted rows return a JS bigint through decryptResults. The mock envelope encodes bigint as a tagged string to preserve the real-world invariant that post-encryption envelopes are JSON-safe. - supabase-v3.test-d: bigint column plaintext is bigint; filter and insert value types pin to bigint (number/string rejected). Part of CIP-3291.
… gate Add the bigint domain family to the Supabase SDK reference and the stash-supabase skill (types table, DDL example, JS bigint in/out semantics, i64 boundary-error behaviour), plus a changeset (minor) noting the FFI-release gate and that bigint columns always decrypt to JS bigint. Part of CIP-3291.
🦋 Changeset detectedLatest commit: 9dd1a06 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
Summary
Adds Bigint support to the stack SDK and its Supabase adapter — the Bigint work stream of CIP-3291. This is step 3 of the CIP-3291 merge order. It was cut from #547's branch (
james/cip-3300-spike-integrate-eql-v3-into-supabase-orm, the full EQL v3 surface); #547 has since merged tomain(merge commit93b29291is main's tip), so this PR targetsmaindirectly and its diff is exactly the bigint work.Recorded decisions (from the Linear ticket — not relitigated here)
-2^63 … 2^63 - 1). Enforcement lives at the protect-ffi boundary (a parallel PR adds JSBigIntto protect-ffi'sJsPlaintexton the eql_v3 release line). The stack layer's job is types + domains + adapters + surfacing those errors — out-of-range values surface as encryption errors, never silent truncation.bigint, always (never a precision-lossynumber).*_ord_ope(CIP-3403): this addsbigint,bigint_eq,bigint_ord,bigint_ord_ore— the same families every other int has.🚧 Why this is a DRAFT — the gate
The pinned
@cipherstash/protect-ffi0.27.0 does not accept/return JSbigint(JsPlaintextlacks it): encrypting abigintthrows at runtime. The pin is deliberately NOT bumped here. This PR un-drafts when ALL of:BigIntinJsPlaintextships (parallel FFI PR on the eql_v3 release line);liveGatefrom the four bigint rows in__tests__/v3-matrix/catalog.ts— the live matrix suites (matrix-live,matrix-live-pg) then automatically pick the bigint domains up (mega-table round-trips at i64::MAX / i64::MIN / 0n / a >2^53 mid value, plus the pg eq/ord proofs) — and run green against live creds + a live DB.Until then, all runtime coverage is mock-based (the repo's established mock pattern in
supabase-v3-builder.test.ts), and the live suites emit explicit, reason-bearing skips for the bigint rows instead of silently omitting them.What changed
SDK (
packages/stack/src):eql/v3/columns.ts:BIGINT/BIGINT_EQ/BIGINT_ORD_ORE/BIGINT_ORDdomain consts (eql_v3.bigint*,castAs: 'bigint'),EncryptedBigint*Columnclasses,AnyEncryptedV3Columnmembership,PlaintextKind/PlaintextFromKindgain'bigint'→bigint.eql/v3/types.ts:types.Bigint/BigintEq/BigintOrdOre/BigintOrdfactories (naming convention preserved); barrel exports ineql/v3/index.ts.types.ts:Plaintext = JsPlaintext | Date | bigint, with the gate documented.bigint_eq→unique(hm);bigint_ord/bigint_ord_ore→oreonly (equality answered viaob, likeinteger_ord). Pinned by regression tests.schema/index.tsalready had'bigint'→'big_int'incastAsEnum/toEqlCastAs(and the wasmnormalizeCastAspath) — no change needed.Supabase adapter: no runtime code change needed —
query-builder-v3.tsis value-generic (filter operands go throughencrypt(); only post-encryption envelopes are JSON-encoded, and envelopes never contain a rawbigint). Coverage added instead (below).Decrypt-path bigint survival (verified): the model decrypt path (
encryption/helpers/model-helpers.ts→ FFIdecryptBulk) and the SupabasedecryptResults→decryptModel/bulkDecryptModels→postprocessDecryptedRowpath pass FFI-returned values through with no JSON round-trip — a JSbigintreturned through the Neon boundary reaches the caller intact.rowReconstructorneeds no bigint arm (comment updated). The onlyJSON.stringifyon the query path operates on post-encryption envelopes (safe).Tests:
v3-matrix/catalog.ts: 4 bigint rows (compile-time coverage gate satisfied);BIGINT_Ssamples include9223372036854775807n(i64::MAX),-9223372036854775808n(i64::MIN),0n, and4611686018427387904n(> 2^53, proves losslessness); newDomainSpec.liveGatefield carries the skip reason naming the gate.matrix-live/matrix-live-pg: live-gated domains are excluded from the shared mega tables / seed INSERT / term encryption — a bigint through FFI 0.27 (including the v2-wire term client) throws at runtime inbeforeAll, which would take every other domain's live proof down — and reported as explicit skips.matrix.test-d.ts:bigint_ordinfers plaintextbigint+'equality' | 'orderAndRange'.schema-v3.test.ts: bigint joins the equality-via-ORE and ore-only (nounique) regression lists.supabase-v3-builder.test.ts(mock, wire-encoding):types.BigintOrdcolumn — insert delivers the realbigintto encrypt;eq/gteoperands JSON-encode safely as full envelopes; decrypted rows return a JSbigintthroughdecryptResults.supabase-v3.test-d.ts: bigint column plaintext type isbigint; filter/insert value types pin tobigint(number/string rejected).Docs:
docs/reference/supabase-sdk.md+skills/stash-supabase/SKILL.mdgain the bigint domains (types/DDL examples), the i64 bounds + boundary-error semantics, and the gate note. Changeset added (minor).Test evidence
pnpm exec tsc --noEmit(packages/stack): 198 errors — byte-identical to the pre-change baseline (all pre-existing in__tests__;src/at 0). Verified by diffing baseline vs after.pnpm exec vitest run— v3-matrix deterministic suites (matrix now 39 domains),schema-v3,schema-builders,supabase-v3-builder(27 tests incl. 3 new bigint cases),typed-client-v3,schema-v3-client: all green (live suites skip locally as normal).pnpm exec vitest --run --typecheck.only: 7 files, 66 tests, no type errors (incl. the new bigint type assertions).Merge order
Step 3 of CIP-3291: (1) protect-ffi JS BigInt PR → (2) base stack PR #547 (merged) → (3) this PR → then pin bump +
liveGateremoval + live verification un-drafts it.