@palbase/backend 3.0.0 → 4.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.
Files changed (37) hide show
  1. package/dist/{chunk-B7EUJP5W.js → chunk-EG7TTYHY.js} +113 -3
  2. package/dist/chunk-EG7TTYHY.js.map +1 -0
  3. package/dist/{chunk-PHAFZGHN.js → chunk-WUQO76NW.js} +26 -19
  4. package/dist/chunk-WUQO76NW.js.map +1 -0
  5. package/dist/db/index.cjs +117 -2
  6. package/dist/db/index.cjs.map +1 -1
  7. package/dist/db/index.d.cts +2 -2
  8. package/dist/db/index.d.ts +2 -2
  9. package/dist/db/index.js +11 -1
  10. package/dist/{endpoint-DJ98tQd6.d.cts → endpoint-2d_DpASt.d.cts} +92 -56
  11. package/dist/{endpoint-DJ98tQd6.d.ts → endpoint-2d_DpASt.d.ts} +92 -56
  12. package/dist/{index-CXUs9iTQ.d.ts → index-DZW9CjiY.d.ts} +210 -41
  13. package/dist/{index-CZAwpQE1.d.cts → index-DzRFS3Tl.d.cts} +210 -41
  14. package/dist/index.cjs +371 -42
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +88 -215
  17. package/dist/index.d.ts +88 -215
  18. package/dist/index.js +217 -21
  19. package/dist/index.js.map +1 -1
  20. package/dist/test/index.cjs +34 -19
  21. package/dist/test/index.cjs.map +1 -1
  22. package/dist/test/index.d.cts +1 -1
  23. package/dist/test/index.d.ts +1 -1
  24. package/dist/test/index.js +10 -2
  25. package/dist/test/index.js.map +1 -1
  26. package/docs/README.md +11 -11
  27. package/docs/database.md +40 -0
  28. package/docs/endpoints.md +98 -92
  29. package/docs/errors.md +37 -30
  30. package/docs/getting-started.md +24 -20
  31. package/docs/llms-full.txt +401 -235
  32. package/docs/routing.md +39 -45
  33. package/docs/schema.md +134 -23
  34. package/docs/services.md +14 -10
  35. package/package.json +2 -2
  36. package/dist/chunk-B7EUJP5W.js.map +0 -1
  37. package/dist/chunk-PHAFZGHN.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -20,16 +20,43 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ BadRequest: () => BadRequest,
24
+ Body: () => Body,
23
25
  Cache: () => Cache,
26
+ Client: () => Client,
27
+ Conflict: () => Conflict,
28
+ Controller: () => Controller,
24
29
  Database: () => Database,
30
+ Delete: () => Delete,
25
31
  Documents: () => Documents,
32
+ EXTENSION_DEPENDENCIES: () => EXTENSION_DEPENDENCIES,
26
33
  Flags: () => Flags,
34
+ Forbidden: () => Forbidden,
35
+ Get: () => Get,
36
+ Headers: () => Headers,
27
37
  HttpError: () => HttpError,
28
38
  Log: () => Log,
39
+ NotFound: () => NotFound,
29
40
  Notifications: () => Notifications,
41
+ OptionalUser: () => OptionalUser,
42
+ PALBASE_EXTENSIONS: () => PALBASE_EXTENSIONS,
43
+ PalError: () => PalError,
44
+ Param: () => Param,
45
+ Patch: () => Patch,
46
+ PolicyBuilder: () => PolicyBuilder,
47
+ Post: () => Post,
48
+ Put: () => Put,
49
+ Query: () => Query,
30
50
  Queue: () => Queue,
51
+ Req: () => Req,
52
+ RequestId: () => RequestId,
31
53
  Resource: () => Resource,
54
+ Returns: () => Returns,
32
55
  Storage: () => Storage,
56
+ TooManyRequests: () => TooManyRequests,
57
+ TraceId: () => TraceId,
58
+ Unauthorized: () => Unauthorized,
59
+ User: () => User,
33
60
  __getRuntime: () => __getRuntime,
34
61
  __registerResource: () => __registerResource,
35
62
  __requestALS: () => __requestALS,
@@ -39,8 +66,6 @@ __export(src_exports, {
39
66
  __shutdownResources: () => __shutdownResources,
40
67
  auth: () => auth,
41
68
  boolean: () => boolean,
42
- defineController: () => defineController,
43
- defineHandler: () => defineHandler,
44
69
  defineJob: () => defineJob,
45
70
  defineMiddleware: () => defineMiddleware,
46
71
  defineSchema: () => defineSchema,
@@ -49,10 +74,11 @@ __export(src_exports, {
49
74
  documents: () => documents,
50
75
  enumType: () => enumType,
51
76
  integer: () => integer,
77
+ isPalbaseExtension: () => isPalbaseExtension,
52
78
  jsonb: () => jsonb,
53
79
  makeEnvDts: () => makeEnvDts,
54
80
  makeTypedDB: () => makeTypedDB,
55
- route: () => route,
81
+ policy: () => policy,
56
82
  storage: () => storage,
57
83
  text: () => text,
58
84
  timestamp: () => timestamp,
@@ -111,27 +137,34 @@ function makeTablesAccessor(ops) {
111
137
  return tablesProxy;
112
138
  }
113
139
  var rawDatabase = makeServiceProxy("Database");
114
- var Database = Object.assign(
115
- // Spread the raw ops onto a fresh object so the added `tables`/typed
116
- // `transaction` members live alongside them. Each op still forwards through
117
- // the request-scoped runtime Proxy.
118
- {
119
- query: (sql, params) => rawDatabase.query(sql, params),
120
- insert: (table, data) => rawDatabase.insert(table, data),
121
- update: (table, id, data) => rawDatabase.update(table, id, data),
122
- delete: (table, id) => rawDatabase.delete(table, id),
123
- findById: (table, id) => rawDatabase.findById(table, id),
124
- findMany: (table, query) => rawDatabase.findMany(table, query)
125
- },
126
- {
127
- tables: makeTablesAccessor(() => rawDatabase),
140
+ function makeTypedSurface(raw) {
141
+ const ops = {
142
+ query: (sql, params) => raw.query(sql, params),
143
+ insert: (table, data) => raw.insert(table, data),
144
+ update: (table, id, data) => raw.update(table, id, data),
145
+ delete: (table, id) => raw.delete(table, id),
146
+ findById: (table, id) => raw.findById(table, id),
147
+ findMany: (table, query) => raw.findMany(table, query)
148
+ };
149
+ return Object.assign(ops, {
150
+ tables: makeTablesAccessor(() => raw),
128
151
  transaction(fn) {
129
- return rawDatabase.transaction(
130
- (rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) })
131
- );
152
+ return raw.transaction((rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) }));
132
153
  }
154
+ });
155
+ }
156
+ var Database = Object.assign(makeTypedSurface(rawDatabase), {
157
+ /**
158
+ * Lazily resolve the runtime's service-role sibling on each call. We do NOT
159
+ * cache it: `rawDatabase.asService()` reads the CURRENT request scope through
160
+ * the runtime proxy, and the per-request runtime injects a service client
161
+ * bound to that request's identity headers — caching would leak one request's
162
+ * sibling into another concurrent request.
163
+ */
164
+ asService() {
165
+ return makeTypedSurface(rawDatabase.asService());
133
166
  }
134
- );
167
+ });
135
168
  var Documents = makeServiceProxy("Documents");
136
169
  var Storage = makeServiceProxy("Storage");
137
170
  var Cache = makeServiceProxy("Cache");
@@ -140,13 +173,118 @@ var Log = makeServiceProxy("Log");
140
173
  var Notifications = makeServiceProxy("Notifications");
141
174
  var Flags = makeServiceProxy("Flags");
142
175
 
176
+ // src/db/policy.ts
177
+ var PolicyBuilder = class {
178
+ _def;
179
+ constructor(name) {
180
+ this._def = {
181
+ name,
182
+ command: "all",
183
+ roles: ["authenticated"],
184
+ using: null,
185
+ withCheck: null,
186
+ permissive: true
187
+ };
188
+ }
189
+ /** Restrict the policy to a single SQL command (default `"all"`). */
190
+ for(command) {
191
+ this._def.command = command;
192
+ return this;
193
+ }
194
+ /**
195
+ * Set the DB roles the policy applies to (the `TO` clause), replacing any
196
+ * previously-set roles. Call with no arguments to target PUBLIC (all roles).
197
+ *
198
+ * @example
199
+ * policy("p").to("authenticated")
200
+ * policy("p").to("authenticated", "service_role")
201
+ * policy("p").to() // PUBLIC
202
+ */
203
+ to(...roles) {
204
+ this._def.roles = roles;
205
+ return this;
206
+ }
207
+ /** Set the `USING (...)` row-visibility expression (raw SQL). */
208
+ using(sqlExpr) {
209
+ this._def.using = sqlExpr;
210
+ return this;
211
+ }
212
+ /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */
213
+ withCheck(sqlExpr) {
214
+ this._def.withCheck = sqlExpr;
215
+ return this;
216
+ }
217
+ /** Set the policy mode: `"permissive"` (default, OR-combined) or
218
+ * `"restrictive"` (AND-combined). */
219
+ as(mode) {
220
+ this._def.permissive = mode === "permissive";
221
+ return this;
222
+ }
223
+ };
224
+ function policy(name) {
225
+ return new PolicyBuilder(name);
226
+ }
227
+
143
228
  // src/db/schema.ts
229
+ function toPolicyDef(p) {
230
+ return p instanceof PolicyBuilder ? p._def : p;
231
+ }
144
232
  function defineSchema(input) {
145
233
  const tables = {};
146
234
  for (const name of Object.keys(input.tables)) {
147
- tables[name] = { name, columns: input.tables[name] };
235
+ const table = input.tables[name];
236
+ if (table === void 0) continue;
237
+ const policies = (table.policies ?? []).map(toPolicyDef);
238
+ const rls = table.rls === true || policies.length > 0;
239
+ tables[name] = {
240
+ name,
241
+ columns: table.columns,
242
+ rls,
243
+ policies
244
+ };
148
245
  }
149
- return { tables };
246
+ const extensions = [...new Set(input.extensions ?? [])];
247
+ return { tables, extensions };
248
+ }
249
+
250
+ // src/db/extensions.ts
251
+ var PALBASE_EXTENSIONS = [
252
+ // Search & text
253
+ "vector",
254
+ // pgvector: AI embeddings + vector similarity search (semantic search / RAG).
255
+ // NB: the Postgres extension is named "vector", not "pgvector" — declare "vector".
256
+ "pg_trgm",
257
+ // trigram fuzzy / typo-tolerant text search
258
+ "unaccent",
259
+ // accent-insensitive text search
260
+ "citext",
261
+ // case-insensitive text type
262
+ // Geospatial / location
263
+ "postgis",
264
+ // geospatial types + queries (maps, "near me")
265
+ "cube",
266
+ // multi-dimensional cubes (dependency of earthdistance)
267
+ "earthdistance",
268
+ // great-circle distance (needs cube)
269
+ // Data types & structures
270
+ "hstore",
271
+ // key/value pairs in a single column
272
+ "ltree",
273
+ // hierarchical tree-structured labels
274
+ // Scheduling
275
+ "pg_cron",
276
+ // schedule jobs inside the database
277
+ // Crypto / ids (also installed by default; listable for explicitness)
278
+ "pgcrypto",
279
+ // cryptographic functions (hashing, encryption)
280
+ "uuid-ossp"
281
+ // UUID generation functions
282
+ ];
283
+ var EXTENSION_DEPENDENCIES = {
284
+ earthdistance: ["cube"]
285
+ };
286
+ function isPalbaseExtension(name) {
287
+ return PALBASE_EXTENSIONS.includes(name);
150
288
  }
151
289
 
152
290
  // src/db/columns.ts
@@ -322,26 +460,145 @@ export {};
322
460
  `;
323
461
  }
324
462
 
325
- // src/handler.ts
326
- function defineHandler(config) {
327
- return { __palbase: "handler", ...config };
463
+ // src/decorators/controller.ts
464
+ var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta");
465
+ function Controller(basePath, options = {}) {
466
+ return function(ctor) {
467
+ const carrier = ctor;
468
+ const meta = {
469
+ __palbase: "controller",
470
+ basePath,
471
+ ...options.auth !== void 0 ? { defaultAuth: options.auth } : {}
472
+ };
473
+ Object.defineProperty(carrier, CONTROLLER_META, {
474
+ value: meta,
475
+ enumerable: false,
476
+ configurable: true,
477
+ writable: false
478
+ });
479
+ Object.defineProperty(carrier, "__palbase", {
480
+ value: "controller",
481
+ enumerable: false,
482
+ configurable: true,
483
+ writable: false
484
+ });
485
+ return ctor;
486
+ };
328
487
  }
329
488
 
330
- // src/controller.ts
331
- function makeRoute(method) {
332
- return function(path, handler) {
333
- return { __palbase: "route", method, path, handler };
489
+ // src/decorators/registry.ts
490
+ var ROUTES = /* @__PURE__ */ Symbol.for("palbase.backend.routes");
491
+ var PARAM_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.paramBuffer");
492
+ function carrierOf(target) {
493
+ const ctor = typeof target === "function" ? target : target.constructor ?? target;
494
+ return ctor;
495
+ }
496
+ function ownRoutes(carrier) {
497
+ if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {
498
+ carrier[ROUTES] = [];
499
+ }
500
+ return carrier[ROUTES];
501
+ }
502
+ function ownParamBuffer(carrier) {
503
+ if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {
504
+ carrier[PARAM_BUFFER] = {};
505
+ }
506
+ return carrier[PARAM_BUFFER];
507
+ }
508
+ function recordRoute(target, fnName, method, subpath, options) {
509
+ const carrier = carrierOf(target);
510
+ const routes = ownRoutes(carrier);
511
+ const buffer = ownParamBuffer(carrier);
512
+ const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);
513
+ routes.push({ method, subpath, fnName, options, params });
514
+ }
515
+ function recordParam(target, fnName, meta) {
516
+ const carrier = carrierOf(target);
517
+ const buffer = ownParamBuffer(carrier);
518
+ (buffer[fnName] ??= []).push(meta);
519
+ const routes = carrier[ROUTES];
520
+ if (routes) {
521
+ const route = routes.find((r) => r.fnName === fnName);
522
+ if (route) {
523
+ route.params.push(meta);
524
+ route.params.sort((a, b) => a.index - b.index);
525
+ }
526
+ }
527
+ }
528
+ var RETURN_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.returnBuffer");
529
+ function recordReturn(target, fnName, schema) {
530
+ const carrier = carrierOf(target);
531
+ const routes = carrier[ROUTES];
532
+ const route = routes?.find((r) => r.fnName === fnName);
533
+ if (route) {
534
+ route.returnSchema = schema;
535
+ return;
536
+ }
537
+ if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {
538
+ carrier[RETURN_BUFFER] = {};
539
+ }
540
+ carrier[RETURN_BUFFER][fnName] = schema;
541
+ }
542
+
543
+ // src/decorators/methods.ts
544
+ function makeMethodDecorator(method) {
545
+ return function(subpath, options = {}) {
546
+ return function(target, propertyKey) {
547
+ recordRoute(target, String(propertyKey), method, subpath, options);
548
+ };
334
549
  };
335
550
  }
336
- var route = {
337
- get: makeRoute("GET"),
338
- post: makeRoute("POST"),
339
- put: makeRoute("PUT"),
340
- patch: makeRoute("PATCH"),
341
- delete: makeRoute("DELETE")
342
- };
343
- function defineController(basePath, routes) {
344
- return { __palbase: "controller", basePath, routes };
551
+ var Get = makeMethodDecorator("GET");
552
+ var Post = makeMethodDecorator("POST");
553
+ var Put = makeMethodDecorator("PUT");
554
+ var Patch = makeMethodDecorator("PATCH");
555
+ var Delete = makeMethodDecorator("DELETE");
556
+ function Returns(schema) {
557
+ return function(target, propertyKey) {
558
+ recordReturn(target, String(propertyKey), schema);
559
+ };
560
+ }
561
+
562
+ // src/decorators/params.ts
563
+ function makeParamDecorator(kind, extra) {
564
+ return function(target, propertyKey, parameterIndex) {
565
+ recordParam(target, String(propertyKey), {
566
+ index: parameterIndex,
567
+ kind,
568
+ ...extra?.schema !== void 0 ? { schema: extra.schema } : {},
569
+ ...extra?.name !== void 0 ? { name: extra.name } : {}
570
+ });
571
+ };
572
+ }
573
+ function Body(schema) {
574
+ return makeParamDecorator("body", { schema });
575
+ }
576
+ function Query(schema) {
577
+ return makeParamDecorator("query", { schema });
578
+ }
579
+ function Headers(schema) {
580
+ return makeParamDecorator("headers", schema !== void 0 ? { schema } : void 0);
581
+ }
582
+ function Param(name) {
583
+ return makeParamDecorator("param", { name });
584
+ }
585
+ function User() {
586
+ return makeParamDecorator("user");
587
+ }
588
+ function OptionalUser() {
589
+ return makeParamDecorator("optionalUser");
590
+ }
591
+ function Client() {
592
+ return makeParamDecorator("client");
593
+ }
594
+ function RequestId() {
595
+ return makeParamDecorator("requestId");
596
+ }
597
+ function TraceId() {
598
+ return makeParamDecorator("traceId");
599
+ }
600
+ function Req() {
601
+ return makeParamDecorator("req");
345
602
  }
346
603
 
347
604
  // src/middleware.ts
@@ -386,6 +643,52 @@ var HttpError = class extends Error {
386
643
  return result;
387
644
  }
388
645
  };
646
+ var PalError = class extends HttpError {
647
+ constructor(status, code, description, data) {
648
+ super(status, code, description, data);
649
+ this.name = "PalError";
650
+ }
651
+ };
652
+ var NamedHttpError = class extends HttpError {
653
+ constructor(status, defaultCode, name, message, code, data) {
654
+ super(status, code ?? defaultCode, message ?? defaultMessage(name), data);
655
+ this.name = name;
656
+ }
657
+ };
658
+ function defaultMessage(name) {
659
+ const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
660
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
661
+ }
662
+ var BadRequest = class extends NamedHttpError {
663
+ constructor(message, code, data) {
664
+ super(400, "bad_request", "BadRequest", message, code, data);
665
+ }
666
+ };
667
+ var Unauthorized = class extends NamedHttpError {
668
+ constructor(message, code, data) {
669
+ super(401, "unauthorized", "Unauthorized", message, code, data);
670
+ }
671
+ };
672
+ var Forbidden = class extends NamedHttpError {
673
+ constructor(message, code, data) {
674
+ super(403, "forbidden", "Forbidden", message, code, data);
675
+ }
676
+ };
677
+ var NotFound = class extends NamedHttpError {
678
+ constructor(message, code, data) {
679
+ super(404, "not_found", "NotFound", message, code, data);
680
+ }
681
+ };
682
+ var Conflict = class extends NamedHttpError {
683
+ constructor(message, code, data) {
684
+ super(409, "conflict", "Conflict", message, code, data);
685
+ }
686
+ };
687
+ var TooManyRequests = class extends NamedHttpError {
688
+ constructor(message, code, data) {
689
+ super(429, "too_many_requests", "TooManyRequests", message, code, data);
690
+ }
691
+ };
389
692
 
390
693
  // src/worker.ts
391
694
  var VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;
@@ -688,16 +991,43 @@ var documents = {
688
991
  var import_zod = require("zod");
689
992
  // Annotate the CommonJS export names for ESM import in node:
690
993
  0 && (module.exports = {
994
+ BadRequest,
995
+ Body,
691
996
  Cache,
997
+ Client,
998
+ Conflict,
999
+ Controller,
692
1000
  Database,
1001
+ Delete,
693
1002
  Documents,
1003
+ EXTENSION_DEPENDENCIES,
694
1004
  Flags,
1005
+ Forbidden,
1006
+ Get,
1007
+ Headers,
695
1008
  HttpError,
696
1009
  Log,
1010
+ NotFound,
697
1011
  Notifications,
1012
+ OptionalUser,
1013
+ PALBASE_EXTENSIONS,
1014
+ PalError,
1015
+ Param,
1016
+ Patch,
1017
+ PolicyBuilder,
1018
+ Post,
1019
+ Put,
1020
+ Query,
698
1021
  Queue,
1022
+ Req,
1023
+ RequestId,
699
1024
  Resource,
1025
+ Returns,
700
1026
  Storage,
1027
+ TooManyRequests,
1028
+ TraceId,
1029
+ Unauthorized,
1030
+ User,
701
1031
  __getRuntime,
702
1032
  __registerResource,
703
1033
  __requestALS,
@@ -707,8 +1037,6 @@ var import_zod = require("zod");
707
1037
  __shutdownResources,
708
1038
  auth,
709
1039
  boolean,
710
- defineController,
711
- defineHandler,
712
1040
  defineJob,
713
1041
  defineMiddleware,
714
1042
  defineSchema,
@@ -717,10 +1045,11 @@ var import_zod = require("zod");
717
1045
  documents,
718
1046
  enumType,
719
1047
  integer,
1048
+ isPalbaseExtension,
720
1049
  jsonb,
721
1050
  makeEnvDts,
722
1051
  makeTypedDB,
723
- route,
1052
+ policy,
724
1053
  storage,
725
1054
  text,
726
1055
  timestamp,