@palbase/backend 29.0.0 → 30.0.1

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 (34) hide show
  1. package/dist/bin/palbase-backend.cjs +22 -7
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +2 -2
  4. package/dist/{chunk-DHJ3SYAE.js → chunk-RADVOY7Y.js} +23 -9
  5. package/dist/{chunk-DHJ3SYAE.js.map → chunk-RADVOY7Y.js.map} +1 -1
  6. package/dist/{chunk-ESSQ3YML.js → chunk-YRVIWHJC.js} +7 -3
  7. package/dist/{chunk-ESSQ3YML.js.map → chunk-YRVIWHJC.js.map} +1 -1
  8. package/dist/db/index.d.cts +1 -1
  9. package/dist/db/index.d.ts +1 -1
  10. package/dist/engine/index.cjs +22 -7
  11. package/dist/engine/index.cjs.map +1 -1
  12. package/dist/engine/index.d.cts +3 -3
  13. package/dist/engine/index.d.ts +3 -3
  14. package/dist/engine/index.js +2 -2
  15. package/dist/{index-BOe82fsK.d.ts → index-8qy3kIuA.d.ts} +66 -4
  16. package/dist/{index-ChvoVczS.d.cts → index-DtCgaZAg.d.cts} +66 -4
  17. package/dist/{index-BZfmdRmh.d.cts → index-Zi7MptvP.d.cts} +3 -3
  18. package/dist/{index-BYDUKexK.d.ts → index-b-Q3l7W5.d.ts} +3 -3
  19. package/dist/index.cjs +55 -2
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +51 -11
  22. package/dist/index.d.ts +51 -11
  23. package/dist/index.js +50 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/openapi/index.d.cts +2 -2
  26. package/dist/openapi/index.d.ts +2 -2
  27. package/dist/{registry-DaqHsOq8.d.ts → registry-BGJ-Al6F.d.ts} +1 -1
  28. package/dist/{registry-B2KfKWv1.d.cts → registry-CEYLH-Iz.d.cts} +1 -1
  29. package/dist/test/index.d.cts +1 -1
  30. package/dist/test/index.d.ts +1 -1
  31. package/docs/README.md +1 -1
  32. package/docs/llms-full.txt +1 -1
  33. package/package.json +1 -1
  34. package/template/package.json +1 -1
@@ -3,8 +3,8 @@ import {
3
3
  BootRefused,
4
4
  createApp,
5
5
  loadConfig
6
- } from "../chunk-DHJ3SYAE.js";
7
- import "../chunk-ESSQ3YML.js";
6
+ } from "../chunk-RADVOY7Y.js";
7
+ import "../chunk-YRVIWHJC.js";
8
8
  import "../chunk-SG4UTNOP.js";
9
9
  import "../chunk-3TUJWHC2.js";
10
10
  import {
@@ -6,7 +6,7 @@ import {
6
6
  assertNoOrphanEntryPoints,
7
7
  buildContainer,
8
8
  buildRelations
9
- } from "./chunk-ESSQ3YML.js";
9
+ } from "./chunk-YRVIWHJC.js";
10
10
  import {
11
11
  qualifiedTableKey
12
12
  } from "./chunk-SG4UTNOP.js";
@@ -2971,7 +2971,7 @@ var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([
2971
2971
  409,
2972
2972
  429
2973
2973
  ]);
2974
- async function refuseUnlessAuthorized(client, spec, requestId) {
2974
+ async function refuseUnlessAuthorized(client, spec, requestId, rolesOfCaller) {
2975
2975
  if (spec.permission !== void 0) {
2976
2976
  const [row] = await client.query("select auth.has_permission($1) as ok", [
2977
2977
  spec.permission
@@ -2981,16 +2981,22 @@ async function refuseUnlessAuthorized(client, spec, requestId) {
2981
2981
  }
2982
2982
  }
2983
2983
  if (spec.role !== void 0) {
2984
- const [row] = await client.query("select $1 = any(auth.app_roles()) as ok", [
2985
- spec.role
2986
- ]);
2987
- if (row?.ok !== true) {
2984
+ const held = await rolesOfCaller();
2985
+ if (!held.includes(spec.role)) {
2988
2986
  return envelope("forbidden", `This endpoint requires the "${spec.role}" role`, 403, requestId);
2989
2987
  }
2990
2988
  }
2991
2989
  return null;
2992
2990
  }
2993
2991
  __name(refuseUnlessAuthorized, "refuseUnlessAuthorized");
2992
+ function makeRoleResolver(client) {
2993
+ let pending = null;
2994
+ return () => {
2995
+ pending ??= client.query("select unnest(auth.app_roles()) as role").then((rows) => rows.map((r) => r.role));
2996
+ return pending;
2997
+ };
2998
+ }
2999
+ __name(makeRoleResolver, "makeRoleResolver");
2994
3000
  async function createApp(opts) {
2995
3001
  const { config, controllers } = opts;
2996
3002
  const container = buildContainer();
@@ -3039,6 +3045,7 @@ async function createApp(opts) {
3039
3045
  Database: db?.client ?? stubModule("Database (a start hook runs before any request \u2014 open your own connection here)"),
3040
3046
  Cache: cache,
3041
3047
  Log: log,
3048
+ Auth: modules.Auth ?? stubModule("Auth"),
3042
3049
  Documents: modules.Documents ?? stubModule("Documents"),
3043
3050
  Storage: modules.Storage ?? stubModule("Storage"),
3044
3051
  Notifications: modules.Notifications ?? stubModule("Notifications"),
@@ -3089,7 +3096,7 @@ async function createApp(opts) {
3089
3096
  claimsJson: JSON.stringify(callerClaims)
3090
3097
  });
3091
3098
  try {
3092
- const refusal = await refuseUnlessAuthorized(uploadDb.client, spec, requestId);
3099
+ const refusal = await refuseUnlessAuthorized(uploadDb.client, spec, requestId, makeRoleResolver(uploadDb.client));
3093
3100
  if (refusal) {
3094
3101
  await uploadDb.commit();
3095
3102
  return refusal;
@@ -3136,8 +3143,9 @@ async function createApp(opts) {
3136
3143
  serviceRole: config.dbServiceRole,
3137
3144
  claimsJson: JSON.stringify(claims ?? {})
3138
3145
  });
3146
+ const rolesOfCaller = makeRoleResolver(db.client);
3139
3147
  if (claims) {
3140
- const refusal = await refuseUnlessAuthorized(db.client, spec, requestId);
3148
+ const refusal = await refuseUnlessAuthorized(db.client, spec, requestId, rolesOfCaller);
3141
3149
  if (refusal) return refusal;
3142
3150
  }
3143
3151
  if (claims && spec.verifiedEmail && claims.email_verified !== true) {
@@ -3290,6 +3298,12 @@ async function createApp(opts) {
3290
3298
  role: claims.role,
3291
3299
  emailVerified: claims.email_verified === true,
3292
3300
  metadata: claims.metadata ?? {},
3301
+ // The caller's APPLICATION roles, from `auth.user_roles` — the
3302
+ // same resolution the gate used, so the handler cannot read a
3303
+ // different set than the one it was admitted on. Never from a
3304
+ // claim: a revoked role has to bite on the next request, and a
3305
+ // token says only what was true when it was minted.
3306
+ roles: await rolesOfCaller(),
3293
3307
  // Server-owned and only ever filled from a verdict palauth
3294
3308
  // returned. Never from a raw header, never from JWT metadata —
3295
3309
  // the type has said so since it was written and this is the
@@ -3551,4 +3565,4 @@ export {
3551
3565
  installEgressFence,
3552
3566
  createApp
3553
3567
  };
3554
- //# sourceMappingURL=chunk-DHJ3SYAE.js.map
3568
+ //# sourceMappingURL=chunk-RADVOY7Y.js.map