@palbase/backend 22.0.1 → 23.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/bin/palbase-backend.cjs +764 -25
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -4
- package/dist/{chunk-POYAFBLF.js → chunk-FSGSB42K.js} +13 -6
- package/dist/chunk-FSGSB42K.js.map +1 -0
- package/dist/{chunk-SSGAMC26.js → chunk-HAF67F2H.js} +114 -5
- package/dist/chunk-HAF67F2H.js.map +1 -0
- package/dist/{chunk-QMVK4X3V.js → chunk-OMRTHM4X.js} +98 -98
- package/dist/chunk-OMRTHM4X.js.map +1 -0
- package/dist/{chunk-QYOHMVUW.js → chunk-REZU6UKT.js} +755 -24
- package/dist/chunk-REZU6UKT.js.map +1 -0
- package/dist/{chunk-YL4C5NRY.js → chunk-Y5HXVUMP.js} +2 -2
- package/dist/{chunk-N32VDWKH.js → chunk-ZC6Q2BRD.js} +4 -59
- package/dist/chunk-ZC6Q2BRD.js.map +1 -0
- package/dist/db/env.cjs.map +1 -1
- package/dist/db/env.d.cts +3 -21
- package/dist/db/env.d.ts +3 -21
- package/dist/db/index.cjs +117 -6
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +3 -2
- package/dist/db/index.d.ts +3 -2
- package/dist/db/index.js +7 -3
- package/dist/{endpoint-B0LpZixz.d.cts → endpoint-BavvbW4P.d.ts} +116 -14
- package/dist/{endpoint-B0LpZixz.d.ts → endpoint-i8TTCohk.d.cts} +116 -14
- package/dist/engine/index.cjs +764 -25
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +6 -5
- package/dist/engine/index.d.ts +6 -5
- package/dist/engine/index.js +3 -3
- package/dist/{index-g-EzitI-.d.ts → index-B3jmmItD.d.ts} +203 -7
- package/dist/{index-BCNtlG1w.d.ts → index-B7YBEG5w.d.ts} +117 -93
- package/dist/{index-BGSCWlUa.d.cts → index-Bmvx1EvJ.d.cts} +203 -7
- package/dist/{index-B4W6d2VJ.d.cts → index-E7OscPJT.d.cts} +117 -93
- package/dist/index.cjs +509 -1085
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +203 -1133
- package/dist/index.d.ts +203 -1133
- package/dist/index.js +288 -900
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +3 -57
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +3 -2
- package/dist/openapi/index.d.ts +3 -2
- package/dist/openapi/index.js +5 -22
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-3BLYv4si.d.ts → registry-C3H2uPeZ.d.cts} +13 -169
- package/dist/{registry-Cw0YEYCg.d.cts → registry-DY3d9l1k.d.ts} +13 -169
- package/dist/{purchases/keys.cjs → stack.cjs} +4 -4
- package/dist/stack.cjs.map +1 -0
- package/dist/stack.d.cts +76 -0
- package/dist/stack.d.ts +76 -0
- package/dist/stack.js +1 -0
- package/docs/README.md +7 -6
- package/docs/endpoints.md +1 -1
- package/docs/errors.md +9 -0
- package/docs/llms-full.txt +17 -261
- package/docs/llms.txt +0 -2
- package/package.json +7 -7
- package/template/package.json +1 -1
- package/dist/chunk-N32VDWKH.js.map +0 -1
- package/dist/chunk-POYAFBLF.js.map +0 -1
- package/dist/chunk-QMVK4X3V.js.map +0 -1
- package/dist/chunk-QYOHMVUW.js.map +0 -1
- package/dist/chunk-SSGAMC26.js.map +0 -1
- package/dist/purchases/keys.cjs.map +0 -1
- package/dist/purchases/keys.d.cts +0 -42
- package/dist/purchases/keys.d.ts +0 -42
- package/dist/purchases/keys.js +0 -1
- package/docs/config.md +0 -147
- package/docs/resources.md +0 -97
- package/template/config/secrets.ts +0 -24
- /package/dist/{chunk-YL4C5NRY.js.map → chunk-Y5HXVUMP.js.map} +0 -0
- /package/dist/{purchases/keys.js.map → stack.js.map} +0 -0
|
@@ -1,155 +1,6 @@
|
|
|
1
|
-
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-i8TTCohk.cjs';
|
|
2
2
|
import { ZodTypeAny } from 'zod';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* storage.ts — the storage-buckets config-as-code DSL.
|
|
6
|
-
*
|
|
7
|
-
* `defineStorage({ buckets })` is the first MODULE config-as-code surface (the
|
|
8
|
-
* sibling of `db/schema.ts`'s `defineSchema`). A `config/storage.ts` file
|
|
9
|
-
* default-exports a `defineStorage(...)` result; on deploy the br-pod evaluates
|
|
10
|
-
* it to JSON and reconciles the declared buckets against the tenant's live
|
|
11
|
-
* buckets via the Storage admin API (create missing, update changed; never
|
|
12
|
-
* auto-delete — dropping a bucket is destructive and warned only).
|
|
13
|
-
*
|
|
14
|
-
* Buckets are DECLARATIVE: name + access + size/mime limits. The FILES inside a
|
|
15
|
-
* bucket are runtime state (uploaded via the SDK), never in git.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* import { defineStorage, bucket } from "@palbase/backend";
|
|
19
|
-
*
|
|
20
|
-
* export default defineStorage({
|
|
21
|
-
* buckets: {
|
|
22
|
-
* avatars: bucket({
|
|
23
|
-
* public: true,
|
|
24
|
-
* fileSizeLimit: "5MB",
|
|
25
|
-
* allowedMimeTypes: ["image/png", "image/jpeg", "image/webp"],
|
|
26
|
-
* }),
|
|
27
|
-
* invoices: bucket({
|
|
28
|
-
* public: false,
|
|
29
|
-
* fileSizeLimit: "20MB",
|
|
30
|
-
* allowedMimeTypes: ["application/pdf"],
|
|
31
|
-
* }),
|
|
32
|
-
* },
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* The returned value is the EXACT JSON shape the runtime's generic config
|
|
36
|
-
* extractor (`config_extract.js`) emits and the Go apply step parses:
|
|
37
|
-
* { __config: "storage", buckets: { avatars: { public, fileSizeLimit, allowedMimeTypes }, ... } }
|
|
38
|
-
* `fileSizeLimit` is always normalized to a number of bytes (or null when
|
|
39
|
-
* omitted, meaning "no limit"); the apply step maps it to the Storage API's
|
|
40
|
-
* `file_size_limit` field. `allowedMimeTypes` is the allowlist or null (any).
|
|
41
|
-
*/
|
|
42
|
-
/** The discriminant written under `__config` so the eval/apply can tell which
|
|
43
|
-
* module config a `config/*.ts` file describes. Storage is `"storage"`. */
|
|
44
|
-
declare const STORAGE_CONFIG_KIND: "storage";
|
|
45
|
-
/**
|
|
46
|
-
* The author-facing options for a single bucket.
|
|
47
|
-
*
|
|
48
|
-
* - `public`: when true the bucket is served without a signed URL. Defaults to
|
|
49
|
-
* `false` (private — signed URLs only).
|
|
50
|
-
* - `fileSizeLimit`: the per-object upload cap. Accepts a human string
|
|
51
|
-
* (`"5MB"`, `"20MB"`, `"1GB"`) or a bare number of BYTES. Omit for no limit.
|
|
52
|
-
* - `allowedMimeTypes`: an allowlist of MIME types accepted on upload. Omit to
|
|
53
|
-
* allow any type. Each entry must look like `type/subtype` (e.g. `image/png`,
|
|
54
|
-
* `application/pdf`, or a wildcard `image/*`).
|
|
55
|
-
*/
|
|
56
|
-
interface BucketOptions {
|
|
57
|
-
public?: boolean;
|
|
58
|
-
fileSizeLimit?: string | number;
|
|
59
|
-
allowedMimeTypes?: string[];
|
|
60
|
-
variants?: Record<string, ImageVariant>;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* One named rendition of an uploaded image — the same three knobs
|
|
64
|
-
* `getPublicUrl(path, ...)` takes, given a name so the size lives with the
|
|
65
|
-
* bucket instead of being retyped at every call site.
|
|
66
|
-
*
|
|
67
|
-
* At least one of `width` / `height` must be set (a variant that resizes
|
|
68
|
-
* nothing and converts nothing is a typo, not a variant).
|
|
69
|
-
*/
|
|
70
|
-
interface ImageVariant {
|
|
71
|
-
width?: number;
|
|
72
|
-
height?: number;
|
|
73
|
-
/**
|
|
74
|
-
* How the source is made to meet the box. Defaults to `"contain"`.
|
|
75
|
-
*
|
|
76
|
-
* - `cover` fills the box exactly and crops the overflow from the centre —
|
|
77
|
-
* what a square avatar or a grid cell needs.
|
|
78
|
-
* - `contain` fits the whole picture inside the box, cropping nothing. One
|
|
79
|
-
* side may come out smaller than declared.
|
|
80
|
-
* - `inside` is `contain` that never ENLARGES. Blowing a 100px image up to
|
|
81
|
-
* 1000px produces a blurry picture that is bigger on the wire.
|
|
82
|
-
*/
|
|
83
|
-
fit?: "cover" | "contain" | "inside";
|
|
84
|
-
format?: "webp" | "avif" | "jpeg" | "png";
|
|
85
|
-
/** Encoder quality, 1–100. Defaults to 85. JPEG only. */
|
|
86
|
-
quality?: number;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* The compiled, serializable bucket definition — the EXACT shape emitted to
|
|
90
|
-
* JSON and consumed by the Go apply step.
|
|
91
|
-
*
|
|
92
|
-
* - `public`: always present (defaulted to `false`).
|
|
93
|
-
* - `fileSizeLimit`: bytes as a number, or `null` for "no limit".
|
|
94
|
-
* - `allowedMimeTypes`: the MIME allowlist, or `null` for "any type".
|
|
95
|
-
*/
|
|
96
|
-
interface BucketDef {
|
|
97
|
-
public: boolean;
|
|
98
|
-
fileSizeLimit: number | null;
|
|
99
|
-
allowedMimeTypes: string[] | null;
|
|
100
|
-
/** Named renditions, or `null` when none are declared. Rendered AT UPLOAD and
|
|
101
|
-
* stored as objects of their own, behind immutable URLs. */
|
|
102
|
-
variants: Record<string, ImageVariant> | null;
|
|
103
|
-
}
|
|
104
|
-
/** A storage config definition: the discriminant + a map of bucket name →
|
|
105
|
-
* {@link BucketDef}. This is the value `defineStorage` returns and the runtime
|
|
106
|
-
* config extractor serializes. */
|
|
107
|
-
interface StorageConfig {
|
|
108
|
-
__config: typeof STORAGE_CONFIG_KIND;
|
|
109
|
-
buckets: Record<string, BucketDef>;
|
|
110
|
-
}
|
|
111
|
-
/** The author-facing input to `defineStorage`: a `buckets` map whose keys are
|
|
112
|
-
* the bucket names and whose values are `bucket({...})` builders. */
|
|
113
|
-
interface StorageInput {
|
|
114
|
-
buckets: Record<string, BucketDef>;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Parse a `fileSizeLimit` into a number of bytes.
|
|
118
|
-
*
|
|
119
|
-
* - A bare number is taken as bytes verbatim (must be a non-negative integer).
|
|
120
|
-
* - A string is `<number><unit>` (e.g. `"5MB"`, `"1.5GB"`, `"500kb"`); the unit
|
|
121
|
-
* is case-insensitive and optional (a bare numeric string = bytes). Binary
|
|
122
|
-
* units (1 MB = 1024 squared bytes) to match the Storage module's parser.
|
|
123
|
-
*
|
|
124
|
-
* Throws on a negative value, a non-finite number, or an unrecognized unit so a
|
|
125
|
-
* bad limit fails at config-author time, not silently at deploy.
|
|
126
|
-
*/
|
|
127
|
-
declare function parseFileSizeLimit(input: string | number): number;
|
|
128
|
-
/**
|
|
129
|
-
* Define a single bucket. The bucket NAME is supplied by the key in
|
|
130
|
-
* `defineStorage({ buckets: { <name>: bucket({...}) } })`, so `bucket()` takes
|
|
131
|
-
* only the options.
|
|
132
|
-
*
|
|
133
|
-
* Validates eagerly (at config-author time):
|
|
134
|
-
* - `fileSizeLimit` parses to a valid non-negative byte count.
|
|
135
|
-
* - each `allowedMimeTypes` entry is a `type/subtype` MIME string.
|
|
136
|
-
*
|
|
137
|
-
* Returns a normalized {@link BucketDef}: `public` defaulted to `false`,
|
|
138
|
-
* `fileSizeLimit` as bytes-or-null, `allowedMimeTypes` deduped-or-null.
|
|
139
|
-
*/
|
|
140
|
-
declare function bucket(opts?: BucketOptions): BucketDef;
|
|
141
|
-
/**
|
|
142
|
-
* Define the storage config for a project. The bucket NAME comes from each
|
|
143
|
-
* object key (authors never repeat the name). Returns the discriminated
|
|
144
|
-
* {@link StorageConfig} the runtime config extractor serializes and the Go
|
|
145
|
-
* apply step reconciles.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* export default defineStorage({
|
|
149
|
-
* buckets: { avatars: bucket({ public: true, fileSizeLimit: "5MB" }) },
|
|
150
|
-
* });
|
|
151
|
-
*/
|
|
152
|
-
declare function defineStorage(input: StorageInput): StorageConfig;
|
|
3
|
+
import { PalbaseBucketName } from './stack.cjs';
|
|
153
4
|
|
|
154
5
|
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
155
6
|
* descriptor)`. */
|
|
@@ -164,7 +15,13 @@ type ParameterDecorator = (target: object, propertyKey: string | symbol, paramet
|
|
|
164
15
|
*/
|
|
165
16
|
interface UploadConfig {
|
|
166
17
|
/**
|
|
167
|
-
* Target bucket NAME
|
|
18
|
+
* Target bucket NAME — one the STACK holds.
|
|
19
|
+
*
|
|
20
|
+
* The union comes from the generated `palbase-stack.d.ts`, so a bucket the
|
|
21
|
+
* stack does not carry is a compile error. It used to say "MUST exist in
|
|
22
|
+
* `config/storage.ts` defineStorage(...)", and that invariant was carried by
|
|
23
|
+
* this sentence plus a cross-check nothing called; it is carried by the type
|
|
24
|
+
* now.
|
|
168
25
|
*
|
|
169
26
|
* The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
|
|
170
27
|
* `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
|
|
@@ -174,7 +31,7 @@ interface UploadConfig {
|
|
|
174
31
|
* enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
|
|
175
32
|
* bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
|
|
176
33
|
*/
|
|
177
|
-
bucket:
|
|
34
|
+
bucket: PalbaseBucketName;
|
|
178
35
|
/**
|
|
179
36
|
* SERVER-side object key template. The client NEVER chooses the path. Tokens:
|
|
180
37
|
* `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
|
|
@@ -191,8 +48,8 @@ interface UploadConfig {
|
|
|
191
48
|
* @example
|
|
192
49
|
* @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
|
|
193
50
|
* async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
|
|
194
|
-
* // The size limit + MIME allowlist come from the "docs" bucket
|
|
195
|
-
* //
|
|
51
|
+
* // The size limit + MIME allowlist come from the "docs" bucket ON THE STACK
|
|
52
|
+
* // — storage enforces them at the PUT.
|
|
196
53
|
*/
|
|
197
54
|
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
198
55
|
/**
|
|
@@ -250,19 +107,6 @@ interface UploadedObject {
|
|
|
250
107
|
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
108
|
*/
|
|
252
109
|
declare function UploadedObject(): ParameterDecorator;
|
|
253
|
-
/**
|
|
254
|
-
* Cross-check one `@Upload` route's uploadConfig against the project's
|
|
255
|
-
* {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.
|
|
256
|
-
* Throws a precise error so a typo fails at deploy, not at the first user upload.
|
|
257
|
-
*
|
|
258
|
-
* That is the ONLY cross-check: the size limit + MIME allowlist live on the
|
|
259
|
-
* bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by
|
|
260
|
-
* storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,
|
|
261
|
-
* so there is nothing to compare — one bucket, one limit, no drift.
|
|
262
|
-
*
|
|
263
|
-
* `routeLabel` is used only for error messages (e.g. `docs.upload`).
|
|
264
|
-
*/
|
|
265
|
-
declare function validateUploadAgainstStorage(uploadConfig: UploadConfig, storage: StorageConfig, routeLabel: string): void;
|
|
266
110
|
|
|
267
111
|
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
112
|
* OpenAPI lower-case on their own). */
|
|
@@ -335,4 +179,4 @@ declare function recordThrows(target: object, fnName: string, throws: ThrowDescr
|
|
|
335
179
|
*/
|
|
336
180
|
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
181
|
|
|
338
|
-
export { type
|
|
182
|
+
export { type HttpMethodUpper as H, type ParamMeta as P, type RouteMeta as R, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type ParamKind as b, Upload as c, UploadedObject as d, getRoutes as g, recordThrows as r };
|
|
@@ -1,155 +1,6 @@
|
|
|
1
|
-
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-BavvbW4P.js';
|
|
2
2
|
import { ZodTypeAny } from 'zod';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* storage.ts — the storage-buckets config-as-code DSL.
|
|
6
|
-
*
|
|
7
|
-
* `defineStorage({ buckets })` is the first MODULE config-as-code surface (the
|
|
8
|
-
* sibling of `db/schema.ts`'s `defineSchema`). A `config/storage.ts` file
|
|
9
|
-
* default-exports a `defineStorage(...)` result; on deploy the br-pod evaluates
|
|
10
|
-
* it to JSON and reconciles the declared buckets against the tenant's live
|
|
11
|
-
* buckets via the Storage admin API (create missing, update changed; never
|
|
12
|
-
* auto-delete — dropping a bucket is destructive and warned only).
|
|
13
|
-
*
|
|
14
|
-
* Buckets are DECLARATIVE: name + access + size/mime limits. The FILES inside a
|
|
15
|
-
* bucket are runtime state (uploaded via the SDK), never in git.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* import { defineStorage, bucket } from "@palbase/backend";
|
|
19
|
-
*
|
|
20
|
-
* export default defineStorage({
|
|
21
|
-
* buckets: {
|
|
22
|
-
* avatars: bucket({
|
|
23
|
-
* public: true,
|
|
24
|
-
* fileSizeLimit: "5MB",
|
|
25
|
-
* allowedMimeTypes: ["image/png", "image/jpeg", "image/webp"],
|
|
26
|
-
* }),
|
|
27
|
-
* invoices: bucket({
|
|
28
|
-
* public: false,
|
|
29
|
-
* fileSizeLimit: "20MB",
|
|
30
|
-
* allowedMimeTypes: ["application/pdf"],
|
|
31
|
-
* }),
|
|
32
|
-
* },
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* The returned value is the EXACT JSON shape the runtime's generic config
|
|
36
|
-
* extractor (`config_extract.js`) emits and the Go apply step parses:
|
|
37
|
-
* { __config: "storage", buckets: { avatars: { public, fileSizeLimit, allowedMimeTypes }, ... } }
|
|
38
|
-
* `fileSizeLimit` is always normalized to a number of bytes (or null when
|
|
39
|
-
* omitted, meaning "no limit"); the apply step maps it to the Storage API's
|
|
40
|
-
* `file_size_limit` field. `allowedMimeTypes` is the allowlist or null (any).
|
|
41
|
-
*/
|
|
42
|
-
/** The discriminant written under `__config` so the eval/apply can tell which
|
|
43
|
-
* module config a `config/*.ts` file describes. Storage is `"storage"`. */
|
|
44
|
-
declare const STORAGE_CONFIG_KIND: "storage";
|
|
45
|
-
/**
|
|
46
|
-
* The author-facing options for a single bucket.
|
|
47
|
-
*
|
|
48
|
-
* - `public`: when true the bucket is served without a signed URL. Defaults to
|
|
49
|
-
* `false` (private — signed URLs only).
|
|
50
|
-
* - `fileSizeLimit`: the per-object upload cap. Accepts a human string
|
|
51
|
-
* (`"5MB"`, `"20MB"`, `"1GB"`) or a bare number of BYTES. Omit for no limit.
|
|
52
|
-
* - `allowedMimeTypes`: an allowlist of MIME types accepted on upload. Omit to
|
|
53
|
-
* allow any type. Each entry must look like `type/subtype` (e.g. `image/png`,
|
|
54
|
-
* `application/pdf`, or a wildcard `image/*`).
|
|
55
|
-
*/
|
|
56
|
-
interface BucketOptions {
|
|
57
|
-
public?: boolean;
|
|
58
|
-
fileSizeLimit?: string | number;
|
|
59
|
-
allowedMimeTypes?: string[];
|
|
60
|
-
variants?: Record<string, ImageVariant>;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* One named rendition of an uploaded image — the same three knobs
|
|
64
|
-
* `getPublicUrl(path, ...)` takes, given a name so the size lives with the
|
|
65
|
-
* bucket instead of being retyped at every call site.
|
|
66
|
-
*
|
|
67
|
-
* At least one of `width` / `height` must be set (a variant that resizes
|
|
68
|
-
* nothing and converts nothing is a typo, not a variant).
|
|
69
|
-
*/
|
|
70
|
-
interface ImageVariant {
|
|
71
|
-
width?: number;
|
|
72
|
-
height?: number;
|
|
73
|
-
/**
|
|
74
|
-
* How the source is made to meet the box. Defaults to `"contain"`.
|
|
75
|
-
*
|
|
76
|
-
* - `cover` fills the box exactly and crops the overflow from the centre —
|
|
77
|
-
* what a square avatar or a grid cell needs.
|
|
78
|
-
* - `contain` fits the whole picture inside the box, cropping nothing. One
|
|
79
|
-
* side may come out smaller than declared.
|
|
80
|
-
* - `inside` is `contain` that never ENLARGES. Blowing a 100px image up to
|
|
81
|
-
* 1000px produces a blurry picture that is bigger on the wire.
|
|
82
|
-
*/
|
|
83
|
-
fit?: "cover" | "contain" | "inside";
|
|
84
|
-
format?: "webp" | "avif" | "jpeg" | "png";
|
|
85
|
-
/** Encoder quality, 1–100. Defaults to 85. JPEG only. */
|
|
86
|
-
quality?: number;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* The compiled, serializable bucket definition — the EXACT shape emitted to
|
|
90
|
-
* JSON and consumed by the Go apply step.
|
|
91
|
-
*
|
|
92
|
-
* - `public`: always present (defaulted to `false`).
|
|
93
|
-
* - `fileSizeLimit`: bytes as a number, or `null` for "no limit".
|
|
94
|
-
* - `allowedMimeTypes`: the MIME allowlist, or `null` for "any type".
|
|
95
|
-
*/
|
|
96
|
-
interface BucketDef {
|
|
97
|
-
public: boolean;
|
|
98
|
-
fileSizeLimit: number | null;
|
|
99
|
-
allowedMimeTypes: string[] | null;
|
|
100
|
-
/** Named renditions, or `null` when none are declared. Rendered AT UPLOAD and
|
|
101
|
-
* stored as objects of their own, behind immutable URLs. */
|
|
102
|
-
variants: Record<string, ImageVariant> | null;
|
|
103
|
-
}
|
|
104
|
-
/** A storage config definition: the discriminant + a map of bucket name →
|
|
105
|
-
* {@link BucketDef}. This is the value `defineStorage` returns and the runtime
|
|
106
|
-
* config extractor serializes. */
|
|
107
|
-
interface StorageConfig {
|
|
108
|
-
__config: typeof STORAGE_CONFIG_KIND;
|
|
109
|
-
buckets: Record<string, BucketDef>;
|
|
110
|
-
}
|
|
111
|
-
/** The author-facing input to `defineStorage`: a `buckets` map whose keys are
|
|
112
|
-
* the bucket names and whose values are `bucket({...})` builders. */
|
|
113
|
-
interface StorageInput {
|
|
114
|
-
buckets: Record<string, BucketDef>;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Parse a `fileSizeLimit` into a number of bytes.
|
|
118
|
-
*
|
|
119
|
-
* - A bare number is taken as bytes verbatim (must be a non-negative integer).
|
|
120
|
-
* - A string is `<number><unit>` (e.g. `"5MB"`, `"1.5GB"`, `"500kb"`); the unit
|
|
121
|
-
* is case-insensitive and optional (a bare numeric string = bytes). Binary
|
|
122
|
-
* units (1 MB = 1024 squared bytes) to match the Storage module's parser.
|
|
123
|
-
*
|
|
124
|
-
* Throws on a negative value, a non-finite number, or an unrecognized unit so a
|
|
125
|
-
* bad limit fails at config-author time, not silently at deploy.
|
|
126
|
-
*/
|
|
127
|
-
declare function parseFileSizeLimit(input: string | number): number;
|
|
128
|
-
/**
|
|
129
|
-
* Define a single bucket. The bucket NAME is supplied by the key in
|
|
130
|
-
* `defineStorage({ buckets: { <name>: bucket({...}) } })`, so `bucket()` takes
|
|
131
|
-
* only the options.
|
|
132
|
-
*
|
|
133
|
-
* Validates eagerly (at config-author time):
|
|
134
|
-
* - `fileSizeLimit` parses to a valid non-negative byte count.
|
|
135
|
-
* - each `allowedMimeTypes` entry is a `type/subtype` MIME string.
|
|
136
|
-
*
|
|
137
|
-
* Returns a normalized {@link BucketDef}: `public` defaulted to `false`,
|
|
138
|
-
* `fileSizeLimit` as bytes-or-null, `allowedMimeTypes` deduped-or-null.
|
|
139
|
-
*/
|
|
140
|
-
declare function bucket(opts?: BucketOptions): BucketDef;
|
|
141
|
-
/**
|
|
142
|
-
* Define the storage config for a project. The bucket NAME comes from each
|
|
143
|
-
* object key (authors never repeat the name). Returns the discriminated
|
|
144
|
-
* {@link StorageConfig} the runtime config extractor serializes and the Go
|
|
145
|
-
* apply step reconciles.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* export default defineStorage({
|
|
149
|
-
* buckets: { avatars: bucket({ public: true, fileSizeLimit: "5MB" }) },
|
|
150
|
-
* });
|
|
151
|
-
*/
|
|
152
|
-
declare function defineStorage(input: StorageInput): StorageConfig;
|
|
3
|
+
import { PalbaseBucketName } from './stack.js';
|
|
153
4
|
|
|
154
5
|
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
155
6
|
* descriptor)`. */
|
|
@@ -164,7 +15,13 @@ type ParameterDecorator = (target: object, propertyKey: string | symbol, paramet
|
|
|
164
15
|
*/
|
|
165
16
|
interface UploadConfig {
|
|
166
17
|
/**
|
|
167
|
-
* Target bucket NAME
|
|
18
|
+
* Target bucket NAME — one the STACK holds.
|
|
19
|
+
*
|
|
20
|
+
* The union comes from the generated `palbase-stack.d.ts`, so a bucket the
|
|
21
|
+
* stack does not carry is a compile error. It used to say "MUST exist in
|
|
22
|
+
* `config/storage.ts` defineStorage(...)", and that invariant was carried by
|
|
23
|
+
* this sentence plus a cross-check nothing called; it is carried by the type
|
|
24
|
+
* now.
|
|
168
25
|
*
|
|
169
26
|
* The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
|
|
170
27
|
* `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
|
|
@@ -174,7 +31,7 @@ interface UploadConfig {
|
|
|
174
31
|
* enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
|
|
175
32
|
* bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
|
|
176
33
|
*/
|
|
177
|
-
bucket:
|
|
34
|
+
bucket: PalbaseBucketName;
|
|
178
35
|
/**
|
|
179
36
|
* SERVER-side object key template. The client NEVER chooses the path. Tokens:
|
|
180
37
|
* `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
|
|
@@ -191,8 +48,8 @@ interface UploadConfig {
|
|
|
191
48
|
* @example
|
|
192
49
|
* @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
|
|
193
50
|
* async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
|
|
194
|
-
* // The size limit + MIME allowlist come from the "docs" bucket
|
|
195
|
-
* //
|
|
51
|
+
* // The size limit + MIME allowlist come from the "docs" bucket ON THE STACK
|
|
52
|
+
* // — storage enforces them at the PUT.
|
|
196
53
|
*/
|
|
197
54
|
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
198
55
|
/**
|
|
@@ -250,19 +107,6 @@ interface UploadedObject {
|
|
|
250
107
|
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
108
|
*/
|
|
252
109
|
declare function UploadedObject(): ParameterDecorator;
|
|
253
|
-
/**
|
|
254
|
-
* Cross-check one `@Upload` route's uploadConfig against the project's
|
|
255
|
-
* {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.
|
|
256
|
-
* Throws a precise error so a typo fails at deploy, not at the first user upload.
|
|
257
|
-
*
|
|
258
|
-
* That is the ONLY cross-check: the size limit + MIME allowlist live on the
|
|
259
|
-
* bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by
|
|
260
|
-
* storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,
|
|
261
|
-
* so there is nothing to compare — one bucket, one limit, no drift.
|
|
262
|
-
*
|
|
263
|
-
* `routeLabel` is used only for error messages (e.g. `docs.upload`).
|
|
264
|
-
*/
|
|
265
|
-
declare function validateUploadAgainstStorage(uploadConfig: UploadConfig, storage: StorageConfig, routeLabel: string): void;
|
|
266
110
|
|
|
267
111
|
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
112
|
* OpenAPI lower-case on their own). */
|
|
@@ -335,4 +179,4 @@ declare function recordThrows(target: object, fnName: string, throws: ThrowDescr
|
|
|
335
179
|
*/
|
|
336
180
|
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
181
|
|
|
338
|
-
export { type
|
|
182
|
+
export { type HttpMethodUpper as H, type ParamMeta as P, type RouteMeta as R, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type ParamKind as b, Upload as c, UploadedObject as d, getRoutes as g, recordThrows as r };
|
|
@@ -13,7 +13,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
13
13
|
};
|
|
14
14
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
15
|
|
|
16
|
-
// src/
|
|
17
|
-
var
|
|
18
|
-
module.exports = __toCommonJS(
|
|
19
|
-
//# sourceMappingURL=
|
|
16
|
+
// src/stack.ts
|
|
17
|
+
var stack_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(stack_exports);
|
|
19
|
+
//# sourceMappingURL=stack.cjs.map
|
|
@@ -0,0 +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;AAAA;","names":[]}
|
package/dist/stack.d.cts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@palbase/backend/stack` — the controlled global augmentation target for the
|
|
3
|
+
* names the project's STACK holds.
|
|
4
|
+
*
|
|
5
|
+
* `Secrets.get(...)`, the Flags client's key parameters and `@Upload({ bucket })`
|
|
6
|
+
* take these unions, never a raw string, so a name the stack does not hold is a
|
|
7
|
+
* COMPILE error rather than a 500 in production — or, worse, a silent read of a
|
|
8
|
+
* secret nobody set.
|
|
9
|
+
*
|
|
10
|
+
* Three interfaces in ONE module because the three share a source and a refresh
|
|
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.
|
|
15
|
+
*
|
|
16
|
+
* All three are EMPTY by default; the generated `palbase-stack.d.ts` augments
|
|
17
|
+
* them with one member per name:
|
|
18
|
+
*
|
|
19
|
+
* // palbase-stack.d.ts (generated — do not edit)
|
|
20
|
+
* declare module "@palbase/backend/stack" {
|
|
21
|
+
* interface Secrets { OPENAI_API_KEY: true }
|
|
22
|
+
* interface Flags { newCheckout: true }
|
|
23
|
+
* interface Buckets { avatars: true }
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* A project that has not generated the file therefore has NO valid names, and
|
|
27
|
+
* every call fails to compile until it does. That is the intended behaviour,
|
|
28
|
+
* not a rough edge: it is the ONLY shape in which the gate is not optional. A
|
|
29
|
+
* permissive `string` fallback would make the check opt-in, and an opt-in gate
|
|
30
|
+
* is the same as no gate — which is precisely the hole the retired
|
|
31
|
+
* `config/secrets.ts` push-check used to paper over.
|
|
32
|
+
*
|
|
33
|
+
* THIS REPLACED A DECLARATION, and the direction matters. `config/secrets.ts`
|
|
34
|
+
* asked the author to restate, in the repo, names the vault already held; the
|
|
35
|
+
* deploy then compared the two lists. Here the stack is simply read and the
|
|
36
|
+
* result is a type. There is no second list to drift.
|
|
37
|
+
*/
|
|
38
|
+
/** The secret names this project's vault holds. EMPTY by default; filled by the
|
|
39
|
+
* generated `palbase-stack.d.ts`. */
|
|
40
|
+
interface Secrets {
|
|
41
|
+
}
|
|
42
|
+
/** The flag keys this project's store defines. EMPTY by default; filled by the
|
|
43
|
+
* generated `palbase-stack.d.ts`. */
|
|
44
|
+
interface Flags {
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One typed bucket: which renditions the stack declared for it.
|
|
48
|
+
*
|
|
49
|
+
* `variants` is a UNION of the declared names, so asking for one the bucket does
|
|
50
|
+
* not have is a compile error rather than a 404 somebody finds in production.
|
|
51
|
+
* The default `never` means a bucket with no variants accepts no variant name at
|
|
52
|
+
* all, which is exactly right.
|
|
53
|
+
*
|
|
54
|
+
* THIS MOVED HERE FROM `db/env.ts` (2026-08-29). It lived there because
|
|
55
|
+
* `config/storage.ts` fed it through `palbase-env.d.ts`, alongside the schema's
|
|
56
|
+
* tables. Buckets do not come from the schema — they come from the STACK — so
|
|
57
|
+
* they belong in the file generated off the stack. Two `Buckets` interfaces for
|
|
58
|
+
* one concept is how `Storage.buckets.docs` and `@Upload({ bucket: "docs" })`
|
|
59
|
+
* came to disagree about whether "docs" exists.
|
|
60
|
+
*/
|
|
61
|
+
interface BucketTypes {
|
|
62
|
+
variants: string;
|
|
63
|
+
}
|
|
64
|
+
/** The buckets this project's storage carries, keyed by name. EMPTY by default;
|
|
65
|
+
* filled by the generated `palbase-stack.d.ts`. Drives BOTH `Storage.buckets.*`
|
|
66
|
+
* (through `EnvBuckets`) and `@Upload({ bucket })`. */
|
|
67
|
+
interface Buckets {
|
|
68
|
+
}
|
|
69
|
+
/** Every secret name the stack holds. */
|
|
70
|
+
type PalbaseSecretName = keyof Secrets & string;
|
|
71
|
+
/** Every flag key the stack defines. */
|
|
72
|
+
type PalbaseFlagKey = keyof Flags & string;
|
|
73
|
+
/** Every bucket the stack carries. */
|
|
74
|
+
type PalbaseBucketName = keyof Buckets & string;
|
|
75
|
+
|
|
76
|
+
export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName, Secrets };
|
package/dist/stack.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@palbase/backend/stack` — the controlled global augmentation target for the
|
|
3
|
+
* names the project's STACK holds.
|
|
4
|
+
*
|
|
5
|
+
* `Secrets.get(...)`, the Flags client's key parameters and `@Upload({ bucket })`
|
|
6
|
+
* take these unions, never a raw string, so a name the stack does not hold is a
|
|
7
|
+
* COMPILE error rather than a 500 in production — or, worse, a silent read of a
|
|
8
|
+
* secret nobody set.
|
|
9
|
+
*
|
|
10
|
+
* Three interfaces in ONE module because the three share a source and a refresh
|
|
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.
|
|
15
|
+
*
|
|
16
|
+
* All three are EMPTY by default; the generated `palbase-stack.d.ts` augments
|
|
17
|
+
* them with one member per name:
|
|
18
|
+
*
|
|
19
|
+
* // palbase-stack.d.ts (generated — do not edit)
|
|
20
|
+
* declare module "@palbase/backend/stack" {
|
|
21
|
+
* interface Secrets { OPENAI_API_KEY: true }
|
|
22
|
+
* interface Flags { newCheckout: true }
|
|
23
|
+
* interface Buckets { avatars: true }
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* A project that has not generated the file therefore has NO valid names, and
|
|
27
|
+
* every call fails to compile until it does. That is the intended behaviour,
|
|
28
|
+
* not a rough edge: it is the ONLY shape in which the gate is not optional. A
|
|
29
|
+
* permissive `string` fallback would make the check opt-in, and an opt-in gate
|
|
30
|
+
* is the same as no gate — which is precisely the hole the retired
|
|
31
|
+
* `config/secrets.ts` push-check used to paper over.
|
|
32
|
+
*
|
|
33
|
+
* THIS REPLACED A DECLARATION, and the direction matters. `config/secrets.ts`
|
|
34
|
+
* asked the author to restate, in the repo, names the vault already held; the
|
|
35
|
+
* deploy then compared the two lists. Here the stack is simply read and the
|
|
36
|
+
* result is a type. There is no second list to drift.
|
|
37
|
+
*/
|
|
38
|
+
/** The secret names this project's vault holds. EMPTY by default; filled by the
|
|
39
|
+
* generated `palbase-stack.d.ts`. */
|
|
40
|
+
interface Secrets {
|
|
41
|
+
}
|
|
42
|
+
/** The flag keys this project's store defines. EMPTY by default; filled by the
|
|
43
|
+
* generated `palbase-stack.d.ts`. */
|
|
44
|
+
interface Flags {
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One typed bucket: which renditions the stack declared for it.
|
|
48
|
+
*
|
|
49
|
+
* `variants` is a UNION of the declared names, so asking for one the bucket does
|
|
50
|
+
* not have is a compile error rather than a 404 somebody finds in production.
|
|
51
|
+
* The default `never` means a bucket with no variants accepts no variant name at
|
|
52
|
+
* all, which is exactly right.
|
|
53
|
+
*
|
|
54
|
+
* THIS MOVED HERE FROM `db/env.ts` (2026-08-29). It lived there because
|
|
55
|
+
* `config/storage.ts` fed it through `palbase-env.d.ts`, alongside the schema's
|
|
56
|
+
* tables. Buckets do not come from the schema — they come from the STACK — so
|
|
57
|
+
* they belong in the file generated off the stack. Two `Buckets` interfaces for
|
|
58
|
+
* one concept is how `Storage.buckets.docs` and `@Upload({ bucket: "docs" })`
|
|
59
|
+
* came to disagree about whether "docs" exists.
|
|
60
|
+
*/
|
|
61
|
+
interface BucketTypes {
|
|
62
|
+
variants: string;
|
|
63
|
+
}
|
|
64
|
+
/** The buckets this project's storage carries, keyed by name. EMPTY by default;
|
|
65
|
+
* filled by the generated `palbase-stack.d.ts`. Drives BOTH `Storage.buckets.*`
|
|
66
|
+
* (through `EnvBuckets`) and `@Upload({ bucket })`. */
|
|
67
|
+
interface Buckets {
|
|
68
|
+
}
|
|
69
|
+
/** Every secret name the stack holds. */
|
|
70
|
+
type PalbaseSecretName = keyof Secrets & string;
|
|
71
|
+
/** Every flag key the stack defines. */
|
|
72
|
+
type PalbaseFlagKey = keyof Flags & string;
|
|
73
|
+
/** Every bucket the stack carries. */
|
|
74
|
+
type PalbaseBucketName = keyof Buckets & string;
|
|
75
|
+
|
|
76
|
+
export type { BucketTypes, Buckets, Flags, PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName, Secrets };
|
package/dist/stack.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=stack.js.map
|
package/docs/README.md
CHANGED
|
@@ -24,8 +24,8 @@ db/schema.ts # config-as-code Postgres schema (tables, co
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
The four folders above are the daily surface. These also exist (own docs, linked
|
|
27
|
-
below): `resources/` (
|
|
28
|
-
`seeds/` (seed data), `jobs/` (background — [background.md](./background.md)),
|
|
27
|
+
below): `resources/` (plain modules a controller imports — a client, a
|
|
28
|
+
formatter, anything shared), `seeds/` (seed data), `jobs/` (background — [background.md](./background.md)),
|
|
29
29
|
`webhooks/` + `hooks/` (events — [events.md](./events.md)), `middleware/`.
|
|
30
30
|
|
|
31
31
|
### The 7 rules (checklist)
|
|
@@ -203,9 +203,11 @@ generated client surface) changes; the verb/path do not affect it.
|
|
|
203
203
|
secrets in its environment. There is no `.env` file: nothing writes one and
|
|
204
204
|
nothing reads one, so the values live in one child process and are gone when it
|
|
205
205
|
exits.
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
a
|
|
206
|
+
- Secrets are written to the stack (`palbase secret set NAME --stdin`) and read
|
|
207
|
+
with `Secrets.get(name)`. The NAME is typed: `palbase-stack.d.ts` is generated
|
|
208
|
+
from the stack, so a secret it does not hold cannot be spelled — a compile
|
|
209
|
+
error rather than a 500. There is no `config/secrets.ts`: it asked you to
|
|
210
|
+
restate names the vault already had, and the deploy compared the two lists.
|
|
209
211
|
- `tsconfig.json` needs `"experimentalDecorators": true` (the scaffold sets it).
|
|
210
212
|
|
|
211
213
|
## Mental model
|
|
@@ -266,7 +268,6 @@ HTTP endpoints are **not** file-path routed. You author a class controller
|
|
|
266
268
|
| Schema & typed DB | [schema.md](./schema.md) |
|
|
267
269
|
| Migrations (additive vs type-change + drift-gate) | [migrations.md](./migrations.md) |
|
|
268
270
|
| Services (Cache, Queue, Storage, …) | [services.md](./services.md) |
|
|
269
|
-
| Resources (external connections) | [resources.md](./resources.md) |
|
|
270
271
|
| Errors | [errors.md](./errors.md) |
|
|
271
272
|
| Workers & Jobs | [background.md](./background.md) |
|
|
272
273
|
| Hooks & Webhooks | [events.md](./events.md) |
|
package/docs/endpoints.md
CHANGED
|
@@ -86,7 +86,7 @@ query (RFC semantics), so a QUERY route carries its whole input there.
|
|
|
86
86
|
| `@Body(schema)` | request body | `: T` (`z.infer<schema>`, same name) | requestBody |
|
|
87
87
|
| `@QueryParams(schema)` | query params | `: T` | query parameters |
|
|
88
88
|
| `@Param("id")` | one path param | `: string` | path parameter |
|
|
89
|
-
| `@Headers(schema?)` | request headers | `Record<string,string
|
|
89
|
+
| `@Headers(schema?)` | request headers (lowercase keys); with a schema, the **parsed** value — declared keys only, matched case-insensitively, and a violating request is refused 400 | `Record<string,string>`, or `z.infer<schema>` | header parameters |
|
|
90
90
|
| `@User()` | authenticated user | `: UserT` | — (from token) |
|
|
91
91
|
| `@OptionalUser()` | user, possibly anon | `: UserT \| null` | — |
|
|
92
92
|
| `@Client()` | parsed client info | `: ClientInfo` | — |
|