@palbase/backend 25.1.0 → 27.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/bin/palbase-backend.cjs +2401 -1039
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +87 -51
- package/dist/bin/palbase-backend.js.map +1 -1
- package/dist/chunk-CGNN2PUH.js +213 -0
- package/dist/chunk-CGNN2PUH.js.map +1 -0
- package/dist/chunk-DRZFQRJI.js +370 -0
- package/dist/chunk-DRZFQRJI.js.map +1 -0
- package/dist/chunk-GYK6QYS4.js +708 -0
- package/dist/chunk-GYK6QYS4.js.map +1 -0
- package/dist/chunk-I3C4PFIW.js +930 -0
- package/dist/chunk-I3C4PFIW.js.map +1 -0
- package/dist/{chunk-VDF2T4AS.js → chunk-OO7R25AI.js} +1213 -591
- package/dist/chunk-OO7R25AI.js.map +1 -0
- package/dist/chunk-TS4U7NBD.js +885 -0
- package/dist/chunk-TS4U7NBD.js.map +1 -0
- package/dist/{chunk-YOY5DFQS.js → chunk-TWX6JTGJ.js} +76 -34
- package/dist/{chunk-YOY5DFQS.js.map → chunk-TWX6JTGJ.js.map} +1 -1
- package/dist/{chunk-35PNTIRN.js → chunk-VVMJEVQP.js} +63 -162
- package/dist/chunk-VVMJEVQP.js.map +1 -0
- package/dist/{chunk-7D4SUZUM.js → chunk-VXPNPVAG.js} +3 -1
- package/dist/db/env.cjs.map +1 -1
- package/dist/db/env.d.cts +2 -2
- package/dist/db/env.d.ts +2 -2
- package/dist/db/index.cjs +754 -344
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +7 -4
- package/dist/engine/index.cjs +2339 -1006
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +6 -6
- package/dist/engine/index.d.ts +6 -6
- package/dist/engine/index.js +7 -6
- package/dist/index-BrvvxSpn.d.ts +4844 -0
- package/dist/index-Bve7BBTL.d.cts +4844 -0
- package/dist/{index-CUomTA3e.d.ts → index-NuzRCuxe.d.ts} +171 -296
- package/dist/{index-ClpDeSos.d.cts → index-VtToZmUm.d.cts} +171 -296
- package/dist/index.cjs +2694 -1169
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -19
- package/dist/index.d.ts +165 -19
- package/dist/index.js +738 -477
- package/dist/index.js.map +1 -1
- package/dist/module-Dl1KFVtc.d.cts +54 -0
- package/dist/module-Dl1KFVtc.d.ts +54 -0
- package/dist/openapi/index.cjs +1330 -484
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +4 -2
- package/dist/openapi/index.d.ts +4 -2
- package/dist/openapi/index.js +1264 -474
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-dZZ5JKYg.d.ts → registry-B0eyOF9x.d.ts} +1 -1
- package/dist/{registry-CC0WBQq6.d.cts → registry-Bk9_rbNd.d.cts} +1 -1
- package/dist/stack.cjs.map +1 -1
- package/dist/test/index.cjs +705 -141
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +30 -4
- package/dist/test/index.d.ts +30 -4
- package/dist/test/index.js +472 -124
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +33 -18
- package/docs/auth.md +1 -1
- package/docs/background.md +2 -2
- package/docs/database.md +221 -50
- package/docs/endpoints.md +3 -4
- package/docs/events.md +3 -3
- package/docs/getting-started.md +1 -1
- package/docs/llms-full.txt +401 -117
- package/docs/migrations.md +2 -2
- package/docs/schema.md +19 -10
- package/docs/services.md +116 -26
- package/package.json +8 -4
- package/stager/generics.js +205 -0
- package/stager/stage.js +39 -3
- package/template/AGENTS.md +110 -72
- package/template/db/public.ts +1 -1
- package/template/{controllers → modules/health}/health.controller.ts +1 -1
- package/template/modules/health/health.module.ts +24 -0
- package/template/modules/notes/note.service.test.ts +49 -0
- package/template/modules/notes/note.service.ts +108 -0
- package/template/{controllers → modules/notes}/notes.controller.ts +17 -11
- package/template/modules/notes/notes.module.ts +37 -0
- package/template/package.json +5 -3
- package/template/scripts/test.sh +33 -0
- package/template/tsconfig.json +29 -30
- package/dist/chunk-35PNTIRN.js.map +0 -1
- package/dist/chunk-CJSKYY76.js +0 -627
- package/dist/chunk-CJSKYY76.js.map +0 -1
- package/dist/chunk-CRQKCRGF.js +0 -276
- package/dist/chunk-CRQKCRGF.js.map +0 -1
- package/dist/chunk-G4R6BTLV.js +0 -662
- package/dist/chunk-G4R6BTLV.js.map +0 -1
- package/dist/chunk-VDF2T4AS.js.map +0 -1
- package/dist/chunk-XABBC7JP.js +0 -55
- package/dist/chunk-XABBC7JP.js.map +0 -1
- package/dist/endpoint-CTEHhb7A.d.ts +0 -2386
- package/dist/endpoint-DYHMo6cC.d.cts +0 -2386
- package/dist/index-CW21M9Z3.d.ts +0 -1222
- package/dist/index-CmBK76nx.d.cts +0 -1222
- package/template/services/note.service.test.ts +0 -45
- package/template/services/note.service.ts +0 -76
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-VXPNPVAG.js.map} +0 -0
- /package/template/{models/notes → modules/notes/dto}/create.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EXTENSION_DEPENDENCIES,
|
|
3
|
+
IndexBuilder,
|
|
3
4
|
PALBASE_EXTENSIONS,
|
|
4
5
|
PolicyBuilder,
|
|
6
|
+
PolicyExprRef,
|
|
5
7
|
TABLE_META,
|
|
6
8
|
bigint,
|
|
7
9
|
boolean,
|
|
8
10
|
defineSchema,
|
|
9
11
|
defineTable,
|
|
10
12
|
enumType,
|
|
13
|
+
exprCtx,
|
|
14
|
+
index,
|
|
11
15
|
installationRef,
|
|
12
16
|
integer,
|
|
13
17
|
isPalbaseExtension,
|
|
14
18
|
jsonb,
|
|
15
|
-
makeTypedDB,
|
|
16
19
|
numeric,
|
|
17
20
|
openai,
|
|
18
21
|
ownedByUser,
|
|
@@ -23,50 +26,61 @@ import {
|
|
|
23
26
|
userRef,
|
|
24
27
|
uuid,
|
|
25
28
|
vector
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-TS4U7NBD.js";
|
|
27
30
|
import {
|
|
28
31
|
defineError,
|
|
29
32
|
getErrorRegistry
|
|
30
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-TWX6JTGJ.js";
|
|
31
34
|
import {
|
|
32
35
|
Cache,
|
|
33
36
|
Database,
|
|
37
|
+
DiError,
|
|
34
38
|
Documents,
|
|
35
39
|
Flags,
|
|
40
|
+
Injectable,
|
|
36
41
|
Log,
|
|
42
|
+
Module,
|
|
37
43
|
Notifications,
|
|
38
44
|
Realtime,
|
|
39
45
|
Secrets,
|
|
40
46
|
Storage,
|
|
47
|
+
__claimInjectables,
|
|
48
|
+
__claimModules,
|
|
41
49
|
__getRuntime,
|
|
42
50
|
__requestALS,
|
|
43
51
|
__resetLifecycleHooks,
|
|
44
52
|
__runStartHooks,
|
|
45
53
|
__runWithRuntime,
|
|
46
54
|
__setRuntime,
|
|
55
|
+
assertNoOrphanEntryPoints,
|
|
56
|
+
buildContainer,
|
|
57
|
+
controllersOf,
|
|
58
|
+
hooksOf,
|
|
59
|
+
jobsOf,
|
|
60
|
+
makeEnvDts,
|
|
47
61
|
onShutdown,
|
|
48
|
-
onStart
|
|
49
|
-
|
|
62
|
+
onStart,
|
|
63
|
+
roomsOf,
|
|
64
|
+
webhooksOf
|
|
65
|
+
} from "./chunk-I3C4PFIW.js";
|
|
66
|
+
import {
|
|
67
|
+
col,
|
|
68
|
+
makeTypedDB,
|
|
69
|
+
sqlFragment,
|
|
70
|
+
toSchemaJSON,
|
|
71
|
+
withRetry
|
|
72
|
+
} from "./chunk-DRZFQRJI.js";
|
|
50
73
|
import {
|
|
51
74
|
TxPlanError,
|
|
52
75
|
TxRefError,
|
|
53
76
|
dec,
|
|
77
|
+
decrement,
|
|
54
78
|
inc,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
} from "./chunk-CJSKYY76.js";
|
|
79
|
+
increment,
|
|
80
|
+
now
|
|
81
|
+
} from "./chunk-GYK6QYS4.js";
|
|
59
82
|
import {
|
|
60
|
-
BadRequest,
|
|
61
|
-
Conflict,
|
|
62
83
|
Controller,
|
|
63
|
-
Forbidden,
|
|
64
|
-
HttpError,
|
|
65
|
-
NotFound,
|
|
66
|
-
PalError,
|
|
67
|
-
TooManyRequests,
|
|
68
|
-
Unauthorized,
|
|
69
|
-
UniqueViolation,
|
|
70
84
|
__resetDefaultAuth,
|
|
71
85
|
__resetRegisteredControllers,
|
|
72
86
|
assertZeroArgConstructor,
|
|
@@ -80,11 +94,30 @@ import {
|
|
|
80
94
|
recordRoute,
|
|
81
95
|
recordThrows,
|
|
82
96
|
resolveEffectiveAuth
|
|
83
|
-
} from "./chunk-
|
|
84
|
-
import
|
|
97
|
+
} from "./chunk-VVMJEVQP.js";
|
|
98
|
+
import {
|
|
99
|
+
BadRequest,
|
|
100
|
+
Conflict,
|
|
101
|
+
DeadlockDetected,
|
|
102
|
+
Forbidden,
|
|
103
|
+
HttpError,
|
|
104
|
+
NotFound,
|
|
105
|
+
PalError,
|
|
106
|
+
SerializationFailure,
|
|
107
|
+
TooManyRequests,
|
|
108
|
+
Unauthorized,
|
|
109
|
+
UniqueViolation,
|
|
110
|
+
isRetryable
|
|
111
|
+
} from "./chunk-CGNN2PUH.js";
|
|
112
|
+
import {
|
|
113
|
+
__name
|
|
114
|
+
} from "./chunk-VXPNPVAG.js";
|
|
85
115
|
|
|
86
116
|
// src/clients/http.ts
|
|
87
117
|
var PalbaseModuleError = class extends Error {
|
|
118
|
+
static {
|
|
119
|
+
__name(this, "PalbaseModuleError");
|
|
120
|
+
}
|
|
88
121
|
code;
|
|
89
122
|
status;
|
|
90
123
|
details;
|
|
@@ -103,7 +136,10 @@ function makeHttpClient(cfg) {
|
|
|
103
136
|
...options.headers ?? {}
|
|
104
137
|
};
|
|
105
138
|
if (cfg.apiKey) headers["apikey"] = cfg.apiKey;
|
|
106
|
-
const init = {
|
|
139
|
+
const init = {
|
|
140
|
+
method,
|
|
141
|
+
headers
|
|
142
|
+
};
|
|
107
143
|
if (options.body !== void 0) {
|
|
108
144
|
if (typeof options.body === "string" || options.body instanceof Uint8Array) {
|
|
109
145
|
init.body = options.body;
|
|
@@ -125,11 +161,7 @@ function makeHttpClient(cfg) {
|
|
|
125
161
|
} catch (err) {
|
|
126
162
|
return {
|
|
127
163
|
data: null,
|
|
128
|
-
error: new PalbaseModuleError(
|
|
129
|
-
"network_error",
|
|
130
|
-
err instanceof Error ? err.message : "Network request failed",
|
|
131
|
-
0
|
|
132
|
-
),
|
|
164
|
+
error: new PalbaseModuleError("network_error", err instanceof Error ? err.message : "Network request failed", 0),
|
|
133
165
|
status: 0
|
|
134
166
|
};
|
|
135
167
|
}
|
|
@@ -152,10 +184,19 @@ function makeHttpClient(cfg) {
|
|
|
152
184
|
status: response.status
|
|
153
185
|
};
|
|
154
186
|
}
|
|
155
|
-
return {
|
|
187
|
+
return {
|
|
188
|
+
data: parsed,
|
|
189
|
+
error: null,
|
|
190
|
+
status: response.status
|
|
191
|
+
};
|
|
156
192
|
}
|
|
157
|
-
|
|
193
|
+
__name(request, "request");
|
|
194
|
+
return {
|
|
195
|
+
baseUrl: cfg.baseUrl,
|
|
196
|
+
request
|
|
197
|
+
};
|
|
158
198
|
}
|
|
199
|
+
__name(makeHttpClient, "makeHttpClient");
|
|
159
200
|
|
|
160
201
|
// src/clients/documents.ts
|
|
161
202
|
var SEGMENT_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -164,27 +205,43 @@ function validateSegment(segment, label) {
|
|
|
164
205
|
throw new Error(`Invalid ${label}: "${segment}". Must match ${SEGMENT_RE.source}`);
|
|
165
206
|
}
|
|
166
207
|
}
|
|
208
|
+
__name(validateSegment, "validateSegment");
|
|
167
209
|
function buildDocumentRef(http, path) {
|
|
168
210
|
return {
|
|
169
211
|
path,
|
|
170
212
|
async set(data) {
|
|
171
|
-
return http.request("PUT", `/v1/docs/${path}`, {
|
|
213
|
+
return http.request("PUT", `/v1/docs/${path}`, {
|
|
214
|
+
body: data
|
|
215
|
+
});
|
|
172
216
|
},
|
|
173
217
|
async get() {
|
|
174
218
|
const response = await http.request("GET", `/v1/docs/${path}`);
|
|
175
|
-
if (response.error) return {
|
|
219
|
+
if (response.error) return {
|
|
220
|
+
data: null,
|
|
221
|
+
error: response.error,
|
|
222
|
+
status: response.status
|
|
223
|
+
};
|
|
176
224
|
const raw2 = response.data ?? {};
|
|
177
225
|
const exists = raw2.exists !== void 0 ? raw2.exists : Boolean(raw2.data || raw2.id);
|
|
178
226
|
const segments = path.split("/");
|
|
179
227
|
const id = raw2.id || segments[segments.length - 1] || "";
|
|
180
228
|
return {
|
|
181
|
-
data: {
|
|
229
|
+
data: {
|
|
230
|
+
id,
|
|
231
|
+
exists,
|
|
232
|
+
data: /* @__PURE__ */ __name(() => raw2.data, "data"),
|
|
233
|
+
ref: {
|
|
234
|
+
path
|
|
235
|
+
}
|
|
236
|
+
},
|
|
182
237
|
error: null,
|
|
183
238
|
status: response.status
|
|
184
239
|
};
|
|
185
240
|
},
|
|
186
241
|
async update(data) {
|
|
187
|
-
return http.request("PATCH", `/v1/docs/${path}`, {
|
|
242
|
+
return http.request("PATCH", `/v1/docs/${path}`, {
|
|
243
|
+
body: data
|
|
244
|
+
});
|
|
188
245
|
},
|
|
189
246
|
async delete() {
|
|
190
247
|
return http.request("DELETE", `/v1/docs/${path}`);
|
|
@@ -195,23 +252,34 @@ function buildDocumentRef(http, path) {
|
|
|
195
252
|
}
|
|
196
253
|
};
|
|
197
254
|
}
|
|
198
|
-
|
|
255
|
+
__name(buildDocumentRef, "buildDocumentRef");
|
|
256
|
+
function buildCollectionRef(http, path, state = {
|
|
257
|
+
where: [],
|
|
258
|
+
orderBy: []
|
|
259
|
+
}) {
|
|
199
260
|
function snapshot(doc) {
|
|
200
261
|
return {
|
|
201
262
|
id: doc.id,
|
|
202
263
|
exists: true,
|
|
203
|
-
data: () => doc.data,
|
|
204
|
-
ref: {
|
|
264
|
+
data: /* @__PURE__ */ __name(() => doc.data, "data"),
|
|
265
|
+
ref: {
|
|
266
|
+
path: `${path}/${doc.id}`
|
|
267
|
+
}
|
|
205
268
|
};
|
|
206
269
|
}
|
|
270
|
+
__name(snapshot, "snapshot");
|
|
207
271
|
function querySnapshot(docs) {
|
|
208
272
|
return {
|
|
209
273
|
docs,
|
|
210
274
|
empty: docs.length === 0,
|
|
211
275
|
size: docs.length,
|
|
212
|
-
docChanges: () => docs.map((doc) => ({
|
|
276
|
+
docChanges: /* @__PURE__ */ __name(() => docs.map((doc) => ({
|
|
277
|
+
type: "added",
|
|
278
|
+
doc
|
|
279
|
+
})), "docChanges")
|
|
213
280
|
};
|
|
214
281
|
}
|
|
282
|
+
__name(querySnapshot, "querySnapshot");
|
|
215
283
|
return {
|
|
216
284
|
path,
|
|
217
285
|
doc(id) {
|
|
@@ -219,9 +287,15 @@ function buildCollectionRef(http, path, state = { where: [], orderBy: [] }) {
|
|
|
219
287
|
return buildDocumentRef(http, `${path}/${id}`);
|
|
220
288
|
},
|
|
221
289
|
async add(data) {
|
|
222
|
-
const resp = await http.request("POST", `/v1/docs/${path}`, {
|
|
290
|
+
const resp = await http.request("POST", `/v1/docs/${path}`, {
|
|
291
|
+
body: data
|
|
292
|
+
});
|
|
223
293
|
if (resp.error || !resp.data) {
|
|
224
|
-
return {
|
|
294
|
+
return {
|
|
295
|
+
data: null,
|
|
296
|
+
error: resp.error,
|
|
297
|
+
status: resp.status
|
|
298
|
+
};
|
|
225
299
|
}
|
|
226
300
|
return {
|
|
227
301
|
data: buildDocumentRef(http, `${path}/${resp.data.id}`),
|
|
@@ -234,59 +308,85 @@ function buildCollectionRef(http, path, state = { where: [], orderBy: [] }) {
|
|
|
234
308
|
where(field, op, value) {
|
|
235
309
|
return buildCollectionRef(http, path, {
|
|
236
310
|
...state,
|
|
237
|
-
where: [
|
|
311
|
+
where: [
|
|
312
|
+
...state.where,
|
|
313
|
+
{
|
|
314
|
+
field,
|
|
315
|
+
op,
|
|
316
|
+
value
|
|
317
|
+
}
|
|
318
|
+
]
|
|
238
319
|
});
|
|
239
320
|
},
|
|
240
321
|
orderBy(field, direction = "asc") {
|
|
241
322
|
return buildCollectionRef(http, path, {
|
|
242
323
|
...state,
|
|
243
|
-
orderBy: [
|
|
324
|
+
orderBy: [
|
|
325
|
+
...state.orderBy,
|
|
326
|
+
{
|
|
327
|
+
field,
|
|
328
|
+
direction
|
|
329
|
+
}
|
|
330
|
+
]
|
|
244
331
|
});
|
|
245
332
|
},
|
|
246
333
|
limit(n) {
|
|
247
|
-
return buildCollectionRef(http, path, {
|
|
334
|
+
return buildCollectionRef(http, path, {
|
|
335
|
+
...state,
|
|
336
|
+
limit: n
|
|
337
|
+
});
|
|
248
338
|
},
|
|
249
339
|
async get() {
|
|
250
340
|
const narrowed = state.where.length > 0 || state.orderBy.length > 0 || state.limit !== void 0;
|
|
251
|
-
const resp = narrowed ? await http.request(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (resp.error) return { data: null, error: resp.error, status: resp.status };
|
|
341
|
+
const resp = narrowed ? await http.request("POST", `/v1/docs/${path}/query`, {
|
|
342
|
+
body: queryBody(state)
|
|
343
|
+
}) : await http.request("GET", `/v1/docs/${path}`);
|
|
344
|
+
if (resp.error) return {
|
|
345
|
+
data: null,
|
|
346
|
+
error: resp.error,
|
|
347
|
+
status: resp.status
|
|
348
|
+
};
|
|
260
349
|
const docs = (resp.data?.documents ?? []).map(snapshot);
|
|
261
|
-
return {
|
|
350
|
+
return {
|
|
351
|
+
data: querySnapshot(docs),
|
|
352
|
+
error: null,
|
|
353
|
+
status: resp.status
|
|
354
|
+
};
|
|
262
355
|
}
|
|
263
356
|
};
|
|
264
357
|
}
|
|
358
|
+
__name(buildCollectionRef, "buildCollectionRef");
|
|
265
359
|
function queryBody(state) {
|
|
266
360
|
const body = {};
|
|
267
361
|
if (state.where.length > 0) {
|
|
268
|
-
body.where = state.where.map((w) => ({
|
|
362
|
+
body.where = state.where.map((w) => ({
|
|
363
|
+
field: w.field,
|
|
364
|
+
op: w.op,
|
|
365
|
+
value: w.value
|
|
366
|
+
}));
|
|
269
367
|
}
|
|
270
368
|
if (state.orderBy.length > 0) {
|
|
271
|
-
body.orderBy = state.orderBy.map((o) => ({
|
|
369
|
+
body.orderBy = state.orderBy.map((o) => ({
|
|
370
|
+
field: o.field,
|
|
371
|
+
direction: o.direction
|
|
372
|
+
}));
|
|
272
373
|
}
|
|
273
374
|
if (state.limit !== void 0) body.limit = state.limit;
|
|
274
375
|
return body;
|
|
275
376
|
}
|
|
377
|
+
__name(queryBody, "queryBody");
|
|
276
378
|
var MAX_BATCH = 500;
|
|
277
379
|
function buildDocumentsClient(http) {
|
|
278
380
|
return {
|
|
279
381
|
/**
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
382
|
+
* `Documents.doc("users/alice")` — segments are collection/documentId PAIRS,
|
|
383
|
+
* so an odd count addresses a COLLECTION and is refused. Accepting it would
|
|
384
|
+
* write a document whose id happens to be a collection's name.
|
|
385
|
+
*/
|
|
284
386
|
doc(path) {
|
|
285
387
|
const segments = String(path).split("/").filter((s) => s.length > 0);
|
|
286
388
|
if (segments.length === 0 || segments.length % 2 !== 0) {
|
|
287
|
-
throw new Error(
|
|
288
|
-
`Invalid document path: "${path}". Expected collection/documentId pairs, got ${segments.length} segment(s).`
|
|
289
|
-
);
|
|
389
|
+
throw new Error(`Invalid document path: "${path}". Expected collection/documentId pairs, got ${segments.length} segment(s).`);
|
|
290
390
|
}
|
|
291
391
|
segments.forEach((s, i) => validateSegment(s, i % 2 === 0 ? "collection name" : "document ID"));
|
|
292
392
|
return buildDocumentRef(http, segments.join("/"));
|
|
@@ -299,21 +399,26 @@ function buildDocumentsClient(http) {
|
|
|
299
399
|
if (operations.length > MAX_BATCH) {
|
|
300
400
|
return {
|
|
301
401
|
data: null,
|
|
302
|
-
error: new PalbaseModuleError(
|
|
303
|
-
"batch_too_large",
|
|
304
|
-
`Batch size ${operations.length} exceeds maximum of ${MAX_BATCH}`,
|
|
305
|
-
400
|
|
306
|
-
),
|
|
402
|
+
error: new PalbaseModuleError("batch_too_large", `Batch size ${operations.length} exceeds maximum of ${MAX_BATCH}`, 400),
|
|
307
403
|
status: 400
|
|
308
404
|
};
|
|
309
405
|
}
|
|
310
|
-
if (operations.length === 0) return {
|
|
406
|
+
if (operations.length === 0) return {
|
|
407
|
+
data: null,
|
|
408
|
+
error: null,
|
|
409
|
+
status: 200
|
|
410
|
+
};
|
|
311
411
|
return http.request("POST", "/v1/docs/batch", {
|
|
312
|
-
body: operations.map((op) => ({
|
|
412
|
+
body: operations.map((op) => ({
|
|
413
|
+
op: op.op,
|
|
414
|
+
path: op.ref.path,
|
|
415
|
+
data: op.data
|
|
416
|
+
}))
|
|
313
417
|
});
|
|
314
418
|
}
|
|
315
419
|
};
|
|
316
420
|
}
|
|
421
|
+
__name(buildDocumentsClient, "buildDocumentsClient");
|
|
317
422
|
|
|
318
423
|
// src/clients/flags.ts
|
|
319
424
|
var FLAG_NAME_RE = /^[A-Za-z0-9_.-]+$/;
|
|
@@ -322,46 +427,54 @@ function assertFlagName(flagName) {
|
|
|
322
427
|
throw new Error(`Invalid flag name: "${flagName}". Flag names must match ${FLAG_NAME_RE.source}`);
|
|
323
428
|
}
|
|
324
429
|
}
|
|
430
|
+
__name(assertFlagName, "assertFlagName");
|
|
325
431
|
function flagEnabled(value) {
|
|
326
432
|
if (typeof value === "boolean") return value;
|
|
327
433
|
return value != null && value !== 0 && value !== "";
|
|
328
434
|
}
|
|
435
|
+
__name(flagEnabled, "flagEnabled");
|
|
329
436
|
function flagVariant(value) {
|
|
330
|
-
return typeof value === "string" ? {
|
|
437
|
+
return typeof value === "string" ? {
|
|
438
|
+
name: value
|
|
439
|
+
} : null;
|
|
331
440
|
}
|
|
441
|
+
__name(flagVariant, "flagVariant");
|
|
332
442
|
function isContextObject(v) {
|
|
333
443
|
return v !== null && typeof v === "object" && !Array.isArray(v) && ("userId" in v || "properties" in v);
|
|
334
444
|
}
|
|
445
|
+
__name(isContextObject, "isContextObject");
|
|
335
446
|
function buildFlagsClient(http, cfg) {
|
|
336
447
|
function resolveUserId(context) {
|
|
337
448
|
if (context && "userId" in context) return context.userId ?? null;
|
|
338
449
|
return cfg.getCurrentUserId() || void 0;
|
|
339
450
|
}
|
|
451
|
+
__name(resolveUserId, "resolveUserId");
|
|
340
452
|
function mergedPath(context) {
|
|
341
453
|
const uid = resolveUserId(context);
|
|
342
454
|
return uid ? `/v1/user-flags/users/${encodeURIComponent(uid)}` : "/v1/user-flags";
|
|
343
455
|
}
|
|
456
|
+
__name(mergedPath, "mergedPath");
|
|
344
457
|
function fetchMerged(context) {
|
|
345
458
|
return http.request("GET", mergedPath(context));
|
|
346
459
|
}
|
|
460
|
+
__name(fetchMerged, "fetchMerged");
|
|
347
461
|
const service = {
|
|
348
462
|
async setOverrideForUser(userId, key, value) {
|
|
349
|
-
return http.request(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
);
|
|
463
|
+
return http.request("PUT", `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`, {
|
|
464
|
+
body: {
|
|
465
|
+
value
|
|
466
|
+
}
|
|
467
|
+
});
|
|
354
468
|
},
|
|
355
469
|
async setOverridesForUser(userId, values) {
|
|
356
470
|
return http.request("PUT", `/v1/user-flags/users/${encodeURIComponent(userId)}`, {
|
|
357
|
-
body: {
|
|
471
|
+
body: {
|
|
472
|
+
values
|
|
473
|
+
}
|
|
358
474
|
});
|
|
359
475
|
},
|
|
360
476
|
async clearOverrideForUser(userId, key) {
|
|
361
|
-
return http.request(
|
|
362
|
-
"DELETE",
|
|
363
|
-
`/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`
|
|
364
|
-
);
|
|
477
|
+
return http.request("DELETE", `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`);
|
|
365
478
|
},
|
|
366
479
|
async clearAllOverridesForUser(userId) {
|
|
367
480
|
return http.request("DELETE", `/v1/user-flags/users/${encodeURIComponent(userId)}`);
|
|
@@ -369,31 +482,54 @@ function buildFlagsClient(http, cfg) {
|
|
|
369
482
|
async batchSetOverrides(operations) {
|
|
370
483
|
const ops = (operations ?? []).map((op) => {
|
|
371
484
|
const raw2 = op;
|
|
372
|
-
return {
|
|
485
|
+
return {
|
|
486
|
+
user_id: raw2.userId ?? raw2.user_id,
|
|
487
|
+
values: raw2.values
|
|
488
|
+
};
|
|
489
|
+
});
|
|
490
|
+
return http.request("POST", "/v1/user-flags/batch", {
|
|
491
|
+
body: {
|
|
492
|
+
operations: ops
|
|
493
|
+
}
|
|
373
494
|
});
|
|
374
|
-
return http.request("POST", "/v1/user-flags/batch", { body: { operations: ops } });
|
|
375
495
|
}
|
|
376
496
|
};
|
|
377
497
|
return {
|
|
378
498
|
async isEnabled(flagName, context) {
|
|
379
499
|
assertFlagName(flagName);
|
|
380
500
|
const res = await fetchMerged(context);
|
|
381
|
-
if (res.error || res.data == null) return {
|
|
382
|
-
|
|
501
|
+
if (res.error || res.data == null) return {
|
|
502
|
+
data: null,
|
|
503
|
+
error: res.error,
|
|
504
|
+
status: res.status
|
|
505
|
+
};
|
|
506
|
+
return {
|
|
507
|
+
data: flagEnabled(res.data.values?.[flagName]),
|
|
508
|
+
error: null,
|
|
509
|
+
status: res.status
|
|
510
|
+
};
|
|
383
511
|
},
|
|
384
512
|
async getVariant(flagName, context) {
|
|
385
513
|
assertFlagName(flagName);
|
|
386
514
|
const res = await fetchMerged(context);
|
|
387
|
-
if (res.error || res.data == null) return {
|
|
388
|
-
|
|
515
|
+
if (res.error || res.data == null) return {
|
|
516
|
+
data: null,
|
|
517
|
+
error: res.error,
|
|
518
|
+
status: res.status
|
|
519
|
+
};
|
|
520
|
+
return {
|
|
521
|
+
data: flagVariant(res.data.values?.[flagName]),
|
|
522
|
+
error: null,
|
|
523
|
+
status: res.status
|
|
524
|
+
};
|
|
389
525
|
},
|
|
390
526
|
/**
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
527
|
+
* `get(key)` · `get(key, default)` · `get(key, default, ctx)` · `get(key, ctx)`.
|
|
528
|
+
*
|
|
529
|
+
* The default is substituted when the flag is ABSENT or when the flags
|
|
530
|
+
* service is unreachable — a product that hides a feature because a lookup
|
|
531
|
+
* timed out is behaving correctly; one that crashes is not.
|
|
532
|
+
*/
|
|
397
533
|
async get(flagName, defaultOrContext, maybeContext) {
|
|
398
534
|
assertFlagName(flagName);
|
|
399
535
|
let defaultValue;
|
|
@@ -411,19 +547,39 @@ function buildFlagsClient(http, cfg) {
|
|
|
411
547
|
}
|
|
412
548
|
const resp = await fetchMerged(context);
|
|
413
549
|
if (resp.error !== null) {
|
|
414
|
-
if (hasDefault) return {
|
|
415
|
-
|
|
550
|
+
if (hasDefault) return {
|
|
551
|
+
data: defaultValue ?? null,
|
|
552
|
+
error: null,
|
|
553
|
+
status: resp.status
|
|
554
|
+
};
|
|
555
|
+
return {
|
|
556
|
+
data: null,
|
|
557
|
+
error: resp.error,
|
|
558
|
+
status: resp.status
|
|
559
|
+
};
|
|
416
560
|
}
|
|
417
561
|
const values = resp.data?.values ?? {};
|
|
418
562
|
const value = values[flagName];
|
|
419
563
|
if (value === void 0) {
|
|
420
|
-
return {
|
|
564
|
+
return {
|
|
565
|
+
data: hasDefault ? defaultValue ?? null : null,
|
|
566
|
+
error: null,
|
|
567
|
+
status: resp.status
|
|
568
|
+
};
|
|
421
569
|
}
|
|
422
|
-
return {
|
|
570
|
+
return {
|
|
571
|
+
data: value,
|
|
572
|
+
error: null,
|
|
573
|
+
status: resp.status
|
|
574
|
+
};
|
|
423
575
|
},
|
|
424
576
|
async getAll(context) {
|
|
425
577
|
const res = await fetchMerged(context);
|
|
426
|
-
if (res.error || res.data == null) return {
|
|
578
|
+
if (res.error || res.data == null) return {
|
|
579
|
+
data: null,
|
|
580
|
+
error: res.error,
|
|
581
|
+
status: res.status
|
|
582
|
+
};
|
|
427
583
|
const values = res.data.values ?? {};
|
|
428
584
|
return {
|
|
429
585
|
data: Object.keys(values).map((name) => {
|
|
@@ -432,7 +588,9 @@ function buildFlagsClient(http, cfg) {
|
|
|
432
588
|
name,
|
|
433
589
|
enabled: flagEnabled(value)
|
|
434
590
|
};
|
|
435
|
-
if (typeof value === "string") flag.variant = {
|
|
591
|
+
if (typeof value === "string") flag.variant = {
|
|
592
|
+
name: value
|
|
593
|
+
};
|
|
436
594
|
return flag;
|
|
437
595
|
}),
|
|
438
596
|
error: null,
|
|
@@ -440,11 +598,11 @@ function buildFlagsClient(http, cfg) {
|
|
|
440
598
|
};
|
|
441
599
|
},
|
|
442
600
|
/**
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
601
|
+
* Override a flag for the CURRENT request user.
|
|
602
|
+
*
|
|
603
|
+
* On an anonymous request this does not silently no-op and does not write
|
|
604
|
+
* for nobody: it refuses and names the call that does cross-user writes.
|
|
605
|
+
*/
|
|
448
606
|
async setOverride(key, value) {
|
|
449
607
|
const uid = cfg.getCurrentUserId();
|
|
450
608
|
if (!uid) {
|
|
@@ -456,25 +614,35 @@ function buildFlagsClient(http, cfg) {
|
|
|
456
614
|
status: 400
|
|
457
615
|
};
|
|
458
616
|
}
|
|
459
|
-
return http.request(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
);
|
|
617
|
+
return http.request("PUT", `/v1/user-flags/users/${encodeURIComponent(uid)}/${encodeURIComponent(key)}`, {
|
|
618
|
+
body: {
|
|
619
|
+
value
|
|
620
|
+
}
|
|
621
|
+
});
|
|
464
622
|
},
|
|
465
623
|
asService() {
|
|
466
624
|
return service;
|
|
467
625
|
}
|
|
468
626
|
};
|
|
469
627
|
}
|
|
628
|
+
__name(buildFlagsClient, "buildFlagsClient");
|
|
470
629
|
|
|
471
630
|
// src/clients/notifications.ts
|
|
472
631
|
function mapEnvelope(res, map) {
|
|
473
632
|
if (res.error !== null || res.data === null || res.data === void 0) {
|
|
474
|
-
return {
|
|
633
|
+
return {
|
|
634
|
+
data: null,
|
|
635
|
+
error: res.error,
|
|
636
|
+
status: res.status
|
|
637
|
+
};
|
|
475
638
|
}
|
|
476
|
-
return {
|
|
639
|
+
return {
|
|
640
|
+
data: map(res.data),
|
|
641
|
+
error: null,
|
|
642
|
+
status: res.status
|
|
643
|
+
};
|
|
477
644
|
}
|
|
645
|
+
__name(mapEnvelope, "mapEnvelope");
|
|
478
646
|
function toEmailTemplate(wire) {
|
|
479
647
|
const view = {
|
|
480
648
|
id: wire.id,
|
|
@@ -490,6 +658,7 @@ function toEmailTemplate(wire) {
|
|
|
490
658
|
if (wire.text_body !== void 0) view.textBody = wire.text_body;
|
|
491
659
|
return view;
|
|
492
660
|
}
|
|
661
|
+
__name(toEmailTemplate, "toEmailTemplate");
|
|
493
662
|
function toSmsTemplate(wire) {
|
|
494
663
|
return {
|
|
495
664
|
id: wire.id,
|
|
@@ -502,40 +671,58 @@ function toSmsTemplate(wire) {
|
|
|
502
671
|
updatedAt: wire.updated_at
|
|
503
672
|
};
|
|
504
673
|
}
|
|
674
|
+
__name(toSmsTemplate, "toSmsTemplate");
|
|
505
675
|
function buildNotificationsClient(http) {
|
|
506
676
|
const push = {
|
|
507
677
|
async send(params) {
|
|
508
|
-
return http.request("POST", "/v1/notifications/push", {
|
|
678
|
+
return http.request("POST", "/v1/notifications/push", {
|
|
679
|
+
body: params
|
|
680
|
+
});
|
|
509
681
|
}
|
|
510
682
|
};
|
|
511
683
|
const email = {
|
|
512
684
|
async send(params) {
|
|
513
685
|
const { templateSlug, html, text: text2, ...rest } = params;
|
|
514
|
-
const body = {
|
|
686
|
+
const body = {
|
|
687
|
+
...rest
|
|
688
|
+
};
|
|
515
689
|
if (templateSlug !== void 0) body.template_slug = templateSlug;
|
|
516
690
|
if (html !== void 0) body.html_body = html;
|
|
517
691
|
if (text2 !== void 0) body.text_body = text2;
|
|
518
|
-
return http.request("POST", "/v1/notifications/email", {
|
|
692
|
+
return http.request("POST", "/v1/notifications/email", {
|
|
693
|
+
body
|
|
694
|
+
});
|
|
519
695
|
}
|
|
520
696
|
};
|
|
521
697
|
const sms = {
|
|
522
698
|
async send(params) {
|
|
523
699
|
const { templateSlug, ...rest } = params;
|
|
524
|
-
const body = templateSlug !== void 0 ? {
|
|
525
|
-
|
|
700
|
+
const body = templateSlug !== void 0 ? {
|
|
701
|
+
...rest,
|
|
702
|
+
template_slug: templateSlug
|
|
703
|
+
} : rest;
|
|
704
|
+
return http.request("POST", "/v1/notifications/sms", {
|
|
705
|
+
body
|
|
706
|
+
});
|
|
526
707
|
}
|
|
527
708
|
};
|
|
528
709
|
const verifications = {
|
|
529
710
|
async start(params) {
|
|
530
|
-
return http.request("POST", "/v1/notifications/verifications", {
|
|
711
|
+
return http.request("POST", "/v1/notifications/verifications", {
|
|
712
|
+
body: params
|
|
713
|
+
});
|
|
531
714
|
},
|
|
532
715
|
async check(params) {
|
|
533
|
-
return http.request("POST", "/v1/notifications/verifications/check", {
|
|
716
|
+
return http.request("POST", "/v1/notifications/verifications/check", {
|
|
717
|
+
body: params
|
|
718
|
+
});
|
|
534
719
|
}
|
|
535
720
|
};
|
|
536
721
|
const inbox = {
|
|
537
722
|
async send(params) {
|
|
538
|
-
return http.request("POST", "/v1/notifications/inbox", {
|
|
723
|
+
return http.request("POST", "/v1/notifications/inbox", {
|
|
724
|
+
body: params
|
|
725
|
+
});
|
|
539
726
|
},
|
|
540
727
|
async list(options) {
|
|
541
728
|
const opts = options ?? {};
|
|
@@ -566,7 +753,9 @@ function buildNotificationsClient(http) {
|
|
|
566
753
|
return http.request("GET", "/v1/notifications/preferences");
|
|
567
754
|
},
|
|
568
755
|
async update(params) {
|
|
569
|
-
return http.request("PUT", "/v1/notifications/preferences", {
|
|
756
|
+
return http.request("PUT", "/v1/notifications/preferences", {
|
|
757
|
+
body: params
|
|
758
|
+
});
|
|
570
759
|
}
|
|
571
760
|
};
|
|
572
761
|
const emailTemplates = {
|
|
@@ -575,10 +764,7 @@ function buildNotificationsClient(http) {
|
|
|
575
764
|
return mapEnvelope(resp, (rows) => (rows ?? []).map(toEmailTemplate));
|
|
576
765
|
},
|
|
577
766
|
async get(id) {
|
|
578
|
-
const resp = await http.request(
|
|
579
|
-
"GET",
|
|
580
|
-
`/v1/notifications/templates/${encodeURIComponent(id)}`
|
|
581
|
-
);
|
|
767
|
+
const resp = await http.request("GET", `/v1/notifications/templates/${encodeURIComponent(id)}`);
|
|
582
768
|
return mapEnvelope(resp, toEmailTemplate);
|
|
583
769
|
},
|
|
584
770
|
async create(input) {
|
|
@@ -589,7 +775,9 @@ function buildNotificationsClient(http) {
|
|
|
589
775
|
};
|
|
590
776
|
if (input.textBody !== void 0) body.text_body = input.textBody;
|
|
591
777
|
if (input.variables !== void 0) body.variables = input.variables;
|
|
592
|
-
const resp = await http.request("POST", "/v1/notifications/templates", {
|
|
778
|
+
const resp = await http.request("POST", "/v1/notifications/templates", {
|
|
779
|
+
body
|
|
780
|
+
});
|
|
593
781
|
return mapEnvelope(resp, toEmailTemplate);
|
|
594
782
|
},
|
|
595
783
|
async update(id, input) {
|
|
@@ -598,11 +786,9 @@ function buildNotificationsClient(http) {
|
|
|
598
786
|
if (input.htmlBody !== void 0) body.html_body = input.htmlBody;
|
|
599
787
|
if (input.textBody !== void 0) body.text_body = input.textBody;
|
|
600
788
|
if (input.variables !== void 0) body.variables = input.variables;
|
|
601
|
-
const resp = await http.request(
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
{ body }
|
|
605
|
-
);
|
|
789
|
+
const resp = await http.request("PUT", `/v1/notifications/templates/${encodeURIComponent(id)}`, {
|
|
790
|
+
body
|
|
791
|
+
});
|
|
606
792
|
return mapEnvelope(resp, toEmailTemplate);
|
|
607
793
|
},
|
|
608
794
|
async delete(id) {
|
|
@@ -615,27 +801,27 @@ function buildNotificationsClient(http) {
|
|
|
615
801
|
return mapEnvelope(resp, (rows) => (rows ?? []).map(toSmsTemplate));
|
|
616
802
|
},
|
|
617
803
|
async get(id) {
|
|
618
|
-
const resp = await http.request(
|
|
619
|
-
"GET",
|
|
620
|
-
`/v1/notifications/sms-templates/${encodeURIComponent(id)}`
|
|
621
|
-
);
|
|
804
|
+
const resp = await http.request("GET", `/v1/notifications/sms-templates/${encodeURIComponent(id)}`);
|
|
622
805
|
return mapEnvelope(resp, toSmsTemplate);
|
|
623
806
|
},
|
|
624
807
|
async create(input) {
|
|
625
|
-
const body = {
|
|
808
|
+
const body = {
|
|
809
|
+
slug: input.slug,
|
|
810
|
+
body: input.body
|
|
811
|
+
};
|
|
626
812
|
if (input.variables !== void 0) body.variables = input.variables;
|
|
627
|
-
const resp = await http.request("POST", "/v1/notifications/sms-templates", {
|
|
813
|
+
const resp = await http.request("POST", "/v1/notifications/sms-templates", {
|
|
814
|
+
body
|
|
815
|
+
});
|
|
628
816
|
return mapEnvelope(resp, toSmsTemplate);
|
|
629
817
|
},
|
|
630
818
|
async update(id, input) {
|
|
631
819
|
const body = {};
|
|
632
820
|
if (input.body !== void 0) body.body = input.body;
|
|
633
821
|
if (input.variables !== void 0) body.variables = input.variables;
|
|
634
|
-
const resp = await http.request(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
{ body }
|
|
638
|
-
);
|
|
822
|
+
const resp = await http.request("PUT", `/v1/notifications/sms-templates/${encodeURIComponent(id)}`, {
|
|
823
|
+
body
|
|
824
|
+
});
|
|
639
825
|
return mapEnvelope(resp, toSmsTemplate);
|
|
640
826
|
},
|
|
641
827
|
async delete(id) {
|
|
@@ -649,27 +835,40 @@ function buildNotificationsClient(http) {
|
|
|
649
835
|
verifications,
|
|
650
836
|
inbox,
|
|
651
837
|
preferences,
|
|
652
|
-
templates: {
|
|
838
|
+
templates: {
|
|
839
|
+
email: emailTemplates,
|
|
840
|
+
sms: smsTemplates
|
|
841
|
+
},
|
|
653
842
|
async registerDevice(params) {
|
|
654
|
-
return http.request("POST", "/v1/notifications/devices", {
|
|
843
|
+
return http.request("POST", "/v1/notifications/devices", {
|
|
844
|
+
body: params
|
|
845
|
+
});
|
|
655
846
|
},
|
|
656
847
|
async unregisterDevice(deviceId) {
|
|
657
848
|
return http.request("DELETE", `/v1/notifications/devices/${encodeURIComponent(deviceId)}`);
|
|
658
849
|
}
|
|
659
850
|
};
|
|
660
851
|
}
|
|
852
|
+
__name(buildNotificationsClient, "buildNotificationsClient");
|
|
661
853
|
|
|
662
854
|
// src/clients/realtime.ts
|
|
663
855
|
import { createHmac } from "crypto";
|
|
664
856
|
function mintToken(secret) {
|
|
665
857
|
const now2 = Math.floor(Date.now() / 1e3);
|
|
666
|
-
const header = Buffer.from(JSON.stringify({
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
).toString("base64url");
|
|
858
|
+
const header = Buffer.from(JSON.stringify({
|
|
859
|
+
alg: "HS256",
|
|
860
|
+
typ: "JWT"
|
|
861
|
+
})).toString("base64url");
|
|
862
|
+
const payload = Buffer.from(JSON.stringify({
|
|
863
|
+
iss: "backend-runtime",
|
|
864
|
+
role: "service_role",
|
|
865
|
+
iat: now2,
|
|
866
|
+
exp: now2 + 60
|
|
867
|
+
})).toString("base64url");
|
|
670
868
|
const sig = createHmac("sha256", secret).update(`${header}.${payload}`).digest("base64url");
|
|
671
869
|
return `${header}.${payload}.${sig}`;
|
|
672
870
|
}
|
|
871
|
+
__name(mintToken, "mintToken");
|
|
673
872
|
function buildRealtimeClient(cfg) {
|
|
674
873
|
const url = `${cfg.baseUrl}/realtime/api/broadcast`;
|
|
675
874
|
const stateUrl = `${cfg.baseUrl}/realtime/api/state`;
|
|
@@ -689,11 +888,7 @@ function buildRealtimeClient(cfg) {
|
|
|
689
888
|
if (!cfg.apiJwtSecret) {
|
|
690
889
|
return {
|
|
691
890
|
data: null,
|
|
692
|
-
error: new PalbaseModuleError(
|
|
693
|
-
"realtime_unconfigured",
|
|
694
|
-
"Realtime.state is unavailable: realtime is not provisioned for this Environment (PALBASE_REALTIME_API_JWT_SECRET unset).",
|
|
695
|
-
503
|
|
696
|
-
)
|
|
891
|
+
error: new PalbaseModuleError("realtime_unconfigured", "Realtime.state is unavailable: realtime is not provisioned for this Environment (PALBASE_REALTIME_API_JWT_SECRET unset).", 503)
|
|
697
892
|
};
|
|
698
893
|
}
|
|
699
894
|
let token;
|
|
@@ -702,57 +897,64 @@ function buildRealtimeClient(cfg) {
|
|
|
702
897
|
} catch (err) {
|
|
703
898
|
return {
|
|
704
899
|
data: null,
|
|
705
|
-
error: new PalbaseModuleError(
|
|
706
|
-
"realtime_token_error",
|
|
707
|
-
err instanceof Error ? err.message : "token mint failed",
|
|
708
|
-
500
|
|
709
|
-
)
|
|
900
|
+
error: new PalbaseModuleError("realtime_token_error", err instanceof Error ? err.message : "token mint failed", 500)
|
|
710
901
|
};
|
|
711
902
|
}
|
|
712
|
-
const op = del ? {
|
|
903
|
+
const op = del ? {
|
|
904
|
+
topic,
|
|
905
|
+
key,
|
|
906
|
+
del: true
|
|
907
|
+
} : {
|
|
908
|
+
topic,
|
|
909
|
+
key,
|
|
910
|
+
value: value ?? {}
|
|
911
|
+
};
|
|
713
912
|
const doFetch = cfg.fetchImpl ?? globalThis.fetch;
|
|
714
913
|
let response;
|
|
715
914
|
try {
|
|
716
915
|
response = await doFetch(stateUrl, {
|
|
717
916
|
method: "POST",
|
|
718
|
-
headers: {
|
|
719
|
-
|
|
917
|
+
headers: {
|
|
918
|
+
"Content-Type": "application/json",
|
|
919
|
+
Authorization: `Bearer ${token}`
|
|
920
|
+
},
|
|
921
|
+
body: JSON.stringify({
|
|
922
|
+
ops: [
|
|
923
|
+
op
|
|
924
|
+
]
|
|
925
|
+
})
|
|
720
926
|
});
|
|
721
927
|
} catch (err) {
|
|
722
928
|
return {
|
|
723
929
|
data: null,
|
|
724
|
-
error: new PalbaseModuleError(
|
|
725
|
-
"network_error",
|
|
726
|
-
err instanceof Error ? err.message : "state request failed",
|
|
727
|
-
0
|
|
728
|
-
)
|
|
930
|
+
error: new PalbaseModuleError("network_error", err instanceof Error ? err.message : "state request failed", 0)
|
|
729
931
|
};
|
|
730
932
|
}
|
|
731
933
|
if (response.status === 202 || response.status === 200) {
|
|
732
|
-
return {
|
|
934
|
+
return {
|
|
935
|
+
data: void 0,
|
|
936
|
+
error: null
|
|
937
|
+
};
|
|
733
938
|
}
|
|
734
939
|
const detail = await response.text().catch(() => "");
|
|
735
940
|
return {
|
|
736
941
|
data: null,
|
|
737
|
-
error: new PalbaseModuleError(
|
|
738
|
-
"realtime_state_failed",
|
|
739
|
-
`realtime state write returned ${response.status}${detail ? `: ${detail}` : ""}`,
|
|
740
|
-
response.status
|
|
741
|
-
)
|
|
942
|
+
error: new PalbaseModuleError("realtime_state_failed", `realtime state write returned ${response.status}${detail ? `: ${detail}` : ""}`, response.status)
|
|
742
943
|
};
|
|
743
944
|
}
|
|
945
|
+
__name(writeState, "writeState");
|
|
744
946
|
return {
|
|
745
947
|
state: {
|
|
746
948
|
/** Write one DURABLE entry on a channel's shared state.
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
set: (topic, key, value) => writeState(topic, key, value, false),
|
|
949
|
+
*
|
|
950
|
+
* The difference from broadcast is WHO it reaches: a broadcast reaches
|
|
951
|
+
* whoever is listening at that instant, while state is also handed to
|
|
952
|
+
* whoever joins afterwards. "This value is now X" wants the second — a
|
|
953
|
+
* client connecting a second later should not have to wait for the next
|
|
954
|
+
* change to learn X. */
|
|
955
|
+
set: /* @__PURE__ */ __name((topic, key, value) => writeState(topic, key, value, false), "set"),
|
|
754
956
|
/** Remove one entry. */
|
|
755
|
-
clear: (topic, key) => writeState(topic, key, void 0, true)
|
|
957
|
+
clear: /* @__PURE__ */ __name((topic, key) => writeState(topic, key, void 0, true), "clear")
|
|
756
958
|
},
|
|
757
959
|
async broadcast(channel, event, payload) {
|
|
758
960
|
if (typeof channel !== "string" || channel.length === 0) {
|
|
@@ -770,11 +972,7 @@ function buildRealtimeClient(cfg) {
|
|
|
770
972
|
if (!cfg.apiJwtSecret) {
|
|
771
973
|
return {
|
|
772
974
|
data: null,
|
|
773
|
-
error: new PalbaseModuleError(
|
|
774
|
-
"realtime_unconfigured",
|
|
775
|
-
"Realtime.broadcast is unavailable: realtime is not provisioned for this Environment (PALBASE_REALTIME_API_JWT_SECRET unset).",
|
|
776
|
-
503
|
|
777
|
-
)
|
|
975
|
+
error: new PalbaseModuleError("realtime_unconfigured", "Realtime.broadcast is unavailable: realtime is not provisioned for this Environment (PALBASE_REALTIME_API_JWT_SECRET unset).", 503)
|
|
778
976
|
};
|
|
779
977
|
}
|
|
780
978
|
let token;
|
|
@@ -783,49 +981,51 @@ function buildRealtimeClient(cfg) {
|
|
|
783
981
|
} catch (err) {
|
|
784
982
|
return {
|
|
785
983
|
data: null,
|
|
786
|
-
error: new PalbaseModuleError(
|
|
787
|
-
"realtime_token_error",
|
|
788
|
-
err instanceof Error ? err.message : "token mint failed",
|
|
789
|
-
500
|
|
790
|
-
)
|
|
984
|
+
error: new PalbaseModuleError("realtime_token_error", err instanceof Error ? err.message : "token mint failed", 500)
|
|
791
985
|
};
|
|
792
986
|
}
|
|
793
987
|
const body = JSON.stringify({
|
|
794
|
-
messages: [
|
|
988
|
+
messages: [
|
|
989
|
+
{
|
|
990
|
+
topic: channel,
|
|
991
|
+
event,
|
|
992
|
+
payload: payload ?? {},
|
|
993
|
+
private: false
|
|
994
|
+
}
|
|
995
|
+
]
|
|
795
996
|
});
|
|
796
997
|
const doFetch = cfg.fetchImpl ?? globalThis.fetch;
|
|
797
998
|
let response;
|
|
798
999
|
try {
|
|
799
1000
|
response = await doFetch(url, {
|
|
800
1001
|
method: "POST",
|
|
801
|
-
headers: {
|
|
1002
|
+
headers: {
|
|
1003
|
+
"Content-Type": "application/json",
|
|
1004
|
+
Authorization: `Bearer ${token}`
|
|
1005
|
+
},
|
|
802
1006
|
body
|
|
803
1007
|
});
|
|
804
1008
|
} catch (err) {
|
|
805
1009
|
return {
|
|
806
1010
|
data: null,
|
|
807
|
-
error: new PalbaseModuleError(
|
|
808
|
-
"network_error",
|
|
809
|
-
err instanceof Error ? err.message : "broadcast request failed",
|
|
810
|
-
0
|
|
811
|
-
)
|
|
1011
|
+
error: new PalbaseModuleError("network_error", err instanceof Error ? err.message : "broadcast request failed", 0)
|
|
812
1012
|
};
|
|
813
1013
|
}
|
|
814
1014
|
if (response.status === 202 || response.status === 200) {
|
|
815
|
-
return {
|
|
1015
|
+
return {
|
|
1016
|
+
data: void 0,
|
|
1017
|
+
error: null
|
|
1018
|
+
};
|
|
816
1019
|
}
|
|
817
1020
|
const detail = await response.text().catch(() => "");
|
|
818
1021
|
return {
|
|
819
1022
|
data: null,
|
|
820
|
-
error: new PalbaseModuleError(
|
|
821
|
-
"realtime_broadcast_failed",
|
|
822
|
-
`broadcast returned ${response.status}: ${detail.slice(0, 200)}`,
|
|
823
|
-
response.status
|
|
824
|
-
)
|
|
1023
|
+
error: new PalbaseModuleError("realtime_broadcast_failed", `broadcast returned ${response.status}: ${detail.slice(0, 200)}`, response.status)
|
|
825
1024
|
};
|
|
826
1025
|
}
|
|
827
1026
|
};
|
|
828
1027
|
}
|
|
1028
|
+
__name(buildRealtimeClient, "buildRealtimeClient");
|
|
829
1029
|
|
|
830
1030
|
// src/clients/storage.ts
|
|
831
1031
|
var BUCKET_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
@@ -833,11 +1033,10 @@ var STORAGE_PATH_RE = /^[a-zA-Z0-9_./-]+$/;
|
|
|
833
1033
|
var STORAGE_TRAVERSAL_RE = /(?:^|\/)\.\.(?:\/|$)/;
|
|
834
1034
|
function validateStoragePath(p) {
|
|
835
1035
|
if (!STORAGE_PATH_RE.test(p) || STORAGE_TRAVERSAL_RE.test(p)) {
|
|
836
|
-
throw new Error(
|
|
837
|
-
`Invalid file path: "${p}". Paths must not contain traversal sequences and must match ${STORAGE_PATH_RE.source}`
|
|
838
|
-
);
|
|
1036
|
+
throw new Error(`Invalid file path: "${p}". Paths must not contain traversal sequences and must match ${STORAGE_PATH_RE.source}`);
|
|
839
1037
|
}
|
|
840
1038
|
}
|
|
1039
|
+
__name(validateStoragePath, "validateStoragePath");
|
|
841
1040
|
function toFileObject(bucket, row) {
|
|
842
1041
|
return {
|
|
843
1042
|
name: row.path ?? "",
|
|
@@ -852,14 +1051,24 @@ function toFileObject(bucket, row) {
|
|
|
852
1051
|
variants: row.variants ?? {}
|
|
853
1052
|
};
|
|
854
1053
|
}
|
|
1054
|
+
__name(toFileObject, "toFileObject");
|
|
855
1055
|
function mapResponse(res, map) {
|
|
856
1056
|
if (res.error || res.data === null || res.data === void 0) {
|
|
857
|
-
return {
|
|
1057
|
+
return {
|
|
1058
|
+
data: null,
|
|
1059
|
+
error: res.error,
|
|
1060
|
+
status: res.status
|
|
1061
|
+
};
|
|
858
1062
|
}
|
|
859
|
-
return {
|
|
1063
|
+
return {
|
|
1064
|
+
data: map(res.data),
|
|
1065
|
+
error: null,
|
|
1066
|
+
status: res.status
|
|
1067
|
+
};
|
|
860
1068
|
}
|
|
1069
|
+
__name(mapResponse, "mapResponse");
|
|
861
1070
|
function buildBucketClient(http, bucketName, publicOrigin) {
|
|
862
|
-
const objectPath = (path) => `/v1/storage/object/${bucketName}/${path}
|
|
1071
|
+
const objectPath = /* @__PURE__ */ __name((path) => `/v1/storage/object/${bucketName}/${path}`, "objectPath");
|
|
863
1072
|
return {
|
|
864
1073
|
async upload(path, file, options) {
|
|
865
1074
|
validateStoragePath(path);
|
|
@@ -876,22 +1085,26 @@ function buildBucketClient(http, bucketName, publicOrigin) {
|
|
|
876
1085
|
},
|
|
877
1086
|
async download(path) {
|
|
878
1087
|
validateStoragePath(path);
|
|
879
|
-
return http.request("GET", objectPath(path), {
|
|
1088
|
+
return http.request("GET", objectPath(path), {
|
|
1089
|
+
headers: {
|
|
1090
|
+
Accept: "*/*"
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
880
1093
|
},
|
|
881
1094
|
getPublicUrl(path, options) {
|
|
882
1095
|
validateStoragePath(path);
|
|
883
1096
|
const variant = options?.variant ? `?variant=${encodeURIComponent(options.variant)}` : "";
|
|
884
1097
|
if (!publicOrigin) {
|
|
885
|
-
throw new Error(
|
|
886
|
-
`Storage.bucket("${bucketName}").getPublicUrl() needs this stack's public origin, and it was not configured. Set PALBASE_PUBLIC_ORIGIN to the address clients reach this stack at (e.g. https://myproject.palbase.studio).`
|
|
887
|
-
);
|
|
1098
|
+
throw new Error(`Storage.bucket("${bucketName}").getPublicUrl() needs this stack's public origin, and it was not configured. Set PALBASE_PUBLIC_ORIGIN to the address clients reach this stack at (e.g. https://myproject.palbase.studio).`);
|
|
888
1099
|
}
|
|
889
1100
|
return `${publicOrigin}/v1/files/${bucketName}/${path}${variant}`;
|
|
890
1101
|
},
|
|
891
1102
|
async createSignedUrl(path, options) {
|
|
892
1103
|
validateStoragePath(path);
|
|
893
1104
|
return http.request("POST", `/v1/storage/sign/${bucketName}/${path}`, {
|
|
894
|
-
body: {
|
|
1105
|
+
body: {
|
|
1106
|
+
expiresIn: options.expiresIn
|
|
1107
|
+
}
|
|
895
1108
|
});
|
|
896
1109
|
},
|
|
897
1110
|
async list(prefix, options) {
|
|
@@ -900,10 +1113,7 @@ function buildBucketClient(http, bucketName, publicOrigin) {
|
|
|
900
1113
|
if (prefix) params.set("prefix", prefix);
|
|
901
1114
|
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
902
1115
|
const query = params.toString();
|
|
903
|
-
const res = await http.request(
|
|
904
|
-
"GET",
|
|
905
|
-
`/v1/storage/bucket/${bucketName}${query ? `?${query}` : ""}`
|
|
906
|
-
);
|
|
1116
|
+
const res = await http.request("GET", `/v1/storage/bucket/${bucketName}${query ? `?${query}` : ""}`);
|
|
907
1117
|
return mapResponse(res, (body) => (body?.objects ?? []).map((row) => toFileObject(bucketName, row)));
|
|
908
1118
|
},
|
|
909
1119
|
async remove(paths) {
|
|
@@ -911,23 +1121,44 @@ function buildBucketClient(http, bucketName, publicOrigin) {
|
|
|
911
1121
|
const removed = [];
|
|
912
1122
|
for (const p of paths) {
|
|
913
1123
|
const res = await http.request("DELETE", objectPath(p));
|
|
914
|
-
if (res.error) return {
|
|
915
|
-
|
|
1124
|
+
if (res.error) return {
|
|
1125
|
+
data: null,
|
|
1126
|
+
error: res.error,
|
|
1127
|
+
status: res.status
|
|
1128
|
+
};
|
|
1129
|
+
removed.push(toFileObject(bucketName, {
|
|
1130
|
+
path: p
|
|
1131
|
+
}));
|
|
916
1132
|
}
|
|
917
|
-
return {
|
|
1133
|
+
return {
|
|
1134
|
+
data: removed,
|
|
1135
|
+
error: null,
|
|
1136
|
+
status: 200
|
|
1137
|
+
};
|
|
918
1138
|
},
|
|
919
1139
|
async move(from, to) {
|
|
920
1140
|
validateStoragePath(from);
|
|
921
1141
|
validateStoragePath(to);
|
|
922
|
-
return http.request("POST", `/v1/storage/move/${bucketName}`, {
|
|
1142
|
+
return http.request("POST", `/v1/storage/move/${bucketName}`, {
|
|
1143
|
+
body: {
|
|
1144
|
+
from,
|
|
1145
|
+
to
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
923
1148
|
},
|
|
924
1149
|
async copy(from, to) {
|
|
925
1150
|
validateStoragePath(from);
|
|
926
1151
|
validateStoragePath(to);
|
|
927
|
-
return http.request("POST", `/v1/storage/copy/${bucketName}`, {
|
|
1152
|
+
return http.request("POST", `/v1/storage/copy/${bucketName}`, {
|
|
1153
|
+
body: {
|
|
1154
|
+
from,
|
|
1155
|
+
to
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
928
1158
|
}
|
|
929
1159
|
};
|
|
930
1160
|
}
|
|
1161
|
+
__name(buildBucketClient, "buildBucketClient");
|
|
931
1162
|
function buildStorageClient(http, publicOrigin) {
|
|
932
1163
|
return {
|
|
933
1164
|
bucket(name) {
|
|
@@ -938,18 +1169,25 @@ function buildStorageClient(http, publicOrigin) {
|
|
|
938
1169
|
}
|
|
939
1170
|
};
|
|
940
1171
|
}
|
|
1172
|
+
__name(buildStorageClient, "buildStorageClient");
|
|
941
1173
|
|
|
942
1174
|
// src/clients/index.ts
|
|
943
1175
|
function buildModuleClients(cfg) {
|
|
944
1176
|
const baseUrl = (cfg.baseUrl || "").replace(/\/+$/, "");
|
|
945
1177
|
if (!baseUrl) return {};
|
|
946
1178
|
const apiKey = cfg.serviceRoleKey || cfg.apiKey || "";
|
|
947
|
-
const http = makeHttpClient({
|
|
1179
|
+
const http = makeHttpClient({
|
|
1180
|
+
baseUrl,
|
|
1181
|
+
apiKey,
|
|
1182
|
+
fetchImpl: cfg.fetchImpl
|
|
1183
|
+
});
|
|
948
1184
|
return {
|
|
949
1185
|
Documents: buildDocumentsClient(http),
|
|
950
1186
|
Storage: buildStorageClient(http, cfg.publicOrigin),
|
|
951
1187
|
Notifications: buildNotificationsClient(http),
|
|
952
|
-
Flags: buildFlagsClient(http, {
|
|
1188
|
+
Flags: buildFlagsClient(http, {
|
|
1189
|
+
getCurrentUserId: cfg.getCurrentUserId
|
|
1190
|
+
}),
|
|
953
1191
|
Realtime: buildRealtimeClient({
|
|
954
1192
|
baseUrl,
|
|
955
1193
|
apiJwtSecret: cfg.realtimeApiJwtSecret,
|
|
@@ -957,46 +1195,68 @@ function buildModuleClients(cfg) {
|
|
|
957
1195
|
})
|
|
958
1196
|
};
|
|
959
1197
|
}
|
|
1198
|
+
__name(buildModuleClients, "buildModuleClients");
|
|
960
1199
|
|
|
961
1200
|
// src/channels.ts
|
|
962
1201
|
var CHANNELS = /* @__PURE__ */ Symbol.for("palbase.backend.channels");
|
|
963
1202
|
function ownerOnly() {
|
|
964
|
-
return {
|
|
1203
|
+
return {
|
|
1204
|
+
kind: "owner"
|
|
1205
|
+
};
|
|
965
1206
|
}
|
|
1207
|
+
__name(ownerOnly, "ownerOnly");
|
|
966
1208
|
function publicChannel(opts = {}) {
|
|
967
|
-
return {
|
|
1209
|
+
return {
|
|
1210
|
+
kind: "public",
|
|
1211
|
+
publish: opts.publish ?? false,
|
|
1212
|
+
state: opts.state
|
|
1213
|
+
};
|
|
968
1214
|
}
|
|
1215
|
+
__name(publicChannel, "publicChannel");
|
|
969
1216
|
function paramCount(pattern) {
|
|
970
1217
|
return pattern.split(":").filter((s) => s.startsWith("{") && s.endsWith("}")).length;
|
|
971
1218
|
}
|
|
1219
|
+
__name(paramCount, "paramCount");
|
|
972
1220
|
function defineChannels(map) {
|
|
973
1221
|
const entries = [];
|
|
974
1222
|
for (const [pattern, entry] of Object.entries(map)) {
|
|
975
1223
|
if ("kind" in entry && entry.kind === "owner") {
|
|
976
1224
|
if (paramCount(pattern) !== 1) {
|
|
977
|
-
throw new Error(
|
|
978
|
-
`defineChannels: ownerOnly() pattern "${pattern}" must carry exactly one {param} (its value is compared to the token subject)`
|
|
979
|
-
);
|
|
1225
|
+
throw new Error(`defineChannels: ownerOnly() pattern "${pattern}" must carry exactly one {param} (its value is compared to the token subject)`);
|
|
980
1226
|
}
|
|
981
|
-
entries.push({
|
|
1227
|
+
entries.push({
|
|
1228
|
+
pattern,
|
|
1229
|
+
kind: "owner"
|
|
1230
|
+
});
|
|
982
1231
|
} else if ("kind" in entry && entry.kind === "public") {
|
|
983
|
-
entries.push({
|
|
1232
|
+
entries.push({
|
|
1233
|
+
pattern,
|
|
1234
|
+
kind: "public",
|
|
1235
|
+
publish: entry.publish,
|
|
1236
|
+
state: entry.state
|
|
1237
|
+
});
|
|
984
1238
|
} else {
|
|
985
1239
|
const c = entry;
|
|
986
|
-
entries.push({
|
|
1240
|
+
entries.push({
|
|
1241
|
+
pattern,
|
|
1242
|
+
kind: "custom",
|
|
1243
|
+
authorize: c.authorize,
|
|
1244
|
+
handler: c.handler
|
|
1245
|
+
});
|
|
987
1246
|
}
|
|
988
1247
|
}
|
|
989
|
-
const def = {
|
|
1248
|
+
const def = {
|
|
1249
|
+
entries
|
|
1250
|
+
};
|
|
990
1251
|
const carrier = globalThis;
|
|
991
1252
|
const existing = carrier[CHANNELS];
|
|
992
1253
|
if (existing && !sameDeclaration(existing, def)) {
|
|
993
|
-
throw new Error(
|
|
994
|
-
`defineChannels: channels were already declared (${existing.entries.length} pattern(s): ${existing.entries.map((e) => e.pattern).join(", ")}). A project declares its channels ONCE \u2014 a second call would overwrite the first, and channels nobody declared are refused.`
|
|
995
|
-
);
|
|
1254
|
+
throw new Error(`defineChannels: channels were already declared (${existing.entries.length} pattern(s): ${existing.entries.map((e) => e.pattern).join(", ")}). A project declares its channels ONCE \u2014 a second call would overwrite the first, and channels nobody declared are refused.`);
|
|
996
1255
|
}
|
|
997
1256
|
carrier[CHANNELS] = def;
|
|
998
1257
|
return def;
|
|
999
1258
|
}
|
|
1259
|
+
__name(defineChannels, "defineChannels");
|
|
1000
1260
|
function wireRow(e) {
|
|
1001
1261
|
return JSON.stringify([
|
|
1002
1262
|
e.pattern,
|
|
@@ -1010,214 +1270,46 @@ function wireRow(e) {
|
|
|
1010
1270
|
e.authorize ? e.authorize.toString() : ""
|
|
1011
1271
|
]);
|
|
1012
1272
|
}
|
|
1273
|
+
__name(wireRow, "wireRow");
|
|
1013
1274
|
function sameDeclaration(a, b) {
|
|
1014
1275
|
if (a.entries.length !== b.entries.length) return false;
|
|
1015
1276
|
return a.entries.every((x, i) => wireRow(x) === wireRow(b.entries[i]));
|
|
1016
1277
|
}
|
|
1017
|
-
|
|
1018
|
-
// src/db/env-gen.ts
|
|
1019
|
-
function baseTsType(def) {
|
|
1020
|
-
switch (def.type) {
|
|
1021
|
-
case "uuid":
|
|
1022
|
-
case "text":
|
|
1023
|
-
case "timestamp":
|
|
1024
|
-
return "string";
|
|
1025
|
-
case "integer":
|
|
1026
|
-
return "number";
|
|
1027
|
-
// Both are exact-precision in Postgres and lossy as a JSON number, so the
|
|
1028
|
-
// database proxy serializes them as strings — measured: 9007199254740993
|
|
1029
|
-
// used to arrive as ...992 and 41.00821234567890123 as 41.0082123456789.
|
|
1030
|
-
// numeric had no case at all and fell through to `unknown`, which typed
|
|
1031
|
-
// every numeric column out of existence.
|
|
1032
|
-
case "bigint":
|
|
1033
|
-
case "numeric":
|
|
1034
|
-
return "string";
|
|
1035
|
-
case "boolean":
|
|
1036
|
-
return "boolean";
|
|
1037
|
-
case "jsonb":
|
|
1038
|
-
return "unknown";
|
|
1039
|
-
// FR-008: the authoring type of a pgvector column. The default `unknown`
|
|
1040
|
-
// branch below STAYS — an unknown wire type is refused on the Go side
|
|
1041
|
-
// (FR-005), never papered over here.
|
|
1042
|
-
case "vector":
|
|
1043
|
-
return "number[]";
|
|
1044
|
-
case "enum": {
|
|
1045
|
-
const values = def.enumValues ?? [];
|
|
1046
|
-
if (values.length === 0) return "string";
|
|
1047
|
-
return values.map((v) => JSON.stringify(v)).join(" | ");
|
|
1048
|
-
}
|
|
1049
|
-
default:
|
|
1050
|
-
return "unknown";
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
function rowType(def) {
|
|
1054
|
-
const base = baseTsType(def);
|
|
1055
|
-
return def.nullable ? `${base} | null` : base;
|
|
1056
|
-
}
|
|
1057
|
-
function optionalOnInsert(def) {
|
|
1058
|
-
return def.nullable === true || def.defaultRandom === true || def.defaultNow === true || def.defaultValue !== void 0;
|
|
1059
|
-
}
|
|
1060
|
-
function forwardName(column) {
|
|
1061
|
-
return column.endsWith("_id") ? column.slice(0, -3) : column;
|
|
1062
|
-
}
|
|
1063
|
-
function describeOrigin(o) {
|
|
1064
|
-
return o.direction === "forward" ? `the foreign key "${o.table}.${o.column}"` : `the reverse of "${o.table}.${o.column}"`;
|
|
1065
|
-
}
|
|
1066
|
-
function renameCall(o) {
|
|
1067
|
-
if (o.direction === "reverse") return `references(() => \u2026, { reverseAs: "\u2026" })`;
|
|
1068
|
-
if (o.def.owns === true) {
|
|
1069
|
-
return `ownedByUser() takes no { as } \u2014 if "${o.column}" only POINTS at a user, declare it userRef({ onDelete: \u2026 }) instead`;
|
|
1070
|
-
}
|
|
1071
|
-
const target = o.def.references?.table;
|
|
1072
|
-
if (target === "auth.users") return `userRef({ onDelete: \u2026, as: "\u2026" })`;
|
|
1073
|
-
if (target === "auth.installations") return `installationRef({ onDelete: \u2026, as: "\u2026" })`;
|
|
1074
|
-
if (o.def.selfRefColumn !== void 0) return `selfReferences("\u2026", { as: "\u2026" })`;
|
|
1075
|
-
return `references(() => \u2026, { as: "\u2026" })`;
|
|
1076
|
-
}
|
|
1077
|
-
function buildRelations(schemas) {
|
|
1078
|
-
const out = /* @__PURE__ */ new Map();
|
|
1079
|
-
const taken = /* @__PURE__ */ new Map();
|
|
1080
|
-
for (const schema of schemas) {
|
|
1081
|
-
for (const t of Object.values(schema.tables)) {
|
|
1082
|
-
const key = qualifiedTableKey(schema.name, t.name);
|
|
1083
|
-
out.set(key, []);
|
|
1084
|
-
taken.set(key, /* @__PURE__ */ new Map());
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
const claim = (tableKey, name, origin, edge) => {
|
|
1088
|
-
const names = taken.get(tableKey);
|
|
1089
|
-
if (names === void 0) return;
|
|
1090
|
-
const held = names.get(name);
|
|
1091
|
-
if (held !== void 0) {
|
|
1092
|
-
if (held.def.owns === true && origin.def.owns === true) {
|
|
1093
|
-
throw new Error(
|
|
1094
|
-
`table "${tableKey}" declares TWO owner columns (${held.column}, ${origin.column}) \u2014 a table has at most ONE ownedByUser(). If the other column only POINTS at a user, declare it userRef({ onDelete: \u2026 }) instead.`
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
const heldFix = renameCall(held);
|
|
1098
|
-
const originFix = renameCall(origin);
|
|
1099
|
-
const remedy = heldFix === originFix ? `rename one of them: ${heldFix}` : `rename one of them \u2014 "${held.table}.${held.column}": ${heldFix}; "${origin.table}.${origin.column}": ${originFix}`;
|
|
1100
|
-
throw new Error(
|
|
1101
|
-
`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
names.set(name, origin);
|
|
1105
|
-
out.get(tableKey)?.push(edge);
|
|
1106
|
-
};
|
|
1107
|
-
for (const schema of schemas) {
|
|
1108
|
-
for (const table of Object.values(schema.tables)) {
|
|
1109
|
-
const childKey = qualifiedTableKey(schema.name, table.name);
|
|
1110
|
-
if (!out.has(childKey)) continue;
|
|
1111
|
-
for (const [col, builder] of Object.entries(table.columns)) {
|
|
1112
|
-
const def = builder._def;
|
|
1113
|
-
if (def.references === void 0) continue;
|
|
1114
|
-
const targetKey = def.references.table;
|
|
1115
|
-
const name = def.owns === true ? "owner" : def.refAs ?? forwardName(col);
|
|
1116
|
-
claim(
|
|
1117
|
-
childKey,
|
|
1118
|
-
name,
|
|
1119
|
-
{ table: table.name, column: col, direction: "forward", def },
|
|
1120
|
-
{ name, to: targetKey, kind: "one", via: col }
|
|
1121
|
-
);
|
|
1122
|
-
if (!out.has(targetKey) || targetKey === childKey) continue;
|
|
1123
|
-
const reverse = def.reverseAs ?? table.name;
|
|
1124
|
-
claim(
|
|
1125
|
-
targetKey,
|
|
1126
|
-
reverse,
|
|
1127
|
-
{ table: table.name, column: col, direction: "reverse", def },
|
|
1128
|
-
{ name: reverse, to: childKey, kind: "many", via: col }
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
return out;
|
|
1134
|
-
}
|
|
1135
|
-
function tableBlock(table, relations, indent) {
|
|
1136
|
-
const cols = Object.entries(table.columns);
|
|
1137
|
-
const rowLines = cols.map(([col, builder]) => {
|
|
1138
|
-
return `${indent} ${col}: ${rowType(builder._def)};`;
|
|
1139
|
-
});
|
|
1140
|
-
const insertLines = cols.map(([col, builder]) => {
|
|
1141
|
-
const def = builder._def;
|
|
1142
|
-
const opt = optionalOnInsert(def) ? "?" : "";
|
|
1143
|
-
return `${indent} ${col}${opt}: ${rowType(def)};`;
|
|
1144
|
-
});
|
|
1145
|
-
const relEntries = relations.map(
|
|
1146
|
-
(r) => `${r.name}: { to: ${JSON.stringify(r.to)}; kind: ${JSON.stringify(r.kind)}; via: ${JSON.stringify(r.via)} }`
|
|
1147
|
-
).join("; ");
|
|
1148
|
-
return [
|
|
1149
|
-
`${indent}${table.name}: {`,
|
|
1150
|
-
`${indent} row: {`,
|
|
1151
|
-
...rowLines,
|
|
1152
|
-
`${indent} };`,
|
|
1153
|
-
`${indent} insert: {`,
|
|
1154
|
-
...insertLines,
|
|
1155
|
-
`${indent} };`,
|
|
1156
|
-
`${indent} relations: {${relEntries === "" ? "" : ` ${relEntries} `}};`,
|
|
1157
|
-
// searchable: vector kolonu YA DA search beyanı → EnvTypedTable'da search()
|
|
1158
|
-
// üyesini açan yapısal bayrak (FR-013). Yokken satır hiç üretilmez ki
|
|
1159
|
-
// mevcut şemaların d.ts'i bayt-aynı kalsın.
|
|
1160
|
-
...cols.some(([, b]) => b._def.type === "vector") || table.search !== void 0 ? [`${indent} searchable: true;`] : [],
|
|
1161
|
-
`${indent}};`
|
|
1162
|
-
].join("\n");
|
|
1163
|
-
}
|
|
1164
|
-
function makeEnvDts(schemas) {
|
|
1165
|
-
const relations = buildRelations(schemas);
|
|
1166
|
-
const publicSchema = schemas.find((s) => s.name === "public");
|
|
1167
|
-
const others = schemas.filter((s) => s.name !== "public");
|
|
1168
|
-
const publicBlocks = Object.keys(publicSchema?.tables ?? {}).map(
|
|
1169
|
-
(name) => tableBlock(publicSchema.tables[name], relations.get(name) ?? [], " ")
|
|
1170
|
-
);
|
|
1171
|
-
const body = publicBlocks.length > 0 ? `
|
|
1172
|
-
${publicBlocks.join("\n")}
|
|
1173
|
-
` : "";
|
|
1174
|
-
const schemaBlocks = others.map((schema) => {
|
|
1175
|
-
const inner = Object.keys(schema.tables).map(
|
|
1176
|
-
(name) => tableBlock(schema.tables[name], relations.get(qualifiedTableKey(schema.name, name)) ?? [], " ")
|
|
1177
|
-
);
|
|
1178
|
-
return ` ${schema.name}: {
|
|
1179
|
-
${inner.join("\n")}
|
|
1180
|
-
};`;
|
|
1181
|
-
});
|
|
1182
|
-
const schemasBody = schemaBlocks.length > 0 ? `
|
|
1183
|
-
${schemaBlocks.join("\n")}
|
|
1184
|
-
` : "";
|
|
1185
|
-
return `// AUTO-GENERATED by @palbase/backend \u2014 DO NOT EDIT.
|
|
1186
|
-
// Regenerated from db/*.ts by \`palbase build\` and by every deploy.
|
|
1187
|
-
// Augments the @palbase/backend/env \`Tables\` interface so \`Database.tables.*\`
|
|
1188
|
-
// is typed with no import and no generic. Schemas other than \`public\` land
|
|
1189
|
-
// under \`Schemas\`, reached with \`Database.schema("<name>").tables.*\`.
|
|
1190
|
-
|
|
1191
|
-
declare module "@palbase/backend/env" {
|
|
1192
|
-
interface Tables {${body}}
|
|
1193
|
-
interface Schemas {${schemasBody}}
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
export {};
|
|
1197
|
-
`;
|
|
1198
|
-
}
|
|
1278
|
+
__name(sameDeclaration, "sameDeclaration");
|
|
1199
1279
|
|
|
1200
1280
|
// src/stack-gen.ts
|
|
1201
1281
|
function liveNames(names) {
|
|
1202
|
-
return [
|
|
1282
|
+
return [
|
|
1283
|
+
...new Set(names)
|
|
1284
|
+
].sort();
|
|
1203
1285
|
}
|
|
1286
|
+
__name(liveNames, "liveNames");
|
|
1204
1287
|
function memberName(name) {
|
|
1205
1288
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
|
|
1206
1289
|
}
|
|
1290
|
+
__name(memberName, "memberName");
|
|
1207
1291
|
function members(names) {
|
|
1208
1292
|
if (names.length === 0) return "";
|
|
1209
1293
|
return `
|
|
1210
1294
|
${names.map((n) => ` ${memberName(n)}: true;`).join("\n")}
|
|
1211
1295
|
`;
|
|
1212
1296
|
}
|
|
1297
|
+
__name(members, "members");
|
|
1213
1298
|
function bucketMembers(buckets) {
|
|
1214
|
-
const normalized = buckets.map((b) => typeof b === "string" ? {
|
|
1299
|
+
const normalized = buckets.map((b) => typeof b === "string" ? {
|
|
1300
|
+
name: b,
|
|
1301
|
+
variants: []
|
|
1302
|
+
} : b);
|
|
1215
1303
|
const byName = /* @__PURE__ */ new Map();
|
|
1216
1304
|
for (const b of normalized) byName.set(b.name, b.variants);
|
|
1217
|
-
const names = [
|
|
1305
|
+
const names = [
|
|
1306
|
+
...byName.keys()
|
|
1307
|
+
].sort();
|
|
1218
1308
|
if (names.length === 0) return "";
|
|
1219
1309
|
const rows = names.map((name) => {
|
|
1220
|
-
const variants = [
|
|
1310
|
+
const variants = [
|
|
1311
|
+
...new Set(byName.get(name) ?? [])
|
|
1312
|
+
].sort();
|
|
1221
1313
|
const union = variants.length === 0 ? "never" : variants.map((v) => JSON.stringify(v)).join(" | ");
|
|
1222
1314
|
return ` ${memberName(name)}: { variants: ${union} };`;
|
|
1223
1315
|
});
|
|
@@ -1225,6 +1317,7 @@ function bucketMembers(buckets) {
|
|
|
1225
1317
|
${rows.join("\n")}
|
|
1226
1318
|
`;
|
|
1227
1319
|
}
|
|
1320
|
+
__name(bucketMembers, "bucketMembers");
|
|
1228
1321
|
function makeStackDts(names) {
|
|
1229
1322
|
const secrets = liveNames(names.secrets);
|
|
1230
1323
|
const flags = liveNames(names.flags);
|
|
@@ -1242,20 +1335,20 @@ declare module "@palbase/backend/stack" {
|
|
|
1242
1335
|
export {};
|
|
1243
1336
|
`;
|
|
1244
1337
|
}
|
|
1338
|
+
__name(makeStackDts, "makeStackDts");
|
|
1245
1339
|
|
|
1246
1340
|
// src/decorators/methods.ts
|
|
1247
1341
|
function makeMethodDecorator(method) {
|
|
1248
1342
|
return function(subpath, options = {}) {
|
|
1249
1343
|
if (typeof subpath !== "string") {
|
|
1250
|
-
throw new Error(
|
|
1251
|
-
`@${method[0]}${method.slice(1).toLowerCase()}(subpath) expects a string subpath, got ${typeof subpath}.` + (method === "QUERY" ? " If this is a zod schema on a method parameter: the query-string param decorator was renamed @QueryParams(schema) in @palbase/backend 9.0.0." : "")
|
|
1252
|
-
);
|
|
1344
|
+
throw new Error(`@${method[0]}${method.slice(1).toLowerCase()}(subpath) expects a string subpath, got ${typeof subpath}.` + (method === "QUERY" ? " If this is a zod schema on a method parameter: the query-string param decorator was renamed @QueryParams(schema) in @palbase/backend 9.0.0." : ""));
|
|
1253
1345
|
}
|
|
1254
1346
|
return function(target, propertyKey) {
|
|
1255
1347
|
recordRoute(target, String(propertyKey), method, subpath, options);
|
|
1256
1348
|
};
|
|
1257
1349
|
};
|
|
1258
1350
|
}
|
|
1351
|
+
__name(makeMethodDecorator, "makeMethodDecorator");
|
|
1259
1352
|
var Get = makeMethodDecorator("GET");
|
|
1260
1353
|
var Post = makeMethodDecorator("POST");
|
|
1261
1354
|
var Put = makeMethodDecorator("PUT");
|
|
@@ -1263,12 +1356,25 @@ var Patch = makeMethodDecorator("PATCH");
|
|
|
1263
1356
|
var Delete = makeMethodDecorator("DELETE");
|
|
1264
1357
|
var Query = makeMethodDecorator("QUERY");
|
|
1265
1358
|
|
|
1359
|
+
// src/decorators/surface-name.ts
|
|
1360
|
+
var SHAPE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
1361
|
+
function assertSurfaceName(name, decorator, kind) {
|
|
1362
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
1363
|
+
throw new Error(`${decorator} requires a \`name\` \u2014 it is this ${kind}'s identity, and it is declared rather than taken from the file name.`);
|
|
1364
|
+
}
|
|
1365
|
+
if (!SHAPE.test(name)) {
|
|
1366
|
+
throw new Error(`${decorator} name "${name}" is not usable: it reaches a URL and a log line, so it must be lowercase letters, digits and dashes, starting and ending with one of those.`);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
__name(assertSurfaceName, "assertSurfaceName");
|
|
1370
|
+
|
|
1266
1371
|
// src/decorators/webhook.ts
|
|
1267
1372
|
var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
|
|
1268
1373
|
var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
|
|
1269
1374
|
function carrierOf(ctor) {
|
|
1270
1375
|
return ctor;
|
|
1271
1376
|
}
|
|
1377
|
+
__name(carrierOf, "carrierOf");
|
|
1272
1378
|
function Webhook(options) {
|
|
1273
1379
|
return function(ctor) {
|
|
1274
1380
|
const carrier = carrierOf(ctor);
|
|
@@ -1287,12 +1393,18 @@ function Webhook(options) {
|
|
|
1287
1393
|
return ctor;
|
|
1288
1394
|
};
|
|
1289
1395
|
}
|
|
1396
|
+
__name(Webhook, "Webhook");
|
|
1290
1397
|
function On(event) {
|
|
1291
1398
|
return function(target, fnName) {
|
|
1292
1399
|
const carrier = carrierOf(target.constructor);
|
|
1293
1400
|
const existing = carrier[WEBHOOK_EVENTS];
|
|
1294
|
-
const entries = existing ? [
|
|
1295
|
-
|
|
1401
|
+
const entries = existing ? [
|
|
1402
|
+
...existing
|
|
1403
|
+
] : [];
|
|
1404
|
+
entries.push({
|
|
1405
|
+
event,
|
|
1406
|
+
fnName: String(fnName)
|
|
1407
|
+
});
|
|
1296
1408
|
Object.defineProperty(carrier, WEBHOOK_EVENTS, {
|
|
1297
1409
|
value: entries,
|
|
1298
1410
|
enumerable: false,
|
|
@@ -1301,24 +1413,30 @@ function On(event) {
|
|
|
1301
1413
|
});
|
|
1302
1414
|
};
|
|
1303
1415
|
}
|
|
1304
|
-
|
|
1416
|
+
__name(On, "On");
|
|
1417
|
+
function getWebhookManifest(ctor) {
|
|
1418
|
+
const { meta, entries } = validateWebhook(ctor);
|
|
1419
|
+
return {
|
|
1420
|
+
name: meta.name,
|
|
1421
|
+
provider: meta.provider,
|
|
1422
|
+
secretEnv: meta.secret.env,
|
|
1423
|
+
events: entries.map((e) => e.event)
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
__name(getWebhookManifest, "getWebhookManifest");
|
|
1427
|
+
function validateWebhook(ctor) {
|
|
1305
1428
|
const carrier = carrierOf(ctor);
|
|
1306
1429
|
const meta = carrier[WEBHOOK_META];
|
|
1307
1430
|
const entries = carrier[WEBHOOK_EVENTS] ?? [];
|
|
1308
1431
|
if (!meta) {
|
|
1309
|
-
throw new Error(
|
|
1310
|
-
`@On used on a class that is not decorated with @Webhook (${ctor.name ?? "anonymous"})`
|
|
1311
|
-
);
|
|
1432
|
+
throw new Error(`@On used on a class that is not decorated with @Webhook (${ctor.name ?? "anonymous"})`);
|
|
1312
1433
|
}
|
|
1434
|
+
assertSurfaceName(meta.name, "@Webhook", "webhook");
|
|
1313
1435
|
if (!meta.provider && !meta.signature) {
|
|
1314
|
-
throw new Error(
|
|
1315
|
-
"@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries"
|
|
1316
|
-
);
|
|
1436
|
+
throw new Error("@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries");
|
|
1317
1437
|
}
|
|
1318
1438
|
if (meta.provider && meta.signature) {
|
|
1319
|
-
throw new Error(
|
|
1320
|
-
"@Webhook declares BOTH a `provider` preset and an explicit `signature` \u2014 these are alternatives; keep the one that describes the sender, because only `provider` would be used"
|
|
1321
|
-
);
|
|
1439
|
+
throw new Error("@Webhook declares BOTH a `provider` preset and an explicit `signature` \u2014 these are alternatives; keep the one that describes the sender, because only `provider` would be used");
|
|
1322
1440
|
}
|
|
1323
1441
|
if (meta.signature) {
|
|
1324
1442
|
const sig = meta.signature;
|
|
@@ -1344,8 +1462,15 @@ function getWebhookConfig(ctor) {
|
|
|
1344
1462
|
if (entries.length === 0) {
|
|
1345
1463
|
throw new Error("@Webhook requires at least one @On handler");
|
|
1346
1464
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1465
|
+
return {
|
|
1466
|
+
meta,
|
|
1467
|
+
entries
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
__name(validateWebhook, "validateWebhook");
|
|
1471
|
+
function getWebhookConfig(ctor, container) {
|
|
1472
|
+
const { meta, entries } = validateWebhook(ctor);
|
|
1473
|
+
const instance = container.get(ctor);
|
|
1349
1474
|
const events = /* @__PURE__ */ Object.create(null);
|
|
1350
1475
|
for (const entry of entries) {
|
|
1351
1476
|
if (Object.prototype.hasOwnProperty.call(events, entry.event)) {
|
|
@@ -1354,15 +1479,23 @@ function getWebhookConfig(ctor) {
|
|
|
1354
1479
|
events[entry.event] = (event, metaArg) => instance[entry.fnName].call(instance, event, metaArg);
|
|
1355
1480
|
}
|
|
1356
1481
|
return {
|
|
1357
|
-
...meta.provider ? {
|
|
1358
|
-
|
|
1482
|
+
...meta.provider ? {
|
|
1483
|
+
provider: meta.provider
|
|
1484
|
+
} : {},
|
|
1485
|
+
...meta.signature ? {
|
|
1486
|
+
signature: meta.signature
|
|
1487
|
+
} : {},
|
|
1359
1488
|
secret: meta.secret,
|
|
1360
1489
|
events
|
|
1361
1490
|
};
|
|
1362
1491
|
}
|
|
1492
|
+
__name(getWebhookConfig, "getWebhookConfig");
|
|
1363
1493
|
|
|
1364
1494
|
// src/decorators/hook.ts
|
|
1365
1495
|
var Deny = class extends Error {
|
|
1496
|
+
static {
|
|
1497
|
+
__name(this, "Deny");
|
|
1498
|
+
}
|
|
1366
1499
|
constructor(reason) {
|
|
1367
1500
|
super(reason);
|
|
1368
1501
|
this.name = "Deny";
|
|
@@ -1373,8 +1506,13 @@ function Hook(event) {
|
|
|
1373
1506
|
return function(target, fnName) {
|
|
1374
1507
|
const carrier = target.constructor;
|
|
1375
1508
|
const existing = carrier[HOOK_BLOCKING];
|
|
1376
|
-
const entries = existing ? [
|
|
1377
|
-
|
|
1509
|
+
const entries = existing ? [
|
|
1510
|
+
...existing
|
|
1511
|
+
] : [];
|
|
1512
|
+
entries.push({
|
|
1513
|
+
event,
|
|
1514
|
+
fnName: String(fnName)
|
|
1515
|
+
});
|
|
1378
1516
|
Object.defineProperty(carrier, HOOK_BLOCKING, {
|
|
1379
1517
|
value: entries,
|
|
1380
1518
|
enumerable: false,
|
|
@@ -1383,6 +1521,7 @@ function Hook(event) {
|
|
|
1383
1521
|
});
|
|
1384
1522
|
};
|
|
1385
1523
|
}
|
|
1524
|
+
__name(Hook, "Hook");
|
|
1386
1525
|
function bind(instance, entries, kind) {
|
|
1387
1526
|
const out = /* @__PURE__ */ Object.create(null);
|
|
1388
1527
|
for (const entry of entries) {
|
|
@@ -1397,22 +1536,34 @@ function bind(instance, entries, kind) {
|
|
|
1397
1536
|
}
|
|
1398
1537
|
return out;
|
|
1399
1538
|
}
|
|
1400
|
-
|
|
1539
|
+
__name(bind, "bind");
|
|
1540
|
+
function getHookConfig(ctor, container) {
|
|
1401
1541
|
const carrier = ctor;
|
|
1402
1542
|
const blockingEntries = carrier[HOOK_BLOCKING] ?? [];
|
|
1403
1543
|
const listenerEntries = carrier[WEBHOOK_EVENTS] ?? [];
|
|
1404
1544
|
if (blockingEntries.length === 0 && listenerEntries.length === 0) {
|
|
1405
|
-
throw new Error(
|
|
1406
|
-
`${ctor.name ?? "a hook class"} carries no handler \u2014 a hook file must declare at least one @Hook (blocking) or @On (listener) method`
|
|
1407
|
-
);
|
|
1545
|
+
throw new Error(`${ctor.name ?? "a hook class"} carries no handler \u2014 a hook file must declare at least one @Hook (blocking) or @On (listener) method`);
|
|
1408
1546
|
}
|
|
1409
|
-
|
|
1410
|
-
const instance = new ctor();
|
|
1547
|
+
const instance = container.get(ctor);
|
|
1411
1548
|
return {
|
|
1412
1549
|
blocking: bind(instance, blockingEntries, "@Hook"),
|
|
1413
1550
|
listeners: bind(instance, listenerEntries, "@On")
|
|
1414
1551
|
};
|
|
1415
1552
|
}
|
|
1553
|
+
__name(getHookConfig, "getHookConfig");
|
|
1554
|
+
function getHookManifest(ctor) {
|
|
1555
|
+
const carrier = ctor;
|
|
1556
|
+
const blockingEntries = carrier[HOOK_BLOCKING] ?? [];
|
|
1557
|
+
const listenerEntries = carrier[WEBHOOK_EVENTS] ?? [];
|
|
1558
|
+
if (blockingEntries.length === 0 && listenerEntries.length === 0) {
|
|
1559
|
+
throw new Error(`${ctor.name ?? "a hook class"} carries no handler \u2014 a hook file must declare at least one @Hook (blocking) or @On (listener) method`);
|
|
1560
|
+
}
|
|
1561
|
+
return {
|
|
1562
|
+
blocking: blockingEntries.map((e) => e.event),
|
|
1563
|
+
listeners: listenerEntries.map((e) => e.event)
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
__name(getHookManifest, "getHookManifest");
|
|
1416
1567
|
|
|
1417
1568
|
// src/decorators/upload.ts
|
|
1418
1569
|
function Upload(subpath, config) {
|
|
@@ -1420,13 +1571,18 @@ function Upload(subpath, config) {
|
|
|
1420
1571
|
validateUploadConfigShape(uploadConfig);
|
|
1421
1572
|
const options = {
|
|
1422
1573
|
uploadConfig,
|
|
1423
|
-
...auth !== void 0 ? {
|
|
1424
|
-
|
|
1574
|
+
...auth !== void 0 ? {
|
|
1575
|
+
auth
|
|
1576
|
+
} : {},
|
|
1577
|
+
...rateLimit !== void 0 ? {
|
|
1578
|
+
rateLimit
|
|
1579
|
+
} : {}
|
|
1425
1580
|
};
|
|
1426
1581
|
return function(target, propertyKey) {
|
|
1427
1582
|
recordRoute(target, String(propertyKey), "POST", subpath, options);
|
|
1428
1583
|
};
|
|
1429
1584
|
}
|
|
1585
|
+
__name(Upload, "Upload");
|
|
1430
1586
|
function UploadedObject() {
|
|
1431
1587
|
return function(target, propertyKey, parameterIndex) {
|
|
1432
1588
|
recordParam(target, String(propertyKey), {
|
|
@@ -1435,6 +1591,7 @@ function UploadedObject() {
|
|
|
1435
1591
|
});
|
|
1436
1592
|
};
|
|
1437
1593
|
}
|
|
1594
|
+
__name(UploadedObject, "UploadedObject");
|
|
1438
1595
|
function validateUploadConfigShape(c) {
|
|
1439
1596
|
if (c === null || typeof c !== "object") {
|
|
1440
1597
|
throw new Error("@Upload config must be an object { bucket, pathTemplate, ... }");
|
|
@@ -1447,37 +1604,49 @@ function validateUploadConfigShape(c) {
|
|
|
1447
1604
|
throw new Error("@Upload config.pathTemplate must be a non-empty key template");
|
|
1448
1605
|
}
|
|
1449
1606
|
}
|
|
1607
|
+
__name(validateUploadConfigShape, "validateUploadConfigShape");
|
|
1450
1608
|
|
|
1451
1609
|
// src/decorators/sse.ts
|
|
1452
1610
|
function Sse(subpath = "", config) {
|
|
1453
1611
|
const { auth, rateLimit, ...sseConfig } = config;
|
|
1454
1612
|
const options = {
|
|
1455
1613
|
sseConfig,
|
|
1456
|
-
...auth !== void 0 ? {
|
|
1457
|
-
|
|
1614
|
+
...auth !== void 0 ? {
|
|
1615
|
+
auth
|
|
1616
|
+
} : {},
|
|
1617
|
+
...rateLimit !== void 0 ? {
|
|
1618
|
+
rateLimit
|
|
1619
|
+
} : {}
|
|
1458
1620
|
};
|
|
1459
1621
|
return function(target, propertyKey) {
|
|
1460
1622
|
recordRoute(target, String(propertyKey), "POST", subpath, options);
|
|
1461
1623
|
};
|
|
1462
1624
|
}
|
|
1625
|
+
__name(Sse, "Sse");
|
|
1463
1626
|
function SseOut() {
|
|
1464
1627
|
return function(target, propertyKey, parameterIndex) {
|
|
1465
|
-
recordParam(target, String(propertyKey), {
|
|
1628
|
+
recordParam(target, String(propertyKey), {
|
|
1629
|
+
index: parameterIndex,
|
|
1630
|
+
kind: "sseOut"
|
|
1631
|
+
});
|
|
1466
1632
|
};
|
|
1467
1633
|
}
|
|
1634
|
+
__name(SseOut, "SseOut");
|
|
1468
1635
|
function Signal() {
|
|
1469
1636
|
return function(target, propertyKey, parameterIndex) {
|
|
1470
|
-
recordParam(target, String(propertyKey), {
|
|
1637
|
+
recordParam(target, String(propertyKey), {
|
|
1638
|
+
index: parameterIndex,
|
|
1639
|
+
kind: "signal"
|
|
1640
|
+
});
|
|
1471
1641
|
};
|
|
1472
1642
|
}
|
|
1643
|
+
__name(Signal, "Signal");
|
|
1473
1644
|
|
|
1474
1645
|
// src/decorators/room.ts
|
|
1475
1646
|
var DEFAULT_GRACE_MS = 6e4;
|
|
1476
1647
|
function assertPattern(pattern) {
|
|
1477
1648
|
if (pattern.includes("/")) {
|
|
1478
|
-
throw new Error(
|
|
1479
|
-
`@Room("${pattern}"): channel patterns are colon-separated, not slash-separated. Write "${pattern.replace(/\//g, ":")}" \u2014 a slash matches no live topic.`
|
|
1480
|
-
);
|
|
1649
|
+
throw new Error(`@Room("${pattern}"): channel patterns are colon-separated, not slash-separated. Write "${pattern.replace(/\//g, ":")}" \u2014 a slash matches no live topic.`);
|
|
1481
1650
|
}
|
|
1482
1651
|
const segments = pattern.split(":");
|
|
1483
1652
|
if (segments.some((s) => s === "")) {
|
|
@@ -1494,6 +1663,7 @@ function assertPattern(pattern) {
|
|
|
1494
1663
|
seen.add(name);
|
|
1495
1664
|
}
|
|
1496
1665
|
}
|
|
1666
|
+
__name(assertPattern, "assertPattern");
|
|
1497
1667
|
function Room(pattern, options) {
|
|
1498
1668
|
return function(ctor) {
|
|
1499
1669
|
assertPattern(pattern);
|
|
@@ -1505,11 +1675,13 @@ function Room(pattern, options) {
|
|
|
1505
1675
|
return ctor;
|
|
1506
1676
|
};
|
|
1507
1677
|
}
|
|
1678
|
+
__name(Room, "Room");
|
|
1508
1679
|
function hookDecorator(hook) {
|
|
1509
1680
|
return () => function(target, propertyKey) {
|
|
1510
1681
|
recordRoomHook(target, hook, String(propertyKey));
|
|
1511
1682
|
};
|
|
1512
1683
|
}
|
|
1684
|
+
__name(hookDecorator, "hookDecorator");
|
|
1513
1685
|
var OnAuthorize = hookDecorator("authorize");
|
|
1514
1686
|
var OnFirst = hookDecorator("first");
|
|
1515
1687
|
var OnJoin = hookDecorator("join");
|
|
@@ -1520,6 +1692,7 @@ function OnMessage(name, schema) {
|
|
|
1520
1692
|
recordRoomMessage(target, name, String(propertyKey), schema);
|
|
1521
1693
|
};
|
|
1522
1694
|
}
|
|
1695
|
+
__name(OnMessage, "OnMessage");
|
|
1523
1696
|
|
|
1524
1697
|
// src/decorators/params.ts
|
|
1525
1698
|
function makeParamDecorator(kind, extra) {
|
|
@@ -1527,48 +1700,70 @@ function makeParamDecorator(kind, extra) {
|
|
|
1527
1700
|
recordParam(target, String(propertyKey), {
|
|
1528
1701
|
index: parameterIndex,
|
|
1529
1702
|
kind,
|
|
1530
|
-
...extra?.schema !== void 0 ? {
|
|
1531
|
-
|
|
1703
|
+
...extra?.schema !== void 0 ? {
|
|
1704
|
+
schema: extra.schema
|
|
1705
|
+
} : {},
|
|
1706
|
+
...extra?.name !== void 0 ? {
|
|
1707
|
+
name: extra.name
|
|
1708
|
+
} : {}
|
|
1532
1709
|
});
|
|
1533
1710
|
};
|
|
1534
1711
|
}
|
|
1712
|
+
__name(makeParamDecorator, "makeParamDecorator");
|
|
1535
1713
|
function Body(schema) {
|
|
1536
|
-
return makeParamDecorator("body", {
|
|
1714
|
+
return makeParamDecorator("body", {
|
|
1715
|
+
schema
|
|
1716
|
+
});
|
|
1537
1717
|
}
|
|
1718
|
+
__name(Body, "Body");
|
|
1538
1719
|
function QueryParams(schema) {
|
|
1539
|
-
return makeParamDecorator("query", {
|
|
1720
|
+
return makeParamDecorator("query", {
|
|
1721
|
+
schema
|
|
1722
|
+
});
|
|
1540
1723
|
}
|
|
1724
|
+
__name(QueryParams, "QueryParams");
|
|
1541
1725
|
function Headers(schema) {
|
|
1542
|
-
return makeParamDecorator("headers", schema !== void 0 ? {
|
|
1726
|
+
return makeParamDecorator("headers", schema !== void 0 ? {
|
|
1727
|
+
schema
|
|
1728
|
+
} : void 0);
|
|
1543
1729
|
}
|
|
1730
|
+
__name(Headers, "Headers");
|
|
1544
1731
|
function Param(name) {
|
|
1545
|
-
return makeParamDecorator("param", {
|
|
1732
|
+
return makeParamDecorator("param", {
|
|
1733
|
+
name
|
|
1734
|
+
});
|
|
1546
1735
|
}
|
|
1736
|
+
__name(Param, "Param");
|
|
1547
1737
|
function User() {
|
|
1548
1738
|
return makeParamDecorator("user");
|
|
1549
1739
|
}
|
|
1740
|
+
__name(User, "User");
|
|
1550
1741
|
function OptionalUser() {
|
|
1551
1742
|
return makeParamDecorator("optionalUser");
|
|
1552
1743
|
}
|
|
1744
|
+
__name(OptionalUser, "OptionalUser");
|
|
1553
1745
|
function Client() {
|
|
1554
1746
|
return makeParamDecorator("client");
|
|
1555
1747
|
}
|
|
1748
|
+
__name(Client, "Client");
|
|
1556
1749
|
function RequestId() {
|
|
1557
1750
|
return makeParamDecorator("requestId");
|
|
1558
1751
|
}
|
|
1752
|
+
__name(RequestId, "RequestId");
|
|
1559
1753
|
function TraceId() {
|
|
1560
1754
|
return makeParamDecorator("traceId");
|
|
1561
1755
|
}
|
|
1756
|
+
__name(TraceId, "TraceId");
|
|
1562
1757
|
function Req() {
|
|
1563
1758
|
return makeParamDecorator("req");
|
|
1564
1759
|
}
|
|
1760
|
+
__name(Req, "Req");
|
|
1565
1761
|
|
|
1566
1762
|
// src/middleware.ts
|
|
1567
1763
|
function defineMiddleware(_fn) {
|
|
1568
|
-
throw new Error(
|
|
1569
|
-
"defineMiddleware() is not wired to anything: no bundler reads a `middleware/` directory and the engine has no middleware pipeline, so a handler defined here deploys and never runs. Put cross-cutting work in a service the controllers call, and use route options for auth (`@Controller(path, { auth })`) and rate limits (`@Get(path, { rateLimit })`)."
|
|
1570
|
-
);
|
|
1764
|
+
throw new Error("defineMiddleware() is not wired to anything: no bundler reads a `middleware/` directory and the engine has no middleware pipeline, so a handler defined here deploys and never runs. Put cross-cutting work in a service the controllers call, and use route options for auth (`@Controller(path, { auth })`) and rate limits (`@Get(path, { rateLimit })`).");
|
|
1571
1765
|
}
|
|
1766
|
+
__name(defineMiddleware, "defineMiddleware");
|
|
1572
1767
|
|
|
1573
1768
|
// src/job.ts
|
|
1574
1769
|
function validateCronExpression(expression) {
|
|
@@ -1580,13 +1775,34 @@ function validateCronExpression(expression) {
|
|
|
1580
1775
|
if (parts.length !== 5) {
|
|
1581
1776
|
return `Invalid cron expression "${trimmed}": expected 5 fields (minute hour day month weekday), got ${parts.length}`;
|
|
1582
1777
|
}
|
|
1583
|
-
const fieldNames = [
|
|
1778
|
+
const fieldNames = [
|
|
1779
|
+
"minute",
|
|
1780
|
+
"hour",
|
|
1781
|
+
"day of month",
|
|
1782
|
+
"month",
|
|
1783
|
+
"day of week"
|
|
1784
|
+
];
|
|
1584
1785
|
const fieldRanges = [
|
|
1585
|
-
[
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
[
|
|
1786
|
+
[
|
|
1787
|
+
0,
|
|
1788
|
+
59
|
|
1789
|
+
],
|
|
1790
|
+
[
|
|
1791
|
+
0,
|
|
1792
|
+
23
|
|
1793
|
+
],
|
|
1794
|
+
[
|
|
1795
|
+
1,
|
|
1796
|
+
31
|
|
1797
|
+
],
|
|
1798
|
+
[
|
|
1799
|
+
1,
|
|
1800
|
+
12
|
|
1801
|
+
],
|
|
1802
|
+
[
|
|
1803
|
+
0,
|
|
1804
|
+
7
|
|
1805
|
+
]
|
|
1590
1806
|
];
|
|
1591
1807
|
for (let i = 0; i < 5; i++) {
|
|
1592
1808
|
const field = parts[i];
|
|
@@ -1599,6 +1815,7 @@ function validateCronExpression(expression) {
|
|
|
1599
1815
|
}
|
|
1600
1816
|
return null;
|
|
1601
1817
|
}
|
|
1818
|
+
__name(validateCronExpression, "validateCronExpression");
|
|
1602
1819
|
function validateCronField(field, name, min, max) {
|
|
1603
1820
|
const listParts = field.split(",");
|
|
1604
1821
|
for (const part of listParts) {
|
|
@@ -1636,6 +1853,7 @@ function validateCronField(field, name, min, max) {
|
|
|
1636
1853
|
}
|
|
1637
1854
|
return null;
|
|
1638
1855
|
}
|
|
1856
|
+
__name(validateCronField, "validateCronField");
|
|
1639
1857
|
|
|
1640
1858
|
// src/decorators/job.ts
|
|
1641
1859
|
var DEFAULT_TIMEOUT_SECONDS = 30;
|
|
@@ -1661,13 +1879,13 @@ function Job(options) {
|
|
|
1661
1879
|
return ctor;
|
|
1662
1880
|
};
|
|
1663
1881
|
}
|
|
1664
|
-
|
|
1882
|
+
__name(Job, "Job");
|
|
1883
|
+
function getJobManifest(ctor) {
|
|
1665
1884
|
const meta = ctor[JOB_META];
|
|
1666
1885
|
if (!meta) {
|
|
1667
|
-
throw new Error(
|
|
1668
|
-
`getJobConfig on a class with no @Job decorator (${ctor.name ?? "anonymous"})`
|
|
1669
|
-
);
|
|
1886
|
+
throw new Error(`getJobConfig on a class with no @Job decorator (${ctor.name ?? "anonymous"})`);
|
|
1670
1887
|
}
|
|
1888
|
+
assertSurfaceName(meta.name, "@Job", "job");
|
|
1671
1889
|
if (!meta.schedule || meta.schedule.trim() === "") {
|
|
1672
1890
|
throw new Error("@Job requires a `schedule` cron expression");
|
|
1673
1891
|
}
|
|
@@ -1689,14 +1907,30 @@ function getJobConfig(ctor) {
|
|
|
1689
1907
|
if (retry > MAX_RETRY) {
|
|
1690
1908
|
throw new Error(`@Job \`retry\` exceeds the ceiling of ${MAX_RETRY}`);
|
|
1691
1909
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1910
|
+
return {
|
|
1911
|
+
name: meta.name,
|
|
1912
|
+
schedule: meta.schedule,
|
|
1913
|
+
timeout,
|
|
1914
|
+
retry
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
__name(getJobManifest, "getJobManifest");
|
|
1918
|
+
function getJobConfig(ctor, container) {
|
|
1919
|
+
const { name, schedule, timeout, retry } = getJobManifest(ctor);
|
|
1920
|
+
const instance = container.get(ctor);
|
|
1694
1921
|
if (typeof instance.run !== "function") {
|
|
1695
1922
|
throw new Error("@Job class must declare an async run() method");
|
|
1696
1923
|
}
|
|
1697
1924
|
const run = instance.run.bind(instance);
|
|
1698
|
-
return {
|
|
1925
|
+
return {
|
|
1926
|
+
name,
|
|
1927
|
+
schedule,
|
|
1928
|
+
timeout,
|
|
1929
|
+
retry,
|
|
1930
|
+
handler: run
|
|
1931
|
+
};
|
|
1699
1932
|
}
|
|
1933
|
+
__name(getJobConfig, "getJobConfig");
|
|
1700
1934
|
|
|
1701
1935
|
// src/index.ts
|
|
1702
1936
|
import { z } from "zod";
|
|
@@ -1708,8 +1942,10 @@ export {
|
|
|
1708
1942
|
Conflict,
|
|
1709
1943
|
Controller,
|
|
1710
1944
|
Database,
|
|
1945
|
+
DeadlockDetected,
|
|
1711
1946
|
Delete,
|
|
1712
1947
|
Deny,
|
|
1948
|
+
DiError,
|
|
1713
1949
|
Documents,
|
|
1714
1950
|
EXTENSION_DEPENDENCIES,
|
|
1715
1951
|
Flags,
|
|
@@ -1718,8 +1954,11 @@ export {
|
|
|
1718
1954
|
Headers,
|
|
1719
1955
|
Hook,
|
|
1720
1956
|
HttpError,
|
|
1957
|
+
IndexBuilder,
|
|
1958
|
+
Injectable,
|
|
1721
1959
|
Job,
|
|
1722
1960
|
Log,
|
|
1961
|
+
Module,
|
|
1723
1962
|
NotFound,
|
|
1724
1963
|
Notifications,
|
|
1725
1964
|
On,
|
|
@@ -1736,6 +1975,7 @@ export {
|
|
|
1736
1975
|
Param,
|
|
1737
1976
|
Patch,
|
|
1738
1977
|
PolicyBuilder,
|
|
1978
|
+
PolicyExprRef,
|
|
1739
1979
|
Post,
|
|
1740
1980
|
Put,
|
|
1741
1981
|
Query,
|
|
@@ -1745,6 +1985,7 @@ export {
|
|
|
1745
1985
|
RequestId,
|
|
1746
1986
|
Room,
|
|
1747
1987
|
Secrets,
|
|
1988
|
+
SerializationFailure,
|
|
1748
1989
|
Signal,
|
|
1749
1990
|
Sse,
|
|
1750
1991
|
SseOut,
|
|
@@ -1760,6 +2001,8 @@ export {
|
|
|
1760
2001
|
UploadedObject,
|
|
1761
2002
|
User,
|
|
1762
2003
|
Webhook,
|
|
2004
|
+
__claimInjectables,
|
|
2005
|
+
__claimModules,
|
|
1763
2006
|
__getRuntime,
|
|
1764
2007
|
__requestALS,
|
|
1765
2008
|
__resetDefaultAuth,
|
|
@@ -1768,11 +2011,16 @@ export {
|
|
|
1768
2011
|
__runStartHooks,
|
|
1769
2012
|
__runWithRuntime,
|
|
1770
2013
|
__setRuntime,
|
|
2014
|
+
assertNoOrphanEntryPoints,
|
|
1771
2015
|
assertZeroArgConstructor,
|
|
1772
2016
|
bigint,
|
|
1773
2017
|
boolean,
|
|
2018
|
+
buildContainer,
|
|
1774
2019
|
buildModuleClients,
|
|
2020
|
+
col,
|
|
2021
|
+
controllersOf,
|
|
1775
2022
|
dec,
|
|
2023
|
+
decrement,
|
|
1776
2024
|
defineChannels,
|
|
1777
2025
|
defineDefaultAuth,
|
|
1778
2026
|
defineError,
|
|
@@ -1780,16 +2028,25 @@ export {
|
|
|
1780
2028
|
defineSchema,
|
|
1781
2029
|
defineTable,
|
|
1782
2030
|
enumType,
|
|
2031
|
+
exprCtx,
|
|
1783
2032
|
getErrorRegistry,
|
|
1784
2033
|
getHookConfig,
|
|
2034
|
+
getHookManifest,
|
|
1785
2035
|
getJobConfig,
|
|
2036
|
+
getJobManifest,
|
|
1786
2037
|
getRegisteredControllers,
|
|
1787
2038
|
getRoutes,
|
|
1788
2039
|
getWebhookConfig,
|
|
2040
|
+
getWebhookManifest,
|
|
2041
|
+
hooksOf,
|
|
1789
2042
|
inc,
|
|
2043
|
+
increment,
|
|
2044
|
+
index,
|
|
1790
2045
|
installationRef,
|
|
1791
2046
|
integer,
|
|
1792
2047
|
isPalbaseExtension,
|
|
2048
|
+
isRetryable,
|
|
2049
|
+
jobsOf,
|
|
1793
2050
|
jsonb,
|
|
1794
2051
|
makeEnvDts,
|
|
1795
2052
|
makeHttpClient,
|
|
@@ -1807,12 +2064,16 @@ export {
|
|
|
1807
2064
|
raw,
|
|
1808
2065
|
recordThrows,
|
|
1809
2066
|
resolveEffectiveAuth,
|
|
2067
|
+
roomsOf,
|
|
2068
|
+
sqlFragment,
|
|
1810
2069
|
text,
|
|
1811
2070
|
timestamp,
|
|
1812
2071
|
toSchemaJSON,
|
|
1813
2072
|
userRef,
|
|
1814
2073
|
uuid,
|
|
1815
2074
|
vector,
|
|
2075
|
+
webhooksOf,
|
|
2076
|
+
withRetry,
|
|
1816
2077
|
z
|
|
1817
2078
|
};
|
|
1818
2079
|
//# sourceMappingURL=index.js.map
|