@palbase/backend 10.3.0 → 12.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-7LAXRLPG.js +418 -0
- package/dist/chunk-7LAXRLPG.js.map +1 -0
- package/dist/{chunk-4WOQWFUP.js → chunk-LUV36KQU.js} +26 -11
- package/dist/{chunk-4WOQWFUP.js.map → chunk-LUV36KQU.js.map} +1 -1
- package/dist/{chunk-2PCNZBNZ.js → chunk-XATG7BRC.js} +20 -2
- package/dist/chunk-XATG7BRC.js.map +1 -0
- package/dist/db/index.cjs +438 -10
- 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 +13 -1
- package/dist/{endpoint-92kVepng.d.cts → endpoint-Ck4hER_7.d.cts} +343 -11
- package/dist/{endpoint-92kVepng.d.ts → endpoint-Ck4hER_7.d.ts} +343 -11
- package/dist/{index-BaHs33jr.d.cts → index-BJAf1uPC.d.cts} +64 -34
- package/dist/{index-DfryIw9U.d.ts → index-l7DhBDtn.d.ts} +64 -34
- package/dist/index.cjs +589 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -162
- package/dist/index.d.ts +60 -162
- package/dist/index.js +139 -108
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +545 -12
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +153 -12
- package/dist/test/index.js.map +1 -1
- package/docs/background.md +8 -9
- package/docs/database.md +106 -16
- package/docs/events.md +20 -17
- package/docs/llms-full.txt +141 -47
- package/docs/schema.md +6 -4
- package/package.json +1 -1
- package/dist/chunk-2PCNZBNZ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
__requestALS,
|
|
14
14
|
__runWithRuntime,
|
|
15
15
|
__setRuntime
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XATG7BRC.js";
|
|
17
17
|
import {
|
|
18
18
|
EXTENSION_DEPENDENCIES,
|
|
19
19
|
PALBASE_EXTENSIONS,
|
|
@@ -32,7 +32,14 @@ import {
|
|
|
32
32
|
text,
|
|
33
33
|
timestamp,
|
|
34
34
|
uuid
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-LUV36KQU.js";
|
|
36
|
+
import {
|
|
37
|
+
TxPlanError,
|
|
38
|
+
TxRefError,
|
|
39
|
+
dec,
|
|
40
|
+
inc,
|
|
41
|
+
now
|
|
42
|
+
} from "./chunk-7LAXRLPG.js";
|
|
36
43
|
|
|
37
44
|
// src/errors.ts
|
|
38
45
|
var HttpError = class extends Error {
|
|
@@ -836,6 +843,12 @@ function defineFlags(input) {
|
|
|
836
843
|
var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta");
|
|
837
844
|
function Controller(basePath, options = {}) {
|
|
838
845
|
return function(ctor) {
|
|
846
|
+
const normalized = basePath.replace(/\/+$/, "");
|
|
847
|
+
if (normalized === "/webhooks" || normalized.startsWith("/webhooks/")) {
|
|
848
|
+
throw new Error(
|
|
849
|
+
`@Controller("${basePath}") uses the reserved /webhooks path \u2014 inbound webhooks are served there`
|
|
850
|
+
);
|
|
851
|
+
}
|
|
839
852
|
const carrier = ctor;
|
|
840
853
|
const meta = {
|
|
841
854
|
__palbase: "controller",
|
|
@@ -1227,12 +1240,81 @@ function defineWorker(config) {
|
|
|
1227
1240
|
};
|
|
1228
1241
|
}
|
|
1229
1242
|
|
|
1243
|
+
// src/decorators/webhook.ts
|
|
1244
|
+
var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
|
|
1245
|
+
var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
|
|
1246
|
+
function carrierOf3(ctor) {
|
|
1247
|
+
return ctor;
|
|
1248
|
+
}
|
|
1249
|
+
function Webhook(options) {
|
|
1250
|
+
return function(ctor) {
|
|
1251
|
+
const carrier = carrierOf3(ctor);
|
|
1252
|
+
Object.defineProperty(carrier, WEBHOOK_META, {
|
|
1253
|
+
value: options,
|
|
1254
|
+
enumerable: false,
|
|
1255
|
+
configurable: true,
|
|
1256
|
+
writable: false
|
|
1257
|
+
});
|
|
1258
|
+
Object.defineProperty(carrier, "__palbase", {
|
|
1259
|
+
value: "webhook",
|
|
1260
|
+
enumerable: false,
|
|
1261
|
+
configurable: true,
|
|
1262
|
+
writable: false
|
|
1263
|
+
});
|
|
1264
|
+
return ctor;
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
function On(event) {
|
|
1268
|
+
return function(target, fnName) {
|
|
1269
|
+
const carrier = carrierOf3(target.constructor);
|
|
1270
|
+
const existing = carrier[WEBHOOK_EVENTS];
|
|
1271
|
+
const entries = existing ? [...existing] : [];
|
|
1272
|
+
entries.push({ event, fnName: String(fnName) });
|
|
1273
|
+
Object.defineProperty(carrier, WEBHOOK_EVENTS, {
|
|
1274
|
+
value: entries,
|
|
1275
|
+
enumerable: false,
|
|
1276
|
+
configurable: true,
|
|
1277
|
+
writable: false
|
|
1278
|
+
});
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
function getWebhookConfig(ctor) {
|
|
1282
|
+
const carrier = carrierOf3(ctor);
|
|
1283
|
+
const meta = carrier[WEBHOOK_META];
|
|
1284
|
+
const entries = carrier[WEBHOOK_EVENTS] ?? [];
|
|
1285
|
+
if (!meta) {
|
|
1286
|
+
throw new Error(
|
|
1287
|
+
`@On used on a class that is not decorated with @Webhook (${ctor.name ?? "anonymous"})`
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
if (!meta.provider && !meta.signature) {
|
|
1291
|
+
throw new Error(
|
|
1292
|
+
"@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries"
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
if (!meta.secret?.env) {
|
|
1296
|
+
throw new Error('@Webhook requires `secret: { env: "VAR_NAME" }`');
|
|
1297
|
+
}
|
|
1298
|
+
if (entries.length === 0) {
|
|
1299
|
+
throw new Error("@Webhook requires at least one @On handler");
|
|
1300
|
+
}
|
|
1301
|
+
const instance = new ctor();
|
|
1302
|
+
const events = /* @__PURE__ */ Object.create(null);
|
|
1303
|
+
for (const entry of entries) {
|
|
1304
|
+
if (Object.prototype.hasOwnProperty.call(events, entry.event)) {
|
|
1305
|
+
throw new Error(`@On("${entry.event}") declared twice on the same webhook`);
|
|
1306
|
+
}
|
|
1307
|
+
events[entry.event] = (event, metaArg) => instance[entry.fnName].call(instance, event, metaArg);
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
...meta.provider ? { provider: meta.provider } : {},
|
|
1311
|
+
...meta.signature ? { signature: meta.signature } : {},
|
|
1312
|
+
secret: meta.secret,
|
|
1313
|
+
events
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1230
1317
|
// src/job.ts
|
|
1231
|
-
var VALID_JOB_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
1232
|
-
var MAX_TIMEOUT_SECONDS = 300;
|
|
1233
|
-
var JOB_DEFAULTS = {
|
|
1234
|
-
timeout: 30
|
|
1235
|
-
};
|
|
1236
1318
|
function validateCronExpression(expression) {
|
|
1237
1319
|
const trimmed = expression.trim();
|
|
1238
1320
|
if (trimmed === "") {
|
|
@@ -1298,115 +1380,56 @@ function validateCronField(field, name, min, max) {
|
|
|
1298
1380
|
}
|
|
1299
1381
|
return null;
|
|
1300
1382
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
if (config.timeout !== void 0 && !Number.isInteger(config.timeout)) {
|
|
1324
|
-
throw new Error("Job timeout must be an integer");
|
|
1325
|
-
}
|
|
1326
|
-
if (config.timeout !== void 0 && config.timeout > MAX_TIMEOUT_SECONDS) {
|
|
1327
|
-
throw new Error(
|
|
1328
|
-
`Job timeout ${config.timeout}s exceeds maximum ${MAX_TIMEOUT_SECONDS}s`
|
|
1329
|
-
);
|
|
1330
|
-
}
|
|
1331
|
-
return {
|
|
1332
|
-
name: config.name,
|
|
1333
|
-
schedule: config.schedule.trim(),
|
|
1334
|
-
timeout: config.timeout ?? JOB_DEFAULTS.timeout,
|
|
1335
|
-
handler: config.handler
|
|
1383
|
+
|
|
1384
|
+
// src/decorators/job.ts
|
|
1385
|
+
var DEFAULT_TIMEOUT_SECONDS = 30;
|
|
1386
|
+
var MAX_TIMEOUT_SECONDS = 300;
|
|
1387
|
+
var JOB_META = /* @__PURE__ */ Symbol.for("palbase.backend.jobMeta");
|
|
1388
|
+
function Job(options) {
|
|
1389
|
+
return function(ctor) {
|
|
1390
|
+
const carrier = ctor;
|
|
1391
|
+
Object.defineProperty(carrier, JOB_META, {
|
|
1392
|
+
value: options,
|
|
1393
|
+
enumerable: false,
|
|
1394
|
+
configurable: true,
|
|
1395
|
+
writable: false
|
|
1396
|
+
});
|
|
1397
|
+
Object.defineProperty(carrier, "__palbase", {
|
|
1398
|
+
value: "job",
|
|
1399
|
+
enumerable: false,
|
|
1400
|
+
configurable: true,
|
|
1401
|
+
writable: false
|
|
1402
|
+
});
|
|
1403
|
+
return ctor;
|
|
1336
1404
|
};
|
|
1337
1405
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
function defineWebhook(config) {
|
|
1342
|
-
if ("provider" in config) {
|
|
1343
|
-
return validateProviderWebhook(config);
|
|
1344
|
-
}
|
|
1345
|
-
return validateCustomWebhook(config);
|
|
1346
|
-
}
|
|
1347
|
-
function validateProviderWebhook(config) {
|
|
1348
|
-
if (!config.provider) {
|
|
1349
|
-
throw new Error("Webhook provider is required");
|
|
1350
|
-
}
|
|
1351
|
-
const validProviders = [
|
|
1352
|
-
"stripe",
|
|
1353
|
-
"github",
|
|
1354
|
-
"twilio",
|
|
1355
|
-
"sendgrid",
|
|
1356
|
-
"slack",
|
|
1357
|
-
"discord",
|
|
1358
|
-
"livekit"
|
|
1359
|
-
];
|
|
1360
|
-
if (!validProviders.includes(config.provider)) {
|
|
1406
|
+
function getJobConfig(ctor) {
|
|
1407
|
+
const meta = ctor[JOB_META];
|
|
1408
|
+
if (!meta) {
|
|
1361
1409
|
throw new Error(
|
|
1362
|
-
`
|
|
1410
|
+
`getJobConfig on a class with no @Job decorator (${ctor.name ?? "anonymous"})`
|
|
1363
1411
|
);
|
|
1364
1412
|
}
|
|
1365
|
-
if (!
|
|
1366
|
-
throw new Error(
|
|
1413
|
+
if (!meta.schedule || meta.schedule.trim() === "") {
|
|
1414
|
+
throw new Error("@Job requires a `schedule` cron expression");
|
|
1367
1415
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1416
|
+
const cronError = validateCronExpression(meta.schedule);
|
|
1417
|
+
if (cronError) {
|
|
1418
|
+
throw new Error(`@Job has an invalid cron schedule: ${cronError}`);
|
|
1370
1419
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1420
|
+
const timeout = meta.timeout ?? DEFAULT_TIMEOUT_SECONDS;
|
|
1421
|
+
if (!Number.isInteger(timeout) || timeout <= 0) {
|
|
1422
|
+
throw new Error("@Job `timeout` must be a positive whole number of seconds");
|
|
1373
1423
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
throw new Error(`Event handler for "${eventName}" must be a function`);
|
|
1377
|
-
}
|
|
1424
|
+
if (timeout > MAX_TIMEOUT_SECONDS) {
|
|
1425
|
+
throw new Error(`@Job \`timeout\` exceeds the ${MAX_TIMEOUT_SECONDS}s sandbox ceiling`);
|
|
1378
1426
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
secret: config.secret,
|
|
1383
|
-
events: config.events
|
|
1384
|
-
};
|
|
1385
|
-
}
|
|
1386
|
-
function validateCustomWebhook(config) {
|
|
1387
|
-
if (!config.path || config.path.trim() === "") {
|
|
1388
|
-
throw new Error("Webhook path is required");
|
|
1389
|
-
}
|
|
1390
|
-
if (!VALID_WEBHOOK_PATH.test(config.path)) {
|
|
1391
|
-
throw new Error(
|
|
1392
|
-
`Invalid webhook path "${config.path}": must start with / and contain only alphanumeric, hyphen, underscore, slash`
|
|
1393
|
-
);
|
|
1394
|
-
}
|
|
1395
|
-
if (!config.handler) {
|
|
1396
|
-
throw new Error("Webhook handler is required");
|
|
1427
|
+
const instance = new ctor();
|
|
1428
|
+
if (typeof instance.run !== "function") {
|
|
1429
|
+
throw new Error("@Job class must declare an async run() method");
|
|
1397
1430
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
}
|
|
1401
|
-
if (config.verify !== void 0 && typeof config.verify !== "function") {
|
|
1402
|
-
throw new Error("Webhook verify must be a function");
|
|
1403
|
-
}
|
|
1404
|
-
return {
|
|
1405
|
-
type: "custom",
|
|
1406
|
-
path: config.path,
|
|
1407
|
-
verify: config.verify,
|
|
1408
|
-
handler: config.handler
|
|
1409
|
-
};
|
|
1431
|
+
const run = instance.run.bind(instance);
|
|
1432
|
+
return { schedule: meta.schedule, timeout, handler: run };
|
|
1410
1433
|
}
|
|
1411
1434
|
|
|
1412
1435
|
// src/resource.ts
|
|
@@ -1510,10 +1533,12 @@ export {
|
|
|
1510
1533
|
Get,
|
|
1511
1534
|
Headers,
|
|
1512
1535
|
HttpError,
|
|
1536
|
+
Job,
|
|
1513
1537
|
Log,
|
|
1514
1538
|
NOTIFICATIONS_CONFIG_KIND,
|
|
1515
1539
|
NotFound,
|
|
1516
1540
|
Notifications,
|
|
1541
|
+
On,
|
|
1517
1542
|
OptionalUser,
|
|
1518
1543
|
PALBASE_EXTENSIONS,
|
|
1519
1544
|
PROVIDER_CATALOG,
|
|
@@ -1539,10 +1564,13 @@ export {
|
|
|
1539
1564
|
TEST_USERS_CONFIG_KIND,
|
|
1540
1565
|
TooManyRequests,
|
|
1541
1566
|
TraceId,
|
|
1567
|
+
TxPlanError,
|
|
1568
|
+
TxRefError,
|
|
1542
1569
|
Unauthorized,
|
|
1543
1570
|
Upload,
|
|
1544
1571
|
UploadedObject,
|
|
1545
1572
|
User,
|
|
1573
|
+
Webhook,
|
|
1546
1574
|
__getRuntime,
|
|
1547
1575
|
__registerResource,
|
|
1548
1576
|
__requestALS,
|
|
@@ -1555,29 +1583,32 @@ export {
|
|
|
1555
1583
|
boolean,
|
|
1556
1584
|
bucket,
|
|
1557
1585
|
buildProvider,
|
|
1586
|
+
dec,
|
|
1558
1587
|
defineEgress,
|
|
1559
1588
|
defineError,
|
|
1560
1589
|
defineFlags,
|
|
1561
|
-
defineJob,
|
|
1562
1590
|
defineMiddleware,
|
|
1563
1591
|
defineNotifications,
|
|
1564
1592
|
defineSchema,
|
|
1565
1593
|
defineStorage,
|
|
1566
1594
|
defineTestUsers,
|
|
1567
|
-
defineWebhook,
|
|
1568
1595
|
defineWorker,
|
|
1569
1596
|
documents,
|
|
1570
1597
|
entitlementFor,
|
|
1571
1598
|
enumType,
|
|
1572
1599
|
flag,
|
|
1573
1600
|
getErrorRegistry,
|
|
1601
|
+
getJobConfig,
|
|
1574
1602
|
getRoutes,
|
|
1603
|
+
getWebhookConfig,
|
|
1604
|
+
inc,
|
|
1575
1605
|
integer,
|
|
1576
1606
|
isPalbaseExtension,
|
|
1577
1607
|
jsonb,
|
|
1578
1608
|
makeEnvDts,
|
|
1579
1609
|
makePurchasesDts,
|
|
1580
1610
|
makeTypedDB,
|
|
1611
|
+
now,
|
|
1581
1612
|
numeric,
|
|
1582
1613
|
parseFileSizeLimit,
|
|
1583
1614
|
policy,
|