@palbase/backend 22.1.0 → 23.1.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 +750 -40
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +5 -5
- package/dist/{chunk-YL4C5NRY.js → chunk-HQRJDARQ.js} +2 -2
- package/dist/{chunk-74XDEF5J.js → chunk-M5MCBWJI.js} +723 -37
- package/dist/chunk-M5MCBWJI.js.map +1 -0
- package/dist/{chunk-W5ODXPY3.js → chunk-NS5V43YQ.js} +14 -1
- package/dist/chunk-NS5V43YQ.js.map +1 -0
- package/dist/{chunk-SQC5EIWY.js → chunk-OHALWEOG.js} +19 -9
- package/dist/chunk-OHALWEOG.js.map +1 -0
- package/dist/{chunk-I3ON7MYF.js → chunk-PY7YJDCT.js} +129 -18
- package/dist/chunk-PY7YJDCT.js.map +1 -0
- package/dist/{chunk-N32VDWKH.js → chunk-R3KN6RHD.js} +4 -59
- package/dist/chunk-R3KN6RHD.js.map +1 -0
- package/dist/{chunk-QMVK4X3V.js → chunk-RCLNBJCM.js} +98 -98
- package/dist/chunk-RCLNBJCM.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 +140 -16
- 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 +2 -2
- package/dist/{endpoint-BVT6jcVW.d.cts → endpoint-CVWXh6oG.d.ts} +147 -15
- package/dist/{endpoint-BVT6jcVW.d.ts → endpoint-c9h5jriX.d.cts} +147 -15
- package/dist/engine/index.cjs +750 -40
- 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 +4 -4
- package/dist/{index-BS1gW4nV.d.cts → index-BZrJXnVh.d.ts} +142 -72
- package/dist/{index-BqCiHao8.d.cts → index-By8Dle5U.d.cts} +196 -21
- package/dist/{index-vwHoS0l2.d.ts → index-CwAJ7HEe.d.ts} +196 -21
- package/dist/{index-CCZqzych.d.ts → index-CxeQSfJP.d.cts} +142 -72
- package/dist/index.cjs +388 -1101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -1134
- package/dist/index.d.ts +89 -1134
- package/dist/index.js +133 -902
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +32 -61
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +6 -2
- package/dist/openapi/index.d.ts +6 -2
- package/dist/openapi/index.js +34 -26
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-Bsuf-orT.d.ts → registry-B3niOVYp.d.ts} +108 -170
- package/dist/{registry-BWttGlaT.d.cts → registry-CqPK2Qby.d.cts} +108 -170
- 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/dist/test/index.cjs +482 -9
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +35 -3
- package/dist/test/index.d.ts +35 -3
- package/dist/test/index.js +480 -8
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +7 -6
- package/docs/llms-full.txt +7 -260
- package/docs/llms.txt +0 -2
- package/package.json +9 -8
- package/stager/return_types.js +23 -0
- package/template/package.json +1 -1
- package/dist/chunk-74XDEF5J.js.map +0 -1
- package/dist/chunk-I3ON7MYF.js.map +0 -1
- package/dist/chunk-N32VDWKH.js.map +0 -1
- package/dist/chunk-QMVK4X3V.js.map +0 -1
- package/dist/chunk-SQC5EIWY.js.map +0 -1
- package/dist/chunk-W5ODXPY3.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-HQRJDARQ.js.map} +0 -0
- /package/dist/{purchases/keys.js.map → stack.js.map} +0 -0
|
@@ -1,161 +1,12 @@
|
|
|
1
|
-
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-CVWXh6oG.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)`. */
|
|
156
|
-
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
7
|
+
type MethodDecorator$1 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
157
8
|
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
158
|
-
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
9
|
+
type ParameterDecorator$1 = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
159
10
|
/**
|
|
160
11
|
* Direct-storage upload settings for an `@Upload` route. The br-pod validates an
|
|
161
12
|
* authorize request against these (size/type), then mints a signed upload URL
|
|
@@ -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,10 +48,10 @@ 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
|
-
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
54
|
+
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator$1;
|
|
198
55
|
/**
|
|
199
56
|
* The uploaded object, injected into an `@Upload` method body by
|
|
200
57
|
* `@UploadedObject()` once storage confirms the upload. Bytes are NOT present
|
|
@@ -249,20 +106,94 @@ interface UploadedObject {
|
|
|
249
106
|
* Co-located with the {@link UploadedObject} TYPE so a single exported name
|
|
250
107
|
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
108
|
*/
|
|
252
|
-
declare function UploadedObject(): ParameterDecorator;
|
|
109
|
+
declare function UploadedObject(): ParameterDecorator$1;
|
|
110
|
+
|
|
111
|
+
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
112
|
+
* descriptor)`. */
|
|
113
|
+
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
114
|
+
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
115
|
+
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Settings for an `@Sse` route.
|
|
118
|
+
*
|
|
119
|
+
* EMPTY in v1, and deliberately so: the pipeline keys off this object's
|
|
120
|
+
* PRESENCE, not its contents (see the file header). Declaring the type now means
|
|
121
|
+
* a later setting arrives as a field on an existing marker rather than as a
|
|
122
|
+
* second marker nothing downstream reads.
|
|
123
|
+
*/
|
|
124
|
+
interface SseConfig {
|
|
125
|
+
/**
|
|
126
|
+
* The shape of ONE frame — what a single `out.write(value)` carries.
|
|
127
|
+
*
|
|
128
|
+
* REQUIRED, not optional, and that is the whole point. An `@Sse` handler
|
|
129
|
+
* returns `Promise<void>`, so the codegen-injected `recordReturn` has no type
|
|
130
|
+
* to record and nothing downstream can infer what a frame is. A route without
|
|
131
|
+
* this declares a stream whose element type is unknown, and every generated
|
|
132
|
+
* client from that contract is opaque — which is precisely the failure
|
|
133
|
+
* `x-palbase-sse` exists to prevent. Making it optional would have left that
|
|
134
|
+
* failure one forgotten field away.
|
|
135
|
+
*
|
|
136
|
+
* Measured live on a real pushed stack (2026-08-29): the contract gate refused
|
|
137
|
+
* the deploy with "2 untyped response(s) — every generated client from it is
|
|
138
|
+
* opaque", naming both routes that omitted it.
|
|
139
|
+
*/
|
|
140
|
+
frame: ZodTypeAny;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The writer injected by `@SseOut()`. Each `write` emits ONE SSE `data:` frame
|
|
144
|
+
* carrying `value` JSON-encoded.
|
|
145
|
+
*
|
|
146
|
+
* The FIRST `write` is load-bearing beyond its frame: it settles the request's
|
|
147
|
+
* database transaction. A streaming response may run for minutes, and the
|
|
148
|
+
* handler runs inside the request's transaction — holding one open for the life
|
|
149
|
+
* of a stream exhausts the connection pool, a failure invisible to a unit test
|
|
150
|
+
* that only dies under load. So the first frame is the point at which the
|
|
151
|
+
* request phase is declared over, and database access after it is refused by
|
|
152
|
+
* name rather than silently run against a settled transaction.
|
|
153
|
+
*
|
|
154
|
+
* The practical rule for a handler: do the database work BEFORE the first write.
|
|
155
|
+
*/
|
|
156
|
+
interface SseWriter {
|
|
157
|
+
write(value: unknown): void;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* `@Sse(subpath, config)` — declare a streaming route.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* @Sse("/chat", { frame: ChatFrame })
|
|
164
|
+
* async chat(@Body() b: ChatInput, @SseOut() out: SseWriter, @Signal() signal: AbortSignal) {
|
|
165
|
+
* const stream = await openai.chat.completions.create(
|
|
166
|
+
* { model: "gpt-5.6", messages: b.messages, stream: true },
|
|
167
|
+
* { signal },
|
|
168
|
+
* );
|
|
169
|
+
* for await (const chunk of stream) out.write(chunk);
|
|
170
|
+
* }
|
|
171
|
+
* // The client disconnects → `signal` aborts → the provider stops being pulled.
|
|
172
|
+
* // The signal is a plain AbortSignal, so it goes wherever the provider takes
|
|
173
|
+
* // one: `{ signal }` for the OpenAI and Anthropic SDKs, `abortSignal:` for the
|
|
174
|
+
* // Vercel AI SDK, `fetch(url, { signal })` for a raw call.
|
|
175
|
+
*/
|
|
176
|
+
declare function Sse(subpath: string | undefined, config: SseConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
177
|
+
/**
|
|
178
|
+
* `@SseOut()` — inject the frame writer (`: SseWriter`) into an `@Sse` method
|
|
179
|
+
* body. Only meaningful on an `@Sse` route.
|
|
180
|
+
*/
|
|
181
|
+
declare function SseOut(): ParameterDecorator;
|
|
253
182
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
* Throws a precise error so a typo fails at deploy, not at the first user upload.
|
|
183
|
+
* `@Signal()` — inject the request's `AbortSignal`, which enters the aborted
|
|
184
|
+
* state when the client disconnects.
|
|
257
185
|
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
186
|
+
* NOT derivable from `@Req()`: `PBRequest` carries only request-scoped data —
|
|
187
|
+
* the typed input, route/query params, headers, the authenticated user, calling
|
|
188
|
+
* client metadata, trace ids, and the declared error throwers — and no signal
|
|
189
|
+
* (endpoint.ts:358-363).
|
|
262
190
|
*
|
|
263
|
-
*
|
|
191
|
+
* Measured 2026-08-29 on Bun: an infinite producer guarded by this signal
|
|
192
|
+
* stopped four frames after the client was killed, and the handler's `finally`
|
|
193
|
+
* ran. It is the same mechanism a NestJS handler reaches through
|
|
194
|
+
* `req.on("close")`.
|
|
264
195
|
*/
|
|
265
|
-
declare function
|
|
196
|
+
declare function Signal(): ParameterDecorator;
|
|
266
197
|
|
|
267
198
|
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
199
|
* OpenAPI lower-case on their own). */
|
|
@@ -279,11 +210,18 @@ interface RouteOptions {
|
|
|
279
210
|
* openapi → codegen). The bytes go client→storage directly; the method body
|
|
280
211
|
* runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */
|
|
281
212
|
uploadConfig?: UploadConfig;
|
|
213
|
+
/** Streaming config — present ONLY on `@Sse` routes (the `@Get`/`@Post`/…
|
|
214
|
+
* decorators never set it). Its presence is what MARKS a route as a streaming
|
|
215
|
+
* route through the whole pipeline (registry → flatten → openapi → codegen),
|
|
216
|
+
* exactly as `uploadConfig` does for uploads — never a special HTTP verb. An
|
|
217
|
+
* `@Sse` route registers POST like any input-bearing route, so the verb cannot
|
|
218
|
+
* carry the distinction. See {@link SseConfig} (decorators/sse.ts). */
|
|
219
|
+
sseConfig?: SseConfig;
|
|
282
220
|
}
|
|
283
221
|
/** The kind of value a parameter decorator injects. Drives both dispatch
|
|
284
222
|
* (which request slice to inject) and codegen (which OpenAPI parameter source a
|
|
285
223
|
* schema-bearing kind maps to). */
|
|
286
|
-
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject";
|
|
224
|
+
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject" | "sseOut" | "signal";
|
|
287
225
|
/** One parameter decorator's recorded metadata. `index` is the parameter
|
|
288
226
|
* position esbuild/tsc preserve; `schema` is present for the schema-bearing
|
|
289
227
|
* kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */
|
|
@@ -335,4 +273,4 @@ declare function recordThrows(target: object, fnName: string, throws: ThrowDescr
|
|
|
335
273
|
*/
|
|
336
274
|
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
275
|
|
|
338
|
-
export { type
|
|
276
|
+
export { type HttpMethodUpper as H, type ParamMeta as P, type RouteMeta as R, type SseConfig as S, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type ParamKind as b, Signal as c, Sse as d, SseOut as e, type SseWriter as f, Upload as g, UploadedObject as h, getRoutes as i, recordThrows as r };
|
|
@@ -1,161 +1,12 @@
|
|
|
1
|
-
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-
|
|
1
|
+
import { A as AuthSpec, R as RateLimitConfig } from './endpoint-c9h5jriX.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)`. */
|
|
156
|
-
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
7
|
+
type MethodDecorator$1 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
157
8
|
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
158
|
-
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
9
|
+
type ParameterDecorator$1 = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
159
10
|
/**
|
|
160
11
|
* Direct-storage upload settings for an `@Upload` route. The br-pod validates an
|
|
161
12
|
* authorize request against these (size/type), then mints a signed upload URL
|
|
@@ -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,10 +48,10 @@ 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
|
-
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
54
|
+
declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator$1;
|
|
198
55
|
/**
|
|
199
56
|
* The uploaded object, injected into an `@Upload` method body by
|
|
200
57
|
* `@UploadedObject()` once storage confirms the upload. Bytes are NOT present
|
|
@@ -249,20 +106,94 @@ interface UploadedObject {
|
|
|
249
106
|
* Co-located with the {@link UploadedObject} TYPE so a single exported name
|
|
250
107
|
* `UploadedObject` carries BOTH the decorator value and the type annotation.
|
|
251
108
|
*/
|
|
252
|
-
declare function UploadedObject(): ParameterDecorator;
|
|
109
|
+
declare function UploadedObject(): ParameterDecorator$1;
|
|
110
|
+
|
|
111
|
+
/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,
|
|
112
|
+
* descriptor)`. */
|
|
113
|
+
type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
114
|
+
/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */
|
|
115
|
+
type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Settings for an `@Sse` route.
|
|
118
|
+
*
|
|
119
|
+
* EMPTY in v1, and deliberately so: the pipeline keys off this object's
|
|
120
|
+
* PRESENCE, not its contents (see the file header). Declaring the type now means
|
|
121
|
+
* a later setting arrives as a field on an existing marker rather than as a
|
|
122
|
+
* second marker nothing downstream reads.
|
|
123
|
+
*/
|
|
124
|
+
interface SseConfig {
|
|
125
|
+
/**
|
|
126
|
+
* The shape of ONE frame — what a single `out.write(value)` carries.
|
|
127
|
+
*
|
|
128
|
+
* REQUIRED, not optional, and that is the whole point. An `@Sse` handler
|
|
129
|
+
* returns `Promise<void>`, so the codegen-injected `recordReturn` has no type
|
|
130
|
+
* to record and nothing downstream can infer what a frame is. A route without
|
|
131
|
+
* this declares a stream whose element type is unknown, and every generated
|
|
132
|
+
* client from that contract is opaque — which is precisely the failure
|
|
133
|
+
* `x-palbase-sse` exists to prevent. Making it optional would have left that
|
|
134
|
+
* failure one forgotten field away.
|
|
135
|
+
*
|
|
136
|
+
* Measured live on a real pushed stack (2026-08-29): the contract gate refused
|
|
137
|
+
* the deploy with "2 untyped response(s) — every generated client from it is
|
|
138
|
+
* opaque", naming both routes that omitted it.
|
|
139
|
+
*/
|
|
140
|
+
frame: ZodTypeAny;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The writer injected by `@SseOut()`. Each `write` emits ONE SSE `data:` frame
|
|
144
|
+
* carrying `value` JSON-encoded.
|
|
145
|
+
*
|
|
146
|
+
* The FIRST `write` is load-bearing beyond its frame: it settles the request's
|
|
147
|
+
* database transaction. A streaming response may run for minutes, and the
|
|
148
|
+
* handler runs inside the request's transaction — holding one open for the life
|
|
149
|
+
* of a stream exhausts the connection pool, a failure invisible to a unit test
|
|
150
|
+
* that only dies under load. So the first frame is the point at which the
|
|
151
|
+
* request phase is declared over, and database access after it is refused by
|
|
152
|
+
* name rather than silently run against a settled transaction.
|
|
153
|
+
*
|
|
154
|
+
* The practical rule for a handler: do the database work BEFORE the first write.
|
|
155
|
+
*/
|
|
156
|
+
interface SseWriter {
|
|
157
|
+
write(value: unknown): void;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* `@Sse(subpath, config)` — declare a streaming route.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* @Sse("/chat", { frame: ChatFrame })
|
|
164
|
+
* async chat(@Body() b: ChatInput, @SseOut() out: SseWriter, @Signal() signal: AbortSignal) {
|
|
165
|
+
* const stream = await openai.chat.completions.create(
|
|
166
|
+
* { model: "gpt-5.6", messages: b.messages, stream: true },
|
|
167
|
+
* { signal },
|
|
168
|
+
* );
|
|
169
|
+
* for await (const chunk of stream) out.write(chunk);
|
|
170
|
+
* }
|
|
171
|
+
* // The client disconnects → `signal` aborts → the provider stops being pulled.
|
|
172
|
+
* // The signal is a plain AbortSignal, so it goes wherever the provider takes
|
|
173
|
+
* // one: `{ signal }` for the OpenAI and Anthropic SDKs, `abortSignal:` for the
|
|
174
|
+
* // Vercel AI SDK, `fetch(url, { signal })` for a raw call.
|
|
175
|
+
*/
|
|
176
|
+
declare function Sse(subpath: string | undefined, config: SseConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator;
|
|
177
|
+
/**
|
|
178
|
+
* `@SseOut()` — inject the frame writer (`: SseWriter`) into an `@Sse` method
|
|
179
|
+
* body. Only meaningful on an `@Sse` route.
|
|
180
|
+
*/
|
|
181
|
+
declare function SseOut(): ParameterDecorator;
|
|
253
182
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
* Throws a precise error so a typo fails at deploy, not at the first user upload.
|
|
183
|
+
* `@Signal()` — inject the request's `AbortSignal`, which enters the aborted
|
|
184
|
+
* state when the client disconnects.
|
|
257
185
|
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
186
|
+
* NOT derivable from `@Req()`: `PBRequest` carries only request-scoped data —
|
|
187
|
+
* the typed input, route/query params, headers, the authenticated user, calling
|
|
188
|
+
* client metadata, trace ids, and the declared error throwers — and no signal
|
|
189
|
+
* (endpoint.ts:358-363).
|
|
262
190
|
*
|
|
263
|
-
*
|
|
191
|
+
* Measured 2026-08-29 on Bun: an infinite producer guarded by this signal
|
|
192
|
+
* stopped four frames after the client was killed, and the handler's `finally`
|
|
193
|
+
* ran. It is the same mechanism a NestJS handler reaches through
|
|
194
|
+
* `req.on("close")`.
|
|
264
195
|
*/
|
|
265
|
-
declare function
|
|
196
|
+
declare function Signal(): ParameterDecorator;
|
|
266
197
|
|
|
267
198
|
/** The HTTP verbs a route may declare, upper-cased (the runtime router +
|
|
268
199
|
* OpenAPI lower-case on their own). */
|
|
@@ -279,11 +210,18 @@ interface RouteOptions {
|
|
|
279
210
|
* openapi → codegen). The bytes go client→storage directly; the method body
|
|
280
211
|
* runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */
|
|
281
212
|
uploadConfig?: UploadConfig;
|
|
213
|
+
/** Streaming config — present ONLY on `@Sse` routes (the `@Get`/`@Post`/…
|
|
214
|
+
* decorators never set it). Its presence is what MARKS a route as a streaming
|
|
215
|
+
* route through the whole pipeline (registry → flatten → openapi → codegen),
|
|
216
|
+
* exactly as `uploadConfig` does for uploads — never a special HTTP verb. An
|
|
217
|
+
* `@Sse` route registers POST like any input-bearing route, so the verb cannot
|
|
218
|
+
* carry the distinction. See {@link SseConfig} (decorators/sse.ts). */
|
|
219
|
+
sseConfig?: SseConfig;
|
|
282
220
|
}
|
|
283
221
|
/** The kind of value a parameter decorator injects. Drives both dispatch
|
|
284
222
|
* (which request slice to inject) and codegen (which OpenAPI parameter source a
|
|
285
223
|
* schema-bearing kind maps to). */
|
|
286
|
-
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject";
|
|
224
|
+
type ParamKind = "body" | "query" | "param" | "headers" | "user" | "optionalUser" | "client" | "requestId" | "traceId" | "req" | "uploadedObject" | "sseOut" | "signal";
|
|
287
225
|
/** One parameter decorator's recorded metadata. `index` is the parameter
|
|
288
226
|
* position esbuild/tsc preserve; `schema` is present for the schema-bearing
|
|
289
227
|
* kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */
|
|
@@ -335,4 +273,4 @@ declare function recordThrows(target: object, fnName: string, throws: ThrowDescr
|
|
|
335
273
|
*/
|
|
336
274
|
declare function getRoutes(ctor: object): RouteMeta[];
|
|
337
275
|
|
|
338
|
-
export { type
|
|
276
|
+
export { type HttpMethodUpper as H, type ParamMeta as P, type RouteMeta as R, type SseConfig as S, type ThrowDescriptor as T, type UploadConfig as U, type RouteOptions as a, type ParamKind as b, Signal as c, Sse as d, SseOut as e, type SseWriter as f, Upload as g, UploadedObject as h, getRoutes as i, recordThrows as r };
|