easy-ping 0.1.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +374 -0
  3. package/dist/adapter-f0OR2DhY.d.cts +200 -0
  4. package/dist/adapter-f0OR2DhY.d.ts +200 -0
  5. package/dist/adapters/drizzle.cjs +440 -0
  6. package/dist/adapters/drizzle.cjs.map +1 -0
  7. package/dist/adapters/drizzle.d.cts +991 -0
  8. package/dist/adapters/drizzle.d.ts +991 -0
  9. package/dist/adapters/drizzle.js +409 -0
  10. package/dist/adapters/drizzle.js.map +1 -0
  11. package/dist/adapters/mongodb.cjs +458 -0
  12. package/dist/adapters/mongodb.cjs.map +1 -0
  13. package/dist/adapters/mongodb.d.cts +32 -0
  14. package/dist/adapters/mongodb.d.ts +32 -0
  15. package/dist/adapters/mongodb.js +376 -0
  16. package/dist/adapters/mongodb.js.map +1 -0
  17. package/dist/browser.cjs +96 -0
  18. package/dist/browser.cjs.map +1 -0
  19. package/dist/browser.d.cts +45 -0
  20. package/dist/browser.d.ts +45 -0
  21. package/dist/browser.js +89 -0
  22. package/dist/browser.js.map +1 -0
  23. package/dist/chunk-BV3U542P.js +11 -0
  24. package/dist/chunk-BV3U542P.js.map +1 -0
  25. package/dist/chunk-NYDVNMKG.js +62 -0
  26. package/dist/chunk-NYDVNMKG.js.map +1 -0
  27. package/dist/chunk-OZSOIX23.js +120 -0
  28. package/dist/chunk-OZSOIX23.js.map +1 -0
  29. package/dist/chunk-PTGHMCCG.js +23 -0
  30. package/dist/chunk-PTGHMCCG.js.map +1 -0
  31. package/dist/chunk-W3BMEPPQ.js +50 -0
  32. package/dist/chunk-W3BMEPPQ.js.map +1 -0
  33. package/dist/client.cjs +160 -0
  34. package/dist/client.cjs.map +1 -0
  35. package/dist/client.d.cts +42 -0
  36. package/dist/client.d.ts +42 -0
  37. package/dist/client.js +158 -0
  38. package/dist/client.js.map +1 -0
  39. package/dist/index.cjs +920 -0
  40. package/dist/index.cjs.map +1 -0
  41. package/dist/index.d.cts +203 -0
  42. package/dist/index.d.ts +203 -0
  43. package/dist/index.js +723 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/node.cjs +49 -0
  46. package/dist/node.cjs.map +1 -0
  47. package/dist/node.d.cts +8 -0
  48. package/dist/node.d.ts +8 -0
  49. package/dist/node.js +46 -0
  50. package/dist/node.js.map +1 -0
  51. package/dist/plugin-Bqj9xAOS.d.cts +217 -0
  52. package/dist/plugin-bTJKmnlq.d.ts +217 -0
  53. package/dist/plugins/digests.cjs +206 -0
  54. package/dist/plugins/digests.cjs.map +1 -0
  55. package/dist/plugins/digests.d.cts +68 -0
  56. package/dist/plugins/digests.d.ts +68 -0
  57. package/dist/plugins/digests.js +201 -0
  58. package/dist/plugins/digests.js.map +1 -0
  59. package/dist/plugins/preferences-client.cjs +23 -0
  60. package/dist/plugins/preferences-client.cjs.map +1 -0
  61. package/dist/plugins/preferences-client.d.cts +29 -0
  62. package/dist/plugins/preferences-client.d.ts +29 -0
  63. package/dist/plugins/preferences-client.js +18 -0
  64. package/dist/plugins/preferences-client.js.map +1 -0
  65. package/dist/plugins/preferences-react.cjs +125 -0
  66. package/dist/plugins/preferences-react.cjs.map +1 -0
  67. package/dist/plugins/preferences-react.d.cts +40 -0
  68. package/dist/plugins/preferences-react.d.ts +40 -0
  69. package/dist/plugins/preferences-react.js +101 -0
  70. package/dist/plugins/preferences-react.js.map +1 -0
  71. package/dist/plugins/preferences.cjs +147 -0
  72. package/dist/plugins/preferences.cjs.map +1 -0
  73. package/dist/plugins/preferences.d.cts +22 -0
  74. package/dist/plugins/preferences.d.ts +22 -0
  75. package/dist/plugins/preferences.js +119 -0
  76. package/dist/plugins/preferences.js.map +1 -0
  77. package/dist/plugins/push.cjs +146 -0
  78. package/dist/plugins/push.cjs.map +1 -0
  79. package/dist/plugins/push.d.cts +60 -0
  80. package/dist/plugins/push.d.ts +60 -0
  81. package/dist/plugins/push.js +144 -0
  82. package/dist/plugins/push.js.map +1 -0
  83. package/dist/provider-CA45WVqt.d.cts +23 -0
  84. package/dist/provider-CA45WVqt.d.ts +23 -0
  85. package/dist/providers/resend.cjs +69 -0
  86. package/dist/providers/resend.cjs.map +1 -0
  87. package/dist/providers/resend.d.cts +20 -0
  88. package/dist/providers/resend.d.ts +20 -0
  89. package/dist/providers/resend.js +66 -0
  90. package/dist/providers/resend.js.map +1 -0
  91. package/dist/providers/web-push.cjs +211 -0
  92. package/dist/providers/web-push.cjs.map +1 -0
  93. package/dist/providers/web-push.d.cts +33 -0
  94. package/dist/providers/web-push.d.ts +33 -0
  95. package/dist/providers/web-push.js +193 -0
  96. package/dist/providers/web-push.js.map +1 -0
  97. package/dist/react.cjs +218 -0
  98. package/dist/react.cjs.map +1 -0
  99. package/dist/react.d.cts +57 -0
  100. package/dist/react.d.ts +57 -0
  101. package/dist/react.js +193 -0
  102. package/dist/react.js.map +1 -0
  103. package/dist/schema.cjs +263 -0
  104. package/dist/schema.cjs.map +1 -0
  105. package/dist/schema.d.cts +180 -0
  106. package/dist/schema.d.ts +180 -0
  107. package/dist/schema.js +200 -0
  108. package/dist/schema.js.map +1 -0
  109. package/dist/testing.cjs +342 -0
  110. package/dist/testing.cjs.map +1 -0
  111. package/dist/testing.d.cts +38 -0
  112. package/dist/testing.d.ts +38 -0
  113. package/dist/testing.js +340 -0
  114. package/dist/testing.js.map +1 -0
  115. package/package.json +168 -0
@@ -0,0 +1,263 @@
1
+ 'use strict';
2
+
3
+ // src/schema/declaration.ts
4
+ var toSnakeCase = (value) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
5
+ var coreSchema = {
6
+ notification: {
7
+ tableName: "notification",
8
+ fields: {
9
+ id: { type: "string", required: true },
10
+ userId: { type: "string", required: true },
11
+ type: { type: "string", required: true },
12
+ payload: { type: "json", required: true },
13
+ actorId: { type: "string" },
14
+ groupKey: { type: "string" },
15
+ dedupeKey: { type: "string" },
16
+ seenAt: { type: "date" },
17
+ readAt: { type: "date" },
18
+ archivedAt: { type: "date" },
19
+ createdAt: { type: "date", required: true, defaultNow: true }
20
+ },
21
+ primaryKey: ["id"],
22
+ indexes: [
23
+ { on: ["userId", "createdAt"], name: "notification_feed_idx" },
24
+ { on: ["userId", "groupKey"], name: "notification_group_idx" },
25
+ { on: ["userId", "dedupeKey"], unique: true, name: "notification_dedupe_idx" }
26
+ ]
27
+ },
28
+ notificationDelivery: {
29
+ tableName: "notification_delivery",
30
+ fields: {
31
+ id: { type: "string", required: true },
32
+ notificationId: { type: "string", required: true },
33
+ channel: { type: "string", required: true },
34
+ status: { type: "string", required: true, default: "pending" },
35
+ attempts: { type: "number", required: true, default: 0 },
36
+ maxAttempts: { type: "number", required: true, default: 5 },
37
+ notBefore: { type: "date", required: true, defaultNow: true },
38
+ claimedAt: { type: "date" },
39
+ claimedBy: { type: "string" },
40
+ lastError: { type: "string" },
41
+ updatedAt: { type: "date", required: true, defaultNow: true }
42
+ },
43
+ primaryKey: ["id"],
44
+ indexes: [
45
+ { on: ["status", "notBefore"], name: "delivery_claim_idx" },
46
+ { on: ["notificationId"], name: "delivery_notification_idx" }
47
+ ]
48
+ },
49
+ notificationPreference: {
50
+ tableName: "notification_preference",
51
+ fields: {
52
+ userId: { type: "string", required: true },
53
+ type: { type: "string", required: true },
54
+ channel: { type: "string", required: true },
55
+ enabled: { type: "boolean", required: true, default: true },
56
+ frequency: { type: "string", required: true, default: "instant" }
57
+ },
58
+ primaryKey: ["userId", "type", "channel"]
59
+ }
60
+ };
61
+
62
+ // src/schema/render-sql.ts
63
+ var SQL_TYPE = {
64
+ string: "text",
65
+ number: "integer",
66
+ boolean: "boolean",
67
+ date: "timestamptz",
68
+ json: "jsonb"
69
+ };
70
+ var quote = (value) => `"${value.replace(/"/g, '""')}"`;
71
+ var defaultClause = (field) => {
72
+ if (field.defaultNow) return " DEFAULT now()";
73
+ if (field.default === void 0) return "";
74
+ if (typeof field.default === "string") return ` DEFAULT '${field.default.replace(/'/g, "''")}'`;
75
+ return ` DEFAULT ${field.default}`;
76
+ };
77
+ function renderPostgresDdl(schema, prefix = "") {
78
+ const statements = [];
79
+ for (const table of Object.values(schema)) {
80
+ const name = quote(prefix + table.tableName);
81
+ const columns = Object.entries(table.fields).map(([field, spec]) => {
82
+ const nullability = spec.required ? " NOT NULL" : "";
83
+ return ` ${quote(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;
84
+ });
85
+ if (table.primaryKey?.length) {
86
+ const key = table.primaryKey.map((field) => quote(toSnakeCase(field))).join(", ");
87
+ columns.push(` PRIMARY KEY (${key})`);
88
+ }
89
+ statements.push(`CREATE TABLE IF NOT EXISTS ${name} (
90
+ ${columns.join(",\n")}
91
+ )`);
92
+ for (const declaration of table.indexes ?? []) {
93
+ const indexName2 = quote(
94
+ prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join("_")}_idx`)
95
+ );
96
+ const columns2 = declaration.on.map((field) => quote(toSnakeCase(field))).join(", ");
97
+ const unique = declaration.unique ? "UNIQUE " : "";
98
+ statements.push(`CREATE ${unique}INDEX IF NOT EXISTS ${indexName2} ON ${name} (${columns2})`);
99
+ }
100
+ }
101
+ return statements;
102
+ }
103
+
104
+ // src/schema/migrate-sql.ts
105
+ var SQL_TYPE2 = {
106
+ string: "text",
107
+ number: "integer",
108
+ boolean: "boolean",
109
+ date: "timestamptz",
110
+ json: "jsonb"
111
+ };
112
+ var LIVE_TYPE = {
113
+ string: ["text", "character varying", "character"],
114
+ number: ["integer", "bigint", "smallint"],
115
+ boolean: ["boolean"],
116
+ date: ["timestamp with time zone", "timestamp without time zone"],
117
+ json: ["jsonb", "json"]
118
+ };
119
+ var quote2 = (value) => `"${value.replace(/"/g, '""')}"`;
120
+ var defaultClause2 = (field) => {
121
+ if (field.defaultNow) return " DEFAULT now()";
122
+ if (field.default === void 0) return "";
123
+ if (typeof field.default === "string") return ` DEFAULT '${field.default.replace(/'/g, "''")}'`;
124
+ return ` DEFAULT ${field.default}`;
125
+ };
126
+ var indexName = (table, declaration) => declaration.name ?? `${table.tableName}_${declaration.on.join("_")}_idx`;
127
+ var INTROSPECT_SQL = `
128
+ SELECT table_name, column_name, data_type, is_nullable
129
+ FROM information_schema.columns
130
+ WHERE table_schema = current_schema()
131
+ `;
132
+ async function planPostgresMigration(introspect, schema, prefix = "") {
133
+ const live = await introspect();
134
+ const byTable = /* @__PURE__ */ new Map();
135
+ for (const column of live) {
136
+ const columns = byTable.get(column.table) ?? /* @__PURE__ */ new Map();
137
+ columns.set(column.column, column);
138
+ byTable.set(column.table, columns);
139
+ }
140
+ const statements = [];
141
+ const unsupported = [];
142
+ const createdTables = [];
143
+ for (const table of Object.values(schema)) {
144
+ const qualified = prefix + table.tableName;
145
+ const existing = byTable.get(qualified);
146
+ if (!existing || existing.size === 0) {
147
+ createdTables.push(qualified);
148
+ statements.push(...renderPostgresDdl({ [table.tableName]: table }, prefix));
149
+ continue;
150
+ }
151
+ for (const [field, spec] of Object.entries(table.fields)) {
152
+ const column = toSnakeCase(field);
153
+ const found = existing.get(column);
154
+ if (!found) {
155
+ const canFill = spec.defaultNow || spec.default !== void 0;
156
+ const nullability = spec.required && canFill ? " NOT NULL" : "";
157
+ statements.push(
158
+ `ALTER TABLE ${quote2(qualified)} ADD COLUMN IF NOT EXISTS ${quote2(column)} ${SQL_TYPE2[spec.type]}${nullability}${defaultClause2(spec)}`
159
+ );
160
+ if (spec.required && !canFill) {
161
+ unsupported.push(
162
+ `${qualified}.${column} is declared required but has no default; it was added nullable. Backfill it, then ALTER ... SET NOT NULL yourself.`
163
+ );
164
+ }
165
+ continue;
166
+ }
167
+ if (!LIVE_TYPE[spec.type].includes(found.type)) {
168
+ unsupported.push(
169
+ `${qualified}.${column} is ${found.type} but ${spec.type} is declared (${SQL_TYPE2[spec.type]}). Changing a column type can lose data \u2014 do it yourself.`
170
+ );
171
+ }
172
+ }
173
+ for (const declaration of table.indexes ?? []) {
174
+ const name = quote2(prefix + indexName(table, declaration));
175
+ const columns = declaration.on.map((field) => quote2(toSnakeCase(field))).join(", ");
176
+ statements.push(
177
+ `CREATE ${declaration.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${name} ON ${quote2(qualified)} (${columns})`
178
+ );
179
+ }
180
+ for (const column of existing.keys()) {
181
+ const declared = Object.keys(table.fields).some((field) => toSnakeCase(field) === column);
182
+ if (!declared) {
183
+ unsupported.push(
184
+ `${qualified}.${column} exists but is not declared. Left alone \u2014 drop it yourself if it is ours and no longer needed.`
185
+ );
186
+ }
187
+ }
188
+ }
189
+ return { statements, unsupported, createdTables };
190
+ }
191
+
192
+ // src/schema/render-drizzle.ts
193
+ var COLUMN_BUILDER = {
194
+ string: "text",
195
+ number: "integer",
196
+ boolean: "boolean",
197
+ date: "timestamp",
198
+ json: "jsonb"
199
+ };
200
+ var literal = (value) => typeof value === "string" ? JSON.stringify(value) : String(value);
201
+ function renderColumn(name, field, isSinglePk) {
202
+ const builder = COLUMN_BUILDER[field.type];
203
+ const column = toSnakeCase(name);
204
+ let expression = field.type === "date" ? `${builder}(${JSON.stringify(column)}, { withTimezone: true })` : `${builder}(${JSON.stringify(column)})`;
205
+ if (isSinglePk) return ` ${name}: ${expression}.primaryKey(),`;
206
+ if (field.required) expression += ".notNull()";
207
+ if (field.defaultNow) expression += ".defaultNow()";
208
+ else if (field.default !== void 0) expression += `.default(${literal(field.default)})`;
209
+ return ` ${name}: ${expression},`;
210
+ }
211
+ function renderTable(key, table, prefix) {
212
+ const compositePk = (table.primaryKey?.length ?? 0) > 1;
213
+ const singlePk = !compositePk ? table.primaryKey?.[0] : void 0;
214
+ const columns = Object.entries(table.fields).map(([name, field]) => renderColumn(name, field, name === singlePk)).join("\n");
215
+ const extras = [];
216
+ for (const declaration of table.indexes ?? []) {
217
+ const builder = declaration.unique ? "uniqueIndex" : "index";
218
+ const name = declaration.name ?? `${table.tableName}_${declaration.on.join("_")}_idx`;
219
+ const columns2 = declaration.on.map((field) => `table.${field}`).join(", ");
220
+ extras.push(` ${builder}(${JSON.stringify(prefix + name)}).on(${columns2}),`);
221
+ }
222
+ if (compositePk) {
223
+ const columns2 = (table.primaryKey ?? []).map((field) => `table.${field}`).join(", ");
224
+ extras.push(` primaryKey({ columns: [${columns2}] }),`);
225
+ }
226
+ const third = extras.length ? `,
227
+ (table) => [
228
+ ${extras.join("\n")}
229
+ ]` : "";
230
+ return `export const ${key} = pgTable(
231
+ ${JSON.stringify(prefix + table.tableName)},
232
+ {
233
+ ${columns}
234
+ }${third},
235
+ );`;
236
+ }
237
+ function renderDrizzleSchema(schema, prefix = "") {
238
+ const tables = Object.entries(schema);
239
+ const used = /* @__PURE__ */ new Set(["pgTable"]);
240
+ for (const [, table] of tables) {
241
+ for (const field of Object.values(table.fields)) used.add(COLUMN_BUILDER[field.type]);
242
+ for (const declaration of table.indexes ?? []) {
243
+ used.add(declaration.unique ? "uniqueIndex" : "index");
244
+ }
245
+ if ((table.primaryKey?.length ?? 0) > 1) used.add("primaryKey");
246
+ }
247
+ const imports = [...used].sort().join(", ");
248
+ const body = tables.map(([key, table]) => renderTable(key, table, prefix)).join("\n\n");
249
+ return `// Generated by easy-ping. Do not edit by hand.
250
+ import { ${imports} } from "drizzle-orm/pg-core";
251
+
252
+ ${body}
253
+ `;
254
+ }
255
+
256
+ exports.INTROSPECT_SQL = INTROSPECT_SQL;
257
+ exports.coreSchema = coreSchema;
258
+ exports.planPostgresMigration = planPostgresMigration;
259
+ exports.renderDrizzleSchema = renderDrizzleSchema;
260
+ exports.renderPostgresDdl = renderPostgresDdl;
261
+ exports.toSnakeCase = toSnakeCase;
262
+ //# sourceMappingURL=schema.cjs.map
263
+ //# sourceMappingURL=schema.cjs.map
@@ -0,0 +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 },\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"]}
@@ -0,0 +1,180 @@
1
+ import { S as SchemaDeclaration } from './plugin-Bqj9xAOS.cjs';
2
+ import './adapter-f0OR2DhY.cjs';
3
+
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
+ */
10
+ declare const coreSchema: {
11
+ notification: {
12
+ tableName: string;
13
+ fields: {
14
+ id: {
15
+ type: "string";
16
+ required: true;
17
+ };
18
+ userId: {
19
+ type: "string";
20
+ required: true;
21
+ };
22
+ type: {
23
+ type: "string";
24
+ required: true;
25
+ };
26
+ payload: {
27
+ type: "json";
28
+ required: true;
29
+ };
30
+ actorId: {
31
+ type: "string";
32
+ };
33
+ groupKey: {
34
+ type: "string";
35
+ };
36
+ dedupeKey: {
37
+ type: "string";
38
+ };
39
+ seenAt: {
40
+ type: "date";
41
+ };
42
+ readAt: {
43
+ type: "date";
44
+ };
45
+ archivedAt: {
46
+ type: "date";
47
+ };
48
+ createdAt: {
49
+ type: "date";
50
+ required: true;
51
+ defaultNow: true;
52
+ };
53
+ };
54
+ primaryKey: string[];
55
+ indexes: ({
56
+ on: string[];
57
+ name: string;
58
+ unique?: never;
59
+ } | {
60
+ on: string[];
61
+ unique: true;
62
+ name: string;
63
+ })[];
64
+ };
65
+ notificationDelivery: {
66
+ tableName: string;
67
+ fields: {
68
+ id: {
69
+ type: "string";
70
+ required: true;
71
+ };
72
+ notificationId: {
73
+ type: "string";
74
+ required: true;
75
+ };
76
+ channel: {
77
+ type: "string";
78
+ required: true;
79
+ };
80
+ status: {
81
+ type: "string";
82
+ required: true;
83
+ default: string;
84
+ };
85
+ attempts: {
86
+ type: "number";
87
+ required: true;
88
+ default: number;
89
+ };
90
+ maxAttempts: {
91
+ type: "number";
92
+ required: true;
93
+ default: number;
94
+ };
95
+ notBefore: {
96
+ type: "date";
97
+ required: true;
98
+ defaultNow: true;
99
+ };
100
+ claimedAt: {
101
+ type: "date";
102
+ };
103
+ claimedBy: {
104
+ type: "string";
105
+ };
106
+ lastError: {
107
+ type: "string";
108
+ };
109
+ updatedAt: {
110
+ type: "date";
111
+ required: true;
112
+ defaultNow: true;
113
+ };
114
+ };
115
+ primaryKey: string[];
116
+ indexes: {
117
+ on: string[];
118
+ name: string;
119
+ }[];
120
+ };
121
+ notificationPreference: {
122
+ tableName: string;
123
+ fields: {
124
+ userId: {
125
+ type: "string";
126
+ required: true;
127
+ };
128
+ type: {
129
+ type: "string";
130
+ required: true;
131
+ };
132
+ channel: {
133
+ type: "string";
134
+ required: true;
135
+ };
136
+ enabled: {
137
+ type: "boolean";
138
+ required: true;
139
+ default: true;
140
+ };
141
+ frequency: {
142
+ type: "string";
143
+ required: true;
144
+ default: string;
145
+ };
146
+ };
147
+ primaryKey: string[];
148
+ };
149
+ };
150
+
151
+ type LiveColumn = {
152
+ table: string;
153
+ column: string;
154
+ type: string;
155
+ nullable: boolean;
156
+ };
157
+ type MigrationPlan = {
158
+ /** Run in order. Empty means the live schema already matches. */
159
+ statements: readonly string[];
160
+ /** Differences this cannot express safely. Read them; they need a human. */
161
+ unsupported: readonly string[];
162
+ /** Tables that do not exist yet — these get a full CREATE TABLE. */
163
+ createdTables: readonly string[];
164
+ };
165
+ /**
166
+ * Reads the live column list. Pass a function that runs the query — this
167
+ * module stays driver-agnostic, as the rest of the schema tooling does.
168
+ */
169
+ type Introspector = () => Promise<readonly LiveColumn[]>;
170
+ /** The query an Introspector should run. Exported so callers need not retype it. */
171
+ 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";
172
+ declare function planPostgresMigration(introspect: Introspector, schema: SchemaDeclaration, prefix?: string): Promise<MigrationPlan>;
173
+
174
+ /** Renders a SchemaDeclaration to Drizzle pg-core source. */
175
+ declare function renderDrizzleSchema(schema: SchemaDeclaration, prefix?: string): string;
176
+
177
+ /** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */
178
+ declare function renderPostgresDdl(schema: SchemaDeclaration, prefix?: string): string[];
179
+
180
+ export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl, toSnakeCase };
@@ -0,0 +1,180 @@
1
+ import { S as SchemaDeclaration } from './plugin-bTJKmnlq.js';
2
+ import './adapter-f0OR2DhY.js';
3
+
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
+ */
10
+ declare const coreSchema: {
11
+ notification: {
12
+ tableName: string;
13
+ fields: {
14
+ id: {
15
+ type: "string";
16
+ required: true;
17
+ };
18
+ userId: {
19
+ type: "string";
20
+ required: true;
21
+ };
22
+ type: {
23
+ type: "string";
24
+ required: true;
25
+ };
26
+ payload: {
27
+ type: "json";
28
+ required: true;
29
+ };
30
+ actorId: {
31
+ type: "string";
32
+ };
33
+ groupKey: {
34
+ type: "string";
35
+ };
36
+ dedupeKey: {
37
+ type: "string";
38
+ };
39
+ seenAt: {
40
+ type: "date";
41
+ };
42
+ readAt: {
43
+ type: "date";
44
+ };
45
+ archivedAt: {
46
+ type: "date";
47
+ };
48
+ createdAt: {
49
+ type: "date";
50
+ required: true;
51
+ defaultNow: true;
52
+ };
53
+ };
54
+ primaryKey: string[];
55
+ indexes: ({
56
+ on: string[];
57
+ name: string;
58
+ unique?: never;
59
+ } | {
60
+ on: string[];
61
+ unique: true;
62
+ name: string;
63
+ })[];
64
+ };
65
+ notificationDelivery: {
66
+ tableName: string;
67
+ fields: {
68
+ id: {
69
+ type: "string";
70
+ required: true;
71
+ };
72
+ notificationId: {
73
+ type: "string";
74
+ required: true;
75
+ };
76
+ channel: {
77
+ type: "string";
78
+ required: true;
79
+ };
80
+ status: {
81
+ type: "string";
82
+ required: true;
83
+ default: string;
84
+ };
85
+ attempts: {
86
+ type: "number";
87
+ required: true;
88
+ default: number;
89
+ };
90
+ maxAttempts: {
91
+ type: "number";
92
+ required: true;
93
+ default: number;
94
+ };
95
+ notBefore: {
96
+ type: "date";
97
+ required: true;
98
+ defaultNow: true;
99
+ };
100
+ claimedAt: {
101
+ type: "date";
102
+ };
103
+ claimedBy: {
104
+ type: "string";
105
+ };
106
+ lastError: {
107
+ type: "string";
108
+ };
109
+ updatedAt: {
110
+ type: "date";
111
+ required: true;
112
+ defaultNow: true;
113
+ };
114
+ };
115
+ primaryKey: string[];
116
+ indexes: {
117
+ on: string[];
118
+ name: string;
119
+ }[];
120
+ };
121
+ notificationPreference: {
122
+ tableName: string;
123
+ fields: {
124
+ userId: {
125
+ type: "string";
126
+ required: true;
127
+ };
128
+ type: {
129
+ type: "string";
130
+ required: true;
131
+ };
132
+ channel: {
133
+ type: "string";
134
+ required: true;
135
+ };
136
+ enabled: {
137
+ type: "boolean";
138
+ required: true;
139
+ default: true;
140
+ };
141
+ frequency: {
142
+ type: "string";
143
+ required: true;
144
+ default: string;
145
+ };
146
+ };
147
+ primaryKey: string[];
148
+ };
149
+ };
150
+
151
+ type LiveColumn = {
152
+ table: string;
153
+ column: string;
154
+ type: string;
155
+ nullable: boolean;
156
+ };
157
+ type MigrationPlan = {
158
+ /** Run in order. Empty means the live schema already matches. */
159
+ statements: readonly string[];
160
+ /** Differences this cannot express safely. Read them; they need a human. */
161
+ unsupported: readonly string[];
162
+ /** Tables that do not exist yet — these get a full CREATE TABLE. */
163
+ createdTables: readonly string[];
164
+ };
165
+ /**
166
+ * Reads the live column list. Pass a function that runs the query — this
167
+ * module stays driver-agnostic, as the rest of the schema tooling does.
168
+ */
169
+ type Introspector = () => Promise<readonly LiveColumn[]>;
170
+ /** The query an Introspector should run. Exported so callers need not retype it. */
171
+ 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";
172
+ declare function planPostgresMigration(introspect: Introspector, schema: SchemaDeclaration, prefix?: string): Promise<MigrationPlan>;
173
+
174
+ /** Renders a SchemaDeclaration to Drizzle pg-core source. */
175
+ declare function renderDrizzleSchema(schema: SchemaDeclaration, prefix?: string): string;
176
+
177
+ /** SchemaDeclaration to Postgres DDL, from the same source as the Drizzle renderer. */
178
+ declare function renderPostgresDdl(schema: SchemaDeclaration, prefix?: string): string[];
179
+
180
+ export { INTROSPECT_SQL, type Introspector, type LiveColumn, type MigrationPlan, coreSchema, planPostgresMigration, renderDrizzleSchema, renderPostgresDdl, toSnakeCase };