@palbase/backend 39.1.7 → 40.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 (44) hide show
  1. package/dist/bin/palbase-backend.cjs.map +1 -1
  2. package/dist/bin/palbase-backend.js +2 -2
  3. package/dist/{chunk-C525N4OW.js → chunk-AS2HDWVQ.js} +3 -2
  4. package/dist/{chunk-C525N4OW.js.map → chunk-AS2HDWVQ.js.map} +1 -1
  5. package/dist/{chunk-H7EKL6HC.js → chunk-RA7KFELX.js} +88 -2
  6. package/dist/chunk-RA7KFELX.js.map +1 -0
  7. package/dist/db/index.d.cts +1 -1
  8. package/dist/db/index.d.ts +1 -1
  9. package/dist/engine/index.cjs +2 -0
  10. package/dist/engine/index.cjs.map +1 -1
  11. package/dist/engine/index.d.cts +3 -3
  12. package/dist/engine/index.d.ts +3 -3
  13. package/dist/engine/index.js +4 -2
  14. package/dist/{index-fLaf0PN2.d.ts → index-B8zC9oV0.d.ts} +3 -3
  15. package/dist/{index-Db5QHdTa.d.cts → index-BAjRbjnq.d.cts} +3 -3
  16. package/dist/{index-QWN1Ncrv.d.ts → index-Ck2K1TgC.d.ts} +3 -3
  17. package/dist/{index-CCY1h_J2.d.cts → index-t7Ie44mM.d.cts} +3 -3
  18. package/dist/index.cjs +84 -59
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +20 -18
  21. package/dist/index.d.ts +20 -18
  22. package/dist/index.js +2 -61
  23. package/dist/index.js.map +1 -1
  24. package/dist/openapi/index.d.cts +2 -2
  25. package/dist/openapi/index.d.ts +2 -2
  26. package/dist/{registry-CH6HRR6T.d.cts → registry-C88au7ti.d.cts} +1 -1
  27. package/dist/{registry-C7tCRyPm.d.ts → registry-wwVUGunv.d.ts} +1 -1
  28. package/dist/stack.cjs.map +1 -1
  29. package/dist/stack.d.cts +21 -6
  30. package/dist/stack.d.ts +21 -6
  31. package/dist/test/index.cjs +19 -1
  32. package/dist/test/index.cjs.map +1 -1
  33. package/dist/test/index.d.cts +21 -2
  34. package/dist/test/index.d.ts +21 -2
  35. package/dist/test/index.js +18 -1
  36. package/dist/test/index.js.map +1 -1
  37. package/docs/README.md +6 -6
  38. package/docs/llms-full.txt +6 -6
  39. package/package.json +3 -6
  40. package/template/AGENTS.md +14 -14
  41. package/template/modules/notes/notes.e2e.test.ts +53 -0
  42. package/template/package.json +2 -2
  43. package/dist/chunk-H7EKL6HC.js.map +0 -1
  44. package/template/scripts/test.sh +0 -33
@@ -1,7 +1,7 @@
1
1
  import { OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi';
2
2
  import { ZodTypeAny } from 'zod';
3
- import { A as AuthSpec, R as RateLimitConfig } from '../index-CCY1h_J2.cjs';
4
- import { P as ParamMeta, T as ThrowDescriptor, U as UploadConfig, S as SseConfig } from '../registry-CH6HRR6T.cjs';
3
+ import { A as AuthSpec, R as RateLimitConfig } from '../index-t7Ie44mM.cjs';
4
+ import { P as ParamMeta, T as ThrowDescriptor, U as UploadConfig, S as SseConfig } from '../registry-C88au7ti.cjs';
5
5
  import '../db/env.cjs';
6
6
  import '../stack.cjs';
7
7
  import 'node:async_hooks';
@@ -1,7 +1,7 @@
1
1
  import { OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi';
2
2
  import { ZodTypeAny } from 'zod';
3
- import { A as AuthSpec, R as RateLimitConfig } from '../index-fLaf0PN2.js';
4
- import { P as ParamMeta, T as ThrowDescriptor, U as UploadConfig, S as SseConfig } from '../registry-C7tCRyPm.js';
3
+ import { A as AuthSpec, R as RateLimitConfig } from '../index-B8zC9oV0.js';
4
+ import { P as ParamMeta, T as ThrowDescriptor, U as UploadConfig, S as SseConfig } from '../registry-wwVUGunv.js';
5
5
  import '../db/env.js';
6
6
  import '../stack.js';
7
7
  import 'node:async_hooks';
@@ -1,4 +1,4 @@
1
- import { D as DatabaseBudget, A as AuthSpec, R as RateLimitConfig } from './index-CCY1h_J2.cjs';
1
+ import { D as DatabaseBudget, A as AuthSpec, R as RateLimitConfig } from './index-t7Ie44mM.cjs';
2
2
  import { ZodTypeAny } from 'zod';
3
3
  import { PalbaseBucketName } from './stack.cjs';
4
4
 
@@ -1,4 +1,4 @@
1
- import { D as DatabaseBudget, A as AuthSpec, R as RateLimitConfig } from './index-fLaf0PN2.js';
1
+ import { D as DatabaseBudget, A as AuthSpec, R as RateLimitConfig } from './index-B8zC9oV0.js';
2
2
  import { ZodTypeAny } from 'zod';
3
3
  import { PalbaseBucketName } from './stack.js';
4
4
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stack.ts"],"sourcesContent":["/**\n * `@palbase/backend/stack` — the controlled global augmentation target for the\n * names the project's STACK holds.\n *\n * `Secrets.get(...)`, the Flags client's key parameters and `@Upload({ bucket })`\n * take these unions, never a raw string, so a name the stack does not hold is a\n * COMPILE error rather than a 500 in production — or, worse, a silent read of a\n * secret nobody set.\n *\n * Three interfaces in ONE module because the three share a source and a refresh\n * moment: they all come from the linked environment's stack, and any `palbase\n * secret set` / `flags add` / `storage add` moves them together. `@palbase/\n * backend/env` and `@palbase/backend/purchases` stay separate for the opposite\n * reason — their sources are the schema and the catalog.\n *\n * All three are EMPTY by default; the generated `palbase-stack.d.ts` augments\n * them with one member per name:\n *\n * // palbase-stack.d.ts (generated — do not edit)\n * declare module \"@palbase/backend/stack\" {\n * interface Secrets { OPENAI_API_KEY: true }\n * interface Flags { newCheckout: true }\n * interface Buckets { avatars: true }\n * }\n *\n * A project that has not generated the file therefore has NO valid names, and\n * every call fails to compile until it does. That is the intended behaviour,\n * not a rough edge: it is the ONLY shape in which the gate is not optional. A\n * permissive `string` fallback would make the check opt-in, and an opt-in gate\n * is the same as no gate — which is precisely the hole the retired\n * `config/secrets.ts` push-check used to paper over.\n *\n * THIS REPLACED A DECLARATION, and the direction matters. `config/secrets.ts`\n * asked the author to restate, in the repo, names the vault already held; the\n * deploy then compared the two lists. Here the stack is simply read and the\n * result is a type. There is no second list to drift.\n */\n\n/** The secret names this project's vault holds. EMPTY by default; filled by the\n * generated `palbase-stack.d.ts`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Secrets {}\n\n/** The flag keys this project's store defines. EMPTY by default; filled by the\n * generated `palbase-stack.d.ts`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Flags {}\n\n/**\n * One typed bucket: which renditions the stack declared for it.\n *\n * `variants` is a UNION of the declared names, so asking for one the bucket does\n * not have is a compile error rather than a 404 somebody finds in production.\n * The default `never` means a bucket with no variants accepts no variant name at\n * all, which is exactly right.\n *\n * THIS MOVED HERE FROM `db/env.ts` (2026-08-29). It lived there because\n * `config/storage.ts` fed it through `palbase-env.d.ts`, alongside the schema's\n * tables. Buckets do not come from the schema — they come from the STACK — so\n * they belong in the file generated off the stack. Two `Buckets` interfaces for\n * one concept is how `Storage.buckets.docs` and `@Upload({ bucket: \"docs\" })`\n * came to disagree about whether \"docs\" exists.\n */\nexport interface BucketTypes {\n variants: string;\n}\n\n/** The buckets this project's storage carries, keyed by name. EMPTY by default;\n * filled by the generated `palbase-stack.d.ts`. Drives BOTH `Storage.buckets.*`\n * (through `EnvBuckets`) and `@Upload({ bucket })`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Buckets {}\n\n/** Every secret name the stack holds. */\nexport type PalbaseSecretName = keyof Secrets & string;\n\n/** Every flag key the stack defines. */\nexport type PalbaseFlagKey = keyof Flags & string;\n\n/** Every bucket the stack carries. */\nexport type PalbaseBucketName = keyof Buckets & string;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;;","names":[]}
1
+ {"version":3,"sources":["../src/stack.ts"],"sourcesContent":["/**\n * `@palbase/backend/stack` — the controlled global augmentation target for the\n * names the project's STACK holds.\n *\n * `Secrets.get(...)`, the Flags client's key parameters and `@Upload({ bucket })`\n * take these unions, never a raw string, so a name the stack does not hold is a\n * COMPILE error rather than a 500 in production — or, worse, a silent read of a\n * secret nobody set.\n *\n * Four interfaces in ONE module because the four share a source and a refresh\n * moment: they all come from the linked environment's stack, and any `palbase\n * secret set` / `flags add` / `storage add` / `roles` change moves them together.\n * `@palbase/backend/env` and `@palbase/backend/purchases` stay separate for the\n * opposite reason — their sources are the schema and the catalog.\n *\n * All four are EMPTY by default; the generated `palbase-stack.d.ts` augments\n * them with one member per name:\n *\n * // palbase-stack.d.ts (generated — do not edit)\n * declare module \"@palbase/backend/stack\" {\n * interface Secrets { OPENAI_API_KEY: true }\n * interface Flags { newCheckout: true }\n * interface Buckets { avatars: true }\n * interface Roles { admin: true }\n * }\n *\n * A project that has not generated the file therefore has NO valid names, and\n * every call fails to compile until it does. That is the intended behaviour,\n * not a rough edge: it is the ONLY shape in which the gate is not optional. A\n * permissive `string` fallback would make the check opt-in, and an opt-in gate\n * is the same as no gate — which is precisely the hole the retired\n * `config/secrets.ts` push-check used to paper over.\n *\n * THIS REPLACED A DECLARATION, and the direction matters. `config/secrets.ts`\n * asked the author to restate, in the repo, names the vault already held; the\n * deploy then compared the two lists. Here the stack is simply read and the\n * result is a type. There is no second list to drift.\n */\n\n/** The secret names this project's vault holds. EMPTY by default; filled by the\n * generated `palbase-stack.d.ts`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Secrets {}\n\n/** The flag keys this project's store defines. EMPTY by default; filled by the\n * generated `palbase-stack.d.ts`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Flags {}\n\n/**\n * One typed bucket: which renditions the stack declared for it.\n *\n * `variants` is a UNION of the declared names, so asking for one the bucket does\n * not have is a compile error rather than a 404 somebody finds in production.\n * The default `never` means a bucket with no variants accepts no variant name at\n * all, which is exactly right.\n *\n * THIS MOVED HERE FROM `db/env.ts` (2026-08-29). It lived there because\n * `config/storage.ts` fed it through `palbase-env.d.ts`, alongside the schema's\n * tables. Buckets do not come from the schema — they come from the STACK — so\n * they belong in the file generated off the stack. Two `Buckets` interfaces for\n * one concept is how `Storage.buckets.docs` and `@Upload({ bucket: \"docs\" })`\n * came to disagree about whether \"docs\" exists.\n */\nexport interface BucketTypes {\n variants: string;\n}\n\n/** The buckets this project's storage carries, keyed by name. EMPTY by default;\n * filled by the generated `palbase-stack.d.ts`. Drives BOTH `Storage.buckets.*`\n * (through `EnvBuckets`) and `@Upload({ bucket })`. */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by generated palbase-stack.d.ts.\nexport interface Buckets {}\n\n/**\n * The application roles this project's stack declares (`palbase roles`).\n * EMPTY by default; filled by the generated file's `@palbase/backend/stack`\n * block. Drives `auth: { role }` and `User.roles`.\n *\n * Same fail-closed shape as the three above, for the same reason: a permissive\n * `string` fallback would make the role gate opt-in, and an opt-in gate is the\n * same as no gate — a misspelled `auth: { role: \"admn\" }` would compile and\n * refuse every caller in production.\n */\n// biome-ignore lint/suspicious/noEmptyInterface: augmentation target — filled by the generated stack block.\nexport interface Roles {}\n\n/** Every secret name the stack holds. */\nexport type PalbaseSecretName = keyof Secrets & string;\n\n/** Every flag key the stack defines. */\nexport type PalbaseFlagKey = keyof Flags & string;\n\n/** Every bucket the stack carries. */\nexport type PalbaseBucketName = keyof Buckets & string;\n\n/** Every application role the stack declares. */\nexport type PalbaseRoleName = keyof Roles & string;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;;","names":[]}
package/dist/stack.d.cts CHANGED
@@ -7,13 +7,13 @@
7
7
  * COMPILE error rather than a 500 in production — or, worse, a silent read of a
8
8
  * secret nobody set.
9
9
  *
10
- * Three interfaces in ONE module because the three share a source and a refresh
10
+ * Four interfaces in ONE module because the four share a source and a refresh
11
11
  * moment: they all come from the linked environment's stack, and any `palbase
12
- * secret set` / `flags add` / `storage add` moves them together. `@palbase/
13
- * backend/env` and `@palbase/backend/purchases` stay separate for the opposite
14
- * reason — their sources are the schema and the catalog.
12
+ * secret set` / `flags add` / `storage add` / `roles` change moves them together.
13
+ * `@palbase/backend/env` and `@palbase/backend/purchases` stay separate for the
14
+ * opposite reason — their sources are the schema and the catalog.
15
15
  *
16
- * All three are EMPTY by default; the generated `palbase-stack.d.ts` augments
16
+ * All four are EMPTY by default; the generated `palbase-stack.d.ts` augments
17
17
  * them with one member per name:
18
18
  *
19
19
  * // palbase-stack.d.ts (generated — do not edit)
@@ -21,6 +21,7 @@
21
21
  * interface Secrets { OPENAI_API_KEY: true }
22
22
  * interface Flags { newCheckout: true }
23
23
  * interface Buckets { avatars: true }
24
+ * interface Roles { admin: true }
24
25
  * }
25
26
  *
26
27
  * A project that has not generated the file therefore has NO valid names, and
@@ -66,11 +67,25 @@ interface BucketTypes {
66
67
  * (through `EnvBuckets`) and `@Upload({ bucket })`. */
67
68
  interface Buckets {
68
69
  }
70
+ /**
71
+ * The application roles this project's stack declares (`palbase roles`).
72
+ * EMPTY by default; filled by the generated file's `@palbase/backend/stack`
73
+ * block. Drives `auth: { role }` and `User.roles`.
74
+ *
75
+ * Same fail-closed shape as the three above, for the same reason: a permissive
76
+ * `string` fallback would make the role gate opt-in, and an opt-in gate is the
77
+ * same as no gate — a misspelled `auth: { role: "admn" }` would compile and
78
+ * refuse every caller in production.
79
+ */
80
+ interface Roles {
81
+ }
69
82
  /** Every secret name the stack holds. */
70
83
  type PalbaseSecretName = keyof Secrets & string;
71
84
  /** Every flag key the stack defines. */
72
85
  type PalbaseFlagKey = keyof Flags & string;
73
86
  /** Every bucket the stack carries. */
74
87
  type PalbaseBucketName = keyof Buckets & string;
88
+ /** Every application role the stack declares. */
89
+ type PalbaseRoleName = keyof Roles & string;
75
90
 
76
- export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName, Secrets };
91
+ export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseRoleName, PalbaseSecretName, Roles, Secrets };
package/dist/stack.d.ts CHANGED
@@ -7,13 +7,13 @@
7
7
  * COMPILE error rather than a 500 in production — or, worse, a silent read of a
8
8
  * secret nobody set.
9
9
  *
10
- * Three interfaces in ONE module because the three share a source and a refresh
10
+ * Four interfaces in ONE module because the four share a source and a refresh
11
11
  * moment: they all come from the linked environment's stack, and any `palbase
12
- * secret set` / `flags add` / `storage add` moves them together. `@palbase/
13
- * backend/env` and `@palbase/backend/purchases` stay separate for the opposite
14
- * reason — their sources are the schema and the catalog.
12
+ * secret set` / `flags add` / `storage add` / `roles` change moves them together.
13
+ * `@palbase/backend/env` and `@palbase/backend/purchases` stay separate for the
14
+ * opposite reason — their sources are the schema and the catalog.
15
15
  *
16
- * All three are EMPTY by default; the generated `palbase-stack.d.ts` augments
16
+ * All four are EMPTY by default; the generated `palbase-stack.d.ts` augments
17
17
  * them with one member per name:
18
18
  *
19
19
  * // palbase-stack.d.ts (generated — do not edit)
@@ -21,6 +21,7 @@
21
21
  * interface Secrets { OPENAI_API_KEY: true }
22
22
  * interface Flags { newCheckout: true }
23
23
  * interface Buckets { avatars: true }
24
+ * interface Roles { admin: true }
24
25
  * }
25
26
  *
26
27
  * A project that has not generated the file therefore has NO valid names, and
@@ -66,11 +67,25 @@ interface BucketTypes {
66
67
  * (through `EnvBuckets`) and `@Upload({ bucket })`. */
67
68
  interface Buckets {
68
69
  }
70
+ /**
71
+ * The application roles this project's stack declares (`palbase roles`).
72
+ * EMPTY by default; filled by the generated file's `@palbase/backend/stack`
73
+ * block. Drives `auth: { role }` and `User.roles`.
74
+ *
75
+ * Same fail-closed shape as the three above, for the same reason: a permissive
76
+ * `string` fallback would make the role gate opt-in, and an opt-in gate is the
77
+ * same as no gate — a misspelled `auth: { role: "admn" }` would compile and
78
+ * refuse every caller in production.
79
+ */
80
+ interface Roles {
81
+ }
69
82
  /** Every secret name the stack holds. */
70
83
  type PalbaseSecretName = keyof Secrets & string;
71
84
  /** Every flag key the stack defines. */
72
85
  type PalbaseFlagKey = keyof Flags & string;
73
86
  /** Every bucket the stack carries. */
74
87
  type PalbaseBucketName = keyof Buckets & string;
88
+ /** Every application role the stack declares. */
89
+ type PalbaseRoleName = keyof Roles & string;
75
90
 
76
- export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName, Secrets };
91
+ export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseRoleName, PalbaseSecretName, Roles, Secrets };
@@ -26,6 +26,7 @@ __export(test_exports, {
26
26
  createTestApi: () => createTestApi,
27
27
  fakeDatabase: () => fakeDatabase,
28
28
  isolated: () => isolated,
29
+ testRun: () => testRun,
29
30
  withServices: () => withServices
30
31
  });
31
32
  module.exports = __toCommonJS(test_exports);
@@ -1406,7 +1407,7 @@ function parseIdentities(raw) {
1406
1407
  try {
1407
1408
  return JSON.parse(raw);
1408
1409
  } catch {
1409
- return {};
1410
+ throw new Error("PALBASE_TEST_IDENTITIES is set but is not JSON \u2014 the run that started these tests handed over a broken identity set");
1410
1411
  }
1411
1412
  }
1412
1413
  __name(parseIdentities, "parseIdentities");
@@ -1418,6 +1419,22 @@ function safeParse(text) {
1418
1419
  }
1419
1420
  }
1420
1421
  __name(safeParse, "safeParse");
1422
+ var testRun = {
1423
+ get stack() {
1424
+ return Boolean(process.env.PALBASE_TEST_BASE_URL);
1425
+ },
1426
+ minted(name) {
1427
+ const raw = process.env.PALBASE_TEST_IDENTITIES;
1428
+ if (!raw) return false;
1429
+ let identities;
1430
+ try {
1431
+ identities = JSON.parse(raw);
1432
+ } catch {
1433
+ throw new Error("PALBASE_TEST_IDENTITIES is set but is not JSON \u2014 the run that started these tests handed over a broken identity set");
1434
+ }
1435
+ return typeof identities === "object" && identities !== null && Object.prototype.hasOwnProperty.call(identities, name);
1436
+ }
1437
+ };
1421
1438
  var configured = null;
1422
1439
  var api = new Proxy({}, {
1423
1440
  get(_target, prop) {
@@ -3321,6 +3338,7 @@ __name(withServices, "withServices");
3321
3338
  createTestApi,
3322
3339
  fakeDatabase,
3323
3340
  isolated,
3341
+ testRun,
3324
3342
  withServices
3325
3343
  });
3326
3344
  /*! Bundled license information: