@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.
package/dist/index.js CHANGED
@@ -940,13 +940,13 @@ function buildBucketClient(http, bucketName) {
940
940
  },
941
941
  async remove(paths) {
942
942
  for (const p of paths) validateStoragePath(p);
943
- const removed = [];
943
+ const removed2 = [];
944
944
  for (const p of paths) {
945
945
  const res = await http.request("DELETE", objectPath(p));
946
946
  if (res.error) return { data: null, error: res.error, status: res.status };
947
- removed.push(toFileObject(bucketName, { path: p }));
947
+ removed2.push(toFileObject(bucketName, { path: p }));
948
948
  }
949
- return { data: removed, error: null, status: 200 };
949
+ return { data: removed2, error: null, status: 200 };
950
950
  },
951
951
  async move(from, to) {
952
952
  validateStoragePath(from);
@@ -1217,7 +1217,7 @@ function makeEnvDts(schema) {
1217
1217
  ${blocks.join("\n")}
1218
1218
  ` : "";
1219
1219
  return `// AUTO-GENERATED by @palbase/backend \u2014 DO NOT EDIT.
1220
- // Regenerated from db/schema.ts on every \`palbase db types\` / deploy.
1220
+ // Regenerated from db/schema.ts by \`palbase build\` and by every deploy.
1221
1221
  // Augments the @palbase/backend/env \`Tables\` interface so \`Database.tables.*\`
1222
1222
  // is typed with no import and no generic.
1223
1223
 
@@ -1883,95 +1883,6 @@ var Patch = makeMethodDecorator("PATCH");
1883
1883
  var Delete = makeMethodDecorator("DELETE");
1884
1884
  var Query = makeMethodDecorator("QUERY");
1885
1885
 
1886
- // src/decorators/upload.ts
1887
- function Upload(subpath, config) {
1888
- const { auth: auth2, rateLimit, ...uploadConfig } = config;
1889
- validateUploadConfigShape(uploadConfig);
1890
- const options = {
1891
- uploadConfig,
1892
- ...auth2 !== void 0 ? { auth: auth2 } : {},
1893
- ...rateLimit !== void 0 ? { rateLimit } : {}
1894
- };
1895
- return function(target, propertyKey) {
1896
- recordRoute(target, String(propertyKey), "POST", subpath, options);
1897
- };
1898
- }
1899
- function UploadedObject() {
1900
- return function(target, propertyKey, parameterIndex) {
1901
- recordParam(target, String(propertyKey), {
1902
- index: parameterIndex,
1903
- kind: "uploadedObject"
1904
- });
1905
- };
1906
- }
1907
- function validateUploadConfigShape(c) {
1908
- if (c === null || typeof c !== "object") {
1909
- throw new Error("@Upload config must be an object { bucket, pathTemplate, ... }");
1910
- }
1911
- if (typeof c.bucket !== "string" || c.bucket.length === 0) {
1912
- throw new Error("@Upload config.bucket must be a non-empty bucket name");
1913
- }
1914
- if (typeof c.pathTemplate !== "string" || c.pathTemplate.length === 0) {
1915
- throw new Error("@Upload config.pathTemplate must be a non-empty key template");
1916
- }
1917
- }
1918
- function validateUploadAgainstStorage(uploadConfig, storage2, routeLabel) {
1919
- const def = storage2.buckets[uploadConfig.bucket];
1920
- if (def === void 0) {
1921
- const known = Object.keys(storage2.buckets);
1922
- throw new Error(
1923
- `@Upload route ${routeLabel} targets bucket "${uploadConfig.bucket}" which is not declared in defineStorage(...). ` + (known.length ? `Known buckets: ${known.join(", ")}.` : "No buckets are declared.")
1924
- );
1925
- }
1926
- }
1927
-
1928
- // src/decorators/params.ts
1929
- function makeParamDecorator(kind, extra) {
1930
- return function(target, propertyKey, parameterIndex) {
1931
- recordParam(target, String(propertyKey), {
1932
- index: parameterIndex,
1933
- kind,
1934
- ...extra?.schema !== void 0 ? { schema: extra.schema } : {},
1935
- ...extra?.name !== void 0 ? { name: extra.name } : {}
1936
- });
1937
- };
1938
- }
1939
- function Body(schema) {
1940
- return makeParamDecorator("body", { schema });
1941
- }
1942
- function QueryParams(schema) {
1943
- return makeParamDecorator("query", { schema });
1944
- }
1945
- function Headers(schema) {
1946
- return makeParamDecorator("headers", schema !== void 0 ? { schema } : void 0);
1947
- }
1948
- function Param(name) {
1949
- return makeParamDecorator("param", { name });
1950
- }
1951
- function User() {
1952
- return makeParamDecorator("user");
1953
- }
1954
- function OptionalUser() {
1955
- return makeParamDecorator("optionalUser");
1956
- }
1957
- function Client() {
1958
- return makeParamDecorator("client");
1959
- }
1960
- function RequestId() {
1961
- return makeParamDecorator("requestId");
1962
- }
1963
- function TraceId() {
1964
- return makeParamDecorator("traceId");
1965
- }
1966
- function Req() {
1967
- return makeParamDecorator("req");
1968
- }
1969
-
1970
- // src/middleware.ts
1971
- function defineMiddleware(fn) {
1972
- return fn;
1973
- }
1974
-
1975
1886
  // src/decorators/webhook.ts
1976
1887
  var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
1977
1888
  var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
@@ -2069,6 +1980,147 @@ function getWebhookConfig(ctor) {
2069
1980
  };
2070
1981
  }
2071
1982
 
1983
+ // src/decorators/hook.ts
1984
+ var Deny = class extends Error {
1985
+ constructor(reason) {
1986
+ super(reason);
1987
+ this.name = "Deny";
1988
+ }
1989
+ };
1990
+ var HOOK_BLOCKING = /* @__PURE__ */ Symbol.for("palbase.backend.hookBlocking");
1991
+ function Hook(event) {
1992
+ return function(target, fnName) {
1993
+ const carrier = target.constructor;
1994
+ const existing = carrier[HOOK_BLOCKING];
1995
+ const entries = existing ? [...existing] : [];
1996
+ entries.push({ event, fnName: String(fnName) });
1997
+ Object.defineProperty(carrier, HOOK_BLOCKING, {
1998
+ value: entries,
1999
+ enumerable: false,
2000
+ configurable: true,
2001
+ writable: false
2002
+ });
2003
+ };
2004
+ }
2005
+ function bind(instance, entries, kind) {
2006
+ const out = /* @__PURE__ */ Object.create(null);
2007
+ for (const entry of entries) {
2008
+ if (Object.prototype.hasOwnProperty.call(out, entry.event)) {
2009
+ throw new Error(`${kind}("${entry.event}") declared twice on the same hook class`);
2010
+ }
2011
+ const fn = instance[entry.fnName];
2012
+ if (typeof fn !== "function") {
2013
+ throw new Error(`${kind}("${entry.event}") names no method "${entry.fnName}" on the class`);
2014
+ }
2015
+ out[entry.event] = (event, meta) => fn.call(instance, event, meta);
2016
+ }
2017
+ return out;
2018
+ }
2019
+ function getHookConfig(ctor) {
2020
+ const carrier = ctor;
2021
+ const blockingEntries = carrier[HOOK_BLOCKING] ?? [];
2022
+ const listenerEntries = carrier[WEBHOOK_EVENTS] ?? [];
2023
+ if (blockingEntries.length === 0 && listenerEntries.length === 0) {
2024
+ throw new Error(
2025
+ `${ctor.name ?? "a hook class"} carries no handler \u2014 a hook file must declare at least one @Hook (blocking) or @On (listener) method`
2026
+ );
2027
+ }
2028
+ const instance = new ctor();
2029
+ return {
2030
+ blocking: bind(instance, blockingEntries, "@Hook"),
2031
+ listeners: bind(instance, listenerEntries, "@On")
2032
+ };
2033
+ }
2034
+
2035
+ // src/decorators/upload.ts
2036
+ function Upload(subpath, config) {
2037
+ const { auth: auth2, rateLimit, ...uploadConfig } = config;
2038
+ validateUploadConfigShape(uploadConfig);
2039
+ const options = {
2040
+ uploadConfig,
2041
+ ...auth2 !== void 0 ? { auth: auth2 } : {},
2042
+ ...rateLimit !== void 0 ? { rateLimit } : {}
2043
+ };
2044
+ return function(target, propertyKey) {
2045
+ recordRoute(target, String(propertyKey), "POST", subpath, options);
2046
+ };
2047
+ }
2048
+ function UploadedObject() {
2049
+ return function(target, propertyKey, parameterIndex) {
2050
+ recordParam(target, String(propertyKey), {
2051
+ index: parameterIndex,
2052
+ kind: "uploadedObject"
2053
+ });
2054
+ };
2055
+ }
2056
+ function validateUploadConfigShape(c) {
2057
+ if (c === null || typeof c !== "object") {
2058
+ throw new Error("@Upload config must be an object { bucket, pathTemplate, ... }");
2059
+ }
2060
+ if (typeof c.bucket !== "string" || c.bucket.length === 0) {
2061
+ throw new Error("@Upload config.bucket must be a non-empty bucket name");
2062
+ }
2063
+ if (typeof c.pathTemplate !== "string" || c.pathTemplate.length === 0) {
2064
+ throw new Error("@Upload config.pathTemplate must be a non-empty key template");
2065
+ }
2066
+ }
2067
+ function validateUploadAgainstStorage(uploadConfig, storage2, routeLabel) {
2068
+ const def = storage2.buckets[uploadConfig.bucket];
2069
+ if (def === void 0) {
2070
+ const known = Object.keys(storage2.buckets);
2071
+ throw new Error(
2072
+ `@Upload route ${routeLabel} targets bucket "${uploadConfig.bucket}" which is not declared in defineStorage(...). ` + (known.length ? `Known buckets: ${known.join(", ")}.` : "No buckets are declared.")
2073
+ );
2074
+ }
2075
+ }
2076
+
2077
+ // src/decorators/params.ts
2078
+ function makeParamDecorator(kind, extra) {
2079
+ return function(target, propertyKey, parameterIndex) {
2080
+ recordParam(target, String(propertyKey), {
2081
+ index: parameterIndex,
2082
+ kind,
2083
+ ...extra?.schema !== void 0 ? { schema: extra.schema } : {},
2084
+ ...extra?.name !== void 0 ? { name: extra.name } : {}
2085
+ });
2086
+ };
2087
+ }
2088
+ function Body(schema) {
2089
+ return makeParamDecorator("body", { schema });
2090
+ }
2091
+ function QueryParams(schema) {
2092
+ return makeParamDecorator("query", { schema });
2093
+ }
2094
+ function Headers(schema) {
2095
+ return makeParamDecorator("headers", schema !== void 0 ? { schema } : void 0);
2096
+ }
2097
+ function Param(name) {
2098
+ return makeParamDecorator("param", { name });
2099
+ }
2100
+ function User() {
2101
+ return makeParamDecorator("user");
2102
+ }
2103
+ function OptionalUser() {
2104
+ return makeParamDecorator("optionalUser");
2105
+ }
2106
+ function Client() {
2107
+ return makeParamDecorator("client");
2108
+ }
2109
+ function RequestId() {
2110
+ return makeParamDecorator("requestId");
2111
+ }
2112
+ function TraceId() {
2113
+ return makeParamDecorator("traceId");
2114
+ }
2115
+ function Req() {
2116
+ return makeParamDecorator("req");
2117
+ }
2118
+
2119
+ // src/middleware.ts
2120
+ function defineMiddleware(fn) {
2121
+ return fn;
2122
+ }
2123
+
2072
2124
  // src/job.ts
2073
2125
  function validateCronExpression(expression) {
2074
2126
  const trimmed = expression.trim();
@@ -2139,6 +2191,8 @@ function validateCronField(field, name, min, max) {
2139
2191
  // src/decorators/job.ts
2140
2192
  var DEFAULT_TIMEOUT_SECONDS = 30;
2141
2193
  var MAX_TIMEOUT_SECONDS = 300;
2194
+ var DEFAULT_RETRY = 5;
2195
+ var MAX_RETRY = 10;
2142
2196
  var JOB_META = /* @__PURE__ */ Symbol.for("palbase.backend.jobMeta");
2143
2197
  function Job(options) {
2144
2198
  return function(ctor) {
@@ -2179,12 +2233,19 @@ function getJobConfig(ctor) {
2179
2233
  if (timeout > MAX_TIMEOUT_SECONDS) {
2180
2234
  throw new Error(`@Job \`timeout\` exceeds the ${MAX_TIMEOUT_SECONDS}s sandbox ceiling`);
2181
2235
  }
2236
+ const retry = meta.retry ?? DEFAULT_RETRY;
2237
+ if (!Number.isInteger(retry) || retry < 0) {
2238
+ throw new Error("@Job `retry` must be a whole number of attempts, zero or more");
2239
+ }
2240
+ if (retry > MAX_RETRY) {
2241
+ throw new Error(`@Job \`retry\` exceeds the ceiling of ${MAX_RETRY}`);
2242
+ }
2182
2243
  const instance = new ctor();
2183
2244
  if (typeof instance.run !== "function") {
2184
2245
  throw new Error("@Job class must declare an async run() method");
2185
2246
  }
2186
2247
  const run = instance.run.bind(instance);
2187
- return { schedule: meta.schedule, timeout, handler: run };
2248
+ return { schedule: meta.schedule, timeout, retry, handler: run };
2188
2249
  }
2189
2250
 
2190
2251
  // src/resource.ts
@@ -2234,38 +2295,31 @@ async function __shutdownResources() {
2234
2295
  }
2235
2296
 
2236
2297
  // src/hooks.ts
2237
- var auth = {
2238
- onUserCreated(handler) {
2239
- return { module: "auth", event: "user.created", handler };
2240
- },
2241
- onSignIn(handler) {
2242
- return { module: "auth", event: "user.sign_in", handler };
2243
- },
2244
- onSignOut(handler) {
2245
- return { module: "auth", event: "user.sign_out", handler };
2246
- },
2247
- onPasswordReset(handler) {
2248
- return { module: "auth", event: "user.password_reset", handler };
2298
+ function removed(helper, decorator, event) {
2299
+ throw new Error(
2300
+ `${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:
2301
+
2302
+ export default class MyHooks {
2303
+ ${decorator}("${event}")
2304
+ async handle(event, meta) { /* \u2026 */ }
2249
2305
  }
2306
+ `
2307
+ );
2308
+ }
2309
+ var auth = {
2310
+ onUserCreated: (_h) => removed("auth.onUserCreated", "@Hook", "before.user.create"),
2311
+ onSignIn: (_h) => removed("auth.onSignIn", "@Hook", "before.login"),
2312
+ onSignOut: (_h) => removed("auth.onSignOut", "@On", "after.session.revoke"),
2313
+ onPasswordReset: (_h) => removed("auth.onPasswordReset", "@Hook", "before.password.reset")
2250
2314
  };
2251
2315
  var storage = {
2252
- onFileUploaded(handler) {
2253
- return { module: "storage", event: "file.uploaded", handler };
2254
- },
2255
- onFileDeleted(handler) {
2256
- return { module: "storage", event: "file.deleted", handler };
2257
- }
2316
+ onFileUploaded: (_h) => removed("storage.onFileUploaded", "@On", "file.uploaded"),
2317
+ onFileDeleted: (_h) => removed("storage.onFileDeleted", "@On", "file.deleted")
2258
2318
  };
2259
2319
  var documents = {
2260
- onDocumentCreated(handler) {
2261
- return { module: "documents", event: "document.created", handler };
2262
- },
2263
- onDocumentUpdated(handler) {
2264
- return { module: "documents", event: "document.updated", handler };
2265
- },
2266
- onDocumentDeleted(handler) {
2267
- return { module: "documents", event: "document.deleted", handler };
2268
- }
2320
+ onDocumentCreated: (_h) => removed("documents.onDocumentCreated", "@On", "document.created"),
2321
+ onDocumentUpdated: (_h) => removed("documents.onDocumentUpdated", "@On", "document.updated"),
2322
+ onDocumentDeleted: (_h) => removed("documents.onDocumentDeleted", "@On", "document.deleted")
2269
2323
  };
2270
2324
 
2271
2325
  // src/index.ts
@@ -2280,6 +2334,7 @@ export {
2280
2334
  DEFAULT_TEMPLATE_LOCALE,
2281
2335
  Database,
2282
2336
  Delete,
2337
+ Deny,
2283
2338
  Documents,
2284
2339
  EGRESS_CONFIG_KIND,
2285
2340
  EGRESS_TIMEOUT_DEFAULT_MS,
@@ -2291,6 +2346,7 @@ export {
2291
2346
  Forbidden,
2292
2347
  Get,
2293
2348
  Headers,
2349
+ Hook,
2294
2350
  HttpError,
2295
2351
  Job,
2296
2352
  Log,
@@ -2362,6 +2418,7 @@ export {
2362
2418
  extractVariables,
2363
2419
  flag,
2364
2420
  getErrorRegistry,
2421
+ getHookConfig,
2365
2422
  getJobConfig,
2366
2423
  getRegisteredControllers,
2367
2424
  getRoutes,