easy-ping 0.4.0 → 0.6.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 (140) hide show
  1. package/README.md +548 -427
  2. package/dist/adapter-B7R4rXtJ.d.cts +17 -0
  3. package/dist/adapter-B7R4rXtJ.d.ts +17 -0
  4. package/dist/{adapter-BfLe2J0t.d.cts → adapter-D3lTy-4E.d.cts} +6 -32
  5. package/dist/{adapter-BfLe2J0t.d.ts → adapter-D3lTy-4E.d.ts} +6 -32
  6. package/dist/adapters/drizzle.cjs +1 -2
  7. package/dist/adapters/drizzle.cjs.map +1 -1
  8. package/dist/adapters/drizzle.d.cts +1 -1
  9. package/dist/adapters/drizzle.d.ts +1 -1
  10. package/dist/adapters/drizzle.js +3 -4
  11. package/dist/adapters/drizzle.js.map +1 -1
  12. package/dist/adapters/mongodb.cjs +144 -5
  13. package/dist/adapters/mongodb.cjs.map +1 -1
  14. package/dist/adapters/mongodb.d.cts +43 -18
  15. package/dist/adapters/mongodb.d.ts +43 -18
  16. package/dist/adapters/mongodb.js +77 -8
  17. package/dist/adapters/mongodb.js.map +1 -1
  18. package/dist/adapters/mysql.cjs +605 -0
  19. package/dist/adapters/mysql.cjs.map +1 -0
  20. package/dist/adapters/mysql.d.cts +38 -0
  21. package/dist/adapters/mysql.d.ts +38 -0
  22. package/dist/adapters/mysql.js +51 -0
  23. package/dist/adapters/mysql.js.map +1 -0
  24. package/dist/adapters/postgres.cjs +162 -9
  25. package/dist/adapters/postgres.cjs.map +1 -1
  26. package/dist/adapters/postgres.d.cts +44 -54
  27. package/dist/adapters/postgres.d.ts +44 -54
  28. package/dist/adapters/postgres.js +82 -42
  29. package/dist/adapters/postgres.js.map +1 -1
  30. package/dist/adapters/sqlite.cjs +593 -0
  31. package/dist/adapters/sqlite.cjs.map +1 -0
  32. package/dist/adapters/sqlite.d.cts +37 -0
  33. package/dist/adapters/sqlite.d.ts +37 -0
  34. package/dist/adapters/sqlite.js +53 -0
  35. package/dist/adapters/sqlite.js.map +1 -0
  36. package/dist/browser.cjs.map +1 -1
  37. package/dist/browser.d.cts +2 -14
  38. package/dist/browser.d.ts +2 -14
  39. package/dist/browser.js.map +1 -1
  40. package/dist/chunk-2EYKPF5A.js +393 -0
  41. package/dist/chunk-2EYKPF5A.js.map +1 -0
  42. package/dist/{chunk-3Y2MBUAW.js → chunk-3VOQOGDR.js} +4 -3
  43. package/dist/chunk-3VOQOGDR.js.map +1 -0
  44. package/dist/{chunk-PSJHXZPR.js → chunk-AEYYTE5I.js} +2 -2
  45. package/dist/chunk-AEYYTE5I.js.map +1 -0
  46. package/dist/chunk-CK5UPVYP.js +48 -0
  47. package/dist/chunk-CK5UPVYP.js.map +1 -0
  48. package/dist/{chunk-W6I3B2CI.js → chunk-E4IZ2CQC.js} +2 -2
  49. package/dist/{chunk-W6I3B2CI.js.map → chunk-E4IZ2CQC.js.map} +1 -1
  50. package/dist/chunk-HY47TQMY.js +52 -0
  51. package/dist/chunk-HY47TQMY.js.map +1 -0
  52. package/dist/{chunk-CYKAM7LE.js → chunk-JKTMUMQK.js} +31 -6
  53. package/dist/chunk-JKTMUMQK.js.map +1 -0
  54. package/dist/chunk-M4R77BJD.js +64 -0
  55. package/dist/chunk-M4R77BJD.js.map +1 -0
  56. package/dist/chunk-ORZKH224.js +75 -0
  57. package/dist/chunk-ORZKH224.js.map +1 -0
  58. package/dist/{chunk-DG3ZL5NP.js → chunk-USQ6CQTJ.js} +88 -3
  59. package/dist/chunk-USQ6CQTJ.js.map +1 -0
  60. package/dist/{chunk-YEMRRMJQ.js → chunk-XIDVLYNQ.js} +14 -4
  61. package/dist/chunk-XIDVLYNQ.js.map +1 -0
  62. package/dist/client.cjs +288 -17
  63. package/dist/client.cjs.map +1 -1
  64. package/dist/client.d.cts +53 -1
  65. package/dist/client.d.ts +53 -1
  66. package/dist/client.js +288 -17
  67. package/dist/client.js.map +1 -1
  68. package/dist/index.cjs +239 -9
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.d.cts +53 -57
  71. package/dist/index.d.ts +53 -57
  72. package/dist/index.js +60 -13
  73. package/dist/index.js.map +1 -1
  74. package/dist/node.cjs +26 -5
  75. package/dist/node.cjs.map +1 -1
  76. package/dist/node.d.cts +1 -1
  77. package/dist/node.d.ts +1 -1
  78. package/dist/node.js +28 -6
  79. package/dist/node.js.map +1 -1
  80. package/dist/{plugin-C9Hoxus2.d.ts → plugin-CHd2ZiGC.d.cts} +5 -21
  81. package/dist/{plugin-CiMsGlQe.d.cts → plugin-Cg9usuUi.d.ts} +5 -21
  82. package/dist/plugins/digests.cjs +1 -4
  83. package/dist/plugins/digests.cjs.map +1 -1
  84. package/dist/plugins/digests.d.cts +6 -31
  85. package/dist/plugins/digests.d.ts +6 -31
  86. package/dist/plugins/digests.js +1 -4
  87. package/dist/plugins/digests.js.map +1 -1
  88. package/dist/plugins/preferences-client.cjs.map +1 -1
  89. package/dist/plugins/preferences-client.d.cts +2 -2
  90. package/dist/plugins/preferences-client.d.ts +2 -2
  91. package/dist/plugins/preferences-client.js +1 -1
  92. package/dist/plugins/preferences-react.cjs.map +1 -1
  93. package/dist/plugins/preferences-react.js.map +1 -1
  94. package/dist/plugins/preferences.cjs +1 -2
  95. package/dist/plugins/preferences.cjs.map +1 -1
  96. package/dist/plugins/preferences.d.cts +2 -2
  97. package/dist/plugins/preferences.d.ts +2 -2
  98. package/dist/plugins/preferences.js +3 -3
  99. package/dist/plugins/preferences.js.map +1 -1
  100. package/dist/plugins/push.cjs +1 -2
  101. package/dist/plugins/push.cjs.map +1 -1
  102. package/dist/plugins/push.d.cts +6 -26
  103. package/dist/plugins/push.d.ts +6 -26
  104. package/dist/plugins/push.js +4 -4
  105. package/dist/plugins/push.js.map +1 -1
  106. package/dist/providers/web-push.cjs.map +1 -1
  107. package/dist/providers/web-push.d.cts +3 -10
  108. package/dist/providers/web-push.d.ts +3 -10
  109. package/dist/providers/web-push.js.map +1 -1
  110. package/dist/react.cjs +311 -19
  111. package/dist/react.cjs.map +1 -1
  112. package/dist/react.d.cts +53 -4
  113. package/dist/react.d.ts +53 -4
  114. package/dist/react.js +311 -19
  115. package/dist/react.js.map +1 -1
  116. package/dist/schema.cjs +119 -1
  117. package/dist/schema.cjs.map +1 -1
  118. package/dist/schema.d.cts +20 -14
  119. package/dist/schema.d.ts +20 -14
  120. package/dist/schema.js +4 -2
  121. package/dist/signals-kPmOlKDX.d.cts +27 -0
  122. package/dist/signals-kPmOlKDX.d.ts +27 -0
  123. package/dist/sw.cjs +39 -0
  124. package/dist/sw.cjs.map +1 -0
  125. package/dist/sw.d.cts +52 -0
  126. package/dist/sw.d.ts +52 -0
  127. package/dist/sw.js +36 -0
  128. package/dist/sw.js.map +1 -0
  129. package/dist/testing.cjs +3 -19
  130. package/dist/testing.cjs.map +1 -1
  131. package/dist/testing.d.cts +4 -22
  132. package/dist/testing.d.ts +4 -22
  133. package/dist/testing.js +3 -19
  134. package/dist/testing.js.map +1 -1
  135. package/package.json +17 -1
  136. package/dist/chunk-3Y2MBUAW.js.map +0 -1
  137. package/dist/chunk-CYKAM7LE.js.map +0 -1
  138. package/dist/chunk-DG3ZL5NP.js.map +0 -1
  139. package/dist/chunk-PSJHXZPR.js.map +0 -1
  140. package/dist/chunk-YEMRRMJQ.js.map +0 -1
package/dist/schema.cjs CHANGED
@@ -125,6 +125,15 @@ var defaultClause2 = (field) => {
125
125
  return ` DEFAULT ${field.default}`;
126
126
  };
127
127
  var indexName = (table, declaration) => declaration.name ?? `${table.tableName}_${declaration.on.join("_")}_idx`;
128
+ function normaliseColumn(row) {
129
+ if ("table" in row) return row;
130
+ return {
131
+ table: String(row.table_name),
132
+ column: String(row.column_name),
133
+ type: String(row.data_type),
134
+ nullable: typeof row.is_nullable === "boolean" ? row.is_nullable : row.is_nullable === "YES"
135
+ };
136
+ }
128
137
  var INTROSPECT_SQL = `
129
138
  SELECT table_name, column_name, data_type, is_nullable
130
139
  FROM information_schema.columns
@@ -133,7 +142,8 @@ var INTROSPECT_SQL = `
133
142
  async function planPostgresMigration(introspect, schema, prefix = "") {
134
143
  const live = await introspect();
135
144
  const byTable = /* @__PURE__ */ new Map();
136
- for (const column of live) {
145
+ for (const row of live) {
146
+ const column = normaliseColumn(row);
137
147
  const columns = byTable.get(column.table) ?? /* @__PURE__ */ new Map();
138
148
  columns.set(column.column, column);
139
149
  byTable.set(column.table, columns);
@@ -254,11 +264,119 @@ ${body}
254
264
  `;
255
265
  }
256
266
 
267
+ // src/schema/render-mysql.ts
268
+ var quote3 = (value) => `\`${value.split("`").join("``")}\``;
269
+ function stringType(field, table, spec) {
270
+ const keys = [
271
+ ...table.primaryKey ? [table.primaryKey] : [],
272
+ ...(table.indexes ?? []).map((index) => index.on)
273
+ ].filter((columns) => columns.includes(field));
274
+ if (keys.some((columns) => columns.length > 1)) return "VARCHAR(255)";
275
+ if (keys.length > 0) return "VARCHAR(768)";
276
+ if (spec.default !== void 0) return "VARCHAR(255)";
277
+ return "TEXT";
278
+ }
279
+ function columnType(field, table, spec) {
280
+ switch (spec.type) {
281
+ case "string":
282
+ return stringType(field, table, spec);
283
+ case "number":
284
+ return "INT";
285
+ case "boolean":
286
+ return "TINYINT(1)";
287
+ case "date":
288
+ return "DATETIME(3)";
289
+ case "json":
290
+ return "JSON";
291
+ }
292
+ }
293
+ var defaultClause3 = (spec) => {
294
+ if (spec.defaultNow) return " DEFAULT CURRENT_TIMESTAMP(3)";
295
+ if (spec.default === void 0) return "";
296
+ if (typeof spec.default === "string") return ` DEFAULT '${spec.default.replace(/'/g, "''")}'`;
297
+ if (typeof spec.default === "boolean") return ` DEFAULT ${spec.default ? 1 : 0}`;
298
+ return ` DEFAULT ${spec.default}`;
299
+ };
300
+ function renderMysqlDdl(schema, prefix = "") {
301
+ const statements = [];
302
+ for (const table of Object.values(schema)) {
303
+ const lines = Object.entries(table.fields).map(([field, spec]) => {
304
+ const nullability = spec.required ? " NOT NULL" : "";
305
+ return ` ${quote3(toSnakeCase(field))} ${columnType(field, table, spec)}${nullability}${defaultClause3(spec)}`;
306
+ });
307
+ if (table.primaryKey?.length) {
308
+ lines.push(
309
+ ` PRIMARY KEY (${table.primaryKey.map((f) => quote3(toSnakeCase(f))).join(", ")})`
310
+ );
311
+ }
312
+ for (const index of table.indexes ?? []) {
313
+ const name = quote3(prefix + (index.name ?? `${table.tableName}_${index.on.join("_")}_idx`));
314
+ const columns = index.on.map((f) => quote3(toSnakeCase(f))).join(", ");
315
+ lines.push(` ${index.unique ? "UNIQUE " : ""}INDEX ${name} (${columns})`);
316
+ }
317
+ statements.push(
318
+ `CREATE TABLE IF NOT EXISTS ${quote3(prefix + table.tableName)} (
319
+ ${lines.join(",\n")}
320
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`
321
+ );
322
+ }
323
+ return statements;
324
+ }
325
+
326
+ // src/schema/render-sqlite.ts
327
+ var SQL_TYPE3 = {
328
+ string: "TEXT",
329
+ number: "INTEGER",
330
+ boolean: "INTEGER",
331
+ // ISO-8601 with milliseconds and a trailing Z, the same 24 characters
332
+ // `Date#toISOString` writes, so `<=` on the text is `<=` on the instant.
333
+ date: "TEXT",
334
+ json: "TEXT"
335
+ };
336
+ var quote4 = (value) => `"${value.split('"').join('""')}"`;
337
+ var defaultClause4 = (spec) => {
338
+ if (spec.defaultNow) return " DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))";
339
+ if (spec.default === void 0) return "";
340
+ if (typeof spec.default === "string") return ` DEFAULT '${spec.default.replace(/'/g, "''")}'`;
341
+ if (typeof spec.default === "boolean") return ` DEFAULT ${spec.default ? 1 : 0}`;
342
+ return ` DEFAULT ${spec.default}`;
343
+ };
344
+ function renderSqliteDdl(schema, prefix = "") {
345
+ const statements = [];
346
+ for (const table of Object.values(schema)) {
347
+ const name = quote4(prefix + table.tableName);
348
+ const columns = Object.entries(table.fields).map(([field, spec]) => {
349
+ const nullability = spec.required ? " NOT NULL" : "";
350
+ return ` ${quote4(toSnakeCase(field))} ${SQL_TYPE3[spec.type]}${nullability}${defaultClause4(spec)}`;
351
+ });
352
+ if (table.primaryKey?.length) {
353
+ columns.push(
354
+ ` PRIMARY KEY (${table.primaryKey.map((f) => quote4(toSnakeCase(f))).join(", ")})`
355
+ );
356
+ }
357
+ statements.push(`CREATE TABLE IF NOT EXISTS ${name} (
358
+ ${columns.join(",\n")}
359
+ )`);
360
+ for (const index of table.indexes ?? []) {
361
+ const indexName2 = quote4(
362
+ prefix + (index.name ?? `${table.tableName}_${index.on.join("_")}_idx`)
363
+ );
364
+ const cols = index.on.map((f) => quote4(toSnakeCase(f))).join(", ");
365
+ statements.push(
366
+ `CREATE ${index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${indexName2} ON ${name} (${cols})`
367
+ );
368
+ }
369
+ }
370
+ return statements;
371
+ }
372
+
257
373
  exports.INTROSPECT_SQL = INTROSPECT_SQL;
258
374
  exports.coreSchema = coreSchema;
259
375
  exports.planPostgresMigration = planPostgresMigration;
260
376
  exports.renderDrizzleSchema = renderDrizzleSchema;
377
+ exports.renderMysqlDdl = renderMysqlDdl;
261
378
  exports.renderPostgresDdl = renderPostgresDdl;
379
+ exports.renderSqliteDdl = renderSqliteDdl;
262
380
  exports.toSnakeCase = toSnakeCase;
263
381
  //# sourceMappingURL=schema.cjs.map
264
382
  //# sourceMappingURL=schema.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema/declaration.ts","../src/schema/render-sql.ts","../src/schema/migrate-sql.ts","../src/schema/render-drizzle.ts"],"names":["indexName","columns","SQL_TYPE","quote","defaultClause"],"mappings":"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","file":"schema.cjs","sourcesContent":["import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/**\n * Core tables in the format plugins use. Less expressive than the hand-written\n * Drizzle schema (no partial indexes, ordering or cascade) — a drift test\n * asserts the two agree on the fields they share.\n */\nexport const coreSchema = {\n notification: {\n tableName: \"notification\",\n fields: {\n id: { type: \"string\", required: true },\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n payload: { type: \"json\", required: true },\n actorId: { type: \"string\" },\n groupKey: { type: \"string\" },\n dedupeKey: { type: \"string\" },\n seenAt: { type: \"date\" },\n readAt: { type: \"date\" },\n archivedAt: { type: \"date\" },\n createdAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"userId\", \"createdAt\"], name: \"notification_feed_idx\" },\n { on: [\"userId\", \"groupKey\"], name: \"notification_group_idx\" },\n { on: [\"userId\", \"dedupeKey\"], unique: true, name: \"notification_dedupe_idx\" },\n ],\n },\n\n notificationDelivery: {\n tableName: \"notification_delivery\",\n fields: {\n id: { type: \"string\", required: true },\n notificationId: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n status: { type: \"string\", required: true, default: \"pending\" },\n attempts: { type: \"number\", required: true, default: 0 },\n maxAttempts: { type: \"number\", required: true, default: 5 },\n notBefore: { type: \"date\", required: true, defaultNow: true },\n claimedAt: { type: \"date\" },\n claimedBy: { type: \"string\" },\n lastError: { type: \"string\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"status\", \"notBefore\"], name: \"delivery_claim_idx\" },\n { on: [\"notificationId\"], name: \"delivery_notification_idx\" },\n ],\n },\n\n notificationPreference: {\n tableName: \"notification_preference\",\n fields: {\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n enabled: { type: \"boolean\", required: true, default: true },\n frequency: { type: \"string\", required: true, default: \"instant\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import type { FieldDeclaration, SchemaDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamptz\",\n json: \"jsonb\",\n};\n\nconst quote = (value: string) => `\"${value.replace(/\"/g, '\"\"')}\"`;\n\nconst defaultClause = (field: FieldDeclaration): string => {\n if (field.defaultNow) return \" DEFAULT now()\";\n if (field.default === undefined) return \"\";\n if (typeof field.default === \"string\") return ` DEFAULT '${field.default.replace(/'/g, \"''\")}'`;\n return ` DEFAULT ${field.default}`;\n};\n\n/** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */\nexport function renderPostgresDdl(schema: SchemaDeclaration, prefix = \"\"): string[] {\n const statements: string[] = [];\n\n for (const table of Object.values(schema)) {\n const name = quote(prefix + table.tableName);\n\n const columns = Object.entries(table.fields).map(([field, spec]) => {\n const nullability = spec.required ? \" NOT NULL\" : \"\";\n return ` ${quote(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;\n });\n\n if (table.primaryKey?.length) {\n const key = table.primaryKey.map((field) => quote(toSnakeCase(field))).join(\", \");\n columns.push(` PRIMARY KEY (${key})`);\n }\n\n statements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n${columns.join(\",\\n\")}\\n)`);\n\n for (const declaration of table.indexes ?? []) {\n const indexName = quote(\n prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n );\n const columns = declaration.on.map((field) => quote(toSnakeCase(field))).join(\", \");\n const unique = declaration.unique ? \"UNIQUE \" : \"\";\n statements.push(`CREATE ${unique}INDEX IF NOT EXISTS ${indexName} ON ${name} (${columns})`);\n }\n }\n\n return statements;\n}\n","import type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\nimport { renderPostgresDdl } from \"./render-sql\";\n\n/**\n * Introspects a live Postgres schema and emits only what is missing.\n *\n * renderPostgresDdl emits CREATE TABLE IF NOT EXISTS, which is correct exactly\n * once. On an existing database it is a silent no-op, so an adopter who\n * bootstrapped with raw SQL had no way to pick up a column a later version\n * added — their app broke at runtime with \"column does not exist\" instead.\n *\n * Additive only, on purpose. Dropping a column or changing a type is\n * destructive and context-dependent, so those are reported in `unsupported`\n * rather than guessed at.\n */\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamptz\",\n json: \"jsonb\",\n};\n\n/** What information_schema reports for each of our declared types. */\nconst LIVE_TYPE: Record<FieldDeclaration[\"type\"], readonly string[]> = {\n string: [\"text\", \"character varying\", \"character\"],\n number: [\"integer\", \"bigint\", \"smallint\"],\n boolean: [\"boolean\"],\n date: [\"timestamp with time zone\", \"timestamp without time zone\"],\n json: [\"jsonb\", \"json\"],\n};\n\nconst quote = (value: string) => `\"${value.replace(/\"/g, '\"\"')}\"`;\n\nconst defaultClause = (field: FieldDeclaration): string => {\n if (field.defaultNow) return \" DEFAULT now()\";\n if (field.default === undefined) return \"\";\n if (typeof field.default === \"string\") return ` DEFAULT '${field.default.replace(/'/g, \"''\")}'`;\n return ` DEFAULT ${field.default}`;\n};\n\nconst indexName = (\n table: TableDeclaration,\n declaration: { on: readonly string[]; name?: string },\n) => declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`;\n\nexport type LiveColumn = { table: string; column: string; type: string; nullable: boolean };\n\nexport type MigrationPlan = {\n /** Run in order. Empty means the live schema already matches. */\n statements: readonly string[];\n /** Differences this cannot express safely. Read them; they need a human. */\n unsupported: readonly string[];\n /** Tables that do not exist yet — these get a full CREATE TABLE. */\n createdTables: readonly string[];\n};\n\n/**\n * Reads the live column list. Pass a function that runs the query — this\n * module stays driver-agnostic, as the rest of the schema tooling does.\n */\nexport type Introspector = () => Promise<readonly LiveColumn[]>;\n\n/** The query an Introspector should run. Exported so callers need not retype it. */\nexport const INTROSPECT_SQL = `\n SELECT table_name, column_name, data_type, is_nullable\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n`;\n\nexport async function planPostgresMigration(\n introspect: Introspector,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<MigrationPlan> {\n const live = await introspect();\n\n const byTable = new Map<string, Map<string, LiveColumn>>();\n for (const column of live) {\n const columns = byTable.get(column.table) ?? new Map<string, LiveColumn>();\n columns.set(column.column, column);\n byTable.set(column.table, columns);\n }\n\n const statements: string[] = [];\n const unsupported: string[] = [];\n const createdTables: string[] = [];\n\n for (const table of Object.values(schema)) {\n const qualified = prefix + table.tableName;\n const existing = byTable.get(qualified);\n\n // Absent entirely: the ordinary bootstrap path still applies.\n if (!existing || existing.size === 0) {\n createdTables.push(qualified);\n statements.push(...renderPostgresDdl({ [table.tableName]: table }, prefix));\n continue;\n }\n\n for (const [field, spec] of Object.entries(table.fields)) {\n const column = toSnakeCase(field);\n const found = existing.get(column);\n\n if (!found) {\n // NOT NULL on a populated table fails without a default, so a required\n // column that cannot fill itself is added nullable and flagged.\n const canFill = spec.defaultNow || spec.default !== undefined;\n const nullability = spec.required && canFill ? \" NOT NULL\" : \"\";\n\n statements.push(\n `ALTER TABLE ${quote(qualified)} ADD COLUMN IF NOT EXISTS ` +\n `${quote(column)} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`,\n );\n\n if (spec.required && !canFill) {\n unsupported.push(\n `${qualified}.${column} is declared required but has no default; ` +\n \"it was added nullable. Backfill it, then ALTER ... SET NOT NULL yourself.\",\n );\n }\n continue;\n }\n\n if (!LIVE_TYPE[spec.type].includes(found.type)) {\n unsupported.push(\n `${qualified}.${column} is ${found.type} but ${spec.type} is declared ` +\n `(${SQL_TYPE[spec.type]}). Changing a column type can lose data — do it yourself.`,\n );\n }\n }\n\n // Indexes are cheap and idempotent, so they are re-issued unconditionally.\n for (const declaration of table.indexes ?? []) {\n const name = quote(prefix + indexName(table, declaration));\n const columns = declaration.on.map((field) => quote(toSnakeCase(field))).join(\", \");\n statements.push(\n `CREATE ${declaration.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${name} ` +\n `ON ${quote(qualified)} (${columns})`,\n );\n }\n\n for (const column of existing.keys()) {\n const declared = Object.keys(table.fields).some((field) => toSnakeCase(field) === column);\n if (!declared) {\n unsupported.push(\n `${qualified}.${column} exists but is not declared. Left alone — ` +\n \"drop it yourself if it is ours and no longer needed.\",\n );\n }\n }\n }\n\n return { statements, unsupported, createdTables };\n}\n","import type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst COLUMN_BUILDER: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamp\",\n json: \"jsonb\",\n};\n\nconst literal = (value: string | number | boolean) =>\n typeof value === \"string\" ? JSON.stringify(value) : String(value);\n\nfunction renderColumn(name: string, field: FieldDeclaration, isSinglePk: boolean): string {\n const builder = COLUMN_BUILDER[field.type];\n const column = toSnakeCase(name);\n\n let expression =\n field.type === \"date\"\n ? `${builder}(${JSON.stringify(column)}, { withTimezone: true })`\n : `${builder}(${JSON.stringify(column)})`;\n\n if (isSinglePk) return ` ${name}: ${expression}.primaryKey(),`;\n\n if (field.required) expression += \".notNull()\";\n if (field.defaultNow) expression += \".defaultNow()\";\n else if (field.default !== undefined) expression += `.default(${literal(field.default)})`;\n\n return ` ${name}: ${expression},`;\n}\n\nfunction renderTable(key: string, table: TableDeclaration, prefix: string): string {\n const compositePk = (table.primaryKey?.length ?? 0) > 1;\n const singlePk = !compositePk ? table.primaryKey?.[0] : undefined;\n\n const columns = Object.entries(table.fields)\n .map(([name, field]) => renderColumn(name, field, name === singlePk))\n .join(\"\\n\");\n\n const extras: string[] = [];\n\n for (const declaration of table.indexes ?? []) {\n const builder = declaration.unique ? \"uniqueIndex\" : \"index\";\n const name = declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`;\n const columns = declaration.on.map((field) => `table.${field}`).join(\", \");\n extras.push(` ${builder}(${JSON.stringify(prefix + name)}).on(${columns}),`);\n }\n\n if (compositePk) {\n const columns = (table.primaryKey ?? []).map((field) => `table.${field}`).join(\", \");\n extras.push(` primaryKey({ columns: [${columns}] }),`);\n }\n\n const third = extras.length ? `,\\n (table) => [\\n${extras.join(\"\\n\")}\\n ]` : \"\";\n\n return `export const ${key} = pgTable(\\n ${JSON.stringify(prefix + table.tableName)},\\n {\\n${columns}\\n }${third},\\n);`;\n}\n\n/** Renders a SchemaDeclaration to Drizzle pg-core source. */\nexport function renderDrizzleSchema(schema: SchemaDeclaration, prefix = \"\"): string {\n const tables = Object.entries(schema);\n\n const used = new Set<string>([\"pgTable\"]);\n for (const [, table] of tables) {\n for (const field of Object.values(table.fields)) used.add(COLUMN_BUILDER[field.type]);\n for (const declaration of table.indexes ?? []) {\n used.add(declaration.unique ? \"uniqueIndex\" : \"index\");\n }\n if ((table.primaryKey?.length ?? 0) > 1) used.add(\"primaryKey\");\n }\n\n const imports = [...used].sort().join(\", \");\n const body = tables.map(([key, table]) => renderTable(key, table, prefix)).join(\"\\n\\n\");\n\n return `// Generated by easy-ping. Do not edit by hand.\\nimport { ${imports} } from \"drizzle-orm/pg-core\";\\n\\n${body}\\n`;\n}\n"]}
1
+ {"version":3,"sources":["../src/schema/declaration.ts","../src/schema/render-sql.ts","../src/schema/migrate-sql.ts","../src/schema/render-drizzle.ts","../src/schema/render-mysql.ts","../src/schema/render-sqlite.ts"],"names":["indexName","columns","SQL_TYPE","quote","defaultClause"],"mappings":"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","file":"schema.cjs","sourcesContent":["import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */\nexport const coreSchema = {\n notification: {\n tableName: \"notification\",\n fields: {\n id: { type: \"string\", required: true },\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n payload: { type: \"json\", required: true },\n actorId: { type: \"string\" },\n groupKey: { type: \"string\" },\n dedupeKey: { type: \"string\" },\n seenAt: { type: \"date\" },\n readAt: { type: \"date\" },\n archivedAt: { type: \"date\" },\n createdAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"userId\", \"createdAt\"], name: \"notification_feed_idx\" },\n { on: [\"userId\", \"groupKey\"], name: \"notification_group_idx\" },\n { on: [\"userId\", \"dedupeKey\"], unique: true, name: \"notification_dedupe_idx\" },\n ],\n },\n\n notificationDelivery: {\n tableName: \"notification_delivery\",\n fields: {\n id: { type: \"string\", required: true },\n notificationId: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n status: { type: \"string\", required: true, default: \"pending\" },\n attempts: { type: \"number\", required: true, default: 0 },\n maxAttempts: { type: \"number\", required: true, default: 5 },\n notBefore: { type: \"date\", required: true, defaultNow: true },\n claimedAt: { type: \"date\" },\n claimedBy: { type: \"string\" },\n lastError: { type: \"string\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"status\", \"notBefore\"], name: \"delivery_claim_idx\" },\n { on: [\"notificationId\"], name: \"delivery_notification_idx\" },\n ],\n },\n\n notificationPreference: {\n tableName: \"notification_preference\",\n fields: {\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n enabled: { type: \"boolean\", required: true, default: true },\n frequency: { type: \"string\", required: true, default: \"instant\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import type { FieldDeclaration, SchemaDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamptz\",\n json: \"jsonb\",\n};\n\nconst quote = (value: string) => `\"${value.replace(/\"/g, '\"\"')}\"`;\n\nconst defaultClause = (field: FieldDeclaration): string => {\n if (field.defaultNow) return \" DEFAULT now()\";\n if (field.default === undefined) return \"\";\n if (typeof field.default === \"string\") return ` DEFAULT '${field.default.replace(/'/g, \"''\")}'`;\n return ` DEFAULT ${field.default}`;\n};\n\n/** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */\nexport function renderPostgresDdl(schema: SchemaDeclaration, prefix = \"\"): string[] {\n const statements: string[] = [];\n\n for (const table of Object.values(schema)) {\n const name = quote(prefix + table.tableName);\n\n const columns = Object.entries(table.fields).map(([field, spec]) => {\n const nullability = spec.required ? \" NOT NULL\" : \"\";\n return ` ${quote(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;\n });\n\n if (table.primaryKey?.length) {\n const key = table.primaryKey.map((field) => quote(toSnakeCase(field))).join(\", \");\n columns.push(` PRIMARY KEY (${key})`);\n }\n\n statements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n${columns.join(\",\\n\")}\\n)`);\n\n for (const declaration of table.indexes ?? []) {\n const indexName = quote(\n prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n );\n const columns = declaration.on.map((field) => quote(toSnakeCase(field))).join(\", \");\n const unique = declaration.unique ? \"UNIQUE \" : \"\";\n statements.push(`CREATE ${unique}INDEX IF NOT EXISTS ${indexName} ON ${name} (${columns})`);\n }\n }\n\n return statements;\n}\n","import type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\nimport { renderPostgresDdl } from \"./render-sql\";\n\n/** Introspects a live Postgres schema and emits only what is missing. Additive only: drops and type changes land in `unsupported`. */\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamptz\",\n json: \"jsonb\",\n};\n\n/** What information_schema reports for each of our declared types. */\nconst LIVE_TYPE: Record<FieldDeclaration[\"type\"], readonly string[]> = {\n string: [\"text\", \"character varying\", \"character\"],\n number: [\"integer\", \"bigint\", \"smallint\"],\n boolean: [\"boolean\"],\n date: [\"timestamp with time zone\", \"timestamp without time zone\"],\n json: [\"jsonb\", \"json\"],\n};\n\nconst quote = (value: string) => `\"${value.replace(/\"/g, '\"\"')}\"`;\n\nconst defaultClause = (field: FieldDeclaration): string => {\n if (field.defaultNow) return \" DEFAULT now()\";\n if (field.default === undefined) return \"\";\n if (typeof field.default === \"string\") return ` DEFAULT '${field.default.replace(/'/g, \"''\")}'`;\n return ` DEFAULT ${field.default}`;\n};\n\nconst indexName = (\n table: TableDeclaration,\n declaration: { on: readonly string[]; name?: string },\n) => declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`;\n\nexport type LiveColumn = { table: string; column: string; type: string; nullable: boolean };\n\n/** A row as INTROSPECT_SQL returns it; `LiveColumn` uses the short forms and both are accepted. */\nexport type LiveColumnRow =\n | LiveColumn\n | {\n table_name: string;\n column_name: string;\n data_type: string;\n is_nullable: string | boolean;\n };\n\n/** Accepts either shape, so raw rows and hand-mapped rows both work. */\nfunction normaliseColumn(row: LiveColumnRow): LiveColumn {\n if (\"table\" in row) return row;\n return {\n table: String(row.table_name),\n column: String(row.column_name),\n type: String(row.data_type),\n nullable: typeof row.is_nullable === \"boolean\" ? row.is_nullable : row.is_nullable === \"YES\",\n };\n}\n\nexport type MigrationPlan = {\n /** Run in order. Empty means the live schema already matches. */\n statements: readonly string[];\n /** Differences this cannot express safely. Read them; they need a human. */\n unsupported: readonly string[];\n /** Tables that do not exist yet — these get a full CREATE TABLE. */\n createdTables: readonly string[];\n};\n\n/** Reads the live column list; a function, so this module stays driver-agnostic. */\nexport type Introspector = () => Promise<readonly LiveColumnRow[]>;\n\n/** The query an Introspector should run; raw rows are accepted as they come back. */\nexport const INTROSPECT_SQL = `\n SELECT table_name, column_name, data_type, is_nullable\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n`;\n\nexport async function planPostgresMigration(\n introspect: Introspector,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<MigrationPlan> {\n const live = await introspect();\n\n const byTable = new Map<string, Map<string, LiveColumn>>();\n for (const row of live) {\n const column = normaliseColumn(row);\n const columns = byTable.get(column.table) ?? new Map<string, LiveColumn>();\n columns.set(column.column, column);\n byTable.set(column.table, columns);\n }\n\n const statements: string[] = [];\n const unsupported: string[] = [];\n const createdTables: string[] = [];\n\n for (const table of Object.values(schema)) {\n const qualified = prefix + table.tableName;\n const existing = byTable.get(qualified);\n\n // Absent entirely: the ordinary bootstrap path still applies.\n if (!existing || existing.size === 0) {\n createdTables.push(qualified);\n statements.push(...renderPostgresDdl({ [table.tableName]: table }, prefix));\n continue;\n }\n\n for (const [field, spec] of Object.entries(table.fields)) {\n const column = toSnakeCase(field);\n const found = existing.get(column);\n\n if (!found) {\n // NOT NULL fails on a populated table without a default: added nullable and flagged.\n const canFill = spec.defaultNow || spec.default !== undefined;\n const nullability = spec.required && canFill ? \" NOT NULL\" : \"\";\n\n statements.push(\n `ALTER TABLE ${quote(qualified)} ADD COLUMN IF NOT EXISTS ` +\n `${quote(column)} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`,\n );\n\n if (spec.required && !canFill) {\n unsupported.push(\n `${qualified}.${column} is declared required but has no default; ` +\n \"it was added nullable. Backfill it, then ALTER ... SET NOT NULL yourself.\",\n );\n }\n continue;\n }\n\n if (!LIVE_TYPE[spec.type].includes(found.type)) {\n unsupported.push(\n `${qualified}.${column} is ${found.type} but ${spec.type} is declared ` +\n `(${SQL_TYPE[spec.type]}). Changing a column type can lose data — do it yourself.`,\n );\n }\n }\n\n // Indexes are cheap and idempotent, so they are re-issued unconditionally.\n for (const declaration of table.indexes ?? []) {\n const name = quote(prefix + indexName(table, declaration));\n const columns = declaration.on.map((field) => quote(toSnakeCase(field))).join(\", \");\n statements.push(\n `CREATE ${declaration.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${name} ` +\n `ON ${quote(qualified)} (${columns})`,\n );\n }\n\n for (const column of existing.keys()) {\n const declared = Object.keys(table.fields).some((field) => toSnakeCase(field) === column);\n if (!declared) {\n unsupported.push(\n `${qualified}.${column} exists but is not declared. Left alone — ` +\n \"drop it yourself if it is ours and no longer needed.\",\n );\n }\n }\n }\n\n return { statements, unsupported, createdTables };\n}\n","import type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst COLUMN_BUILDER: Record<FieldDeclaration[\"type\"], string> = {\n string: \"text\",\n number: \"integer\",\n boolean: \"boolean\",\n date: \"timestamp\",\n json: \"jsonb\",\n};\n\nconst literal = (value: string | number | boolean) =>\n typeof value === \"string\" ? JSON.stringify(value) : String(value);\n\nfunction renderColumn(name: string, field: FieldDeclaration, isSinglePk: boolean): string {\n const builder = COLUMN_BUILDER[field.type];\n const column = toSnakeCase(name);\n\n let expression =\n field.type === \"date\"\n ? `${builder}(${JSON.stringify(column)}, { withTimezone: true })`\n : `${builder}(${JSON.stringify(column)})`;\n\n if (isSinglePk) return ` ${name}: ${expression}.primaryKey(),`;\n\n if (field.required) expression += \".notNull()\";\n if (field.defaultNow) expression += \".defaultNow()\";\n else if (field.default !== undefined) expression += `.default(${literal(field.default)})`;\n\n return ` ${name}: ${expression},`;\n}\n\nfunction renderTable(key: string, table: TableDeclaration, prefix: string): string {\n const compositePk = (table.primaryKey?.length ?? 0) > 1;\n const singlePk = !compositePk ? table.primaryKey?.[0] : undefined;\n\n const columns = Object.entries(table.fields)\n .map(([name, field]) => renderColumn(name, field, name === singlePk))\n .join(\"\\n\");\n\n const extras: string[] = [];\n\n for (const declaration of table.indexes ?? []) {\n const builder = declaration.unique ? \"uniqueIndex\" : \"index\";\n const name = declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`;\n const columns = declaration.on.map((field) => `table.${field}`).join(\", \");\n extras.push(` ${builder}(${JSON.stringify(prefix + name)}).on(${columns}),`);\n }\n\n if (compositePk) {\n const columns = (table.primaryKey ?? []).map((field) => `table.${field}`).join(\", \");\n extras.push(` primaryKey({ columns: [${columns}] }),`);\n }\n\n const third = extras.length ? `,\\n (table) => [\\n${extras.join(\"\\n\")}\\n ]` : \"\";\n\n return `export const ${key} = pgTable(\\n ${JSON.stringify(prefix + table.tableName)},\\n {\\n${columns}\\n }${third},\\n);`;\n}\n\n/** Renders a SchemaDeclaration to Drizzle pg-core source. */\nexport function renderDrizzleSchema(schema: SchemaDeclaration, prefix = \"\"): string {\n const tables = Object.entries(schema);\n\n const used = new Set<string>([\"pgTable\"]);\n for (const [, table] of tables) {\n for (const field of Object.values(table.fields)) used.add(COLUMN_BUILDER[field.type]);\n for (const declaration of table.indexes ?? []) {\n used.add(declaration.unique ? \"uniqueIndex\" : \"index\");\n }\n if ((table.primaryKey?.length ?? 0) > 1) used.add(\"primaryKey\");\n }\n\n const imports = [...used].sort().join(\", \");\n const body = tables.map(([key, table]) => renderTable(key, table, prefix)).join(\"\\n\\n\");\n\n return `// Generated by easy-ping. Do not edit by hand.\\nimport { ${imports} } from \"drizzle-orm/pg-core\";\\n\\n${body}\\n`;\n}\n","import type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst quote = (value: string) => `\\`${value.split(\"`\").join(\"``\")}\\``;\n\n/** InnoDB caps a key at 3072 bytes: 768 utf8mb4 chars for one column, 255 each for three. TEXT cannot be a key or carry a default. */\nfunction stringType(field: string, table: TableDeclaration, spec: FieldDeclaration): string {\n const keys = [\n ...(table.primaryKey ? [table.primaryKey] : []),\n ...(table.indexes ?? []).map((index) => index.on),\n ].filter((columns) => columns.includes(field));\n\n if (keys.some((columns) => columns.length > 1)) return \"VARCHAR(255)\";\n if (keys.length > 0) return \"VARCHAR(768)\";\n if (spec.default !== undefined) return \"VARCHAR(255)\";\n return \"TEXT\";\n}\n\nfunction columnType(field: string, table: TableDeclaration, spec: FieldDeclaration): string {\n switch (spec.type) {\n case \"string\":\n return stringType(field, table, spec);\n case \"number\":\n return \"INT\";\n case \"boolean\":\n return \"TINYINT(1)\";\n case \"date\":\n return \"DATETIME(3)\";\n case \"json\":\n return \"JSON\";\n }\n}\n\nconst defaultClause = (spec: FieldDeclaration): string => {\n if (spec.defaultNow) return \" DEFAULT CURRENT_TIMESTAMP(3)\";\n if (spec.default === undefined) return \"\";\n if (typeof spec.default === \"string\") return ` DEFAULT '${spec.default.replace(/'/g, \"''\")}'`;\n if (typeof spec.default === \"boolean\") return ` DEFAULT ${spec.default ? 1 : 0}`;\n return ` DEFAULT ${spec.default}`;\n};\n\n/** MySQL DDL, one CREATE TABLE IF NOT EXISTS per table with indexes inline (no CREATE INDEX IF NOT EXISTS). */\nexport function renderMysqlDdl(schema: SchemaDeclaration, prefix = \"\"): string[] {\n const statements: string[] = [];\n\n for (const table of Object.values(schema)) {\n const lines = Object.entries(table.fields).map(([field, spec]) => {\n const nullability = spec.required ? \" NOT NULL\" : \"\";\n return ` ${quote(toSnakeCase(field))} ${columnType(field, table, spec)}${nullability}${defaultClause(spec)}`;\n });\n\n if (table.primaryKey?.length) {\n lines.push(\n ` PRIMARY KEY (${table.primaryKey.map((f) => quote(toSnakeCase(f))).join(\", \")})`,\n );\n }\n\n for (const index of table.indexes ?? []) {\n const name = quote(prefix + (index.name ?? `${table.tableName}_${index.on.join(\"_\")}_idx`));\n const columns = index.on.map((f) => quote(toSnakeCase(f))).join(\", \");\n lines.push(` ${index.unique ? \"UNIQUE \" : \"\"}INDEX ${name} (${columns})`);\n }\n\n statements.push(\n `CREATE TABLE IF NOT EXISTS ${quote(prefix + table.tableName)} (\\n${lines.join(\",\\n\")}\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`,\n );\n }\n\n return statements;\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"TEXT\",\n number: \"INTEGER\",\n boolean: \"INTEGER\",\n // ISO-8601 with milliseconds and a trailing Z, the same 24 characters\n // `Date#toISOString` writes, so `<=` on the text is `<=` on the instant.\n date: \"TEXT\",\n json: \"TEXT\",\n};\n\nconst quote = (value: string) => `\"${value.split('\"').join('\"\"')}\"`;\n\nconst defaultClause = (spec: FieldDeclaration): string => {\n if (spec.defaultNow) return \" DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\";\n if (spec.default === undefined) return \"\";\n if (typeof spec.default === \"string\") return ` DEFAULT '${spec.default.replace(/'/g, \"''\")}'`;\n if (typeof spec.default === \"boolean\") return ` DEFAULT ${spec.default ? 1 : 0}`;\n return ` DEFAULT ${spec.default}`;\n};\n\n/** SchemaDeclaration to SQLite DDL. Every statement is `IF NOT EXISTS`. */\nexport function renderSqliteDdl(schema: SchemaDeclaration, prefix = \"\"): string[] {\n const statements: string[] = [];\n\n for (const table of Object.values(schema)) {\n const name = quote(prefix + table.tableName);\n\n const columns = Object.entries(table.fields).map(([field, spec]) => {\n const nullability = spec.required ? \" NOT NULL\" : \"\";\n return ` ${quote(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;\n });\n\n if (table.primaryKey?.length) {\n columns.push(\n ` PRIMARY KEY (${table.primaryKey.map((f) => quote(toSnakeCase(f))).join(\", \")})`,\n );\n }\n\n statements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n${columns.join(\",\\n\")}\\n)`);\n\n for (const index of table.indexes ?? []) {\n const indexName = quote(\n prefix + (index.name ?? `${table.tableName}_${index.on.join(\"_\")}_idx`),\n );\n const cols = index.on.map((f) => quote(toSnakeCase(f))).join(\", \");\n statements.push(\n `CREATE ${index.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${indexName} ON ${name} (${cols})`,\n );\n }\n }\n\n return statements;\n}\n"]}
package/dist/schema.d.cts CHANGED
@@ -1,12 +1,8 @@
1
- import { S as SchemaDeclaration } from './plugin-CiMsGlQe.cjs';
2
- import './adapter-BfLe2J0t.cjs';
1
+ import { S as SchemaDeclaration } from './plugin-CHd2ZiGC.cjs';
2
+ import './adapter-D3lTy-4E.cjs';
3
3
 
4
4
  declare const toSnakeCase: (value: string) => string;
5
- /**
6
- * Core tables in the format plugins use. Less expressive than the hand-written
7
- * Drizzle schema (no partial indexes, ordering or cascade) — a drift test
8
- * asserts the two agree on the fields they share.
9
- */
5
+ /** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */
10
6
  declare const coreSchema: {
11
7
  notification: {
12
8
  tableName: string;
@@ -159,6 +155,13 @@ type LiveColumn = {
159
155
  type: string;
160
156
  nullable: boolean;
161
157
  };
158
+ /** A row as INTROSPECT_SQL returns it; `LiveColumn` uses the short forms and both are accepted. */
159
+ type LiveColumnRow = LiveColumn | {
160
+ table_name: string;
161
+ column_name: string;
162
+ data_type: string;
163
+ is_nullable: string | boolean;
164
+ };
162
165
  type MigrationPlan = {
163
166
  /** Run in order. Empty means the live schema already matches. */
164
167
  statements: readonly string[];
@@ -167,19 +170,22 @@ type MigrationPlan = {
167
170
  /** Tables that do not exist yet — these get a full CREATE TABLE. */
168
171
  createdTables: readonly string[];
169
172
  };
170
- /**
171
- * Reads the live column list. Pass a function that runs the query — this
172
- * module stays driver-agnostic, as the rest of the schema tooling does.
173
- */
174
- type Introspector = () => Promise<readonly LiveColumn[]>;
175
- /** The query an Introspector should run. Exported so callers need not retype it. */
173
+ /** Reads the live column list; a function, so this module stays driver-agnostic. */
174
+ type Introspector = () => Promise<readonly LiveColumnRow[]>;
175
+ /** The query an Introspector should run; raw rows are accepted as they come back. */
176
176
  declare const INTROSPECT_SQL = "\n SELECT table_name, column_name, data_type, is_nullable\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n";
177
177
  declare function planPostgresMigration(introspect: Introspector, schema: SchemaDeclaration, prefix?: string): Promise<MigrationPlan>;
178
178
 
179
179
  /** Renders a SchemaDeclaration to Drizzle pg-core source. */
180
180
  declare function renderDrizzleSchema(schema: SchemaDeclaration, prefix?: string): string;
181
181
 
182
+ /** MySQL DDL, one CREATE TABLE IF NOT EXISTS per table with indexes inline (no CREATE INDEX IF NOT EXISTS). */
183
+ declare function renderMysqlDdl(schema: SchemaDeclaration, prefix?: string): string[];
184
+
182
185
  /** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */
183
186
  declare function renderPostgresDdl(schema: SchemaDeclaration, prefix?: string): string[];
184
187
 
185
- export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl, toSnakeCase };
188
+ /** SchemaDeclaration to SQLite DDL. Every statement is `IF NOT EXISTS`. */
189
+ declare function renderSqliteDdl(schema: SchemaDeclaration, prefix?: string): string[];
190
+
191
+ export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderMysqlDdl, renderPostgresDdl, renderSqliteDdl, toSnakeCase };
package/dist/schema.d.ts CHANGED
@@ -1,12 +1,8 @@
1
- import { S as SchemaDeclaration } from './plugin-C9Hoxus2.js';
2
- import './adapter-BfLe2J0t.js';
1
+ import { S as SchemaDeclaration } from './plugin-Cg9usuUi.js';
2
+ import './adapter-D3lTy-4E.js';
3
3
 
4
4
  declare const toSnakeCase: (value: string) => string;
5
- /**
6
- * Core tables in the format plugins use. Less expressive than the hand-written
7
- * Drizzle schema (no partial indexes, ordering or cascade) — a drift test
8
- * asserts the two agree on the fields they share.
9
- */
5
+ /** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */
10
6
  declare const coreSchema: {
11
7
  notification: {
12
8
  tableName: string;
@@ -159,6 +155,13 @@ type LiveColumn = {
159
155
  type: string;
160
156
  nullable: boolean;
161
157
  };
158
+ /** A row as INTROSPECT_SQL returns it; `LiveColumn` uses the short forms and both are accepted. */
159
+ type LiveColumnRow = LiveColumn | {
160
+ table_name: string;
161
+ column_name: string;
162
+ data_type: string;
163
+ is_nullable: string | boolean;
164
+ };
162
165
  type MigrationPlan = {
163
166
  /** Run in order. Empty means the live schema already matches. */
164
167
  statements: readonly string[];
@@ -167,19 +170,22 @@ type MigrationPlan = {
167
170
  /** Tables that do not exist yet — these get a full CREATE TABLE. */
168
171
  createdTables: readonly string[];
169
172
  };
170
- /**
171
- * Reads the live column list. Pass a function that runs the query — this
172
- * module stays driver-agnostic, as the rest of the schema tooling does.
173
- */
174
- type Introspector = () => Promise<readonly LiveColumn[]>;
175
- /** The query an Introspector should run. Exported so callers need not retype it. */
173
+ /** Reads the live column list; a function, so this module stays driver-agnostic. */
174
+ type Introspector = () => Promise<readonly LiveColumnRow[]>;
175
+ /** The query an Introspector should run; raw rows are accepted as they come back. */
176
176
  declare const INTROSPECT_SQL = "\n SELECT table_name, column_name, data_type, is_nullable\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n";
177
177
  declare function planPostgresMigration(introspect: Introspector, schema: SchemaDeclaration, prefix?: string): Promise<MigrationPlan>;
178
178
 
179
179
  /** Renders a SchemaDeclaration to Drizzle pg-core source. */
180
180
  declare function renderDrizzleSchema(schema: SchemaDeclaration, prefix?: string): string;
181
181
 
182
+ /** MySQL DDL, one CREATE TABLE IF NOT EXISTS per table with indexes inline (no CREATE INDEX IF NOT EXISTS). */
183
+ declare function renderMysqlDdl(schema: SchemaDeclaration, prefix?: string): string[];
184
+
182
185
  /** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */
183
186
  declare function renderPostgresDdl(schema: SchemaDeclaration, prefix?: string): string[];
184
187
 
185
- export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl, toSnakeCase };
188
+ /** SchemaDeclaration to SQLite DDL. Every statement is `IF NOT EXISTS`. */
189
+ declare function renderSqliteDdl(schema: SchemaDeclaration, prefix?: string): string[];
190
+
191
+ export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderMysqlDdl, renderPostgresDdl, renderSqliteDdl, toSnakeCase };
package/dist/schema.js CHANGED
@@ -1,4 +1,6 @@
1
- export { INTROSPECT_SQL, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl } from './chunk-YEMRRMJQ.js';
2
- export { coreSchema, toSnakeCase } from './chunk-PSJHXZPR.js';
1
+ export { INTROSPECT_SQL, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl } from './chunk-XIDVLYNQ.js';
2
+ export { renderMysqlDdl } from './chunk-M4R77BJD.js';
3
+ export { renderSqliteDdl } from './chunk-HY47TQMY.js';
4
+ export { coreSchema, toSnakeCase } from './chunk-AEYYTE5I.js';
3
5
  //# sourceMappingURL=schema.js.map
4
6
  //# sourceMappingURL=schema.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The wake-up seam. A publish carries no payload: it says "something changed
3
+ * on this channel, go look", so losing one costs latency, never data.
4
+ * RFC 0006 §4C.
5
+ */
6
+ type Signals = {
7
+ /** True when a publish in one process reaches subscribers in another. */
8
+ readonly crossProcess: boolean;
9
+ publish(channel: string): void;
10
+ subscribe(channel: string, handler: () => void): () => void;
11
+ close?(): Promise<void> | void;
12
+ };
13
+ declare const DELIVERIES_CHANNEL = "deliveries";
14
+ declare const inboxChannel: (userId: string) => string;
15
+ /** In-process only. The default, and exactly right on SQLite or a single replica. */
16
+ declare function createMemorySignals(): Signals;
17
+ /**
18
+ * Wraps a cross-process transport (LISTEN/NOTIFY, a change stream) so local
19
+ * subscribers still hear local publishes even if the transport drops them,
20
+ * and a transport failure degrades to in-process rather than to silence.
21
+ */
22
+ declare function createBridgedSignals(transport: {
23
+ publish(channel: string): Promise<void> | void;
24
+ subscribe(channel: string, handler: () => void): Promise<() => void> | (() => void);
25
+ }, onError: (error: unknown) => void): Signals;
26
+
27
+ export { DELIVERIES_CHANNEL as D, type Signals as S, createMemorySignals as a, createBridgedSignals as c, inboxChannel as i };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The wake-up seam. A publish carries no payload: it says "something changed
3
+ * on this channel, go look", so losing one costs latency, never data.
4
+ * RFC 0006 §4C.
5
+ */
6
+ type Signals = {
7
+ /** True when a publish in one process reaches subscribers in another. */
8
+ readonly crossProcess: boolean;
9
+ publish(channel: string): void;
10
+ subscribe(channel: string, handler: () => void): () => void;
11
+ close?(): Promise<void> | void;
12
+ };
13
+ declare const DELIVERIES_CHANNEL = "deliveries";
14
+ declare const inboxChannel: (userId: string) => string;
15
+ /** In-process only. The default, and exactly right on SQLite or a single replica. */
16
+ declare function createMemorySignals(): Signals;
17
+ /**
18
+ * Wraps a cross-process transport (LISTEN/NOTIFY, a change stream) so local
19
+ * subscribers still hear local publishes even if the transport drops them,
20
+ * and a transport failure degrades to in-process rather than to silence.
21
+ */
22
+ declare function createBridgedSignals(transport: {
23
+ publish(channel: string): Promise<void> | void;
24
+ subscribe(channel: string, handler: () => void): Promise<() => void> | (() => void);
25
+ }, onError: (error: unknown) => void): Signals;
26
+
27
+ export { DELIVERIES_CHANNEL as D, type Signals as S, createMemorySignals as a, createBridgedSignals as c, inboxChannel as i };
package/dist/sw.cjs ADDED
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ // src/sw/index.ts
4
+ var isRelayMessage = (value) => {
5
+ const message = value;
6
+ return message?.source === "easy-ping" && message.type === "changed";
7
+ };
8
+ async function handlePush(event, options = {}, scope = globalThis) {
9
+ let payload = {};
10
+ try {
11
+ payload = event.data?.json() ?? {};
12
+ } catch {
13
+ payload = {};
14
+ }
15
+ const notificationId = typeof payload.data?.notificationId === "string" ? payload.data.notificationId : void 0;
16
+ if (options.showNotification !== false) {
17
+ const rendered = options.render?.(payload) ?? {
18
+ title: payload.title ?? "Notification",
19
+ options: {
20
+ body: payload.body ?? "",
21
+ data: payload.data ?? {},
22
+ ...notificationId ? { tag: notificationId } : {}
23
+ }
24
+ };
25
+ await scope.registration.showNotification(rendered.title, rendered.options);
26
+ }
27
+ const message = {
28
+ source: "easy-ping",
29
+ type: "changed",
30
+ ...notificationId ? { notificationId } : {}
31
+ };
32
+ const tabs = await scope.clients.matchAll({ type: "window", includeUncontrolled: true });
33
+ for (const tab of tabs) tab.postMessage(message);
34
+ }
35
+
36
+ exports.handlePush = handlePush;
37
+ exports.isRelayMessage = isRelayMessage;
38
+ //# sourceMappingURL=sw.cjs.map
39
+ //# sourceMappingURL=sw.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sw/index.ts"],"names":[],"mappings":";;;AAwBO,IAAM,cAAA,GAAiB,CAAC,KAAA,KAA0C;AACvE,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAA,EAAS,MAAA,KAAW,WAAA,IAAe,OAAA,CAAQ,IAAA,KAAS,SAAA;AAC7D;AAuBA,eAAsB,WACpB,KAAA,EACA,OAAA,GAA6B,EAAC,EAC9B,QAAgC,UAAA,EACjB;AACf,EAAA,IAAI,UAAuB,EAAC;AAC5B,EAAA,IAAI;AACF,IAAA,OAAA,GAAW,KAAA,CAAM,IAAA,EAAM,IAAA,EAAK,IAAqB,EAAC;AAAA,EACpD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,GAAU,EAAC;AAAA,EACb;AAEA,EAAA,MAAM,cAAA,GACJ,OAAO,OAAA,CAAQ,IAAA,EAAM,mBAAmB,QAAA,GAAW,OAAA,CAAQ,KAAK,cAAA,GAAiB,MAAA;AAEnF,EAAA,IAAI,OAAA,CAAQ,qBAAqB,KAAA,EAAO;AACtC,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAA,GAAS,OAAO,CAAA,IAAK;AAAA,MAC5C,KAAA,EAAO,QAAQ,KAAA,IAAS,cAAA;AAAA,MACxB,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,QAAQ,IAAA,IAAQ,EAAA;AAAA,QACtB,IAAA,EAAM,OAAA,CAAQ,IAAA,IAAQ,EAAC;AAAA,QACvB,GAAI,cAAA,GAAiB,EAAE,GAAA,EAAK,cAAA,KAAmB;AAAC;AAClD,KACF;AACA,IAAA,MAAM,MAAM,YAAA,CAAa,gBAAA,CAAiB,QAAA,CAAS,KAAA,EAAO,SAAS,OAAO,CAAA;AAAA,EAC5E;AAEA,EAAA,MAAM,OAAA,GAAwB;AAAA,IAC5B,MAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAM,SAAA;AAAA,IACN,GAAI,cAAA,GAAiB,EAAE,cAAA,KAAmB;AAAC,GAC7C;AACA,EAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,mBAAA,EAAqB,IAAA,EAAM,CAAA;AACvF,EAAA,KAAA,MAAW,GAAA,IAAO,IAAA,EAAM,GAAA,CAAI,WAAA,CAAY,OAAO,CAAA;AACjD","file":"sw.cjs","sourcesContent":["/**\n * The service-worker half of the push relay (RFC 0006 idea 4).\n *\n * import { handlePush } from \"easy-ping/sw\";\n * self.addEventListener(\"push\", (event) => event.waitUntil(handlePush(event)));\n *\n * Shows the OS notification the push was sent for, then tells every open tab\n * on this origin that the inbox changed, so the bell refreshes without a poll.\n * Nothing here imports service-worker types: the globals are taken\n * structurally so the file compiles under the DOM lib.\n */\n\nexport type PushPayload = {\n title?: string;\n body?: string;\n data?: Record<string, unknown>;\n};\n\nexport type RelayMessage = {\n source: \"easy-ping\";\n type: \"changed\";\n notificationId?: string;\n};\n\nexport const isRelayMessage = (value: unknown): value is RelayMessage => {\n const message = value as Partial<RelayMessage> | null;\n return message?.source === \"easy-ping\" && message.type === \"changed\";\n};\n\ntype PushEventLike = { data: { json(): unknown } | null };\n\ntype ServiceWorkerScopeLike = {\n registration: {\n showNotification(title: string, options?: Record<string, unknown>): Promise<void>;\n };\n clients: {\n matchAll(options?: {\n type?: \"window\";\n includeUncontrolled?: boolean;\n }): Promise<{ postMessage(message: unknown): void }[]>;\n };\n};\n\nexport type HandlePushOptions = {\n /** Override what the OS notification shows. Default: the payload's title and body. */\n render?: (payload: PushPayload) => { title: string; options?: Record<string, unknown> };\n /** Skip the OS notification. Browsers ration silent pushes; leave this on unless you know why. */\n showNotification?: boolean;\n};\n\nexport async function handlePush(\n event: PushEventLike,\n options: HandlePushOptions = {},\n scope: ServiceWorkerScopeLike = globalThis as unknown as ServiceWorkerScopeLike,\n): Promise<void> {\n let payload: PushPayload = {};\n try {\n payload = (event.data?.json() as PushPayload) ?? {};\n } catch {\n payload = {};\n }\n\n const notificationId =\n typeof payload.data?.notificationId === \"string\" ? payload.data.notificationId : undefined;\n\n if (options.showNotification !== false) {\n const rendered = options.render?.(payload) ?? {\n title: payload.title ?? \"Notification\",\n options: {\n body: payload.body ?? \"\",\n data: payload.data ?? {},\n ...(notificationId ? { tag: notificationId } : {}),\n },\n };\n await scope.registration.showNotification(rendered.title, rendered.options);\n }\n\n const message: RelayMessage = {\n source: \"easy-ping\",\n type: \"changed\",\n ...(notificationId ? { notificationId } : {}),\n };\n const tabs = await scope.clients.matchAll({ type: \"window\", includeUncontrolled: true });\n for (const tab of tabs) tab.postMessage(message);\n}\n"]}
package/dist/sw.d.cts ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The service-worker half of the push relay (RFC 0006 idea 4).
3
+ *
4
+ * import { handlePush } from "easy-ping/sw";
5
+ * self.addEventListener("push", (event) => event.waitUntil(handlePush(event)));
6
+ *
7
+ * Shows the OS notification the push was sent for, then tells every open tab
8
+ * on this origin that the inbox changed, so the bell refreshes without a poll.
9
+ * Nothing here imports service-worker types: the globals are taken
10
+ * structurally so the file compiles under the DOM lib.
11
+ */
12
+ type PushPayload = {
13
+ title?: string;
14
+ body?: string;
15
+ data?: Record<string, unknown>;
16
+ };
17
+ type RelayMessage = {
18
+ source: "easy-ping";
19
+ type: "changed";
20
+ notificationId?: string;
21
+ };
22
+ declare const isRelayMessage: (value: unknown) => value is RelayMessage;
23
+ type PushEventLike = {
24
+ data: {
25
+ json(): unknown;
26
+ } | null;
27
+ };
28
+ type ServiceWorkerScopeLike = {
29
+ registration: {
30
+ showNotification(title: string, options?: Record<string, unknown>): Promise<void>;
31
+ };
32
+ clients: {
33
+ matchAll(options?: {
34
+ type?: "window";
35
+ includeUncontrolled?: boolean;
36
+ }): Promise<{
37
+ postMessage(message: unknown): void;
38
+ }[]>;
39
+ };
40
+ };
41
+ type HandlePushOptions = {
42
+ /** Override what the OS notification shows. Default: the payload's title and body. */
43
+ render?: (payload: PushPayload) => {
44
+ title: string;
45
+ options?: Record<string, unknown>;
46
+ };
47
+ /** Skip the OS notification. Browsers ration silent pushes; leave this on unless you know why. */
48
+ showNotification?: boolean;
49
+ };
50
+ declare function handlePush(event: PushEventLike, options?: HandlePushOptions, scope?: ServiceWorkerScopeLike): Promise<void>;
51
+
52
+ export { type HandlePushOptions, type PushPayload, type RelayMessage, handlePush, isRelayMessage };