@supalive/core 1.1.0 → 1.2.1
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.
- package/README.md +28 -0
- package/dist/db-ClCicssQ.js +28 -0
- package/dist/db-ClCicssQ.js.map +1 -0
- package/dist/{index-DouKwYL6.d.ts → index-DJYvJYR4.d.ts} +214 -9
- package/dist/index-DJYvJYR4.d.ts.map +1 -0
- package/dist/{mysql-Bxurg_PH.d.ts → mysql-53W9lRh9.d.ts} +8 -3
- package/dist/mysql-53W9lRh9.d.ts.map +1 -0
- package/dist/{mysql-bvnjYWvZ.js → mysql-C0mysDQ_.js} +57 -25
- package/dist/mysql-C0mysDQ_.js.map +1 -0
- package/dist/{overlap-checker-Ct_HP_iB.js → overlap-checker-ClJC0nxW.js} +52 -4
- package/dist/overlap-checker-ClJC0nxW.js.map +1 -0
- package/dist/{postgres-Ck-xt72U.d.ts → postgres-7d6R9P7w.d.ts} +8 -3
- package/dist/postgres-7d6R9P7w.d.ts.map +1 -0
- package/dist/{postgres-B8u1YN8X.js → postgres-SvdXfb0w.js} +55 -22
- package/dist/postgres-SvdXfb0w.js.map +1 -0
- package/dist/{procedure-DX87tyef.js → procedure-Ze1GE-N9.js} +33 -2
- package/dist/procedure-Ze1GE-N9.js.map +1 -0
- package/dist/{query-Bh0RNxDz.js → query-CrbJ_W0W.js} +21 -1
- package/dist/query-CrbJ_W0W.js.map +1 -0
- package/dist/{realtime_db-DOCgqbwi.js → realtime_db-BtwBABDY.js} +76 -51
- package/dist/realtime_db-BtwBABDY.js.map +1 -0
- package/dist/{router-DlTYWpop.js → router-CiWYeWUR.js} +8 -2
- package/dist/router-CiWYeWUR.js.map +1 -0
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/index.js +44 -5
- package/dist/src/client/index.js.map +1 -1
- package/dist/src/exports/mysql.d.ts +1 -1
- package/dist/src/exports/mysql.js +1 -1
- package/dist/src/exports/postgres.d.ts +1 -1
- package/dist/src/exports/postgres.js +1 -1
- package/dist/src/exports/procedure.d.ts +2 -2
- package/dist/src/exports/procedure.js +4 -4
- package/dist/src/exports/schema-sql.d.ts +36 -2
- package/dist/src/exports/schema-sql.d.ts.map +1 -1
- package/dist/src/exports/schema-sql.js +74 -19
- package/dist/src/exports/schema-sql.js.map +1 -1
- package/dist/src/exports/server.d.ts +65 -17
- package/dist/src/exports/server.d.ts.map +1 -1
- package/dist/src/exports/server.js +724 -63
- package/dist/src/exports/server.js.map +1 -1
- package/dist/src/exports/subscription-manager-worker-entry.js +8 -5
- package/dist/src/exports/subscription-manager-worker-entry.js.map +1 -1
- package/dist/src/exports/types.d.ts +3 -3
- package/dist/src/exports/types.js +1 -1
- package/dist/{subscription-worker-CqoWp6zB.js → subscription-worker-B2XtjFWY.js} +307 -69
- package/dist/subscription-worker-B2XtjFWY.js.map +1 -0
- package/dist/{types_db-DXj_l9n-.js → types_db-CTRm_awX.js} +7 -2
- package/dist/types_db-CTRm_awX.js.map +1 -0
- package/dist/types_server-wW3ZgE7l.d.ts +420 -0
- package/dist/types_server-wW3ZgE7l.d.ts.map +1 -0
- package/package.json +5 -4
- package/dist/index-CaWMDqq0.d.ts +0 -1754
- package/dist/index-CaWMDqq0.d.ts.map +0 -1
- package/dist/index-DouKwYL6.d.ts.map +0 -1
- package/dist/mysql-Bxurg_PH.d.ts.map +0 -1
- package/dist/mysql-Cxd4Uq5p.d.ts +0 -104
- package/dist/mysql-Cxd4Uq5p.d.ts.map +0 -1
- package/dist/mysql-bvnjYWvZ.js.map +0 -1
- package/dist/overlap-checker-Ct_HP_iB.js.map +0 -1
- package/dist/postgres-B8u1YN8X.js.map +0 -1
- package/dist/postgres-CfT_aDx3.d.ts +0 -108
- package/dist/postgres-CfT_aDx3.d.ts.map +0 -1
- package/dist/postgres-Ck-xt72U.d.ts.map +0 -1
- package/dist/procedure-DX87tyef.js.map +0 -1
- package/dist/query-Bh0RNxDz.js.map +0 -1
- package/dist/realtime_db-DOCgqbwi.js.map +0 -1
- package/dist/router-DlTYWpop.js.map +0 -1
- package/dist/src/exports/codegen.d.ts +0 -38
- package/dist/src/exports/codegen.d.ts.map +0 -1
- package/dist/src/exports/codegen.js +0 -134
- package/dist/src/exports/codegen.js.map +0 -1
- package/dist/subscription-worker-CqoWp6zB.js.map +0 -1
- package/dist/subscription-worker-PtmJWEj1.js +0 -511
- package/dist/subscription-worker-PtmJWEj1.js.map +0 -1
- package/dist/subscription-worker-pahX0zxg.js +0 -511
- package/dist/subscription-worker-pahX0zxg.js.map +0 -1
- package/dist/types_db-DXj_l9n-.js.map +0 -1
- package/dist/types_server-BW1ys_SK.d.ts +0 -216
- package/dist/types_server-BW1ys_SK.d.ts.map +0 -1
- package/dist/types_server-Dpsi0wpG.d.ts +0 -216
- package/dist/types_server-Dpsi0wpG.d.ts.map +0 -1
- package/dist/types_server-DzrIccyO.d.ts +0 -216
- package/dist/types_server-DzrIccyO.d.ts.map +0 -1
- package/dist/types_server-TFo6SWDH.d.ts +0 -216
- package/dist/types_server-TFo6SWDH.d.ts.map +0 -1
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { An as CacheLayer, Cn as DbType, En as PreparedQueries, On as SqlBuilder, Or as ReadEntry, Sn as DbQueryResult, Tn as PooledClient, Zn as CommitLogEntry, jr as WriteEntry, kn as TxDatabase, wn as LazyCommitTsParam, xn as Database } from "./index-DouKwYL6.js";
|
|
2
|
-
import { Pool, PoolConfig } from "pg";
|
|
3
|
-
import { Logger } from "pino";
|
|
4
|
-
|
|
5
|
-
//#region src/db/postgres.d.ts
|
|
6
|
-
declare class PgDatabase implements Database {
|
|
7
|
-
constructor(logger: Logger, config: PoolConfig, pool?: Pool | undefined);
|
|
8
|
-
private logger;
|
|
9
|
-
config: PoolConfig;
|
|
10
|
-
private pool;
|
|
11
|
-
readonly sqlBuilder: SqlBuilder;
|
|
12
|
-
readonly dbType: DbType;
|
|
13
|
-
columnTypes: Map<string, Map<string, string>>;
|
|
14
|
-
protected sqlCache: Map<string, string>;
|
|
15
|
-
/**
|
|
16
|
-
* Fetches actual column types from Postgres for `table` and returns a
|
|
17
|
-
* map of DB column name → PG type string (as produced by `format_type`,
|
|
18
|
-
* e.g. `bigint`, `integer`, `character varying(32)`, `text[]`, `jsonb`).
|
|
19
|
-
* No caching here — see {@link getColumnTypes} for the cached path.
|
|
20
|
-
*/
|
|
21
|
-
loadColumnTypesFromPg(table: string): Promise<Map<string, string>>;
|
|
22
|
-
/**
|
|
23
|
-
* Synchronous column-type lookup. The apply path calls this on every
|
|
24
|
-
* batched write, so it can't await — populate the cache via
|
|
25
|
-
* {@link bootstrapColumnTypes} at server start. Throws if `table` is
|
|
26
|
-
* missing (programmer error / bootstrap skipped).
|
|
27
|
-
*/
|
|
28
|
-
getColumnTypes(table: string): Map<string, string> | null;
|
|
29
|
-
/**
|
|
30
|
-
* Eagerly load column types into the in-memory cache. With a Redis
|
|
31
|
-
* client supplied, attempts the cache key first and falls through to
|
|
32
|
-
* Postgres on miss (writing the result back to Redis). This is the
|
|
33
|
-
* "one server queries PG, the rest read from Redis" pattern for cold
|
|
34
|
-
* starts in a multi-instance deploy. Without Redis, always queries PG.
|
|
35
|
-
*
|
|
36
|
-
* Pass `tables` to limit the load to a specific list; otherwise every
|
|
37
|
-
* user table in the connected database is loaded.
|
|
38
|
-
*
|
|
39
|
-
* The Redis cache key should encode whatever invalidates types in your
|
|
40
|
-
* environment (typically a schema version / deploy version). The
|
|
41
|
-
* subscriber in supalive-server.ts is expected to publish a reload
|
|
42
|
-
* signal after migrations and invoke {@link invalidateColumnTypes}.
|
|
43
|
-
*/
|
|
44
|
-
bootstrapColumnTypes(opts: {
|
|
45
|
-
redis?: CacheLayer;
|
|
46
|
-
cacheKey: string;
|
|
47
|
-
tables?: string[];
|
|
48
|
-
}): Promise<void>;
|
|
49
|
-
/**
|
|
50
|
-
* Invalidate cached types (and dependent SQL) for `table`, or the entire
|
|
51
|
-
* cache if `table` is omitted. The Redis-pubsub reload signal in
|
|
52
|
-
* supalive-server.ts is expected to call this on schema changes.
|
|
53
|
-
*/
|
|
54
|
-
private invalidateColumnTypes;
|
|
55
|
-
/** Enumerate the user-defined tables in the connected database — used
|
|
56
|
-
* by bootstrapColumnTypes() when no explicit list is provided. */
|
|
57
|
-
private listUserTables;
|
|
58
|
-
migrationSql: string[];
|
|
59
|
-
query<T = any>(sql: string, params?: unknown[]): Promise<DbQueryResult<T>>;
|
|
60
|
-
getClient(): Promise<PooledClient>;
|
|
61
|
-
getTransactionClient(): Promise<TxDatabase>;
|
|
62
|
-
/** Internal: replace this instance's caches with shared references from
|
|
63
|
-
* a parent. Used by PgDatabase.getTransactionClient. */
|
|
64
|
-
adoptCaches(columnTypes: Map<string, Map<string, string>>, sqlCache: Map<string, string>): void;
|
|
65
|
-
getLatestSnapshotTimestamp(): Promise<bigint>;
|
|
66
|
-
updateLatestSnapshotTimestamp(commitTs: bigint): Promise<void>;
|
|
67
|
-
getNextTimestamp(): Promise<bigint>;
|
|
68
|
-
attachPrevDataToWriteSet(writeSet: WriteEntry[], readSet: ReadEntry[]): Promise<void>;
|
|
69
|
-
prepareCommitWrites(readSet: ReadEntry[], writeSet: WriteEntry[], commitTs: LazyCommitTsParam): Promise<PreparedQueries>;
|
|
70
|
-
private pgPrepareBatchWrites;
|
|
71
|
-
private pgPrepareInsertSingle;
|
|
72
|
-
private pgPrepareInsertBatch;
|
|
73
|
-
private pgPrepareUpdateSingle;
|
|
74
|
-
private pgPrepareUpdateBatch;
|
|
75
|
-
private pgPrepareDeleteSingle;
|
|
76
|
-
private pgPrepareDeleteBatch;
|
|
77
|
-
private buildOrGetInsertSql;
|
|
78
|
-
private buildOrGetUpdateSql;
|
|
79
|
-
private buildOrGetDeleteSql;
|
|
80
|
-
private pgPrepareCommitLogs;
|
|
81
|
-
/**
|
|
82
|
-
* Point-only OCC check. For each genuine point read, compare the row's
|
|
83
|
-
* current commit_ts against the value captured at read time. A `null`
|
|
84
|
-
* expectedCommitTs means "row didn't exist when we read"; any row found
|
|
85
|
-
* now is a conflict. Reads whose row is being written in this same txn
|
|
86
|
-
* are skipped — the CAS UPDATE/DELETE already validated those.
|
|
87
|
-
*/
|
|
88
|
-
private pgPrepareValidatePointReadsByCommitTs;
|
|
89
|
-
commitWrites(beginTs: bigint, queries: PreparedQueries, commitTs: bigint): Promise<{
|
|
90
|
-
success: boolean;
|
|
91
|
-
}>;
|
|
92
|
-
private pgApplyWrites;
|
|
93
|
-
/**
|
|
94
|
-
* Point-only OCC check. For each genuine point read, compare the row's
|
|
95
|
-
* current commit_ts against the value captured at read time. A `null`
|
|
96
|
-
* expectedCommitTs means "row didn't exist when we read"; any row found
|
|
97
|
-
* now is a conflict. Reads whose row is being written in this same txn
|
|
98
|
-
* are skipped — the CAS UPDATE/DELETE already validated those.
|
|
99
|
-
*/
|
|
100
|
-
private validatePointReadsByCommitTs;
|
|
101
|
-
pruneCommitLogsBefore(ts: bigint): Promise<bigint>;
|
|
102
|
-
getCommitLogsBetweenTs(beginTs: bigint, endTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;
|
|
103
|
-
getCommitLogsSinceTs(sinceTs: bigint, excludeTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;
|
|
104
|
-
close(): Promise<void>;
|
|
105
|
-
}
|
|
106
|
-
//#endregion
|
|
107
|
-
export { PgDatabase as t };
|
|
108
|
-
//# sourceMappingURL=postgres-CfT_aDx3.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-CfT_aDx3.d.ts","names":[],"sources":["../src/db/postgres.ts"],"mappings":";;;;;cAiBa,UAAA,YAAsB,QAAA;cAE/B,MAAA,EAAQ,MAAA,EACR,MAAA,EAAQ,UAAA,EACR,IAAA,GAAM,IAAA;EAAA,QAWA,MAAA;EACD,MAAA,EAAQ,UAAA;EAAA,QACP,IAAA;EAAA,SACC,UAAA,EAAY,UAAA;EAAA,SACZ,MAAA,EAAQ,MAAA;EAMV,WAAA,EAAa,GAAA,SAAY,GAAA;EAAA,UAGtB,QAAA,EAAU,GAAA;EAHY;;;;;;EAW1B,qBAAA,CAAsB,KAAA,WAAgB,OAAA,CAAQ,GAAA;EAoDhD;;;;;;EA5BJ,cAAA,CAAe,KAAA,WAAgB,GAAA;EAuID;;;;;;;;;;;;;;;EA/GxB,oBAAA,CAAqB,IAAA;IACzB,KAAA,GAAQ,UAAA;IACR,QAAA;IACA,MAAA;EAAA,IACE,OAAA;EA02BkF;;;;;EAAA,QAh0B9E,qBAAA;EAlIiC;;EAAA,QAgJ3B,cAAA;EAUd,YAAA;EAsBM,KAAA,UAAe,GAAA,UAAa,MAAA,eAAyB,OAAA,CAAQ,aAAA,CAAc,CAAA;EAe3E,SAAA,IAAa,OAAA,CAAQ,YAAA;EAIrB,oBAAA,IAAwB,OAAA,CAAQ,UAAA;EAhMpC;;EA4MF,WAAA,CACE,WAAA,EAAa,GAAA,SAAY,GAAA,mBACzB,QAAA,EAAU,GAAA;EAMN,0BAAA,IAA8B,OAAA;EAK9B,6BAAA,CAA8B,QAAA,WAAmB,OAAA;EAOjD,gBAAA,IAAoB,OAAA;EAuBpB,wBAAA,CAAyB,QAAA,EAAU,UAAA,IAAc,OAAA,EAAS,SAAA,KAAc,OAAA;EAgExE,mBAAA,CACJ,OAAA,EAAS,SAAA,IACT,QAAA,EAAU,UAAA,IACV,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,eAAA;EAAA,QAoBG,oBAAA;EAAA,QA2BN,qBAAA;EAAA,QAkBM,oBAAA;EAAA,QA+DN,qBAAA;EAAA,QAwBM,oBAAA;EAAA,QAsEN,qBAAA;EAAA,QAgBM,oBAAA;EAAA,QAiDN,mBAAA;EAAA,QAqBA,mBAAA;EAAA,QA4BA,mBAAA;EAAA,QAcM,mBAAA;EAxnBsC;;;;;;;EAAA,QAsqB5C,qCAAA;EAkDF,YAAA,CACJ,OAAA,UACA,OAAA,EAAS,eAAA,EACT,QAAA,WACC,OAAA;IAAU,OAAA;EAAA;EAAA,QAqCC,aAAA;EArpBA;;;;;;;EAAA,QAgwBA,4BAAA;EA0CR,qBAAA,CAAsB,EAAA,WAAa,OAAA;EAQnC,sBAAA,CAAuB,OAAA,UAAiB,KAAA,UAAe,QAAA,EAAU,UAAA,KAAe,OAAA,CAAQ,cAAA;EAmBxF,oBAAA,CAAqB,OAAA,UAAiB,SAAA,UAAmB,QAAA,EAAU,UAAA,KAAe,OAAA,CAAQ,cAAA;EAmB1F,KAAA,IAAS,OAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-Ck-xt72U.d.ts","names":[],"sources":["../src/db/postgres.ts"],"mappings":";;;;;cAiBa,UAAA,YAAsB,QAAA;cAE/B,MAAA,EAAQ,MAAA,EACR,MAAA,EAAQ,UAAA,EACR,IAAA,GAAM,IAAA;EAAA,QAWA,MAAA;EACD,MAAA,EAAQ,UAAA;EAAA,QACP,IAAA;EAAA,SACC,UAAA,EAAY,UAAA;EAAA,SACZ,MAAA,EAAQ,MAAA;EAMV,WAAA,EAAa,GAAA,SAAY,GAAA;EAAA,UAGtB,QAAA,EAAU,GAAA;EAHY;;;;;;EAW1B,qBAAA,CAAsB,KAAA,WAAgB,OAAA,CAAQ,GAAA;EAoDhD;;;;;;EA5BJ,cAAA,CAAe,KAAA,WAAgB,GAAA;EAuID;;;;;;;;;;;;;;;EA/GxB,oBAAA,CAAqB,IAAA;IACzB,KAAA,GAAQ,UAAA;IACR,QAAA;IACA,MAAA;EAAA,IACE,OAAA;EA02BkF;;;;;EAAA,QAh0B9E,qBAAA;EAlIiC;;EAAA,QAgJ3B,cAAA;EAUd,YAAA;EAsBM,KAAA,UAAe,GAAA,UAAa,MAAA,eAAyB,OAAA,CAAQ,aAAA,CAAc,CAAA;EAe3E,SAAA,IAAa,OAAA,CAAQ,YAAA;EAIrB,oBAAA,IAAwB,OAAA,CAAQ,UAAA;EAhMpC;;EA4MF,WAAA,CACE,WAAA,EAAa,GAAA,SAAY,GAAA,mBACzB,QAAA,EAAU,GAAA;EAMN,0BAAA,IAA8B,OAAA;EAK9B,6BAAA,CAA8B,QAAA,WAAmB,OAAA;EAOjD,gBAAA,IAAoB,OAAA;EAuBpB,wBAAA,CAAyB,QAAA,EAAU,UAAA,IAAc,OAAA,EAAS,SAAA,KAAc,OAAA;EAgExE,mBAAA,CACJ,OAAA,EAAS,SAAA,IACT,QAAA,EAAU,UAAA,IACV,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,eAAA;EAAA,QAoBG,oBAAA;EAAA,QA2BN,qBAAA;EAAA,QAkBM,oBAAA;EAAA,QA+DN,qBAAA;EAAA,QAwBM,oBAAA;EAAA,QAsEN,qBAAA;EAAA,QAgBM,oBAAA;EAAA,QAiDN,mBAAA;EAAA,QAqBA,mBAAA;EAAA,QA4BA,mBAAA;EAAA,QAcM,mBAAA;EAxnBsC;;;;;;;EAAA,QAsqB5C,qCAAA;EAkDF,YAAA,CACJ,OAAA,UACA,OAAA,EAAS,eAAA,EACT,QAAA,WACC,OAAA;IAAU,OAAA;EAAA;EAAA,QAqCC,aAAA;EArpBA;;;;;;;EAAA,QAgwBA,4BAAA;EA0CR,qBAAA,CAAsB,EAAA,WAAa,OAAA;EAQnC,sBAAA,CAAuB,OAAA,UAAiB,KAAA,UAAe,QAAA,EAAU,UAAA,KAAe,OAAA,CAAQ,cAAA;EAmBxF,oBAAA,CAAqB,OAAA,UAAiB,SAAA,UAAmB,QAAA,EAAU,UAAA,KAAe,OAAA,CAAQ,cAAA;EAmB1F,KAAA,IAAS,OAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"procedure-DX87tyef.js","names":[],"sources":["../src/router/procedure.ts"],"sourcesContent":["import type { ZodType } from \"zod\";\nimport type { DbReader, DbWriter } from \"../db/context\";\nimport type { SupaliveDb } from \"../db/realtime_db\";\n\n// ─── Context Types ───────────────────────────────────────────────────────────\n\n/**\n * Query context passed to query handlers.\n * Contains database reader and user-defined server context.\n */\nexport interface QueryCtx<TContext = unknown> {\n /** Database reader for queries */\n db: DbReader;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Mutation context passed to mutation handlers.\n * Contains database writer and user-defined server context.\n */\nexport interface MutationCtx<TContext = unknown> {\n /** Database writer for mutations (includes insert/update/delete) */\n db: DbWriter;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Action context passed to action handlers.\n * Contains the full SupaliveDb for both queries and mutations, plus user-defined server context.\n */\nexport interface ActionCtx<TContext = unknown> {\n /** Full database interface for queries and mutations */\n db: SupaliveDb;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n// ─── Procedure Types ─────────────────────────────────────────────────────────\n\nexport type QueryFn<TInput, TResult, TContext = unknown> = (\n ctx: QueryCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type MutationFn<TInput, TResult, TContext = unknown> = (\n ctx: MutationCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type ActionFn<TInput, TResult, TContext = unknown> = (\n ctx: ActionCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\n/**\n * Per-procedure override for the cache/subscription segmentation key.\n *\n * omitted | undefined → fall back to `config.getUserId(serverCtx)` (default)\n * false → no identity in hash; cache/sub shared across all users\n * string → a static identity literal (e.g. \"public\" or a tenant id)\n * function → compute from serverCtx + input (sync)\n *\n * When the result of a query is identical regardless of who calls it, set\n * this to a literal (or `false`) so a single cache entry serves everyone.\n *\n * The function form intentionally takes `serverCtx` (not the full `QueryCtx`)\n * because identity is resolved before any DB read is issued.\n */\nexport type QueryIdentitySpec<TInput, TContext> =\n | false\n | string\n | ((serverCtx: TContext, input: TInput) => string | null | undefined);\n\nexport interface BaseProcedure<\n TInput, TResult,\n TType extends \"query\" | \"mutation\" | \"action\",\n TContext = unknown,\n TInternal extends boolean = boolean\n> {\n readonly _type: \"procedure\";\n readonly procedureType: TType;\n readonly inputSchema: ZodType<TInput>;\n readonly fn: QueryFn<TInput, TResult, TContext> | MutationFn<TInput, TResult, TContext> | ActionFn<TInput, TResult, TContext>;\n readonly internal: TInternal;\n}\n\nexport interface QueryProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"query\", TContext, TInternal> {\n readonly procedureType: \"query\";\n readonly fn: QueryFn<TInput, TResult, TContext>;\n readonly queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"mutation\", TContext, TInternal> {\n readonly procedureType: \"mutation\";\n readonly fn: MutationFn<TInput, TResult, TContext>;\n}\n\nexport interface ActionProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"action\", TContext, TInternal> {\n readonly procedureType: \"action\";\n readonly fn: ActionFn<TInput, TResult, TContext>;\n}\n\nexport type AnyProcedure<TContext = unknown> =\n | QueryProcedure<any, any, TContext>\n | MutationProcedure<any, any, TContext>\n | ActionProcedure<any, any, TContext>;\n\n// ─── Procedure Configuration Types ───────────────────────────────────────────\n\nexport interface QueryConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The query handler function */\n handler: QueryFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Override the cache/subscription segmentation key for this procedure.\n * See {@link QueryIdentitySpec}. Omit to keep the default (per-user) behavior.\n */\n queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The mutation handler function */\n handler: MutationFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n}\n\nexport interface ActionConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The action handler function */\n handler: ActionFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n}\n\n/** Extract input type from a procedure */\nexport type InputOf<T> = T extends BaseProcedure<infer I, any, any, any> ? I : never;\n\n/** Extract output type from a procedure */\nexport type OutputOf<T> = T extends BaseProcedure<any, infer O, any, any> ? O : never;\n\n/** Extract procedure type (query/mutation) */\nexport type TypeOf<T> = T extends BaseProcedure<any, any, infer Type, any> ? Type : never;\n\n/** Extract server context type from a procedure */\nexport type ContextOf<T> = T extends BaseProcedure<any, any, any, infer C> ? C : never;\n\n/**\n * Create a query builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your query handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed query builder\n * const query = createQueryBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const getUser = query({\n * args: z.object({ id: z.string() }),\n * handler: async (ctx, { id }) => {\n * // ctx.db for database queries\n * const user = await ctx.db.query(UsersSchema).find(id);\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return user;\n * }\n * });\n */\nexport function createQueryBuilder<TContext = unknown>() {\n return function query<TInput, TResult, const TInternal extends boolean = false>(\n config: QueryConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): QueryProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"query\",\n inputSchema: config.args,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n queryIdentity: config.queryIdentity,\n };\n };\n}\n\n// ─── Mutation Builder Factory ────────────────────────────────────────────────\n\n/**\n * Create a mutation builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your mutation handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed mutation builder\n * const mutation = createMutationBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const createUser = mutation({\n * args: z.object({ name: z.string() }),\n * handler: async (ctx, { name }) => {\n * // ctx.db for mutations\n * await ctx.db.insert(UsersSchema, id, { name });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createMutationBuilder<TContext = unknown>() {\n return function mutation<TInput, TResult, const TInternal extends boolean = false>(\n config: MutationConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): MutationProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"mutation\",\n inputSchema: config.args,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}\n\n// ─── Action Builder Factory ──────────────────────────────────────────────────\n\n/**\n * Create an action builder with a pre-defined context type.\n * Actions have access to the full SupaliveDb for both queries and mutations.\n *\n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n *\n * // Create a typed action builder\n * const action = createActionBuilder<ServerContext>();\n *\n * // Use it - context type is automatically inferred!\n * const processOrder = action({\n * args: z.object({ orderId: z.string() }),\n * handler: async (ctx, { orderId }) => {\n * // ctx.db for full database access\n * const order = await ctx.db.query(async (db) => {\n * return db.query(OrdersSchema).find(orderId);\n * });\n * await ctx.db.mutation(async (db) => {\n * await db.update(OrdersSchema, orderId, { status: \"processed\" });\n * });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createActionBuilder<TContext = unknown>() {\n return function action<TInput, TResult, const TInternal extends boolean = false>(\n config: ActionConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): ActionProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"action\",\n inputSchema: config.args,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkMA,SAAgB,qBAAyC;CACvD,OAAO,SAAS,MACd,QACsD;EACtD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;GAC9B,eAAe,OAAO;EACxB;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,wBAA4C;CAC1D,OAAO,SAAS,SACd,QACyD;EACzD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,sBAA0C;CACxD,OAAO,SAAS,OACd,QACuD;EACvD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-Bh0RNxDz.js","names":["formatComment","z"],"sources":["../src/db/sqlcommenter.ts","../src/db/query.ts"],"sourcesContent":["export function comment(input: string | Record<string, string>): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return `/*${input}*/`;\n const entries = Object.entries(input).filter(([_, v]) => v != null);\n if (entries.length === 0) return \"\";\n const pairs = entries\n .map(([k, v]) => `${encodeURIComponent(k)}='${encodeURIComponent(v)}'`)\n .sort();\n return `/*${pairs.join(\",\")}*/`;\n}\n","import { z, ZodRawShape } from \"zod\";\nimport { Predicate, LeafPredicate, CompareOperator, QuerySpec, RangeRead } from \"./types_db\";\nimport {\n ColumnCodec, ComputedCodec, ComputedDataType, ComputedField, ComputedFieldConfig,\n InferSchema, Model, OverrideField, Prettify, SchemaDefinition\n} from \"./schema\";\nimport { TxContext } from \"./context\";\nimport { normalizeCodec } from \"./codec\";\nimport { SqlBuilder } from \"./db\";\nimport { bytesEqual } from \"./bytes\";\nimport { comment as formatComment } from \"./sqlcommenter\";\n\n// Decoded value type of a schema field (codec-applied), narrowed to the\n// caller's key. `K` is not constrained to `keyof InferSchema<S>` so callers\n// can pass a key constrained to a subset (e.g. StringFieldKeys) without\n// TypeScript widening the resulting value type.\ntype FieldValue<S extends SchemaDefinition<string, ZodRawShape>, K> =\n K extends keyof InferSchema<S> ? InferSchema<S>[K] : never;\n\ntype OrderableValue = number | bigint | string | Date;\n\n// Keys whose decoded value is string-like (covers `string`, string literal\n// unions like enums, and `string | null | undefined`).\ntype StringFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = {\n [K in keyof InferSchema<S>]: NonNullable<InferSchema<S>[K]> extends string ? K : never;\n}[keyof InferSchema<S>];\n\n// Keys whose decoded value supports SQL ordering (gt/gte/lt/lte/between).\ntype OrderableFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = {\n [K in keyof InferSchema<S>]: NonNullable<InferSchema<S>[K]> extends OrderableValue ? K : never;\n}[keyof InferSchema<S>];\n\n// Keys whose decoded value is shaped like a JSON/JSONB column (object/array/unknown).\n// Used to constrain jsonContains / jsonContainedBy / jsonHasKey / jsonArrayContains\n// so they can't be invoked on plain scalar fields.\ntype JsonFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = {\n [K in keyof InferSchema<S>]:\n NonNullable<InferSchema<S>[K]> extends OrderableValue ? never :\n NonNullable<InferSchema<S>[K]> extends boolean ? never :\n NonNullable<InferSchema<S>[K]> extends (object | unknown[]) ? K :\n unknown extends NonNullable<InferSchema<S>[K]> ? K :\n never;\n}[keyof InferSchema<S>];\n\nexport interface JsonOpOptions {\n /**\n * Skip client-side preparation of the value (no JSON-stringify, no key\n * escaping). The caller is responsible for the exact form the dialect\n * expects: a JSON path string for jsonHasKey, a JSON-encoded string for\n * the contains family.\n */\n raw?: true;\n}\n\nexport interface JsonContainsOptions extends JsonOpOptions {\n /**\n * Sub-path into the target JSON to scope the check to. `string` is a\n * single literal top-level key; `string[]` is a nested literal-key path\n * compiled to `$.\"a\".\"b\"`. Mutually exclusive with `pathRaw`.\n */\n path?: string | string[];\n /**\n * Raw jsonpath expression used verbatim by the dialect (PG `jsonpath`,\n * MySQL JSON path). Mutually exclusive with `path`.\n */\n pathRaw?: string;\n}\n\nexport interface JsonHasKeyMultiOptions extends JsonOpOptions {\n /** Required for the multi-path overload — chooses any vs every. */\n mode: \"one\" | \"all\";\n}\n\n// Escape and join a key path into a JSON path expression usable by both\n// PG (`jsonb_path_exists`) and MySQL (`JSON_CONTAINS_PATH`):\n// [\"a\", \"b.c\"] → `$.\"a\".\"b.c\"`\nfunction jsonKeysToPath(keys: string[]): string {\n let out = \"$\";\n for (const k of keys) {\n out += `.\"${k.replace(/\"/g, '\\\\\"')}\"`;\n }\n return out;\n}\n\n// Resolve the `path` / `pathRaw` option pair down to a single jsonpath\n// expression. Returns a string in `$.\"...\"` form for structured `path`,\n// or the caller's `pathRaw` verbatim. Returns `undefined` when neither is\n// set. Throws when both are supplied.\nfunction resolveJsonPath(opts: JsonContainsOptions | undefined): string | undefined {\n if (opts?.path !== undefined && opts?.pathRaw !== undefined) {\n throw new Error(\"jsonContains: pass either `path` or `pathRaw`, not both\");\n }\n if (opts?.pathRaw !== undefined) return opts.pathRaw;\n if (opts?.path !== undefined) {\n const arr = Array.isArray(opts.path) ? opts.path : [opts.path];\n return jsonKeysToPath(arr);\n }\n return undefined;\n}\n\nexport class QueryBuilder<S extends SchemaDefinition<string, ZodRawShape>> {\n constructor(\n protected ctx: TxContext,\n protected model: Model\n ) { }\n\n protected getColumnName(key: string): string {\n return this.model.columns[key] ?? key;\n }\n\n select(): SelectQueryBuilder<S, keyof InferSchema<S>>;\n select<K extends keyof InferSchema<S>>(...columns: K[]): SelectQueryBuilder<S, K>;\n select<K extends keyof InferSchema<S>>(...columns: K[]): SelectQueryBuilder<S, K> {\n const selectedProps = (columns.length > 0 ? columns : Object.keys(this.model.columns)) as K[];\n return new SelectQueryBuilder<S, K>(this.ctx, this.model, [], null, null, null, selectedProps);\n }\n}\n\nexport type IdAndCommitTs = { id: string; commitTs: bigint };\n\n// Row type returned by `.get()`, `.find()`, `.first()`. Selected schema keys\n// plus the always-included id/commitTs and any computed fields, flattened so\n// the IDE renders a plain object literal instead of an intersection chain.\ntype SelectRow<\n S extends SchemaDefinition<string, ZodRawShape>,\n K extends keyof InferSchema<S>,\n C extends Record<string, unknown>,\n> = Prettify<Pick<InferSchema<S>, Extract<K | \"id\" | \"commitTs\", keyof InferSchema<S>>> & C>;\n\nclass SelectQueryBuilder<\n S extends SchemaDefinition<string, ZodRawShape>,\n K extends keyof InferSchema<S> = never,\n C extends Record<string, unknown> = {},\n> {\n private filters: ((fb: FilterBuilder<S>) => void)[] = [];\n private orderByClause: string | null = null;\n private limitVal: number | null = null;\n private offsetVal: number | null = null;\n private selectedProps: (keyof InferSchema<S>)[] = [];\n private computedFields: ComputedField[] = [];\n private commentStr: string = \"\";\n\n constructor(\n private ctx: TxContext,\n private model: Model,\n filters: ((fb: FilterBuilder<S>) => void)[] = [],\n orderByClause: string | null = null,\n limitVal: number | null = null,\n offsetVal: number | null = null,\n selectedProps: (keyof InferSchema<S>)[] = [],\n computedFields: ComputedField[] = [],\n commentStr: string = \"\",\n ) {\n this.filters = filters;\n this.orderByClause = orderByClause;\n this.limitVal = limitVal;\n this.offsetVal = offsetVal;\n this.selectedProps = selectedProps;\n this.computedFields = computedFields;\n this.commentStr = commentStr;\n }\n\n private getColumnName(key: string): string {\n return this.model.columns[key] ?? key;\n }\n\n private getPropertyName(column: string): string {\n return this.model.reverseColumns[column] ?? this.computedFields.find(f => f.alias === column)?.field ?? column;\n }\n\n private mapRowToSchema(row: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n for (const [col, value] of Object.entries(row)) {\n const prop = this.getPropertyName(col)\n const codec = this.model.codecs[prop] ?? this.computedFields.find((f) => f.alias === col)?.codec;\n result[prop] = codec?.decode && value !== undefined && value !== null ? codec.decode(value) : value;\n }\n return result;\n }\n\n where(filterFn: (fb: FilterBuilder<S>) => void): SelectQueryBuilder<S, K, C> {\n this.filters.push(filterFn);\n return this;\n }\n\n orderBy(\n column: keyof InferSchema<S> | keyof C,\n direction: \"asc\" | \"desc\" = \"asc\",\n ): SelectQueryBuilder<S, K, C> {\n this.orderByClause = `${this.getColumnName(column as string)} ${direction}`;\n return this\n }\n\n limit(n: number): SelectQueryBuilder<S, K, C> {\n this.limitVal = n;\n return this;\n }\n\n offset(n: number): SelectQueryBuilder<S, K, C> {\n this.offsetVal = n;\n return this;\n }\n computed<\n TField extends string,\n TZodType extends z.ZodTypeAny | undefined = undefined,\n TDecode extends (value: any) => any = (value: unknown) => unknown,\n >(\n config: ComputedFieldConfig<TField, ReturnType<TDecode>, Parameters<TDecode>[0], TZodType> & {\n codec: {\n decode: TDecode;\n encode?: (value: ReturnType<TDecode>) => Parameters<TDecode>[0];\n };\n }\n ): SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<ComputedCodec<ReturnType<TDecode>, Parameters<TDecode>[0]>, TZodType>>>;\n computed<\n TField extends string,\n TZodType extends z.ZodTypeAny | undefined = undefined,\n >(\n config: ComputedFieldConfig<TField, unknown, unknown, TZodType> & {\n codec?: undefined;\n }\n ): SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<undefined, TZodType>>>;\n computed<\n TField extends string,\n TZodType extends z.ZodTypeAny | undefined = undefined,\n TCodec extends ComputedCodec<any, any> | undefined = undefined,\n >(\n config: ComputedFieldConfig<TField, unknown, unknown, TZodType> & {\n codec?: TCodec;\n }\n ): SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<TCodec, TZodType>>> {\n const computed: ComputedField = {\n field: config.field,\n sql: config.sql,\n alias: config.alias ?? config.field,\n codec: normalizeCodec(config.codec, config.type),\n };\n this.computedFields.push(computed);\n return new SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<TCodec, TZodType>>>(\n this.ctx, this.model, this.filters, this.orderByClause,\n this.limitVal, this.offsetVal, [...this.selectedProps, config.field], this.computedFields,\n this.commentStr,\n );\n }\n\n comment(input: string | Record<string, string>): SelectQueryBuilder<S, K, C> {\n this.commentStr = formatComment(input);\n return this;\n }\n\n async first(): Promise<SelectRow<S, K, C> | null> {\n const rows = await this.limit(1).get();\n return (rows[0] ?? null) as any;\n }\n\n async exists(): Promise<boolean> {\n return await this.count() > 0;\n }\n\n private static defaultCountType = z.coerce.number();\n\n async count(): Promise<number>;\n async count<T extends z.ZodType>(parser: T): Promise<z.output<T>>;\n async count<T extends z.ZodType>(parser?: T): Promise<z.output<T>> {\n const predicate = this.buildPredicate() ?? { kind: \"leaf\" as const, column: \"1\", operator: \"=\" as const, value: \"1\" };\n const table = this.model.table;\n\n // Build query spec for read tracking (without totalTs)\n const querySpec: RangeRead = {\n kind: \"range\",\n table: table,\n tableId: this.model.tableId,\n predicate: predicate,\n columns: [\"count\"],\n orderBy: null,\n limit: null,\n offset: null,\n };\n\n // Execute query\n const params: unknown[] = [];\n const whereSql = buildPredicateSql(predicate, params, this.ctx.db.sqlBuilder);\n\n const sql = `SELECT COUNT(*) as count FROM ${table} WHERE (${whereSql})${this.commentStr ? \" \" + this.commentStr : \"\"}`;\n const result = await this.ctx.db.query(sql, params);\n const raw = result.rows[0]?.count ?? \"0\";\n\n // Record read with totalTs for OCC validation\n this.ctx.internalGetReadSet().push({\n ...querySpec,\n tableId: this.model.tableId,\n });\n\n if (parser) {\n return parser.parse(raw) as z.output<T>;\n } else {\n return SelectQueryBuilder.defaultCountType.parse(raw) as z.output<T>;\n }\n }\n\n async find(id: string): Promise<SelectRow<S, K, C> | null> {\n if (this.filters.length > 0) {\n throw new Error(`Cannot use find() after where() - find() is meant for primary key lookups without additional filters`);\n }\n\n const table = this.model.table;\n const tableId = this.model.tableId;\n\n // Check pending writes first\n const pendingWrite = this.ctx.internalGetWriteSet().find(w => w.id === id && bytesEqual(w.tableId, tableId));\n\n if (pendingWrite) {\n if (pendingWrite.op === \"delete\") {\n // Don't cache pending writes, just return\n return null;\n }\n const row = this.mapRowToSchema({ ...pendingWrite.data, id, commit_ts: this.ctx.beginTs });\n return row as SelectRow<S, K, C>;\n }\n\n const computedCols = this.computedFields.map(f => `${f.sql} as ${f.alias}`);\n const selectPropsWithComputed = this.selectedProps.slice(0, this.selectedProps.length - this.computedFields.length);\n const selectCols = selectPropsWithComputed.length > 0\n ? [\"id\", ...selectPropsWithComputed.map(p => this.getColumnName(p as string)), ...computedCols, \"commit_ts\"].join(\", \")\n : \"*\";\n let sql = `SELECT ${selectCols} FROM ${table} WHERE id = ${this.ctx.db.sqlBuilder.placeholder(1)}`;\n if (this.commentStr) sql += ` ${this.commentStr}`;\n const result = await this.ctx.db.query(sql, [id]);\n\n const row = result.rows[0] ?? null;\n\n // Capture commit_ts as the per-row OCC fingerprint. `null` means\n // \"no row at read time\" — a later concurrent insert with this id\n // becomes a conflict at commit time.\n const expectedCommitTs: bigint | null = row ? BigInt(row.commit_ts) : null;\n this.ctx.internalGetReadSet().push({\n kind: \"point\",\n table,\n tableId,\n id,\n expectedCommitTs,\n });\n\n const mappedRow = row ? this.mapRowToSchema(row) as SelectRow<S, K, C> : null;\n\n return mappedRow;\n }\n\n async get(): Promise<SelectRow<S, K, C>[]> {\n const predicate = this.buildPredicate() ?? { kind: \"leaf\" as const, column: \"1\", operator: \"=\" as const, value: \"1\" };\n const table = this.model.table;\n const tableId = this.model.tableId;\n\n // Build query spec for read tracking (without totalTs)\n const querySpec: RangeRead = {\n kind: \"range\",\n table: table,\n tableId: tableId,\n predicate: predicate,\n columns: this.selectedProps as string[],\n orderBy: this.orderByClause,\n limit: this.limitVal,\n offset: this.offsetVal,\n };\n\n // Execute query\n const params: unknown[] = [];\n const whereSql = buildPredicateSql(predicate, params, this.ctx.db.sqlBuilder);\n\n const computedCols = this.computedFields.map(f => `${f.sql} as ${f.alias}`);\n const selectPropsWithComputed = this.selectedProps.slice(0, this.selectedProps.length - this.computedFields.length);\n const selectColsNames = selectPropsWithComputed.length > 0\n ? [\"id\", ...selectPropsWithComputed.map(p => this.getColumnName(p as string)), ...computedCols, \"commit_ts\"]\n : \"*\";\n const selectCols = Array.from(new Set(selectColsNames).values()).join(\", \")\n let sql = `SELECT ${selectCols} FROM ${table} WHERE (${whereSql})`;\n\n if (this.orderByClause) {\n sql += ` ORDER BY ${this.orderByClause}`;\n }\n if (this.limitVal !== null) {\n sql += ` LIMIT ${this.limitVal}`;\n }\n if (this.offsetVal !== null) {\n sql += ` OFFSET ${this.offsetVal}`;\n }\n if (this.commentStr) sql += ` ${this.commentStr}`;\n\n const result = await this.ctx.db.query(sql, params);\n\n // Record read with totalTs for OCC validation\n this.ctx.internalGetReadSet().push({\n ...querySpec,\n tableId: tableId,\n });\n\n const rows = result.rows.map(row => this.mapRowToSchema(row)) as SelectRow<S, K, C>[];\n\n return rows;\n }\n\n private buildPredicate(): Predicate | null {\n if (this.filters.length === 0) return null;\n\n const predicates: Predicate[] = [];\n const fb = new FilterBuilder<S>(this.model.columns, this.model.codecs);\n\n for (const filterFn of this.filters) {\n filterFn(fb);\n if (fb.predicates.length > 0) {\n const hasOr = fb.predicates.some(p => p.kind === \"or\");\n if (hasOr) {\n predicates.push(...fb.predicates);\n } else {\n predicates.push({ kind: \"and\", children: fb.predicates });\n }\n fb.predicates = [];\n }\n }\n\n if (predicates.length === 0) return null;\n if (predicates.length === 1) return predicates[0] ?? null;\n return { kind: \"and\", children: predicates };\n }\n}\n\n// ─── Filter Builder ──────────────────────────────────────────────────────────────\n\nclass FilterBuilder<S extends SchemaDefinition<string, ZodRawShape>> {\n predicates: Predicate[] = [];\n\n constructor(\n private columns: Record<string, string>,\n private codecs: Record<string, ColumnCodec<unknown, unknown>>\n ) { }\n\n private add(column: string, operator: CompareOperator, value: unknown, value2?: unknown, raw?: boolean): void {\n const leaf: LeafPredicate = { kind: \"leaf\", column, operator: operator as any, value, value2 };\n if (raw) leaf.raw = true;\n this.predicates.push(leaf);\n }\n\n private addJsonContains(operator: CompareOperator, key: string, value: unknown, opts: JsonContainsOptions | undefined): void {\n const col = this.getColumnName(key);\n const leaf: LeafPredicate = {\n kind: \"leaf\",\n column: col,\n operator: operator as any,\n value: this.encodeJson(value, opts?.raw),\n };\n if (opts?.raw) leaf.raw = true;\n const path = resolveJsonPath(opts);\n if (path !== undefined) leaf.path = path;\n this.predicates.push(leaf);\n }\n\n private getColumnName(key: string): string {\n return this.columns[key] ?? key;\n }\n\n private encode(key: string, value: unknown): unknown {\n const codec = this.codecs[key];\n if (!codec?.encode || value === undefined || value === null) return value;\n return codec.encode(value);\n }\n\n private encodeJson(value: unknown, raw: boolean | undefined): unknown {\n if (value === null || value === undefined) return value;\n // raw=true: caller has already produced the dialect-native form\n // (typically a JSON-encoded string or a path expression). Pass through.\n if (raw) return value;\n // Otherwise serialize the JS value to a JSON literal so the SQL\n // emitter can hand a single text param to the driver.\n return JSON.stringify(value);\n }\n\n eq<K extends keyof InferSchema<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"=\", this.encode(key as string, value));\n return this;\n }\n\n neq<K extends keyof InferSchema<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"!=\", this.encode(key as string, value));\n return this;\n }\n\n gt<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \">\", this.encode(key as string, value));\n return this;\n }\n\n gte<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \">=\", this.encode(key as string, value));\n return this;\n }\n\n lt<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"<\", this.encode(key as string, value));\n return this;\n }\n\n lte<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"<=\", this.encode(key as string, value));\n return this;\n }\n\n like<K extends StringFieldKeys<S>>(key: K, pattern: string): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"like\", this.encode(key as string, pattern));\n return this;\n }\n\n ilike<K extends StringFieldKeys<S>>(key: K, pattern: string): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"ilike\", this.encode(key as string, pattern));\n return this;\n }\n\n contains<K extends StringFieldKeys<S>>(key: K, value: string): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"contains\", this.encode(key as string, value));\n return this;\n }\n\n icontains<K extends StringFieldKeys<S>>(key: K, value: string): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"icontains\", this.encode(key as string, value));\n return this;\n }\n\n /**\n * JSON containment. Targets a JSON/JSONB column and asserts the document\n * contains the given candidate (object-key subset for objects,\n * element-subset for arrays — see dialect-specific docs for edge cases).\n * Pass `{ raw: true }` if `value` is already a JSON-encoded string.\n * Pass `{ path: ... }` to scope the check to a sub-document of the\n * target (jsonb_path_query_first on PG, JSON_CONTAINS path arg on MySQL).\n */\n jsonContains<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S> {\n this.addJsonContains(\"jsonContains\", key as string, value, opts);\n return this;\n }\n\n /** Inverse of {@link jsonContains}: column is contained in the given value. */\n jsonContainedBy<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S> {\n this.addJsonContains(\"jsonContainedBy\", key as string, value, opts);\n return this;\n }\n\n /**\n * Key/path existence check on a JSON column.\n *\n * - String form (top-level key): `jsonHasKey(\"meta\", \"color\")`. On PG\n * also matches when the column is a string array and `value` is one of\n * its elements (PG `?` semantics); MySQL stays strict to object keys.\n * - Array form (nested path): `jsonHasKey(\"meta\", [\"a\", \"b\"])` compiles\n * to a path expression `$.\"a\".\"b\"` on both dialects.\n * - Raw form: `jsonHasKey(\"meta\", \"$.foo[*]\", { raw: true })` passes the\n * string through as a dialect path expression (PG `jsonb_path_exists`\n * jsonpath, MySQL `JSON_CONTAINS_PATH`). Caller owns the syntax.\n * - Multi-path form: `jsonHasKey(\"meta\", [[\"a\",\"b\"], \"color\"], { mode: \"all\" })`\n * compiles each entry to a jsonpath and emits PG OR/AND of\n * `jsonb_path_exists` or MySQL `JSON_CONTAINS_PATH('all', ...)`.\n */\n jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string): FilterBuilder<S>;\n jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string[]): FilterBuilder<S>;\n jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string, opts: { raw: true }): FilterBuilder<S>;\n jsonHasKey<K extends JsonFieldKeys<S>>(key: K, paths: (string | string[])[], opts: JsonHasKeyMultiOptions): FilterBuilder<S>;\n jsonHasKey<K extends JsonFieldKeys<S>>(key: K, paths: string[], opts: JsonHasKeyMultiOptions & { raw: true }): FilterBuilder<S>;\n jsonHasKey<K extends JsonFieldKeys<S>>(\n key: K,\n value: string | string[] | (string | string[])[],\n opts?: JsonOpOptions & { mode?: \"one\" | \"all\" }\n ): FilterBuilder<S> {\n const col = this.getColumnName(key as string);\n // Multi-path mode: array of (string|string[]) entries with explicit mode.\n if (opts?.mode && Array.isArray(value)) {\n const paths = (value as (string | string[])[]).map((p) =>\n opts.raw && typeof p === \"string\" ? p : jsonKeysToPath(Array.isArray(p) ? p : [p])\n );\n const leaf: LeafPredicate = {\n kind: \"leaf\",\n column: col,\n operator: \"jsonHasKey\",\n value: paths,\n mode: opts.mode,\n };\n this.predicates.push(leaf);\n return this;\n }\n // Single-key/path mode.\n if (Array.isArray(value)) {\n this.add(col, \"jsonHasKey\", jsonKeysToPath(value as string[]), undefined, true);\n } else if (opts?.raw) {\n this.add(col, \"jsonHasKey\", value, undefined, true);\n } else {\n this.add(col, \"jsonHasKey\", value, undefined, false);\n }\n return this;\n }\n\n /**\n * Array element containment: target column is a JSON array; the given\n * `value` (any JSON-encodable type) must appear as one of its elements.\n * Pass `{ raw: true }` if `value` is already a JSON-encoded string.\n * Pass `{ path: ... }` to scope the check to a sub-array of the column.\n */\n jsonArrayContains<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S> {\n this.addJsonContains(\"jsonArrayContains\", key as string, value, opts);\n return this;\n }\n\n between<K extends OrderableFieldKeys<S>>(key: K, lo: FieldValue<S, K>, hi: FieldValue<S, K>): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"between\", this.encode(key as string, lo), this.encode(key as string, hi));\n return this;\n }\n\n isNull<K extends keyof InferSchema<S>>(key: K): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"isNull\", null);\n return this;\n }\n\n notNull<K extends keyof InferSchema<S>>(key: K): FilterBuilder<S> {\n this.add(this.getColumnName(key as string), \"isNotNull\", null);\n return this;\n }\n\n /**\n * Compose an OR clause. Each callback fills a fresh sub-FilterBuilder\n * with predicates that are AND-ed together within that branch; the\n * branches themselves are OR-ed. Example:\n * f.or([\n * b => b.eq(\"tag\", \"a\"),\n * b => b.eq(\"tag\", \"b\").gt(\"qty\", 3), // (tag=b AND qty>3)\n * ])\n * produces (tag=a) OR (tag=b AND qty>3).\n */\n or(branches: ((fb: FilterBuilder<S>) => void)[]): FilterBuilder<S> {\n const children: Predicate[] = [];\n for (const fn of branches) {\n const sub = new FilterBuilder<S>(this.columns, this.codecs);\n fn(sub);\n if (sub.predicates.length === 1) {\n children.push(sub.predicates[0]);\n } else if (sub.predicates.length > 1) {\n children.push({ kind: \"and\", children: sub.predicates });\n }\n }\n if (children.length > 0) {\n this.predicates.push({ kind: \"or\", children });\n }\n return this;\n }\n}\n\n\nexport function buildPredicateSql(predicate: Predicate, params: unknown[], sql: SqlBuilder): string {\n switch (predicate.kind) {\n case \"and\": {\n const parts = predicate.children.map((c) => buildPredicateSql(c, params, sql));\n return `(${parts.join(\" AND \")})`;\n }\n case \"or\": {\n const parts = predicate.children.map((c) => buildPredicateSql(c, params, sql));\n return `(${parts.join(\" OR \")})`;\n }\n case \"leaf\": {\n return buildLeafSql(predicate, params, sql);\n }\n }\n}\n\nfunction buildLeafSql(leaf: LeafPredicate, params: unknown[], sql: SqlBuilder): string {\n const col = leaf.column;\n switch (leaf.operator) {\n case \"=\": case \"!=\": case \">\": case \">=\": case \"<\": case \"<=\": {\n params.push(leaf.value);\n return `${col} ${leaf.operator} ${sql.placeholder(params.length)}`;\n }\n case \"between\": {\n params.push(leaf.value);\n const p1 = sql.placeholder(params.length);\n params.push(leaf.value2);\n const p2 = sql.placeholder(params.length);\n return `${col} BETWEEN ${p1} AND ${p2}`;\n }\n case \"like\": {\n params.push(leaf.value);\n return `${col} LIKE ${sql.placeholder(params.length)}`;\n }\n case \"ilike\": {\n params.push(leaf.value);\n return sql.ilike(col, params.length);\n }\n case \"contains\": {\n params.push(`%${leaf.value}%`);\n return `${col} LIKE ${sql.placeholder(params.length)}`;\n }\n case \"icontains\": {\n params.push(`%${leaf.value}%`);\n return sql.icontains(col, params.length);\n }\n case \"jsonContains\": {\n params.push(leaf.value);\n const valIdx = params.length;\n let pathIndex: number | undefined;\n if (leaf.path !== undefined) {\n params.push(leaf.path);\n pathIndex = params.length;\n }\n return sql.jsonContains(col, valIdx, { raw: leaf.raw, pathIndex });\n }\n case \"jsonContainedBy\": {\n params.push(leaf.value);\n const valIdx = params.length;\n let pathIndex: number | undefined;\n if (leaf.path !== undefined) {\n params.push(leaf.path);\n pathIndex = params.length;\n }\n return sql.jsonContainedBy(col, valIdx, { raw: leaf.raw, pathIndex });\n }\n case \"jsonHasKey\": {\n if (leaf.mode && Array.isArray(leaf.value)) {\n const paths = leaf.value as string[];\n const startIdx = params.length + 1;\n for (const p of paths) params.push(p);\n return sql.jsonHasKey(col, startIdx, {\n raw: true,\n mode: leaf.mode,\n pathCount: paths.length,\n });\n }\n params.push(leaf.value);\n return sql.jsonHasKey(col, params.length, { raw: leaf.raw });\n }\n case \"jsonArrayContains\": {\n params.push(leaf.value);\n const valIdx = params.length;\n let pathIndex: number | undefined;\n if (leaf.path !== undefined) {\n params.push(leaf.path);\n pathIndex = params.length;\n }\n return sql.jsonArrayContains(col, valIdx, { raw: leaf.raw, pathIndex });\n }\n case \"isNull\": return `${col} IS NULL`;\n case \"isNotNull\": return `${col} IS NOT NULL`;\n }\n}\n\nexport function matchesPredicate(row: Record<string, unknown>, predicate: Predicate): boolean {\n switch (predicate.kind) {\n case \"and\": return predicate.children.every((c) => matchesPredicate(row, c));\n case \"or\": return predicate.children.some((c) => matchesPredicate(row, c));\n case \"leaf\": return matchesLeaf(row, predicate);\n }\n}\n\nfunction matchesLeaf(row: Record<string, unknown>, leaf: LeafPredicate): boolean {\n const val = row[leaf.column];\n\n switch (leaf.operator) {\n case \"=\": return val === leaf.value;\n case \"!=\": return val !== leaf.value;\n case \">\": return (val as number) > (leaf.value as number);\n case \">=\": return (val as number) >= (leaf.value as number);\n case \"<\": return (val as number) < (leaf.value as number);\n case \"<=\": return (val as number) <= (leaf.value as number);\n\n case \"between\":\n return (val as number) >= (leaf.value as number) &&\n (val as number) <= (leaf.value2 as number);\n\n case \"like\":\n case \"contains\":\n case \"ilike\":\n case \"icontains\": {\n if (typeof val !== \"string\" || typeof leaf.value !== \"string\") return false;\n const haystack = (leaf.operator === \"ilike\" || leaf.operator === \"icontains\")\n ? (val as string).toLowerCase()\n : val as string;\n const raw = leaf.value as string;\n const needle = (leaf.operator === \"ilike\" || leaf.operator === \"icontains\")\n ? raw.toLowerCase()\n : raw;\n const pattern = (leaf.operator === \"contains\" || leaf.operator === \"icontains\")\n ? `%${needle}%`\n : needle;\n const regex = new RegExp(\n \"^\" + pattern.replace(/%/g, \".*\").replace(/_/g, \".\") + \"$\"\n );\n return regex.test(haystack);\n }\n\n case \"jsonContains\": {\n const candidate = decodeJsonLeafValue(leaf);\n const target = leaf.path !== undefined ? jsonPathExtract(val, leaf.path) : val;\n if (target === undefined) return false;\n return jsonContains(target, candidate);\n }\n\n case \"jsonContainedBy\": {\n const candidate = decodeJsonLeafValue(leaf);\n const target = leaf.path !== undefined ? jsonPathExtract(val, leaf.path) : val;\n if (target === undefined) return false;\n return jsonContains(candidate, target);\n }\n\n case \"jsonHasKey\": {\n if (leaf.mode && Array.isArray(leaf.value)) {\n const paths = leaf.value as string[];\n if (paths.length === 0) return false;\n return leaf.mode === \"all\"\n ? paths.every((p) => jsonPathExists(val, p))\n : paths.some((p) => jsonPathExists(val, p));\n }\n if (leaf.raw) {\n return jsonPathExists(val, leaf.value as string);\n }\n const key = leaf.value as string;\n if (val === null || typeof val !== \"object\") return false;\n if (Array.isArray(val)) return (val as unknown[]).includes(key);\n return key in (val as object);\n }\n\n case \"jsonArrayContains\": {\n const candidate = decodeJsonLeafValue(leaf);\n const target = leaf.path !== undefined ? jsonPathExtract(val, leaf.path) : val;\n if (!Array.isArray(target)) return false;\n return (target as unknown[]).some((el) => jsonContains(el, candidate));\n }\n\n case \"isNull\":\n return val === null;\n\n case \"isNotNull\":\n return val !== null;\n\n default:\n return false;\n }\n}\n\n// When raw=true the leaf.value is a JSON-encoded string; decode for in-memory\n// comparison. Otherwise the value is the original JS value as passed.\nfunction decodeJsonLeafValue(leaf: LeafPredicate): unknown {\n if (!leaf.raw) return leaf.value;\n if (typeof leaf.value !== \"string\") return leaf.value;\n try { return JSON.parse(leaf.value); } catch { return leaf.value; }\n}\n\n// PG `@>` / MySQL `JSON_CONTAINS` semantics. Recursive containment:\n// - scalars: strict equality\n// - object: every candidate key matches target's value recursively\n// - array: every candidate element is contained in some target element\n// - scalar candidate vs array target: candidate equals some element\nexport function jsonContains(target: unknown, candidate: unknown): boolean {\n if (candidate === target) return true;\n if (target === null || candidate === null) return target === candidate;\n if (target === undefined || candidate === undefined) return false;\n\n const tArr = Array.isArray(target);\n const cArr = Array.isArray(candidate);\n const tObj = !tArr && typeof target === \"object\";\n const cObj = !cArr && typeof candidate === \"object\";\n\n // Scalar candidate in array target.\n if (!cArr && !cObj && tArr) {\n return (target as unknown[]).some((el) => jsonContains(el, candidate));\n }\n // Both arrays: every candidate element matches some target element.\n if (cArr && tArr) {\n const t = target as unknown[];\n return (candidate as unknown[]).every((c) => t.some((el) => jsonContains(el, c)));\n }\n // Both objects.\n if (cObj && tObj) {\n const t = target as Record<string, unknown>;\n const c = candidate as Record<string, unknown>;\n for (const k of Object.keys(c)) {\n if (!(k in t)) return false;\n if (!jsonContains(t[k], c[k])) return false;\n }\n return true;\n }\n return false;\n}\n\n// Walk the JSON path and return the value at it, or `undefined` if any\n// segment is missing or unresolvable. Same syntax subset as\n// {@link jsonPathExists}.\nexport function jsonPathExtract(val: unknown, path: string): unknown {\n let p = path;\n if (p.startsWith(\"$\")) p = p.slice(1);\n let cur: unknown = val;\n while (p.length > 0) {\n if (p.startsWith('.\"')) {\n let end = 2;\n while (end < p.length) {\n if (p[end] === \"\\\\\" && end + 1 < p.length) { end += 2; continue; }\n if (p[end] === '\"') break;\n end++;\n }\n if (end >= p.length) return undefined;\n const key = p.slice(2, end).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n if (cur === null || typeof cur !== \"object\" || Array.isArray(cur)) return undefined;\n if (!(key in (cur as object))) return undefined;\n cur = (cur as Record<string, unknown>)[key];\n p = p.slice(end + 1);\n } else if (p.startsWith(\".\")) {\n const m = p.slice(1).match(/^([^.[]+)/);\n if (!m) return undefined;\n const key = m[1];\n if (cur === null || typeof cur !== \"object\" || Array.isArray(cur)) return undefined;\n if (!(key in (cur as object))) return undefined;\n cur = (cur as Record<string, unknown>)[key];\n p = p.slice(1 + key.length);\n } else if (p.startsWith(\"[\")) {\n const end = p.indexOf(\"]\");\n if (end === -1) return undefined;\n const idx = parseInt(p.slice(1, end), 10);\n if (!Array.isArray(cur) || idx < 0 || idx >= (cur as unknown[]).length) return undefined;\n cur = (cur as unknown[])[idx];\n p = p.slice(end + 1);\n } else {\n return undefined;\n }\n }\n return cur;\n}\n\n// Best-effort JSON path evaluator for the in-memory predicate match.\n// Supports the path syntax this module emits (`$.\"key\".\"nested\"`) plus the\n// common shorthands `$.key` and `$.key[0]`. Anything more exotic (filters,\n// wildcards) returns false — DB will still evaluate it correctly server-side.\nexport function jsonPathExists(val: unknown, path: string): boolean {\n let p = path;\n if (p.startsWith(\"$\")) p = p.slice(1);\n let cur: unknown = val;\n while (p.length > 0) {\n if (p.startsWith('.\"')) {\n let end = 2;\n while (end < p.length) {\n if (p[end] === \"\\\\\" && end + 1 < p.length) { end += 2; continue; }\n if (p[end] === '\"') break;\n end++;\n }\n if (end >= p.length) return false;\n const key = p.slice(2, end).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n if (cur === null || typeof cur !== \"object\" || Array.isArray(cur)) return false;\n if (!(key in (cur as object))) return false;\n cur = (cur as Record<string, unknown>)[key];\n p = p.slice(end + 1);\n } else if (p.startsWith(\".\")) {\n const m = p.slice(1).match(/^([^.[]+)/);\n if (!m) return false;\n const key = m[1];\n if (cur === null || typeof cur !== \"object\" || Array.isArray(cur)) return false;\n if (!(key in (cur as object))) return false;\n cur = (cur as Record<string, unknown>)[key];\n p = p.slice(1 + key.length);\n } else if (p.startsWith(\"[\")) {\n const end = p.indexOf(\"]\");\n if (end === -1) return false;\n const idx = parseInt(p.slice(1, end), 10);\n if (!Array.isArray(cur) || idx < 0 || idx >= (cur as unknown[]).length) return false;\n cur = (cur as unknown[])[idx];\n p = p.slice(end + 1);\n } else {\n return false;\n }\n }\n return cur !== undefined;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime_db-DOCgqbwi.js","names":["z"],"sources":["../src/db/db.ts","../src/db/context.ts","../src/db/realtime_db.ts"],"sourcesContent":["import { CacheLayer } from \"./cache\";\nimport type { CommitLogEntry, PointRead, RawPointRead, RawReadEntry } from \"./types_db\";\nimport { ReadEntry, WriteEntry } from \"./types_db\";\n\nexport interface DbQueryResult<T = any> {\n rows: T[];\n rowCount?: number | null;\n}\n\nexport interface RawClient {\n query<T = any>(sql: string, params?: unknown[]): Promise<DbQueryResult<T>>;\n}\n\nexport interface PooledClient extends RawClient {\n release(): void;\n}\n\nexport type DbType = \"postgres\" | \"mysql\";\n\nexport interface PendingPointEntry {\n entry: PointRead;\n /* Table name and point read id = key = `${tableName} ${entry.id}` */\n key: string;\n}\n\nexport interface PreparedQuery {\n sql: string;\n params: unknown[] | unknown[][];\n operation: \"insertSingle\" | \"insertBatch\" | \"updateSingle\" | \"updateBatch\" | \"deleteSingle\" | \"deleteBatch\" | \"pointReadValidation\" | \"commit_logs\";\n table: string;\n entryId?: unknown;\n expectedTs?: bigint,\n entries?: WriteEntry[],\n pendingsEntry?: PendingPointEntry[];\n};\n\nexport interface PreparedQueries {\n commits: PreparedQuery[];\n validateReadPoints?: PreparedQuery[];\n hasRangeRead: boolean;\n tableIds?: Uint8Array[];\n rawReadSet?: RawReadEntry[],\n}\n\nexport interface Database {\n readonly dbType: DbType;\n readonly sqlBuilder: SqlBuilder;\n columnTypes: Map<string, Map<string, string>>;\n migrationSql: string[];\n bootstrapColumnTypes(opts: { redis?: CacheLayer; cacheKey: string; tables?: string[]; }): Promise<void>;\n query<T = any>(sql: string, params?: unknown[]): Promise<DbQueryResult<T>>;\n getClient(): Promise<PooledClient>;\n getTransactionClient(): Promise<TxDatabase>;\n getLatestSnapshotTimestamp(): Promise<bigint>;\n updateLatestSnapshotTimestamp(commitTs: bigint): Promise<void>;\n getNextTimestamp(): Promise<bigint>;\n prepareCommitWrites(readSet: ReadEntry[], writeSet: WriteEntry[], commitTs: LazyCommitTsParam): Promise<PreparedQueries>;\n commitWrites(beginTs: bigint, queries: PreparedQueries, commitTs: bigint): Promise<{ success: boolean }>;\n close(): Promise<void>;\n /**\n * Delete commit_logs older than `ts` (exclusive). Used by the periodic\n * retention sweep in SubscriptionManager so the table doesn't grow\n * unbounded.\n */\n pruneCommitLogsBefore(ts: bigint): Promise<bigint>;\n /**\n * Half-open range scan: ts >= beginTs AND ts < endTs. Used by the\n * subscription-recovery path to replay logs in a specific time window.\n */\n getCommitLogsBetweenTs(beginTs: bigint, endTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;\n /**\n * Conflict-check scan for OCC: ts >= sinceTs AND ts <> excludeTs. The\n * exclude is our own commitTs so we don't conflict with ourselves; the\n * lack of an upper bound is intentional, so a concurrent peer that\n * happens to have a higher commitTs but committed before us is still\n * visible. (MVCC keeps in-flight peers invisible until they commit.)\n */\n getCommitLogsSinceTs(sinceTs: bigint, excludeTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;\n /**\n * For each `update`/`delete` entry, attach `prevData` (consumed by the\n * invalidator) and `expectedCommitTs` (the CAS fence).\n *\n * `expectedCommitTs` is preferentially copied from a prior point-read of\n * the same row in `readSet` — that's the value the handler's logic\n * actually depended on, so the CAS check enforces beginTs-level isolation\n * for read-then-update patterns. If no prior read exists (\"blind\"\n * write), we fall back to the value observed in this batch fetch (weak\n * OCC, sufficient for writes that don't depend on prior state).\n *\n * `prevData` always comes from this batch fetch (SELECT * per table) so\n * the invalidator has the full row regardless of which columns the\n * handler's read selected.\n *\n * If the target row no longer exists at fetch time, `expectedCommitTs`\n * is left undefined and the per-row CAS will match nothing — surfaced\n * as OccConflictError.\n */\n attachPrevDataToWriteSet(writeSet: WriteEntry[], readSet: ReadEntry[]): Promise<void>;\n}\n\nexport interface TxDatabase extends Database {\n begin(): Promise<void>;\n commit(): Promise<void>;\n rollback(): Promise<void>;\n release(): void;\n}\n\nexport interface JsonOpOptions {\n /**\n * When true, the bound `value` parameter is treated as already prepared\n * for the underlying SQL (e.g. a literal JSON path string for\n * jsonHasKey, a JSON-encoded literal for the contains family). When\n * false/omitted, the value was prepared client-side from a JS value.\n */\n raw?: boolean;\n /**\n * 1-based positional index of an extra bound parameter holding a\n * jsonpath that scopes the contains-family check to a sub-document of\n * the target column. When omitted, the check runs against the whole\n * column value.\n */\n pathIndex?: number;\n /**\n * jsonHasKey only: when set, multiple path parameters are bound starting\n * at `paramIndex`, and the predicate evaluates whether any (`one`) or\n * every (`all`) path exists in the column.\n */\n mode?: \"one\" | \"all\";\n /** Number of bound path parameters in multi-path mode. */\n pathCount?: number;\n}\n\nexport interface SqlBuilder {\n placeholder(index: number): string;\n like(col: string, paramIndex: number): string;\n ilike(col: string, paramIndex: number): string;\n icontains(col: string, paramIndex: number): string;\n /** PG @> ; MySQL JSON_CONTAINS */\n jsonContains(col: string, paramIndex: number, opts?: JsonOpOptions): string;\n /** PG <@ ; MySQL JSON_CONTAINS(candidate, target) */\n jsonContainedBy(col: string, paramIndex: number, opts?: JsonOpOptions): string;\n /**\n * Key/path existence. With `opts.raw === true`, the bound param is a JSON\n * path expression (PG `jsonb_path_exists`, MySQL `JSON_CONTAINS_PATH`).\n * Otherwise the bound param is a literal top-level key (PG `?`, MySQL\n * `JSON_CONTAINS_PATH($.\"<key>\")` with server-side quoting).\n * With `opts.pathCount` set, emits the multi-path form keyed by `mode`.\n */\n jsonHasKey(col: string, paramIndex: number, opts?: JsonOpOptions): string;\n /** Array membership: target array contains the given element. */\n jsonArrayContains(col: string, paramIndex: number, opts?: JsonOpOptions): string;\n}\n\nexport class LazyCommitTsParam {\n constructor(public value: unknown) { }\n\n // used by postgres\n toPostgres(prepareValue: (value: any) => any): any {\n return prepareValue(this.value);\n }\n\n // used by mysql\n toString() {\n return (this.value as any).toString();\n }\n\n validate() {\n const p = new LazyCommitTsParam(undefined);\n const hasNotObjConstructor = p.constructor !== Object;\n const hasNotToJSON = typeof (p as any).toJSON !== 'function';\n console.log('constructor must not object', hasNotObjConstructor);\n console.log('should not have toJSON', hasNotToJSON);\n }\n}","import { z, ZodRawShape } from \"zod\";\nimport { Database } from \"./db\";\nimport { ReadEntry, WriteEntry, } from \"./types_db\";\n\nimport { ColumnCodec, InferSchema, InsertData, Model, SchemaDefinition } from \"./schema\";\nimport { normalizeCodec, unwrapZodType } from \"./codec\";\nimport { QueryBuilder } from \"./query\";\n\nexport class TxContext {\n readonly beginTs: bigint;\n readonly db: Database;\n protected readSet: ReadEntry[] = [];\n protected writeSet: WriteEntry[] = [];\n private models: Map<string, Model> = new Map();\n\n protected getOrCreateModel(schema: SchemaDefinition<string, ZodRawShape>): Model {\n const existing = this.models.get(schema.table);\n if (existing) return existing;\n\n const shape = schema.schema.shape;\n const customColumns = (schema as any).columns;\n const columns: Record<string, string> = {};\n const types: Record<string, string> = {};\n const codecs: Record<string, ColumnCodec<any, any>> = {};\n const schemaCodecs = schema.columnsOptions.codecs ?? {};\n\n for (const key of Object.keys(shape)) {\n columns[key] = customColumns?.[key] ?? key;\n const field = shape[key];\n const baseField = unwrapZodType(field);\n if (baseField instanceof z.ZodNumber) {\n types[key] = \"integer\";\n } else if (baseField instanceof z.ZodString) {\n types[key] = \"string\";\n } else if (baseField instanceof z.ZodBoolean) {\n types[key] = \"boolean\";\n } else if (baseField instanceof z.ZodArray) {\n types[key] = \"array\";\n } else {\n types[key] = \"json\";\n }\n codecs[key] = normalizeCodec(schemaCodecs[key], baseField);\n }\n\n const model: Model = {\n table: schema.table,\n tableId: schema.tableId,\n columns,\n reverseColumns: Object.fromEntries(Object.entries(columns).map(([k, v]) => [v, k])),\n types,\n codecs,\n };\n\n this.models.set(schema.table, model);\n return model;\n }\n\n constructor(db: Database, beginTs: bigint) {\n this.db = db;\n this.beginTs = beginTs;\n }\n\n internalGetReadSet(): ReadEntry[] { return this.readSet; }\n internalGetWriteSet(): WriteEntry[] { return this.writeSet; }\n\n protected findPendingWrite(table: string, id: string): WriteEntry | undefined {\n return this.writeSet.find(w => w.table === table && w.id === id);\n }\n\n protected findPendingInsert(table: string, id: string): WriteEntry | undefined {\n return this.writeSet.find(w => w.table === table && w.id === id && w.op === \"insert\");\n }\n\n protected encodeWithCodec(model: Model, property: string, value: unknown): unknown {\n const codec = model.codecs[property];\n if (!codec?.encode || value === undefined || value === null) return value;\n return codec.encode(value);\n }\n}\n\nexport class DbReader extends TxContext {\n query<S extends SchemaDefinition<string, ZodRawShape>>(schema: S): QueryBuilder<S> {\n const model = this.getOrCreateModel(schema);\n return new QueryBuilder<S>(this, model);\n }\n}\n\nexport class DbWriter extends DbReader {\n async insert<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(\n schema: S,\n id: ID,\n data: InsertData<S>\n ): Promise<void> {\n const model = this.getOrCreateModel(schema);\n const mappedData: Record<string, unknown> = { id };\n const shape = schema.schema.shape;\n\n for (const key of Object.keys(shape)) {\n let value = data[key];\n\n if (value === undefined) {\n const field = shape[key];\n if (field instanceof z.ZodDefault) {\n const defaultVal = field.def.defaultValue;\n value = (typeof defaultVal === \"function\" ? defaultVal() : defaultVal)\n\n if (value !== undefined) {\n const columnName = model.columns[key] ?? key;\n mappedData[columnName] = this.encodeWithCodec(model, key, value);\n }\n }\n } else {\n const columnName = model.columns[key] ?? key;\n mappedData[columnName] = this.encodeWithCodec(model, key, value);\n }\n }\n // ensure id same\n mappedData[\"id\"] = id;\n\n // Check for existing pending write for the same ID\n const existing = this.findPendingWrite(schema.table, id);\n if (existing) {\n if (existing.op === \"delete\") {\n // If there's a pending delete, change it to an update with the new data\n existing.op = \"update\";\n existing.data = mappedData;\n } else {\n // If there's a pending update or same insert with the same ID , merge the new data\n existing.data = { ...existing.data, ...mappedData };\n }\n } else {\n this.writeSet.push({ table: schema.table, tableId: schema.tableId, id: id, op: \"insert\", data: mappedData });\n }\n }\n\n async update<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(\n schema: S,\n id: ID,\n data: Partial<Omit<InferSchema<S>, \"id\" | \"commitTs\">>,\n ): Promise<void> {\n const model = this.getOrCreateModel(schema);\n const mappedData: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n const columnName = model.columns[key] ?? key;\n mappedData[columnName] = this.encodeWithCodec(model, key, value);\n }\n\n const existing = this.findPendingWrite(schema.table, id);\n if (existing) {\n existing.op = existing.op === \"insert\" ? \"insert\" : \"update\";\n existing.data = { ...existing.data, ...mappedData };\n } else {\n // expectedTs will be filled by the committer via batch fetch if not known yet\n this.writeSet.push({ table: schema.table, tableId: schema.tableId, id, op: \"update\", data: mappedData });\n }\n }\n\n async delete<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(\n schema: S,\n id: ID,\n ): Promise<void> {\n // If there's a pending insert for the same ID, remove it instead of adding a delete\n const existingInsert = this.findPendingInsert(schema.table, id);\n if (existingInsert) {\n this.writeSet = this.writeSet.filter(w => w !== existingInsert);\n return;\n }\n\n // expectedTs will be filled by the committer via batch fetch if not known yet\n this.writeSet.push({ table: schema.table, tableId: schema.tableId, id, op: \"delete\" });\n }\n}\n","import { Database, LazyCommitTsParam, TxDatabase } from \"./db\";\nimport {\n OccConflictError, WriteEntry, CommitTs, LiveResult, MutationResult\n} from \"./types_db\";\nimport { DbReader, DbWriter } from \"./context\";\nimport { ExponentialBackoff, handleWhen, retry, RetryPolicy } from \"cockatiel\";\n\nexport const occRetryPolicy = retry(\n handleWhen((err) => OccConflictError.isOccConflictError(err)),\n {\n maxAttempts: 15,\n backoff: new ExponentialBackoff({\n initialDelay: 10,\n maxDelay: 7000,\n exponent: 2,\n }),\n },\n);\n\nexport const getDbclientRetryPolicy = retry(\n handleWhen((err) => err.message.includes('timeout exceeded')),\n {\n maxAttempts: 3,\n backoff: new ExponentialBackoff({\n initialDelay: 500,\n maxDelay: 2000,\n exponent: 2,\n }),\n },\n);\n\nexport class SupaliveDb {\n constructor(readonly impl: Database) { }\n\n static create(config: { db: Database }): SupaliveDb {\n return new SupaliveDb(config.db);\n }\n\n protected onAfterCommit?: (writeSet: WriteEntry[], commitTs: CommitTs) => void;\n\n // ── Read-only query ──────────────────────────────────────────────\n\n async query<T>(fn: (ctx: DbReader) => Promise<T>): Promise<T> {\n const beginTs = await this.impl.getLatestSnapshotTimestamp();\n const ctx = new DbReader(this.impl, beginTs);\n return await fn(ctx);\n }\n\n async liveQuery<T>(fn: (ctx: DbReader) => Promise<T>): Promise<LiveResult<T>> {\n const beginTs = await this.impl.getLatestSnapshotTimestamp();\n const ctx = new DbReader(this.impl, beginTs);\n const data = await fn(ctx);\n\n return {\n ts: beginTs,\n data,\n readSet: ctx.internalGetReadSet(),\n };\n }\n\n // ── Mutation ───────────────────────────────────────────────────────\n\n async mutation<T>(\n fn: (ctx: DbWriter) => Promise<T>,\n retryPolicy: RetryPolicy = occRetryPolicy,\n ): Promise<MutationResult<T>> {\n return await retryPolicy.execute(async () => {\n let db: TxDatabase | undefined;\n try {\n // Step1: Get latest snapshot timestamp as beginTs\n const beginTs = await this.impl.getLatestSnapshotTimestamp() + 1n;\n\n const ctx = new DbWriter(this.impl, beginTs);\n const result = await fn(ctx);\n\n const readSet = ctx.internalGetReadSet();\n const writeSet = ctx.internalGetWriteSet();\n const commitTsLazy = new LazyCommitTsParam(undefined);\n\n // Step2: Capture prevData + expectedCommitTs per write. prevData\n // is consumed by the invalidator (range subs need it to detect\n // result-set transitions). expectedCommitTs becomes the CAS fence\n // for the apply step — preferring prior find()-captured ts so\n // read-then-update patterns get beginTs-level isolation.\n await this.impl.attachPrevDataToWriteSet(writeSet, readSet);\n\n // Step3: Prepare quieries before transaction\n const queries = await this.impl.prepareCommitWrites(\n readSet,\n writeSet,\n commitTsLazy,\n );\n\n // Step4: Starts new transaction\n db = await getDbclientRetryPolicy.execute(() => this.impl.getTransactionClient());\n await db.begin();\n\n // Step5: Get commitTs from DB sequence (bigger than all previous)\n const commitTs = await db.getNextTimestamp();\n commitTsLazy.value = commitTs;\n\n // Step6: Apply + validate. CAS UPDATE/DELETE catches concurrent\n // peer touches on the write set; the readSet is validated either\n // per-row (fast path, no range reads) or via commit-log scan\n // (slow path, when range reads are present so phantoms still\n // need detection).\n const commitResult = await db.commitWrites(\n beginTs,\n queries,\n commitTs,\n );\n\n if (!commitResult.success) {\n throw new OccConflictError(\"Commit failed\", { commitResult });\n }\n\n await db.updateLatestSnapshotTimestamp(commitTs);\n await db.commit();\n\n // Notify after successful commit\n this.onAfterCommit?.(writeSet, commitTs);\n\n return { result, writeSet, commitTs };\n } catch (err) {\n await db?.rollback();\n throw err;\n } finally {\n db?.release();\n }\n });\n }\n}\n\nexport const sleep = (ms: number) => new Promise<void>((res) => setTimeout(res, ms));\n"],"mappings":";;;;;;AAyJA,IAAa,oBAAb,MAAa,kBAAkB;CACV;CAAnB,YAAY,OAAuB;EAAhB,KAAA,QAAA;CAAkB;CAGrC,WAAW,cAAwC;EACjD,OAAO,aAAa,KAAK,KAAK;CAChC;CAGA,WAAW;EACT,OAAQ,KAAK,MAAc,SAAS;CACtC;CAEA,WAAW;EACT,MAAM,IAAI,IAAI,kBAAkB,KAAA,CAAS;EACzC,MAAM,uBAAuB,EAAE,gBAAgB;EAC/C,MAAM,eAAe,OAAQ,EAAU,WAAW;EAClD,QAAQ,IAAI,+BAA+B,oBAAoB;EAC/D,QAAQ,IAAI,0BAA0B,YAAY;CACpD;AACF;;;ACrKA,IAAa,YAAb,MAAuB;CACrB;CACA;CACA,UAAiC,CAAC;CAClC,WAAmC,CAAC;CACpC,yBAAqC,IAAI,IAAI;CAE7C,iBAA2B,QAAsD;EAC/E,MAAM,WAAW,KAAK,OAAO,IAAI,OAAO,KAAK;EAC7C,IAAI,UAAU,OAAO;EAErB,MAAM,QAAQ,OAAO,OAAO;EAC5B,MAAM,gBAAiB,OAAe;EACtC,MAAM,UAAkC,CAAC;EACzC,MAAM,QAAgC,CAAC;EACvC,MAAM,SAAgD,CAAC;EACvD,MAAM,eAAe,OAAO,eAAe,UAAU,CAAC;EAEtD,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAG;GACpC,QAAQ,OAAO,gBAAgB,QAAQ;GACvC,MAAM,QAAQ,MAAM;GACpB,MAAM,YAAY,cAAc,KAAK;GACrC,IAAI,qBAAqBA,IAAE,WACzB,MAAM,OAAO;QACR,IAAI,qBAAqBA,IAAE,WAChC,MAAM,OAAO;QACR,IAAI,qBAAqBA,IAAE,YAChC,MAAM,OAAO;QACR,IAAI,qBAAqBA,IAAE,UAChC,MAAM,OAAO;QAEb,MAAM,OAAO;GAEf,OAAO,OAAO,eAAe,aAAa,MAAM,SAAS;EAC3D;EAEA,MAAM,QAAe;GACnB,OAAO,OAAO;GACd,SAAS,OAAO;GAChB;GACA,gBAAgB,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;GAClF;GACA;EACF;EAEA,KAAK,OAAO,IAAI,OAAO,OAAO,KAAK;EACnC,OAAO;CACT;CAEA,YAAY,IAAc,SAAiB;EACzC,KAAK,KAAK;EACV,KAAK,UAAU;CACjB;CAEA,qBAAkC;EAAE,OAAO,KAAK;CAAS;CACzD,sBAAoC;EAAE,OAAO,KAAK;CAAU;CAE5D,iBAA2B,OAAe,IAAoC;EAC5E,OAAO,KAAK,SAAS,MAAK,MAAK,EAAE,UAAU,SAAS,EAAE,OAAO,EAAE;CACjE;CAEA,kBAA4B,OAAe,IAAoC;EAC7E,OAAO,KAAK,SAAS,MAAK,MAAK,EAAE,UAAU,SAAS,EAAE,OAAO,MAAM,EAAE,OAAO,QAAQ;CACtF;CAEA,gBAA0B,OAAc,UAAkB,OAAyB;EACjF,MAAM,QAAQ,MAAM,OAAO;EAC3B,IAAI,CAAC,OAAO,UAAU,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO;EACpE,OAAO,MAAM,OAAO,KAAK;CAC3B;AACF;AAEA,IAAa,WAAb,cAA8B,UAAU;CACtC,MAAuD,QAA4B;EACjF,MAAM,QAAQ,KAAK,iBAAiB,MAAM;EAC1C,OAAO,IAAI,aAAgB,MAAM,KAAK;CACxC;AACF;AAEA,IAAa,WAAb,cAA8B,SAAS;CACrC,MAAM,OACJ,QACA,IACA,MACe;EACf,MAAM,QAAQ,KAAK,iBAAiB,MAAM;EAC1C,MAAM,aAAsC,EAAE,GAAG;EACjD,MAAM,QAAQ,OAAO,OAAO;EAE5B,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAG;GACpC,IAAI,QAAQ,KAAK;GAEjB,IAAI,UAAU,KAAA,GAAW;IACvB,MAAM,QAAQ,MAAM;IACpB,IAAI,iBAAiBA,IAAE,YAAY;KACjC,MAAM,aAAa,MAAM,IAAI;KAC7B,QAAS,OAAO,eAAe,aAAa,WAAW,IAAI;KAE3D,IAAI,UAAU,KAAA,GAAW;MACvB,MAAM,aAAa,MAAM,QAAQ,QAAQ;MACzC,WAAW,cAAc,KAAK,gBAAgB,OAAO,KAAK,KAAK;KACjE;IACF;GACF,OAAO;IACL,MAAM,aAAa,MAAM,QAAQ,QAAQ;IACzC,WAAW,cAAc,KAAK,gBAAgB,OAAO,KAAK,KAAK;GACjE;EACF;EAEA,WAAW,QAAQ;EAGnB,MAAM,WAAW,KAAK,iBAAiB,OAAO,OAAO,EAAE;EACvD,IAAI,UACF,IAAI,SAAS,OAAO,UAAU;GAE5B,SAAS,KAAK;GACd,SAAS,OAAO;EAClB,OAEE,SAAS,OAAO;GAAE,GAAG,SAAS;GAAM,GAAG;EAAW;OAGpD,KAAK,SAAS,KAAK;GAAE,OAAO,OAAO;GAAO,SAAS,OAAO;GAAa;GAAI,IAAI;GAAU,MAAM;EAAW,CAAC;CAE/G;CAEA,MAAM,OACJ,QACA,IACA,MACe;EACf,MAAM,QAAQ,KAAK,iBAAiB,MAAM;EAC1C,MAAM,aAAsC,CAAC;EAE7C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;GAC/C,MAAM,aAAa,MAAM,QAAQ,QAAQ;GACzC,WAAW,cAAc,KAAK,gBAAgB,OAAO,KAAK,KAAK;EACjE;EAEA,MAAM,WAAW,KAAK,iBAAiB,OAAO,OAAO,EAAE;EACvD,IAAI,UAAU;GACZ,SAAS,KAAK,SAAS,OAAO,WAAW,WAAW;GACpD,SAAS,OAAO;IAAE,GAAG,SAAS;IAAM,GAAG;GAAW;EACpD,OAEE,KAAK,SAAS,KAAK;GAAE,OAAO,OAAO;GAAO,SAAS,OAAO;GAAS;GAAI,IAAI;GAAU,MAAM;EAAW,CAAC;CAE3G;CAEA,MAAM,OACJ,QACA,IACe;EAEf,MAAM,iBAAiB,KAAK,kBAAkB,OAAO,OAAO,EAAE;EAC9D,IAAI,gBAAgB;GAClB,KAAK,WAAW,KAAK,SAAS,QAAO,MAAK,MAAM,cAAc;GAC9D;EACF;EAGA,KAAK,SAAS,KAAK;GAAE,OAAO,OAAO;GAAO,SAAS,OAAO;GAAS;GAAI,IAAI;EAAS,CAAC;CACvF;AACF;;;ACrKA,MAAa,iBAAiB,MAC5B,YAAY,QAAQ,iBAAiB,mBAAmB,GAAG,CAAC,GAC5D;CACE,aAAa;CACb,SAAS,IAAI,mBAAmB;EAC9B,cAAc;EACd,UAAU;EACV,UAAU;CACZ,CAAC;AACH,CACF;AAEA,MAAa,yBAAyB,MACpC,YAAY,QAAQ,IAAI,QAAQ,SAAS,kBAAkB,CAAC,GAC5D;CACE,aAAa;CACb,SAAS,IAAI,mBAAmB;EAC9B,cAAc;EACd,UAAU;EACV,UAAU;CACZ,CAAC;AACH,CACF;AAEA,IAAa,aAAb,MAAa,WAAW;CACD;CAArB,YAAY,MAAyB;EAAhB,KAAA,OAAA;CAAkB;CAEvC,OAAO,OAAO,QAAsC;EAClD,OAAO,IAAI,WAAW,OAAO,EAAE;CACjC;CAEA;CAIA,MAAM,MAAS,IAA+C;EAC5D,MAAM,UAAU,MAAM,KAAK,KAAK,2BAA2B;EAE3D,OAAO,MAAM,GAAG,IADA,SAAS,KAAK,MAAM,OAClB,CAAC;CACrB;CAEA,MAAM,UAAa,IAA2D;EAC5E,MAAM,UAAU,MAAM,KAAK,KAAK,2BAA2B;EAC3D,MAAM,MAAM,IAAI,SAAS,KAAK,MAAM,OAAO;EAG3C,OAAO;GACL,IAAI;GACJ,MAAA,MAJiB,GAAG,GAAG;GAKvB,SAAS,IAAI,mBAAmB;EAClC;CACF;CAIA,MAAM,SACJ,IACA,cAA2B,gBACC;EAC5B,OAAO,MAAM,YAAY,QAAQ,YAAY;GAC3C,IAAI;GACJ,IAAI;IAEF,MAAM,UAAU,MAAM,KAAK,KAAK,2BAA2B,IAAI;IAE/D,MAAM,MAAM,IAAI,SAAS,KAAK,MAAM,OAAO;IAC3C,MAAM,SAAS,MAAM,GAAG,GAAG;IAE3B,MAAM,UAAU,IAAI,mBAAmB;IACvC,MAAM,WAAW,IAAI,oBAAoB;IACzC,MAAM,eAAe,IAAI,kBAAkB,KAAA,CAAS;IAOpD,MAAM,KAAK,KAAK,yBAAyB,UAAU,OAAO;IAG1D,MAAM,UAAU,MAAM,KAAK,KAAK,oBAC9B,SACA,UACA,YACF;IAGA,KAAK,MAAM,uBAAuB,cAAc,KAAK,KAAK,qBAAqB,CAAC;IAChF,MAAM,GAAG,MAAM;IAGf,MAAM,WAAW,MAAM,GAAG,iBAAiB;IAC3C,aAAa,QAAQ;IAOrB,MAAM,eAAe,MAAM,GAAG,aAC5B,SACA,SACA,QACF;IAEA,IAAI,CAAC,aAAa,SAChB,MAAM,IAAI,iBAAiB,iBAAiB,EAAE,aAAa,CAAC;IAG9D,MAAM,GAAG,8BAA8B,QAAQ;IAC/C,MAAM,GAAG,OAAO;IAGhB,KAAK,gBAAgB,UAAU,QAAQ;IAEvC,OAAO;KAAE;KAAQ;KAAU;IAAS;GACtC,SAAS,KAAK;IACZ,MAAM,IAAI,SAAS;IACnB,MAAM;GACR,UAAU;IACR,IAAI,QAAQ;GACd;EACF,CAAC;CACH;AACF;AAEA,MAAa,SAAS,OAAe,IAAI,SAAe,QAAQ,WAAW,KAAK,EAAE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-DlTYWpop.js","names":[],"sources":["../src/router/router.ts"],"sourcesContent":["import type { AnyProcedure } from \"./procedure\";\n\n// ─── Router Types ────────────────────────────────────────────────────────────\n\n/**\n * A router maps procedure names (keys) to their definitions.\n * This is the type that's exported from your app and used by the client.\n */\nexport type Router<TProcedures extends Record<string, AnyProcedure<TContext>>, TContext = unknown> = {\n _type: \"router\";\n procedures: TProcedures;\n contextName: string;\n};\n\n/**\n * Inferred AppRouter type from router() call.\n * Captures the full procedure map for client type inference.\n */\nexport type AppRouter<\n TProcedures extends Record<string, AnyProcedure<TContext>> = Record<string, AnyProcedure>,\n TContext = unknown\n> = Router<TProcedures, TContext>;\n\n// ─── Type Helpers for Client ─────────────────────────────────────────────────\n\n/** Get query procedures only from a router */\nexport type QueryProcedures<T extends Record<string, AnyProcedure>> = {\n [K in keyof T as T[K] extends { procedureType: \"query\" } ? K : never]: T[K];\n};\n\n/** Get mutation procedures only from a router */\nexport type MutationProcedures<T extends Record<string, AnyProcedure>> = {\n [K in keyof T as T[K] extends { procedureType: \"mutation\" } ? K : never]: T[K];\n};\n\n/** Get action procedures only from a router */\nexport type ActionProcedures<T extends Record<string, AnyProcedure>> = {\n [K in keyof T as T[K] extends { procedureType: \"action\" } ? K : never]: T[K];\n};\n\n/** Get public (non-internal) procedures - for client type safety */\nexport type PublicProcedures<T extends Record<string, AnyProcedure>> = Pick<\n T,\n { [K in keyof T]: T[K] extends { internal: true } ? never : K }[keyof T]\n>;\n\n/** Extract procedure names from a router */\nexport type ProcedureNames<T extends Router<any>> =\n T extends Router<infer P> ? keyof P : never;\n\nexport type RouterConfig<T> = {\n procedures: T;\n contextName?: string;\n};\n\n/**\n* Create a router from procedure definitions.\n* Procedure names are inferred from the object keys.\n* \n* @example\n* const appRouter = router({\n* procedures: {\n* getUser,\n* createUser,\n* internalGetAll,\n* },\n* });\n* \n* export type AppRouter = typeof appRouter;\n*/\nexport function router<TProcedures extends Record<string, AnyProcedure<any>>, TContext = unknown>(\n config: RouterConfig<TProcedures>,\n): Router<TProcedures, TContext> {\n const registry = getContextRegistry(config.contextName ?? \"default\");\n\n // Register all procedures at router creation time\n for (const [name, proc] of Object.entries(config.procedures)) {\n registry.registerProcedure(name, proc);\n }\n\n\n return {\n _type: \"router\",\n procedures: config.procedures,\n contextName: config.contextName ?? \"default\",\n };\n}\n\nexport interface RegisteredProcedure<TContext = unknown> {\n name: string;\n type: \"query\" | \"mutation\" | \"action\";\n internal: boolean;\n inputSchema: AnyProcedure<TContext>[\"inputSchema\"];\n fn: AnyProcedure<TContext>[\"fn\"];\n /** Only present for `type === \"query\"`. See `QueryIdentitySpec`. */\n queryIdentity?: false | string | ((serverCtx: TContext | undefined, input: unknown) => string | null | undefined);\n}\n\n\nconst contextRegistry = new Map<string, ContextRegistry>();\n\nexport function getContextRegistry(inContext: string): ContextRegistry {\n let registry = contextRegistry.get(inContext);\n if (!registry) {\n registry = new ContextRegistry();\n contextRegistry.set(inContext, registry);\n }\n return registry;\n}\n\nexport class ContextRegistry {\n procedureRegistry = new Map<string, RegisteredProcedure<any>>();\n internalProcedureNames = new Set<string>();\n\n registerProcedure<TContext>(name: string, proc: AnyProcedure<TContext>): void {\n if (this.procedureRegistry.has(name)) {\n throw new Error(\n `[router] Procedure \"${name}\" is already registered. ` +\n `Each procedure name must be unique across the application.`\n );\n }\n\n // Track internal procedures by name\n if (proc.internal) {\n this.markInternalProcedure(name);\n }\n\n const queryIdentity =\n proc.procedureType === \"query\"\n ? (proc as { queryIdentity?: RegisteredProcedure<TContext>[\"queryIdentity\"] }).queryIdentity\n : undefined;\n\n this.procedureRegistry.set(name, {\n name,\n type: proc.procedureType,\n internal: proc.internal,\n inputSchema: proc.inputSchema,\n fn: proc.fn,\n queryIdentity,\n });\n }\n\n /** Get a registered procedure by name (runtime lookup) */\n getProcedure<TContext = unknown>(name: string): RegisteredProcedure<TContext> | undefined {\n return this.procedureRegistry.get(name);\n }\n\n /** Get all registered procedure names */\n getProcedureNames(): string[] {\n return [...this.procedureRegistry.keys()];\n }\n\n /** Get all registered procedures */\n getAllProcedures(): Map<string, RegisteredProcedure> {\n return new Map(this.procedureRegistry);\n }\n\n /** Clear the registry (for testing only) */\n clearRegistry(): void {\n this.procedureRegistry.clear();\n this.clearInternalProcedures();\n }\n\n markInternalProcedure(name: string): void {\n this.internalProcedureNames.add(name);\n }\n\n isInternalProcedure(name: string): boolean {\n return this.internalProcedureNames.has(name);\n }\n\n clearInternalProcedures(): void {\n this.internalProcedureNames.clear();\n }\n}"],"mappings":";;;;;;;;;;;;;;;;AAsEA,SAAgB,OACd,QAC+B;CAC/B,MAAM,WAAW,mBAAmB,OAAO,eAAe,SAAS;CAGnE,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,OAAO,UAAU,GACzD,SAAS,kBAAkB,MAAM,IAAI;CAIvC,OAAO;EACL,OAAO;EACP,YAAY,OAAO;EACnB,aAAa,OAAO,eAAe;CACrC;AACF;AAaA,MAAM,kCAAkB,IAAI,IAA6B;AAEzD,SAAgB,mBAAmB,WAAoC;CACrE,IAAI,WAAW,gBAAgB,IAAI,SAAS;CAC5C,IAAI,CAAC,UAAU;EACb,WAAW,IAAI,gBAAgB;EAC/B,gBAAgB,IAAI,WAAW,QAAQ;CACzC;CACA,OAAO;AACT;AAEA,IAAa,kBAAb,MAA6B;CAC3B,oCAAoB,IAAI,IAAsC;CAC9D,yCAAyB,IAAI,IAAY;CAEzC,kBAA4B,MAAc,MAAoC;EAC5E,IAAI,KAAK,kBAAkB,IAAI,IAAI,GACjC,MAAM,IAAI,MACR,uBAAuB,KAAK,oFAE9B;EAIF,IAAI,KAAK,UACP,KAAK,sBAAsB,IAAI;EAGjC,MAAM,gBACJ,KAAK,kBAAkB,UAClB,KAA4E,gBAC7E,KAAA;EAEN,KAAK,kBAAkB,IAAI,MAAM;GAC/B;GACA,MAAM,KAAK;GACX,UAAU,KAAK;GACf,aAAa,KAAK;GAClB,IAAI,KAAK;GACT;EACF,CAAC;CACH;;CAGA,aAAiC,MAAyD;EACxF,OAAO,KAAK,kBAAkB,IAAI,IAAI;CACxC;;CAGA,oBAA8B;EAC5B,OAAO,CAAC,GAAG,KAAK,kBAAkB,KAAK,CAAC;CAC1C;;CAGA,mBAAqD;EACnD,OAAO,IAAI,IAAI,KAAK,iBAAiB;CACvC;;CAGA,gBAAsB;EACpB,KAAK,kBAAkB,MAAM;EAC7B,KAAK,wBAAwB;CAC/B;CAEA,sBAAsB,MAAoB;EACxC,KAAK,uBAAuB,IAAI,IAAI;CACtC;CAEA,oBAAoB,MAAuB;EACzC,OAAO,KAAK,uBAAuB,IAAI,IAAI;CAC7C;CAEA,0BAAgC;EAC9B,KAAK,uBAAuB,MAAM;CACpC;AACF"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { nt as Router } from "../../index-CaWMDqq0.js";
|
|
2
|
-
import { z as z$1 } from "zod";
|
|
3
|
-
|
|
4
|
-
//#region src/db/codegen/zod-to-json.d.ts
|
|
5
|
-
interface JsonSchemaType {
|
|
6
|
-
type?: "string" | "number" | "boolean" | "integer" | "array" | "object";
|
|
7
|
-
format?: string;
|
|
8
|
-
enum?: (string | number)[];
|
|
9
|
-
items?: JsonSchemaType;
|
|
10
|
-
properties?: Record<string, JsonSchemaType>;
|
|
11
|
-
required?: string[];
|
|
12
|
-
additionalProperties?: JsonSchemaType;
|
|
13
|
-
nullable?: boolean;
|
|
14
|
-
anyOf?: JsonSchemaType[];
|
|
15
|
-
allOf?: JsonSchemaType[];
|
|
16
|
-
$ref?: string;
|
|
17
|
-
const?: string | number | boolean;
|
|
18
|
-
description?: string;
|
|
19
|
-
}
|
|
20
|
-
declare function zodToJsonSchema(schema: z$1.ZodType<any>): JsonSchemaType;
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/db/codegen/manifest.d.ts
|
|
23
|
-
interface ProcedureManifest {
|
|
24
|
-
name: string;
|
|
25
|
-
type: "query" | "mutation" | "action";
|
|
26
|
-
group: string;
|
|
27
|
-
input: JsonSchemaType | null;
|
|
28
|
-
output: null;
|
|
29
|
-
}
|
|
30
|
-
interface RouterManifest {
|
|
31
|
-
version: "1";
|
|
32
|
-
procedures: ProcedureManifest[];
|
|
33
|
-
definitions: Record<string, JsonSchemaType>;
|
|
34
|
-
}
|
|
35
|
-
declare function extractRouterManifest(router: Router): RouterManifest;
|
|
36
|
-
//#endregion
|
|
37
|
-
export { type JsonSchemaType, type ProcedureManifest, type RouterManifest, extractRouterManifest, zodToJsonSchema };
|
|
38
|
-
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","names":[],"sources":["../../../src/db/codegen/zod-to-json.ts","../../../src/db/codegen/manifest.ts"],"mappings":";;;;UAEiB,cAAA;EACb,IAAA;EACA,MAAA;EACA,IAAA;EACA,KAAA,GAAQ,cAAA;EACR,UAAA,GAAa,MAAA,SAAe,cAAA;EAC5B,QAAA;EACA,oBAAA,GAAuB,cAAA;EACvB,QAAA;EACA,KAAA,GAAQ,cAAA;EACR,KAAA,GAAQ,cAAA;EACR,IAAA;EACA,KAAA;EACA,WAAA;AAAA;AAAA,iBAWY,eAAA,CAAgB,MAAA,EAAQ,GAAA,CAAE,OAAA,QAAe,cAAc;;;UCtBtD,iBAAA;EACb,IAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA,EAAO,cAAc;EACrB,MAAA;AAAA;AAAA,UAGa,cAAA;EACb,OAAA;EACA,UAAA,EAAY,iBAAA;EACZ,WAAA,EAAa,MAAA,SAAe,cAAA;AAAA;AAAA,iBAYhB,qBAAA,CAAsB,MAAA,EAAQ,MAAA,GAAS,cAAc"}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { z as z$1 } from "zod";
|
|
2
|
-
//#region src/db/codegen/zod-to-json.ts
|
|
3
|
-
function isOptionalField(schema) {
|
|
4
|
-
return schema instanceof z$1.ZodOptional || schema instanceof z$1.ZodNullable || schema instanceof z$1.ZodDefault;
|
|
5
|
-
}
|
|
6
|
-
function zodToJsonSchema(schema) {
|
|
7
|
-
if (schema instanceof z$1.ZodString) return { type: "string" };
|
|
8
|
-
if (schema instanceof z$1.ZodNumber) return { type: "number" };
|
|
9
|
-
if (schema instanceof z$1.ZodBoolean) return { type: "boolean" };
|
|
10
|
-
if (schema instanceof z$1.ZodBigInt) return {
|
|
11
|
-
type: "string",
|
|
12
|
-
format: "bigint"
|
|
13
|
-
};
|
|
14
|
-
if (schema instanceof z$1.ZodDate) return {
|
|
15
|
-
type: "string",
|
|
16
|
-
format: "date-time"
|
|
17
|
-
};
|
|
18
|
-
if (schema instanceof z$1.ZodEnum) {
|
|
19
|
-
const entries = schema._def?.entries;
|
|
20
|
-
if (entries && typeof entries === "object") {
|
|
21
|
-
const values = Object.values(entries).filter((v) => typeof v === "string");
|
|
22
|
-
if (values.length > 0) return {
|
|
23
|
-
type: "string",
|
|
24
|
-
enum: values
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
return { type: "string" };
|
|
28
|
-
}
|
|
29
|
-
if (schema instanceof z$1.ZodArray) {
|
|
30
|
-
const inner = schema._def?.type;
|
|
31
|
-
return {
|
|
32
|
-
type: "array",
|
|
33
|
-
items: inner ? zodToJsonSchema(inner) : { type: "string" }
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (schema instanceof z$1.ZodObject) {
|
|
37
|
-
const shape = schema._def?.shape ?? schema.shape;
|
|
38
|
-
const properties = {};
|
|
39
|
-
const required = [];
|
|
40
|
-
if (shape && typeof shape === "object") for (const [key, field] of Object.entries(shape)) {
|
|
41
|
-
if (!field) continue;
|
|
42
|
-
properties[key] = zodToJsonSchema(field);
|
|
43
|
-
if (!isOptionalField(field)) required.push(key);
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
type: "object",
|
|
47
|
-
properties,
|
|
48
|
-
required: required.length > 0 ? required : void 0
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
if (schema instanceof z$1.ZodRecord) {
|
|
52
|
-
const valueType = schema._def?.valueType;
|
|
53
|
-
return {
|
|
54
|
-
type: "object",
|
|
55
|
-
additionalProperties: valueType ? zodToJsonSchema(valueType) : { type: "string" }
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
if (schema instanceof z$1.ZodOptional) {
|
|
59
|
-
const inner = schema._def?.innerType;
|
|
60
|
-
return {
|
|
61
|
-
...inner ? zodToJsonSchema(inner) : { type: "string" },
|
|
62
|
-
nullable: true
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
if (schema instanceof z$1.ZodNullable) {
|
|
66
|
-
const inner = schema._def?.innerType;
|
|
67
|
-
return {
|
|
68
|
-
...inner ? zodToJsonSchema(inner) : { type: "string" },
|
|
69
|
-
nullable: true
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (schema instanceof z$1.ZodDefault) {
|
|
73
|
-
const inner = schema._def?.innerType;
|
|
74
|
-
return inner ? zodToJsonSchema(inner) : { type: "string" };
|
|
75
|
-
}
|
|
76
|
-
if (schema instanceof z$1.ZodUnion) {
|
|
77
|
-
const options = schema._def?.options;
|
|
78
|
-
if (Array.isArray(options) && options.length > 0) return { anyOf: options.map((o) => zodToJsonSchema(o)) };
|
|
79
|
-
return { type: "string" };
|
|
80
|
-
}
|
|
81
|
-
if (schema instanceof z$1.ZodIntersection) {
|
|
82
|
-
const left = schema._def?.left;
|
|
83
|
-
const right = schema._def?.right;
|
|
84
|
-
if (left && right) return { allOf: [zodToJsonSchema(left), zodToJsonSchema(right)] };
|
|
85
|
-
return { type: "object" };
|
|
86
|
-
}
|
|
87
|
-
if (schema instanceof z$1.ZodLiteral) return { const: schema._def?.value };
|
|
88
|
-
if (schema instanceof z$1.ZodPipe || schema instanceof z$1.ZodTransform) {
|
|
89
|
-
const inner = schema._def?.schema ?? schema._def?.input;
|
|
90
|
-
return inner ? zodToJsonSchema(inner) : { type: "string" };
|
|
91
|
-
}
|
|
92
|
-
if (schema instanceof z$1.ZodAny || schema instanceof z$1.ZodUnknown) return {};
|
|
93
|
-
return { type: "string" };
|
|
94
|
-
}
|
|
95
|
-
//#endregion
|
|
96
|
-
//#region src/db/codegen/manifest.ts
|
|
97
|
-
function extractGroup(name) {
|
|
98
|
-
const dot = name.indexOf(".");
|
|
99
|
-
return dot > 0 ? name.slice(0, dot) : name;
|
|
100
|
-
}
|
|
101
|
-
function isPublicProcedure(proc) {
|
|
102
|
-
return !proc.internal;
|
|
103
|
-
}
|
|
104
|
-
function extractRouterManifest(router) {
|
|
105
|
-
const procedures = [];
|
|
106
|
-
const definitions = {};
|
|
107
|
-
for (const [name, proc] of Object.entries(router.procedures)) {
|
|
108
|
-
if (!isPublicProcedure(proc)) continue;
|
|
109
|
-
let input = null;
|
|
110
|
-
try {
|
|
111
|
-
const inputSchema = proc.inputSchema;
|
|
112
|
-
if (inputSchema) input = zodToJsonSchema(inputSchema);
|
|
113
|
-
} catch {
|
|
114
|
-
input = null;
|
|
115
|
-
}
|
|
116
|
-
procedures.push({
|
|
117
|
-
name,
|
|
118
|
-
type: proc.procedureType,
|
|
119
|
-
group: extractGroup(name),
|
|
120
|
-
input,
|
|
121
|
-
output: null
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
procedures.sort((a, b) => a.name.localeCompare(b.name));
|
|
125
|
-
return {
|
|
126
|
-
version: "1",
|
|
127
|
-
procedures,
|
|
128
|
-
definitions
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
export { extractRouterManifest, zodToJsonSchema };
|
|
133
|
-
|
|
134
|
-
//# sourceMappingURL=codegen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.js","names":["z"],"sources":["../../../src/db/codegen/zod-to-json.ts","../../../src/db/codegen/manifest.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface JsonSchemaType {\n type?: \"string\" | \"number\" | \"boolean\" | \"integer\" | \"array\" | \"object\";\n format?: string;\n enum?: (string | number)[];\n items?: JsonSchemaType;\n properties?: Record<string, JsonSchemaType>;\n required?: string[];\n additionalProperties?: JsonSchemaType;\n nullable?: boolean;\n anyOf?: JsonSchemaType[];\n allOf?: JsonSchemaType[];\n $ref?: string;\n const?: string | number | boolean;\n description?: string;\n}\n\nfunction isOptionalField(schema: z.ZodType<any>): boolean {\n return (\n schema instanceof z.ZodOptional ||\n schema instanceof z.ZodNullable ||\n schema instanceof z.ZodDefault\n );\n}\n\nexport function zodToJsonSchema(schema: z.ZodType<any>): JsonSchemaType {\n if (schema instanceof z.ZodString) {\n return { type: \"string\" };\n }\n if (schema instanceof z.ZodNumber) {\n return { type: \"number\" };\n }\n if (schema instanceof z.ZodBoolean) {\n return { type: \"boolean\" };\n }\n if (schema instanceof z.ZodBigInt) {\n return { type: \"string\", format: \"bigint\" };\n }\n if (schema instanceof z.ZodDate) {\n return { type: \"string\", format: \"date-time\" };\n }\n if (schema instanceof z.ZodEnum) {\n const entries = (schema as any)._def?.entries;\n if (entries && typeof entries === \"object\") {\n const values = Object.values(entries).filter(v => typeof v === \"string\") as string[];\n if (values.length > 0) {\n return { type: \"string\", enum: values };\n }\n }\n return { type: \"string\" };\n }\n if (schema instanceof z.ZodArray) {\n const inner = (schema as any)._def?.type;\n return {\n type: \"array\",\n items: inner ? zodToJsonSchema(inner) : { type: \"string\" },\n };\n }\n if (schema instanceof z.ZodObject) {\n const shape = (schema as any)._def?.shape ?? (schema as any).shape;\n const properties: Record<string, JsonSchemaType> = {};\n const required: string[] = [];\n if (shape && typeof shape === \"object\") {\n for (const [key, field] of Object.entries(shape)) {\n if (!field) continue;\n const fieldSchema = zodToJsonSchema(field as z.ZodType<any>);\n properties[key] = fieldSchema;\n if (!isOptionalField(field as z.ZodType<any>)) {\n required.push(key);\n }\n }\n }\n return { type: \"object\", properties, required: required.length > 0 ? required : undefined };\n }\n if (schema instanceof z.ZodRecord) {\n const valueType = (schema as any)._def?.valueType;\n return {\n type: \"object\",\n additionalProperties: valueType ? zodToJsonSchema(valueType) : { type: \"string\" },\n };\n }\n if (schema instanceof z.ZodOptional) {\n const inner = (schema as any)._def?.innerType;\n const innerSchema = inner ? zodToJsonSchema(inner) : { type: \"string\" };\n return { ...innerSchema, nullable: true };\n }\n if (schema instanceof z.ZodNullable) {\n const inner = (schema as any)._def?.innerType;\n const innerSchema = inner ? zodToJsonSchema(inner) : { type: \"string\" };\n return { ...innerSchema, nullable: true };\n }\n if (schema instanceof z.ZodDefault) {\n const inner = (schema as any)._def?.innerType;\n return inner ? zodToJsonSchema(inner) : { type: \"string\" };\n }\n if (schema instanceof z.ZodUnion) {\n const options = (schema as any)._def?.options;\n if (Array.isArray(options) && options.length > 0) {\n return { anyOf: options.map(o => zodToJsonSchema(o)) };\n }\n return { type: \"string\" };\n }\n if (schema instanceof z.ZodIntersection) {\n const left = (schema as any)._def?.left;\n const right = (schema as any)._def?.right;\n if (left && right) {\n return { allOf: [zodToJsonSchema(left), zodToJsonSchema(right)] };\n }\n return { type: \"object\" };\n }\n if (schema instanceof z.ZodLiteral) {\n return { const: (schema as any)._def?.value };\n }\n if (schema instanceof z.ZodPipe || schema instanceof z.ZodTransform) {\n const inner = (schema as any)._def?.schema ?? (schema as any)._def?.input;\n return inner ? zodToJsonSchema(inner) : { type: \"string\" };\n }\n if (schema instanceof z.ZodAny || schema instanceof z.ZodUnknown) {\n return {};\n }\n return { type: \"string\" };\n}\n","import type { Router } from \"../../router/router\";\nimport type { AnyProcedure } from \"../../router/procedure\";\nimport { zodToJsonSchema, type JsonSchemaType } from \"./zod-to-json\";\n\nexport interface ProcedureManifest {\n name: string;\n type: \"query\" | \"mutation\" | \"action\";\n group: string;\n input: JsonSchemaType | null;\n output: null; // output type inference requires runtime annotation\n}\n\nexport interface RouterManifest {\n version: \"1\";\n procedures: ProcedureManifest[];\n definitions: Record<string, JsonSchemaType>;\n}\n\nfunction extractGroup(name: string): string {\n const dot = name.indexOf(\".\");\n return dot > 0 ? name.slice(0, dot) : name;\n}\n\nfunction isPublicProcedure(proc: AnyProcedure): boolean {\n return !proc.internal;\n}\n\nexport function extractRouterManifest(router: Router): RouterManifest {\n const procedures: ProcedureManifest[] = [];\n const definitions: Record<string, JsonSchemaType> = {};\n\n for (const [name, proc] of Object.entries(router.procedures)) {\n if (!isPublicProcedure(proc)) continue;\n\n let input: JsonSchemaType | null = null;\n try {\n const inputSchema = proc.inputSchema;\n if (inputSchema) {\n input = zodToJsonSchema(inputSchema as any);\n }\n } catch {\n input = null;\n }\n\n procedures.push({\n name,\n type: proc.procedureType as \"query\" | \"mutation\" | \"action\",\n group: extractGroup(name),\n input,\n output: null,\n });\n }\n\n procedures.sort((a, b) => a.name.localeCompare(b.name));\n\n return {\n version: \"1\",\n procedures,\n definitions,\n };\n}\n"],"mappings":"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"}
|