@palbase/backend 2.0.2 → 3.0.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.
- package/dist/{chunk-4J3F32SH.js → chunk-B7EUJP5W.js} +38 -9
- package/dist/chunk-B7EUJP5W.js.map +1 -0
- package/dist/{chunk-L36JLUPO.js → chunk-PHAFZGHN.js} +43 -46
- package/dist/chunk-PHAFZGHN.js.map +1 -0
- package/dist/db/env.cjs +19 -0
- package/dist/db/env.cjs.map +1 -0
- package/dist/db/env.d.cts +45 -0
- package/dist/db/env.d.ts +45 -0
- package/dist/db/env.js +1 -0
- package/dist/db/env.js.map +1 -0
- package/dist/db/index.cjs +28 -231
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +4 -20
- package/dist/db/index.d.ts +4 -20
- package/dist/db/index.js +3 -233
- package/dist/db/index.js.map +1 -1
- package/dist/{endpoint-Djk5L6G2.d.ts → endpoint-DJ98tQd6.d.cts} +30 -68
- package/dist/{endpoint-BlcY2xNA.d.cts → endpoint-DJ98tQd6.d.ts} +30 -68
- package/dist/index-CXUs9iTQ.d.ts +294 -0
- package/dist/index-CZAwpQE1.d.cts +294 -0
- package/dist/index.cjs +229 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +398 -154
- package/dist/index.d.ts +398 -154
- package/dist/index.js +147 -12
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +41 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -2
- package/dist/test/index.d.ts +1 -2
- package/dist/test/index.js +1 -1
- package/docs/README.md +31 -10
- package/docs/background.md +19 -13
- package/docs/database.md +30 -17
- package/docs/endpoints.md +42 -24
- package/docs/errors.md +3 -4
- package/docs/events.md +25 -17
- package/docs/getting-started.md +25 -9
- package/docs/llms-full.txt +489 -164
- package/docs/llms.txt +3 -1
- package/docs/migrations.md +98 -0
- package/docs/resources.md +94 -0
- package/docs/routing.md +59 -26
- package/docs/schema.md +48 -38
- package/docs/services.md +5 -6
- package/package.json +11 -1
- package/dist/chunk-4J3F32SH.js.map +0 -1
- package/dist/chunk-L36JLUPO.js.map +0 -1
- package/dist/schema-BqfEhIC0.d.cts +0 -133
- package/dist/schema-BqfEhIC0.d.ts +0 -133
package/dist/db/index.js
CHANGED
|
@@ -4,248 +4,18 @@ import {
|
|
|
4
4
|
enumType,
|
|
5
5
|
integer,
|
|
6
6
|
jsonb,
|
|
7
|
-
|
|
7
|
+
makeTypedDB,
|
|
8
8
|
text,
|
|
9
9
|
timestamp,
|
|
10
10
|
uuid
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
|
|
13
|
-
// src/db/generator.ts
|
|
14
|
-
function columnTypeToSQL(col) {
|
|
15
|
-
switch (col.type) {
|
|
16
|
-
case "uuid":
|
|
17
|
-
return "UUID";
|
|
18
|
-
case "text":
|
|
19
|
-
return "TEXT";
|
|
20
|
-
case "integer":
|
|
21
|
-
return "INTEGER";
|
|
22
|
-
case "boolean":
|
|
23
|
-
return "BOOLEAN";
|
|
24
|
-
case "timestamp":
|
|
25
|
-
return "TIMESTAMPTZ";
|
|
26
|
-
case "jsonb":
|
|
27
|
-
return "JSONB";
|
|
28
|
-
case "enum":
|
|
29
|
-
return col.enumName ?? "TEXT";
|
|
30
|
-
default:
|
|
31
|
-
return "TEXT";
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function defaultClause(col) {
|
|
35
|
-
if (col.defaultRandom) {
|
|
36
|
-
return " DEFAULT gen_random_uuid()";
|
|
37
|
-
}
|
|
38
|
-
if (col.defaultNow) {
|
|
39
|
-
return " DEFAULT now()";
|
|
40
|
-
}
|
|
41
|
-
if (col.defaultValue !== void 0) {
|
|
42
|
-
if (typeof col.defaultValue === "string") {
|
|
43
|
-
const escaped = col.defaultValue.replace(/'/g, "''");
|
|
44
|
-
return ` DEFAULT '${escaped}'`;
|
|
45
|
-
}
|
|
46
|
-
if (typeof col.defaultValue === "boolean") {
|
|
47
|
-
return ` DEFAULT ${col.defaultValue ? "true" : "false"}`;
|
|
48
|
-
}
|
|
49
|
-
if (typeof col.defaultValue === "object" && col.defaultValue !== null) {
|
|
50
|
-
const escaped = JSON.stringify(col.defaultValue).replace(/'/g, "''");
|
|
51
|
-
return ` DEFAULT '${escaped}'::jsonb`;
|
|
52
|
-
}
|
|
53
|
-
return ` DEFAULT ${col.defaultValue}`;
|
|
54
|
-
}
|
|
55
|
-
return "";
|
|
56
|
-
}
|
|
57
|
-
function onDeleteSQL(action) {
|
|
58
|
-
switch (action) {
|
|
59
|
-
case "cascade":
|
|
60
|
-
return "CASCADE";
|
|
61
|
-
case "set null":
|
|
62
|
-
return "SET NULL";
|
|
63
|
-
case "restrict":
|
|
64
|
-
return "RESTRICT";
|
|
65
|
-
case "no action":
|
|
66
|
-
return "NO ACTION";
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function generateEnumTypes(tables) {
|
|
70
|
-
const enums = /* @__PURE__ */ new Map();
|
|
71
|
-
for (const tableDef of Object.values(tables)) {
|
|
72
|
-
for (const col of Object.values(tableDef.columns)) {
|
|
73
|
-
if (col._def.type === "enum" && col._def.enumName && col._def.enumValues) {
|
|
74
|
-
enums.set(col._def.enumName, col._def.enumValues);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return Array.from(enums.entries()).map(([name, values]) => {
|
|
79
|
-
const vals = values.map((v) => `'${v.replace(/'/g, "''")}'`).join(", ");
|
|
80
|
-
return `CREATE TYPE ${name} AS ENUM (${vals});`;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
function generateCreateTable(tableDef) {
|
|
84
|
-
const lines = [];
|
|
85
|
-
for (const [colName, colBuilder] of Object.entries(tableDef.columns)) {
|
|
86
|
-
const col = colBuilder._def;
|
|
87
|
-
let line = ` ${colName} ${columnTypeToSQL(col)}`;
|
|
88
|
-
if (col.primaryKey) {
|
|
89
|
-
line += " PRIMARY KEY";
|
|
90
|
-
}
|
|
91
|
-
if (!col.nullable && !col.primaryKey) {
|
|
92
|
-
line += " NOT NULL";
|
|
93
|
-
}
|
|
94
|
-
line += defaultClause(col);
|
|
95
|
-
if (col.references) {
|
|
96
|
-
line += ` REFERENCES ${col.references.table}(${col.references.column})`;
|
|
97
|
-
if (col.onDeleteAction) {
|
|
98
|
-
line += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
lines.push(line);
|
|
102
|
-
}
|
|
103
|
-
return `CREATE TABLE ${tableDef.name} (
|
|
104
|
-
${lines.join(",\n")}
|
|
105
|
-
);`;
|
|
106
|
-
}
|
|
107
|
-
function generateDropTable(tableDef) {
|
|
108
|
-
return `DROP TABLE IF EXISTS ${tableDef.name};`;
|
|
109
|
-
}
|
|
110
|
-
function generateDropEnumTypes(tables) {
|
|
111
|
-
const enums = /* @__PURE__ */ new Set();
|
|
112
|
-
for (const tableDef of Object.values(tables)) {
|
|
113
|
-
for (const col of Object.values(tableDef.columns)) {
|
|
114
|
-
if (col._def.type === "enum" && col._def.enumName) {
|
|
115
|
-
enums.add(col._def.enumName);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return Array.from(enums).map((name) => `DROP TYPE IF EXISTS ${name};`);
|
|
120
|
-
}
|
|
121
|
-
function generateMigration(schema) {
|
|
122
|
-
const upParts = [];
|
|
123
|
-
const downParts = [];
|
|
124
|
-
const enumTypes = generateEnumTypes(schema.tables);
|
|
125
|
-
upParts.push(...enumTypes);
|
|
126
|
-
for (const tableDef of Object.values(schema.tables)) {
|
|
127
|
-
upParts.push(generateCreateTable(tableDef));
|
|
128
|
-
}
|
|
129
|
-
const tableNames = Object.values(schema.tables);
|
|
130
|
-
for (let i = tableNames.length - 1; i >= 0; i--) {
|
|
131
|
-
downParts.push(generateDropTable(tableNames[i]));
|
|
132
|
-
}
|
|
133
|
-
downParts.push(...generateDropEnumTypes(schema.tables));
|
|
134
|
-
return {
|
|
135
|
-
up: upParts.join("\n\n"),
|
|
136
|
-
down: downParts.join("\n\n")
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function diffSchemas(oldSchema, newSchema) {
|
|
140
|
-
const addedTables = [];
|
|
141
|
-
const droppedTables = [];
|
|
142
|
-
const columnDiffs = [];
|
|
143
|
-
const oldTableNames = new Set(Object.keys(oldSchema.tables));
|
|
144
|
-
const newTableNames = new Set(Object.keys(newSchema.tables));
|
|
145
|
-
for (const name of newTableNames) {
|
|
146
|
-
if (!oldTableNames.has(name)) {
|
|
147
|
-
addedTables.push(newSchema.tables[name]);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
for (const name of oldTableNames) {
|
|
151
|
-
if (!newTableNames.has(name)) {
|
|
152
|
-
droppedTables.push(oldSchema.tables[name]);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
for (const name of newTableNames) {
|
|
156
|
-
if (!oldTableNames.has(name)) continue;
|
|
157
|
-
const oldTable = oldSchema.tables[name];
|
|
158
|
-
const newTable = newSchema.tables[name];
|
|
159
|
-
const oldCols = new Set(Object.keys(oldTable.columns));
|
|
160
|
-
const newCols = new Set(Object.keys(newTable.columns));
|
|
161
|
-
for (const col of newCols) {
|
|
162
|
-
if (!oldCols.has(col)) {
|
|
163
|
-
columnDiffs.push({
|
|
164
|
-
type: "add",
|
|
165
|
-
table: newTable.name,
|
|
166
|
-
column: col,
|
|
167
|
-
def: newTable.columns[col]._def
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
for (const col of oldCols) {
|
|
172
|
-
if (!newCols.has(col)) {
|
|
173
|
-
columnDiffs.push({
|
|
174
|
-
type: "drop",
|
|
175
|
-
table: oldTable.name,
|
|
176
|
-
column: col,
|
|
177
|
-
oldDef: oldTable.columns[col]._def
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return { addedTables, droppedTables, columnDiffs };
|
|
183
|
-
}
|
|
184
|
-
function generateAddColumn(table2, column, col) {
|
|
185
|
-
let sql = `ALTER TABLE ${table2} ADD COLUMN ${column} ${columnTypeToSQL(col)}`;
|
|
186
|
-
if (!col.nullable) {
|
|
187
|
-
sql += " NOT NULL";
|
|
188
|
-
}
|
|
189
|
-
sql += defaultClause(col);
|
|
190
|
-
if (col.references) {
|
|
191
|
-
sql += ` REFERENCES ${col.references.table}(${col.references.column})`;
|
|
192
|
-
if (col.onDeleteAction) {
|
|
193
|
-
sql += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return `${sql};`;
|
|
197
|
-
}
|
|
198
|
-
function generateDropColumn(table2, column) {
|
|
199
|
-
return `ALTER TABLE ${table2} DROP COLUMN ${column};`;
|
|
200
|
-
}
|
|
201
|
-
function generateDiffMigration(oldSchema, newSchema) {
|
|
202
|
-
const { addedTables, droppedTables, columnDiffs } = diffSchemas(oldSchema, newSchema);
|
|
203
|
-
if (addedTables.length === 0 && droppedTables.length === 0 && columnDiffs.length === 0) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
const upParts = [];
|
|
207
|
-
const downParts = [];
|
|
208
|
-
const newEnums = generateEnumTypes(
|
|
209
|
-
Object.fromEntries(addedTables.map((t) => [t.name, t]))
|
|
210
|
-
);
|
|
211
|
-
upParts.push(...newEnums);
|
|
212
|
-
for (const table2 of addedTables) {
|
|
213
|
-
upParts.push(generateCreateTable(table2));
|
|
214
|
-
downParts.push(generateDropTable(table2));
|
|
215
|
-
}
|
|
216
|
-
for (const table2 of droppedTables) {
|
|
217
|
-
upParts.push(generateDropTable(table2));
|
|
218
|
-
downParts.push(generateCreateTable(table2));
|
|
219
|
-
}
|
|
220
|
-
for (const diff of columnDiffs) {
|
|
221
|
-
if (diff.type === "add" && diff.def) {
|
|
222
|
-
upParts.push(generateAddColumn(diff.table, diff.column, diff.def));
|
|
223
|
-
downParts.push(generateDropColumn(diff.table, diff.column));
|
|
224
|
-
} else if (diff.type === "drop") {
|
|
225
|
-
upParts.push(generateDropColumn(diff.table, diff.column));
|
|
226
|
-
if (diff.oldDef) {
|
|
227
|
-
downParts.push(generateAddColumn(diff.table, diff.column, diff.oldDef));
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const droppedEnums = generateDropEnumTypes(
|
|
232
|
-
Object.fromEntries(droppedTables.map((t) => [t.name, t]))
|
|
233
|
-
);
|
|
234
|
-
downParts.push(...droppedEnums);
|
|
235
|
-
return {
|
|
236
|
-
up: upParts.join("\n\n"),
|
|
237
|
-
down: downParts.join("\n\n")
|
|
238
|
-
};
|
|
239
|
-
}
|
|
11
|
+
} from "../chunk-B7EUJP5W.js";
|
|
240
12
|
export {
|
|
241
13
|
boolean,
|
|
242
14
|
defineSchema,
|
|
243
15
|
enumType,
|
|
244
|
-
generateDiffMigration,
|
|
245
|
-
generateMigration,
|
|
246
16
|
integer,
|
|
247
17
|
jsonb,
|
|
248
|
-
|
|
18
|
+
makeTypedDB,
|
|
249
19
|
text,
|
|
250
20
|
timestamp,
|
|
251
21
|
uuid
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/generator.ts"],"sourcesContent":["import type { ColumnDef, OnDeleteAction } from \"./columns.js\";\nimport type { SchemaDef, TableDef } from \"./schema.js\";\n\n/** Maps column types to their PostgreSQL SQL equivalents. */\nfunction columnTypeToSQL(col: ColumnDef): string {\n switch (col.type) {\n case \"uuid\":\n return \"UUID\";\n case \"text\":\n return \"TEXT\";\n case \"integer\":\n return \"INTEGER\";\n case \"boolean\":\n return \"BOOLEAN\";\n case \"timestamp\":\n return \"TIMESTAMPTZ\";\n case \"jsonb\":\n return \"JSONB\";\n case \"enum\":\n return col.enumName ?? \"TEXT\";\n default:\n return \"TEXT\";\n }\n}\n\n/** Generates the DEFAULT clause for a column. */\nfunction defaultClause(col: ColumnDef): string {\n if (col.defaultRandom) {\n return \" DEFAULT gen_random_uuid()\";\n }\n if (col.defaultNow) {\n return \" DEFAULT now()\";\n }\n if (col.defaultValue !== undefined) {\n if (typeof col.defaultValue === \"string\") {\n // Escape single quotes in string defaults\n const escaped = col.defaultValue.replace(/'/g, \"''\");\n return ` DEFAULT '${escaped}'`;\n }\n if (typeof col.defaultValue === \"boolean\") {\n return ` DEFAULT ${col.defaultValue ? \"true\" : \"false\"}`;\n }\n if (typeof col.defaultValue === \"object\" && col.defaultValue !== null) {\n const escaped = JSON.stringify(col.defaultValue).replace(/'/g, \"''\");\n return ` DEFAULT '${escaped}'::jsonb`;\n }\n return ` DEFAULT ${col.defaultValue}`;\n }\n return \"\";\n}\n\n/** Maps OnDeleteAction to SQL. */\nfunction onDeleteSQL(action: OnDeleteAction): string {\n switch (action) {\n case \"cascade\":\n return \"CASCADE\";\n case \"set null\":\n return \"SET NULL\";\n case \"restrict\":\n return \"RESTRICT\";\n case \"no action\":\n return \"NO ACTION\";\n }\n}\n\n/** Generates CREATE TYPE statements for enum columns. */\nfunction generateEnumTypes(tables: Record<string, TableDef>): string[] {\n const enums = new Map<string, string[]>();\n for (const tableDef of Object.values(tables)) {\n for (const col of Object.values(tableDef.columns)) {\n if (col._def.type === \"enum\" && col._def.enumName && col._def.enumValues) {\n enums.set(col._def.enumName, col._def.enumValues);\n }\n }\n }\n\n return Array.from(enums.entries()).map(([name, values]) => {\n const vals = values.map((v) => `'${v.replace(/'/g, \"''\")}'`).join(\", \");\n return `CREATE TYPE ${name} AS ENUM (${vals});`;\n });\n}\n\n/** Generates a CREATE TABLE statement for a single table. */\nfunction generateCreateTable(tableDef: TableDef): string {\n const lines: string[] = [];\n\n for (const [colName, colBuilder] of Object.entries(tableDef.columns)) {\n const col = colBuilder._def;\n let line = ` ${colName} ${columnTypeToSQL(col)}`;\n\n if (col.primaryKey) {\n line += \" PRIMARY KEY\";\n }\n\n if (!col.nullable && !col.primaryKey) {\n line += \" NOT NULL\";\n }\n\n line += defaultClause(col);\n\n if (col.references) {\n line += ` REFERENCES ${col.references.table}(${col.references.column})`;\n if (col.onDeleteAction) {\n line += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;\n }\n }\n\n lines.push(line);\n }\n\n return `CREATE TABLE ${tableDef.name} (\\n${lines.join(\",\\n\")}\\n);`;\n}\n\n/** Generates a DROP TABLE statement (for down migration). */\nfunction generateDropTable(tableDef: TableDef): string {\n return `DROP TABLE IF EXISTS ${tableDef.name};`;\n}\n\n/** Generates DROP TYPE statements for enum columns (for down migration). */\nfunction generateDropEnumTypes(tables: Record<string, TableDef>): string[] {\n const enums = new Set<string>();\n for (const tableDef of Object.values(tables)) {\n for (const col of Object.values(tableDef.columns)) {\n if (col._def.type === \"enum\" && col._def.enumName) {\n enums.add(col._def.enumName);\n }\n }\n }\n return Array.from(enums).map((name) => `DROP TYPE IF EXISTS ${name};`);\n}\n\n/** Result of migration generation. */\nexport interface MigrationResult {\n up: string;\n down: string;\n}\n\n/**\n * Generates a full migration (up + down) from a schema definition.\n * Used for initial schema creation.\n */\nexport function generateMigration(schema: SchemaDef): MigrationResult {\n const upParts: string[] = [];\n const downParts: string[] = [];\n\n // Enum types first (up) / last (down)\n const enumTypes = generateEnumTypes(schema.tables);\n upParts.push(...enumTypes);\n\n // Tables\n for (const tableDef of Object.values(schema.tables)) {\n upParts.push(generateCreateTable(tableDef));\n }\n\n // Down: reverse order — drop tables first, then types\n const tableNames = Object.values(schema.tables);\n for (let i = tableNames.length - 1; i >= 0; i--) {\n downParts.push(generateDropTable(tableNames[i]!));\n }\n downParts.push(...generateDropEnumTypes(schema.tables));\n\n return {\n up: upParts.join(\"\\n\\n\"),\n down: downParts.join(\"\\n\\n\"),\n };\n}\n\n/** Column diff operation. */\ninterface ColumnDiff {\n type: \"add\" | \"drop\" | \"alter\";\n table: string;\n column: string;\n def?: ColumnDef;\n oldDef?: ColumnDef;\n}\n\n/** Computes column-level diffs between two schemas. */\nfunction diffSchemas(\n oldSchema: SchemaDef,\n newSchema: SchemaDef,\n): { addedTables: TableDef[]; droppedTables: TableDef[]; columnDiffs: ColumnDiff[] } {\n const addedTables: TableDef[] = [];\n const droppedTables: TableDef[] = [];\n const columnDiffs: ColumnDiff[] = [];\n\n const oldTableNames = new Set(Object.keys(oldSchema.tables));\n const newTableNames = new Set(Object.keys(newSchema.tables));\n\n // New tables\n for (const name of newTableNames) {\n if (!oldTableNames.has(name)) {\n addedTables.push(newSchema.tables[name]!);\n }\n }\n\n // Dropped tables\n for (const name of oldTableNames) {\n if (!newTableNames.has(name)) {\n droppedTables.push(oldSchema.tables[name]!);\n }\n }\n\n // Column-level diffs for existing tables\n for (const name of newTableNames) {\n if (!oldTableNames.has(name)) continue;\n\n const oldTable = oldSchema.tables[name]!;\n const newTable = newSchema.tables[name]!;\n const oldCols = new Set(Object.keys(oldTable.columns));\n const newCols = new Set(Object.keys(newTable.columns));\n\n for (const col of newCols) {\n if (!oldCols.has(col)) {\n columnDiffs.push({\n type: \"add\",\n table: newTable.name,\n column: col,\n def: newTable.columns[col]!._def,\n });\n }\n }\n\n for (const col of oldCols) {\n if (!newCols.has(col)) {\n columnDiffs.push({\n type: \"drop\",\n table: oldTable.name,\n column: col,\n oldDef: oldTable.columns[col]!._def,\n });\n }\n }\n }\n\n return { addedTables, droppedTables, columnDiffs };\n}\n\n/** Generates an ALTER TABLE ADD COLUMN statement. */\nfunction generateAddColumn(table: string, column: string, col: ColumnDef): string {\n let sql = `ALTER TABLE ${table} ADD COLUMN ${column} ${columnTypeToSQL(col)}`;\n if (!col.nullable) {\n sql += \" NOT NULL\";\n }\n sql += defaultClause(col);\n if (col.references) {\n sql += ` REFERENCES ${col.references.table}(${col.references.column})`;\n if (col.onDeleteAction) {\n sql += ` ON DELETE ${onDeleteSQL(col.onDeleteAction)}`;\n }\n }\n return `${sql};`;\n}\n\n/** Generates an ALTER TABLE DROP COLUMN statement. */\nfunction generateDropColumn(table: string, column: string): string {\n return `ALTER TABLE ${table} DROP COLUMN ${column};`;\n}\n\n/**\n * Generates a diff migration between two schemas.\n * Returns null if there are no changes.\n */\nexport function generateDiffMigration(\n oldSchema: SchemaDef,\n newSchema: SchemaDef,\n): MigrationResult | null {\n const { addedTables, droppedTables, columnDiffs } = diffSchemas(oldSchema, newSchema);\n\n if (addedTables.length === 0 && droppedTables.length === 0 && columnDiffs.length === 0) {\n return null;\n }\n\n const upParts: string[] = [];\n const downParts: string[] = [];\n\n // New enum types from added tables\n const newEnums = generateEnumTypes(\n Object.fromEntries(addedTables.map((t) => [t.name, t])),\n );\n upParts.push(...newEnums);\n\n // New tables\n for (const table of addedTables) {\n upParts.push(generateCreateTable(table));\n downParts.push(generateDropTable(table));\n }\n\n // Dropped tables\n for (const table of droppedTables) {\n upParts.push(generateDropTable(table));\n downParts.push(generateCreateTable(table));\n }\n\n // Column diffs\n for (const diff of columnDiffs) {\n if (diff.type === \"add\" && diff.def) {\n upParts.push(generateAddColumn(diff.table, diff.column, diff.def));\n downParts.push(generateDropColumn(diff.table, diff.column));\n } else if (diff.type === \"drop\") {\n upParts.push(generateDropColumn(diff.table, diff.column));\n if (diff.oldDef) {\n downParts.push(generateAddColumn(diff.table, diff.column, diff.oldDef));\n }\n }\n }\n\n // Drop enum types from dropped tables (down)\n const droppedEnums = generateDropEnumTypes(\n Object.fromEntries(droppedTables.map((t) => [t.name, t])),\n );\n downParts.push(...droppedEnums);\n\n return {\n up: upParts.join(\"\\n\\n\"),\n down: downParts.join(\"\\n\\n\"),\n };\n}\n"],"mappings":"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","names":["table"]}
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ZodSchema, z } from 'zod';
|
|
2
|
-
import { S as SchemaDef } from './schema-BqfEhIC0.js';
|
|
3
2
|
|
|
4
3
|
/** Supported HTTP methods for endpoints. */
|
|
5
4
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
6
5
|
/** Authenticated user attached to the request context. */
|
|
7
6
|
interface User {
|
|
8
7
|
id: string;
|
|
9
|
-
email
|
|
8
|
+
/** User's email, if they signed up with one (absent for phone-only users). */
|
|
9
|
+
email?: string;
|
|
10
10
|
role: string;
|
|
11
11
|
metadata: Record<string, unknown>;
|
|
12
12
|
}
|
|
@@ -54,10 +54,10 @@ declare function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler;
|
|
|
54
54
|
* 1. Directly: `throw new HttpError(404, "todo_not_found", "No such todo")`.
|
|
55
55
|
* Surfaces on the wire (and to iOS) as `BackendError.server(code, status,
|
|
56
56
|
* message, requestId)`.
|
|
57
|
-
* 2. Via `
|
|
58
|
-
* `
|
|
59
|
-
* one, and the CLI codegen emits a typed `<Endpoint>.Error` enum so
|
|
60
|
-
* callers can `catch <Endpoint>.Error.<case>` directly.
|
|
57
|
+
* 2. Via `req.errors.<name>(data?)` for declared errors — see a handler's
|
|
58
|
+
* `errors` map (`defineHandler`). The endpoint's OpenAPI spec describes
|
|
59
|
+
* each one, and the CLI codegen emits a typed `<Endpoint>.Error` enum so
|
|
60
|
+
* iOS callers can `catch <Endpoint>.Error.<case>` directly.
|
|
61
61
|
*
|
|
62
62
|
* The optional `data` field carries a structured payload alongside the
|
|
63
63
|
* standard envelope — used by declared errors that need to ship extra context
|
|
@@ -1349,20 +1349,19 @@ type ErrorThrowers<TErrors extends ErrorMap | undefined> = TErrors extends Error
|
|
|
1349
1349
|
* error throwers. Services (`Database`, `Documents`, `Cache`, …) are NOT on
|
|
1350
1350
|
* the request: import them directly from `@palbase/backend` as singletons.
|
|
1351
1351
|
*
|
|
1352
|
-
* import {
|
|
1352
|
+
* import { defineHandler, Database } from "@palbase/backend";
|
|
1353
1353
|
*
|
|
1354
|
-
* export default
|
|
1355
|
-
* method: "POST",
|
|
1354
|
+
* export default defineHandler({
|
|
1356
1355
|
* handler: async (req) => Database.insert("todos", { title: req.input.title }),
|
|
1357
1356
|
* });
|
|
1358
1357
|
*
|
|
1359
1358
|
* Generic parameters:
|
|
1360
1359
|
* - `TInput` — the validated `input` type (inferred from the `input` Zod
|
|
1361
|
-
* schema by `
|
|
1360
|
+
* schema by `defineHandler`). The user-facing form is single-generic:
|
|
1362
1361
|
* `PBRequest<TodoInput>`.
|
|
1363
1362
|
* - `TAuthed` — whether `user` is non-null. DEFAULTS to `true` (the common
|
|
1364
1363
|
* case; the auth pipeline returns 401 before the handler when auth is
|
|
1365
|
-
* required, so a non-null `user` is runtime-honest). `
|
|
1364
|
+
* required, so a non-null `user` is runtime-honest). `defineHandler` passes
|
|
1366
1365
|
* `IsAuthed<TAuth>` here, so `auth: false` → `User | null`.
|
|
1367
1366
|
* - `TErrors` — the declared `errors` map, typing `req.errors.<name>(...)`.
|
|
1368
1367
|
*/
|
|
@@ -1377,7 +1376,7 @@ interface PBRequest<TInput = unknown, TAuthed extends boolean = true, TErrors ex
|
|
|
1377
1376
|
headers: Record<string, string>;
|
|
1378
1377
|
/** Authenticated user. Non-null (`User`) by default; `User | null` only when
|
|
1379
1378
|
* the endpoint's `auth` config disables enforcement (driven by `TAuthed`,
|
|
1380
|
-
* which `
|
|
1379
|
+
* which `defineHandler` computes from the `auth` literal via {@link IsAuthed}). */
|
|
1381
1380
|
user: TAuthed extends true ? User : User | null;
|
|
1382
1381
|
/** Calling-client metadata derived from request headers (all nullable). */
|
|
1383
1382
|
client: ClientInfo;
|
|
@@ -1392,7 +1391,7 @@ interface PBRequest<TInput = unknown, TAuthed extends boolean = true, TErrors ex
|
|
|
1392
1391
|
/** W3C span id for this handler invocation. */
|
|
1393
1392
|
spanId: string;
|
|
1394
1393
|
/** Typed throwers for the endpoint's declared errors. Empty when the
|
|
1395
|
-
* `errors` block is absent on `
|
|
1394
|
+
* `errors` block is absent on `defineHandler`. */
|
|
1396
1395
|
errors: ErrorThrowers<TErrors>;
|
|
1397
1396
|
}
|
|
1398
1397
|
/** Middleware function signature — uses MiddlewareContext (no input, not yet validated). */
|
|
@@ -1407,64 +1406,27 @@ type AuthSpec = boolean | Partial<AuthConfig>;
|
|
|
1407
1406
|
/** Compute, at the type level, whether an endpoint authenticates its caller —
|
|
1408
1407
|
* i.e. whether `req.user` should be `User` (non-null) instead of `User | null`.
|
|
1409
1408
|
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
* `
|
|
1413
|
-
* `auth`
|
|
1409
|
+
* SECURE BY DEFAULT — mirrors the runtime (loader.go DefaultAuthConfig +
|
|
1410
|
+
* pipeline/auth.go): an endpoint requires auth UNLESS it explicitly opts out.
|
|
1411
|
+
* `req.user` is nullable ONLY for `auth: false` or `auth: { required: false }`.
|
|
1412
|
+
* Omitting `auth` means AUTH REQUIRED (non-null `req.user`), so a handler that
|
|
1413
|
+
* forgets `auth` fails safe (401) instead of silently exposing data.
|
|
1414
1414
|
*
|
|
1415
|
-
* | `TAuth`
|
|
1416
|
-
*
|
|
1417
|
-
* | `undefined`
|
|
1418
|
-
* | `true`
|
|
1419
|
-
* | `false`
|
|
1420
|
-
* | `{ required: true }`
|
|
1421
|
-
* | `{ required: false }`
|
|
1422
|
-
* | `{ role: 'admin' }` (no `required`) | `true`
|
|
1415
|
+
* | `TAuth` | `IsAuthed<TAuth>` |
|
|
1416
|
+
* |----------------------------------|-------------------|
|
|
1417
|
+
* | omitted (`undefined`) | `true` (secure) |
|
|
1418
|
+
* | `true` | `true` |
|
|
1419
|
+
* | `false` | `false` (public) |
|
|
1420
|
+
* | `{ required: true }` | `true` |
|
|
1421
|
+
* | `{ required: false }` | `false` (public) |
|
|
1422
|
+
* | `{ role: 'admin' }` (no `required`) | `true` |
|
|
1423
1423
|
*
|
|
1424
|
-
* Order matters: the `{ required: false }` branch is checked first so the
|
|
1425
|
-
*
|
|
1426
|
-
*
|
|
1427
|
-
* "required omitted ⇒ required" corner case).
|
|
1424
|
+
* Order matters: the `{ required: false }` branch is checked first so the object
|
|
1425
|
+
* case can't swallow it; `true`/`false` literals next; the catch-all (omitted)
|
|
1426
|
+
* resolves to `true` (secure-by-default).
|
|
1428
1427
|
*/
|
|
1429
1428
|
type IsAuthed<TAuth> = TAuth extends {
|
|
1430
1429
|
required: false;
|
|
1431
|
-
} ? false : TAuth extends true ? true : TAuth extends false ? false : TAuth extends object ? true :
|
|
1432
|
-
/** Configuration for defining an endpoint.
|
|
1433
|
-
*
|
|
1434
|
-
* `TSchema` — optional `SchemaDef` carried on the `schema` field. The runtime
|
|
1435
|
-
* uses it to wire a typed `.tables.*` API; authors opt in per endpoint with
|
|
1436
|
-
* `typedDatabase(schema)` (see runtime.ts).
|
|
1437
|
-
*
|
|
1438
|
-
* `TAuth` — captures the literal type of the `auth` field (via the `const`
|
|
1439
|
-
* type parameter on `defineEndpoint`) so the handler's `req.user` can be
|
|
1440
|
-
* narrowed to non-null `User` when auth is required. See {@link IsAuthed}.
|
|
1441
|
-
*
|
|
1442
|
-
* `TErrors` — captures the literal `errors` map (via the `const` type
|
|
1443
|
-
* parameter on `defineEndpoint`) so `req.errors.<name>(...)` is typed per
|
|
1444
|
-
* declared entry. The OpenAPI generator emits each one as a discriminated
|
|
1445
|
-
* response under `responses[<status>]`, and the CLI codegen lowers them to
|
|
1446
|
-
* a typed `<Endpoint>.Error` enum on iOS.
|
|
1447
|
-
*/
|
|
1448
|
-
interface EndpointConfig<TInputSchema extends ZodSchema = ZodSchema, TOutputSchema extends ZodSchema = ZodSchema, TSchema extends SchemaDef | undefined = undefined, TAuth extends AuthSpec | undefined = undefined, TErrors extends ErrorMap | undefined = undefined> {
|
|
1449
|
-
method: HttpMethod;
|
|
1450
|
-
auth?: TAuth;
|
|
1451
|
-
rateLimit?: RateLimitConfig;
|
|
1452
|
-
input?: TInputSchema;
|
|
1453
|
-
output?: TOutputSchema;
|
|
1454
|
-
schema?: TSchema;
|
|
1455
|
-
errors?: TErrors;
|
|
1456
|
-
middleware?: Middleware[];
|
|
1457
|
-
handler: (req: PBRequest<z.infer<TInputSchema>, IsAuthed<TAuth>, TErrors>) => Promise<z.infer<TOutputSchema>>;
|
|
1458
|
-
}
|
|
1459
|
-
/** Define a type-safe endpoint. The input schema infers the `req.input` type.
|
|
1460
|
-
* Pass a `schema` (from `defineSchema`) and wrap `Database` with
|
|
1461
|
-
* `typedDatabase(schema)` in the handler for a typed `.tables.*` API.
|
|
1462
|
-
*
|
|
1463
|
-
* The `const TAuth` and `const TErrors` type parameters capture the `auth`
|
|
1464
|
-
* and `errors` fields as literals, so `req.user` narrows to non-null `User`
|
|
1465
|
-
* when auth is enforced and `req.errors.<name>(...)` is typed per declared
|
|
1466
|
-
* entry.
|
|
1467
|
-
*/
|
|
1468
|
-
declare function defineEndpoint<TInputSchema extends ZodSchema, TOutputSchema extends ZodSchema, TSchema extends SchemaDef | undefined = undefined, const TAuth extends AuthSpec | undefined = undefined, const TErrors extends ErrorMap | undefined = undefined>(config: EndpointConfig<TInputSchema, TOutputSchema, TSchema, TAuth, TErrors>): EndpointConfig<TInputSchema, TOutputSchema, TSchema, TAuth, TErrors>;
|
|
1430
|
+
} ? false : TAuth extends true ? true : TAuth extends false ? false : TAuth extends object ? true : true;
|
|
1469
1431
|
|
|
1470
|
-
export { type
|
|
1432
|
+
export { type PalbaseEventsQueryInput as $, type AuthSpec as A, type PalbaseCohortQueryInput as B, type CacheClient as C, type DBClient as D, type ErrorMap as E, type FileContext as F, type PalbaseCohortResult as G, HttpError as H, type IsAuthed as I, type PalbaseCollectionRef as J, type PalbaseCountQueryInput as K, type Logger as L, type Middleware as M, type PalbaseCountResult as N, type PalbaseCreateLinkParams as O, type PBRequest as P, type QueueClient as Q, type RateLimitConfig as R, type PalbaseDeviceInfo as S, type PalbaseDeviceTokenView as T, type User as U, type PalbaseDocumentRef as V, type PalbaseDocumentSnapshot as W, type PalbaseEmailClient as X, type PalbaseEmailSendParams as Y, type PalbaseEmailSendResponse as Z, type PalbaseEventNamesResult as _, type PalbaseModuleClients as a, type PalbaseEventsResult as a0, type PalbaseFileObject as a1, type PalbaseFlag as a2, type PalbaseFlagContext as a3, type PalbaseFlagVariant as a4, type PalbaseFunctionsClient as a5, type PalbaseFunnelQueryInput as a6, type PalbaseFunnelResult as a7, type PalbaseIdentifyTraits as a8, type PalbaseInboxClient as a9, type PalbaseRealtimeClient as aA, type PalbaseRealtimeMessage as aB, type PalbaseRegisterDeviceParams as aC, type PalbaseResult as aD, type PalbaseRetentionQueryInput as aE, type PalbaseRetentionResult as aF, type PalbaseSession as aG, type PalbaseSignedUrlResponse as aH, type PalbaseSmsClient as aI, type PalbaseSmsSendParams as aJ, type PalbaseSmsSendResponse as aK, type PalbaseTransformOptions as aL, type PalbaseUpdateLinkParams as aM, type PalbaseUploadOptions as aN, type PalbaseUser as aO, type PalbaseUserDetailResult as aP, type PalbaseUsersQueryInput as aQ, type PalbaseUsersResult as aR, type PalbaseVerifyRequestSignatureParams as aS, type PalbaseWhereOperator as aT, type TxClient as aU, defineMiddleware as aV, type PalbaseInboxListOptions as aa, type PalbaseInboxListResult as ab, type PalbaseInboxMessage as ac, type PalbaseInboxSendParams as ad, type PalbaseInboxSendResponse as ae, type PalbaseInitialLink as af, type PalbaseInvokeOptions as ag, type PalbaseLink as ah, type PalbaseLinkAnalytics as ai, type PalbaseLinkDetails as aj, type PalbaseLinksClient as ak, type PalbaseListLinksOptions as al, type PalbaseListLinksResult as am, type PalbaseListOptions as an, type PalbaseMatchParams as ao, type PalbaseMultiChannelResponse as ap, type PalbaseOverviewResult as aq, type PalbasePreferences as ar, type PalbasePreferencesClient as as, type PalbasePublicUrlResponse as at, type PalbasePushClient as au, type PalbasePushSendParams as av, type PalbasePushSendResponse as aw, type PalbaseQrCodeOptions as ax, type PalbaseQuerySnapshot as ay, type PalbaseRealtimeChannel as az, type PalbaseDocsClient as b, type PalbaseFlagsClient as c, type PalbaseNotificationsClient as d, type PalbaseStorageClient as e, type AuthConfig as f, type ClientInfo as g, type ErrorDef as h, type ErrorThrowers as i, type HttpMethod as j, type MiddlewareContext as k, type MiddlewareHandler as l, type PalbaseAnalyticsClient as m, type PalbaseAnalyticsManagementNamespace as n, type PalbaseAnalyticsProperties as o, type PalbaseAnalyticsQueryNamespace as p, type PalbaseAttestAndroidParams as q, type PalbaseAttestAndroidResult as r, type PalbaseAttestiOSParams as s, type PalbaseAttestiOSResult as t, type PalbaseAuthClient as u, type PalbaseBindDeviceParams as v, type PalbaseBucketClient as w, type PalbaseCmsClient as x, type PalbaseCmsFindOneOptions as y, type PalbaseCmsFindOptions as z };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ZodSchema, z } from 'zod';
|
|
2
|
-
import { S as SchemaDef } from './schema-BqfEhIC0.cjs';
|
|
3
2
|
|
|
4
3
|
/** Supported HTTP methods for endpoints. */
|
|
5
4
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
6
5
|
/** Authenticated user attached to the request context. */
|
|
7
6
|
interface User {
|
|
8
7
|
id: string;
|
|
9
|
-
email
|
|
8
|
+
/** User's email, if they signed up with one (absent for phone-only users). */
|
|
9
|
+
email?: string;
|
|
10
10
|
role: string;
|
|
11
11
|
metadata: Record<string, unknown>;
|
|
12
12
|
}
|
|
@@ -54,10 +54,10 @@ declare function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler;
|
|
|
54
54
|
* 1. Directly: `throw new HttpError(404, "todo_not_found", "No such todo")`.
|
|
55
55
|
* Surfaces on the wire (and to iOS) as `BackendError.server(code, status,
|
|
56
56
|
* message, requestId)`.
|
|
57
|
-
* 2. Via `
|
|
58
|
-
* `
|
|
59
|
-
* one, and the CLI codegen emits a typed `<Endpoint>.Error` enum so
|
|
60
|
-
* callers can `catch <Endpoint>.Error.<case>` directly.
|
|
57
|
+
* 2. Via `req.errors.<name>(data?)` for declared errors — see a handler's
|
|
58
|
+
* `errors` map (`defineHandler`). The endpoint's OpenAPI spec describes
|
|
59
|
+
* each one, and the CLI codegen emits a typed `<Endpoint>.Error` enum so
|
|
60
|
+
* iOS callers can `catch <Endpoint>.Error.<case>` directly.
|
|
61
61
|
*
|
|
62
62
|
* The optional `data` field carries a structured payload alongside the
|
|
63
63
|
* standard envelope — used by declared errors that need to ship extra context
|
|
@@ -1349,20 +1349,19 @@ type ErrorThrowers<TErrors extends ErrorMap | undefined> = TErrors extends Error
|
|
|
1349
1349
|
* error throwers. Services (`Database`, `Documents`, `Cache`, …) are NOT on
|
|
1350
1350
|
* the request: import them directly from `@palbase/backend` as singletons.
|
|
1351
1351
|
*
|
|
1352
|
-
* import {
|
|
1352
|
+
* import { defineHandler, Database } from "@palbase/backend";
|
|
1353
1353
|
*
|
|
1354
|
-
* export default
|
|
1355
|
-
* method: "POST",
|
|
1354
|
+
* export default defineHandler({
|
|
1356
1355
|
* handler: async (req) => Database.insert("todos", { title: req.input.title }),
|
|
1357
1356
|
* });
|
|
1358
1357
|
*
|
|
1359
1358
|
* Generic parameters:
|
|
1360
1359
|
* - `TInput` — the validated `input` type (inferred from the `input` Zod
|
|
1361
|
-
* schema by `
|
|
1360
|
+
* schema by `defineHandler`). The user-facing form is single-generic:
|
|
1362
1361
|
* `PBRequest<TodoInput>`.
|
|
1363
1362
|
* - `TAuthed` — whether `user` is non-null. DEFAULTS to `true` (the common
|
|
1364
1363
|
* case; the auth pipeline returns 401 before the handler when auth is
|
|
1365
|
-
* required, so a non-null `user` is runtime-honest). `
|
|
1364
|
+
* required, so a non-null `user` is runtime-honest). `defineHandler` passes
|
|
1366
1365
|
* `IsAuthed<TAuth>` here, so `auth: false` → `User | null`.
|
|
1367
1366
|
* - `TErrors` — the declared `errors` map, typing `req.errors.<name>(...)`.
|
|
1368
1367
|
*/
|
|
@@ -1377,7 +1376,7 @@ interface PBRequest<TInput = unknown, TAuthed extends boolean = true, TErrors ex
|
|
|
1377
1376
|
headers: Record<string, string>;
|
|
1378
1377
|
/** Authenticated user. Non-null (`User`) by default; `User | null` only when
|
|
1379
1378
|
* the endpoint's `auth` config disables enforcement (driven by `TAuthed`,
|
|
1380
|
-
* which `
|
|
1379
|
+
* which `defineHandler` computes from the `auth` literal via {@link IsAuthed}). */
|
|
1381
1380
|
user: TAuthed extends true ? User : User | null;
|
|
1382
1381
|
/** Calling-client metadata derived from request headers (all nullable). */
|
|
1383
1382
|
client: ClientInfo;
|
|
@@ -1392,7 +1391,7 @@ interface PBRequest<TInput = unknown, TAuthed extends boolean = true, TErrors ex
|
|
|
1392
1391
|
/** W3C span id for this handler invocation. */
|
|
1393
1392
|
spanId: string;
|
|
1394
1393
|
/** Typed throwers for the endpoint's declared errors. Empty when the
|
|
1395
|
-
* `errors` block is absent on `
|
|
1394
|
+
* `errors` block is absent on `defineHandler`. */
|
|
1396
1395
|
errors: ErrorThrowers<TErrors>;
|
|
1397
1396
|
}
|
|
1398
1397
|
/** Middleware function signature — uses MiddlewareContext (no input, not yet validated). */
|
|
@@ -1407,64 +1406,27 @@ type AuthSpec = boolean | Partial<AuthConfig>;
|
|
|
1407
1406
|
/** Compute, at the type level, whether an endpoint authenticates its caller —
|
|
1408
1407
|
* i.e. whether `req.user` should be `User` (non-null) instead of `User | null`.
|
|
1409
1408
|
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
* `
|
|
1413
|
-
* `auth`
|
|
1409
|
+
* SECURE BY DEFAULT — mirrors the runtime (loader.go DefaultAuthConfig +
|
|
1410
|
+
* pipeline/auth.go): an endpoint requires auth UNLESS it explicitly opts out.
|
|
1411
|
+
* `req.user` is nullable ONLY for `auth: false` or `auth: { required: false }`.
|
|
1412
|
+
* Omitting `auth` means AUTH REQUIRED (non-null `req.user`), so a handler that
|
|
1413
|
+
* forgets `auth` fails safe (401) instead of silently exposing data.
|
|
1414
1414
|
*
|
|
1415
|
-
* | `TAuth`
|
|
1416
|
-
*
|
|
1417
|
-
* | `undefined`
|
|
1418
|
-
* | `true`
|
|
1419
|
-
* | `false`
|
|
1420
|
-
* | `{ required: true }`
|
|
1421
|
-
* | `{ required: false }`
|
|
1422
|
-
* | `{ role: 'admin' }` (no `required`) | `true`
|
|
1415
|
+
* | `TAuth` | `IsAuthed<TAuth>` |
|
|
1416
|
+
* |----------------------------------|-------------------|
|
|
1417
|
+
* | omitted (`undefined`) | `true` (secure) |
|
|
1418
|
+
* | `true` | `true` |
|
|
1419
|
+
* | `false` | `false` (public) |
|
|
1420
|
+
* | `{ required: true }` | `true` |
|
|
1421
|
+
* | `{ required: false }` | `false` (public) |
|
|
1422
|
+
* | `{ role: 'admin' }` (no `required`) | `true` |
|
|
1423
1423
|
*
|
|
1424
|
-
* Order matters: the `{ required: false }` branch is checked first so the
|
|
1425
|
-
*
|
|
1426
|
-
*
|
|
1427
|
-
* "required omitted ⇒ required" corner case).
|
|
1424
|
+
* Order matters: the `{ required: false }` branch is checked first so the object
|
|
1425
|
+
* case can't swallow it; `true`/`false` literals next; the catch-all (omitted)
|
|
1426
|
+
* resolves to `true` (secure-by-default).
|
|
1428
1427
|
*/
|
|
1429
1428
|
type IsAuthed<TAuth> = TAuth extends {
|
|
1430
1429
|
required: false;
|
|
1431
|
-
} ? false : TAuth extends true ? true : TAuth extends false ? false : TAuth extends object ? true :
|
|
1432
|
-
/** Configuration for defining an endpoint.
|
|
1433
|
-
*
|
|
1434
|
-
* `TSchema` — optional `SchemaDef` carried on the `schema` field. The runtime
|
|
1435
|
-
* uses it to wire a typed `.tables.*` API; authors opt in per endpoint with
|
|
1436
|
-
* `typedDatabase(schema)` (see runtime.ts).
|
|
1437
|
-
*
|
|
1438
|
-
* `TAuth` — captures the literal type of the `auth` field (via the `const`
|
|
1439
|
-
* type parameter on `defineEndpoint`) so the handler's `req.user` can be
|
|
1440
|
-
* narrowed to non-null `User` when auth is required. See {@link IsAuthed}.
|
|
1441
|
-
*
|
|
1442
|
-
* `TErrors` — captures the literal `errors` map (via the `const` type
|
|
1443
|
-
* parameter on `defineEndpoint`) so `req.errors.<name>(...)` is typed per
|
|
1444
|
-
* declared entry. The OpenAPI generator emits each one as a discriminated
|
|
1445
|
-
* response under `responses[<status>]`, and the CLI codegen lowers them to
|
|
1446
|
-
* a typed `<Endpoint>.Error` enum on iOS.
|
|
1447
|
-
*/
|
|
1448
|
-
interface EndpointConfig<TInputSchema extends ZodSchema = ZodSchema, TOutputSchema extends ZodSchema = ZodSchema, TSchema extends SchemaDef | undefined = undefined, TAuth extends AuthSpec | undefined = undefined, TErrors extends ErrorMap | undefined = undefined> {
|
|
1449
|
-
method: HttpMethod;
|
|
1450
|
-
auth?: TAuth;
|
|
1451
|
-
rateLimit?: RateLimitConfig;
|
|
1452
|
-
input?: TInputSchema;
|
|
1453
|
-
output?: TOutputSchema;
|
|
1454
|
-
schema?: TSchema;
|
|
1455
|
-
errors?: TErrors;
|
|
1456
|
-
middleware?: Middleware[];
|
|
1457
|
-
handler: (req: PBRequest<z.infer<TInputSchema>, IsAuthed<TAuth>, TErrors>) => Promise<z.infer<TOutputSchema>>;
|
|
1458
|
-
}
|
|
1459
|
-
/** Define a type-safe endpoint. The input schema infers the `req.input` type.
|
|
1460
|
-
* Pass a `schema` (from `defineSchema`) and wrap `Database` with
|
|
1461
|
-
* `typedDatabase(schema)` in the handler for a typed `.tables.*` API.
|
|
1462
|
-
*
|
|
1463
|
-
* The `const TAuth` and `const TErrors` type parameters capture the `auth`
|
|
1464
|
-
* and `errors` fields as literals, so `req.user` narrows to non-null `User`
|
|
1465
|
-
* when auth is enforced and `req.errors.<name>(...)` is typed per declared
|
|
1466
|
-
* entry.
|
|
1467
|
-
*/
|
|
1468
|
-
declare function defineEndpoint<TInputSchema extends ZodSchema, TOutputSchema extends ZodSchema, TSchema extends SchemaDef | undefined = undefined, const TAuth extends AuthSpec | undefined = undefined, const TErrors extends ErrorMap | undefined = undefined>(config: EndpointConfig<TInputSchema, TOutputSchema, TSchema, TAuth, TErrors>): EndpointConfig<TInputSchema, TOutputSchema, TSchema, TAuth, TErrors>;
|
|
1430
|
+
} ? false : TAuth extends true ? true : TAuth extends false ? false : TAuth extends object ? true : true;
|
|
1469
1431
|
|
|
1470
|
-
export { type
|
|
1432
|
+
export { type PalbaseEventsQueryInput as $, type AuthSpec as A, type PalbaseCohortQueryInput as B, type CacheClient as C, type DBClient as D, type ErrorMap as E, type FileContext as F, type PalbaseCohortResult as G, HttpError as H, type IsAuthed as I, type PalbaseCollectionRef as J, type PalbaseCountQueryInput as K, type Logger as L, type Middleware as M, type PalbaseCountResult as N, type PalbaseCreateLinkParams as O, type PBRequest as P, type QueueClient as Q, type RateLimitConfig as R, type PalbaseDeviceInfo as S, type PalbaseDeviceTokenView as T, type User as U, type PalbaseDocumentRef as V, type PalbaseDocumentSnapshot as W, type PalbaseEmailClient as X, type PalbaseEmailSendParams as Y, type PalbaseEmailSendResponse as Z, type PalbaseEventNamesResult as _, type PalbaseModuleClients as a, type PalbaseEventsResult as a0, type PalbaseFileObject as a1, type PalbaseFlag as a2, type PalbaseFlagContext as a3, type PalbaseFlagVariant as a4, type PalbaseFunctionsClient as a5, type PalbaseFunnelQueryInput as a6, type PalbaseFunnelResult as a7, type PalbaseIdentifyTraits as a8, type PalbaseInboxClient as a9, type PalbaseRealtimeClient as aA, type PalbaseRealtimeMessage as aB, type PalbaseRegisterDeviceParams as aC, type PalbaseResult as aD, type PalbaseRetentionQueryInput as aE, type PalbaseRetentionResult as aF, type PalbaseSession as aG, type PalbaseSignedUrlResponse as aH, type PalbaseSmsClient as aI, type PalbaseSmsSendParams as aJ, type PalbaseSmsSendResponse as aK, type PalbaseTransformOptions as aL, type PalbaseUpdateLinkParams as aM, type PalbaseUploadOptions as aN, type PalbaseUser as aO, type PalbaseUserDetailResult as aP, type PalbaseUsersQueryInput as aQ, type PalbaseUsersResult as aR, type PalbaseVerifyRequestSignatureParams as aS, type PalbaseWhereOperator as aT, type TxClient as aU, defineMiddleware as aV, type PalbaseInboxListOptions as aa, type PalbaseInboxListResult as ab, type PalbaseInboxMessage as ac, type PalbaseInboxSendParams as ad, type PalbaseInboxSendResponse as ae, type PalbaseInitialLink as af, type PalbaseInvokeOptions as ag, type PalbaseLink as ah, type PalbaseLinkAnalytics as ai, type PalbaseLinkDetails as aj, type PalbaseLinksClient as ak, type PalbaseListLinksOptions as al, type PalbaseListLinksResult as am, type PalbaseListOptions as an, type PalbaseMatchParams as ao, type PalbaseMultiChannelResponse as ap, type PalbaseOverviewResult as aq, type PalbasePreferences as ar, type PalbasePreferencesClient as as, type PalbasePublicUrlResponse as at, type PalbasePushClient as au, type PalbasePushSendParams as av, type PalbasePushSendResponse as aw, type PalbaseQrCodeOptions as ax, type PalbaseQuerySnapshot as ay, type PalbaseRealtimeChannel as az, type PalbaseDocsClient as b, type PalbaseFlagsClient as c, type PalbaseNotificationsClient as d, type PalbaseStorageClient as e, type AuthConfig as f, type ClientInfo as g, type ErrorDef as h, type ErrorThrowers as i, type HttpMethod as j, type MiddlewareContext as k, type MiddlewareHandler as l, type PalbaseAnalyticsClient as m, type PalbaseAnalyticsManagementNamespace as n, type PalbaseAnalyticsProperties as o, type PalbaseAnalyticsQueryNamespace as p, type PalbaseAttestAndroidParams as q, type PalbaseAttestAndroidResult as r, type PalbaseAttestiOSParams as s, type PalbaseAttestiOSResult as t, type PalbaseAuthClient as u, type PalbaseBindDeviceParams as v, type PalbaseBucketClient as w, type PalbaseCmsClient as x, type PalbaseCmsFindOneOptions as y, type PalbaseCmsFindOptions as z };
|