@palbase/backend 17.4.0 → 18.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.
- package/dist/bin/palbase-backend.cjs +1848 -0
- package/dist/bin/palbase-backend.cjs.map +1 -0
- package/dist/bin/palbase-backend.d.cts +1 -0
- package/dist/bin/palbase-backend.d.ts +1 -0
- package/dist/bin/palbase-backend.js +168 -0
- package/dist/bin/palbase-backend.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-N32VDWKH.js +172 -0
- package/dist/chunk-N32VDWKH.js.map +1 -0
- package/dist/chunk-POYAFBLF.js +189 -0
- package/dist/chunk-POYAFBLF.js.map +1 -0
- package/dist/chunk-QMVK4X3V.js +200 -0
- package/dist/chunk-QMVK4X3V.js.map +1 -0
- package/dist/chunk-SSGAMC26.js +342 -0
- package/dist/chunk-SSGAMC26.js.map +1 -0
- package/dist/chunk-VYH4U7ZQ.js +1138 -0
- package/dist/chunk-VYH4U7ZQ.js.map +1 -0
- package/dist/{chunk-AAN642N5.js → chunk-W5ODXPY3.js} +2 -336
- package/dist/chunk-W5ODXPY3.js.map +1 -0
- package/dist/chunk-YL4C5NRY.js +90 -0
- package/dist/chunk-YL4C5NRY.js.map +1 -0
- package/dist/db/env.cjs.map +1 -1
- package/dist/db/env.d.cts +21 -1
- package/dist/db/env.d.ts +21 -1
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +2 -1
- package/dist/db/index.d.ts +2 -1
- package/dist/db/index.js +9 -6
- package/dist/{index-VLrU7rSW.d.ts → endpoint-B0LpZixz.d.cts} +124 -685
- package/dist/{index-BA_oFAz9.d.cts → endpoint-B0LpZixz.d.ts} +124 -685
- package/dist/engine/index.cjs +1797 -0
- package/dist/engine/index.cjs.map +1 -0
- package/dist/engine/index.d.cts +7 -0
- package/dist/engine/index.d.ts +7 -0
- package/dist/engine/index.js +43 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/index-B46CGNvx.d.cts +839 -0
- package/dist/index-BGSCWlUa.d.cts +674 -0
- package/dist/index-DZDUMth5.d.ts +839 -0
- package/dist/index-g-EzitI-.d.ts +674 -0
- package/dist/index.cjs +1031 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +290 -532
- package/dist/index.d.ts +290 -532
- package/dist/index.js +999 -509
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +6464 -0
- package/dist/openapi/index.cjs.map +1 -0
- package/dist/openapi/index.d.cts +170 -0
- package/dist/openapi/index.d.ts +170 -0
- package/dist/openapi/index.js +6248 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/registry-3BLYv4si.d.ts +338 -0
- package/dist/registry-Cw0YEYCg.d.cts +338 -0
- package/dist/test/index.js +2 -0
- package/dist/test/index.js.map +1 -1
- package/docs/database.md +16 -3
- package/docs/llms-full.txt +16 -3
- package/package.json +43 -13
- package/stager/package.json +4 -0
- package/stager/return_types.js +338 -0
- package/stager/stage.js +78 -0
- package/stager/throw_analysis.js +726 -0
- package/template/AGENTS.md +261 -0
- package/template/config/secrets.ts +24 -0
- package/template/controllers/health.controller.ts +30 -0
- package/template/db/schema.ts +35 -0
- package/template/package.json +18 -0
- package/template/tsconfig.json +30 -0
- package/LICENSE +0 -21
- package/dist/chunk-AAN642N5.js.map +0 -1
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-B0LpZixz.js';
|
|
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;
|
|
153
|
+
|
|
154
|
+
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
155
|
+
* descriptor)`. */
|
|
156
|
+
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
157
|
+
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
158
|
+
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
159
|
+
/**
|
|
160
|
+
* Direct-storage upload settings for an `@Upload` route. The br-pod validates an
|
|
161
|
+
* authorize request against these (size/type), then mints a signed upload URL
|
|
162
|
+
* that PINS the limits so storage itself rejects an over-limit / wrong-type PUT
|
|
163
|
+
* — the client cannot exceed what it declared.
|
|
164
|
+
*/
|
|
165
|
+
interface UploadConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.
|
|
168
|
+
*
|
|
169
|
+
* The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
|
|
170
|
+
* `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
|
|
171
|
+
* actual PUT (the only guard a client cannot skip), so `@Upload` deliberately
|
|
172
|
+
* does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would
|
|
173
|
+
* let a route declare a tighter limit than its bucket that storage would not
|
|
174
|
+
* enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
|
|
175
|
+
* bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
|
|
176
|
+
*/
|
|
177
|
+
bucket: string;
|
|
178
|
+
/**
|
|
179
|
+
* SERVER-side object key template. The client NEVER chooses the path. Tokens:
|
|
180
|
+
* `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
|
|
181
|
+
* `{filename}` (the client-declared filename, sanitized). e.g.
|
|
182
|
+
* `"{userId}/{uploadId}-{filename}"`.
|
|
183
|
+
*/
|
|
184
|
+
pathTemplate: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* `@Upload(subpath, config)` — declare a direct-storage upload route. The method
|
|
188
|
+
* body is the completion handler; `config.uploadConfig` drives the authorize
|
|
189
|
+
* guard + signed-URL pinning.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
|
|
193
|
+
* async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
|
|
194
|
+
* // The size limit + MIME allowlist come from the "docs" bucket in
|
|
195
|
+
* // config/storage.ts — storage enforces them at the PUT.
|
|
196
|
+
*/
|
|
197
|
+
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
198
|
+
/**
|
|
199
|
+
* The uploaded object, injected into an `@Upload` method body by
|
|
200
|
+
* `@UploadedObject()` once storage confirms the upload. Bytes are NOT present
|
|
201
|
+
* (they went straight to storage) — this is the metadata the completion handler
|
|
202
|
+
* persists.
|
|
203
|
+
*/
|
|
204
|
+
interface UploadedObject {
|
|
205
|
+
/** Server-minted id correlating authorize ↔ completion (idempotency key). */
|
|
206
|
+
uploadId: string;
|
|
207
|
+
/** Final object key in the bucket (rendered from `pathTemplate`). */
|
|
208
|
+
path: string;
|
|
209
|
+
/** Bucket the object landed in. */
|
|
210
|
+
bucket: string;
|
|
211
|
+
/** Object size in bytes, as reported by storage. */
|
|
212
|
+
size: number;
|
|
213
|
+
/** Object MIME type, as reported by storage — detected from the BYTES, not
|
|
214
|
+
* from the filename or from what the client claimed. */
|
|
215
|
+
contentType: string;
|
|
216
|
+
/** SHA-256 of the stored bytes, hex. The same value the object's ETag is
|
|
217
|
+
* derived from, so a client that has it can tell whether it already holds
|
|
218
|
+
* these bytes. */
|
|
219
|
+
checksum: string;
|
|
220
|
+
/** Pixel width, for an image. Absent otherwise — a PDF has no dimensions,
|
|
221
|
+
* and reporting 0 would be a measurement rather than an absence. */
|
|
222
|
+
width?: number;
|
|
223
|
+
/** Pixel height, for an image. */
|
|
224
|
+
height?: number;
|
|
225
|
+
/**
|
|
226
|
+
* A ~25-byte placeholder the client paints INSTANTLY while the real image
|
|
227
|
+
* downloads — the thing that replaces a grey skeleton with something already
|
|
228
|
+
* shaped like the picture. Absent for non-images.
|
|
229
|
+
*
|
|
230
|
+
* Persist it beside the object's path: it costs a column and saves a request
|
|
231
|
+
* per picture on every gallery render.
|
|
232
|
+
*/
|
|
233
|
+
thumbhash?: string;
|
|
234
|
+
/**
|
|
235
|
+
* The renditions the bucket declared, by name, as URLs ready to use.
|
|
236
|
+
*
|
|
237
|
+
* Present on the completion input so the handler that stores the row has
|
|
238
|
+
* everything it needs in one place — asking for them afterwards would be a
|
|
239
|
+
* second call per upload, and per picture on every read.
|
|
240
|
+
*/
|
|
241
|
+
variants: Record<string, string>;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* `@UploadedObject()` — inject the uploaded object (`: UploadedObject`) into an
|
|
245
|
+
* `@Upload` method body (the completion input). Only valid on an `@Upload`
|
|
246
|
+
* route; the bytes are NOT present (they went directly to storage), this is the
|
|
247
|
+
* confirmed object's metadata.
|
|
248
|
+
*
|
|
249
|
+
* Co-located with the {@link UploadedObject} TYPE so a single exported name
|
|
250
|
+
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
|
+
*/
|
|
252
|
+
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
|
+
|
|
267
|
+
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
|
+
* OpenAPI lower-case on their own). */
|
|
269
|
+
type HttpMethodUpper = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "QUERY";
|
|
270
|
+
/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */
|
|
271
|
+
interface RouteOptions {
|
|
272
|
+
/** OVERRIDES the controller-level default auth for this one route. */
|
|
273
|
+
auth?: AuthSpec;
|
|
274
|
+
/** Per-route rate limit. */
|
|
275
|
+
rateLimit?: RateLimitConfig;
|
|
276
|
+
/** Direct-storage upload config — present ONLY on `@Upload` routes (the
|
|
277
|
+
* `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a
|
|
278
|
+
* route as an upload route through the whole pipeline (registry → flatten →
|
|
279
|
+
* openapi → codegen). The bytes go client→storage directly; the method body
|
|
280
|
+
* runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */
|
|
281
|
+
uploadConfig?: UploadConfig;
|
|
282
|
+
}
|
|
283
|
+
/** The kind of value a parameter decorator injects. Drives both dispatch
|
|
284
|
+
* (which request slice to inject) and codegen (which OpenAPI parameter source a
|
|
285
|
+
* schema-bearing kind maps to). */
|
|
286
|
+
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject";
|
|
287
|
+
/** One parameter decorator's recorded metadata. `index` is the parameter
|
|
288
|
+
* position esbuild/tsc preserve; `schema` is present for the schema-bearing
|
|
289
|
+
* kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */
|
|
290
|
+
interface ParamMeta {
|
|
291
|
+
index: number;
|
|
292
|
+
kind: ParamKind;
|
|
293
|
+
/** Zod schema for `body`/`query`/`headers` (validation + codegen source). */
|
|
294
|
+
schema?: ZodTypeAny;
|
|
295
|
+
/** Path-param name for `@Param("id")`. */
|
|
296
|
+
name?: string;
|
|
297
|
+
}
|
|
298
|
+
/** One inferred throw site: the error CLASS name (e.g. "TodoLocked") and its
|
|
299
|
+
* wire code (e.g. "todo_locked"). `status`, `hasData`, and the data JSON schema
|
|
300
|
+
* are NOT carried here — they resolve from the error registry by `code` at
|
|
301
|
+
* extract/openapi time (single source of truth). */
|
|
302
|
+
interface ThrowDescriptor {
|
|
303
|
+
name: string;
|
|
304
|
+
code: string;
|
|
305
|
+
}
|
|
306
|
+
/** One route's recorded metadata: the verb + subpath + method name + options,
|
|
307
|
+
* the ordered parameter metas, and the resolved return schema (injected by the
|
|
308
|
+
* codegen step — see `returnSchema`). */
|
|
309
|
+
interface RouteMeta {
|
|
310
|
+
method: HttpMethodUpper;
|
|
311
|
+
subpath: string;
|
|
312
|
+
fnName: string;
|
|
313
|
+
options: RouteOptions;
|
|
314
|
+
params: ParamMeta[];
|
|
315
|
+
/** Response schema for the route, if any. Derived from the method's RETURN
|
|
316
|
+
* TYPE by codegen and written here via `recordReturn` (a generated top-level
|
|
317
|
+
* IIFE injected per controller), not by an author-written decorator. */
|
|
318
|
+
returnSchema?: ZodTypeAny;
|
|
319
|
+
/** Error classes this route can throw, if inferred. Derived from the method
|
|
320
|
+
* body + service call graph by the deploy stager's throw analysis and written
|
|
321
|
+
* here via `recordThrows` (a generated top-level IIFE injected per controller,
|
|
322
|
+
* the `recordReturn` twin), not by an author-written decorator. */
|
|
323
|
+
throws?: ThrowDescriptor[];
|
|
324
|
+
}
|
|
325
|
+
/** Attach the inferred throw descriptors to the route for `fnName` (called by
|
|
326
|
+
* the stager-injected IIFE that carries the throw analysis result — the
|
|
327
|
+
* `recordReturn` twin). If the route does not exist yet, the descriptors are
|
|
328
|
+
* buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the
|
|
329
|
+
* method decorator runs. */
|
|
330
|
+
declare function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): void;
|
|
331
|
+
/** Read the route metadata for a controller class (the deploy/dispatch entry
|
|
332
|
+
* point). Applies any buffered return schemas + throw descriptors (for the
|
|
333
|
+
* recordReturn/recordThrows-runs-before orderings) and returns a defensive copy
|
|
334
|
+
* so callers cannot mutate the registry.
|
|
335
|
+
*/
|
|
336
|
+
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
|
+
|
|
338
|
+
export { type BucketDef as B, type HttpMethodUpper as H, type ImageVariant as I, type ParamMeta as P, type RouteMeta as R, STORAGE_CONFIG_KIND as S, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type BucketOptions as b, type ParamKind as c, type StorageConfig as d, type StorageInput as e, Upload as f, UploadedObject as g, bucket as h, defineStorage as i, getRoutes as j, parseFileSizeLimit as p, recordThrows as r, validateUploadAgainstStorage as v };
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-B0LpZixz.cjs';
|
|
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;
|
|
153
|
+
|
|
154
|
+
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
155
|
+
* descriptor)`. */
|
|
156
|
+
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
157
|
+
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
158
|
+
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
159
|
+
/**
|
|
160
|
+
* Direct-storage upload settings for an `@Upload` route. The br-pod validates an
|
|
161
|
+
* authorize request against these (size/type), then mints a signed upload URL
|
|
162
|
+
* that PINS the limits so storage itself rejects an over-limit / wrong-type PUT
|
|
163
|
+
* — the client cannot exceed what it declared.
|
|
164
|
+
*/
|
|
165
|
+
interface UploadConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.
|
|
168
|
+
*
|
|
169
|
+
* The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
|
|
170
|
+
* `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
|
|
171
|
+
* actual PUT (the only guard a client cannot skip), so `@Upload` deliberately
|
|
172
|
+
* does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would
|
|
173
|
+
* let a route declare a tighter limit than its bucket that storage would not
|
|
174
|
+
* enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
|
|
175
|
+
* bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
|
|
176
|
+
*/
|
|
177
|
+
bucket: string;
|
|
178
|
+
/**
|
|
179
|
+
* SERVER-side object key template. The client NEVER chooses the path. Tokens:
|
|
180
|
+
* `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
|
|
181
|
+
* `{filename}` (the client-declared filename, sanitized). e.g.
|
|
182
|
+
* `"{userId}/{uploadId}-{filename}"`.
|
|
183
|
+
*/
|
|
184
|
+
pathTemplate: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* `@Upload(subpath, config)` — declare a direct-storage upload route. The method
|
|
188
|
+
* body is the completion handler; `config.uploadConfig` drives the authorize
|
|
189
|
+
* guard + signed-URL pinning.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
|
|
193
|
+
* async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
|
|
194
|
+
* // The size limit + MIME allowlist come from the "docs" bucket in
|
|
195
|
+
* // config/storage.ts — storage enforces them at the PUT.
|
|
196
|
+
*/
|
|
197
|
+
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
198
|
+
/**
|
|
199
|
+
* The uploaded object, injected into an `@Upload` method body by
|
|
200
|
+
* `@UploadedObject()` once storage confirms the upload. Bytes are NOT present
|
|
201
|
+
* (they went straight to storage) — this is the metadata the completion handler
|
|
202
|
+
* persists.
|
|
203
|
+
*/
|
|
204
|
+
interface UploadedObject {
|
|
205
|
+
/** Server-minted id correlating authorize ↔ completion (idempotency key). */
|
|
206
|
+
uploadId: string;
|
|
207
|
+
/** Final object key in the bucket (rendered from `pathTemplate`). */
|
|
208
|
+
path: string;
|
|
209
|
+
/** Bucket the object landed in. */
|
|
210
|
+
bucket: string;
|
|
211
|
+
/** Object size in bytes, as reported by storage. */
|
|
212
|
+
size: number;
|
|
213
|
+
/** Object MIME type, as reported by storage — detected from the BYTES, not
|
|
214
|
+
* from the filename or from what the client claimed. */
|
|
215
|
+
contentType: string;
|
|
216
|
+
/** SHA-256 of the stored bytes, hex. The same value the object's ETag is
|
|
217
|
+
* derived from, so a client that has it can tell whether it already holds
|
|
218
|
+
* these bytes. */
|
|
219
|
+
checksum: string;
|
|
220
|
+
/** Pixel width, for an image. Absent otherwise — a PDF has no dimensions,
|
|
221
|
+
* and reporting 0 would be a measurement rather than an absence. */
|
|
222
|
+
width?: number;
|
|
223
|
+
/** Pixel height, for an image. */
|
|
224
|
+
height?: number;
|
|
225
|
+
/**
|
|
226
|
+
* A ~25-byte placeholder the client paints INSTANTLY while the real image
|
|
227
|
+
* downloads — the thing that replaces a grey skeleton with something already
|
|
228
|
+
* shaped like the picture. Absent for non-images.
|
|
229
|
+
*
|
|
230
|
+
* Persist it beside the object's path: it costs a column and saves a request
|
|
231
|
+
* per picture on every gallery render.
|
|
232
|
+
*/
|
|
233
|
+
thumbhash?: string;
|
|
234
|
+
/**
|
|
235
|
+
* The renditions the bucket declared, by name, as URLs ready to use.
|
|
236
|
+
*
|
|
237
|
+
* Present on the completion input so the handler that stores the row has
|
|
238
|
+
* everything it needs in one place — asking for them afterwards would be a
|
|
239
|
+
* second call per upload, and per picture on every read.
|
|
240
|
+
*/
|
|
241
|
+
variants: Record<string, string>;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* `@UploadedObject()` — inject the uploaded object (`: UploadedObject`) into an
|
|
245
|
+
* `@Upload` method body (the completion input). Only valid on an `@Upload`
|
|
246
|
+
* route; the bytes are NOT present (they went directly to storage), this is the
|
|
247
|
+
* confirmed object's metadata.
|
|
248
|
+
*
|
|
249
|
+
* Co-located with the {@link UploadedObject} TYPE so a single exported name
|
|
250
|
+
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
|
+
*/
|
|
252
|
+
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
|
+
|
|
267
|
+
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
|
+
* OpenAPI lower-case on their own). */
|
|
269
|
+
type HttpMethodUpper = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "QUERY";
|
|
270
|
+
/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */
|
|
271
|
+
interface RouteOptions {
|
|
272
|
+
/** OVERRIDES the controller-level default auth for this one route. */
|
|
273
|
+
auth?: AuthSpec;
|
|
274
|
+
/** Per-route rate limit. */
|
|
275
|
+
rateLimit?: RateLimitConfig;
|
|
276
|
+
/** Direct-storage upload config — present ONLY on `@Upload` routes (the
|
|
277
|
+
* `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a
|
|
278
|
+
* route as an upload route through the whole pipeline (registry → flatten →
|
|
279
|
+
* openapi → codegen). The bytes go client→storage directly; the method body
|
|
280
|
+
* runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */
|
|
281
|
+
uploadConfig?: UploadConfig;
|
|
282
|
+
}
|
|
283
|
+
/** The kind of value a parameter decorator injects. Drives both dispatch
|
|
284
|
+
* (which request slice to inject) and codegen (which OpenAPI parameter source a
|
|
285
|
+
* schema-bearing kind maps to). */
|
|
286
|
+
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject";
|
|
287
|
+
/** One parameter decorator's recorded metadata. `index` is the parameter
|
|
288
|
+
* position esbuild/tsc preserve; `schema` is present for the schema-bearing
|
|
289
|
+
* kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */
|
|
290
|
+
interface ParamMeta {
|
|
291
|
+
index: number;
|
|
292
|
+
kind: ParamKind;
|
|
293
|
+
/** Zod schema for `body`/`query`/`headers` (validation + codegen source). */
|
|
294
|
+
schema?: ZodTypeAny;
|
|
295
|
+
/** Path-param name for `@Param("id")`. */
|
|
296
|
+
name?: string;
|
|
297
|
+
}
|
|
298
|
+
/** One inferred throw site: the error CLASS name (e.g. "TodoLocked") and its
|
|
299
|
+
* wire code (e.g. "todo_locked"). `status`, `hasData`, and the data JSON schema
|
|
300
|
+
* are NOT carried here — they resolve from the error registry by `code` at
|
|
301
|
+
* extract/openapi time (single source of truth). */
|
|
302
|
+
interface ThrowDescriptor {
|
|
303
|
+
name: string;
|
|
304
|
+
code: string;
|
|
305
|
+
}
|
|
306
|
+
/** One route's recorded metadata: the verb + subpath + method name + options,
|
|
307
|
+
* the ordered parameter metas, and the resolved return schema (injected by the
|
|
308
|
+
* codegen step — see `returnSchema`). */
|
|
309
|
+
interface RouteMeta {
|
|
310
|
+
method: HttpMethodUpper;
|
|
311
|
+
subpath: string;
|
|
312
|
+
fnName: string;
|
|
313
|
+
options: RouteOptions;
|
|
314
|
+
params: ParamMeta[];
|
|
315
|
+
/** Response schema for the route, if any. Derived from the method's RETURN
|
|
316
|
+
* TYPE by codegen and written here via `recordReturn` (a generated top-level
|
|
317
|
+
* IIFE injected per controller), not by an author-written decorator. */
|
|
318
|
+
returnSchema?: ZodTypeAny;
|
|
319
|
+
/** Error classes this route can throw, if inferred. Derived from the method
|
|
320
|
+
* body + service call graph by the deploy stager's throw analysis and written
|
|
321
|
+
* here via `recordThrows` (a generated top-level IIFE injected per controller,
|
|
322
|
+
* the `recordReturn` twin), not by an author-written decorator. */
|
|
323
|
+
throws?: ThrowDescriptor[];
|
|
324
|
+
}
|
|
325
|
+
/** Attach the inferred throw descriptors to the route for `fnName` (called by
|
|
326
|
+
* the stager-injected IIFE that carries the throw analysis result — the
|
|
327
|
+
* `recordReturn` twin). If the route does not exist yet, the descriptors are
|
|
328
|
+
* buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the
|
|
329
|
+
* method decorator runs. */
|
|
330
|
+
declare function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): void;
|
|
331
|
+
/** Read the route metadata for a controller class (the deploy/dispatch entry
|
|
332
|
+
* point). Applies any buffered return schemas + throw descriptors (for the
|
|
333
|
+
* recordReturn/recordThrows-runs-before orderings) and returns a defensive copy
|
|
334
|
+
* so callers cannot mutate the registry.
|
|
335
|
+
*/
|
|
336
|
+
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
|
+
|
|
338
|
+
export { type BucketDef as B, type HttpMethodUpper as H, type ImageVariant as I, type ParamMeta as P, type RouteMeta as R, STORAGE_CONFIG_KIND as S, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type BucketOptions as b, type ParamKind as c, type StorageConfig as d, type StorageInput as e, Upload as f, UploadedObject as g, bucket as h, defineStorage as i, getRoutes as j, parseFileSizeLimit as p, recordThrows as r, validateUploadAgainstStorage as v };
|