@lunora/sql-store 1.0.0-alpha.108 → 1.0.0-alpha.109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,8 +63,19 @@ interface SqlDialect {
63
63
  * decimal string), and `LONGTEXT` for everything else — strings unbounded
64
64
  * so they never truncate, composites because their wire-marked form is not
65
65
  * valid JSON and a `JSON` column would reject it on insert.
66
+ *
67
+ * `unique` says the column carries a `.unique()` constraint, so the type has
68
+ * to be one the engine can index in FULL. It exists for MySQL: InnoDB cannot
69
+ * index a `LONGTEXT` without a key prefix, and a prefixed UNIQUE index
70
+ * enforces uniqueness of the PREFIX — two distinct 200-character emails
71
+ * sharing their first 191 characters collided as a duplicate. A bounded
72
+ * `VARCHAR` indexes whole, so the constraint means what it says; a value
73
+ * past the bound is a loud write error rather than a wrong conflict. SQLite
74
+ * and Postgres index text of any length and ignore the flag.
66
75
  */
67
- columnType: (kind: string | undefined) => string;
76
+ columnType: (kind: string | undefined, options?: {
77
+ unique?: boolean;
78
+ }) => string;
68
79
  /**
69
80
  * Engine SQL types for the **internal companion tables** (aggregate / rank /
70
81
  * CDC), which are built from raw SQL types, not validator kinds. SQLite uses
package/dist/dialect.d.ts CHANGED
@@ -63,8 +63,19 @@ interface SqlDialect {
63
63
  * decimal string), and `LONGTEXT` for everything else — strings unbounded
64
64
  * so they never truncate, composites because their wire-marked form is not
65
65
  * valid JSON and a `JSON` column would reject it on insert.
66
+ *
67
+ * `unique` says the column carries a `.unique()` constraint, so the type has
68
+ * to be one the engine can index in FULL. It exists for MySQL: InnoDB cannot
69
+ * index a `LONGTEXT` without a key prefix, and a prefixed UNIQUE index
70
+ * enforces uniqueness of the PREFIX — two distinct 200-character emails
71
+ * sharing their first 191 characters collided as a duplicate. A bounded
72
+ * `VARCHAR` indexes whole, so the constraint means what it says; a value
73
+ * past the bound is a loud write error rather than a wrong conflict. SQLite
74
+ * and Postgres index text of any length and ignore the flag.
66
75
  */
67
- columnType: (kind: string | undefined) => string;
76
+ columnType: (kind: string | undefined, options?: {
77
+ unique?: boolean;
78
+ }) => string;
68
79
  /**
69
80
  * Engine SQL types for the **internal companion tables** (aggregate / rank /
70
81
  * CDC), which are built from raw SQL types, not validator kinds. SQLite uses
package/dist/index.d.mts CHANGED
@@ -123,6 +123,41 @@ interface SqlCtxDbOptions {
123
123
  * key cap when omitted.
124
124
  */
125
125
  maxRelationKeys?: number;
126
+ /**
127
+ * Object identifying the database this store provisions, so the one-shot
128
+ * `CREATE TABLE/INDEX IF NOT EXISTS` sweep is shared by every ctx-db built
129
+ * against it instead of repeating per instance.
130
+ *
131
+ * Hosts build a ctx-db **per request** (the writer captures the caller's
132
+ * identity and D1 bookmark), so without this the sweep — one round trip per
133
+ * global table plus one per index — runs again on the first `.global()`
134
+ * access of every request. On a 50-table schema that is ~1s in `lunora dev`
135
+ * and a real latency floor in production.
136
+ *
137
+ * WHAT TO PASS: something that outlives the request AND names one database
138
+ * (and one configuration). The D1 binding off `env` and the declaration
139
+ * object a host builds once both qualify; the result of a per-request
140
+ * factory does not — it keys the memo on a fresh object every time and
141
+ * shares nothing (which is silent, and looks exactly like not passing it).
142
+ *
143
+ * INVARIANT, unenforced: one scope ⇒ one `schema`, `dialect` and `cdc`. The
144
+ * memoised run closes over the FIRST writer's, so a later writer sharing a
145
+ * scope with `cdc: true` behind one with `cdc: false` never gets
146
+ * `__cdc_log`. Hosts pass app-level constants for all three, which is why
147
+ * this is a note rather than a composite key.
148
+ *
149
+ * Two behaviours change with a shared memo, both benign and both worth
150
+ * knowing: the DDL runs in the FIRST writer's D1 session, so a later
151
+ * session's first read is no longer implicitly pinned behind a write of its
152
+ * own (on a replicated binding that can mean one transient stale read on a
153
+ * freshly-provisioned database); and a database reset out from under a live
154
+ * isolate is no longer healed by the next request, since the entry lives as
155
+ * long as the scope does.
156
+ *
157
+ * Omit it and the memo stays per ctx-db — slower, never wrong, and what the
158
+ * tests want (they pair a fresh database with a reused schema object).
159
+ */
160
+ provisionScope?: object;
126
161
  /**
127
162
  * Scheduler exposed to global-table trigger handlers as `ctx.scheduler`.
128
163
  * Absent it, `ctx.scheduler` is a stub that throws on use — pass one when
@@ -243,7 +278,7 @@ declare const SEARCH_STATE_TABLE = "__lunora_search_state";
243
278
  /** Create the progress table. Idempotent; runs alongside the companion DDL. */
244
279
  declare const migrateSearchState: (exec: SqlCtxExec, dialect: SqlDialect) => Promise<void>;
245
280
  /** Map a JS value onto its SQLite storage form — SQLite has no boolean, so true/false → 1/0. */
246
- declare const sqliteEncode: (value: unknown) => unknown;
281
+ declare const sqliteEncode: (value: unknown, kind?: string) => unknown;
247
282
  /** Parse `raw` as JSON, returning `raw` unchanged when it is not valid JSON. */
248
283
  declare const tryJsonParse: (raw: string) => unknown;
249
284
  /**
@@ -277,8 +312,12 @@ declare const effectiveColumnKind: (validator: ValidatorLike) => string | undefi
277
312
  * belongs here because {@link sqliteEncode} keys off the runtime JS type and
278
313
  * stores the `{ lat, lng }` object as JSON in a TEXT column; without the case
279
314
  * it fell through to `default:` and every client read back the raw JSON text.
280
- * - `union`/`any`/`from`: parsed back only when the stored string is a JSON
281
- * non-scalar (a scalar member round-trips through SQLite's native column type).
315
+ * - `union`/`any`/`from`: parsed back when the stored string is a JSON
316
+ * non-scalar, or when it carries the {@link WIRE_PREFIX} marker.
317
+ * A `number` or `boolean` does NOT round-trip through the column's native
318
+ * type — all three kinds store as TEXT on every engine, which coerces a bound
319
+ * `42` to the text `42.0` — so {@link sqliteEncode} writes those two in the
320
+ * marked form and this branch reverses them by the marker alone.
282
321
  * `from` belongs to THIS group, not to `object`/`array`/`record`: an external
283
322
  * Standard Schema can describe a string just as easily as an object, and
284
323
  * {@link sqliteEncode} keys off the runtime JS type — so a `v.from(z.string())`
package/dist/index.d.ts CHANGED
@@ -123,6 +123,41 @@ interface SqlCtxDbOptions {
123
123
  * key cap when omitted.
124
124
  */
125
125
  maxRelationKeys?: number;
126
+ /**
127
+ * Object identifying the database this store provisions, so the one-shot
128
+ * `CREATE TABLE/INDEX IF NOT EXISTS` sweep is shared by every ctx-db built
129
+ * against it instead of repeating per instance.
130
+ *
131
+ * Hosts build a ctx-db **per request** (the writer captures the caller's
132
+ * identity and D1 bookmark), so without this the sweep — one round trip per
133
+ * global table plus one per index — runs again on the first `.global()`
134
+ * access of every request. On a 50-table schema that is ~1s in `lunora dev`
135
+ * and a real latency floor in production.
136
+ *
137
+ * WHAT TO PASS: something that outlives the request AND names one database
138
+ * (and one configuration). The D1 binding off `env` and the declaration
139
+ * object a host builds once both qualify; the result of a per-request
140
+ * factory does not — it keys the memo on a fresh object every time and
141
+ * shares nothing (which is silent, and looks exactly like not passing it).
142
+ *
143
+ * INVARIANT, unenforced: one scope ⇒ one `schema`, `dialect` and `cdc`. The
144
+ * memoised run closes over the FIRST writer's, so a later writer sharing a
145
+ * scope with `cdc: true` behind one with `cdc: false` never gets
146
+ * `__cdc_log`. Hosts pass app-level constants for all three, which is why
147
+ * this is a note rather than a composite key.
148
+ *
149
+ * Two behaviours change with a shared memo, both benign and both worth
150
+ * knowing: the DDL runs in the FIRST writer's D1 session, so a later
151
+ * session's first read is no longer implicitly pinned behind a write of its
152
+ * own (on a replicated binding that can mean one transient stale read on a
153
+ * freshly-provisioned database); and a database reset out from under a live
154
+ * isolate is no longer healed by the next request, since the entry lives as
155
+ * long as the scope does.
156
+ *
157
+ * Omit it and the memo stays per ctx-db — slower, never wrong, and what the
158
+ * tests want (they pair a fresh database with a reused schema object).
159
+ */
160
+ provisionScope?: object;
126
161
  /**
127
162
  * Scheduler exposed to global-table trigger handlers as `ctx.scheduler`.
128
163
  * Absent it, `ctx.scheduler` is a stub that throws on use — pass one when
@@ -243,7 +278,7 @@ declare const SEARCH_STATE_TABLE = "__lunora_search_state";
243
278
  /** Create the progress table. Idempotent; runs alongside the companion DDL. */
244
279
  declare const migrateSearchState: (exec: SqlCtxExec, dialect: SqlDialect) => Promise<void>;
245
280
  /** Map a JS value onto its SQLite storage form — SQLite has no boolean, so true/false → 1/0. */
246
- declare const sqliteEncode: (value: unknown) => unknown;
281
+ declare const sqliteEncode: (value: unknown, kind?: string) => unknown;
247
282
  /** Parse `raw` as JSON, returning `raw` unchanged when it is not valid JSON. */
248
283
  declare const tryJsonParse: (raw: string) => unknown;
249
284
  /**
@@ -277,8 +312,12 @@ declare const effectiveColumnKind: (validator: ValidatorLike) => string | undefi
277
312
  * belongs here because {@link sqliteEncode} keys off the runtime JS type and
278
313
  * stores the `{ lat, lng }` object as JSON in a TEXT column; without the case
279
314
  * it fell through to `default:` and every client read back the raw JSON text.
280
- * - `union`/`any`/`from`: parsed back only when the stored string is a JSON
281
- * non-scalar (a scalar member round-trips through SQLite's native column type).
315
+ * - `union`/`any`/`from`: parsed back when the stored string is a JSON
316
+ * non-scalar, or when it carries the {@link WIRE_PREFIX} marker.
317
+ * A `number` or `boolean` does NOT round-trip through the column's native
318
+ * type — all three kinds store as TEXT on every engine, which coerces a bound
319
+ * `42` to the text `42.0` — so {@link sqliteEncode} writes those two in the
320
+ * marked form and this branch reverses them by the marker alone.
282
321
  * `from` belongs to THIS group, not to `object`/`array`/`record`: an external
283
322
  * Standard Schema can describe a string just as easily as an object, and
284
323
  * {@link sqliteEncode} keys off the runtime JS type — so a `v.from(z.string())`
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlCdcMigration as s,sweepSqlCdcRetention as n}from"./packem_shared/createSqlCtxDb-BNu9kPCB.mjs";import{runSqlAggregateMigrations as d,runSqlGlobalTableMigrations as S,runSqlRankMigrations as c}from"./packem_shared/runSqlAggregateMigrations-D9KIdXhq.mjs";import{d as g,r as C}from"./packem_shared/ctx-db-search-CHAHn9hB.mjs";import{S as m,m as x}from"./packem_shared/ctx-db-search-state-ClbuTC47.mjs";import{c as b,e as u,a as h,s as M,t as T}from"./packem_shared/value-codec-ByV_h-TJ.mjs";import{decodeGlobalRow as E}from"./packem_shared/decodeGlobalRow-DVG7FHVz.mjs";export{m as SEARCH_STATE_TABLE,g as backfillSqlSearchIndexes,a as createSqlCtxDb,b as decodeBigint,E as decodeGlobalRow,u as effectiveColumnKind,x as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,d as runSqlAggregateMigrations,s as runSqlCdcMigration,S as runSqlGlobalTableMigrations,c as runSqlRankMigrations,C as runSqlSearchMigrations,h as sqliteDecode,M as sqliteEncode,n as sweepSqlCdcRetention,T as tryJsonParse};
1
+ import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlCdcMigration as s,sweepSqlCdcRetention as n}from"./packem_shared/createSqlCtxDb-BIFOgsTf.mjs";import{runSqlAggregateMigrations as d,runSqlGlobalTableMigrations as S,runSqlRankMigrations as c}from"./packem_shared/runSqlAggregateMigrations-DA8EVLuX.mjs";import{d as g,r as C}from"./packem_shared/ctx-db-search-3QrN4xRN.mjs";import{S as m,m as x}from"./packem_shared/ctx-db-search-state-C0hUwzYJ.mjs";import{c as b,e as u,a as h,s as M,t as T}from"./packem_shared/value-codec-nCDJEXH_.mjs";import{decodeGlobalRow as E}from"./packem_shared/decodeGlobalRow-B6zmyAi5.mjs";export{m as SEARCH_STATE_TABLE,g as backfillSqlSearchIndexes,a as createSqlCtxDb,b as decodeBigint,E as decodeGlobalRow,u as effectiveColumnKind,x as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,d as runSqlAggregateMigrations,s as runSqlCdcMigration,S as runSqlGlobalTableMigrations,c as runSqlRankMigrations,C as runSqlSearchMigrations,h as sqliteDecode,M as sqliteEncode,n as sweepSqlCdcRetention,T as tryJsonParse};
@@ -1 +1 @@
1
- import{S as t,a as S,m as c,r as l,b as i,w as s}from"./ctx-db-search-state-ClbuTC47.mjs";import"./decodeGlobalRow-DVG7FHVz.mjs";export{t as SEARCH_STATE_TABLE,S as clearSearchBackfillState,c as migrateSearchState,l as readSearchBackfillState,i as readSearchIndexCoverage,s as writeSearchBackfillState};
1
+ import{S as t,a as S,m as c,r as l,b as i,w as s}from"./ctx-db-search-state-C0hUwzYJ.mjs";import"./decodeGlobalRow-B6zmyAi5.mjs";export{t as SEARCH_STATE_TABLE,S as clearSearchBackfillState,c as migrateSearchState,l as readSearchBackfillState,i as readSearchIndexCoverage,s as writeSearchBackfillState};
@@ -0,0 +1 @@
1
+ import"./ctx-db-search-state-C0hUwzYJ.mjs";import{d as S,c as s,a as i,r as l}from"./ctx-db-search-3QrN4xRN.mjs";import"./decodeGlobalRow-B6zmyAi5.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -0,0 +1,7 @@
1
+ import{LunoraError as T}from"@lunora/errors";import{m as qt,D as Ot}from"./ctx-db-search-state-C0hUwzYJ.mjs";import{c as Wt,r as Ft,A as Ut,C as xt,R as Pt,a as Ht,T as Kt,x as jt,b as Gt}from"./ctx-db-search-3QrN4xRN.mjs";import{d as fi}from"./ctx-db-search-3QrN4xRN.mjs";import{literalInList as Vt,throwingScheduler as Yt,CDC_LOG_TABLE as G,cursorBelowRetainedFloor as Xt,cdcTrimmedError as zt,assertNoExplicitUndefined as Ze,hasTrigger as Qt,runRowValidators as Ne,assertFlatPredicate as et,mergeWhere as q,rankTableName as de,sortColumnName as $e,resolveRankPartition as tt,encodePartitionKey as Ie,resolveRankSeekTuple as Jt,RANK_TIEBREAK as _e,CountRlsUnsupportedError as nt,normalizeIdStructurally as Zt,assertValidClientId as en,aggregateSqlFunction as le,softDeleteScope as ue,compileWhereSql as fe,normalizeOrderKeys as tn,buildSeekWhere as nn,decodeCursor as on,resolveRelationPredicates as it,resolveWith as ot,relationHooks as rt,applySelect as st,encodeCursor as rn,NotFoundError as sn,applyOnDelete as an,ConflictError as Ce,normalizeCountArgument as cn,selectIndexForCount as dn,encodeAggregateKey as Y,aggregateTableName as Q,selectIndexForAggregate as ln,readAggregateValue as De,runTriggers as un,matchesRankStaticWhere as at,rankPivotConditionSql as yt,CURSOR_PREFIX as fn,selectIndexForGroupBy as wn,tiebreakDirectionFor as $n,fanOutScalarCounts as _n,matchesStaticWhere as Be,foldAggregateTally as ct,coerceAggregateNumber as qe,CDC_LOG_TABLE_SEQ_INDEX as hn,NotUniqueError as En}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as pt,e as Rt,n as yn,b as pn}from"./value-codec-nCDJEXH_.mjs";import{runSqlGlobalTableMigrations as Rn,runSqlAggregateMigrations as Sn,runSqlRankMigrations as gn}from"./runSqlAggregateMigrations-DA8EVLuX.mjs";import{queryAll as I,queryRun as k,createIndexIfNotExists as Tn,decodeRow as Z,serializeDocumentColumn as be,serializeColumnValue as we,columnRefSql as O,decodeRows as dt,tableColumns as St,OCC_VERSION_COLUMN as lt,forEachRowPaged as ut,BACKFILL_BATCH_SIZE as Oe,queryBatch as ft}from"./decodeGlobalRow-B6zmyAi5.mjs";import{decodeGlobalRow as $i}from"./decodeGlobalRow-B6zmyAi5.mjs";const vn=(a,c)=>{if(a.size<c)return;const _=a.keys().next().value;_!==void 0&&a.delete(_)},wt=50,mn=(a,c={})=>{const _=c.maxBatch??wt,r=Number.isInteger(_)&&_>0?_:wt,p=new Map;let $=!1;const u=async(g,v)=>{const m=[...v.keys()];for(let M=0;M<m.length;M+=r){const N=m.slice(M,M+r);try{const W=await a(g,N);for(const V of N){const P=W.get(V);for(const Ae of v.get(V)??[])Ae.resolve(P)}}catch(W){for(const V of N)for(const P of v.get(V)??[])P.reject(W)}}},b=()=>{$=!1;const g=[...p.entries()];p.clear();for(const[v,m]of g)u(v,m).catch(()=>{})};return{async load(g,v){return new Promise((m,M)=>{let N=p.get(g);N||(N=new Map,p.set(g,N));const W=N.get(v);W?W.push({reject:M,resolve:m}):N.set(v,[{reject:M,resolve:m}]),$||($=!0,queueMicrotask(b))})}}},In=new Set(["_id","id"]),xe=(a,c,_)=>a==="postgres"?e`${c} IS NOT DISTINCT FROM ${_}`:a==="mysql"?e`${c} <=> ${_}`:e`${c} IS ${_}`,gt=(a,c)=>a.name!=="postgres"||c.nullable!==!0?"":c.direction==="desc"?" NULLS LAST":" NULLS FIRST",bn=(a,c)=>{const _=a.map(r=>e`${O(r.field)} ${e.raw(`${r.direction==="desc"?"DESC":"ASC"}${gt(c,r)}`)}`);if(!a.some(r=>In.has(r.field))){const r=$n(a);_.push(e`${O("id")} ${e.raw(r==="desc"?"DESC":"ASC")}`)}return e.join(_,e`, `)},$t=50,Cn=(a,c,_)=>{const r={...c};for(const[p,$]of St(a)){if($.serverDefault){r[p]=$.serverDefault({auth:_});continue}r[p]===void 0&&($.defaultFn?r[p]=$.defaultFn():"defaultValue"in $&&(r[p]=$.defaultValue))}return r},_t=(a,c,_,r)=>{for(const[p,$]of St(a)){if($.serverDefault){p in c&&(_[p]=$.serverDefault({auth:r}));continue}$.onUpdateFn&&!(p in c)&&(_[p]=$.onUpdateFn())}},An=128,Ln=()=>{const a=new Map;return{delete:c=>{a.delete(c)},get:c=>{const _=a.get(c);if(_!==void 0)return a.delete(c),a.set(c,_),_},set:(c,_)=>{a.has(c)?a.delete(c):vn(a,An),a.set(c,_)}}},kn=async(a,c,_,r,p)=>{const $=p.get(r);if($!==void 0)return $;const u=Object.entries(_.tables).filter(([,g])=>g.shardMode===void 0||g.shardMode.kind==="global").map(([g])=>g),b=await Promise.all(u.map(async g=>({found:(await I(a,c,e`SELECT 1 FROM ${e.identifier(g)} WHERE ${e.identifier("id")} = ${r} LIMIT 1`)).length>0,tableName:g})));for(const g of b)if(g.found)return p.set(r,g.tableName),g.tableName},ee=a=>a==null?null:Number(a),Mn=(a,c)=>c.map(_=>{const r={};for(const p of a)r[p]=_[p]??null;return{key:r,value:ee(_.value)}}),Nn=(a,c,_)=>[...a.partitionBy??[],...a.sortBy.map(p=>p.field),...a.where?Object.keys(a.where):[]].every(p=>c[p]===_[p]),Tt=a=>a.length===1?a[0]:e`(${e.join(a,e` AND `)})`,J=a=>e.join(a.map(c=>e`${e.identifier(c)}`),e`, `),te=a=>e.join(a.map(c=>e`${c}`),e`, `),Dn=(a,c,_,r,p)=>{const $=[];for(let u=0;u<_.length+1;u+=1){const b=_[u],g=c.sortBy[u],v=u<_.length&&b!==void 0&&g!==void 0,m=g?.direction==="desc"?"desc":"asc",M=v?yt(b,r[b],m,!1):e`${e.identifier(_e)} < ${p}`;if(M===void 0)continue;const N=_.slice(0,u).map(W=>xe(a,e`${e.identifier(W)}`,r[W]));N.push(M),$.push(Tt(N))}return $.length>0?e.join($,e` OR `):e`1 = 0`},Bn=(a,c,_)=>{if(_.length!==c.length)return;const r=[];for(const[p,$]of c.entries()){const u=yt($.column,_[p],$.direction,!0);if(u===void 0)continue;const b=[];for(let g=0;g<p;g+=1){const v=c[g];v!==void 0&&b.push(xe(a,e`${e.identifier(v.column)}`,_[g]))}b.push(u),r.push(Tt(b))}return r.length===0?e`(1 = 0)`:e`(${e.join(r,e` OR `)})`},qn=(a,c)=>{if(a.sortBy.length===0)throw new T("INTERNAL",`rankIndex "${a.name}" requires at least one "sortBy" column for stable pagination`);const _=[{column:"__partition__",direction:"asc",nullable:!1}];for(const[r,p]of a.sortBy.entries())_.push({column:c[r]??$e(r),direction:p.direction,nullable:!0});return _.push({column:_e,direction:"asc",nullable:!1}),_},On=async(a,c,_,r,p)=>{const u=[];for(let m=0;m<p.length;m+=50)u.push(p.slice(m,m+50));const b=await Promise.all(u.map(async m=>I(a,c,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} IN (${te(m)})`))),g=new Map;for(const m of b)for(const M of m)g.set(M.id,M);const v=[];for(const m of p){const M=Z(_,g.get(m));M&&v.push(M)}return v},Wn=a=>{const c=JSON.stringify(a),_=new TextEncoder().encode(c);let r="";for(const p of _)r+=String.fromCodePoint(p);return fn+btoa(r)},Fe=(a,c,_)=>{const r=a.shape[c];if(r!==void 0&&Rt(r)==="bigint")throw new T("BAD_REQUEST",`${_}: "${c}" is stored as an order-preserving key, which SQL cannot reduce or group — declare an aggregateIndex covering this (by, field, op) so the maintained companion answers it instead (its running total is a REAL, so it stays exact only while the total is inside 2^53)`)},Fn=a=>{if(a===void 0)return!1;const c=Rt(a);return c==="any"||c==="bigint"||c==="from"||c==="union"},Un=(a,c,_,r)=>{for(const p of _)Fe(a,p,`groupBy(${c}, { by: [..."${p}"] })`);r.field!==void 0&&Fe(a,r.field,`groupBy(${c}, { agg: { op: "${r.op}", field: "${r.field}" } })`)},Ue="__cdc_sweep",vt="global",xn=6e4,Pn=1e4,Hn=3e4;let ht=0;const Kn=async(a,c)=>{const{autoincrementPrimaryKey:_,key:r,real:p,text:$}=c.companionTypes;await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(G)} (${e.identifier("seq")} ${e.raw(_)}, ${e.identifier("ts")} ${e.raw(p)} NOT NULL, ${e.identifier("table")} ${e.raw(r)} NOT NULL, ${e.identifier("id")} ${e.raw(r)} NOT NULL, ${e.identifier("op")} ${e.raw(r)} NOT NULL, ${e.identifier("doc")} ${e.raw($)})`);const u=c.indexKeyPrefix?.("string");await Tn(a,c,{columns:e`${u===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(u))})`}, ${e.identifier("seq")}`,name:hn,table:G,unique:!1}),await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(Ue)} (${e.identifier("id")} ${e.raw(r)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(p)} NOT NULL)`),await k(a,c,e`INSERT INTO ${e.identifier(Ue)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${vt}, ${0}) ${c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},jn=async(a,c,_)=>{const r=e`UPDATE ${e.identifier(Ue)} SET ${e.identifier("lease_until")} = ${_+xn} WHERE ${e.identifier("id")} = ${vt} AND ${e.identifier("lease_until")} <= ${_}`;if(c.supportsReturning)return(await I(a,c,e`${r} RETURNING ${e.identifier("id")}`)).length>0;const p=await k(a,c,r);return(c.affectedRows?c.affectedRows(p??{rowsAffected:0}):0)>0},Gn=async(a,c,_,r)=>{if(!await jn(a,c,r))return;const p=r-_;await k(a,c,e`
2
+ DELETE FROM ${e.identifier(G)} WHERE ${e.identifier("seq")} IN (
3
+ SELECT ${e.identifier("seq")} FROM (
4
+ SELECT ${e.identifier("seq")} FROM ${e.identifier(G)} WHERE ${e.identifier("ts")} <= ${p} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Pn))}
5
+ ) AS ${e.identifier("expired")}
6
+ )
7
+ `)},mt=async(a,c)=>{const _=await I(a,c,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(G)}`),r=Number(_[0]?.seq??Number.NaN);return Number.isFinite(r)?r:void 0},Vn=a=>JSON.stringify(yn(a)?pn(a):a),Yn=async(a,c,_,r,p,$,u)=>{await k(a,u,e`INSERT INTO ${e.identifier(G)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${c}, ${_}, ${r}, ${p}, ${$===void 0?null:Vn($)})`)},ci=async(a,c,_)=>{const r=c.sinceSeq??0,p=Math.max(1,Math.min(c.limit??1e3,1e4)),$=await mt(a,_);if($!==void 0&&Xt($,r))throw zt($,r,"global");const b=(await I(a,_,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(G)} WHERE seq > ${r} ORDER BY seq ASC LIMIT ${e.raw(String(p))}`)).map(g=>{const{doc:v}=g,m={id:String(g.id),op:String(g.op),seq:Number(g.seq),table:String(g.table),ts:Number(g.ts)};return typeof v=="string"?{...m,doc:pt(JSON.parse(v))}:m});return{changes:b,cursor:b.at(-1)?.seq??r}},Xn=async(a,c,_,r={})=>{if(r.cursorOnly){const g=await I(a,_,e`SELECT MAX(seq) AS seq FROM ${e.identifier(G)}`),v=Number(g[0]?.seq??c);return{cursor:Number.isFinite(v)?v:c,tables:[]}}const p=await I(a,_,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(G)} WHERE seq > ${c} GROUP BY ${e.identifier("table")}`);let $=c;const u=[];for(const g of p){const v=Number(g.seq);Number.isFinite(v)&&v>$&&($=v),u.push(String(g.table))}const b=r.retained===!0?await mt(a,_):void 0;return{cursor:$,tables:u,...b===void 0?{}:{floor:b}}},zn=/string or blob too big/iu,Qn=/row is too big/iu,Jn=(a,c)=>{const{code:_,errno:r}=c,p=c instanceof Error?c.message:"";switch(a.name){case"mysql":return r===1118||_==="ER_TOO_BIG_ROWSIZE"?"InnoDB's per-row ceiling — roughly 8 KB, half a 16 KB page, for the part of the row stored inline":void 0;case"postgres":return Qn.test(p)?"the 8 KB heap page a tuple must fit once its wide columns have been TOASTed out":void 0;default:return zn.test(p)?"the storage engine's per-row ceiling (2 MB on D1)":void 0}},Zn=(a,c,_)=>{const r=Jn(a,c);if(r!==void 0)throw new T("PAYLOAD_TOO_LARGE",`document is too large to store in "${_}": a single row cannot exceed ${r}. The limit is on the STORED bytes, which are UTF-8. Keep the payload in R2 (ctx.storage) and store a reference on the row.`)},Et=(a,c,_)=>{throw a.isUniqueViolation(c)?new Ce(`unique constraint violation on "${_}"`,"unique"):(Zn(a,c,_),c)},We=new WeakMap,di=a=>{const{crossShardCounter:c,crossShardReader:_,exec:r,maxRelationKeys:p,schema:$}=a,{dialect:u}=a,b={fieldRef:O,serialize:we,...u.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...u.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...u.name==="sqlite"?{}:{inList:Vt}},g=(t,n)=>xe(u.name,t,n),v=t=>{const n=J(t.columns),i=te(t.values),o=l=>u.name==="mysql"?e`VALUES(${e.identifier(l)})`:e`excluded.${e.identifier(l)}`,s=l=>u.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(l)}`:e`${e.identifier(l)}`,f=e.join(Object.entries(t.set(o,s)).map(([l,E])=>e`${e.identifier(l)} = ${E}`),e`, `),h=u.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${f}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${f}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${i}) ${h}`},m=a.clock??(()=>Date.now()),M=a.idGenerator??(()=>crypto.randomUUID()),N=a.cdc??!1,W=typeof a.cdcRetentionMs=="number"&&Number.isFinite(a.cdcRetentionMs)&&a.cdcRetentionMs>0?a.cdcRetentionMs:void 0,V=a.auth??{identity:null,userId:null},P=async(t,n,i,o)=>{if(!N||(await Yn(r,m(),t,n,i,o,u),W===void 0))return;const s=m();if(!(s-ht<Hn)){ht=s;try{await Gn(r,u,W,s)}catch{}}},Ae=a.scheduler??Yt,Le=Ln();let he=0;const ke=a.provisionScope??{},U=async()=>{const t=We.get(ke);if(t)return t;const n=(async()=>{await Rn(r,$,u),await Sn(r,$,u),await gn(r,$,u),await qt(r,u),await Ft(r,$,u),N&&await Kn(r,u)})().catch(i=>{throw We.delete(ke),i});return We.set(ke,n),n},ne=async(t,n)=>{await U();const i=await kn(r,u,$,t,Le);if(!(n!==void 0&&i!==n))return i},ie=new Map,Pe=async(t,n)=>{const i=Q(t,n);return(await I(r,u,u.tableExists(i))).length>0},Ee=async(t,n)=>{const i=`${t}::${n.name}`,o=ie.get(i);if(o!==void 0)return o;if(!await Pe(t,n.name))return ie.set(i,!1),!1;const f=$.tables[t];if(!f)return ie.set(i,!1),!1;const h=n.by??[],l=new Map;await ut(r,u,f,t,w=>{if(n.where&&!Be(w,n.where))return;const y=Y(h,w);ct(l,y,n,w)});const E=Q(t,n.name);await k(r,u,e`DELETE FROM ${e.identifier(E)}`);const d=[];for(const[w,y]of l)d.push(e`INSERT INTO ${e.identifier(E)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${w}, ${y.value}, ${y.count})`);return await ft(r,u,d),ie.set(i,!0),!0},It=async(t,n,i,o)=>{const s=new Map;let f,h=!0;for(;h;){const l=f===void 0?o:[...o,e`${e.identifier("id")} > ${f}`],E=l.length>0?e` WHERE ${e.join(l,e` AND `)}`:e``,d=await I(r,u,e`SELECT ${e.identifier("id")}, ${O(i.field??"")} FROM ${e.identifier(n)}${E} ORDER BY ${e.identifier("id")} ASC LIMIT ${e.raw(String(Oe))}`);for(const w of dt(t,d))ct(s,"",i,w);f=d.at(-1)?.id,h=d.length===Oe}return s.get("")?.value??null},bt=async(t,n,i)=>{const o=n.field??"",s=[];for(const d of n.by??[]){const w=we(i[d]??null);s.push(w===null?e`${O(d)} IS NULL`:e`${O(d)} = ${w}`)}for(const[d,w]of Object.entries(n.where??{})){const y=w!==null&&typeof w=="object"&&!Array.isArray(w)?w.eq:w,R=we(y);s.push(R===null?e`${O(d)} IS NULL`:e`${O(d)} = ${R}`)}const f=s.length>0?e` WHERE ${e.join(s,e` AND `)}`:e``,h=$.tables[t];if(h&&Fn(h.shape[o]))return It(h,t,n,s);const l=le(n.op),E=await I(r,u,e`SELECT ${e.raw(l)}(${O(o)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}${f}`);return ee(E[0]?.value)},Ct=async(t,n)=>{await k(r,u,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},At=async(t,n,i,o)=>{const s=Q(t,n.name),{op:f}=n,h=n.field??"",l=i&&(!n.where||Be(i,n.where))?i:void 0,E=o&&(!n.where||Be(o,n.where))?o:void 0;if(!(!l&&!E)){if(f==="count"||f==="sum"||f==="avg"){const d=new Set;for(const[w,y]of[[l,-1],[E,1]]){if(!w)continue;const R=f==="count"?1:qe(w[h]);if(R===void 0)continue;const S=Y(n.by??[],w);d.add(S),await k(r,u,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(C,A)=>({__count__:e`${A("__count__")} + ${C("__count__")}`,__value__:f==="count"?e`${A("__value__")} + ${C("__value__")}`:e`COALESCE(${A("__value__")}, 0) + ${C("__value__")}`}),table:s,values:[S,y*R,y]}))}for(const w of d)await Ct(s,w);return}if(l){const d=Y(n.by??[],l),w=qe(l[h]),R=(await I(r,u,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`))[0],S=ee(R?.value),C=(R?.count??0)-1;if(C<=0)await k(r,u,e`DELETE FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`);else if(R&&w!==void 0&&S!==null&&w===S){const A=await bt(t,n,l);await k(r,u,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__value__")} = ${A}, ${e.identifier("__count__")} = ${C} WHERE ${e.identifier("__key__")} = ${d}`)}else await k(r,u,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${d}`)}if(E){const d=Y(n.by??[],E),w=qe(E[h]);if(w===void 0)await k(r,u,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(y,R)=>({__count__:e`${R("__count__")} + 1`}),table:s,values:[d,null,1]}));else{const y=f==="min"?"MIN":"MAX";await k(r,u,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(R,S)=>({__count__:e`${S("__count__")} + 1`,__value__:e`${e.raw(y)}(COALESCE(${S("__value__")}, ${R("__value__")}), ${R("__value__")})`}),table:s,values:[d,w,1]}))}}}},ye=async t=>{const n=$.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const i of n)await Ee(t,i)},oe=async(t,n,i)=>{const o=$.tables[t]?.aggregateIndexes;if(!(!o||o.length===0))for(const s of o){const f=`${t}::${s.name}`;(ie.get(f)??await Pe(t,s.name))&&await At(t,s,n,i)}},re=new Map,He=async(t,n)=>{const i=de(t,n);return(await I(r,u,u.tableExists(i))).length>0},Me=async(t,n)=>{const i=`${t}::rank::${n.name}`,o=re.get(i);if(o!==void 0)return o;if(!await He(t,n.name))return re.set(i,!1),!1;const f=$.tables[t];if(!f)return re.set(i,!1),!1;const h=de(t,n.name);await k(r,u,e`DELETE FROM ${e.identifier(h)}`);const l=n.sortBy.map((y,R)=>$e(R)),E=J(["__id__","__partition__",...l]);let d=[];const w=async()=>{if(d.length===0)return;const y=d;d=[],await ft(r,u,y)};return await ut(r,u,f,t,async y=>{if(n.where&&!at(y,n.where))return;const R=Ie(n.partitionBy??[],y),S=n.sortBy.map(C=>we(y[C.field]??null));d.push(e`INSERT INTO ${e.identifier(h)} (${E}) VALUES (${te([y._id,R,...S])})`),d.length>=Oe&&await w()}),await w(),re.set(i,!0),!0},pe=async t=>{const n=$.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const i of n)await Me(t,i)},X=async(t,n,i,o)=>{const s=$.tables[t],f=s?.rankIndexes;if(!f||f.length===0)return;const h=s?.softDeleteMode?.field,l=h===void 0||o===void 0?void 0:o[h],E=l!=null;for(const d of f){if(i!==void 0&&o!==void 0&&Nn(d,i,o))continue;const w=`${t}::rank::${d.name}`;if(!(re.get(w)??await He(t,d.name)))continue;const S=de(t,d.name);if(i&&await k(r,u,e`DELETE FROM ${e.identifier(S)} WHERE ${e.identifier("__id__")} = ${n}`),o&&!E){if(d.where&&!at(o,d.where))continue;const C=d.sortBy.map((B,j)=>$e(j)),A=J(["__id__","__partition__",...C]),F=Ie(d.partitionBy??[],o),L=d.sortBy.map(B=>we(o[B.field]??null));await k(r,u,e`INSERT INTO ${e.identifier(S)} (${A}) VALUES (${te([n,F,...L])})`)}}},se=Wt({dialect:u,exec:r,schema:$}),Ke=new Set;for(const[t,n]of Object.entries($.tables))for(const i of Object.values(n.triggerMap??{}))Ke.add(`${t} ${i.timing} ${i.op}`);const H=(t,n,i)=>Ke.has(`${t} ${n} ${i}`);let je;const K=async(t,n,i)=>{if(he+=1,he>$t)throw he-=1,new Ce(`trigger recursion exceeded ${String($t)} levels on "${i.table}" — check for a self-triggering write`,"trigger");try{await un({ctx:je,event:i,op:n,schema:$,tableName:i.table,timing:t})}finally{he-=1}},Lt=async(t,n)=>{try{await k(r,u,n)}catch(i){Et(u,i,t)}},Re=async(t,n)=>(await I(r,u,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],Se=async(t,n,i,o)=>{if(o===void 0)return;const s=e`${e.identifier(lt)}`,f=e.join([g(e`${e.identifier("id")}`,o.id),g(s,o[lt]??null)],e` AND `),h=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${i}, ${s} = COALESCE(${s}, 0) + 1 WHERE ${f}`:e`DELETE FROM ${e.identifier(t)} WHERE ${f}`,l=()=>{throw new Ce(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(u.supportsReturning)(await I(r,u,e`${h} RETURNING ${e.identifier("id")}`)).length===0&&l();else{const E=await k(r,u,h);(u.affectedRows?u.affectedRows(E??{rowsAffected:0}):0)===0&&l()}}catch(E){Et(u,E,t)}},kt=(t,n,i,o)=>{const s=Object.keys(t.shape);return{columns:["id","_creationTime",...s],values:[n,i,...s.map(f=>be(t,f,o[f]??null))]}},Mt=async(t,n,i,o)=>{const s=wn(n,i.op,i.field,o.by,o.where);if(!s||!await Ee(t,s.index))return;const h=Q(t,s.index.name),l=Object.keys(s.partial);if(l.length===(s.index.by??[]).length&&l.length>0){const d=Y(s.index.by??[],s.partial),w=await I(r,u,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)} WHERE ${e.identifier("__key__")} = ${d}`);if(w.length===0)return[];const y=w[0];return[{key:{...s.partial},value:De(i.op,{count:y.count,value:ee(y.value)})}]}return l.length>0?void 0:(await I(r,u,e`SELECT ${e.identifier("__key__")} AS ${e.identifier("key")}, ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)}`)).map(d=>{const w=d;return{key:pt(JSON.parse(w.key)),value:De(i.op,{count:w.count,value:ee(w.value)})}})},Ge=t=>{const n=$.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Ve=t=>{throw new T("INTERNAL",`cross-backend relation: a global table cannot load the shard-local relation '${t}' (it spans every shard) — wire a cross-shard reader to support it`)},Nt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new T("MASK_UNSUPPORTED",`masking cannot follow a nested \`with\` across the cross-shard relation hop to "${t}" — the nested rows are hydrated on the serving shard, where the mask policy does not exist. Read the nested relation at its own (masked) call site instead.`);const i={};if(n?.relationBaseWhere)for(const o of Object.keys($.tables)){const s=n.relationBaseWhere(o);s!==void 0&&(i[o]=s)}return{orderBy:n?.orderBy,relationPolicies:i,where:q(n?.baseWhere,n?.where),with:n?.with}},Ye=(t,n)=>Ge(t)?_?_(t,Nt(t,n)):Ve(t):x.findMany(t,n),ge=(t,n,i)=>it(t,{fetcher:Ye,maxRelationKeys:p,relationBaseWhere:i,schema:$,tableName:n}),Dt=mn(async(t,n)=>{const i=await I(r,u,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${te(n)})`),o=new Map;for(const s of i){const{id:f}=s;typeof f=="string"&&o.set(f,s)}return o}),x={async cdcChangedTables(t,n){if(N)try{return await U(),await Xn(r,t,u,{...n,retained:W!==void 0})}catch{return}},async aggregate(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);if(await U(),le(n.op),n.op==="count")return x.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new T("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const o=ue(i.softDeleteMode,void 0),s=q(q(n.baseWhere,n.where),o),f=await ge(s,t,n.relationBaseWhere),h=f!==s;if(i.aggregateIndexes&&!n.baseWhere&&!h&&!o){const R=ln(i.aggregateIndexes,n.op,n.field,n.where);if(R&&await Ee(t,R.index)){const C=Y(R.index.by??[],R.key),A=Q(t,R.index.name),L=(await I(r,u,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(A)} WHERE ${e.identifier("__key__")} = ${C}`))[0];return De(n.op,L===void 0?void 0:{count:L.count,value:ee(L.value)})}}Fe(i,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const l=fe(f,b),E=e.raw(le(n.op)),d=e`SELECT ${E}(${O(n.field)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,y=(await I(r,u,l?e`${d} WHERE ${l}`:d))[0]?.value;return y==null?null:Number(y)},async count(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=cn(n);if(o.restrictsCounts)throw new nt(t);const s=ue(i.softDeleteMode,void 0),f=q(q(o.baseWhere,o.where),s),h=await ge(f,t,o.relationBaseWhere),l=h!==f;if(i.aggregateIndexes&&!o.baseWhere&&!l&&!s){const y=dn(i.aggregateIndexes,o.where);if(y&&await Ee(t,y.index)){const S=Y(y.index.by??[],y.key),C=Q(t,y.index.name),A=await I(r,u,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")} FROM ${e.identifier(C)} WHERE ${e.identifier("__key__")} = ${S}`);return Number(A[0]?.value??0)}}const E=fe(h,b),d=e`SELECT COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(t)}`,w=await I(r,u,E?e`${d} WHERE ${E}`:d);return Number(w[0]?.count??0)},async delete(t,n,i){const o=await ne(t,n);if(!o)return;const s=$.tables[o];if(!s)return;const f=await Re(o,t),h=Z(s,f),l=i?.hard===!0,E=!l&&s.softDeleteMode?s.softDeleteMode.field:void 0;if(!(E&&(!h||h[E]!==null&&h[E]!==void 0))){if(H(o,"before","delete")&&await K("before","delete",{id:t,op:"delete",previous:h??void 0,table:o}),await an({deletedId:t,deletedReference:d=>h?.[d],findHolders:async(d,w,y)=>{if($.tables[d]?.shardMode?.kind==="shardBy")throw new T("INTERNAL",`cross-backend cascade from global '${o}' into shardBy '${d}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany(d,{includeDeleted:l,where:{[w]:y}})).page},onCascade:(d,w)=>x.delete(w,void 0,i),onRestrict:d=>{throw new Ce(d,"restrict")},onSetNull:(d,w,y)=>x.patch(w,{[y]:null}),schema:$,tableName:o}),await ye(o),await pe(o),E&&h){const d={...h,[E]:m()},w=e.join(Object.keys(s.shape).map(y=>e`${e.identifier(y)} = ${be(s,y,d[y]??null)}`),e`, `);await Se(o,"UPDATE",w,f),await oe(o,h,d),await X(o,t,h,void 0),await se(o,t,d,h),await P(o,t,"update",d),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h,table:o});return}await Se(o,"DELETE",void 0,f),Le.delete(t),await oe(o,h??void 0,void 0),await X(o,t,h??void 0,void 0),await se(o,t,void 0),await P(o,t,"delete"),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h??void 0,table:o})}},async findFirst(t,n={}){return(await x.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const i=await x.findFirst(t,n);if(i===null)throw new sn(`findFirstOrThrow: no "${t}" document matched`);return i},async findMany(t,n={}){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=tn(n.orderBy,i.shape),s=n.cursor?nn(o,on(n.cursor)):void 0,f=Ye,h=async(L,B,j,Te)=>{if(Ge(L))return c?_n(c,L,B,j,Te):Ve(L);const ve=$.tables[L];if(!ve)throw new T("INTERNAL",`unknown table: ${L}`);const me=ue(ve.softDeleteMode,void 0),z={[B]:{in:j}},D=q(q(z,Te),me),ae=await ge(D,L,void 0),Xe=fe(ae,b),ze=O(B);let ce=e`SELECT ${ze} AS __fk__, COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(L)}`;Xe&&(ce=e`${ce} WHERE ${Xe}`),ce=e`${ce} GROUP BY ${ze}`;const Bt=await I(r,u,ce),Qe=new Map;for(const Je of Bt)Qe.set(Je.__fk__,Number(Je.count??0));return Qe};let l=q(n.baseWhere,n.where);l=q(l,ue(i.softDeleteMode,n.includeDeleted)),l=await it(l,{fetcher:f,maxRelationKeys:p,relationBaseWhere:n.relationBaseWhere,schema:$,tableName:t}),s&&(l=l?{AND:[l,s]}:s);const E=fe(l,b),d=bn(o,u);let w=e`SELECT * FROM ${e.identifier(t)}`;E&&(w=e`${w} WHERE ${E}`),w=e`${w} ORDER BY ${d}`;const y=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;y!==void 0&&(w=e`${w} LIMIT ${e.raw(String(y+1))}`);const R=await I(r,u,w),S=dt(i,R);if(y===void 0)return n.with&&await ot({fetcher:f,groupedCounter:h,parents:S,...rt(n),schema:$,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:st(S,n.select,n.with)};const C=S.length>y,A=C?S.slice(0,y):S,F=A.at(-1);return n.with&&await ot({fetcher:f,groupedCounter:h,parents:A,...rt(n),schema:$,tableName:t,with:n.with}),{continueCursor:C&&F?rn(F,o):null,isDone:!C,page:st(A,n.select,n.with)}},async get(t,n){const i=await ne(t,n);if(!i)return null;const o=$.tables[i];return o?Z(o,await Dt.load(i,t)):null},async groupBy(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=n.agg??{op:"count"};if(le(o.op),o.op!=="count"&&!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);const s=ue(i.softDeleteMode,void 0),f=q(q(n.baseWhere,n.where),s),h=await ge(f,t,n.relationBaseWhere),l=h!==f;if(i.aggregateIndexes&&!n.baseWhere&&!l&&!s){const S=await Mt(t,i.aggregateIndexes,o,n);if(S!==void 0)return S}Un(i,t,n.by,o);const E=fe(h,b),d=n.by.map(S=>e`${O(S)} AS ${e.identifier(S)}`);if(o.op==="count")d.push(e`COUNT(*) AS ${e.identifier("value")}`);else{if(!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);d.push(e`${e.raw(le(o.op))}(${O(o.field)}) AS ${e.identifier("value")}`)}const w=e.join(n.by.map(S=>O(S)),e`, `);let y=e`SELECT ${e.join(d,e`, `)} FROM ${e.identifier(t)}`;E&&(y=e`${y} WHERE ${E}`),y=e`${y} GROUP BY ${w}`;const R=await I(r,u,y);return Mn(n.by,R)},async insert(t,n,i){const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);await U();const s=Cn(o,n,V);Ne(o,s);let f,h=!0;i?.clientId!==void 0?(en(i.clientId),f=i.clientId):i?.allowExplicitId&&typeof s._id=="string"?f=s._id:(f=M(),h=!1);const l=i?.allowExplicitId&&typeof s._creationTime=="number"?s._creationTime:m(),E={...s,_creationTime:l,_id:f};H(t,"before","insert")&&await K("before","insert",{doc:{...E},id:f,op:"insert",table:t}),await ye(t),await pe(t);const{columns:d,values:w}=kt(o,f,l,s);return await Lt(t,e`INSERT INTO ${e.identifier(t)} (${J(d)}) VALUES (${te(w)})`),h&&Le.set(f,t),await oe(t,void 0,E),await X(t,f,void 0,E),await se(t,f,E),await P(t,f,"insert",E),H(t,"after","insert")&&await K("after","insert",{doc:E,id:f,op:"insert",table:t}),f},normalizeId(t,n){return Zt($,t,n)},async patch(t,n,i){Ze("patch",n);const o=await ne(t,i);if(!o)throw new T("INTERNAL",`document not found: ${t}`);const s=$.tables[o];if(!s)throw new T("INTERNAL",`document not found: ${t}`);const f=await Re(o,t),h=Z(s,f);if(!h)throw new T("INTERNAL",`document not found: ${t}`);const l={...h,...n,_id:t};_t(s,n,l,V),Ne(s,l,!0),H(o,"before","update")&&await K("before","update",{doc:{...l},id:t,op:"update",previous:h,table:o}),await ye(o),await pe(o);const E=Object.keys(s.shape),d=e.join(E.map(w=>e`${e.identifier(w)} = ${be(s,w,l[w]??null)}`),e`, `);await Se(o,"UPDATE",d,f),await oe(o,h,l),await X(o,t,h,l),await se(o,t,l,h),await P(o,t,"update",l),H(o,"after","update")&&await K("after","update",{doc:l,id:t,op:"update",previous:h,table:o})},async restore(t,n){const i=await ne(t,n);if(!i)throw new T("INTERNAL",`document not found: ${t}`);const o=$.tables[i],s=o?.softDeleteMode?.field;if(!o||!s)throw new T("INTERNAL",`ctx.db.restore: table "${i}" is not a .softDelete() table`);const f=await Re(i,t),h=f?.[s]!==null&&f?.[s]!==void 0;if(await x.patch(t,{[s]:null},n),h){const l=Z(o,f);l!==null&&await X(i,t,void 0,{...l,[s]:null})}},query(t){const n=$.tables[t];if(!n)throw new T("INTERNAL",`unknown table: ${t}`);const i="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",o=[],s=l=>o.every(E=>E(l)),f=async(l,E)=>{await U();const d=o.length>0,w=await Ht(r,u,n,t,l,Kt(d?void 0:E));if(!d)return E===void 0&&jt(w),w;const y=w.filter(R=>s(R));return E===void 0?y:y.slice(0,E)},h=l=>{const E={async*[Symbol.asyncIterator](){if(!l)throw new T("INTERNAL",i);yield*await f(l,void 0)},async collect(){if(!l)throw new T("INTERNAL",i);return f(l,void 0)},async collectWithScores(){throw new T("GLOBAL_SEARCH_SCORES_UNSUPPORTED",`collectWithScores() is not supported on \`.global()\` tables (table "${t}") — relevance scores are not yet surfaced on this backend; use .collect() instead`)},filter(d){return o.push(d),E},async first(){if(!l)throw new T("INTERNAL",i);return(await f(l,1))[0]??null},order(){return E},async paginate(d){if(!l)throw new T("INTERNAL",i);const w=xt(d);return Pt(await f(l,Gt(w)),w)},async take(d){if(!l)throw new T("INTERNAL",i);return f(l,d)},async unique(){if(!l)throw new T("INTERNAL",i);const d=await f(l,2);if(d.length>1)throw new En(`unique() on table "${t}" matched ${String(d.length)} documents; expected at most one`);return d[0]??null},withGeoIndex(){throw new T("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new T("INTERNAL",i)},withSearchIndex(d,w){const y=(n.searchIndexes??[]).find(S=>S.name===d);if(!y)throw new T("INTERNAL",`unknown search index "${d}" on table "${t}"`);const R={definition:y,field:y.field,filters:[],hasQuery:!1,indexName:d,query:""};if(w(Ut(R,t,Ot(y.language))),!R.hasQuery)throw new T("INTERNAL",`search index "${d}" on table "${t}" requires a .search(field, query) call`);return h(R)}};return E};return h(void 0)},async rank(t,n,i){const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(B=>B.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(i.restrictsCounts)throw new nt(t);if(await U(),!await Me(t,s))return null;const h=typeof i.row=="string"?i.row:i.row._id;if(!h)return null;const l=de(t,s.name),E=s.sortBy.map((B,j)=>$e(j)),d=J(["__partition__",...E]),y=(await I(r,u,e`SELECT ${d} FROM ${e.identifier(l)} WHERE ${e.identifier("__id__")} = ${h}`))[0];if(!y)return null;const R=y.__partition__,S=q(i.baseWhere,i.where);et(S,$,t,"rank");const C=tt(s,S);if(C&&Ie(s.partitionBy??[],C)!==R)return null;const A=Dn(u.name,s,E,y,h),F=await I(r,u,e`SELECT COUNT(*) AS c FROM ${e.identifier(l)} WHERE ${e.identifier("__partition__")} = ${R} AND (${A})`),L=await I(r,u,e`SELECT COUNT(*) AS c FROM ${e.identifier(l)} WHERE ${e.identifier("__partition__")} = ${R}`);return{position:Number(F[0]?.c??0)+1,total:Number(L[0]?.c??0)}},async rankPage(t,n,i={}){et(q(i.baseWhere,i.where),$,t,"rankPage");const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(D=>D.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await Me(t,s))return{continueCursor:null,isDone:!0,page:[]};const h=de(t,s.name),l=s.sortBy.map((D,ae)=>$e(ae)),E=Math.max(1,Math.min(1e3,Math.floor(i.take??100))),d=q(i.baseWhere,i.where),w=tt(s,d),y=qn(s,l),R=e.join(y.map(D=>e`${e.identifier(D.column)} ${e.raw(`${D.direction==="desc"?"DESC":"ASC"}${gt(u,{direction:D.direction,nullable:D.nullable})}`)}`),e`, `),S=[];typeof i.partitionKey=="string"?S.push(e`${e.identifier("__partition__")} = ${i.partitionKey}`):w&&S.push(e`${e.identifier("__partition__")} = ${Ie(s.partitionBy??[],w)}`);const C=Jt(i);if(C!==void 0){const D=Bn(u.name,y,C);D!==void 0&&S.push(D)}const A=J([_e,"__partition__",...l]);let F=e`SELECT ${A} FROM ${e.identifier(h)}`;S.length>0&&(F=e`${F} WHERE ${e.join(S,e` AND `)}`),F=e`${F} ORDER BY ${R} LIMIT ${e.raw(String(E+1))}`;const L=await I(r,u,F),B=L.length>E,j=B?L.slice(0,E):L,Te=j.map(D=>D[_e]),ve=await On(r,u,o,t,Te);let me=null;const z=j.at(-1);if(B&&z!==void 0){const D=[z.__partition__,...l.map(ae=>z[ae]),z[_e]];me=Wn(D)}return{continueCursor:me,isDone:!B,page:ve}},async replace(t,n,i,o){Ze("replace",n);const s=await ne(t,i);if(!s)throw new T("INTERNAL",`document not found: ${t}`);const f=$.tables[s];if(!f)throw new T("INTERNAL",`document not found: ${t}`);const h=await Re(s,t);if(h===void 0)throw new T("INTERNAL",`document not found: ${t}`);const E=Qt($,s,"update")||(f.aggregateIndexes??[]).length>0||(f.rankIndexes??[]).length>0?Z(f,h)??void 0:void 0,d=o?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:m(),w={...n,_creationTime:d,_id:t};_t(f,n,w,V),Ne(f,w),H(s,"before","update")&&await K("before","update",{doc:{...w},id:t,op:"update",previous:E,table:s}),await ye(s),await pe(s);const y=Object.keys(f.shape),R=e.join([e`${e.identifier("_creationTime")} = ${d}`,...y.map(S=>e`${e.identifier(S)} = ${be(f,S,w[S]??null)}`)],e`, `);await Se(s,"UPDATE",R,h),await oe(s,E,w),await X(s,t,E,w),await se(s,t,w,E),await P(s,t,"update",w),H(s,"after","update")&&await K("after","update",{doc:w,id:t,op:"update",previous:E,table:s})}};return je={db:x,scheduler:Ae},x};export{fi as backfillSqlSearchIndexes,di as createSqlCtxDb,$i as decodeGlobalRow,Xn as readSqlCdcChangedTables,ci as readSqlCdcChanges,mt as readSqlCdcFloor,Kn as runSqlCdcMigration,Ft as runSqlSearchMigrations,Gn as sweepSqlCdcRetention};
@@ -1 +1 @@
1
- import{LunoraError as l}from"@lunora/errors";import{D as y,c as Z,m as tt,r as R,a as nt,l as W,w as N,b as et}from"./ctx-db-search-state-ClbuTC47.mjs";import{sql as e}from"drizzle-orm";import{unionAll as it}from"@lunora/shard-engine";import{queryRun as E,decodeRows as Q,queryAll as A,queryBatch as rt,createIndexIfNotExists as q,columnRefSql as M,serializeColumnValue as ot,forEachRowPaged as G}from"./decodeGlobalRow-DVG7FHVz.mjs";const st=t=>{const n=atob(t),i=Uint8Array.from(n,r=>r.codePointAt(0)??0);return new TextDecoder().decode(i)},at=()=>new l("BAD_REQUEST","invalid cursor"),F=16,k=8,h=1024,v=(t,n)=>n.query(t),ft=(t,n)=>{if(!n)return{exact:!0,lower:t,upper:t};const i=[...t].at(-1)??"",r=(i.codePointAt(0)??0)+1;if(r>=55296&&r<=57343||r>1114111)return{exact:!0,lower:t,upper:t};const o=t.slice(0,t.length-i.length);return{exact:!1,lower:t,upper:o+String.fromCodePoint(r)}},Lt=(t,n,i)=>{const r={eq:(o,s)=>{if(!t.definition.filterFields?.includes(o))throw new l("INTERNAL",`field "${o}" is not a filter field of search index "${t.indexName}" on table "${n}"`);if(t.filters.length>=k)throw new l("BAD_REQUEST",`search index "${t.indexName}" on table "${n}": at most ${String(k)} .eq() filters are supported per search query`);return t.filters.push({field:o,value:s}),r},search:(o,s)=>{const a=t;if(o!==a.definition.field)throw new l("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${o}"`);const f=v(s,i).length;if(f>F)throw new l("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(F)} search terms are supported (got ${String(f)})`);return a.field=o,a.query=s,a.hasQuery=!0,r}};return r},Ot=t=>{if(t.length>h)throw new l("BAD_REQUEST",`more than ${String(h)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},xt=t=>Math.min(t.offset+t.numItems+1,h),ct=t=>btoa(`search:${String(t)}`),ut=t=>{let n;try{n=st(t)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ut=t=>{if(typeof t.endCursor=="string")throw new l("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(t.numItems))throw new l("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(t.numItems)}`);const n=Math.max(0,Math.floor(t.numItems)),i=t.cursor?ut(t.cursor):0;if(i===void 0)throw at();if(i+n>=h)throw new l("BAD_REQUEST",`search pagination reaches the ${String(h)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,h-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},Bt=(t,n)=>{const i=n.offset+n.numItems,r=n.numItems>0&&t.length>i;return{continueCursor:r?ct(i):null,isDone:!r,page:t.slice(n.offset,i)}},qt=t=>{if(t===void 0)return h+1;if(!Number.isFinite(t))return h;const n=Math.max(0,Math.floor(t));if(n>h)throw new l("BAD_REQUEST",`search returns at most ${String(h)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},dt=(t,n)=>{if(!n.includes("."))return t[n];let i=t;for(const r of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[r]}return i},b=(t,n)=>`${t}__fts_${n}`,$t="__text__",$="__id__",g="__token__",O="__n__",mt=1e3,V=(t,n)=>n.document(t),x=(t,n)=>dt(t,n),lt=t=>typeof t=="string"?t:t==null?"":typeof t=="number"||typeof t=="bigint"||typeof t=="boolean"?String(t):JSON.stringify(t)??"",St=(t,n,i)=>t!==void 0&&n!==void 0&&x(t,i.field)===x(n,i.field),ht=(t,n)=>V(lt(x(t,n.field)),y(n.language)).slice(0,mt),U=(t,n)=>ht(t,n).join(" "),wt=(t,n)=>{const i=new Map;for(const r of V(t,n))i.set(r,(i.get(r)??0)+1);return i},C=async(t,n,i,r)=>{await E(t,n,e`DELETE FROM ${e.identifier(i)} WHERE ${e.identifier($)} = ${r}`)},L=(t,n)=>t.name==="mysql"?e`${e.identifier(n)}(191)`:t.textPatternOperatorClass===void 0?e`${e.identifier(n)}`:e`${e.identifier(n)} ${e.raw(t.textPatternOperatorClass)}`,H=50,Et=(t,n)=>n?e`${e.identifier(g)} LIKE ${`${t}%`}`:e`${e.identifier(g)} = ${t}`,X=(t,n)=>{const i=n.filters.map(r=>e`m.${M(r.field)} = ${ot(r.value)}`);return t.softDeleteMode&&i.push(e`m.${M(t.softDeleteMode.field)} IS NULL`),i},J=async(t,n,i,r,o,s,a)=>{const f=X(i,o);let c=e`SELECT m.* FROM (${a}) s JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = s.${e.identifier($)}`;return f.length>0&&(c=e`${c} WHERE ${e.join(f,e` AND `)}`),c=e`${c} ORDER BY s.${e.identifier("__score__")} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`,Q(i,await A(t,n,c))},pt=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=a.length-1,u=a.map((d,_)=>Et(d,_===c)),m=e.join(u,e` OR `),S=u.map(d=>e`SUM(CASE WHEN ${d} THEN ${e.identifier(O)} ELSE 0 END)`),p=e.join(S.map(d=>e`${d} > 0`),e` AND `),w=e`SELECT ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM ${e.identifier(f)} WHERE ${m} GROUP BY ${e.identifier($)} HAVING ${p}`;return J(t,n,i,r,o,s,w)},_t=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=`${f}__vocab`,u=a.length-1,m=a.map((w,d)=>{const _=ft(w,d===u),z=_.exact?e`${e.identifier("term")} = ${_.lower}`:e`${e.identifier("term")} >= ${_.lower} AND ${e.identifier("term")} < ${_.upper}`;return e`SELECT ${e.identifier("doc")}, ${e.raw(String(d))} AS ${e.identifier("__term__")}, COUNT(*) AS ${e.identifier("__n__")} FROM ${e.identifier(c)} WHERE ${z} GROUP BY ${e.identifier("doc")}`}),S=a.map((w,d)=>e`SUM(CASE WHEN u.${e.identifier("__term__")} = ${e.raw(String(d))} THEN u.${e.identifier("__n__")} ELSE 0 END)`),p=e`SELECT f.${e.identifier($)} AS ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM (${it(m)}) u JOIN ${e.identifier(f)} f ON f.rowid = u.${e.identifier("doc")} GROUP BY f.${e.identifier($)} HAVING ${e.join(S.map(w=>e`${w} > 0`),e` AND `)}`;return J(t,n,i,r,o,s,p)},gt=async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch,f=v(o.query,y(o.definition.language));if(!a||f.length===0)return[];const c=b(r,o.indexName),u=[a.matches(c,f),...X(i,o)],m=e`SELECT m.* FROM ${e.identifier(c)} JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = ${e.identifier(c)}.${e.identifier($)} WHERE ${e.join(u,e` AND `)} ORDER BY ${a.rank(c,f)} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`;return Q(i,await A(t,n,m))},yt={ensureCompanion:async(t,n,i)=>{const{integer:r,key:o}=n.companionTypes;await E(t,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${e.identifier(g)} ${e.raw(o)} NOT NULL, ${e.identifier($)} ${e.raw(o)} NOT NULL, ${e.identifier(O)} ${e.raw(r)} NOT NULL)`),await q(t,n,{columns:e`${L(n,g)}, ${L(n,$)}`,name:`${i}__btree`,table:i,unique:!1}),await q(t,n,{columns:L(n,$),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r);const a=[...wt(U(o,s),y(s.language))],f=e.join([g,$,O].map(u=>e.identifier(u)),e`, `),c=[];for(let u=0;u<a.length;u+=H){const m=e.join(a.slice(u,u+H).map(([S,p])=>e`(${S}, ${r}, ${p})`),e`, `);c.push(e`INSERT INTO ${e.identifier(i)} (${f}) VALUES ${m}`)}await rt(t,n,c)},name:"inverted",runSearch:pt},Tt={ensureCompanion:async(t,n,i)=>{await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(i)} USING fts5(${e.identifier($t)}, ${e.identifier($)} UNINDEXED)`),await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(`${i}__vocab`)} USING fts5vocab(${e.identifier(i)}, ${e.raw("instance")})`)},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r),await E(t,n,e`INSERT INTO ${e.identifier(i)} (${e.identifier("__text__")}, ${e.identifier($)}) VALUES (${U(o,s)}, ${r})`)},name:"fts5",runSearch:_t},It={ensureCompanion:async(t,n,i)=>{const r=n.nativeTextSearch;if(r){await E(t,n,r.createCompanion(i,n.companionTypes.key));for(const o of r.createIndexes(i))await E(t,n,o)}},indexDocument:async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch;a&&(await C(t,n,i,r),await E(t,n,a.indexDocument(i,r,U(o,s))))},name:"native",runSearch:gt},T=(t,n)=>t.strategy==="native"&&n.nativeTextSearch!==void 0?It:n.supportsFts5?Tt:yt,D=(t,n)=>`${Z(t)}/${T(t,n).name}`,B=function*(t){for(const[n,i]of Object.entries(t.tables)){const r=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!r))for(const o of r)yield[n,i,o]}},I=(t,n)=>b(t,n.name),Nt=async(t,n,i,r)=>{const o=I(i,r);return W(await R(t,n,o),D(r,n)).finished?!0:et(t,n,o)},Mt=async(t,n,i,r,o,s)=>{if(!await Nt(t,n,r,o.definition))throw new l("SEARCH_INDEX_BUILDING",`search index "${o.indexName}" on table "${r}" is still backfilling and currently covers only part of the table — retry once it finishes, or run the backfillSearch admin operation to complete it now`);return T(o.definition,n).runSearch(t,n,i,r,o,s)},P=t=>t.slice(t.lastIndexOf("/")+1),j=200,Y=async(t,n,i,r,o)=>{const s=I(r,o),a=T(o,n),f=D(o,n),c=W(await R(t,n,s),f);if(c.finished)return!0;if(c.wipe&&await N(t,n,s,void 0,!1,f),(await A(t,n,n.tableExists(r))).length===0)return await N(t,n,s,void 0,!0,f),!0;let m=0,S=c.cursor;await G(t,n,i,r,async w=>{m+=1;const d=w._id;typeof d=="string"&&(S=d,await a.indexDocument(t,n,s,d,w,o))},{after:c.cursor,limit:j});const p=m<j;return await N(t,n,s,S,p,f),p},K=async(t,n,i)=>{await tt(t,i);for(const[r,,o]of B(n)){const s=I(r,o),a=D(o,i),f=await R(t,i,s);f.profile!==void 0&&P(f.profile)!==P(a)&&(await E(t,i,e`DROP TABLE IF EXISTS ${e.identifier(s)}`),await nt(t,i,s)),await T(o,i).ensureCompanion(t,i,s)}},Rt=async(t,n,i,r,o)=>{const s=I(r,o);if((await R(t,n,s)).profile!==void 0)return;let f=0;(await A(t,n,n.tableExists(r))).length>0&&await G(t,n,i,r,()=>{f+=1},{limit:1}),await N(t,n,s,void 0,f===0,D(o,n))},Ft=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){if(s.staged){await Rt(t,i,o,r,s);continue}await Y(t,i,o,r,s)}},kt=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){let a=!1;for(;!a;)a=await Y(t,i,o,r,s)}},Ht=t=>{const{dialect:n,exec:i,schema:r}=t;return async(o,s,a,f)=>{const c=r.tables[o]?.searchIndexes;if(!(!c||c.length===0))for(const u of c){if(St(f,a,u))continue;const m=I(o,u);if(a){await T(u,n).indexDocument(i,n,m,s,a,u);continue}await C(i,n,m,s)}}};export{Lt as A,Ut as C,Bt as R,qt as T,Mt as a,xt as b,Ht as c,kt as d,Ft as r,Ot as x};
1
+ import{LunoraError as l}from"@lunora/errors";import{D as y,c as Z,m as tt,r as R,a as nt,l as W,w as N,b as et}from"./ctx-db-search-state-C0hUwzYJ.mjs";import{sql as e}from"drizzle-orm";import{unionAll as it}from"@lunora/shard-engine";import{queryRun as E,decodeRows as Q,queryAll as A,queryBatch as rt,createIndexIfNotExists as q,columnRefSql as M,serializeColumnValue as ot,forEachRowPaged as G}from"./decodeGlobalRow-B6zmyAi5.mjs";const st=t=>{const n=atob(t),i=Uint8Array.from(n,r=>r.codePointAt(0)??0);return new TextDecoder().decode(i)},at=()=>new l("BAD_REQUEST","invalid cursor"),F=16,k=8,h=1024,v=(t,n)=>n.query(t),ft=(t,n)=>{if(!n)return{exact:!0,lower:t,upper:t};const i=[...t].at(-1)??"",r=(i.codePointAt(0)??0)+1;if(r>=55296&&r<=57343||r>1114111)return{exact:!0,lower:t,upper:t};const o=t.slice(0,t.length-i.length);return{exact:!1,lower:t,upper:o+String.fromCodePoint(r)}},Lt=(t,n,i)=>{const r={eq:(o,s)=>{if(!t.definition.filterFields?.includes(o))throw new l("INTERNAL",`field "${o}" is not a filter field of search index "${t.indexName}" on table "${n}"`);if(t.filters.length>=k)throw new l("BAD_REQUEST",`search index "${t.indexName}" on table "${n}": at most ${String(k)} .eq() filters are supported per search query`);return t.filters.push({field:o,value:s}),r},search:(o,s)=>{const a=t;if(o!==a.definition.field)throw new l("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${o}"`);const f=v(s,i).length;if(f>F)throw new l("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(F)} search terms are supported (got ${String(f)})`);return a.field=o,a.query=s,a.hasQuery=!0,r}};return r},Ot=t=>{if(t.length>h)throw new l("BAD_REQUEST",`more than ${String(h)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},xt=t=>Math.min(t.offset+t.numItems+1,h),ct=t=>btoa(`search:${String(t)}`),ut=t=>{let n;try{n=st(t)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ut=t=>{if(typeof t.endCursor=="string")throw new l("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(t.numItems))throw new l("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(t.numItems)}`);const n=Math.max(0,Math.floor(t.numItems)),i=t.cursor?ut(t.cursor):0;if(i===void 0)throw at();if(i+n>=h)throw new l("BAD_REQUEST",`search pagination reaches the ${String(h)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,h-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},Bt=(t,n)=>{const i=n.offset+n.numItems,r=n.numItems>0&&t.length>i;return{continueCursor:r?ct(i):null,isDone:!r,page:t.slice(n.offset,i)}},qt=t=>{if(t===void 0)return h+1;if(!Number.isFinite(t))return h;const n=Math.max(0,Math.floor(t));if(n>h)throw new l("BAD_REQUEST",`search returns at most ${String(h)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},dt=(t,n)=>{if(!n.includes("."))return t[n];let i=t;for(const r of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[r]}return i},b=(t,n)=>`${t}__fts_${n}`,$t="__text__",$="__id__",g="__token__",O="__n__",mt=1e3,V=(t,n)=>n.document(t),x=(t,n)=>dt(t,n),lt=t=>typeof t=="string"?t:t==null?"":typeof t=="number"||typeof t=="bigint"||typeof t=="boolean"?String(t):JSON.stringify(t)??"",St=(t,n,i)=>t!==void 0&&n!==void 0&&x(t,i.field)===x(n,i.field),ht=(t,n)=>V(lt(x(t,n.field)),y(n.language)).slice(0,mt),U=(t,n)=>ht(t,n).join(" "),wt=(t,n)=>{const i=new Map;for(const r of V(t,n))i.set(r,(i.get(r)??0)+1);return i},C=async(t,n,i,r)=>{await E(t,n,e`DELETE FROM ${e.identifier(i)} WHERE ${e.identifier($)} = ${r}`)},L=(t,n)=>t.name==="mysql"?e`${e.identifier(n)}(191)`:t.textPatternOperatorClass===void 0?e`${e.identifier(n)}`:e`${e.identifier(n)} ${e.raw(t.textPatternOperatorClass)}`,H=50,Et=(t,n)=>n?e`${e.identifier(g)} LIKE ${`${t}%`}`:e`${e.identifier(g)} = ${t}`,X=(t,n)=>{const i=n.filters.map(r=>e`m.${M(r.field)} = ${ot(r.value)}`);return t.softDeleteMode&&i.push(e`m.${M(t.softDeleteMode.field)} IS NULL`),i},J=async(t,n,i,r,o,s,a)=>{const f=X(i,o);let c=e`SELECT m.* FROM (${a}) s JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = s.${e.identifier($)}`;return f.length>0&&(c=e`${c} WHERE ${e.join(f,e` AND `)}`),c=e`${c} ORDER BY s.${e.identifier("__score__")} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`,Q(i,await A(t,n,c))},pt=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=a.length-1,u=a.map((d,_)=>Et(d,_===c)),m=e.join(u,e` OR `),S=u.map(d=>e`SUM(CASE WHEN ${d} THEN ${e.identifier(O)} ELSE 0 END)`),p=e.join(S.map(d=>e`${d} > 0`),e` AND `),w=e`SELECT ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM ${e.identifier(f)} WHERE ${m} GROUP BY ${e.identifier($)} HAVING ${p}`;return J(t,n,i,r,o,s,w)},_t=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=`${f}__vocab`,u=a.length-1,m=a.map((w,d)=>{const _=ft(w,d===u),z=_.exact?e`${e.identifier("term")} = ${_.lower}`:e`${e.identifier("term")} >= ${_.lower} AND ${e.identifier("term")} < ${_.upper}`;return e`SELECT ${e.identifier("doc")}, ${e.raw(String(d))} AS ${e.identifier("__term__")}, COUNT(*) AS ${e.identifier("__n__")} FROM ${e.identifier(c)} WHERE ${z} GROUP BY ${e.identifier("doc")}`}),S=a.map((w,d)=>e`SUM(CASE WHEN u.${e.identifier("__term__")} = ${e.raw(String(d))} THEN u.${e.identifier("__n__")} ELSE 0 END)`),p=e`SELECT f.${e.identifier($)} AS ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM (${it(m)}) u JOIN ${e.identifier(f)} f ON f.rowid = u.${e.identifier("doc")} GROUP BY f.${e.identifier($)} HAVING ${e.join(S.map(w=>e`${w} > 0`),e` AND `)}`;return J(t,n,i,r,o,s,p)},gt=async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch,f=v(o.query,y(o.definition.language));if(!a||f.length===0)return[];const c=b(r,o.indexName),u=[a.matches(c,f),...X(i,o)],m=e`SELECT m.* FROM ${e.identifier(c)} JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = ${e.identifier(c)}.${e.identifier($)} WHERE ${e.join(u,e` AND `)} ORDER BY ${a.rank(c,f)} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`;return Q(i,await A(t,n,m))},yt={ensureCompanion:async(t,n,i)=>{const{integer:r,key:o}=n.companionTypes;await E(t,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${e.identifier(g)} ${e.raw(o)} NOT NULL, ${e.identifier($)} ${e.raw(o)} NOT NULL, ${e.identifier(O)} ${e.raw(r)} NOT NULL)`),await q(t,n,{columns:e`${L(n,g)}, ${L(n,$)}`,name:`${i}__btree`,table:i,unique:!1}),await q(t,n,{columns:L(n,$),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r);const a=[...wt(U(o,s),y(s.language))],f=e.join([g,$,O].map(u=>e.identifier(u)),e`, `),c=[];for(let u=0;u<a.length;u+=H){const m=e.join(a.slice(u,u+H).map(([S,p])=>e`(${S}, ${r}, ${p})`),e`, `);c.push(e`INSERT INTO ${e.identifier(i)} (${f}) VALUES ${m}`)}await rt(t,n,c)},name:"inverted",runSearch:pt},Tt={ensureCompanion:async(t,n,i)=>{await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(i)} USING fts5(${e.identifier($t)}, ${e.identifier($)} UNINDEXED)`),await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(`${i}__vocab`)} USING fts5vocab(${e.identifier(i)}, ${e.raw("instance")})`)},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r),await E(t,n,e`INSERT INTO ${e.identifier(i)} (${e.identifier("__text__")}, ${e.identifier($)}) VALUES (${U(o,s)}, ${r})`)},name:"fts5",runSearch:_t},It={ensureCompanion:async(t,n,i)=>{const r=n.nativeTextSearch;if(r){await E(t,n,r.createCompanion(i,n.companionTypes.key));for(const o of r.createIndexes(i))await E(t,n,o)}},indexDocument:async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch;a&&(await C(t,n,i,r),await E(t,n,a.indexDocument(i,r,U(o,s))))},name:"native",runSearch:gt},T=(t,n)=>t.strategy==="native"&&n.nativeTextSearch!==void 0?It:n.supportsFts5?Tt:yt,D=(t,n)=>`${Z(t)}/${T(t,n).name}`,B=function*(t){for(const[n,i]of Object.entries(t.tables)){const r=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!r))for(const o of r)yield[n,i,o]}},I=(t,n)=>b(t,n.name),Nt=async(t,n,i,r)=>{const o=I(i,r);return W(await R(t,n,o),D(r,n)).finished?!0:et(t,n,o)},Mt=async(t,n,i,r,o,s)=>{if(!await Nt(t,n,r,o.definition))throw new l("SEARCH_INDEX_BUILDING",`search index "${o.indexName}" on table "${r}" is still backfilling and currently covers only part of the table — retry once it finishes, or run the backfillSearch admin operation to complete it now`);return T(o.definition,n).runSearch(t,n,i,r,o,s)},P=t=>t.slice(t.lastIndexOf("/")+1),j=200,Y=async(t,n,i,r,o)=>{const s=I(r,o),a=T(o,n),f=D(o,n),c=W(await R(t,n,s),f);if(c.finished)return!0;if(c.wipe&&await N(t,n,s,void 0,!1,f),(await A(t,n,n.tableExists(r))).length===0)return await N(t,n,s,void 0,!0,f),!0;let m=0,S=c.cursor;await G(t,n,i,r,async w=>{m+=1;const d=w._id;typeof d=="string"&&(S=d,await a.indexDocument(t,n,s,d,w,o))},{after:c.cursor,limit:j});const p=m<j;return await N(t,n,s,S,p,f),p},K=async(t,n,i)=>{await tt(t,i);for(const[r,,o]of B(n)){const s=I(r,o),a=D(o,i),f=await R(t,i,s);f.profile!==void 0&&P(f.profile)!==P(a)&&(await E(t,i,e`DROP TABLE IF EXISTS ${e.identifier(s)}`),await nt(t,i,s)),await T(o,i).ensureCompanion(t,i,s)}},Rt=async(t,n,i,r,o)=>{const s=I(r,o);if((await R(t,n,s)).profile!==void 0)return;let f=0;(await A(t,n,n.tableExists(r))).length>0&&await G(t,n,i,r,()=>{f+=1},{limit:1}),await N(t,n,s,void 0,f===0,D(o,n))},Ft=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){if(s.staged){await Rt(t,i,o,r,s);continue}await Y(t,i,o,r,s)}},kt=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){let a=!1;for(;!a;)a=await Y(t,i,o,r,s)}},Ht=t=>{const{dialect:n,exec:i,schema:r}=t;return async(o,s,a,f)=>{const c=r.tables[o]?.searchIndexes;if(!(!c||c.length===0))for(const u of c){if(St(f,a,u))continue;const m=I(o,u);if(a){await T(u,n).indexDocument(i,n,m,s,a,u);continue}await C(i,n,m,s)}}};export{Lt as A,Ut as C,Bt as R,qt as T,Mt as a,xt as b,Ht as c,kt as d,Ft as r,Ot as x};
@@ -1 +1 @@
1
- import{sql as e}from"drizzle-orm";import{queryRun as p,queryAll as m}from"./decodeGlobalRow-DVG7FHVz.mjs";const y=["de","en","es","fr","it","nl","none","pt"],L=i=>y.includes(i),A="a an and are as at be but by for if in into is it no not of on or such that the their then there these they this to was will with",R="aber als am an auch auf aus bei bin bis bist da dass der den des dem die das denn dir du ein eine für hat ich im in ist mit nicht noch nur oder sich sie sind über und von vor war wie wir zu zum zur",F="a al como con de del el en es la las lo los mas no o para pero por que se su sus un una uno y ya",N="au aux avec ce ces dans de des du elle en et eux il je la le les leur lui ma mais me même mes moi mon ne nos notre nous on ou par pas pour qu que qui sa se ses son sur ta te tes toi ton tu un une vos votre vous y",_="a ai al alla anche che chi ci coi col come con da dal degli dei del della di do e ed gli ha hai hanno i il in la le lo ma mi ne nei nel non o per più quale quanto se si sono su sul tra un una uno vi",q="aan al als bij dan dat de der deze die dit door een en er het hij ij in is je kan me men met mij na naar niet nog nu of om ons ook op over te tot uit van voor was wat we wij zij zijn zo",x="a ao aos as até com como da das de do dos e em entre era essa esse esta este eu foi há isso já mais mas me mesmo meu na nas no nos num numa o os ou para pela pelo por qual que quem se sem seu só sua também te tem um uma você",C=new RegExp("(?<=\\p{Script=Cyrillic})[\\u0300-\\u0305\\u0307\\u0309-\\u036F]|(?<!\\p{Script=Cyrillic})[\\u0300-\\u036F]","gu"),O=/[\u0080-\u{10FFFF}]/u,b=/[\p{L}\p{N}]+/gu,H=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]+/gu,g=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u,D=i=>{if(!g.test(i))return[i];const n=[];let t=0;for(const r of i.matchAll(H)){const o=r.index,s=[...r[0]];if(o>t&&n.push(i.slice(t,o)),t=o+r[0].length,s.length===1){n.push(r[0]);continue}for(let a=0;a+1<s.length;a+=1)n.push(`${String(s[a])}${String(s[a+1])}`)}return t<i.length&&n.push(i.slice(t)),n},v=i=>O.test(i)?i.normalize("NFD").replaceAll(C,"").normalize("NFC").toLowerCase():i.toLowerCase(),f=i=>new Set(v(i).split(" ")),j={de:f(R),en:f(A),es:f(F),fr:f(N),it:f(_),nl:f(q),none:new Set,pt:f(x)},z=3,U=256,w=new Map,k=i=>{const n=i!==void 0&&L(i)?i:"none",t=w.get(n);if(t)return t;const r=j[n],o=a=>{const d=v(a),$=d.match(b)??[],u=(g.test(d)?$.flatMap(l=>D(l)):$).filter(l=>l.length<=U);return r.size===0?u:u.filter(l=>!r.has(l))},s={document:o,profile:`${n}-v${String(z)}`,query:a=>{const d=o(a);return d.filter(($,u)=>d.lastIndexOf($)===u)}};return w.set(n,s),s},W=i=>`${k(i.language).profile}:${i.field}`,S=i=>{const n=i.slice(i.indexOf(":")+1),t=n.lastIndexOf("/");return t===-1?n:n.slice(0,t)},V=(i,n)=>i.profile!==n?{cursor:void 0,finished:!1,wipe:i.cursor!==void 0||i.done}:{cursor:i.cursor,finished:i.done,wipe:!1},I=(i,n)=>typeof i=="string"&&S(i)===S(n),c="__lunora_search_state",K=async(i,n)=>{const{integer:t,key:r}=n.companionTypes,o=async(s,a)=>{try{await p(i,n,e`ALTER TABLE ${e.identifier(c)} ADD COLUMN ${e.identifier(s)} ${e.raw(a)}`)}catch{}};await p(i,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(c)} (${e.identifier("companion")} ${e.raw(r)} PRIMARY KEY, ${e.identifier("cursor")} ${e.raw(r)}, ${e.identifier("done")} ${e.raw(t)} NOT NULL DEFAULT 0, ${e.identifier("profile")} ${e.raw(r)}, ${e.identifier("covered")} ${e.raw(t)} NOT NULL DEFAULT 0)`),await o("profile",r),await o("covered",`${t} NOT NULL DEFAULT 0`),await p(i,n,e`UPDATE ${e.identifier(c)} SET ${e.identifier("covered")} = 1 WHERE ${e.identifier("done")} = 1 AND ${e.identifier("covered")} = 0`)},T=i=>i===1||i===!0||i==="1",P=async(i,n,t)=>{const r=await m(i,n,e`SELECT ${e.identifier("covered")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`);return T(r[0]?.covered)},Y=async(i,n,t)=>{await p(i,n,e`DELETE FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`)},X=async(i,n,t)=>{const o=(await m(i,n,e`SELECT ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`))[0];if(!o)return{cursor:void 0,done:!1,profile:void 0};const{cursor:s,profile:a}=o;return{cursor:typeof s=="string"?s:void 0,done:T(o.done),profile:typeof a=="string"?a:void 0}},G=async(i,n,t,r,o,s)=>{const a=r??null,d=await m(i,n,e`SELECT ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`),$=I(d[0]?.profile,s),u=o?1:0,l=o||!$?e`${e.identifier("covered")} = ${u}`:e`${e.identifier("covered")} = ${e.identifier("covered")}`,h=e`UPDATE ${e.identifier(c)} SET ${e.identifier("cursor")} = ${a}, ${e.identifier("done")} = ${u}, ${e.identifier("profile")} = ${s}, ${l} WHERE ${e.identifier("companion")} = ${t}`;if(d.length>0){await p(i,n,h);return}try{await p(i,n,e`INSERT INTO ${e.identifier(c)} (${e.identifier("companion")}, ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")}, ${e.identifier("covered")}) VALUES (${t}, ${a}, ${o?1:0}, ${s}, ${o?1:0})`)}catch(E){if(!n.isUniqueViolation(E))throw E;await p(i,n,h)}};export{k as D,c as S,Y as a,P as b,W as c,V as l,K as m,X as r,G as w};
1
+ import{sql as e}from"drizzle-orm";import{queryRun as p,queryAll as m}from"./decodeGlobalRow-B6zmyAi5.mjs";const y=["de","en","es","fr","it","nl","none","pt"],L=i=>y.includes(i),A="a an and are as at be but by for if in into is it no not of on or such that the their then there these they this to was will with",R="aber als am an auch auf aus bei bin bis bist da dass der den des dem die das denn dir du ein eine für hat ich im in ist mit nicht noch nur oder sich sie sind über und von vor war wie wir zu zum zur",F="a al como con de del el en es la las lo los mas no o para pero por que se su sus un una uno y ya",N="au aux avec ce ces dans de des du elle en et eux il je la le les leur lui ma mais me même mes moi mon ne nos notre nous on ou par pas pour qu que qui sa se ses son sur ta te tes toi ton tu un une vos votre vous y",_="a ai al alla anche che chi ci coi col come con da dal degli dei del della di do e ed gli ha hai hanno i il in la le lo ma mi ne nei nel non o per più quale quanto se si sono su sul tra un una uno vi",q="aan al als bij dan dat de der deze die dit door een en er het hij ij in is je kan me men met mij na naar niet nog nu of om ons ook op over te tot uit van voor was wat we wij zij zijn zo",x="a ao aos as até com como da das de do dos e em entre era essa esse esta este eu foi há isso já mais mas me mesmo meu na nas no nos num numa o os ou para pela pelo por qual que quem se sem seu só sua também te tem um uma você",C=new RegExp("(?<=\\p{Script=Cyrillic})[\\u0300-\\u0305\\u0307\\u0309-\\u036F]|(?<!\\p{Script=Cyrillic})[\\u0300-\\u036F]","gu"),O=/[\u0080-\u{10FFFF}]/u,b=/[\p{L}\p{N}]+/gu,H=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]+/gu,g=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u,D=i=>{if(!g.test(i))return[i];const n=[];let t=0;for(const r of i.matchAll(H)){const o=r.index,s=[...r[0]];if(o>t&&n.push(i.slice(t,o)),t=o+r[0].length,s.length===1){n.push(r[0]);continue}for(let a=0;a+1<s.length;a+=1)n.push(`${String(s[a])}${String(s[a+1])}`)}return t<i.length&&n.push(i.slice(t)),n},v=i=>O.test(i)?i.normalize("NFD").replaceAll(C,"").normalize("NFC").toLowerCase():i.toLowerCase(),f=i=>new Set(v(i).split(" ")),j={de:f(R),en:f(A),es:f(F),fr:f(N),it:f(_),nl:f(q),none:new Set,pt:f(x)},z=3,U=256,w=new Map,k=i=>{const n=i!==void 0&&L(i)?i:"none",t=w.get(n);if(t)return t;const r=j[n],o=a=>{const d=v(a),$=d.match(b)??[],u=(g.test(d)?$.flatMap(l=>D(l)):$).filter(l=>l.length<=U);return r.size===0?u:u.filter(l=>!r.has(l))},s={document:o,profile:`${n}-v${String(z)}`,query:a=>{const d=o(a);return d.filter(($,u)=>d.lastIndexOf($)===u)}};return w.set(n,s),s},W=i=>`${k(i.language).profile}:${i.field}`,S=i=>{const n=i.slice(i.indexOf(":")+1),t=n.lastIndexOf("/");return t===-1?n:n.slice(0,t)},V=(i,n)=>i.profile!==n?{cursor:void 0,finished:!1,wipe:i.cursor!==void 0||i.done}:{cursor:i.cursor,finished:i.done,wipe:!1},I=(i,n)=>typeof i=="string"&&S(i)===S(n),c="__lunora_search_state",K=async(i,n)=>{const{integer:t,key:r}=n.companionTypes,o=async(s,a)=>{try{await p(i,n,e`ALTER TABLE ${e.identifier(c)} ADD COLUMN ${e.identifier(s)} ${e.raw(a)}`)}catch{}};await p(i,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(c)} (${e.identifier("companion")} ${e.raw(r)} PRIMARY KEY, ${e.identifier("cursor")} ${e.raw(r)}, ${e.identifier("done")} ${e.raw(t)} NOT NULL DEFAULT 0, ${e.identifier("profile")} ${e.raw(r)}, ${e.identifier("covered")} ${e.raw(t)} NOT NULL DEFAULT 0)`),await o("profile",r),await o("covered",`${t} NOT NULL DEFAULT 0`),await p(i,n,e`UPDATE ${e.identifier(c)} SET ${e.identifier("covered")} = 1 WHERE ${e.identifier("done")} = 1 AND ${e.identifier("covered")} = 0`)},T=i=>i===1||i===!0||i==="1",P=async(i,n,t)=>{const r=await m(i,n,e`SELECT ${e.identifier("covered")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`);return T(r[0]?.covered)},Y=async(i,n,t)=>{await p(i,n,e`DELETE FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`)},X=async(i,n,t)=>{const o=(await m(i,n,e`SELECT ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`))[0];if(!o)return{cursor:void 0,done:!1,profile:void 0};const{cursor:s,profile:a}=o;return{cursor:typeof s=="string"?s:void 0,done:T(o.done),profile:typeof a=="string"?a:void 0}},G=async(i,n,t,r,o,s)=>{const a=r??null,d=await m(i,n,e`SELECT ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`),$=I(d[0]?.profile,s),u=o?1:0,l=o||!$?e`${e.identifier("covered")} = ${u}`:e`${e.identifier("covered")} = ${e.identifier("covered")}`,h=e`UPDATE ${e.identifier(c)} SET ${e.identifier("cursor")} = ${a}, ${e.identifier("done")} = ${u}, ${e.identifier("profile")} = ${s}, ${l} WHERE ${e.identifier("companion")} = ${t}`;if(d.length>0){await p(i,n,h);return}try{await p(i,n,e`INSERT INTO ${e.identifier(c)} (${e.identifier("companion")}, ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")}, ${e.identifier("covered")}) VALUES (${t}, ${a}, ${o?1:0}, ${s}, ${o?1:0})`)}catch(E){if(!n.isUniqueViolation(E))throw E;await p(i,n,h)}};export{k as D,c as S,Y as a,P as b,W as c,V as l,K as m,X as r,G as w};
@@ -1 +1 @@
1
- import{bigintSqlKey as o}from"@lunora/shard-engine";import{B as a,c as i,e as n,a as r,s as c,t as d}from"./value-codec-ByV_h-TJ.mjs";export{a as BIGINT_KEY_LENGTH,o as bigintSqlKey,i as decodeBigint,n as effectiveColumnKind,r as sqliteDecode,c as sqliteEncode,d as tryJsonParse};
1
+ import{bigintSqlKey as o}from"@lunora/shard-engine";import{B as a,c as i,e as n,a as r,s as c,t as d}from"./value-codec-nCDJEXH_.mjs";export{a as BIGINT_KEY_LENGTH,o as bigintSqlKey,i as decodeBigint,n as effectiveColumnKind,r as sqliteDecode,c as sqliteEncode,d as tryJsonParse};
@@ -0,0 +1 @@
1
+ import{renderSql as d}from"@lunora/shard-engine";import{sql as r}from"drizzle-orm";import{s as R,a as q,e as y}from"./value-codec-nCDJEXH_.mjs";const K="_version",O=n=>n==="_id"||n==="id"?"id":n,k=n=>r`${r.identifier(O(n))}`,D=n=>{const t=[];for(const[e,o]of Object.entries(n.shape)){const i=o._meta?.column;i&&t.push([e,i])}return t},b=(n,t,e)=>{const{params:o,sql:i}=d(t.name,e);return n.all(i,o)},u=(n,t,e)=>{const{params:o,sql:i}=d(t.name,e);return n.run(i,o)},B=async(n,t,e)=>{if(e.length!==0){if(!n.batch){for(const o of e)await u(n,t,o);return}await n.batch(e.map(o=>d(t.name,o)))}},F=async(n,t,e)=>{const o=e.unique?r`UNIQUE `:r``;if(t.name==="mysql"){try{await u(n,t,r`CREATE ${o}INDEX ${r.identifier(e.name)} ON ${r.identifier(e.table)} (${e.columns})`)}catch(i){const s=i;if(s.errno!==1061&&s.code!=="ER_DUP_KEYNAME"&&s.code!==1061)throw i}return}await u(n,t,r`CREATE ${o}INDEX IF NOT EXISTS ${r.identifier(e.name)} ON ${r.identifier(e.table)} (${e.columns})`)},L=R,h=n=>n?._meta?.column?.notNull===!1,g=n=>{if(n.kind!=="optional"||h(n))return!1;const t=n._meta?.inner;return!h(t)},w=new WeakMap,$=n=>{let t=w.get(n);return t===void 0&&(t=Object.entries(n.shape).map(([e,o])=>[e,y(o),g(o)]),w.set(n,t)),t},C=new WeakMap,M=(n,t)=>{let e=C.get(n);return e===void 0&&(e=new Map($(n).map(([o,i])=>[o,i])),C.set(n,e)),e.get(t)},U=(n,t,e)=>R(e,M(n,t)),S=(n,t)=>{const e={};for(const[o,i,s]of $(n)){const c=t[o];c===void 0||s&&c===null||(e[o]=q(c,i))}return e._id=t.id,e._creationTime=t._creationTime,e},_=(n,t)=>t?S(n,t):null,z=(n,t)=>{const e=[];for(const o of t){const i=_(n,o);i&&e.push(i)}return e},p=500,W=async(n,t,e,o,i,s={})=>{let c=s.after,a=s.limit,m=!0;for(;m&&(a===void 0||a>0);){const f=a===void 0?p:Math.min(p,a),I=c===void 0?r``:r` WHERE ${r.identifier("id")} > ${c}`,l=await b(n,t,r`SELECT * FROM ${r.identifier(o)}${I} ORDER BY ${r.identifier("id")} ASC LIMIT ${r.raw(String(f))}`);for(const N of l){const E=_(e,N);E&&await i(E)}c=l.at(-1)?.id,m=l.length===f,a=a===void 0?void 0:a-l.length}};export{p as BACKFILL_BATCH_SIZE,K as OCC_VERSION_COLUMN,k as columnRefSql,F as createIndexIfNotExists,S as decodeGlobalRow,_ as decodeRow,z as decodeRows,W as forEachRowPaged,O as physicalColumn,b as queryAll,B as queryBatch,u as queryRun,L as serializeColumnValue,U as serializeDocumentColumn,D as tableColumns};
@@ -0,0 +1 @@
1
+ import{LunoraError as R}from"@lunora/errors";import{aggregateTableName as C,rankTableName as x,sortColumnName as A,renderSql as v,bigintSqlKey as D}from"@lunora/shard-engine";import{sql as n}from"drizzle-orm";import{queryRun as g,queryAll as w,createIndexIfNotExists as p,OCC_VERSION_COLUMN as T,tableColumns as M,columnRefSql as d,queryBatch as B}from"./decodeGlobalRow-B6zmyAi5.mjs";import{B as S,e as h}from"./value-codec-nCDJEXH_.mjs";const N=(t,i,e=!1)=>i.columnType(h(t),{unique:e||t._meta?.column?.unique===!0}),L=t=>{const i=new Set;for(const e of t.indexes)e.unique===!0&&e.fields.length===1&&i.add(e.fields[0]);return i},k=(t,i,e)=>{if(e.indexKeyPrefix!==void 0)for(const o of i.indexes){if(o.unique!==!0||o.fields.length<=1)continue;const r=o.fields.filter(s=>{const a=i.shape[s];return a!==void 0&&e.indexKeyPrefix?.(h(a))!==void 0});if(r.length>0)throw new Error(`${t}.${o.name}: a composite unique index cannot cover ${r.join(", ")} in full on this engine (its key limit forces a prefix, which would constrain the prefix rather than the value). Split it into single-column unique indexes, or store those fields as a bounded type.`)}},U=(t,i,e)=>{const o=[],r=L(i);for(const[l,f]of Object.entries(i.shape)){if(!f._meta?.column)continue;const c=f._meta.column.notNull&&f.kind!=="optional"?" NOT NULL":"";o.push(n`${n.identifier(l)} ${n.raw(`${N(f,e,r.has(l))}${c}`)}`)}const s=[...e.frameworkColumns().map(l=>n`${n.identifier(l.name)} ${n.raw(l.type)}`),n`${n.identifier(T)} ${n.raw(e.companionTypes.integer)}`],a=s.length+o.length,u=e.maxTableColumns;if(u!==void 0&&a>u){const l=a-1===u,f="Move one or more fields into a single object field, or split the table — either way the existing rows need a data migration (`defineMigration` + `lunora migrate up`); there is no in-place path.";throw new R("VALIDATION_ERROR",`@lunora/sql-store: global table "${t}" needs ${String(a)} columns, over this engine's ${String(u)}-column limit. ${l?`One of them is "${T}", the row version every guarded write reads, which caps declared fields at ${String(u-s.length)}. A table provisioned at ${String(u)} columns before that column existed cannot be widened to hold it. `:""}${f}`)}return n.join([...s,...o],n`, `)},j=t=>{if(t.indexKeyPrefix?.("string")===void 0)return n`${d("_creationTime")}, ${d("id")}`},F=async(t,i,e)=>{if(i.name!=="sqlite")return;const r=(await w(t,i,n`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${e.name} AND tbl_name = ${e.table}`))[0]?.sql;if(typeof r!="string")return;const s=l=>{const f=l.indexOf("(");return f===-1?void 0:l.slice(f,l.lastIndexOf(")")+1)},a=e.unique?n`UNIQUE `:n``,u=s(v(i.name,n`CREATE ${a}INDEX ${n.identifier(e.name)} ON ${n.identifier(e.table)} (${e.columns})`).sql);if(!(u===void 0||u===s(r))){if(e.unique){const l=n.join(e.refs.map(c=>n`${c} IS NOT NULL`),n` AND `);if((await w(t,i,n`SELECT ${e.columns} FROM ${n.identifier(e.table)} WHERE ${l} GROUP BY ${e.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new R("INTERNAL",`unique index "${e.name}" on "${e.table}" cannot be re-created with its new column list: existing rows are duplicates under it. De-duplicate the table with a data migration first; the previous index is left in place.`)}await g(t,i,n`DROP INDEX IF EXISTS ${n.identifier(e.name)}`)}},P=async(t,i,e,o)=>{k(i,e,o);const r=L(e),s=u=>{const l=d(u),f=e.shape[u],c=f&&o.indexKeyPrefix&&f._meta?.column?.unique!==!0&&!r.has(u)?o.indexKeyPrefix(h(f)):void 0;return c===void 0?l:n`${l}(${n.raw(String(c))})`},a=j(o);for(const u of e.indexes){const l=u.fields.map($=>s($)),f=n.join(l,n`, `),c=u.unique??!1,m={columns:c||a===void 0?f:n`${f}, ${a}`,name:`${i}_${u.name}`,refs:l,table:i,unique:c};await F(t,o,m),await p(t,o,m)}a!==void 0&&await p(t,o,{columns:a,name:`${i}__by_creation`,table:i,unique:!1});for(const[u,l]of M(e))l.unique&&await p(t,o,{columns:s(u),name:`${i}_unique_${u}`,table:i,unique:!0})},_="__lunora_migration_state",K=async(t,i)=>{await g(t,i,n`CREATE TABLE IF NOT EXISTS ${n.identifier(_)} (${n.identifier("name")} ${n.raw(i.companionTypes.key)} PRIMARY KEY)`)},G=async(t,i,e)=>(await w(t,i,n`SELECT ${n.identifier("name")} FROM ${n.identifier(_)} WHERE ${n.identifier("name")} = ${e}`)).length>0,Y=async(t,i,e,o,r)=>{r>0&&console.warn(`[@lunora/sql-store] bigint storage migration on "${o}": ${String(r)} row(s) hold a value the order-preserving key cannot represent (non-numeric text, or a magnitude past 39 digits) and were left as stored — range filters and ORDER BY over them stay wrong until they are corrected by hand.`);try{await g(t,i,n`INSERT INTO ${n.identifier(_)} (${n.identifier("name")}) VALUES (${e})`)}catch(s){if(!i.isUniqueViolation(s))throw s}},H=100,V=t=>Object.entries(t.shape).filter(([,i])=>i._meta?.column!==void 0&&h(i)==="bigint").map(([i])=>i),X=(t,i)=>{const e=[],o=[];for(const r of i){const s=t[r];if(!(typeof s!="string"||s.length===S))try{const a=D(BigInt(s));e.push(n`${d(r)} = ${a}`),o.push(n`${d(r)} = ${s}`)}catch{}}return{assignments:e,guards:o}},W=async(t,i,e,o)=>{const r=V(e);if(r.length===0)return;await K(t,o);const s=`bigint-key:${i}`;if(await G(t,o,s))return;const a=n.join(r.map(c=>n`(${d(c)} IS NOT NULL AND LENGTH(${d(c)}) <> ${S})`),n` OR `),u=n.join([d("id"),...r.map(c=>d(c))],n`, `);let l="",f=0;for(;;){const c=await w(t,o,n`SELECT ${u} FROM ${n.identifier(i)} WHERE (${a}) AND ${d("id")} > ${l} ORDER BY ${d("id")} LIMIT ${n.raw(String(H))}`);if(c.length===0){await Y(t,o,s,i,f);return}const m=[];for(const y of c){const{id:I}=y,{assignments:b,guards:q}=typeof I=="string"?X(y,r):{assignments:[],guards:[]};if(b.length===0){f+=1;continue}m.push(n`UPDATE ${n.identifier(i)} SET ${n.join(b,n`, `)} WHERE ${d("id")} = ${I} AND ${n.join(q,n` AND `)}`)}await B(t,o,m);const $=c.at(-1)?.id;if(typeof $!="string")return;l=$}},Q=async(t,i,e,o)=>{const r=[[T,o.companionTypes.integer],...Object.entries(e.shape).filter(([,a])=>a._meta?.column!==void 0).map(([a,u])=>[a,N(u,o)])],s=async a=>{try{return await w(t,o,n`SELECT ${n.join(a.map(u=>d(u)),n`, `)} FROM ${n.identifier(i)} LIMIT 0`),!0}catch{return!1}};if(!await s(r.map(([a])=>a)))for(const[a,u]of r)await s([a])||await g(t,o,n`ALTER TABLE ${n.identifier(i)} ADD COLUMN ${n.identifier(a)} ${n.raw(u)}`)},rn=async(t,i,e)=>{for(const[o,r]of Object.entries(i.tables)){if(r.shardMode?.kind!=="global")continue;const s=U(o,r,e);await g(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(o)} (${s})`),await Q(t,o,r,e),await P(t,o,r,e),await W(t,o,r,e)}},O=t=>t.shardMode===void 0||t.shardMode.kind==="global",sn=async(t,i,e)=>{const{integer:o,key:r,real:s}=e.companionTypes;for(const[a,u]of Object.entries(i.tables)){const l=u.aggregateIndexes;if(!(!l||l.length===0||!O(u)))for(const f of l){const c=C(a,f.name);await g(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(c)} (${n.identifier("__key__")} ${n.raw(r)} PRIMARY KEY, ${n.identifier("__value__")} ${n.raw(s)}, ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0)`),e.name==="sqlite"&&((await w(t,e,n`PRAGMA table_info(${n.identifier(c)})`)).some($=>$.name==="__count__")||await g(t,e,n`ALTER TABLE ${n.identifier(c)} ADD COLUMN ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0`))}}},E=(t,i,e,o)=>{const r=t.name==="mysql"&&o?n`${n.identifier(i)}(191)`:n`${n.identifier(i)}`;return n`${r} ${n.raw(e)}`},z=(t,i,e)=>{const o=[E(t,"__partition__","ASC",!0)];for(const[r,s]of i.sortBy.entries()){const a=e.shape[s.field],u=a!==void 0&&t.indexKeyPrefix?.(h(a))!==void 0;o.push(E(t,A(r),s.direction==="desc"?"DESC":"ASC",u))}return o.push(E(t,"__id__","ASC",!0)),o},J=(t,i,e)=>i.sortBy.map((o,r)=>{const s=e.shape[o.field],a=t.columnType(s?h(s):void 0);return n`${n.identifier(A(r))} ${n.raw(a)}`}),an=async(t,i,e)=>{const{key:o}=e.companionTypes;for(const[r,s]of Object.entries(i.tables)){const a=s.rankIndexes;if(!(!a||a.length===0||!O(s)))for(const u of a){const l=x(r,u.name),f=J(e,u,s),c=f.length>0?n`, ${n.join(f,n`, `)}`:n``;await g(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(l)} (${n.identifier("__id__")} ${n.raw(o)} PRIMARY KEY, ${n.identifier("__partition__")} ${n.raw(o)} NOT NULL${c})`);const m=z(e,u,s),$=`${r}__rank_${u.name}__btree`;await p(t,e,{columns:n.join(m,n`, `),name:$,table:l,unique:!1})}}};export{sn as runSqlAggregateMigrations,rn as runSqlGlobalTableMigrations,an as runSqlRankMigrations};
@@ -0,0 +1 @@
1
+ import{LunoraError as T}from"@lunora/errors";import{decodeBigintSqlKey as I,bigintSqlKey as N,BIGINT_KEY_DIGITS as U}from"@lunora/shard-engine";const B=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?B(t):r.kind},A=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},k=r=>{const t=atob(r),i=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)i[o]=t.codePointAt(o)??0;return i},s="$lunora.wire$",m=64,l=1024,g="__proto__",h={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},O={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},S=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>m)return!0;if(r===null)return!1;const i=typeof r;if(i==="string"||i==="boolean")return!1;if(i==="number")return!Number.isFinite(r);if(i!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===s?!0:r.some(o=>o===void 0||E(o,t+1));if(!S(r)||Object.hasOwn(r,g))return!0;for(const o of Object.keys(r)){const f=r[o];if(f!==void 0&&E(f,t+1))return!0}return!1},b=(r,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(r===void 0)return[s,"undefined"];if(r===null)return null;const i=typeof r;if(i==="bigint")return[s,"bigint",r.toString()];if(i==="number"){const e=r;return Number.isNaN(e)?[s,"nan"]:e===1/0?[s,"inf"]:e===-1/0?[s,"-inf"]:e}if(i!=="object")return r;if(r instanceof Date)return[s,"date",b(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const c of Object.keys(e)){if(e[c]===void 0)continue;const a=b(e[c],t+1);c===g?Object.defineProperty(n,c,{configurable:!0,enumerable:!0,value:a,writable:!0}):n[c]=a}const y=[s,"error",e.name,e.message,n];return e.cause!==void 0&&y.push(b(e.cause,t+1)),y}if(r instanceof URL)return[s,"url",r.href];if(r instanceof Map)return[s,"map",[...r.entries()].map(([e,n])=>[b(e,t+1),b(n,t+1)])];if(r instanceof Set)return[s,"set",[...r].map(e=>b(e,t+1))];if(r instanceof ArrayBuffer)return[s,"bytes",A(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,y=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[s,"bytes",A(y)]:[s,"bytes",A(y),n]}if(Array.isArray(r)){const e=r.map(n=>b(n,t+1));return e.length>0&&e[0]===s?[s,"arr",e]:e}if(!S(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const o=r,f={};for(const e of Object.keys(o)){const n=o[e];if(n===void 0)continue;const y=b(n,t+1);e===g?Object.defineProperty(f,e,{configurable:!0,enumerable:!0,value:y,writable:!0}):f[e]=y}return f},u=(r,t=0)=>{if(t>m)throw new RangeError(`wire-codec: value nesting exceeds the ${m}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===s)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>u(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>l||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${l} digits)`);return BigInt(e)}case"date":{const e=u(r[2],t+1);if(typeof e!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(e)}case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[u(n[0],t+1),u(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>u(e,t+1)));case"url":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(e)}case"error":{const e=r[2],n=r[3],y=(Object.hasOwn(O,e)?O[e]:void 0)??Error,c=new y(n);c.name!==e&&Object.defineProperty(c,"name",{configurable:!0,value:e,writable:!0});const a=u(r[4],t+1);if(a===null||typeof a!="object"||Array.isArray(a))throw new TypeError("wire-codec: malformed error — props must be an object");for(const d of Object.keys(a))d===g?Object.defineProperty(c,d,{configurable:!0,enumerable:!0,value:a[d],writable:!0}):c[d]=a[d];return r.length>5&&Object.defineProperty(c,"cause",{configurable:!0,value:u(r[5],t+1),writable:!0}),c}case"bytes":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const n=k(e),y=r[3]??"Uint8Array";if(y==="ArrayBuffer")return n.buffer.byteLength===n.byteLength?n.buffer:n.slice().buffer;const c=Object.hasOwn(h,y)?h[y]:void 0;return c?new c(n.slice().buffer):n}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>u(e,t+1))}return r.map(f=>u(f,t+1))}const i=r,o={};for(const f of Object.keys(i)){const e=u(i[f],t+1);f===g?Object.defineProperty(o,f,{configurable:!0,enumerable:!0,value:e,writable:!0}):o[f]=e}return o},p=s,w=(r,t)=>r.startsWith(p)?u(t(r.slice(p.length))):t(r),R=new Set(["any","from","union"]),L=(r,t)=>{if(t!==void 0&&(typeof r=="number"||typeof r=="boolean")&&R.has(t))return p+JSON.stringify(r);if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return N(r);if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?p+JSON.stringify(b(r)):JSON.stringify(r)}catch(i){throw new T("BAD_REQUEST",`this value cannot be stored: ${i instanceof Error?i.message:String(i)}`)}},j=r=>{try{return JSON.parse(r)}catch{return r}},_=r=>{if(typeof r!="string")return r;const t=I(r);if(t!==void 0)return t;try{return BigInt(r)}catch{return r}},C=r=>B(r),x=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r!="string"?r:r.startsWith("{")||r.startsWith("[")||r.startsWith(p)?w(r,j):I(r)??r;case"array":case"geoPoint":case"object":case"record":return typeof r=="string"?w(r,j):r;case"bigint":return _(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}},K=U+1;export{K as B,x as a,b,_ as c,u as d,C as e,E as n,L as s,j as t};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/sql-store",
3
- "version": "1.0.0-alpha.108",
3
+ "version": "1.0.0-alpha.109",
4
4
  "description": "Internal dialect-parameterized SQL store core for Lunora .global() backends (D1, PlanetScale)",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -50,8 +50,8 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "@lunora/errors": "1.0.0-alpha.31",
54
- "@lunora/shard-engine": "1.0.0-alpha.55",
53
+ "@lunora/errors": "1.0.0-alpha.32",
54
+ "@lunora/shard-engine": "1.0.0-alpha.56",
55
55
  "drizzle-orm": "^0.45.2"
56
56
  },
57
57
  "engines": {
@@ -1 +0,0 @@
1
- const o="_version";export{o as OCC_VERSION_COLUMN};
@@ -1 +0,0 @@
1
- import"./ctx-db-search-state-ClbuTC47.mjs";import{d as S,c as s,a as i,r as l}from"./ctx-db-search-CHAHn9hB.mjs";import"./decodeGlobalRow-DVG7FHVz.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -1,7 +0,0 @@
1
- import{LunoraError as T}from"@lunora/errors";import{m as Mt,D as Nt}from"./ctx-db-search-state-ClbuTC47.mjs";import{c as Dt,r as Bt,A as qt,C as Ot,R as Wt,a as Ft,T as Ut,x as xt,b as Pt}from"./ctx-db-search-CHAHn9hB.mjs";import{d as li}from"./ctx-db-search-CHAHn9hB.mjs";import{literalInList as Ht,throwingScheduler as Kt,CDC_LOG_TABLE as V,cursorBelowRetainedFloor as jt,cdcTrimmedError as Gt,assertNoExplicitUndefined as ze,hasTrigger as Vt,runRowValidators as Me,assertFlatPredicate as Je,mergeWhere as B,rankTableName as le,sortColumnName as $e,resolveRankPartition as Ze,encodePartitionKey as Ie,resolveRankSeekTuple as Yt,RANK_TIEBREAK as _e,CountRlsUnsupportedError as et,normalizeIdStructurally as Xt,assertValidClientId as Qt,aggregateSqlFunction as fe,softDeleteScope as ue,compileWhereSql as we,normalizeOrderKeys as zt,buildSeekWhere as Jt,decodeCursor as Zt,resolveRelationPredicates as tt,resolveWith as nt,relationHooks as it,applySelect as ot,encodeCursor as en,NotFoundError as tn,applyOnDelete as nn,ConflictError as be,normalizeCountArgument as on,selectIndexForCount as rn,encodeAggregateKey as X,aggregateTableName as J,selectIndexForAggregate as sn,readAggregateValue as Ne,runTriggers as an,matchesRankStaticWhere as rt,CURSOR_PREFIX as cn,selectIndexForGroupBy as dn,tiebreakDirectionFor as ln,fanOutScalarCounts as fn,matchesStaticWhere as De,foldAggregateTally as st,coerceAggregateNumber as Be,CDC_LOG_TABLE_SEQ_INDEX as un,NotUniqueError as wn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as ht,e as Et,n as $n,b as _n}from"./value-codec-ByV_h-TJ.mjs";import{runSqlGlobalTableMigrations as hn,runSqlAggregateMigrations as En,runSqlRankMigrations as yn}from"./runSqlAggregateMigrations-D9KIdXhq.mjs";import{queryAll as I,queryRun as k,createIndexIfNotExists as pn,decodeRow as ee,serializeColumnValue as G,columnRefSql as q,decodeRows as at,tableColumns as yt,forEachRowPaged as ct,BACKFILL_BATCH_SIZE as qe,queryBatch as dt}from"./decodeGlobalRow-DVG7FHVz.mjs";import{decodeGlobalRow as ui}from"./decodeGlobalRow-DVG7FHVz.mjs";import{OCC_VERSION_COLUMN as lt}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const Rn=(a,c)=>{if(a.size<c)return;const _=a.keys().next().value;_!==void 0&&a.delete(_)},ft=50,Sn=(a,c={})=>{const _=c.maxBatch??ft,r=Number.isInteger(_)&&_>0?_:ft,p=new Map;let $=!1;const f=async(g,m)=>{const v=[...m.keys()];for(let M=0;M<v.length;M+=r){const O=v.slice(M,M+r);try{const F=await a(g,O);for(const Y of O){const P=F.get(Y);for(const Ce of m.get(Y)??[])Ce.resolve(P)}}catch(F){for(const Y of O)for(const P of m.get(Y)??[])P.reject(F)}}},b=()=>{$=!1;const g=[...p.entries()];p.clear();for(const[m,v]of g)f(m,v).catch(()=>{})};return{async load(g,m){return new Promise((v,M)=>{let O=p.get(g);O||(O=new Map,p.set(g,O));const F=O.get(m);F?F.push({reject:M,resolve:v}):O.set(m,[{reject:M,resolve:v}]),$||($=!0,queueMicrotask(b))})}}},gn=new Set(["_id","id"]),Fe=(a,c,_)=>a==="postgres"?e`${c} IS NOT DISTINCT FROM ${_}`:a==="mysql"?e`${c} <=> ${_}`:e`${c} IS ${_}`,Tn=(a,c)=>a.name!=="postgres"||c.nullable!==!0?"":c.direction==="desc"?" NULLS LAST":" NULLS FIRST",vn=(a,c)=>{const _=a.map(r=>e`${q(r.field)} ${e.raw(`${r.direction==="desc"?"DESC":"ASC"}${Tn(c,r)}`)}`);if(!a.some(r=>gn.has(r.field))){const r=ln(a);_.push(e`${q("id")} ${e.raw(r==="desc"?"DESC":"ASC")}`)}return e.join(_,e`, `)},ut=50,mn=(a,c,_)=>{const r={...c};for(const[p,$]of yt(a)){if($.serverDefault){r[p]=$.serverDefault({auth:_});continue}r[p]===void 0&&($.defaultFn?r[p]=$.defaultFn():"defaultValue"in $&&(r[p]=$.defaultValue))}return r},wt=(a,c,_,r)=>{for(const[p,$]of yt(a)){if($.serverDefault){p in c&&(_[p]=$.serverDefault({auth:r}));continue}$.onUpdateFn&&!(p in c)&&(_[p]=$.onUpdateFn())}},In=128,bn=()=>{const a=new Map;return{delete:c=>{a.delete(c)},get:c=>{const _=a.get(c);if(_!==void 0)return a.delete(c),a.set(c,_),_},set:(c,_)=>{a.has(c)?a.delete(c):Rn(a,In),a.set(c,_)}}},Cn=async(a,c,_,r,p)=>{const $=p.get(r);if($!==void 0)return $;const f=Object.entries(_.tables).filter(([,g])=>g.shardMode===void 0||g.shardMode.kind==="global").map(([g])=>g),b=await Promise.all(f.map(async g=>({found:(await I(a,c,e`SELECT 1 FROM ${e.identifier(g)} WHERE ${e.identifier("id")} = ${r} LIMIT 1`)).length>0,tableName:g})));for(const g of b)if(g.found)return p.set(r,g.tableName),g.tableName},te=a=>a==null?null:Number(a),An=(a,c)=>c.map(_=>{const r={};for(const p of a)r[p]=_[p]??null;return{key:r,value:te(_.value)}}),Ln=(a,c,_)=>[...a.partitionBy??[],...a.sortBy.map(p=>p.field),...a.where?Object.keys(a.where):[]].every(p=>c[p]===_[p]),pt=a=>a.length===1?a[0]:e`(${e.join(a,e` AND `)})`,Z=a=>e.join(a.map(c=>e`${e.identifier(c)}`),e`, `),ne=a=>e.join(a.map(c=>e`${c}`),e`, `),kn=(a,c,_,r,p)=>{const $=[];for(let f=0;f<_.length+1;f+=1){const b=_.slice(0,f).map(v=>Fe(a,e`${e.identifier(v)}`,r[v])),g=_[f],m=c.sortBy[f];f<_.length&&g!==void 0&&m!==void 0?b.push(e`${e.identifier(g)} ${e.raw(m.direction==="desc"?">":"<")} ${r[g]}`):b.push(e`${e.identifier(_e)} < ${p}`),$.push(pt(b))}return $.length>0?e.join($,e` OR `):void 0},Mn=(a,c,_)=>{if(_.length!==c.length)return;const r=[];for(const[p,$]of c.entries()){const f=[];for(let b=0;b<p;b+=1){const g=c[b];g!==void 0&&f.push(Fe(a,e`${e.identifier(g.column)}`,_[b]))}f.push(e`${e.identifier($.column)} ${e.raw($.direction==="desc"?"<":">")} ${_[p]}`),r.push(pt(f))}return e`(${e.join(r,e` OR `)})`},Nn=(a,c)=>{if(a.sortBy.length===0)throw new T("INTERNAL",`rankIndex "${a.name}" requires at least one "sortBy" column for stable pagination`);const _=[{column:"__partition__",direction:"asc"}];for(const[r,p]of a.sortBy.entries())_.push({column:c[r]??$e(r),direction:p.direction});return _.push({column:_e,direction:"asc"}),_},Dn=async(a,c,_,r,p)=>{const f=[];for(let v=0;v<p.length;v+=50)f.push(p.slice(v,v+50));const b=await Promise.all(f.map(async v=>I(a,c,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} IN (${ne(v)})`))),g=new Map;for(const v of b)for(const M of v)g.set(M.id,M);const m=[];for(const v of p){const M=ee(_,g.get(v));M&&m.push(M)}return m},Bn=a=>{const c=JSON.stringify(a),_=new TextEncoder().encode(c);let r="";for(const p of _)r+=String.fromCodePoint(p);return cn+btoa(r)},Oe=(a,c,_)=>{const r=a.shape[c];if(r!==void 0&&Et(r)==="bigint")throw new T("BAD_REQUEST",`${_}: "${c}" is stored as an order-preserving key, which SQL cannot reduce or group — declare an aggregateIndex covering this (by, field, op) so the maintained companion answers it instead (its running total is a REAL, so it stays exact only while the total is inside 2^53)`)},qn=a=>{if(a===void 0)return!1;const c=Et(a);return c==="any"||c==="bigint"||c==="from"||c==="union"},On=(a,c,_,r)=>{for(const p of _)Oe(a,p,`groupBy(${c}, { by: [..."${p}"] })`);r.field!==void 0&&Oe(a,r.field,`groupBy(${c}, { agg: { op: "${r.op}", field: "${r.field}" } })`)},We="__cdc_sweep",Rt="global",Wn=6e4,Fn=1e4,Un=3e4;let $t=0;const xn=async(a,c)=>{const{autoincrementPrimaryKey:_,key:r,real:p,text:$}=c.companionTypes;await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(V)} (${e.identifier("seq")} ${e.raw(_)}, ${e.identifier("ts")} ${e.raw(p)} NOT NULL, ${e.identifier("table")} ${e.raw(r)} NOT NULL, ${e.identifier("id")} ${e.raw(r)} NOT NULL, ${e.identifier("op")} ${e.raw(r)} NOT NULL, ${e.identifier("doc")} ${e.raw($)})`);const f=c.indexKeyPrefix?.("string");await pn(a,c,{columns:e`${f===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(f))})`}, ${e.identifier("seq")}`,name:un,table:V,unique:!1}),await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(We)} (${e.identifier("id")} ${e.raw(r)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(p)} NOT NULL)`),await k(a,c,e`INSERT INTO ${e.identifier(We)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${Rt}, ${0}) ${c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},Pn=async(a,c,_)=>{const r=e`UPDATE ${e.identifier(We)} SET ${e.identifier("lease_until")} = ${_+Wn} WHERE ${e.identifier("id")} = ${Rt} AND ${e.identifier("lease_until")} <= ${_}`;if(c.supportsReturning)return(await I(a,c,e`${r} RETURNING ${e.identifier("id")}`)).length>0;const p=await k(a,c,r);return(c.affectedRows?c.affectedRows(p??{rowsAffected:0}):0)>0},Hn=async(a,c,_,r)=>{if(!await Pn(a,c,r))return;const p=r-_;await k(a,c,e`
2
- DELETE FROM ${e.identifier(V)} WHERE ${e.identifier("seq")} IN (
3
- SELECT ${e.identifier("seq")} FROM (
4
- SELECT ${e.identifier("seq")} FROM ${e.identifier(V)} WHERE ${e.identifier("ts")} <= ${p} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Fn))}
5
- ) AS ${e.identifier("expired")}
6
- )
7
- `)},St=async(a,c)=>{const _=await I(a,c,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(V)}`),r=Number(_[0]?.seq??Number.NaN);return Number.isFinite(r)?r:void 0},Kn=a=>JSON.stringify($n(a)?_n(a):a),jn=async(a,c,_,r,p,$,f)=>{await k(a,f,e`INSERT INTO ${e.identifier(V)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${c}, ${_}, ${r}, ${p}, ${$===void 0?null:Kn($)})`)},si=async(a,c,_)=>{const r=c.sinceSeq??0,p=Math.max(1,Math.min(c.limit??1e3,1e4)),$=await St(a,_);if($!==void 0&&jt($,r))throw Gt($,r,"global");const b=(await I(a,_,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(V)} WHERE seq > ${r} ORDER BY seq ASC LIMIT ${e.raw(String(p))}`)).map(g=>{const{doc:m}=g,v={id:String(g.id),op:String(g.op),seq:Number(g.seq),table:String(g.table),ts:Number(g.ts)};return typeof m=="string"?{...v,doc:ht(JSON.parse(m))}:v});return{changes:b,cursor:b.at(-1)?.seq??r}},Gn=async(a,c,_,r={})=>{if(r.cursorOnly){const g=await I(a,_,e`SELECT MAX(seq) AS seq FROM ${e.identifier(V)}`),m=Number(g[0]?.seq??c);return{cursor:Number.isFinite(m)?m:c,tables:[]}}const p=await I(a,_,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(V)} WHERE seq > ${c} GROUP BY ${e.identifier("table")}`);let $=c;const f=[];for(const g of p){const m=Number(g.seq);Number.isFinite(m)&&m>$&&($=m),f.push(String(g.table))}const b=r.retained===!0?await St(a,_):void 0;return{cursor:$,tables:f,...b===void 0?{}:{floor:b}}},Vn=/string or blob too big/iu,Yn=/row is too big/iu,Xn=(a,c)=>{const{code:_,errno:r}=c,p=c instanceof Error?c.message:"";switch(a.name){case"mysql":return r===1118||_==="ER_TOO_BIG_ROWSIZE"?"InnoDB's per-row ceiling — roughly 8 KB, half a 16 KB page, for the part of the row stored inline":void 0;case"postgres":return Yn.test(p)?"the 8 KB heap page a tuple must fit once its wide columns have been TOASTed out":void 0;default:return Vn.test(p)?"the storage engine's per-row ceiling (2 MB on D1)":void 0}},Qn=(a,c,_)=>{const r=Xn(a,c);if(r!==void 0)throw new T("PAYLOAD_TOO_LARGE",`document is too large to store in "${_}": a single row cannot exceed ${r}. The limit is on the STORED bytes, which are UTF-8. Keep the payload in R2 (ctx.storage) and store a reference on the row.`)},_t=(a,c,_)=>{throw a.isUniqueViolation(c)?new be(`unique constraint violation on "${_}"`,"unique"):(Qn(a,c,_),c)},ai=a=>{const{crossShardCounter:c,crossShardReader:_,exec:r,maxRelationKeys:p,schema:$}=a,{dialect:f}=a,b={fieldRef:q,serialize:G,...f.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...f.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...f.name==="sqlite"?{}:{inList:Ht}},g=(t,n)=>Fe(f.name,t,n),m=t=>{const n=Z(t.columns),i=ne(t.values),o=l=>f.name==="mysql"?e`VALUES(${e.identifier(l)})`:e`excluded.${e.identifier(l)}`,s=l=>f.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(l)}`:e`${e.identifier(l)}`,u=e.join(Object.entries(t.set(o,s)).map(([l,E])=>e`${e.identifier(l)} = ${E}`),e`, `),h=f.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${u}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${u}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${i}) ${h}`},v=a.clock??(()=>Date.now()),M=a.idGenerator??(()=>crypto.randomUUID()),O=a.cdc??!1,F=typeof a.cdcRetentionMs=="number"&&Number.isFinite(a.cdcRetentionMs)&&a.cdcRetentionMs>0?a.cdcRetentionMs:void 0,Y=a.auth??{identity:null,userId:null},P=async(t,n,i,o)=>{if(!O||(await jn(r,v(),t,n,i,o,f),F===void 0))return;const s=v();if(!(s-$t<Un)){$t=s;try{await Hn(r,f,F,s)}catch{}}},Ce=a.scheduler??Kt,Ae=bn();let he=0,Le;const U=async()=>(Le??=(async()=>{await hn(r,$,f),await En(r,$,f),await yn(r,$,f),await Mt(r,f),await Bt(r,$,f),O&&await xn(r,f)})().catch(t=>{throw Le=void 0,t}),Le),ie=async(t,n)=>{await U();const i=await Cn(r,f,$,t,Ae);if(!(n!==void 0&&i!==n))return i},oe=new Map,Ue=async(t,n)=>{const i=J(t,n);return(await I(r,f,f.tableExists(i))).length>0},Ee=async(t,n)=>{const i=`${t}::${n.name}`,o=oe.get(i);if(o!==void 0)return o;if(!await Ue(t,n.name))return oe.set(i,!1),!1;const u=$.tables[t];if(!u)return oe.set(i,!1),!1;const h=n.by??[],l=new Map;await ct(r,f,u,t,w=>{if(n.where&&!De(w,n.where))return;const y=X(h,w);st(l,y,n,w)});const E=J(t,n.name);await k(r,f,e`DELETE FROM ${e.identifier(E)}`);const d=[];for(const[w,y]of l)d.push(e`INSERT INTO ${e.identifier(E)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${w}, ${y.value}, ${y.count})`);return await dt(r,f,d),oe.set(i,!0),!0},gt=async(t,n,i,o)=>{const s=new Map;let u,h=!0;for(;h;){const l=u===void 0?o:[...o,e`${e.identifier("id")} > ${u}`],E=l.length>0?e` WHERE ${e.join(l,e` AND `)}`:e``,d=await I(r,f,e`SELECT ${e.identifier("id")}, ${q(i.field??"")} FROM ${e.identifier(n)}${E} ORDER BY ${e.identifier("id")} ASC LIMIT ${e.raw(String(qe))}`);for(const w of at(t,d))st(s,"",i,w);u=d.at(-1)?.id,h=d.length===qe}return s.get("")?.value??null},Tt=async(t,n,i)=>{const o=n.field??"",s=[];for(const d of n.by??[]){const w=G(i[d]??null);s.push(w===null?e`${q(d)} IS NULL`:e`${q(d)} = ${w}`)}for(const[d,w]of Object.entries(n.where??{})){const y=w!==null&&typeof w=="object"&&!Array.isArray(w)?w.eq:w,R=G(y);s.push(R===null?e`${q(d)} IS NULL`:e`${q(d)} = ${R}`)}const u=s.length>0?e` WHERE ${e.join(s,e` AND `)}`:e``,h=$.tables[t];if(h&&qn(h.shape[o]))return gt(h,t,n,s);const l=fe(n.op),E=await I(r,f,e`SELECT ${e.raw(l)}(${q(o)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}${u}`);return te(E[0]?.value)},vt=async(t,n)=>{await k(r,f,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},mt=async(t,n,i,o)=>{const s=J(t,n.name),{op:u}=n,h=n.field??"",l=i&&(!n.where||De(i,n.where))?i:void 0,E=o&&(!n.where||De(o,n.where))?o:void 0;if(!(!l&&!E)){if(u==="count"||u==="sum"||u==="avg"){const d=new Set;for(const[w,y]of[[l,-1],[E,1]]){if(!w)continue;const R=u==="count"?1:Be(w[h]);if(R===void 0)continue;const S=X(n.by??[],w);d.add(S),await k(r,f,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(C,A)=>({__count__:e`${A("__count__")} + ${C("__count__")}`,__value__:u==="count"?e`${A("__value__")} + ${C("__value__")}`:e`COALESCE(${A("__value__")}, 0) + ${C("__value__")}`}),table:s,values:[S,y*R,y]}))}for(const w of d)await vt(s,w);return}if(l){const d=X(n.by??[],l),w=Be(l[h]),R=(await I(r,f,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`))[0],S=te(R?.value),C=(R?.count??0)-1;if(C<=0)await k(r,f,e`DELETE FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`);else if(R&&w!==void 0&&S!==null&&w===S){const A=await Tt(t,n,l);await k(r,f,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__value__")} = ${A}, ${e.identifier("__count__")} = ${C} WHERE ${e.identifier("__key__")} = ${d}`)}else await k(r,f,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${d}`)}if(E){const d=X(n.by??[],E),w=Be(E[h]);if(w===void 0)await k(r,f,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(y,R)=>({__count__:e`${R("__count__")} + 1`}),table:s,values:[d,null,1]}));else{const y=u==="min"?"MIN":"MAX";await k(r,f,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(R,S)=>({__count__:e`${S("__count__")} + 1`,__value__:e`${e.raw(y)}(COALESCE(${S("__value__")}, ${R("__value__")}), ${R("__value__")})`}),table:s,values:[d,w,1]}))}}}},ye=async t=>{const n=$.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const i of n)await Ee(t,i)},re=async(t,n,i)=>{const o=$.tables[t]?.aggregateIndexes;if(!(!o||o.length===0))for(const s of o){const u=`${t}::${s.name}`;(oe.get(u)??await Ue(t,s.name))&&await mt(t,s,n,i)}},se=new Map,xe=async(t,n)=>{const i=le(t,n);return(await I(r,f,f.tableExists(i))).length>0},ke=async(t,n)=>{const i=`${t}::rank::${n.name}`,o=se.get(i);if(o!==void 0)return o;if(!await xe(t,n.name))return se.set(i,!1),!1;const u=$.tables[t];if(!u)return se.set(i,!1),!1;const h=le(t,n.name);await k(r,f,e`DELETE FROM ${e.identifier(h)}`);const l=n.sortBy.map((y,R)=>$e(R)),E=Z(["__id__","__partition__",...l]);let d=[];const w=async()=>{if(d.length===0)return;const y=d;d=[],await dt(r,f,y)};return await ct(r,f,u,t,async y=>{if(n.where&&!rt(y,n.where))return;const R=Ie(n.partitionBy??[],y),S=n.sortBy.map(C=>G(y[C.field]??null));d.push(e`INSERT INTO ${e.identifier(h)} (${E}) VALUES (${ne([y._id,R,...S])})`),d.length>=qe&&await w()}),await w(),se.set(i,!0),!0},pe=async t=>{const n=$.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const i of n)await ke(t,i)},Q=async(t,n,i,o)=>{const s=$.tables[t],u=s?.rankIndexes;if(!u||u.length===0)return;const h=s?.softDeleteMode?.field,l=h===void 0||o===void 0?void 0:o[h],E=l!=null;for(const d of u){if(i!==void 0&&o!==void 0&&Ln(d,i,o))continue;const w=`${t}::rank::${d.name}`;if(!(se.get(w)??await xe(t,d.name)))continue;const S=le(t,d.name);if(i&&await k(r,f,e`DELETE FROM ${e.identifier(S)} WHERE ${e.identifier("__id__")} = ${n}`),o&&!E){if(d.where&&!rt(o,d.where))continue;const C=d.sortBy.map((N,j)=>$e(j)),A=Z(["__id__","__partition__",...C]),W=Ie(d.partitionBy??[],o),L=d.sortBy.map(N=>G(o[N.field]??null));await k(r,f,e`INSERT INTO ${e.identifier(S)} (${A}) VALUES (${ne([n,W,...L])})`)}}},ae=Dt({dialect:f,exec:r,schema:$}),Pe=new Set;for(const[t,n]of Object.entries($.tables))for(const i of Object.values(n.triggerMap??{}))Pe.add(`${t} ${i.timing} ${i.op}`);const H=(t,n,i)=>Pe.has(`${t} ${n} ${i}`);let He;const K=async(t,n,i)=>{if(he+=1,he>ut)throw he-=1,new be(`trigger recursion exceeded ${String(ut)} levels on "${i.table}" — check for a self-triggering write`,"trigger");try{await an({ctx:He,event:i,op:n,schema:$,tableName:i.table,timing:t})}finally{he-=1}},It=async(t,n)=>{try{await k(r,f,n)}catch(i){_t(f,i,t)}},Re=async(t,n)=>(await I(r,f,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],Se=async(t,n,i,o)=>{if(o===void 0)return;const s=e`${e.identifier(lt)}`,u=e.join([g(e`${e.identifier("id")}`,o.id),g(s,o[lt]??null)],e` AND `),h=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${i}, ${s} = COALESCE(${s}, 0) + 1 WHERE ${u}`:e`DELETE FROM ${e.identifier(t)} WHERE ${u}`,l=()=>{throw new be(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(f.supportsReturning)(await I(r,f,e`${h} RETURNING ${e.identifier("id")}`)).length===0&&l();else{const E=await k(r,f,h);(f.affectedRows?f.affectedRows(E??{rowsAffected:0}):0)===0&&l()}}catch(E){_t(f,E,t)}},bt=(t,n,i,o)=>{const s=Object.keys(t.shape);return{columns:["id","_creationTime",...s],values:[n,i,...s.map(u=>G(o[u]??null))]}},Ct=async(t,n,i,o)=>{const s=dn(n,i.op,i.field,o.by,o.where);if(!s||!await Ee(t,s.index))return;const h=J(t,s.index.name),l=Object.keys(s.partial);if(l.length===(s.index.by??[]).length&&l.length>0){const d=X(s.index.by??[],s.partial),w=await I(r,f,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)} WHERE ${e.identifier("__key__")} = ${d}`);if(w.length===0)return[];const y=w[0];return[{key:{...s.partial},value:Ne(i.op,{count:y.count,value:te(y.value)})}]}return l.length>0?void 0:(await I(r,f,e`SELECT ${e.identifier("__key__")} AS ${e.identifier("key")}, ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)}`)).map(d=>{const w=d;return{key:ht(JSON.parse(w.key)),value:Ne(i.op,{count:w.count,value:te(w.value)})}})},Ke=t=>{const n=$.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},je=t=>{throw new T("INTERNAL",`cross-backend relation: a global table cannot load the shard-local relation '${t}' (it spans every shard) — wire a cross-shard reader to support it`)},At=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new T("MASK_UNSUPPORTED",`masking cannot follow a nested \`with\` across the cross-shard relation hop to "${t}" — the nested rows are hydrated on the serving shard, where the mask policy does not exist. Read the nested relation at its own (masked) call site instead.`);const i={};if(n?.relationBaseWhere)for(const o of Object.keys($.tables)){const s=n.relationBaseWhere(o);s!==void 0&&(i[o]=s)}return{orderBy:n?.orderBy,relationPolicies:i,where:B(n?.baseWhere,n?.where),with:n?.with}},Ge=(t,n)=>Ke(t)?_?_(t,At(t,n)):je(t):x.findMany(t,n),ge=(t,n,i)=>tt(t,{fetcher:Ge,maxRelationKeys:p,relationBaseWhere:i,schema:$,tableName:n}),Lt=Sn(async(t,n)=>{const i=await I(r,f,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${ne(n)})`),o=new Map;for(const s of i){const{id:u}=s;typeof u=="string"&&o.set(u,s)}return o}),x={async cdcChangedTables(t,n){if(O)try{return await U(),await Gn(r,t,f,{...n,retained:F!==void 0})}catch{return}},async aggregate(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);if(await U(),fe(n.op),n.op==="count")return x.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new T("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const o=ue(i.softDeleteMode,void 0),s=B(B(n.baseWhere,n.where),o),u=await ge(s,t,n.relationBaseWhere),h=u!==s;if(i.aggregateIndexes&&!n.baseWhere&&!h&&!o){const R=sn(i.aggregateIndexes,n.op,n.field,n.where);if(R&&await Ee(t,R.index)){const C=X(R.index.by??[],R.key),A=J(t,R.index.name),L=(await I(r,f,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(A)} WHERE ${e.identifier("__key__")} = ${C}`))[0];return Ne(n.op,L===void 0?void 0:{count:L.count,value:te(L.value)})}}Oe(i,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const l=we(u,b),E=e.raw(fe(n.op)),d=e`SELECT ${E}(${q(n.field)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,y=(await I(r,f,l?e`${d} WHERE ${l}`:d))[0]?.value;return y==null?null:Number(y)},async count(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=on(n);if(o.restrictsCounts)throw new et(t);const s=ue(i.softDeleteMode,void 0),u=B(B(o.baseWhere,o.where),s),h=await ge(u,t,o.relationBaseWhere),l=h!==u;if(i.aggregateIndexes&&!o.baseWhere&&!l&&!s){const y=rn(i.aggregateIndexes,o.where);if(y&&await Ee(t,y.index)){const S=X(y.index.by??[],y.key),C=J(t,y.index.name),A=await I(r,f,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")} FROM ${e.identifier(C)} WHERE ${e.identifier("__key__")} = ${S}`);return Number(A[0]?.value??0)}}const E=we(h,b),d=e`SELECT COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(t)}`,w=await I(r,f,E?e`${d} WHERE ${E}`:d);return Number(w[0]?.count??0)},async delete(t,n,i){const o=await ie(t,n);if(!o)return;const s=$.tables[o];if(!s)return;const u=await Re(o,t),h=ee(s,u),l=i?.hard===!0,E=!l&&s.softDeleteMode?s.softDeleteMode.field:void 0;if(!(E&&(!h||h[E]!==null&&h[E]!==void 0))){if(H(o,"before","delete")&&await K("before","delete",{id:t,op:"delete",previous:h??void 0,table:o}),await nn({deletedId:t,deletedReference:d=>h?.[d],findHolders:async(d,w,y)=>{if($.tables[d]?.shardMode?.kind==="shardBy")throw new T("INTERNAL",`cross-backend cascade from global '${o}' into shardBy '${d}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany(d,{includeDeleted:l,where:{[w]:y}})).page},onCascade:(d,w)=>x.delete(w,void 0,i),onRestrict:d=>{throw new be(d,"restrict")},onSetNull:(d,w,y)=>x.patch(w,{[y]:null}),schema:$,tableName:o}),await ye(o),await pe(o),E&&h){const d={...h,[E]:v()},w=e.join(Object.keys(s.shape).map(y=>e`${e.identifier(y)} = ${G(d[y]??null)}`),e`, `);await Se(o,"UPDATE",w,u),await re(o,h,d),await Q(o,t,h,void 0),await ae(o,t,d,h),await P(o,t,"update",d),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h,table:o});return}await Se(o,"DELETE",void 0,u),Ae.delete(t),await re(o,h??void 0,void 0),await Q(o,t,h??void 0,void 0),await ae(o,t,void 0),await P(o,t,"delete"),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h??void 0,table:o})}},async findFirst(t,n={}){return(await x.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const i=await x.findFirst(t,n);if(i===null)throw new tn(`findFirstOrThrow: no "${t}" document matched`);return i},async findMany(t,n={}){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=zt(n.orderBy,i.shape),s=n.cursor?Jt(o,Zt(n.cursor)):void 0,u=Ge,h=async(L,N,j,Te)=>{if(Ke(L))return c?fn(c,L,N,j,Te):je(L);const ve=$.tables[L];if(!ve)throw new T("INTERNAL",`unknown table: ${L}`);const me=ue(ve.softDeleteMode,void 0),z={[N]:{in:j}},D=B(B(z,Te),me),ce=await ge(D,L,void 0),Ve=we(ce,b),Ye=q(N);let de=e`SELECT ${Ye} AS __fk__, COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(L)}`;Ve&&(de=e`${de} WHERE ${Ve}`),de=e`${de} GROUP BY ${Ye}`;const kt=await I(r,f,de),Xe=new Map;for(const Qe of kt)Xe.set(Qe.__fk__,Number(Qe.count??0));return Xe};let l=B(n.baseWhere,n.where);l=B(l,ue(i.softDeleteMode,n.includeDeleted)),l=await tt(l,{fetcher:u,maxRelationKeys:p,relationBaseWhere:n.relationBaseWhere,schema:$,tableName:t}),s&&(l=l?{AND:[l,s]}:s);const E=we(l,b),d=vn(o,f);let w=e`SELECT * FROM ${e.identifier(t)}`;E&&(w=e`${w} WHERE ${E}`),w=e`${w} ORDER BY ${d}`;const y=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;y!==void 0&&(w=e`${w} LIMIT ${e.raw(String(y+1))}`);const R=await I(r,f,w),S=at(i,R);if(y===void 0)return n.with&&await nt({fetcher:u,groupedCounter:h,parents:S,...it(n),schema:$,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:ot(S,n.select,n.with)};const C=S.length>y,A=C?S.slice(0,y):S,W=A.at(-1);return n.with&&await nt({fetcher:u,groupedCounter:h,parents:A,...it(n),schema:$,tableName:t,with:n.with}),{continueCursor:C&&W?en(W,o):null,isDone:!C,page:ot(A,n.select,n.with)}},async get(t,n){const i=await ie(t,n);if(!i)return null;const o=$.tables[i];return o?ee(o,await Lt.load(i,t)):null},async groupBy(t,n){const i=$.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=n.agg??{op:"count"};if(fe(o.op),o.op!=="count"&&!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);const s=ue(i.softDeleteMode,void 0),u=B(B(n.baseWhere,n.where),s),h=await ge(u,t,n.relationBaseWhere),l=h!==u;if(i.aggregateIndexes&&!n.baseWhere&&!l&&!s){const S=await Ct(t,i.aggregateIndexes,o,n);if(S!==void 0)return S}On(i,t,n.by,o);const E=we(h,b),d=n.by.map(S=>e`${q(S)} AS ${e.identifier(S)}`);if(o.op==="count")d.push(e`COUNT(*) AS ${e.identifier("value")}`);else{if(!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);d.push(e`${e.raw(fe(o.op))}(${q(o.field)}) AS ${e.identifier("value")}`)}const w=e.join(n.by.map(S=>q(S)),e`, `);let y=e`SELECT ${e.join(d,e`, `)} FROM ${e.identifier(t)}`;E&&(y=e`${y} WHERE ${E}`),y=e`${y} GROUP BY ${w}`;const R=await I(r,f,y);return An(n.by,R)},async insert(t,n,i){const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);await U();const s=mn(o,n,Y);Me(o,s);let u,h=!0;i?.clientId!==void 0?(Qt(i.clientId),u=i.clientId):i?.allowExplicitId&&typeof s._id=="string"?u=s._id:(u=M(),h=!1);const l=i?.allowExplicitId&&typeof s._creationTime=="number"?s._creationTime:v(),E={...s,_creationTime:l,_id:u};H(t,"before","insert")&&await K("before","insert",{doc:{...E},id:u,op:"insert",table:t}),await ye(t),await pe(t);const{columns:d,values:w}=bt(o,u,l,s);return await It(t,e`INSERT INTO ${e.identifier(t)} (${Z(d)}) VALUES (${ne(w)})`),h&&Ae.set(u,t),await re(t,void 0,E),await Q(t,u,void 0,E),await ae(t,u,E),await P(t,u,"insert",E),H(t,"after","insert")&&await K("after","insert",{doc:E,id:u,op:"insert",table:t}),u},normalizeId(t,n){return Xt($,t,n)},async patch(t,n,i){ze("patch",n);const o=await ie(t,i);if(!o)throw new T("INTERNAL",`document not found: ${t}`);const s=$.tables[o];if(!s)throw new T("INTERNAL",`document not found: ${t}`);const u=await Re(o,t),h=ee(s,u);if(!h)throw new T("INTERNAL",`document not found: ${t}`);const l={...h,...n,_id:t};wt(s,n,l,Y),Me(s,l,!0),H(o,"before","update")&&await K("before","update",{doc:{...l},id:t,op:"update",previous:h,table:o}),await ye(o),await pe(o);const E=Object.keys(s.shape),d=e.join(E.map(w=>e`${e.identifier(w)} = ${G(l[w]??null)}`),e`, `);await Se(o,"UPDATE",d,u),await re(o,h,l),await Q(o,t,h,l),await ae(o,t,l,h),await P(o,t,"update",l),H(o,"after","update")&&await K("after","update",{doc:l,id:t,op:"update",previous:h,table:o})},async restore(t,n){const i=await ie(t,n);if(!i)throw new T("INTERNAL",`document not found: ${t}`);const o=$.tables[i],s=o?.softDeleteMode?.field;if(!o||!s)throw new T("INTERNAL",`ctx.db.restore: table "${i}" is not a .softDelete() table`);const u=await Re(i,t),h=u?.[s]!==null&&u?.[s]!==void 0;if(await x.patch(t,{[s]:null},n),h){const l=ee(o,u);l!==null&&await Q(i,t,void 0,{...l,[s]:null})}},query(t){const n=$.tables[t];if(!n)throw new T("INTERNAL",`unknown table: ${t}`);const i="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",o=[],s=l=>o.every(E=>E(l)),u=async(l,E)=>{await U();const d=o.length>0,w=await Ft(r,f,n,t,l,Ut(d?void 0:E));if(!d)return E===void 0&&xt(w),w;const y=w.filter(R=>s(R));return E===void 0?y:y.slice(0,E)},h=l=>{const E={async*[Symbol.asyncIterator](){if(!l)throw new T("INTERNAL",i);yield*await u(l,void 0)},async collect(){if(!l)throw new T("INTERNAL",i);return u(l,void 0)},async collectWithScores(){throw new T("GLOBAL_SEARCH_SCORES_UNSUPPORTED",`collectWithScores() is not supported on \`.global()\` tables (table "${t}") — relevance scores are not yet surfaced on this backend; use .collect() instead`)},filter(d){return o.push(d),E},async first(){if(!l)throw new T("INTERNAL",i);return(await u(l,1))[0]??null},order(){return E},async paginate(d){if(!l)throw new T("INTERNAL",i);const w=Ot(d);return Wt(await u(l,Pt(w)),w)},async take(d){if(!l)throw new T("INTERNAL",i);return u(l,d)},async unique(){if(!l)throw new T("INTERNAL",i);const d=await u(l,2);if(d.length>1)throw new wn(`unique() on table "${t}" matched ${String(d.length)} documents; expected at most one`);return d[0]??null},withGeoIndex(){throw new T("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new T("INTERNAL",i)},withSearchIndex(d,w){const y=(n.searchIndexes??[]).find(S=>S.name===d);if(!y)throw new T("INTERNAL",`unknown search index "${d}" on table "${t}"`);const R={definition:y,field:y.field,filters:[],hasQuery:!1,indexName:d,query:""};if(w(qt(R,t,Nt(y.language))),!R.hasQuery)throw new T("INTERNAL",`search index "${d}" on table "${t}" requires a .search(field, query) call`);return h(R)}};return E};return h(void 0)},async rank(t,n,i){const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(N=>N.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(i.restrictsCounts)throw new et(t);if(await U(),!await ke(t,s))return null;const h=typeof i.row=="string"?i.row:i.row._id;if(!h)return null;const l=le(t,s.name),E=s.sortBy.map((N,j)=>$e(j)),d=Z(["__partition__",...E]),y=(await I(r,f,e`SELECT ${d} FROM ${e.identifier(l)} WHERE ${e.identifier("__id__")} = ${h}`))[0];if(!y)return null;const R=y.__partition__,S=B(i.baseWhere,i.where);Je(S,$,t,"rank");const C=Ze(s,S);if(C&&Ie(s.partitionBy??[],C)!==R)return null;const A=kn(f.name,s,E,y,h),W=await I(r,f,e`SELECT COUNT(*) AS c FROM ${e.identifier(l)} WHERE ${e.identifier("__partition__")} = ${R}${A?e` AND (${A})`:e``}`),L=await I(r,f,e`SELECT COUNT(*) AS c FROM ${e.identifier(l)} WHERE ${e.identifier("__partition__")} = ${R}`);return{position:Number(W[0]?.c??0)+1,total:Number(L[0]?.c??0)}},async rankPage(t,n,i={}){Je(B(i.baseWhere,i.where),$,t,"rankPage");const o=$.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(D=>D.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await ke(t,s))return{continueCursor:null,isDone:!0,page:[]};const h=le(t,s.name),l=s.sortBy.map((D,ce)=>$e(ce)),E=Math.max(1,Math.min(1e3,Math.floor(i.take??100))),d=B(i.baseWhere,i.where),w=Ze(s,d),y=Nn(s,l),R=e.join(y.map(D=>e`${e.identifier(D.column)} ${e.raw(D.direction==="desc"?"DESC":"ASC")}`),e`, `),S=[];typeof i.partitionKey=="string"?S.push(e`${e.identifier("__partition__")} = ${i.partitionKey}`):w&&S.push(e`${e.identifier("__partition__")} = ${Ie(s.partitionBy??[],w)}`);const C=Yt(i);if(C!==void 0){const D=Mn(f.name,y,C);D!==void 0&&S.push(D)}const A=Z([_e,"__partition__",...l]);let W=e`SELECT ${A} FROM ${e.identifier(h)}`;S.length>0&&(W=e`${W} WHERE ${e.join(S,e` AND `)}`),W=e`${W} ORDER BY ${R} LIMIT ${e.raw(String(E+1))}`;const L=await I(r,f,W),N=L.length>E,j=N?L.slice(0,E):L,Te=j.map(D=>D[_e]),ve=await Dn(r,f,o,t,Te);let me=null;const z=j.at(-1);if(N&&z!==void 0){const D=[z.__partition__,...l.map(ce=>z[ce]),z[_e]];me=Bn(D)}return{continueCursor:me,isDone:!N,page:ve}},async replace(t,n,i,o){ze("replace",n);const s=await ie(t,i);if(!s)throw new T("INTERNAL",`document not found: ${t}`);const u=$.tables[s];if(!u)throw new T("INTERNAL",`document not found: ${t}`);const h=await Re(s,t);if(h===void 0)throw new T("INTERNAL",`document not found: ${t}`);const E=Vt($,s,"update")||(u.aggregateIndexes??[]).length>0||(u.rankIndexes??[]).length>0?ee(u,h)??void 0:void 0,d=o?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:v(),w={...n,_creationTime:d,_id:t};wt(u,n,w,Y),Me(u,w),H(s,"before","update")&&await K("before","update",{doc:{...w},id:t,op:"update",previous:E,table:s}),await ye(s),await pe(s);const y=Object.keys(u.shape),R=e.join([e`${e.identifier("_creationTime")} = ${d}`,...y.map(S=>e`${e.identifier(S)} = ${G(w[S]??null)}`)],e`, `);await Se(s,"UPDATE",R,h),await re(s,E,w),await Q(s,t,E,w),await ae(s,t,w,E),await P(s,t,"update",w),H(s,"after","update")&&await K("after","update",{doc:w,id:t,op:"update",previous:E,table:s})}};return He={db:x,scheduler:Ce},x};export{li as backfillSqlSearchIndexes,ai as createSqlCtxDb,ui as decodeGlobalRow,Gn as readSqlCdcChangedTables,si as readSqlCdcChanges,St as readSqlCdcFloor,xn as runSqlCdcMigration,Bt as runSqlSearchMigrations,Hn as sweepSqlCdcRetention};
@@ -1 +0,0 @@
1
- import{renderSql as d}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{s as I,a as N,e as _}from"./value-codec-ByV_h-TJ.mjs";import{OCC_VERSION_COLUMN as F}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const q=n=>n==="_id"||n==="id"?"id":n,M=n=>i`${i.identifier(q(n))}`,v=n=>{const t=[];for(const[e,o]of Object.entries(n.shape)){const r=o._meta?.column;r&&t.push([e,r])}return t},O=(n,t,e)=>{const{params:o,sql:r}=d(t.name,e);return n.all(r,o)},u=(n,t,e)=>{const{params:o,sql:r}=d(t.name,e);return n.run(r,o)},k=async(n,t,e)=>{if(e.length!==0){if(!n.batch){for(const o of e)await u(n,t,o);return}await n.batch(e.map(o=>d(t.name,o)))}},D=async(n,t,e)=>{const o=e.unique?i`UNIQUE `:i``;if(t.name==="mysql"){try{await u(n,t,i`CREATE ${o}INDEX ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)}catch(r){const s=r;if(s.errno!==1061&&s.code!=="ER_DUP_KEYNAME"&&s.code!==1061)throw r}return}await u(n,t,i`CREATE ${o}INDEX IF NOT EXISTS ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)},K=I,h=n=>n?._meta?.column?.notNull===!1,b=n=>{if(n.kind!=="optional"||h(n))return!1;const t=n._meta?.inner;return!h(t)},w=new WeakMap,y=n=>{let t=w.get(n);return t===void 0&&(t=Object.entries(n.shape).map(([e,o])=>[e,_(o),b(o)]),w.set(n,t)),t},S=(n,t)=>{const e={};for(const[o,r,s]of y(n)){const c=t[o];c===void 0||s&&c===null||(e[o]=N(c,r))}return e._id=t.id,e._creationTime=t._creationTime,e},$=(n,t)=>t?S(n,t):null,L=(n,t)=>{const e=[];for(const o of t){const r=$(n,o);r&&e.push(r)}return e},R=500,B=async(n,t,e,o,r,s={})=>{let c=s.after,a=s.limit,m=!0;for(;m&&(a===void 0||a>0);){const f=a===void 0?R:Math.min(R,a),C=c===void 0?i``:i` WHERE ${i.identifier("id")} > ${c}`,l=await O(n,t,i`SELECT * FROM ${i.identifier(o)}${C} ORDER BY ${i.identifier("id")} ASC LIMIT ${i.raw(String(f))}`);for(const p of l){const E=$(e,p);E&&await r(E)}c=l.at(-1)?.id,m=l.length===f,a=a===void 0?void 0:a-l.length}};export{R as BACKFILL_BATCH_SIZE,F as OCC_VERSION_COLUMN,M as columnRefSql,D as createIndexIfNotExists,S as decodeGlobalRow,$ as decodeRow,L as decodeRows,B as forEachRowPaged,q as physicalColumn,O as queryAll,k as queryBatch,u as queryRun,K as serializeColumnValue,v as tableColumns};
@@ -1 +0,0 @@
1
- import{LunoraError as R}from"@lunora/errors";import{aggregateTableName as C,rankTableName as q,sortColumnName as A,renderSql as v,bigintSqlKey as D}from"@lunora/shard-engine";import{sql as n}from"drizzle-orm";import{queryRun as d,queryAll as w,createIndexIfNotExists as E,tableColumns as M,columnRefSql as m,queryBatch as B}from"./decodeGlobalRow-DVG7FHVz.mjs";import{B as N,e as T}from"./value-codec-ByV_h-TJ.mjs";import{OCC_VERSION_COLUMN as p}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const S=(t,i)=>i.columnType(T(t)),k=(t,i,e)=>{const o=[];for(const[f,l]of Object.entries(i.shape)){if(!l._meta?.column)continue;const u=l._meta.column.notNull&&l.kind!=="optional"?" NOT NULL":"";o.push(n`${n.identifier(f)} ${n.raw(`${S(l,e)}${u}`)}`)}const s=[...e.frameworkColumns().map(f=>n`${n.identifier(f.name)} ${n.raw(f.type)}`),n`${n.identifier(p)} ${n.raw(e.companionTypes.integer)}`],a=s.length+o.length,r=e.maxTableColumns;if(r!==void 0&&a>r){const f=a-1===r,l="Move one or more fields into a single object field, or split the table — either way the existing rows need a data migration (`defineMigration` + `lunora migrate up`); there is no in-place path.";throw new R("VALIDATION_ERROR",`@lunora/sql-store: global table "${t}" needs ${String(a)} columns, over this engine's ${String(r)}-column limit. ${f?`One of them is "${p}", the row version every guarded write reads, which caps declared fields at ${String(r-s.length)}. A table provisioned at ${String(r)} columns before that column existed cannot be widened to hold it. `:""}${l}`)}return n.join([...s,...o],n`, `)},x=t=>{if(t.indexKeyPrefix?.("string")===void 0)return n`${m("_creationTime")}, ${m("id")}`},U=async(t,i,e)=>{if(i.name!=="sqlite")return;const s=(await w(t,i,n`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${e.name} AND tbl_name = ${e.table}`))[0]?.sql;if(typeof s!="string")return;const a=l=>{const u=l.indexOf("(");return u===-1?void 0:l.slice(u,l.lastIndexOf(")")+1)},r=e.unique?n`UNIQUE `:n``,f=a(v(i.name,n`CREATE ${r}INDEX ${n.identifier(e.name)} ON ${n.identifier(e.table)} (${e.columns})`).sql);if(!(f===void 0||f===a(s))){if(e.unique){const l=n.join(e.refs.map(c=>n`${c} IS NOT NULL`),n` AND `);if((await w(t,i,n`SELECT ${e.columns} FROM ${n.identifier(e.table)} WHERE ${l} GROUP BY ${e.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new R("INTERNAL",`unique index "${e.name}" on "${e.table}" cannot be re-created with its new column list: existing rows are duplicates under it. De-duplicate the table with a data migration first; the previous index is left in place.`)}await d(t,i,n`DROP INDEX IF EXISTS ${n.identifier(e.name)}`)}},j=async(t,i,e,o)=>{const s=r=>{const f=m(r),l=e.shape[r],u=l&&o.indexKeyPrefix?o.indexKeyPrefix(T(l)):void 0;return u===void 0?f:n`${f}(${n.raw(String(u))})`},a=x(o);for(const r of e.indexes){const f=r.fields.map($=>s($)),l=n.join(f,n`, `),u=r.unique??!1,c={columns:u||a===void 0?l:n`${l}, ${a}`,name:`${i}_${r.name}`,refs:f,table:i,unique:u};await U(t,o,c),await E(t,o,c)}a!==void 0&&await E(t,o,{columns:a,name:`${i}__by_creation`,table:i,unique:!1});for(const[r,f]of M(e))f.unique&&await E(t,o,{columns:s(r),name:`${i}_unique_${r}`,table:i,unique:!0})},y="__lunora_migration_state",P=async(t,i)=>{await d(t,i,n`CREATE TABLE IF NOT EXISTS ${n.identifier(y)} (${n.identifier("name")} ${n.raw(i.companionTypes.key)} PRIMARY KEY)`)},F=async(t,i,e)=>(await w(t,i,n`SELECT ${n.identifier("name")} FROM ${n.identifier(y)} WHERE ${n.identifier("name")} = ${e}`)).length>0,K=async(t,i,e,o,s)=>{s>0&&console.warn(`[@lunora/sql-store] bigint storage migration on "${o}": ${String(s)} row(s) hold a value the order-preserving key cannot represent (non-numeric text, or a magnitude past 39 digits) and were left as stored — range filters and ORDER BY over them stay wrong until they are corrected by hand.`);try{await d(t,i,n`INSERT INTO ${n.identifier(y)} (${n.identifier("name")}) VALUES (${e})`)}catch(a){if(!i.isUniqueViolation(a))throw a}},G=100,Y=t=>Object.entries(t.shape).filter(([,i])=>i._meta?.column!==void 0&&T(i)==="bigint").map(([i])=>i),H=(t,i)=>{const e=[],o=[];for(const s of i){const a=t[s];if(!(typeof a!="string"||a.length===N))try{const r=D(BigInt(a));e.push(n`${m(s)} = ${r}`),o.push(n`${m(s)} = ${a}`)}catch{}}return{assignments:e,guards:o}},X=async(t,i,e,o)=>{const s=Y(e);if(s.length===0)return;await P(t,o);const a=`bigint-key:${i}`;if(await F(t,o,a))return;const r=n.join(s.map(c=>n`(${m(c)} IS NOT NULL AND LENGTH(${m(c)}) <> ${N})`),n` OR `),f=n.join([m("id"),...s.map(c=>m(c))],n`, `);let l="",u=0;for(;;){const c=await w(t,o,n`SELECT ${f} FROM ${n.identifier(i)} WHERE (${r}) AND ${m("id")} > ${l} ORDER BY ${m("id")} LIMIT ${n.raw(String(G))}`);if(c.length===0){await K(t,o,a,i,u);return}const $=[];for(const h of c){const{id:b}=h,{assignments:I,guards:O}=typeof b=="string"?H(h,s):{assignments:[],guards:[]};if(I.length===0){u+=1;continue}$.push(n`UPDATE ${n.identifier(i)} SET ${n.join(I,n`, `)} WHERE ${m("id")} = ${b} AND ${n.join(O,n` AND `)}`)}await B(t,o,$);const g=c.at(-1)?.id;if(typeof g!="string")return;l=g}},V=async(t,i,e,o)=>{const s=[[p,o.companionTypes.integer],...Object.entries(e.shape).filter(([,r])=>r._meta?.column!==void 0).map(([r,f])=>[r,S(f,o)])],a=async r=>{try{return await w(t,o,n`SELECT ${n.join(r.map(f=>m(f)),n`, `)} FROM ${n.identifier(i)} LIMIT 0`),!0}catch{return!1}};if(!await a(s.map(([r])=>r)))for(const[r,f]of s)await a([r])||await d(t,o,n`ALTER TABLE ${n.identifier(i)} ADD COLUMN ${n.identifier(r)} ${n.raw(f)}`)},on=async(t,i,e)=>{for(const[o,s]of Object.entries(i.tables)){if(s.shardMode?.kind!=="global")continue;const a=k(o,s,e);await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(o)} (${a})`),await V(t,o,s,e),await j(t,o,s,e),await X(t,o,s,e)}},L=t=>t.shardMode===void 0||t.shardMode.kind==="global",rn=async(t,i,e)=>{const{integer:o,key:s,real:a}=e.companionTypes;for(const[r,f]of Object.entries(i.tables)){const l=f.aggregateIndexes;if(!(!l||l.length===0||!L(f)))for(const u of l){const c=C(r,u.name);await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(c)} (${n.identifier("__key__")} ${n.raw(s)} PRIMARY KEY, ${n.identifier("__value__")} ${n.raw(a)}, ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0)`),e.name==="sqlite"&&((await w(t,e,n`PRAGMA table_info(${n.identifier(c)})`)).some(g=>g.name==="__count__")||await d(t,e,n`ALTER TABLE ${n.identifier(c)} ADD COLUMN ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0`))}}},_=(t,i,e,o)=>{const s=t.name==="mysql"&&o?n`${n.identifier(i)}(191)`:n`${n.identifier(i)}`;return n`${s} ${n.raw(e)}`},W=(t,i,e)=>{const o=[_(t,"__partition__","ASC",!0)];for(const[s,a]of i.sortBy.entries()){const r=e.shape[a.field],f=r!==void 0&&t.indexKeyPrefix?.(T(r))!==void 0;o.push(_(t,A(s),a.direction==="desc"?"DESC":"ASC",f))}return o.push(_(t,"__id__","ASC",!0)),o},Q=(t,i,e)=>i.sortBy.map((o,s)=>{const a=e.shape[o.field],r=t.columnType(a?T(a):void 0);return n`${n.identifier(A(s))} ${n.raw(r)}`}),sn=async(t,i,e)=>{const{key:o}=e.companionTypes;for(const[s,a]of Object.entries(i.tables)){const r=a.rankIndexes;if(!(!r||r.length===0||!L(a)))for(const f of r){const l=q(s,f.name),u=Q(e,f,a),c=u.length>0?n`, ${n.join(u,n`, `)}`:n``;await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(l)} (${n.identifier("__id__")} ${n.raw(o)} PRIMARY KEY, ${n.identifier("__partition__")} ${n.raw(o)} NOT NULL${c})`);const $=W(e,f,a),g=`${s}__rank_${f.name}__btree`;await E(t,e,{columns:n.join($,n`, `),name:g,table:l,unique:!1})}}};export{rn as runSqlAggregateMigrations,on as runSqlGlobalTableMigrations,sn as runSqlRankMigrations};
@@ -1 +0,0 @@
1
- import{LunoraError as T}from"@lunora/errors";import{decodeBigintSqlKey as I,bigintSqlKey as R,BIGINT_KEY_DIGITS as U}from"@lunora/shard-engine";const B=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?B(t):r.kind},A=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},S=r=>{const t=atob(r),s=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)s[o]=t.codePointAt(o)??0;return s},i="$lunora.wire$",g=64,l=1024,m="__proto__",h={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},O={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},k=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>g)return!0;if(r===null)return!1;const s=typeof r;if(s==="string"||s==="boolean")return!1;if(s==="number")return!Number.isFinite(r);if(s!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===i?!0:r.some(o=>o===void 0||E(o,t+1));if(!k(r)||Object.hasOwn(r,m))return!0;for(const o of Object.keys(r)){const c=r[o];if(c!==void 0&&E(c,t+1))return!0}return!1},u=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===void 0)return[i,"undefined"];if(r===null)return null;const s=typeof r;if(s==="bigint")return[i,"bigint",r.toString()];if(s==="number"){const e=r;return Number.isNaN(e)?[i,"nan"]:e===1/0?[i,"inf"]:e===-1/0?[i,"-inf"]:e}if(s!=="object")return r;if(r instanceof Date)return[i,"date",u(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const y of Object.keys(e))e[y]!==void 0&&(n[y]=u(e[y],t+1));const f=[i,"error",e.name,e.message,n];return e.cause!==void 0&&f.push(u(e.cause,t+1)),f}if(r instanceof URL)return[i,"url",r.href];if(r instanceof Map)return[i,"map",[...r.entries()].map(([e,n])=>[u(e,t+1),u(n,t+1)])];if(r instanceof Set)return[i,"set",[...r].map(e=>u(e,t+1))];if(r instanceof ArrayBuffer)return[i,"bytes",A(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,f=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[i,"bytes",A(f)]:[i,"bytes",A(f),n]}if(Array.isArray(r)){const e=r.map(n=>u(n,t+1));return e.length>0&&e[0]===i?[i,"arr",e]:e}if(!k(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const o=r,c={};for(const e of Object.keys(o)){const n=o[e];if(n===void 0)continue;const f=u(n,t+1);e===m?Object.defineProperty(c,e,{configurable:!0,enumerable:!0,value:f,writable:!0}):c[e]=f}return c},a=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===i)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>a(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>l||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${l} digits)`);return BigInt(e)}case"date":{const e=a(r[2],t+1);if(typeof e!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(e)}case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[a(n[0],t+1),a(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>a(e,t+1)));case"url":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(e)}case"error":{const e=r[2],n=r[3],f=(Object.hasOwn(O,e)?O[e]:void 0)??Error,y=new f(n);y.name!==e&&Object.defineProperty(y,"name",{configurable:!0,value:e,writable:!0});const b=a(r[4],t+1);if(b===null||typeof b!="object"||Array.isArray(b))throw new TypeError("wire-codec: malformed error — props must be an object");for(const d of Object.keys(b))d===m?Object.defineProperty(y,d,{configurable:!0,enumerable:!0,value:b[d],writable:!0}):y[d]=b[d];return r.length>5&&Object.defineProperty(y,"cause",{configurable:!0,value:a(r[5],t+1),writable:!0}),y}case"bytes":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const n=S(e),f=r[3]??"Uint8Array";if(f==="ArrayBuffer")return n.buffer.byteLength===n.byteLength?n.buffer:n.slice().buffer;const y=Object.hasOwn(h,f)?h[f]:void 0;return y?new y(n.slice().buffer):n}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>a(e,t+1))}return r.map(c=>a(c,t+1))}const s=r,o={};for(const c of Object.keys(s)){const e=a(s[c],t+1);c===m?Object.defineProperty(o,c,{configurable:!0,enumerable:!0,value:e,writable:!0}):o[c]=e}return o},p=i,j=(r,t)=>r.startsWith(p)?a(t(r.slice(p.length))):t(r),L=r=>{if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return R(r);if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?p+JSON.stringify(u(r)):JSON.stringify(r)}catch(t){throw new T("BAD_REQUEST",`this value cannot be stored: ${t instanceof Error?t.message:String(t)}`)}},w=r=>{try{return JSON.parse(r)}catch{return r}},_=r=>{if(typeof r!="string")return r;const t=I(r);if(t!==void 0)return t;try{return BigInt(r)}catch{return r}},C=r=>B(r),D=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r!="string"?r:r.startsWith("{")||r.startsWith("[")||r.startsWith(p)?j(r,w):I(r)??r;case"array":case"geoPoint":case"object":case"record":return typeof r=="string"?j(r,w):r;case"bigint":return _(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}},x=U+1;export{x as B,D as a,u as b,_ as c,a as d,C as e,E as n,L as s,w as t};