@supalive/core 1.0.0 → 1.2.0

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.
Files changed (85) hide show
  1. package/README.md +28 -0
  2. package/dist/db-ClCicssQ.js +28 -0
  3. package/dist/db-ClCicssQ.js.map +1 -0
  4. package/dist/{index-DouKwYL6.d.ts → index-E1_1iRI1.d.ts} +213 -9
  5. package/dist/index-E1_1iRI1.d.ts.map +1 -0
  6. package/dist/{mysql-Bxurg_PH.d.ts → mysql-BmkLy5oY.d.ts} +8 -3
  7. package/dist/mysql-BmkLy5oY.d.ts.map +1 -0
  8. package/dist/{mysql-bvnjYWvZ.js → mysql-Ca1B_0k_.js} +58 -25
  9. package/dist/mysql-Ca1B_0k_.js.map +1 -0
  10. package/dist/{overlap-checker-Ct_HP_iB.js → overlap-checker-ClJC0nxW.js} +52 -4
  11. package/dist/overlap-checker-ClJC0nxW.js.map +1 -0
  12. package/dist/{postgres-B8u1YN8X.js → postgres-CHDY1HPf.js} +59 -22
  13. package/dist/postgres-CHDY1HPf.js.map +1 -0
  14. package/dist/{postgres-Ck-xt72U.d.ts → postgres-v2ctNE6o.d.ts} +8 -3
  15. package/dist/postgres-v2ctNE6o.d.ts.map +1 -0
  16. package/dist/{procedure-DX87tyef.js → procedure-Ze1GE-N9.js} +33 -2
  17. package/dist/procedure-Ze1GE-N9.js.map +1 -0
  18. package/dist/{query-Bh0RNxDz.js → query-CrbJ_W0W.js} +21 -1
  19. package/dist/query-CrbJ_W0W.js.map +1 -0
  20. package/dist/{realtime_db-DOCgqbwi.js → realtime_db-BtwBABDY.js} +76 -51
  21. package/dist/realtime_db-BtwBABDY.js.map +1 -0
  22. package/dist/{router-DlTYWpop.js → router-CiWYeWUR.js} +8 -2
  23. package/dist/router-CiWYeWUR.js.map +1 -0
  24. package/dist/src/client/index.d.ts +1 -1
  25. package/dist/src/client/index.js +44 -5
  26. package/dist/src/client/index.js.map +1 -1
  27. package/dist/src/exports/mysql.d.ts +1 -1
  28. package/dist/src/exports/mysql.js +1 -1
  29. package/dist/src/exports/postgres.d.ts +1 -1
  30. package/dist/src/exports/postgres.js +1 -1
  31. package/dist/src/exports/procedure.d.ts +2 -2
  32. package/dist/src/exports/procedure.js +4 -4
  33. package/dist/src/exports/schema-sql.d.ts +35 -2
  34. package/dist/src/exports/schema-sql.d.ts.map +1 -1
  35. package/dist/src/exports/schema-sql.js +69 -19
  36. package/dist/src/exports/schema-sql.js.map +1 -1
  37. package/dist/src/exports/server.d.ts +64 -17
  38. package/dist/src/exports/server.d.ts.map +1 -1
  39. package/dist/src/exports/server.js +726 -64
  40. package/dist/src/exports/server.js.map +1 -1
  41. package/dist/src/exports/subscription-manager-worker-entry.js +8 -5
  42. package/dist/src/exports/subscription-manager-worker-entry.js.map +1 -1
  43. package/dist/src/exports/types.d.ts +3 -3
  44. package/dist/src/exports/types.js +1 -1
  45. package/dist/{subscription-worker-CqoWp6zB.js → subscription-worker-CAf6MUta.js} +306 -69
  46. package/dist/subscription-worker-CAf6MUta.js.map +1 -0
  47. package/dist/{types_db-DXj_l9n-.js → types_db-CTRm_awX.js} +7 -2
  48. package/dist/types_db-CTRm_awX.js.map +1 -0
  49. package/dist/types_server-CzAufcee.d.ts +420 -0
  50. package/dist/types_server-CzAufcee.d.ts.map +1 -0
  51. package/package.json +5 -4
  52. package/dist/index-CaWMDqq0.d.ts +0 -1754
  53. package/dist/index-CaWMDqq0.d.ts.map +0 -1
  54. package/dist/index-DouKwYL6.d.ts.map +0 -1
  55. package/dist/mysql-Bxurg_PH.d.ts.map +0 -1
  56. package/dist/mysql-Cxd4Uq5p.d.ts +0 -104
  57. package/dist/mysql-Cxd4Uq5p.d.ts.map +0 -1
  58. package/dist/mysql-bvnjYWvZ.js.map +0 -1
  59. package/dist/overlap-checker-Ct_HP_iB.js.map +0 -1
  60. package/dist/postgres-B8u1YN8X.js.map +0 -1
  61. package/dist/postgres-CfT_aDx3.d.ts +0 -108
  62. package/dist/postgres-CfT_aDx3.d.ts.map +0 -1
  63. package/dist/postgres-Ck-xt72U.d.ts.map +0 -1
  64. package/dist/procedure-DX87tyef.js.map +0 -1
  65. package/dist/query-Bh0RNxDz.js.map +0 -1
  66. package/dist/realtime_db-DOCgqbwi.js.map +0 -1
  67. package/dist/router-DlTYWpop.js.map +0 -1
  68. package/dist/src/exports/codegen.d.ts +0 -38
  69. package/dist/src/exports/codegen.d.ts.map +0 -1
  70. package/dist/src/exports/codegen.js +0 -134
  71. package/dist/src/exports/codegen.js.map +0 -1
  72. package/dist/subscription-worker-CqoWp6zB.js.map +0 -1
  73. package/dist/subscription-worker-PtmJWEj1.js +0 -511
  74. package/dist/subscription-worker-PtmJWEj1.js.map +0 -1
  75. package/dist/subscription-worker-pahX0zxg.js +0 -511
  76. package/dist/subscription-worker-pahX0zxg.js.map +0 -1
  77. package/dist/types_db-DXj_l9n-.js.map +0 -1
  78. package/dist/types_server-BW1ys_SK.d.ts +0 -216
  79. package/dist/types_server-BW1ys_SK.d.ts.map +0 -1
  80. package/dist/types_server-Dpsi0wpG.d.ts +0 -216
  81. package/dist/types_server-Dpsi0wpG.d.ts.map +0 -1
  82. package/dist/types_server-DzrIccyO.d.ts +0 -216
  83. package/dist/types_server-DzrIccyO.d.ts.map +0 -1
  84. package/dist/types_server-TFo6SWDH.d.ts +0 -216
  85. package/dist/types_server-TFo6SWDH.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { _n as schemaRegistry, bn as trackSchema, pn as SchemaDefinition } from "../../index-DouKwYL6.js";
1
+ import { Cn as schemaRegistry, En as trackSchema, yn as SchemaDefinition } from "../../index-E1_1iRI1.js";
2
2
 
3
3
  //#region src/db/schema-sql.d.ts
4
4
  type SqlDialect = "postgres" | "mysql";
@@ -11,8 +11,41 @@ interface GenerateSchemaSqlOptions {
11
11
  dialect?: SqlDialect;
12
12
  ifNotExists?: boolean;
13
13
  header?: boolean;
14
+ /**
15
+ * Prepend the framework-owned core tables (`commit_logs`, `metadata`) and
16
+ * their indexes so the generated SQL fully describes the database. Default
17
+ * true. Non-table core bootstrap (sequences, seed rows) is handled at
18
+ * runtime by `initCore`, not emitted here.
19
+ */
20
+ includeCoreTables?: boolean;
14
21
  }
15
22
  declare function generateSchemaSql(schemas?: Map<string, SchemaDefinition<string, any, any>> | SchemaDefinition<string, any, any>[], options?: GenerateSchemaSqlOptions): string;
16
23
  //#endregion
17
- export { type GenerateSchemaSqlOptions, type SchemaToCreateTableOptions, type SqlDialect, generateSchemaSql, schemaRegistry, schemaToCreateTable, trackSchema };
24
+ //#region src/db/core-tables.d.ts
25
+ /**
26
+ * DDL for the core, framework-owned tables that every Supalive database must
27
+ * have alongside the user's own tables:
28
+ *
29
+ * - `commit_logs` — the append-only OCC change log (+ its lookup indexes).
30
+ * - `metadata` — the small key/value table holding the OCC watermarks
31
+ * (`latest_committed_ts`, `min_retained_ts`) and the core
32
+ * schema version (`core_version`).
33
+ *
34
+ * These used to live in each `Database.migrationSql` array and were applied
35
+ * ad-hoc. They now belong in the generated `schema.sql` (see
36
+ * {@link generateSchemaSql}, which prepends them by default) so a single
37
+ * generated file fully describes the database.
38
+ *
39
+ * Note: this module intentionally covers ONLY tables + indexes. Non-table
40
+ * bootstrap (the `global_commit_ts` sequence, the MySQL `sequence` table, and
41
+ * the metadata seed rows) is handled at runtime by `initCore` — see
42
+ * {@link file://./init_db.ts}.
43
+ */
44
+ interface CoreTablesSqlOptions {
45
+ /** Emit `IF NOT EXISTS` on `CREATE TABLE`/`CREATE INDEX`. Default true. */
46
+ ifNotExists?: boolean;
47
+ }
48
+ declare function coreTablesSql(dialect?: SqlDialect, options?: CoreTablesSqlOptions): string[];
49
+ //#endregion
50
+ export { type CoreTablesSqlOptions, type GenerateSchemaSqlOptions, type SchemaToCreateTableOptions, type SqlDialect, coreTablesSql, generateSchemaSql, schemaRegistry, schemaToCreateTable, trackSchema };
18
51
  //# sourceMappingURL=schema-sql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-sql.d.ts","names":[],"sources":["../../../src/db/schema-sql.ts"],"mappings":";;;KAKY,UAAA;AAAA,UAgIK,0BAAA;EACb,OAAA,GAAU,UAAU;EACpB,WAAA;AAAA;AAAA,iBAGY,mBAAA,CACZ,MAAA,EAAQ,gBAAA,oBACR,OAAA,GAAU,0BAA0B;AAAA,UA4DvB,wBAAA;EACb,OAAA,GAAU,UAAU;EACpB,WAAA;EACA,MAAA;AAAA;AAAA,iBAGY,iBAAA,CACZ,OAAA,GAAU,GAAA,SAAY,gBAAA,sBAAsC,gBAAA,sBAC5D,OAAA,GAAU,wBAAA"}
1
+ {"version":3,"file":"schema-sql.d.ts","names":[],"sources":["../../../src/db/schema-sql.ts","../../../src/db/core-tables.ts"],"mappings":";;;KAMY,UAAA;AAAA,UAsKK,0BAAA;EACb,OAAA,GAAU,UAAU;EACpB,WAAA;AAAA;AAAA,iBAGY,mBAAA,CACZ,MAAA,EAAQ,gBAAA,oBACR,OAAA,GAAU,0BAA0B;AAAA,UAoFvB,wBAAA;EACb,OAAA,GAAU,UAAU;EACpB,WAAA;EACA,MAAA;EAzF+B;;;;;;EAgG/B,iBAAA;AAAA;AAAA,iBAGY,iBAAA,CACZ,OAAA,GAAU,GAAA,SAAY,gBAAA,sBAAsC,gBAAA,sBAC5D,OAAA,GAAU,wBAAA;;;;;AAhRd;;;;AAAsB;AAsKtB;;;;;;;;AAEe;AAGf;;;UC3JiB,oBAAA;ED4JL;EC1JR,WAAW;AAAA;AAAA,iBAGC,aAAA,CACZ,OAAA,GAAS,UAAA,EACT,OAAA,GAAU,oBAAoB"}
@@ -1,6 +1,20 @@
1
1
  import { r as unwrapZodType } from "../../codec-BHAmGEIQ.js";
2
2
  import { o as trackSchema, r as schemaRegistry } from "../../schema-Dd7u0A1L.js";
3
3
  import { z as z$1 } from "zod";
4
+ //#region src/db/core-tables.ts
5
+ function coreTablesSql(dialect = "postgres", options) {
6
+ const ifNotExists = options?.ifNotExists ?? true;
7
+ const t = ifNotExists ? "IF NOT EXISTS " : "";
8
+ const i = ifNotExists ? "IF NOT EXISTS " : "";
9
+ if (dialect === "mysql") return [`CREATE TABLE ${t}commit_logs (\n id BINARY(16) NOT NULL,\n ts BIGINT NOT NULL,\n table_id BINARY(16) NOT NULL,\n data LONGBLOB NOT NULL,\n PRIMARY KEY (ts, table_id, id),\n INDEX commit_logs_by_table_and_id (table_id, id, ts)\n) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;`, `CREATE TABLE ${t}metadata (\n meta_key VARCHAR(255) PRIMARY KEY,\n meta_value BIGINT NOT NULL\n) ENGINE=InnoDB;`];
10
+ return [
11
+ `CREATE TABLE ${t}commit_logs (\n id BYTEA NOT NULL,\n ts BIGINT NOT NULL,\n table_id BYTEA NOT NULL,\n data BYTEA NOT NULL,\n PRIMARY KEY (ts, table_id, id)\n);`,
12
+ `CREATE INDEX ${i}commit_logs_by_table_and_id ON commit_logs (table_id, id, ts);`,
13
+ `CREATE INDEX ${i}commit_logs_by_table_ts_and_id ON commit_logs (table_id, ts, id);`,
14
+ `CREATE TABLE ${t}metadata (\n meta_key TEXT PRIMARY KEY,\n meta_value BIGINT NOT NULL\n);`
15
+ ];
16
+ }
17
+ //#endregion
4
18
  //#region src/db/schema-sql.ts
5
19
  function getFieldMeta(field) {
6
20
  const f = field;
@@ -15,10 +29,10 @@ function getFieldMeta(field) {
15
29
  function getStringMaxLength(field) {
16
30
  const unwrapped = unwrapZodType(field);
17
31
  if (!(unwrapped instanceof z$1.ZodString)) return void 0;
18
- const checks = unwrapped._def?.checks ?? [];
32
+ const checks = unwrapped.def?.checks ?? [];
19
33
  let maxLength;
20
34
  for (const check of checks) {
21
- const c = check.def ?? check;
35
+ const c = check._zod?.def ?? check.def ?? check;
22
36
  if (c.check === "length_equals" || c.check === "size_equals") {
23
37
  const len = c.length ?? c.size;
24
38
  if (typeof len === "number") maxLength = maxLength === void 0 ? len : Math.min(maxLength, len);
@@ -41,7 +55,7 @@ function getDefaultFromZod(field) {
41
55
  try {
42
56
  const f = field;
43
57
  let value = f.defaultValue;
44
- if (value === void 0) value = f._def?.defaultValue;
58
+ if (value === void 0) value = f.def?.defaultValue;
45
59
  if (typeof value === "function") value = value();
46
60
  if (value === void 0) return void 0;
47
61
  if (value === null) return "NULL";
@@ -55,14 +69,10 @@ function getDefaultFromZod(field) {
55
69
  }
56
70
  }
57
71
  const VARCHAR_MAX = 65535;
58
- function getSqlType(field, dialect) {
59
- const meta = getFieldMeta(field);
60
- if (meta) {
61
- const dialectKey = dialect === "mysql" ? "mysqlType" : "pgType";
62
- if (typeof meta[dialectKey] === "string") return meta[dialectKey];
63
- if (typeof meta.sql_type === "string") return meta.sql_type;
64
- }
65
- const unwrapped = unwrapZodType(field);
72
+ function jsonType(dialect) {
73
+ return dialect === "mysql" ? "JSON" : "JSONB";
74
+ }
75
+ function getScalarSqlType(unwrapped, field, dialect) {
66
76
  if (unwrapped instanceof z$1.ZodString) {
67
77
  const maxLen = getStringMaxLength(field);
68
78
  if (maxLen !== void 0 && maxLen <= VARCHAR_MAX) return `VARCHAR(${maxLen})`;
@@ -72,10 +82,33 @@ function getSqlType(field, dialect) {
72
82
  if (unwrapped instanceof z$1.ZodBoolean) return dialect === "mysql" ? "TINYINT(1)" : "BOOLEAN";
73
83
  if (unwrapped instanceof z$1.ZodDate) return dialect === "mysql" ? "DATETIME(3)" : "TIMESTAMPTZ";
74
84
  if (unwrapped instanceof z$1.ZodBigInt) return "BIGINT";
75
- if (unwrapped instanceof z$1.ZodArray) return dialect === "mysql" ? "JSON" : "JSONB";
76
- if (unwrapped instanceof z$1.ZodObject || unwrapped instanceof z$1.ZodRecord) return dialect === "mysql" ? "JSON" : "JSONB";
77
85
  if (unwrapped instanceof z$1.ZodEnum) return "TEXT";
78
- return "TEXT";
86
+ }
87
+ function getArrayElement(arr) {
88
+ return arr.element ?? arr.def?.element ?? arr.def?.type;
89
+ }
90
+ function getArraySqlType(arr, dialect) {
91
+ if (dialect === "mysql") return "JSON";
92
+ const rawElement = getArrayElement(arr);
93
+ const element = unwrapZodType(rawElement);
94
+ const elementMeta = getFieldMeta(rawElement);
95
+ if (elementMeta) {
96
+ if (typeof elementMeta.pgType === "string") return `${elementMeta.pgType}[]`;
97
+ }
98
+ const scalar = getScalarSqlType(element, rawElement, dialect);
99
+ if (scalar !== void 0) return `${scalar}[]`;
100
+ return "JSONB";
101
+ }
102
+ function getSqlType(field, dialect) {
103
+ const meta = getFieldMeta(field);
104
+ if (meta) {
105
+ const dialectKey = dialect === "mysql" ? "mysqlType" : "pgType";
106
+ if (typeof meta[dialectKey] === "string") return meta[dialectKey];
107
+ }
108
+ const unwrapped = unwrapZodType(field);
109
+ if (unwrapped instanceof z$1.ZodArray) return getArraySqlType(unwrapped, dialect);
110
+ if (unwrapped instanceof z$1.ZodObject || unwrapped instanceof z$1.ZodRecord) return jsonType(dialect);
111
+ return getScalarSqlType(unwrapped, field, dialect) ?? "TEXT";
79
112
  }
80
113
  function isPrimaryKey(field) {
81
114
  return getFieldMeta(field)?.primaryKey === true;
@@ -122,15 +155,27 @@ function formatDeclarativeIndex(idx, tableName, columns) {
122
155
  if (idx.where) sql += ` WHERE ${idx.where}`;
123
156
  return sql + ";";
124
157
  }
125
- function schemaIndexes(schema) {
126
- return (schema.indexes ?? []).map((idx) => {
158
+ function schemaIndexes(schema, options) {
159
+ const out = (schema.indexes ?? []).map((idx) => {
127
160
  if (typeof idx === "string") return idx;
128
161
  return formatDeclarativeIndex(idx, schema.table, schema.columns);
129
162
  });
163
+ const commitCol = schema.columns["commitTs"] ?? "commit_ts";
164
+ const autoName = `${schema.table}_commit_ts_idx`;
165
+ if (!(schema.indexes ?? []).some((idx) => {
166
+ if (typeof idx === "string") return idx.includes(autoName);
167
+ if (idx.name === autoName) return true;
168
+ return idx.columns.length === 1 && (idx.columns[0] === "commitTs" || idx.columns[0] === commitCol);
169
+ })) {
170
+ const ifNot = options?.ifNotExists ?? true ? "IF NOT EXISTS " : "";
171
+ out.push(`CREATE INDEX ${ifNot}${autoName} ON ${schema.table} (${commitCol});`);
172
+ }
173
+ return out;
130
174
  }
131
175
  function generateSchemaSql(schemas, options) {
132
176
  const dialect = options?.dialect ?? "postgres";
133
177
  const header = options?.header ?? true;
178
+ const includeCoreTables = options?.includeCoreTables ?? true;
134
179
  let list;
135
180
  if (schemas instanceof Map) list = [...schemas.values()];
136
181
  else if (Array.isArray(schemas)) list = schemas;
@@ -141,7 +186,12 @@ function generateSchemaSql(schemas, options) {
141
186
  if (header) {
142
187
  parts.push("-- Generated by Supalive Schema Generator");
143
188
  parts.push(`-- Dialect: ${dialect}`);
144
- parts.push(`-- Tables: ${list.length}`);
189
+ parts.push(`-- Tables: ${list.length}${includeCoreTables ? " (+ core)" : ""}`);
190
+ parts.push("");
191
+ }
192
+ if (includeCoreTables) {
193
+ parts.push("-- Core tables (framework-owned)");
194
+ for (const stmt of coreTablesSql(dialect, { ifNotExists: options?.ifNotExists })) parts.push(stmt);
145
195
  parts.push("");
146
196
  }
147
197
  for (const schema of list) {
@@ -149,13 +199,13 @@ function generateSchemaSql(schemas, options) {
149
199
  ...options,
150
200
  dialect
151
201
  }));
152
- const indexStmts = schemaIndexes(schema);
202
+ const indexStmts = schemaIndexes(schema, { ifNotExists: options?.ifNotExists });
153
203
  for (const stmt of indexStmts) parts.push(stmt);
154
204
  parts.push("");
155
205
  }
156
206
  return parts.join("\n");
157
207
  }
158
208
  //#endregion
159
- export { generateSchemaSql, schemaRegistry, schemaToCreateTable, trackSchema };
209
+ export { coreTablesSql, generateSchemaSql, schemaRegistry, schemaToCreateTable, trackSchema };
160
210
 
161
211
  //# sourceMappingURL=schema-sql.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-sql.js","names":["z"],"sources":["../../../src/db/schema-sql.ts"],"sourcesContent":["import { z, ZodRawShape } from \"zod\";\nimport { SchemaDefinition, schemaRegistry } from \"./schema\";\nimport type { DeclarativeIndex } from \"./schema\";\nimport { unwrapZodType } from \"./codec\";\n\nexport type SqlDialect = \"postgres\" | \"mysql\";\n\nfunction getFieldMeta(field: unknown): Record<string, unknown> | undefined {\n const f = field as any;\n const meta = typeof f.meta === \"function\" ? f.meta() : undefined;\n if (meta) return meta;\n\n const unwrapped = unwrapZodType(field);\n if (unwrapped !== field) {\n const innerMeta = typeof (unwrapped as any).meta === \"function\" ? (unwrapped as any).meta() : undefined;\n if (innerMeta) return innerMeta;\n }\n\n return undefined;\n}\n\nfunction getStringMaxLength(field: unknown): number | undefined {\n const unwrapped = unwrapZodType(field);\n if (!(unwrapped instanceof z.ZodString)) return undefined;\n\n const checks: any[] = (unwrapped as any)._def?.checks ?? [];\n let maxLength: number | undefined;\n\n for (const check of checks) {\n const c = check.def ?? check;\n if (c.check === \"length_equals\" || c.check === \"size_equals\") {\n const len = c.length ?? c.size;\n if (typeof len === \"number\") maxLength = maxLength === undefined ? len : Math.min(maxLength, len);\n }\n if (c.check === \"max_length\" || c.check === \"max_size\") {\n const len = c.maximum ?? c.max;\n if (typeof len === \"number\") maxLength = maxLength === undefined ? len : Math.min(maxLength, len);\n }\n }\n\n return maxLength;\n}\n\nfunction isOptional(field: unknown): boolean {\n return (\n field instanceof z.ZodOptional ||\n field instanceof z.ZodNullable\n );\n}\n\nfunction escapeSQLString(s: string): string {\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction getDefaultFromZod(field: unknown): string | undefined {\n if (!(field instanceof z.ZodDefault)) return undefined;\n\n try {\n const f = field as any;\n let value = f.defaultValue;\n if (value === undefined) value = f._def?.defaultValue;\n if (typeof value === \"function\") value = value();\n\n if (value === undefined) return undefined;\n if (value === null) return \"NULL\";\n if (typeof value === \"string\") return escapeSQLString(value);\n if (typeof value === \"number\") return value.toString();\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (typeof value === \"bigint\") return value.toString();\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nconst VARCHAR_MAX = 65535;\n\nfunction getSqlType(field: unknown, dialect: SqlDialect): string {\n const meta = getFieldMeta(field);\n if (meta) {\n const dialectKey = dialect === \"mysql\" ? \"mysqlType\" : \"pgType\";\n if (typeof meta[dialectKey] === \"string\") return meta[dialectKey] as string;\n if (typeof meta.sql_type === \"string\") return meta.sql_type;\n }\n\n const unwrapped = unwrapZodType(field);\n\n if (unwrapped instanceof z.ZodString) {\n const maxLen = getStringMaxLength(field);\n if (maxLen !== undefined && maxLen <= VARCHAR_MAX) return `VARCHAR(${maxLen})`;\n return \"TEXT\";\n }\n\n if (unwrapped instanceof z.ZodNumber) return \"BIGINT\";\n\n if (unwrapped instanceof z.ZodBoolean) {\n return dialect === \"mysql\" ? \"TINYINT(1)\" : \"BOOLEAN\";\n }\n\n if (unwrapped instanceof z.ZodDate) {\n return dialect === \"mysql\" ? \"DATETIME(3)\" : \"TIMESTAMPTZ\";\n }\n\n if (unwrapped instanceof z.ZodBigInt) return \"BIGINT\";\n\n if (unwrapped instanceof z.ZodArray) {\n return dialect === \"mysql\" ? \"JSON\" : \"JSONB\";\n }\n\n if (unwrapped instanceof z.ZodObject || unwrapped instanceof z.ZodRecord) {\n return dialect === \"mysql\" ? \"JSON\" : \"JSONB\";\n }\n\n if (unwrapped instanceof z.ZodEnum) return \"TEXT\";\n\n return \"TEXT\";\n}\n\nfunction isPrimaryKey(field: unknown): boolean {\n const meta = getFieldMeta(field);\n return meta?.primaryKey === true;\n}\n\nfunction getDefaultValue(field: unknown): string | undefined {\n const meta = getFieldMeta(field);\n if (meta && typeof meta.defaultValue === \"string\") {\n return meta.defaultValue;\n }\n\n return getDefaultFromZod(field);\n}\n\nexport interface SchemaToCreateTableOptions {\n dialect?: SqlDialect;\n ifNotExists?: boolean;\n}\n\nexport function schemaToCreateTable(\n schema: SchemaDefinition<string, any, any>,\n options?: SchemaToCreateTableOptions,\n): string {\n const dialect = options?.dialect ?? \"postgres\";\n const ifNotExists = options?.ifNotExists ?? true;\n\n const tableName = schema.table;\n const shape = schema.schema.shape;\n const columns: Record<string, string> = schema.columns;\n\n const userKeys = Object.keys(shape).filter(k => k !== \"id\" && k !== \"commitTs\");\n const orderedKeys = [\"id\", ...userKeys, \"commitTs\"];\n\n const lines: string[] = [];\n\n for (const fieldName of orderedKeys) {\n const field = shape[fieldName];\n if (!field) continue;\n\n const colName = columns[fieldName] ?? fieldName;\n if (!colName) continue;\n\n const sqlType = getSqlType(field, dialect);\n const notNull = !isOptional(field);\n const pk = isPrimaryKey(field);\n const defaultVal = fieldName === \"commitTs\" ? \"0\" : getDefaultValue(field);\n\n let line = ` ${colName} ${sqlType}`;\n if (notNull) line += \" NOT NULL\";\n if (pk) line += \" PRIMARY KEY\";\n if (defaultVal !== undefined) line += ` DEFAULT ${defaultVal}`;\n\n lines.push(line);\n }\n\n const ifNot = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n return `CREATE TABLE ${ifNot}${tableName} (\\n${lines.join(\",\\n\")}\\n);`;\n}\n\nexport function formatDeclarativeIndex(\n idx: DeclarativeIndex,\n tableName: string,\n columns: Record<string, string>,\n): string {\n const colNames = idx.columns.map(c => columns[c] ?? c).join(\", \");\n let sql = `CREATE ${idx.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${idx.name} ON ${tableName}`;\n if (idx.type) sql += ` USING ${idx.type}`;\n sql += ` (${colNames})`;\n if (idx.where) sql += ` WHERE ${idx.where}`;\n return sql + \";\";\n}\n\nexport function schemaIndexes(\n schema: SchemaDefinition<string, any, any>,\n): string[] {\n return (schema.indexes ?? []).map(idx => {\n if (typeof idx === \"string\") return idx;\n return formatDeclarativeIndex(idx, schema.table, schema.columns);\n });\n}\n\nexport interface GenerateSchemaSqlOptions {\n dialect?: SqlDialect;\n ifNotExists?: boolean;\n header?: boolean;\n}\n\nexport function generateSchemaSql(\n schemas?: Map<string, SchemaDefinition<string, any, any>> | SchemaDefinition<string, any, any>[],\n options?: GenerateSchemaSqlOptions,\n): string {\n const dialect = options?.dialect ?? \"postgres\";\n const header = options?.header ?? true;\n\n let list: SchemaDefinition<string, any, any>[];\n\n if (schemas instanceof Map) {\n list = [...schemas.values()];\n } else if (Array.isArray(schemas)) {\n list = schemas;\n } else {\n list = [...schemaRegistry.values()];\n }\n\n list = list.filter(s => s?.table);\n list.sort((a, b) => a.table.localeCompare(b.table));\n\n const parts: string[] = [];\n\n if (header) {\n parts.push(\"-- Generated by Supalive Schema Generator\");\n parts.push(`-- Dialect: ${dialect}`);\n parts.push(`-- Tables: ${list.length}`);\n parts.push(\"\");\n }\n\n for (const schema of list) {\n parts.push(schemaToCreateTable(schema, { ...options, dialect }));\n const indexStmts = schemaIndexes(schema);\n for (const stmt of indexStmts) {\n parts.push(stmt);\n }\n parts.push(\"\");\n }\n\n return parts.join(\"\\n\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schema-sql.js","names":["z"],"sources":["../../../src/db/core-tables.ts","../../../src/db/schema-sql.ts"],"sourcesContent":["import type { SqlDialect } from \"./schema-sql\";\n\n/**\n * DDL for the core, framework-owned tables that every Supalive database must\n * have alongside the user's own tables:\n *\n * - `commit_logs` — the append-only OCC change log (+ its lookup indexes).\n * - `metadata` — the small key/value table holding the OCC watermarks\n * (`latest_committed_ts`, `min_retained_ts`) and the core\n * schema version (`core_version`).\n *\n * These used to live in each `Database.migrationSql` array and were applied\n * ad-hoc. They now belong in the generated `schema.sql` (see\n * {@link generateSchemaSql}, which prepends them by default) so a single\n * generated file fully describes the database.\n *\n * Note: this module intentionally covers ONLY tables + indexes. Non-table\n * bootstrap (the `global_commit_ts` sequence, the MySQL `sequence` table, and\n * the metadata seed rows) is handled at runtime by `initCore` — see\n * {@link file://./init_db.ts}.\n */\n\nexport interface CoreTablesSqlOptions {\n /** Emit `IF NOT EXISTS` on `CREATE TABLE`/`CREATE INDEX`. Default true. */\n ifNotExists?: boolean;\n}\n\nexport function coreTablesSql(\n dialect: SqlDialect = \"postgres\",\n options?: CoreTablesSqlOptions,\n): string[] {\n const ifNotExists = options?.ifNotExists ?? true;\n const t = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n const i = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n\n if (dialect === \"mysql\") {\n return [\n `CREATE TABLE ${t}commit_logs (\\n` +\n ` id BINARY(16) NOT NULL,\\n` +\n ` ts BIGINT NOT NULL,\\n` +\n ` table_id BINARY(16) NOT NULL,\\n` +\n ` data LONGBLOB NOT NULL,\\n` +\n ` PRIMARY KEY (ts, table_id, id),\\n` +\n ` INDEX commit_logs_by_table_and_id (table_id, id, ts)\\n` +\n `) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;`,\n `CREATE TABLE ${t}metadata (\\n` +\n ` meta_key VARCHAR(255) PRIMARY KEY,\\n` +\n ` meta_value BIGINT NOT NULL\\n` +\n `) ENGINE=InnoDB;`,\n ];\n }\n\n return [\n `CREATE TABLE ${t}commit_logs (\\n` +\n ` id BYTEA NOT NULL,\\n` +\n ` ts BIGINT NOT NULL,\\n` +\n ` table_id BYTEA NOT NULL,\\n` +\n ` data BYTEA NOT NULL,\\n` +\n ` PRIMARY KEY (ts, table_id, id)\\n` +\n `);`,\n `CREATE INDEX ${i}commit_logs_by_table_and_id ON commit_logs (table_id, id, ts);`,\n `CREATE INDEX ${i}commit_logs_by_table_ts_and_id ON commit_logs (table_id, ts, id);`,\n `CREATE TABLE ${t}metadata (\\n` +\n ` meta_key TEXT PRIMARY KEY,\\n` +\n ` meta_value BIGINT NOT NULL\\n` +\n `);`,\n ];\n}\n","import { z } from \"zod\";\nimport { SchemaDefinition, schemaRegistry } from \"./schema\";\nimport type { DeclarativeIndex } from \"./schema\";\nimport { unwrapZodType } from \"./codec\";\nimport { coreTablesSql } from \"./core-tables\";\n\nexport type SqlDialect = \"postgres\" | \"mysql\";\n\nfunction getFieldMeta(field: unknown): Record<string, unknown> | undefined {\n const f = field as any;\n const meta = typeof f.meta === \"function\" ? f.meta() : undefined;\n if (meta) return meta;\n\n const unwrapped = unwrapZodType(field);\n if (unwrapped !== field) {\n const innerMeta = typeof (unwrapped as any).meta === \"function\" ? (unwrapped as any).meta() : undefined;\n if (innerMeta) return innerMeta;\n }\n\n return undefined;\n}\n\nfunction getStringMaxLength(field: unknown): number | undefined {\n const unwrapped = unwrapZodType(field);\n if (!(unwrapped instanceof z.ZodString)) return undefined;\n\n const checks: any[] = (unwrapped as any).def?.checks ?? [];\n let maxLength: number | undefined;\n\n for (const check of checks) {\n const c = check._zod?.def ?? check.def ?? check;\n if (c.check === \"length_equals\" || c.check === \"size_equals\") {\n const len = c.length ?? c.size;\n if (typeof len === \"number\") maxLength = maxLength === undefined ? len : Math.min(maxLength, len);\n }\n if (c.check === \"max_length\" || c.check === \"max_size\") {\n const len = c.maximum ?? c.max;\n if (typeof len === \"number\") maxLength = maxLength === undefined ? len : Math.min(maxLength, len);\n }\n }\n\n return maxLength;\n}\n\nfunction isOptional(field: unknown): boolean {\n return (\n field instanceof z.ZodOptional ||\n field instanceof z.ZodNullable\n );\n}\n\nfunction escapeSQLString(s: string): string {\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction getDefaultFromZod(field: unknown): string | undefined {\n if (!(field instanceof z.ZodDefault)) return undefined;\n\n try {\n const f = field as any;\n let value = f.defaultValue;\n if (value === undefined) value = f.def?.defaultValue;\n if (typeof value === \"function\") value = value();\n\n if (value === undefined) return undefined;\n if (value === null) return \"NULL\";\n if (typeof value === \"string\") return escapeSQLString(value);\n if (typeof value === \"number\") return value.toString();\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (typeof value === \"bigint\") return value.toString();\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nconst VARCHAR_MAX = 65535;\n\nfunction jsonType(dialect: SqlDialect): string {\n return dialect === \"mysql\" ? \"JSON\" : \"JSONB\";\n}\n\n// Maps a scalar (non-collection) Zod type to a native SQL column type.\n// Returns undefined for types that don't have a simple scalar mapping\n// (objects, records, nested arrays, unknown types), so callers can decide\n// how to fall back. `field` is the original (possibly wrapped) node used to\n// read length constraints; `unwrapped` is the underlying scalar type.\nfunction getScalarSqlType(unwrapped: unknown, field: unknown, dialect: SqlDialect): string | undefined {\n if (unwrapped instanceof z.ZodString) {\n const maxLen = getStringMaxLength(field);\n if (maxLen !== undefined && maxLen <= VARCHAR_MAX) return `VARCHAR(${maxLen})`;\n return \"TEXT\";\n }\n\n if (unwrapped instanceof z.ZodNumber) return \"BIGINT\";\n\n if (unwrapped instanceof z.ZodBoolean) {\n return dialect === \"mysql\" ? \"TINYINT(1)\" : \"BOOLEAN\";\n }\n\n if (unwrapped instanceof z.ZodDate) {\n return dialect === \"mysql\" ? \"DATETIME(3)\" : \"TIMESTAMPTZ\";\n }\n\n if (unwrapped instanceof z.ZodBigInt) return \"BIGINT\";\n\n if (unwrapped instanceof z.ZodEnum) return \"TEXT\";\n\n return undefined;\n}\n\nfunction getArrayElement(arr: z.ZodArray): unknown {\n return arr.element ?? arr.def?.element ?? arr.def?.type;\n}\n\n// Resolves the SQL type for an array field. MySQL has no native array column\n// type, so arrays are stored as JSON. Postgres supports native arrays of\n// scalar types (e.g. TEXT[], BIGINT[]); arrays of objects/records or nested\n// arrays fall back to JSONB.\nfunction getArraySqlType(arr: z.ZodArray, dialect: SqlDialect): string {\n if (dialect === \"mysql\") return \"JSON\";\n\n const rawElement = getArrayElement(arr);\n const element = unwrapZodType(rawElement);\n\n // Honor an explicit SQL type declared on the element's meta.\n const elementMeta = getFieldMeta(rawElement);\n if (elementMeta) {\n if (typeof elementMeta.pgType === \"string\") return `${elementMeta.pgType}[]`;\n }\n\n const scalar = getScalarSqlType(element, rawElement, dialect);\n if (scalar !== undefined) return `${scalar}[]`;\n\n return \"JSONB\";\n}\n\nfunction getSqlType(field: unknown, dialect: SqlDialect): string {\n const meta = getFieldMeta(field);\n if (meta) {\n const dialectKey = dialect === \"mysql\" ? \"mysqlType\" : \"pgType\";\n if (typeof meta[dialectKey] === \"string\") return meta[dialectKey] as string;\n }\n\n const unwrapped = unwrapZodType(field);\n\n if (unwrapped instanceof z.ZodArray) {\n return getArraySqlType(unwrapped, dialect);\n }\n\n if (unwrapped instanceof z.ZodObject || unwrapped instanceof z.ZodRecord) {\n return jsonType(dialect);\n }\n\n return getScalarSqlType(unwrapped, field, dialect) ?? \"TEXT\";\n}\n\nfunction isPrimaryKey(field: unknown): boolean {\n const meta = getFieldMeta(field);\n return meta?.primaryKey === true;\n}\n\nfunction getDefaultValue(field: unknown): string | undefined {\n const meta = getFieldMeta(field);\n if (meta && typeof meta.defaultValue === \"string\") {\n return meta.defaultValue;\n }\n\n return getDefaultFromZod(field);\n}\n\nexport interface SchemaToCreateTableOptions {\n dialect?: SqlDialect;\n ifNotExists?: boolean;\n}\n\nexport function schemaToCreateTable(\n schema: SchemaDefinition<string, any, any>,\n options?: SchemaToCreateTableOptions,\n): string {\n const dialect = options?.dialect ?? \"postgres\";\n const ifNotExists = options?.ifNotExists ?? true;\n\n const tableName = schema.table;\n const shape = schema.schema.shape;\n const columns: Record<string, string> = schema.columns;\n\n const userKeys = Object.keys(shape).filter(k => k !== \"id\" && k !== \"commitTs\");\n const orderedKeys = [\"id\", ...userKeys, \"commitTs\"];\n\n const lines: string[] = [];\n\n for (const fieldName of orderedKeys) {\n const field = shape[fieldName];\n if (!field) continue;\n\n const colName = columns[fieldName] ?? fieldName;\n if (!colName) continue;\n\n const sqlType = getSqlType(field, dialect);\n const notNull = !isOptional(field);\n const pk = isPrimaryKey(field);\n const defaultVal = fieldName === \"commitTs\" ? \"0\" : getDefaultValue(field);\n\n let line = ` ${colName} ${sqlType}`;\n if (notNull) line += \" NOT NULL\";\n if (pk) line += \" PRIMARY KEY\";\n if (defaultVal !== undefined) line += ` DEFAULT ${defaultVal}`;\n\n lines.push(line);\n }\n\n const ifNot = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n return `CREATE TABLE ${ifNot}${tableName} (\\n${lines.join(\",\\n\")}\\n);`;\n}\n\nexport function formatDeclarativeIndex(\n idx: DeclarativeIndex,\n tableName: string,\n columns: Record<string, string>,\n): string {\n const colNames = idx.columns.map(c => columns[c] ?? c).join(\", \");\n let sql = `CREATE ${idx.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${idx.name} ON ${tableName}`;\n if (idx.type) sql += ` USING ${idx.type}`;\n sql += ` (${colNames})`;\n if (idx.where) sql += ` WHERE ${idx.where}`;\n return sql + \";\";\n}\n\nexport interface SchemaIndexesOptions {\n /** Emit `IF NOT EXISTS` on the auto-generated commit_ts index. Default true. */\n ifNotExists?: boolean;\n}\n\nexport function schemaIndexes(\n schema: SchemaDefinition<string, any, any>,\n options?: SchemaIndexesOptions,\n): string[] {\n const out = (schema.indexes ?? []).map(idx => {\n if (typeof idx === \"string\") return idx;\n return formatDeclarativeIndex(idx, schema.table, schema.columns);\n });\n\n // Every table has a `commit_ts` column (OCC) that is otherwise unindexed.\n // Auto-add an index on it unless the user already declared one covering\n // the commit_ts field or one with the same generated name.\n const commitCol = schema.columns[\"commitTs\"] ?? \"commit_ts\";\n const autoName = `${schema.table}_commit_ts_idx`;\n const alreadyDeclared = (schema.indexes ?? []).some(idx => {\n if (typeof idx === \"string\") return idx.includes(autoName);\n if (idx.name === autoName) return true;\n return idx.columns.length === 1 &&\n (idx.columns[0] === \"commitTs\" || idx.columns[0] === commitCol);\n });\n if (!alreadyDeclared) {\n const ifNot = (options?.ifNotExists ?? true) ? \"IF NOT EXISTS \" : \"\";\n out.push(`CREATE INDEX ${ifNot}${autoName} ON ${schema.table} (${commitCol});`);\n }\n\n return out;\n}\n\nexport interface GenerateSchemaSqlOptions {\n dialect?: SqlDialect;\n ifNotExists?: boolean;\n header?: boolean;\n /**\n * Prepend the framework-owned core tables (`commit_logs`, `metadata`) and\n * their indexes so the generated SQL fully describes the database. Default\n * true. Non-table core bootstrap (sequences, seed rows) is handled at\n * runtime by `initCore`, not emitted here.\n */\n includeCoreTables?: boolean;\n}\n\nexport function generateSchemaSql(\n schemas?: Map<string, SchemaDefinition<string, any, any>> | SchemaDefinition<string, any, any>[],\n options?: GenerateSchemaSqlOptions,\n): string {\n const dialect = options?.dialect ?? \"postgres\";\n const header = options?.header ?? true;\n const includeCoreTables = options?.includeCoreTables ?? true;\n\n let list: SchemaDefinition<string, any, any>[];\n\n if (schemas instanceof Map) {\n list = [...schemas.values()];\n } else if (Array.isArray(schemas)) {\n list = schemas;\n } else {\n list = [...schemaRegistry.values()];\n }\n\n list = list.filter(s => s?.table);\n list.sort((a, b) => a.table.localeCompare(b.table));\n\n const parts: string[] = [];\n\n if (header) {\n parts.push(\"-- Generated by Supalive Schema Generator\");\n parts.push(`-- Dialect: ${dialect}`);\n parts.push(`-- Tables: ${list.length}${includeCoreTables ? \" (+ core)\" : \"\"}`);\n parts.push(\"\");\n }\n\n if (includeCoreTables) {\n parts.push(\"-- Core tables (framework-owned)\");\n for (const stmt of coreTablesSql(dialect, { ifNotExists: options?.ifNotExists })) {\n parts.push(stmt);\n }\n parts.push(\"\");\n }\n\n for (const schema of list) {\n parts.push(schemaToCreateTable(schema, { ...options, dialect }));\n const indexStmts = schemaIndexes(schema, { ifNotExists: options?.ifNotExists });\n for (const stmt of indexStmts) {\n parts.push(stmt);\n }\n parts.push(\"\");\n }\n\n return parts.join(\"\\n\");\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { An as CacheLayer, Bn as UnregisterSubscriptionResult, E as Context, Fn as RegisterSubscriptionParams, Gn as UpdateSubscriptionReadSetResult, Hn as UnregisterSubscriptionsResult, In as RegisterSubscriptionParamsSchema, Ln as RegisterSubscriptionResult, Mn as InvalidateWritesetParams, Nn as InvalidateWritesetParamsSchema, Pn as InvalidateWritesetResult, Rn as UnregisterSubscriptionParams, Un as UpdateSubscriptionReadSetParams, Vn as UnregisterSubscriptionsParams, Wn as UpdateSubscriptionReadSetParamsSchema, jn as AffectedSubscription, nt as Router, wt as SupaliveDb, zn as UnregisterSubscriptionParamsSchema } from "../../index-DouKwYL6.js";
2
- import { t as MySqlDatabase } from "../../mysql-Bxurg_PH.js";
3
- import { t as PgDatabase } from "../../postgres-CfT_aDx3.js";
4
- import { _ as UpstashConfig, f as DatabaseConfig, g as SupaliveServerConfig, h as SubscriptionManagerConfig, u as SubId } from "../../types_server-BW1ys_SK.js";
1
+ import { At as SupaliveDb, Bn as InvalidateWritesetParamsSchema, E as Context, Gn as UnregisterSubscriptionParams, Hn as RegisterSubscriptionParams, Jn as UnregisterSubscriptionsParams, Kn as UnregisterSubscriptionParamsSchema, Ln as CacheLayer, On as Database, Qn as UpdateSubscriptionReadSetResult, Rn as AffectedSubscription, Un as RegisterSubscriptionParamsSchema, Vn as InvalidateWritesetResult, Wn as RegisterSubscriptionResult, Xn as UpdateSubscriptionReadSetParams, Yn as UnregisterSubscriptionsResult, Zn as UpdateSubscriptionReadSetParamsSchema, qn as UnregisterSubscriptionResult, rt as Router, zn as InvalidateWritesetParams } from "../../index-E1_1iRI1.js";
2
+ import { t as MySqlDatabase } from "../../mysql-BmkLy5oY.js";
3
+ import { t as PgDatabase } from "../../postgres-v2ctNE6o.js";
4
+ import { A as ScheduledJobDef, C as EnqueueOptions, D as QStashScheduler, E as JobScheduler, O as QStashSchedulerOptions, S as DevSchedulerOptions, T as JobClient, b as UpstashConfig, f as DatabaseConfig, k as ScheduleHandle, u as SubId, v as SubscriptionManagerConfig, w as IncomingJobRequest, x as DevScheduler, y as SupaliveServerConfig } from "../../types_server-CzAufcee.js";
5
5
  import pino, { Level } from "pino";
6
6
  import Redis$1 from "ioredis";
7
7
 
@@ -19,6 +19,12 @@ declare class SupaliveWebSocketServer<TContext extends Context> {
19
19
  private db;
20
20
  private contextRegistry;
21
21
  private router?;
22
+ private retentionWatermark;
23
+ private oneShotDeps;
24
+ private scheduler?;
25
+ private jobPath;
26
+ private jobClient?;
27
+ private rpcHandler?;
22
28
  private sessions;
23
29
  private serverSubscriptions;
24
30
  private subManagerClient;
@@ -40,6 +46,28 @@ declare class SupaliveWebSocketServer<TContext extends Context> {
40
46
  private clearSessionTimers;
41
47
  registerRouter(router: Router<any, TContext>): void;
42
48
  start(): Promise<void>;
49
+ /**
50
+ * Reconcile every registered recurring (cron) job with the scheduler. Safe
51
+ * to call more than once. No-op when no scheduler is configured or the router
52
+ * declares no cron jobs. Runs after the HTTP listener is up so the endpoints
53
+ * the scheduler registers are already reachable.
54
+ */
55
+ private syncJobSchedules;
56
+ /** Absolute URL the scheduler POSTs to for a given job name. */
57
+ endpointFor(name: string): string;
58
+ /**
59
+ * Enqueue a precise, one-shot run of a job (e.g. "expire this record at
60
+ * exactly `expiresAt`"). Returns a handle whose `id` can be passed to
61
+ * {@link cancelJob}. Requires a configured scheduler.
62
+ */
63
+ scheduleJob(name: string, body: unknown, opts?: EnqueueOptions): Promise<ScheduleHandle>;
64
+ /** Cancel a one-shot previously created by {@link scheduleJob}. */
65
+ cancelJob(handleId: string): Promise<void>;
66
+ /**
67
+ * The app-facing {@link JobClient} — hand it to your service layer so
68
+ * procedures can schedule/cancel one-shots without reaching for the server.
69
+ */
70
+ getJobClient(): JobClient | undefined;
43
71
  stop(): Promise<void>;
44
72
  getStats(): {
45
73
  instanceId: string;
@@ -48,6 +76,12 @@ declare class SupaliveWebSocketServer<TContext extends Context> {
48
76
  activeSubscriptions: number;
49
77
  };
50
78
  getInstanceId(): string;
79
+ /**
80
+ * Plain-HTTP entrypoint (non-WS). Serves a liveness probe and the job
81
+ * webhook: `POST {jobPath}/<jobName>`. Every job POST is authenticated by the
82
+ * configured scheduler before the (server-only) job handler runs.
83
+ */
84
+ private handleHttpRequest;
51
85
  private setupWebSocketHandlers;
52
86
  private handleConnection;
53
87
  private handleMessage;
@@ -113,18 +147,6 @@ declare class SupaliveWebSocketServer<TContext extends Context> {
113
147
  private publishRecomputeRace;
114
148
  private reexecuteAffectedQuery;
115
149
  private executeLiveQuery;
116
- /**
117
- * Resolve the segmentation key used in the subId/cacheKey hash for a
118
- * query subscription. Priority:
119
- *
120
- * 1. Procedure-level `queryIdentity` override:
121
- * - `false` → identity = `ANONYMOUS_IDENTITY` (cache shared across users)
122
- * - `string` → that literal
123
- * - `function` → ctx + input → string | null | undefined
124
- * 2. `config.getUserId(serverCtx)` → falls back to ANONYMOUS_IDENTITY if it
125
- * returns null/undefined or isn't configured.
126
- */
127
- private resolveQueryIdentity;
128
150
  private sendMessage;
129
151
  private sendMessageRaw;
130
152
  private sendError;
@@ -173,6 +195,10 @@ declare class SubscriptionManager {
173
195
  start(): Promise<void>;
174
196
  stop(): Promise<void>;
175
197
  private pruneCommitLogs;
198
+ /** Fan a watermark value out to every worker's in-memory copy. Worker 0 (the
199
+ * pruner/seeder) already has it, but re-sending is harmless — {@link
200
+ * SubscriptionWorker.setRetentionWatermark} is monotonic. */
201
+ private broadcastRetentionWatermark;
176
202
  workerCount(): number;
177
203
  workerIndexFor(subId: string): number;
178
204
  private workerFor;
@@ -303,6 +329,27 @@ declare class SubManagerClient {
303
329
  }
304
330
  //#endregion
305
331
  //#region src/db/init_db.d.ts
332
+ /**
333
+ * Current core schema version. Bump this whenever core needs a new non-table
334
+ * database operation (a sequence, a seed row, a backfill). Each increment adds
335
+ * a case to `Database.coreMigrationStatements` for that version step.
336
+ *
337
+ * The core *tables* (commit_logs, metadata) are NOT versioned here — they come
338
+ * from the generated schema (`coreTablesSql` / `generateSchemaSql`) which must
339
+ * be applied to the database BEFORE `initCore` runs.
340
+ */
341
+ declare const CORE_VERSION = 1n;
342
+ /**
343
+ * Bring the core, non-table database state up to {@link CORE_VERSION}. Idempotent
344
+ * and safe to call from every process at startup: a lock-free version read
345
+ * short-circuits the common "already current" case, and the actual migration
346
+ * runs under a cross-process lock with a re-check so only one process applies
347
+ * it.
348
+ *
349
+ * Assumes the core tables already exist (apply the generated schema first);
350
+ * the `metadata` table is where the version and seed rows live.
351
+ */
352
+ declare function initCore(db: Database): Promise<void>;
306
353
  /**
307
354
  * Default and env override for the per-statement DB timeout. PG enforces
308
355
  * this via `statement_timeout` (server cancels), MySQL via the per-query
@@ -365,5 +412,5 @@ declare function generateSubscriptionId(procedure: string, input: unknown | stri
365
412
  */
366
413
  declare function generateCacheKey(queryName: string, input: unknown | string, queryIdentity: string): Promise<string>;
367
414
  //#endregion
368
- export { ANONYMOUS_IDENTITY, type AffectedSubscription, CacheLayer, DB_QUERY_TIMEOUT_MS, InitCacheLayerOptions, InitDbOptions, type InvalidateWritesetParams, InvalidateWritesetParamsSchema, type InvalidateWritesetResult, type RegisterSubscriptionParams, RegisterSubscriptionParamsSchema, type RegisterSubscriptionResult, type SubId, SubManagerClient, SubscriptionManager, SupaliveWebSocketServer, type UnregisterSubscriptionParams, UnregisterSubscriptionParamsSchema, type UnregisterSubscriptionResult, type UpdateSubscriptionReadSetParams, UpdateSubscriptionReadSetParamsSchema, type UpdateSubscriptionReadSetResult, appInstanceId, bootstrapDbTypes, createDatabase, generateCacheKey, generateSubscriptionId, getHashOf, initCacheLayer, initDatabase, isProduction, logLevelOf, logger, serializeMapValue };
415
+ export { ANONYMOUS_IDENTITY, type AffectedSubscription, CORE_VERSION, CacheLayer, DB_QUERY_TIMEOUT_MS, DevScheduler, type DevSchedulerOptions, type EnqueueOptions, type IncomingJobRequest, InitCacheLayerOptions, InitDbOptions, type InvalidateWritesetParams, InvalidateWritesetParamsSchema, type InvalidateWritesetResult, JobClient, type JobScheduler, QStashScheduler, type QStashSchedulerOptions, type RegisterSubscriptionParams, RegisterSubscriptionParamsSchema, type RegisterSubscriptionResult, type ScheduleHandle, type ScheduledJobDef, type SubId, SubManagerClient, SubscriptionManager, SupaliveWebSocketServer, type UnregisterSubscriptionParams, UnregisterSubscriptionParamsSchema, type UnregisterSubscriptionResult, type UpdateSubscriptionReadSetParams, UpdateSubscriptionReadSetParamsSchema, type UpdateSubscriptionReadSetResult, appInstanceId, bootstrapDbTypes, createDatabase, generateCacheKey, generateSubscriptionId, getHashOf, initCacheLayer, initCore, initDatabase, isProduction, logLevelOf, logger, serializeMapValue };
369
416
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../../../src/server/supalive-server.ts","../../../src/logger.ts","../../../src/server/subscription-manager.ts","../../../src/server/subscription-manager-client.ts","../../../src/db/init_db.ts","../../../src/server/sub_hash.ts"],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../../../src/server/supalive-server.ts","../../../src/logger.ts","../../../src/server/subscription-manager.ts","../../../src/server/subscription-manager-client.ts","../../../src/db/init_db.ts","../../../src/server/sub_hash.ts"],"mappings":"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"}