@palbase/backend 18.0.0 → 20.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.
@@ -1,4 +1,4 @@
1
- export { A as App, l as AuthVerifier, B as BootRefused, m as CreateAppOptions, E as EgressPolicy, n as EngineConfig, M as ModuleClients, o as RateLimiter, p as RequestDatabase, q as RouteEntry, r as RuntimeHooks, s as ScrubResult, t as SqlDriver, u as SqlTx, v as buildRouteTable, w as createApp, x as createLazyTransaction, y as createOps, z as createRequestDatabase, G as effectiveAuth, H as hostAllowed, I as installEgressFence, J as loadConfig, K as makeMemoryCache, O as matchRoute, Q as quoteIdent, T as scrubSecrets, U as withTables } from '../index-B46CGNvx.cjs';
1
+ export { A as App, l as AuthVerifier, B as BootRefused, m as CreateAppOptions, E as EgressPolicy, n as EngineConfig, M as ModuleClients, o as RateLimiter, p as RequestDatabase, q as RouteEntry, r as RuntimeHooks, s as ScrubResult, t as SqlDriver, u as SqlTx, v as buildRouteTable, w as createApp, x as createLazyTransaction, y as createOps, z as createRequestDatabase, G as effectiveAuth, H as hostAllowed, I as installEgressFence, J as loadConfig, K as makeMemoryCache, O as matchRoute, Q as quoteIdent, T as scrubSecrets, U as withTables } from '../index-Br9P7yRu.cjs';
2
2
  import '../endpoint-B0LpZixz.cjs';
3
3
  import '../db/env.cjs';
4
4
  import 'node:async_hooks';
@@ -1,4 +1,4 @@
1
- export { A as App, l as AuthVerifier, B as BootRefused, m as CreateAppOptions, E as EgressPolicy, n as EngineConfig, M as ModuleClients, o as RateLimiter, p as RequestDatabase, q as RouteEntry, r as RuntimeHooks, s as ScrubResult, t as SqlDriver, u as SqlTx, v as buildRouteTable, w as createApp, x as createLazyTransaction, y as createOps, z as createRequestDatabase, G as effectiveAuth, H as hostAllowed, I as installEgressFence, J as loadConfig, K as makeMemoryCache, O as matchRoute, Q as quoteIdent, T as scrubSecrets, U as withTables } from '../index-DZDUMth5.js';
1
+ export { A as App, l as AuthVerifier, B as BootRefused, m as CreateAppOptions, E as EgressPolicy, n as EngineConfig, M as ModuleClients, o as RateLimiter, p as RequestDatabase, q as RouteEntry, r as RuntimeHooks, s as ScrubResult, t as SqlDriver, u as SqlTx, v as buildRouteTable, w as createApp, x as createLazyTransaction, y as createOps, z as createRequestDatabase, G as effectiveAuth, H as hostAllowed, I as installEgressFence, J as loadConfig, K as makeMemoryCache, O as matchRoute, Q as quoteIdent, T as scrubSecrets, U as withTables } from '../index-BeHLq2i-.js';
2
2
  import '../endpoint-B0LpZixz.js';
3
3
  import '../db/env.js';
4
4
  import 'node:async_hooks';
@@ -16,7 +16,7 @@ import {
16
16
  quoteIdent,
17
17
  scrubSecrets,
18
18
  withTables
19
- } from "../chunk-VYH4U7ZQ.js";
19
+ } from "../chunk-PFQJYW6C.js";
20
20
  import "../chunk-POYAFBLF.js";
21
21
  import "../chunk-W5ODXPY3.js";
22
22
  import "../chunk-QMVK4X3V.js";
@@ -827,6 +827,11 @@ interface App {
827
827
  handle: (req: Request) => Promise<Response>;
828
828
  routes: readonly RouteEntry[];
829
829
  config: EngineConfig;
830
+ /**
831
+ * Run work that has no request behind it — a scheduled job — inside the same
832
+ * request scope a handler gets, with its own transaction.
833
+ */
834
+ runInServiceScope: <T>(fn: () => T | Promise<T>) => Promise<T>;
830
835
  /** Close the pool and release resources. */
831
836
  shutdown: () => Promise<void>;
832
837
  }
@@ -827,6 +827,11 @@ interface App {
827
827
  handle: (req: Request) => Promise<Response>;
828
828
  routes: readonly RouteEntry[];
829
829
  config: EngineConfig;
830
+ /**
831
+ * Run work that has no request behind it — a scheduled job — inside the same
832
+ * request scope a handler gets, with its own transaction.
833
+ */
834
+ runInServiceScope: <T>(fn: () => T | Promise<T>) => Promise<T>;
830
835
  /** Close the pool and release resources. */
831
836
  shutdown: () => Promise<void>;
832
837
  }
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ __export(src_exports, {
29
29
  DEFAULT_TEMPLATE_LOCALE: () => DEFAULT_TEMPLATE_LOCALE,
30
30
  Database: () => Database,
31
31
  Delete: () => Delete,
32
+ Deny: () => Deny,
32
33
  Documents: () => Documents,
33
34
  EGRESS_CONFIG_KIND: () => EGRESS_CONFIG_KIND,
34
35
  EGRESS_TIMEOUT_DEFAULT_MS: () => EGRESS_TIMEOUT_DEFAULT_MS,
@@ -40,6 +41,7 @@ __export(src_exports, {
40
41
  Forbidden: () => Forbidden,
41
42
  Get: () => Get,
42
43
  Headers: () => Headers,
44
+ Hook: () => Hook,
43
45
  HttpError: () => HttpError,
44
46
  Job: () => Job,
45
47
  Log: () => Log,
@@ -111,6 +113,7 @@ __export(src_exports, {
111
113
  extractVariables: () => extractVariables,
112
114
  flag: () => flag,
113
115
  getErrorRegistry: () => getErrorRegistry,
116
+ getHookConfig: () => getHookConfig,
114
117
  getJobConfig: () => getJobConfig,
115
118
  getRegisteredControllers: () => getRegisteredControllers,
116
119
  getRoutes: () => getRoutes,
@@ -1703,13 +1706,13 @@ function buildBucketClient(http, bucketName) {
1703
1706
  },
1704
1707
  async remove(paths) {
1705
1708
  for (const p of paths) validateStoragePath(p);
1706
- const removed = [];
1709
+ const removed2 = [];
1707
1710
  for (const p of paths) {
1708
1711
  const res = await http.request("DELETE", objectPath(p));
1709
1712
  if (res.error) return { data: null, error: res.error, status: res.status };
1710
- removed.push(toFileObject(bucketName, { path: p }));
1713
+ removed2.push(toFileObject(bucketName, { path: p }));
1711
1714
  }
1712
- return { data: removed, error: null, status: 200 };
1715
+ return { data: removed2, error: null, status: 200 };
1713
1716
  },
1714
1717
  async move(from, to) {
1715
1718
  validateStoragePath(from);
@@ -2297,7 +2300,7 @@ function makeEnvDts(schema) {
2297
2300
  ${blocks.join("\n")}
2298
2301
  ` : "";
2299
2302
  return `// AUTO-GENERATED by @palbase/backend \u2014 DO NOT EDIT.
2300
- // Regenerated from db/schema.ts on every \`palbase db types\` / deploy.
2303
+ // Regenerated from db/schema.ts by \`palbase build\` and by every deploy.
2301
2304
  // Augments the @palbase/backend/env \`Tables\` interface so \`Database.tables.*\`
2302
2305
  // is typed with no import and no generic.
2303
2306
 
@@ -3114,6 +3117,155 @@ var Patch = makeMethodDecorator("PATCH");
3114
3117
  var Delete = makeMethodDecorator("DELETE");
3115
3118
  var Query = makeMethodDecorator("QUERY");
3116
3119
 
3120
+ // src/decorators/webhook.ts
3121
+ var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
3122
+ var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
3123
+ function carrierOf3(ctor) {
3124
+ return ctor;
3125
+ }
3126
+ function Webhook(options) {
3127
+ return function(ctor) {
3128
+ const carrier = carrierOf3(ctor);
3129
+ Object.defineProperty(carrier, WEBHOOK_META, {
3130
+ value: options,
3131
+ enumerable: false,
3132
+ configurable: true,
3133
+ writable: false
3134
+ });
3135
+ Object.defineProperty(carrier, "__palbase", {
3136
+ value: "webhook",
3137
+ enumerable: false,
3138
+ configurable: true,
3139
+ writable: false
3140
+ });
3141
+ return ctor;
3142
+ };
3143
+ }
3144
+ function On(event) {
3145
+ return function(target, fnName) {
3146
+ const carrier = carrierOf3(target.constructor);
3147
+ const existing = carrier[WEBHOOK_EVENTS];
3148
+ const entries = existing ? [...existing] : [];
3149
+ entries.push({ event, fnName: String(fnName) });
3150
+ Object.defineProperty(carrier, WEBHOOK_EVENTS, {
3151
+ value: entries,
3152
+ enumerable: false,
3153
+ configurable: true,
3154
+ writable: false
3155
+ });
3156
+ };
3157
+ }
3158
+ function getWebhookConfig(ctor) {
3159
+ const carrier = carrierOf3(ctor);
3160
+ const meta = carrier[WEBHOOK_META];
3161
+ const entries = carrier[WEBHOOK_EVENTS] ?? [];
3162
+ if (!meta) {
3163
+ throw new Error(
3164
+ `@On used on a class that is not decorated with @Webhook (${ctor.name ?? "anonymous"})`
3165
+ );
3166
+ }
3167
+ if (!meta.provider && !meta.signature) {
3168
+ throw new Error(
3169
+ "@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries"
3170
+ );
3171
+ }
3172
+ if (meta.provider && meta.signature) {
3173
+ throw new Error(
3174
+ "@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"
3175
+ );
3176
+ }
3177
+ if (meta.signature) {
3178
+ const sig = meta.signature;
3179
+ if (!sig.header) {
3180
+ throw new Error("@Webhook signature requires `header` \u2014 the header the signature arrives in");
3181
+ }
3182
+ if (sig.algo !== "hmac-sha256" && sig.algo !== "hmac-sha1") {
3183
+ throw new Error(`@Webhook signature has an unsupported algo "${sig.algo}"`);
3184
+ }
3185
+ if (sig.encoding !== "hex" && sig.encoding !== "base64") {
3186
+ throw new Error(`@Webhook signature has an unsupported encoding "${sig.encoding}"`);
3187
+ }
3188
+ if (!sig.signs?.includes("{body}")) {
3189
+ throw new Error("@Webhook signature `signs` must contain {body} \u2014 signing a constant is not a signature");
3190
+ }
3191
+ if (sig.signs.includes("{ts}") && !sig.timestampHeader) {
3192
+ throw new Error("@Webhook signature uses {ts} but declares no `timestampHeader` to read it from");
3193
+ }
3194
+ }
3195
+ if (!meta.secret?.env) {
3196
+ throw new Error('@Webhook requires `secret: { env: "VAR_NAME" }`');
3197
+ }
3198
+ if (entries.length === 0) {
3199
+ throw new Error("@Webhook requires at least one @On handler");
3200
+ }
3201
+ const instance = new ctor();
3202
+ const events = /* @__PURE__ */ Object.create(null);
3203
+ for (const entry of entries) {
3204
+ if (Object.prototype.hasOwnProperty.call(events, entry.event)) {
3205
+ throw new Error(`@On("${entry.event}") declared twice on the same webhook`);
3206
+ }
3207
+ events[entry.event] = (event, metaArg) => instance[entry.fnName].call(instance, event, metaArg);
3208
+ }
3209
+ return {
3210
+ ...meta.provider ? { provider: meta.provider } : {},
3211
+ ...meta.signature ? { signature: meta.signature } : {},
3212
+ secret: meta.secret,
3213
+ events
3214
+ };
3215
+ }
3216
+
3217
+ // src/decorators/hook.ts
3218
+ var Deny = class extends Error {
3219
+ constructor(reason) {
3220
+ super(reason);
3221
+ this.name = "Deny";
3222
+ }
3223
+ };
3224
+ var HOOK_BLOCKING = /* @__PURE__ */ Symbol.for("palbase.backend.hookBlocking");
3225
+ function Hook(event) {
3226
+ return function(target, fnName) {
3227
+ const carrier = target.constructor;
3228
+ const existing = carrier[HOOK_BLOCKING];
3229
+ const entries = existing ? [...existing] : [];
3230
+ entries.push({ event, fnName: String(fnName) });
3231
+ Object.defineProperty(carrier, HOOK_BLOCKING, {
3232
+ value: entries,
3233
+ enumerable: false,
3234
+ configurable: true,
3235
+ writable: false
3236
+ });
3237
+ };
3238
+ }
3239
+ function bind(instance, entries, kind) {
3240
+ const out = /* @__PURE__ */ Object.create(null);
3241
+ for (const entry of entries) {
3242
+ if (Object.prototype.hasOwnProperty.call(out, entry.event)) {
3243
+ throw new Error(`${kind}("${entry.event}") declared twice on the same hook class`);
3244
+ }
3245
+ const fn = instance[entry.fnName];
3246
+ if (typeof fn !== "function") {
3247
+ throw new Error(`${kind}("${entry.event}") names no method "${entry.fnName}" on the class`);
3248
+ }
3249
+ out[entry.event] = (event, meta) => fn.call(instance, event, meta);
3250
+ }
3251
+ return out;
3252
+ }
3253
+ function getHookConfig(ctor) {
3254
+ const carrier = ctor;
3255
+ const blockingEntries = carrier[HOOK_BLOCKING] ?? [];
3256
+ const listenerEntries = carrier[WEBHOOK_EVENTS] ?? [];
3257
+ if (blockingEntries.length === 0 && listenerEntries.length === 0) {
3258
+ throw new Error(
3259
+ `${ctor.name ?? "a hook class"} carries no handler \u2014 a hook file must declare at least one @Hook (blocking) or @On (listener) method`
3260
+ );
3261
+ }
3262
+ const instance = new ctor();
3263
+ return {
3264
+ blocking: bind(instance, blockingEntries, "@Hook"),
3265
+ listeners: bind(instance, listenerEntries, "@On")
3266
+ };
3267
+ }
3268
+
3117
3269
  // src/decorators/upload.ts
3118
3270
  function Upload(subpath, config) {
3119
3271
  const { auth: auth2, rateLimit, ...uploadConfig } = config;
@@ -3333,103 +3485,6 @@ function humanize(code) {
3333
3485
  return s.charAt(0).toUpperCase() + s.slice(1);
3334
3486
  }
3335
3487
 
3336
- // src/decorators/webhook.ts
3337
- var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
3338
- var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
3339
- function carrierOf3(ctor) {
3340
- return ctor;
3341
- }
3342
- function Webhook(options) {
3343
- return function(ctor) {
3344
- const carrier = carrierOf3(ctor);
3345
- Object.defineProperty(carrier, WEBHOOK_META, {
3346
- value: options,
3347
- enumerable: false,
3348
- configurable: true,
3349
- writable: false
3350
- });
3351
- Object.defineProperty(carrier, "__palbase", {
3352
- value: "webhook",
3353
- enumerable: false,
3354
- configurable: true,
3355
- writable: false
3356
- });
3357
- return ctor;
3358
- };
3359
- }
3360
- function On(event) {
3361
- return function(target, fnName) {
3362
- const carrier = carrierOf3(target.constructor);
3363
- const existing = carrier[WEBHOOK_EVENTS];
3364
- const entries = existing ? [...existing] : [];
3365
- entries.push({ event, fnName: String(fnName) });
3366
- Object.defineProperty(carrier, WEBHOOK_EVENTS, {
3367
- value: entries,
3368
- enumerable: false,
3369
- configurable: true,
3370
- writable: false
3371
- });
3372
- };
3373
- }
3374
- function getWebhookConfig(ctor) {
3375
- const carrier = carrierOf3(ctor);
3376
- const meta = carrier[WEBHOOK_META];
3377
- const entries = carrier[WEBHOOK_EVENTS] ?? [];
3378
- if (!meta) {
3379
- throw new Error(
3380
- `@On used on a class that is not decorated with @Webhook (${ctor.name ?? "anonymous"})`
3381
- );
3382
- }
3383
- if (!meta.provider && !meta.signature) {
3384
- throw new Error(
3385
- "@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries"
3386
- );
3387
- }
3388
- if (meta.provider && meta.signature) {
3389
- throw new Error(
3390
- "@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"
3391
- );
3392
- }
3393
- if (meta.signature) {
3394
- const sig = meta.signature;
3395
- if (!sig.header) {
3396
- throw new Error("@Webhook signature requires `header` \u2014 the header the signature arrives in");
3397
- }
3398
- if (sig.algo !== "hmac-sha256" && sig.algo !== "hmac-sha1") {
3399
- throw new Error(`@Webhook signature has an unsupported algo "${sig.algo}"`);
3400
- }
3401
- if (sig.encoding !== "hex" && sig.encoding !== "base64") {
3402
- throw new Error(`@Webhook signature has an unsupported encoding "${sig.encoding}"`);
3403
- }
3404
- if (!sig.signs?.includes("{body}")) {
3405
- throw new Error("@Webhook signature `signs` must contain {body} \u2014 signing a constant is not a signature");
3406
- }
3407
- if (sig.signs.includes("{ts}") && !sig.timestampHeader) {
3408
- throw new Error("@Webhook signature uses {ts} but declares no `timestampHeader` to read it from");
3409
- }
3410
- }
3411
- if (!meta.secret?.env) {
3412
- throw new Error('@Webhook requires `secret: { env: "VAR_NAME" }`');
3413
- }
3414
- if (entries.length === 0) {
3415
- throw new Error("@Webhook requires at least one @On handler");
3416
- }
3417
- const instance = new ctor();
3418
- const events = /* @__PURE__ */ Object.create(null);
3419
- for (const entry of entries) {
3420
- if (Object.prototype.hasOwnProperty.call(events, entry.event)) {
3421
- throw new Error(`@On("${entry.event}") declared twice on the same webhook`);
3422
- }
3423
- events[entry.event] = (event, metaArg) => instance[entry.fnName].call(instance, event, metaArg);
3424
- }
3425
- return {
3426
- ...meta.provider ? { provider: meta.provider } : {},
3427
- ...meta.signature ? { signature: meta.signature } : {},
3428
- secret: meta.secret,
3429
- events
3430
- };
3431
- }
3432
-
3433
3488
  // src/job.ts
3434
3489
  function validateCronExpression(expression) {
3435
3490
  const trimmed = expression.trim();
@@ -3500,6 +3555,8 @@ function validateCronField(field, name, min, max) {
3500
3555
  // src/decorators/job.ts
3501
3556
  var DEFAULT_TIMEOUT_SECONDS = 30;
3502
3557
  var MAX_TIMEOUT_SECONDS = 300;
3558
+ var DEFAULT_RETRY = 5;
3559
+ var MAX_RETRY = 10;
3503
3560
  var JOB_META = /* @__PURE__ */ Symbol.for("palbase.backend.jobMeta");
3504
3561
  function Job(options) {
3505
3562
  return function(ctor) {
@@ -3540,12 +3597,19 @@ function getJobConfig(ctor) {
3540
3597
  if (timeout > MAX_TIMEOUT_SECONDS) {
3541
3598
  throw new Error(`@Job \`timeout\` exceeds the ${MAX_TIMEOUT_SECONDS}s sandbox ceiling`);
3542
3599
  }
3600
+ const retry = meta.retry ?? DEFAULT_RETRY;
3601
+ if (!Number.isInteger(retry) || retry < 0) {
3602
+ throw new Error("@Job `retry` must be a whole number of attempts, zero or more");
3603
+ }
3604
+ if (retry > MAX_RETRY) {
3605
+ throw new Error(`@Job \`retry\` exceeds the ceiling of ${MAX_RETRY}`);
3606
+ }
3543
3607
  const instance = new ctor();
3544
3608
  if (typeof instance.run !== "function") {
3545
3609
  throw new Error("@Job class must declare an async run() method");
3546
3610
  }
3547
3611
  const run = instance.run.bind(instance);
3548
- return { schedule: meta.schedule, timeout, handler: run };
3612
+ return { schedule: meta.schedule, timeout, retry, handler: run };
3549
3613
  }
3550
3614
 
3551
3615
  // src/resource.ts
@@ -3595,38 +3659,31 @@ async function __shutdownResources() {
3595
3659
  }
3596
3660
 
3597
3661
  // src/hooks.ts
3598
- var auth = {
3599
- onUserCreated(handler) {
3600
- return { module: "auth", event: "user.created", handler };
3601
- },
3602
- onSignIn(handler) {
3603
- return { module: "auth", event: "user.sign_in", handler };
3604
- },
3605
- onSignOut(handler) {
3606
- return { module: "auth", event: "user.sign_out", handler };
3607
- },
3608
- onPasswordReset(handler) {
3609
- return { module: "auth", event: "user.password_reset", handler };
3662
+ function removed(helper, decorator, event) {
3663
+ throw new Error(
3664
+ `${helper}() does not register anything and never did \u2014 nothing in the runtime or the bundler reads what it returns, so the handler you passed would never run. Declare it instead in hooks/<name>.ts:
3665
+
3666
+ export default class MyHooks {
3667
+ ${decorator}("${event}")
3668
+ async handle(event, meta) { /* \u2026 */ }
3610
3669
  }
3670
+ `
3671
+ );
3672
+ }
3673
+ var auth = {
3674
+ onUserCreated: (_h) => removed("auth.onUserCreated", "@Hook", "before.user.create"),
3675
+ onSignIn: (_h) => removed("auth.onSignIn", "@Hook", "before.login"),
3676
+ onSignOut: (_h) => removed("auth.onSignOut", "@On", "after.session.revoke"),
3677
+ onPasswordReset: (_h) => removed("auth.onPasswordReset", "@Hook", "before.password.reset")
3611
3678
  };
3612
3679
  var storage = {
3613
- onFileUploaded(handler) {
3614
- return { module: "storage", event: "file.uploaded", handler };
3615
- },
3616
- onFileDeleted(handler) {
3617
- return { module: "storage", event: "file.deleted", handler };
3618
- }
3680
+ onFileUploaded: (_h) => removed("storage.onFileUploaded", "@On", "file.uploaded"),
3681
+ onFileDeleted: (_h) => removed("storage.onFileDeleted", "@On", "file.deleted")
3619
3682
  };
3620
3683
  var documents = {
3621
- onDocumentCreated(handler) {
3622
- return { module: "documents", event: "document.created", handler };
3623
- },
3624
- onDocumentUpdated(handler) {
3625
- return { module: "documents", event: "document.updated", handler };
3626
- },
3627
- onDocumentDeleted(handler) {
3628
- return { module: "documents", event: "document.deleted", handler };
3629
- }
3684
+ onDocumentCreated: (_h) => removed("documents.onDocumentCreated", "@On", "document.created"),
3685
+ onDocumentUpdated: (_h) => removed("documents.onDocumentUpdated", "@On", "document.updated"),
3686
+ onDocumentDeleted: (_h) => removed("documents.onDocumentDeleted", "@On", "document.deleted")
3630
3687
  };
3631
3688
 
3632
3689
  // src/index.ts
@@ -3642,6 +3699,7 @@ var import_zod2 = require("zod");
3642
3699
  DEFAULT_TEMPLATE_LOCALE,
3643
3700
  Database,
3644
3701
  Delete,
3702
+ Deny,
3645
3703
  Documents,
3646
3704
  EGRESS_CONFIG_KIND,
3647
3705
  EGRESS_TIMEOUT_DEFAULT_MS,
@@ -3653,6 +3711,7 @@ var import_zod2 = require("zod");
3653
3711
  Forbidden,
3654
3712
  Get,
3655
3713
  Headers,
3714
+ Hook,
3656
3715
  HttpError,
3657
3716
  Job,
3658
3717
  Log,
@@ -3724,6 +3783,7 @@ var import_zod2 = require("zod");
3724
3783
  extractVariables,
3725
3784
  flag,
3726
3785
  getErrorRegistry,
3786
+ getHookConfig,
3727
3787
  getJobConfig,
3728
3788
  getRegisteredControllers,
3729
3789
  getRoutes,