@defjs/core 0.3.2 → 0.4.0-beta.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/LICENSE +1 -1
- package/README.md +122 -2
- package/index.d.ts +1593 -189
- package/index.js +5140 -846
- package/index.min.js +2 -1
- package/package.json +13 -12
package/index.d.ts
CHANGED
|
@@ -1,194 +1,1598 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
//#region src/internal/http_request.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* How the HTTP response body should be parsed before struct validation.
|
|
4
|
+
* Defaults to `'json'` when an output shape is declared.
|
|
5
|
+
*/
|
|
6
|
+
type HttpResponseType = 'arraybuffer' | 'blob' | 'json' | 'text';
|
|
7
|
+
/**
|
|
8
|
+
* Progress snapshot for upload or download callbacks.
|
|
9
|
+
* Mirrors the familiar `ProgressEvent` shape (`loaded` / `total` / `lengthComputable`).
|
|
10
|
+
*/
|
|
11
|
+
interface HttpProgressEvent {
|
|
12
|
+
readonly lengthComputable: boolean;
|
|
13
|
+
readonly loaded: number;
|
|
14
|
+
readonly total: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Callback invoked as request bytes are uploaded or response bytes are downloaded.
|
|
18
|
+
*/
|
|
19
|
+
type HttpProgressFn = (event: HttpProgressEvent) => Promise<void> | void;
|
|
20
|
+
/**
|
|
21
|
+
* Normalized outgoing HTTP request used by handlers, interceptors, and `fetchHandler`.
|
|
22
|
+
*
|
|
23
|
+
* After `struct.json(...)` (or another body codec) runs during command build, `body` is
|
|
24
|
+
* already the wire value — for JSON that means a **JSON text string**. Sign HMAC / digests
|
|
25
|
+
* against that string (or other final bytes), not the original Struct input object.
|
|
26
|
+
*/
|
|
27
|
+
interface HttpRequest {
|
|
28
|
+
abort?: AbortSignal;
|
|
29
|
+
baseEndpoint?: string;
|
|
30
|
+
body?: Blob | ArrayBuffer | FormData | URLSearchParams | ReadableStream<Uint8Array> | object | string | number | boolean | null;
|
|
31
|
+
bodyContentType?: string | null;
|
|
32
|
+
/** @internal Tracks which body value produced bodyContentType so interceptors cannot leave stale metadata behind. */
|
|
33
|
+
bodyContentTypeSource?: unknown;
|
|
34
|
+
downloadProgress?: HttpProgressFn;
|
|
35
|
+
endpoint: string;
|
|
36
|
+
headers?: Headers;
|
|
37
|
+
method: string;
|
|
38
|
+
/** Static, low-cardinality endpoint identity for telemetry and diagnostics. */
|
|
39
|
+
operation?: string;
|
|
40
|
+
queryParams?: URLSearchParams;
|
|
41
|
+
queryString?: string;
|
|
42
|
+
responseType?: HttpResponseType;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
uploadProgress?: HttpProgressFn;
|
|
45
|
+
withCredentials?: boolean;
|
|
46
|
+
xsrf?: {
|
|
47
|
+
cookieName: string;
|
|
48
|
+
headerName: string;
|
|
49
|
+
tokenProvider?: (context: {
|
|
50
|
+
request: HttpRequest;
|
|
51
|
+
}) => string | null | undefined;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/internal/http_response.d.ts
|
|
56
|
+
declare const HTTP_RESPONSE: unique symbol;
|
|
57
|
+
/**
|
|
58
|
+
* Parsed HTTP response wrapper returned by handlers and `executeHttpCommand`.
|
|
59
|
+
* `ok` is true for status codes in the 2xx range; `error` may hold transport or parse failures.
|
|
60
|
+
*/
|
|
61
|
+
type HttpResponse<R> = {
|
|
62
|
+
readonly [HTTP_RESPONSE]: true;
|
|
63
|
+
readonly url: string;
|
|
64
|
+
readonly status: number;
|
|
65
|
+
readonly statusText: string;
|
|
66
|
+
readonly headers: Headers;
|
|
67
|
+
readonly body: R | null;
|
|
68
|
+
readonly error?: unknown;
|
|
69
|
+
readonly ok: boolean;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Fields accepted by `makeResponse` when building a synthetic `HttpResponse` (for example in interceptors).
|
|
73
|
+
*/
|
|
74
|
+
type MakeResponseOptions<R> = {
|
|
75
|
+
status?: number;
|
|
76
|
+
statusText?: string;
|
|
77
|
+
url?: string;
|
|
78
|
+
headers?: Headers;
|
|
79
|
+
body?: R | null;
|
|
80
|
+
error?: unknown;
|
|
81
|
+
request?: HttpRequest;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Build an `HttpResponse` value without performing a network call.
|
|
85
|
+
* Useful in interceptors that short-circuit `next`, and in tests.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Status, headers, body, optional request to copy headers/url from, and optional error; defaults yield status `0`.
|
|
88
|
+
* @returns An `HttpResponse` with `ok` derived from the status code.
|
|
89
|
+
*/
|
|
90
|
+
export declare function makeResponse<R>(options?: MakeResponseOptions<R>): HttpResponse<R>;
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/struct/errors.d.ts
|
|
93
|
+
/**
|
|
94
|
+
* Optional callback that rewrites a `StructIssue` message before it is stored.
|
|
95
|
+
*
|
|
96
|
+
* Return a string to replace the default message, or `undefined` to keep it.
|
|
97
|
+
*
|
|
98
|
+
* @param issue - Issue about to be recorded.
|
|
99
|
+
* @returns Replacement message, or `undefined` to keep the default.
|
|
100
|
+
*/
|
|
101
|
+
type ErrorMap = (issue: StructIssue) => string | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Aggregate of one or more `StructIssue`s from a failed parse.
|
|
104
|
+
*
|
|
105
|
+
* Use `format()`, `flatten()`, or `prettify()` to present issues to callers.
|
|
106
|
+
*/
|
|
107
|
+
export declare class StructError extends Error {
|
|
108
|
+
/** Issues collected for this failure, in encounter order. */
|
|
109
|
+
readonly issues: StructIssue[];
|
|
110
|
+
/**
|
|
111
|
+
* @param issues - Non-empty list of parse issues (empty lists still produce a generic message).
|
|
112
|
+
*/
|
|
113
|
+
constructor(issues: StructIssue[]);
|
|
114
|
+
/**
|
|
115
|
+
* Build a nested error tree keyed by path segments.
|
|
116
|
+
*
|
|
117
|
+
* @returns A `FormattedStructError` with `_errors` arrays at each node.
|
|
118
|
+
*/
|
|
119
|
+
format(): FormattedStructError;
|
|
120
|
+
/**
|
|
121
|
+
* Split issues into root `formErrors` and first-segment `fieldErrors`.
|
|
122
|
+
*
|
|
123
|
+
* @returns Flat bags suitable for form libraries.
|
|
124
|
+
*/
|
|
125
|
+
flatten(): FlattenedStructError;
|
|
126
|
+
/**
|
|
127
|
+
* Render a multi-line, human-readable summary of all issues.
|
|
128
|
+
*
|
|
129
|
+
* @returns One `× path: message` line per issue.
|
|
130
|
+
*/
|
|
131
|
+
prettify(): string;
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/struct/types.d.ts
|
|
135
|
+
type Path = Array<number | string>;
|
|
136
|
+
/**
|
|
137
|
+
* Error-first parse tuple from `struct.parse`.
|
|
138
|
+
*
|
|
139
|
+
* On success the error is `null` and `value` is the parsed output. On failure
|
|
140
|
+
* the error is a `StructError` and `value` is always `undefined`.
|
|
141
|
+
*/
|
|
142
|
+
type ParseResult<O> = [error: null, value: O] | [error: StructError, value: undefined];
|
|
143
|
+
type LiteralValue = boolean | null | number | string;
|
|
144
|
+
interface StructTypes<Input = unknown, Output = unknown, OptionalOut extends boolean = false> {
|
|
145
|
+
input: Input;
|
|
146
|
+
optionalOut: OptionalOut extends true ? true : undefined;
|
|
147
|
+
output: Output;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Minimal structural brand carried by every struct instance.
|
|
151
|
+
*
|
|
152
|
+
* `_struct` holds input/output phantom types used by `Infer` and `StructInput`.
|
|
153
|
+
*/
|
|
154
|
+
interface StructLike<I = unknown, O = unknown, OO extends boolean = boolean> {
|
|
155
|
+
readonly _struct: StructTypes<I, O, OO>;
|
|
156
|
+
}
|
|
157
|
+
type OptionalOutputStruct = {
|
|
158
|
+
readonly _struct: {
|
|
159
|
+
readonly optionalOut: true;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* A single validation failure produced while parsing a struct.
|
|
164
|
+
*/
|
|
165
|
+
interface StructIssue {
|
|
166
|
+
/** Machine-readable failure category. */
|
|
167
|
+
code: 'custom' | 'invalid_enum' | 'invalid_literal' | 'invalid_type' | 'invalid_union' | 'missing_key';
|
|
168
|
+
/** Human-readable description of the expected type or value. */
|
|
169
|
+
expected: string;
|
|
170
|
+
/** Final message after optional `ErrorMap` rewriting. */
|
|
171
|
+
message: string;
|
|
172
|
+
/** Path from the parse root to the failing location. */
|
|
173
|
+
path: Path;
|
|
174
|
+
/** Value that failed validation at `path`. */
|
|
175
|
+
received: unknown;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Nested error tree returned by `StructError.format()`.
|
|
179
|
+
*
|
|
180
|
+
* Leaf messages live under `_errors`; nested keys mirror the failing path.
|
|
181
|
+
*/
|
|
182
|
+
interface FormattedStructError {
|
|
183
|
+
_errors: string[];
|
|
184
|
+
[key: string]: FormattedStructError | string[];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Flat field/form error bags returned by `StructError.flatten()`.
|
|
188
|
+
*/
|
|
189
|
+
interface FlattenedStructError {
|
|
190
|
+
/** Messages whose path is empty (root-level issues). */
|
|
191
|
+
formErrors: string[];
|
|
192
|
+
/** Messages keyed by the first path segment. */
|
|
193
|
+
fieldErrors: {
|
|
194
|
+
[key: string]: string[];
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Chainable modifiers available on every `Struct` instance.
|
|
199
|
+
*/
|
|
200
|
+
interface StructMethods<I, O, OO extends boolean> {
|
|
201
|
+
/**
|
|
202
|
+
* Override the external wire name for this field without changing the TypeScript property name.
|
|
203
|
+
*
|
|
204
|
+
* @param name - Wire / protocol field name.
|
|
205
|
+
* @returns The same struct branded with the alias.
|
|
206
|
+
*/
|
|
207
|
+
alias(name: string): Struct<I, O, OO>;
|
|
208
|
+
/**
|
|
209
|
+
* Allow `null` in addition to the current input and output types.
|
|
210
|
+
*
|
|
211
|
+
* @returns A struct that accepts and emits `null`.
|
|
212
|
+
*/
|
|
213
|
+
null(): Struct<I | null, O | null, OO>;
|
|
214
|
+
/**
|
|
215
|
+
* Alias for {@link StructMethods.null}.
|
|
216
|
+
*
|
|
217
|
+
* @returns A struct that accepts and emits `null`.
|
|
218
|
+
*/
|
|
219
|
+
nullable(): Struct<I | null, O | null, OO>;
|
|
220
|
+
/**
|
|
221
|
+
* Allow `null` or `undefined`, marking the field optional in object output.
|
|
222
|
+
*
|
|
223
|
+
* @returns A struct that accepts `null`/`undefined` and treats the field as optional.
|
|
224
|
+
*/
|
|
225
|
+
nullish(): Struct<I | null | undefined, O | null | undefined, true>;
|
|
226
|
+
/**
|
|
227
|
+
* Allow `undefined`, marking the field optional in object shapes.
|
|
228
|
+
*
|
|
229
|
+
* @returns A struct that accepts `undefined` and treats the field as optional.
|
|
230
|
+
*/
|
|
231
|
+
optional(): Struct<I | undefined, O | undefined, true>;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Public struct contract: modifiers plus the `_struct` type brand.
|
|
235
|
+
*
|
|
236
|
+
* Built via the `struct` facade (`struct.string()`, `struct.object()`, …).
|
|
237
|
+
*/
|
|
238
|
+
type Struct<Input = unknown, Output = Input, OptionalOut extends boolean = false> = StructMethods<Input, Output, OptionalOut> & StructLike<Input, Output, OptionalOut>;
|
|
239
|
+
type PresentValue = NonNullable<unknown>;
|
|
240
|
+
/**
|
|
241
|
+
* Broad struct constraint for endpoint and client generics.
|
|
242
|
+
*
|
|
243
|
+
* Prefer a concrete `Struct<…>` when you need precise input/output inference.
|
|
244
|
+
*/
|
|
245
|
+
type AnyStruct = Struct<any, any, boolean>;
|
|
246
|
+
/**
|
|
247
|
+
* Infer the accepted input type of a struct.
|
|
248
|
+
*
|
|
249
|
+
* @typeParam T - A struct-like value with a `_struct.input` brand.
|
|
250
|
+
*/
|
|
251
|
+
type StructInput<T> = T extends {
|
|
252
|
+
readonly _struct: {
|
|
253
|
+
readonly input: unknown;
|
|
254
|
+
};
|
|
255
|
+
} ? T['_struct']['input'] : never;
|
|
256
|
+
type StructOutput<T> = T extends {
|
|
257
|
+
readonly _struct: {
|
|
258
|
+
readonly output: unknown;
|
|
259
|
+
};
|
|
260
|
+
} ? T['_struct']['output'] : never;
|
|
261
|
+
/**
|
|
262
|
+
* Infer the parsed output type of a struct (alias of the internal output brand).
|
|
263
|
+
*
|
|
264
|
+
* @typeParam T - A struct-like value with a `_struct.output` brand.
|
|
265
|
+
*/
|
|
266
|
+
type Infer<T> = StructOutput<T>;
|
|
267
|
+
type FieldOutput<S> = S extends StructLike<unknown, unknown, boolean> ? S extends OptionalOutputStruct ? Exclude<S['_struct']['output'], undefined> : S['_struct']['output'] : never;
|
|
268
|
+
type Simplify<T> = { [K in keyof T]: T[K]; } & {};
|
|
269
|
+
type ObjectShape = {
|
|
270
|
+
[key: string]: any;
|
|
271
|
+
};
|
|
272
|
+
type ObjectInput<T extends ObjectShape> = Simplify<{ -readonly [K in keyof T as T[K] extends OptionalOutputStruct ? never : K]: T[K]['_struct']['input']; } & { -readonly [K in keyof T as T[K] extends OptionalOutputStruct ? K : never]?: Exclude<T[K]['_struct']['input'], undefined>; }>;
|
|
273
|
+
type ObjectOutput<T extends ObjectShape> = Simplify<{ -readonly [K in keyof T as T[K] extends OptionalOutputStruct ? never : K]: FieldOutput<T[K]>; } & { -readonly [K in keyof T as T[K] extends OptionalOutputStruct ? K : never]?: FieldOutput<T[K]>; }>;
|
|
274
|
+
type TupleInput<T extends readonly StructLike<unknown, unknown, boolean>[]> = { -readonly [K in keyof T]: StructInput<T[K]>; };
|
|
275
|
+
type TupleOutput<T extends readonly StructLike<unknown, unknown, boolean>[]> = { -readonly [K in keyof T]: StructOutput<T[K]>; };
|
|
276
|
+
type UnionOutput<T extends readonly StructLike<unknown, unknown, boolean>[]> = Exclude<StructOutput<T[number]>, undefined>;
|
|
277
|
+
type UnionInput<T extends readonly StructLike<unknown, unknown, boolean>[]> = Exclude<StructInput<T[number]>, undefined>;
|
|
278
|
+
type IntersectionInputValue<T extends readonly StructLike<unknown, unknown, boolean>[]> = T extends readonly [infer Head extends StructLike<unknown, unknown, boolean>, ...infer Tail extends StructLike<unknown, unknown, boolean>[]] ? StructInput<Head> & IntersectionInputValue<Tail> : unknown;
|
|
279
|
+
type IntersectionInput<T extends readonly StructLike<unknown, unknown, boolean>[]> = Exclude<IntersectionInputValue<T>, undefined>;
|
|
280
|
+
type IntersectionOutputValue<T extends readonly StructLike<unknown, unknown, boolean>[]> = T extends readonly [infer Head extends StructLike<unknown, unknown, boolean>, ...infer Tail extends StructLike<unknown, unknown, boolean>[]] ? StructOutput<Head> & IntersectionOutputValue<Tail> : unknown;
|
|
281
|
+
type IntersectionOutput<T extends readonly StructLike<unknown, unknown, boolean>[]> = Exclude<IntersectionOutputValue<T>, undefined>;
|
|
282
|
+
type StringStruct = Struct<string, string>;
|
|
283
|
+
type NumberStruct = Struct<number, number>;
|
|
284
|
+
type UnknownStruct = Struct<PresentValue, unknown>;
|
|
285
|
+
type ArrayInput<S extends StructLike<unknown, unknown, boolean>> = StructInput<S>[];
|
|
286
|
+
type ArrayOutput<S extends StructLike<unknown, unknown, boolean>> = StructOutput<S>[];
|
|
287
|
+
interface ArrayStructTypes<S extends StructLike<unknown, unknown, boolean>> extends StructTypes<ArrayInput<S>, ArrayOutput<S>, false> {
|
|
288
|
+
input: ArrayInput<S>;
|
|
289
|
+
optionalOut: undefined;
|
|
290
|
+
output: ArrayOutput<S>;
|
|
291
|
+
}
|
|
292
|
+
interface ArrayStruct<S extends StructLike<unknown, unknown, boolean>> extends StructMethods<ArrayInput<S>, ArrayOutput<S>, false>, StructLike<ArrayInput<S>, ArrayOutput<S>, false> {
|
|
293
|
+
readonly _struct: ArrayStructTypes<S>;
|
|
294
|
+
}
|
|
295
|
+
interface ObjectStructTypes<T extends ObjectShape> extends StructTypes<ObjectInput<T>, ObjectOutput<T>, false> {
|
|
296
|
+
input: ObjectInput<T>;
|
|
297
|
+
optionalOut: undefined;
|
|
298
|
+
output: ObjectOutput<T>;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Object-shaped struct produced by `struct.object(shape)`.
|
|
302
|
+
*
|
|
303
|
+
* Field presence follows each field's optional/nullish modifiers; wire names
|
|
304
|
+
* can differ from TypeScript keys via `.alias()`.
|
|
305
|
+
*/
|
|
306
|
+
interface ObjectStruct<T extends ObjectShape> extends StructMethods<ObjectInput<T>, ObjectOutput<T>, false>, StructLike<ObjectInput<T>, ObjectOutput<T>, false> {
|
|
307
|
+
readonly _struct: ObjectStructTypes<T>;
|
|
308
|
+
}
|
|
309
|
+
type RequestBodyCodec = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text' | 'urlencoded';
|
|
310
|
+
interface RequestBodyStructTypes<C extends RequestBodyCodec, S extends StructLike<unknown, unknown, boolean>> extends StructTypes<Exclude<StructInput<S>, undefined>, Exclude<StructOutput<S>, undefined>, false> {
|
|
311
|
+
codec: C;
|
|
312
|
+
input: Exclude<StructInput<S>, undefined>;
|
|
313
|
+
optionalOut: undefined;
|
|
314
|
+
output: Exclude<StructOutput<S>, undefined>;
|
|
315
|
+
}
|
|
316
|
+
interface RequestBodyStruct<C extends RequestBodyCodec, S extends StructLike<unknown, unknown, boolean>> extends StructMethods<Exclude<StructInput<S>, undefined>, Exclude<StructOutput<S>, undefined>, false>, StructLike<Exclude<StructInput<S>, undefined>, Exclude<StructOutput<S>, undefined>, false> {
|
|
317
|
+
readonly _struct: RequestBodyStructTypes<C, S>;
|
|
318
|
+
}
|
|
319
|
+
type RequestBinaryBodyStruct = Struct<ArrayBuffer, ArrayBuffer> | Struct<Blob, Blob>;
|
|
320
|
+
type RequestBodyShapeStruct = RequestBinaryBodyStruct | RequestBodyStruct<RequestBodyCodec, StructLike<unknown, unknown, boolean>>;
|
|
321
|
+
type RequestShape = {
|
|
322
|
+
body?: RequestBodyShapeStruct;
|
|
323
|
+
headers?: ObjectStruct<ObjectShape>;
|
|
324
|
+
path?: ObjectStruct<ObjectShape>;
|
|
325
|
+
query?: ObjectStruct<ObjectShape>;
|
|
326
|
+
};
|
|
327
|
+
type RequestObjectSectionInput<TKey extends 'headers' | 'path' | 'query', TSection> = TSection extends ObjectStruct<ObjectShape> ? {} extends StructInput<TSection> ? { [K in TKey]?: StructInput<TSection>; } : { [K in TKey]: StructInput<TSection>; } : {};
|
|
328
|
+
type RequestInput<T extends RequestShape> = Simplify<RequestObjectSectionInput<'path', T['path']> & RequestObjectSectionInput<'query', T['query']> & RequestObjectSectionInput<'headers', T['headers']> & (T['body'] extends StructLike<unknown, unknown, boolean> ? {
|
|
329
|
+
body: StructInput<T['body']>;
|
|
330
|
+
} : {})>;
|
|
331
|
+
type RequestOutput<T extends RequestShape> = Simplify<(T['path'] extends ObjectStruct<ObjectShape> ? {
|
|
332
|
+
path: StructOutput<T['path']>;
|
|
333
|
+
} : {}) & (T['query'] extends ObjectStruct<ObjectShape> ? {
|
|
334
|
+
query: StructOutput<T['query']>;
|
|
335
|
+
} : {}) & (T['headers'] extends ObjectStruct<ObjectShape> ? {
|
|
336
|
+
headers: StructOutput<T['headers']>;
|
|
337
|
+
} : {}) & (T['body'] extends StructLike<unknown, unknown, boolean> ? {
|
|
338
|
+
body: StructOutput<T['body']>;
|
|
339
|
+
} : {})>;
|
|
340
|
+
interface RequestStructTypes<T extends RequestShape> extends StructTypes<RequestInput<T>, RequestOutput<T>, false> {
|
|
341
|
+
input: RequestInput<T>;
|
|
342
|
+
optionalOut: undefined;
|
|
343
|
+
output: RequestOutput<T>;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Request-section struct produced by `struct.request({ path, query, headers, body })`.
|
|
347
|
+
*
|
|
348
|
+
* Groups path, query, headers, and body contracts used by HTTP/SSE/WebSocket builders.
|
|
349
|
+
*/
|
|
350
|
+
interface RequestStruct<T extends RequestShape> extends StructMethods<RequestInput<T>, RequestOutput<T>, false>, StructLike<RequestInput<T>, RequestOutput<T>, false> {
|
|
351
|
+
readonly _struct: RequestStructTypes<T>;
|
|
352
|
+
}
|
|
353
|
+
type RecordStruct<S extends StructLike<unknown, unknown, boolean>> = Struct<{
|
|
354
|
+
[key: string]: StructInput<S>;
|
|
355
|
+
}, {
|
|
356
|
+
[key: string]: FieldOutput<S>;
|
|
357
|
+
}>;
|
|
358
|
+
type TupleStruct<T extends readonly StructLike<unknown, unknown, boolean>[]> = Struct<TupleInput<T>, TupleOutput<T>>;
|
|
359
|
+
type UnionStruct<T extends readonly StructLike<unknown, unknown, boolean>[]> = Struct<UnionInput<T>, UnionOutput<T>>;
|
|
360
|
+
type DiscriminatedUnionStruct<TOptions extends readonly ObjectStruct<ObjectShape>[]> = Struct<StructInput<TOptions[number]>, StructOutput<TOptions[number]>>;
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/internal/request_values.d.ts
|
|
363
|
+
interface RequestBodyOptions {
|
|
364
|
+
readonly contentType?: string | null;
|
|
365
|
+
}
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/internal/request_builder.d.ts
|
|
368
|
+
type RequestTransport = 'http' | 'sse' | 'webSocket';
|
|
369
|
+
declare const BOUND_SOURCE: unique symbol;
|
|
370
|
+
declare const ARRAY_PROJECTION: unique symbol;
|
|
371
|
+
type BuildBoundRef<TOutput = unknown> = {
|
|
372
|
+
readonly [BOUND_SOURCE]: {
|
|
373
|
+
readonly output: TOutput;
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
type BuildArrayProjection<TItem> = {
|
|
377
|
+
readonly [ARRAY_PROJECTION]: never;
|
|
378
|
+
readonly item: TItem;
|
|
379
|
+
};
|
|
380
|
+
type BuildArray<TItem, TOutput extends readonly unknown[]> = BuildBoundRef<TOutput> & {
|
|
381
|
+
map<TProjection>(callback: (item: TItem) => TProjection): BuildArrayProjection<TProjection>;
|
|
382
|
+
};
|
|
383
|
+
type BuildInput<T> = T extends {
|
|
384
|
+
readonly _struct: {
|
|
385
|
+
readonly output: infer TOutput;
|
|
386
|
+
};
|
|
387
|
+
} ? BuildOutput<TOutput> : BuildBoundRef;
|
|
388
|
+
type BuildOutput<TOutput> = TOutput extends readonly (infer TItem)[] ? BuildArray<BuildOutput<TItem>, TOutput> : TOutput extends {
|
|
389
|
+
[key: string]: unknown;
|
|
390
|
+
} ? BuildBoundRef & { readonly [K in keyof TOutput]: BuildOutput<TOutput[K]>; } : BuildBoundRef<TOutput>;
|
|
391
|
+
type BuildFlatScalar = bigint | boolean | Date | null | number | string | undefined;
|
|
392
|
+
type BuildFlatValue = BuildFlatScalar | readonly BuildFlatScalar[];
|
|
393
|
+
type BuildFormDataValue = BuildFlatValue | Blob | File | readonly (Blob | BuildFlatScalar | File)[];
|
|
394
|
+
type BuildJsonProjection = BuildArrayProjection<unknown> | BuildBoundRef | undefined | readonly BuildJsonProjection[] | {
|
|
395
|
+
readonly [key: string]: BuildJsonProjection;
|
|
396
|
+
};
|
|
397
|
+
type BuildRecordProjection = {
|
|
398
|
+
readonly [key: string]: BuildBoundRef<BuildFlatValue> | undefined;
|
|
399
|
+
};
|
|
400
|
+
type BuildFormDataProjection = {
|
|
401
|
+
readonly [key: string]: BuildBoundRef<BuildFormDataValue> | undefined;
|
|
402
|
+
};
|
|
403
|
+
interface RequestBuilder {
|
|
404
|
+
addFormData(projection: BuildFormDataProjection): void;
|
|
405
|
+
addFormUrlEncoded(projection: BuildRecordProjection, options?: RequestBodyOptions): void;
|
|
406
|
+
addHeaders(projection: BuildRecordProjection): void;
|
|
407
|
+
setArrayBuffer(value: BuildBoundRef<ArrayBuffer>, options?: RequestBodyOptions): void;
|
|
408
|
+
setBlob(value: BuildBoundRef<Blob>, options?: RequestBodyOptions): void;
|
|
409
|
+
setFormData(projection: BuildFormDataProjection): void;
|
|
410
|
+
setFormUrlEncoded(projection: BuildRecordProjection, options?: RequestBodyOptions): void;
|
|
411
|
+
setHeaders(projection: BuildRecordProjection): void;
|
|
412
|
+
setHtml(value: BuildBoundRef<string>, options?: RequestBodyOptions): void;
|
|
413
|
+
setJson(projection: BuildJsonProjection, options?: RequestBodyOptions): void;
|
|
414
|
+
setPathParams(projection: BuildRecordProjection): void;
|
|
415
|
+
setQueryParams(projection: BuildRecordProjection): void;
|
|
416
|
+
setText(value: BuildBoundRef<string>, options?: RequestBodyOptions): void;
|
|
417
|
+
}
|
|
418
|
+
interface WebSocketRequestBuildContext {
|
|
419
|
+
setPathParams(projection: BuildRecordProjection): void;
|
|
420
|
+
setQueryParams(projection: BuildRecordProjection): void;
|
|
421
|
+
}
|
|
422
|
+
type RequestBuildInput<TInput extends AnyStruct | undefined> = [TInput] extends [undefined] ? unknown : TInput extends AnyStruct ? BuildInput<TInput> : never;
|
|
423
|
+
type RequestBuildContext<TTransport extends RequestTransport = 'http'> = TTransport extends 'webSocket' ? WebSocketRequestBuildContext : RequestBuilder;
|
|
424
|
+
type RequestBuildHandler<TInput extends AnyStruct | undefined, TTransport extends RequestTransport = 'http'> = (request: RequestBuildContext<TTransport>, input: RequestBuildInput<TInput>) => void;
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/struct/constructors.d.ts
|
|
427
|
+
declare function createStringStruct(): StringStruct;
|
|
428
|
+
declare function createNumberStruct(): NumberStruct;
|
|
429
|
+
declare function createBooleanStruct(): Struct<boolean, boolean>;
|
|
430
|
+
declare function createNullStruct(): Struct<null, null>;
|
|
431
|
+
declare function createAnyStruct(): Struct<PresentValue, any>;
|
|
432
|
+
declare function createUnknownStruct(): UnknownStruct;
|
|
433
|
+
declare function createLiteralStruct<const T extends LiteralValue>(value: T): Struct<T, T>;
|
|
434
|
+
declare function createArrayStruct<S extends StructLike<unknown, unknown, boolean>>(item: S): ArrayStruct<S>;
|
|
435
|
+
declare function createObjectStruct<T extends ObjectShape>(shape: T): ObjectStruct<T>;
|
|
436
|
+
declare function createRequestStruct<const T extends RequestShape>(shape: T): RequestStruct<T>;
|
|
437
|
+
declare function createJsonBodyStruct<S extends StructLike<unknown, unknown, boolean>>(struct: S, options?: {
|
|
438
|
+
contentType?: string | null;
|
|
439
|
+
}): RequestBodyStruct<'json', S>;
|
|
440
|
+
declare function createUrlencodedBodyStruct<T extends ObjectShape>(shape: T): RequestBodyStruct<'urlencoded', ObjectStruct<T>>;
|
|
441
|
+
declare function createFormDataBodyStruct<T extends ObjectShape>(shape: T): RequestBodyStruct<'formData', ObjectStruct<T>>;
|
|
442
|
+
declare function createTextBodyStruct(): RequestBodyStruct<'text', StringStruct>;
|
|
443
|
+
declare function createRecordStruct<S extends StructLike<unknown, unknown, boolean>>(value: S): RecordStruct<S>;
|
|
444
|
+
declare function createTupleStruct<const T extends readonly [StructLike<unknown, unknown, boolean>, ...StructLike<unknown, unknown, boolean>[]]>(items: T): TupleStruct<T>;
|
|
445
|
+
type RequiredDiscriminatorOption<TDiscriminator extends string, TOption extends ObjectStruct<ObjectShape>> = TOption extends ObjectStruct<infer TShape> ? TDiscriminator extends keyof TShape ? TShape[TDiscriminator] extends StructLike<infer TInput, unknown, false> ? undefined extends TInput ? never : null extends TInput ? [TInput] extends [null] ? TOption : never : TOption : never : never : never;
|
|
446
|
+
type RequiredDiscriminatorOptions<TDiscriminator extends string, TOptions extends readonly ObjectStruct<ObjectShape>[]> = { [K in keyof TOptions]: TOptions[K] extends ObjectStruct<ObjectShape> ? RequiredDiscriminatorOption<TDiscriminator, TOptions[K]> : never; };
|
|
447
|
+
declare function createDiscriminatedUnionStruct<const TDiscriminator extends string, const TOptions extends readonly [ObjectStruct<ObjectShape>, ...ObjectStruct<ObjectShape>[]]>(discriminator: TDiscriminator, options: TOptions & RequiredDiscriminatorOptions<TDiscriminator, TOptions>): DiscriminatedUnionStruct<TOptions>;
|
|
448
|
+
declare function createBlobStruct(): Struct<Blob, Blob>;
|
|
449
|
+
declare function createBigIntStruct(): Struct<bigint | string, bigint>;
|
|
450
|
+
declare function createDateStruct(): Struct<Date | number | string, Date>;
|
|
451
|
+
declare function createIntersectionStruct<const T extends readonly [StructLike<unknown, unknown, boolean>, ...StructLike<unknown, unknown, boolean>[]]>(...structs: T): Struct<IntersectionInput<T>, IntersectionOutput<T>>;
|
|
452
|
+
declare function createFileStruct(): Struct<File, File>;
|
|
453
|
+
declare function createArrayBufferStruct(): Struct<ArrayBuffer, ArrayBuffer>;
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/struct/introspection.d.ts
|
|
456
|
+
declare function parseStructTuple<S extends StructLike<unknown, unknown, boolean>>(struct: S, value: unknown, options?: {
|
|
457
|
+
aliases?: boolean;
|
|
458
|
+
errorMap?: ErrorMap;
|
|
459
|
+
}): ParseResult<S['_struct']['output']>;
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region src/struct/facade.d.ts
|
|
462
|
+
type EnumValue<T> = T extends readonly (infer U extends string)[] ? U : T extends {
|
|
463
|
+
[key: string]: infer U extends number | string;
|
|
464
|
+
} ? U : never;
|
|
465
|
+
declare function structEnum<const T extends readonly [string, ...string[]]>(value: T): Struct<EnumValue<T>, EnumValue<T>>;
|
|
466
|
+
declare function structEnum<const T extends {
|
|
467
|
+
[key: string]: number | string;
|
|
468
|
+
}>(value: T): Struct<EnumValue<T>, EnumValue<T>>;
|
|
469
|
+
declare function structOr<const T extends readonly [StructLike, ...StructLike[]]>(...options: T): UnionStruct<T>;
|
|
470
|
+
/**
|
|
471
|
+
* Facade for building protocol-boundary structs and parsing values.
|
|
472
|
+
*
|
|
473
|
+
* Prefer this entry point over internal constructors. Compose shapes with
|
|
474
|
+
* `struct.object` / `struct.request`, then parse with `struct.parse` or let
|
|
475
|
+
* HTTP/SSE/WebSocket endpoints apply the same contracts at the wire boundary.
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* const User = struct.object({
|
|
480
|
+
* id: struct.number(),
|
|
481
|
+
* displayName: struct.string().alias('display_name'),
|
|
482
|
+
* })
|
|
483
|
+
*
|
|
484
|
+
* const getUserInput = struct.request({
|
|
485
|
+
* path: struct.object({ id: struct.number() }),
|
|
486
|
+
* })
|
|
487
|
+
*
|
|
488
|
+
* const [error, user] = struct.parse(User, { id: 1, displayName: 'Ada' })
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
export declare const struct: {
|
|
492
|
+
readonly any: typeof createAnyStruct;
|
|
493
|
+
readonly array: typeof createArrayStruct;
|
|
494
|
+
readonly arrayBuffer: typeof createArrayBufferStruct;
|
|
495
|
+
readonly bigint: typeof createBigIntStruct;
|
|
496
|
+
readonly blob: typeof createBlobStruct;
|
|
497
|
+
readonly boolean: typeof createBooleanStruct;
|
|
498
|
+
readonly date: typeof createDateStruct;
|
|
499
|
+
readonly discriminatedUnion: typeof createDiscriminatedUnionStruct;
|
|
500
|
+
readonly enum: typeof structEnum;
|
|
501
|
+
readonly file: typeof createFileStruct;
|
|
502
|
+
readonly formData: typeof createFormDataBodyStruct;
|
|
503
|
+
readonly intersection: typeof createIntersectionStruct;
|
|
504
|
+
readonly json: typeof createJsonBodyStruct;
|
|
505
|
+
readonly literal: typeof createLiteralStruct;
|
|
506
|
+
readonly null: typeof createNullStruct;
|
|
507
|
+
readonly number: typeof createNumberStruct;
|
|
508
|
+
readonly object: typeof createObjectStruct;
|
|
509
|
+
readonly or: typeof structOr;
|
|
510
|
+
readonly parse: typeof parseStructTuple;
|
|
511
|
+
readonly record: typeof createRecordStruct;
|
|
512
|
+
readonly request: typeof createRequestStruct;
|
|
513
|
+
readonly string: typeof createStringStruct;
|
|
514
|
+
readonly text: typeof createTextBodyStruct;
|
|
515
|
+
readonly tuple: typeof createTupleStruct;
|
|
516
|
+
readonly unknown: typeof createUnknownStruct;
|
|
517
|
+
readonly urlencoded: typeof createUrlencodedBodyStruct;
|
|
518
|
+
};
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region src/http/request.d.ts
|
|
521
|
+
/**
|
|
522
|
+
* One status-to-body mapping used in the array form of `RequestOutputShape`.
|
|
523
|
+
* `status` may be a single code or a list of codes that share the same body struct.
|
|
524
|
+
*/
|
|
525
|
+
type ResponseGroupItem<S extends number = number, B extends AnyStruct = AnyStruct> = {
|
|
526
|
+
body: B;
|
|
527
|
+
status: S | readonly S[];
|
|
528
|
+
};
|
|
529
|
+
/**
|
|
530
|
+
* Declared HTTP response shapes keyed by status code, as a map or a list of `ResponseGroupItem`s.
|
|
531
|
+
*/
|
|
532
|
+
type RequestOutputShape = {
|
|
533
|
+
[key: number]: AnyStruct;
|
|
534
|
+
} | readonly ResponseGroupItem[];
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region src/sse/transport/parser.d.ts
|
|
537
|
+
/**
|
|
538
|
+
* Portions of this file are adapted from Azure/fetch-event-source.
|
|
539
|
+
* See packages/core/THIRD_PARTY_NOTICES.md for the license text.
|
|
540
|
+
*/
|
|
541
|
+
interface EventStreamMessage {
|
|
542
|
+
id: string;
|
|
543
|
+
event: string;
|
|
544
|
+
data: string;
|
|
545
|
+
}
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/sse/transport/event_stream.d.ts
|
|
548
|
+
/** Metadata available after an SSE response opens successfully. */
|
|
549
|
+
interface EventStreamOpenInfo {
|
|
550
|
+
response: HttpResponse<unknown>;
|
|
551
|
+
url: string;
|
|
552
|
+
}
|
|
553
|
+
/** Fatal or recoverable error codes reported when an SSE stream closes with `code: 'error'`. */
|
|
554
|
+
type EventStreamErrorCode = 'INVALID_RESPONSE' | 'MESSAGE_PROCESSING_FAILED' | 'PARSER_LIMIT_EXCEEDED' | 'QUEUE_OVERFLOW' | 'TIMEOUT' | 'TRANSPORT_ERROR';
|
|
555
|
+
interface EventStreamCloseInfoBase {
|
|
556
|
+
reason?: string;
|
|
557
|
+
cause?: unknown;
|
|
558
|
+
}
|
|
559
|
+
/** How an SSE stream ended: clean EOF, abort, or an error with `errorCode`. */
|
|
560
|
+
type EventStreamCloseInfo = (EventStreamCloseInfoBase & {
|
|
561
|
+
code: 'eof';
|
|
562
|
+
}) | (EventStreamCloseInfoBase & {
|
|
563
|
+
code: 'aborted';
|
|
564
|
+
}) | (EventStreamCloseInfoBase & {
|
|
565
|
+
code: 'error';
|
|
566
|
+
errorCode: EventStreamErrorCode;
|
|
567
|
+
});
|
|
568
|
+
/** Open SSE stream: iterate events, inspect open metadata, and close early. */
|
|
569
|
+
interface EventStreamHandle<TEvent = EventStreamMessage> extends AsyncIterable<TEvent>, AsyncDisposable {
|
|
570
|
+
readonly open: EventStreamOpenInfo;
|
|
571
|
+
readonly closed: Promise<EventStreamCloseInfo>;
|
|
572
|
+
close(reason?: unknown): void;
|
|
573
|
+
[Symbol.asyncDispose](): PromiseLike<void>;
|
|
574
|
+
}
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/error/types.d.ts
|
|
577
|
+
/**
|
|
578
|
+
* Error for an HTTP response whose status is treated as failure.
|
|
579
|
+
*/
|
|
580
|
+
export interface HttpStatusError<TErrorData = unknown, TStatus extends number = number> extends Error {
|
|
581
|
+
code: 'HTTP_STATUS';
|
|
582
|
+
data: TErrorData;
|
|
583
|
+
kind: 'http';
|
|
584
|
+
message: string;
|
|
585
|
+
response: HttpResponse<unknown>;
|
|
586
|
+
status: TStatus;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Error for transport-level failures such as abort, timeout, or network issues.
|
|
590
|
+
*/
|
|
591
|
+
export interface TransportError extends Error {
|
|
592
|
+
cause?: unknown;
|
|
593
|
+
code: 'ABORTED' | 'NETWORK_ERROR' | 'TIMEOUT';
|
|
594
|
+
kind: 'transport';
|
|
595
|
+
message: string;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Error for definition-time validation or undeclared response status failures.
|
|
599
|
+
*/
|
|
600
|
+
export type DefinitionError = (Error & {
|
|
601
|
+
cause?: unknown;
|
|
602
|
+
code: 'REQUEST_VALIDATION_FAILED' | 'RESPONSE_VALIDATION_FAILED' | 'INTERCEPTOR_FAILED';
|
|
603
|
+
kind: 'definition';
|
|
604
|
+
response?: HttpResponse<unknown>;
|
|
605
|
+
}) | (Error & {
|
|
606
|
+
cause?: unknown;
|
|
607
|
+
code: 'UNDECLARED_STATUS';
|
|
608
|
+
kind: 'definition';
|
|
609
|
+
response: HttpResponse<unknown>;
|
|
610
|
+
status: number;
|
|
611
|
+
});
|
|
612
|
+
/**
|
|
613
|
+
* Union of HTTP status, transport, and definition errors from request execution.
|
|
614
|
+
*
|
|
615
|
+
* @typeParam TErrorData - Declared error body type for `HttpStatusError` variants.
|
|
616
|
+
*/
|
|
617
|
+
export type RequestError<TErrorData = unknown> = HttpStatusError<TErrorData> | TransportError | DefinitionError;
|
|
618
|
+
//#endregion
|
|
619
|
+
//#region src/error/factory.d.ts
|
|
620
|
+
/** Shared cause/message sentinel for aborted requests. */
|
|
66
621
|
export declare const ERR_ABORTED: Error;
|
|
622
|
+
/** Shared cause/message sentinel for timed-out requests. */
|
|
67
623
|
export declare const ERR_TIMEOUT: Error;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
export declare
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
export
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
624
|
+
/**
|
|
625
|
+
* Build a `TransportError` from an abort, timeout, or other network cause.
|
|
626
|
+
*
|
|
627
|
+
* @param cause - Underlying abort/timeout/error value.
|
|
628
|
+
* @returns A normalized `TransportError`.
|
|
629
|
+
*/
|
|
630
|
+
export declare function createTransportError(cause: unknown): TransportError;
|
|
631
|
+
/**
|
|
632
|
+
* Build a `DefinitionError` for request/response validation or undeclared status.
|
|
633
|
+
*
|
|
634
|
+
* @param code - Definition error code.
|
|
635
|
+
* @param cause - Underlying validation or status failure.
|
|
636
|
+
* @param response - HTTP response; required for `UNDECLARED_STATUS` (status is taken from it).
|
|
637
|
+
* @returns A normalized `DefinitionError`.
|
|
638
|
+
*/
|
|
639
|
+
export declare function createDefinitionError(code: 'UNDECLARED_STATUS', cause: unknown, response: HttpResponse<unknown>): Extract<DefinitionError, {
|
|
640
|
+
code: 'UNDECLARED_STATUS';
|
|
641
|
+
}>;
|
|
642
|
+
export declare function createDefinitionError(code: Exclude<DefinitionError['code'], 'UNDECLARED_STATUS'>, cause: unknown, response?: HttpResponse<unknown>): Extract<DefinitionError, {
|
|
643
|
+
code: Exclude<DefinitionError['code'], 'UNDECLARED_STATUS'>;
|
|
644
|
+
}>;
|
|
645
|
+
/**
|
|
646
|
+
* Build an `HttpStatusError` for a non-success HTTP status.
|
|
647
|
+
*
|
|
648
|
+
* @param status - HTTP status code.
|
|
649
|
+
* @param message - Human-readable error message.
|
|
650
|
+
* @param response - Full HTTP response.
|
|
651
|
+
* @param data - Optional parsed error body.
|
|
652
|
+
* @returns A normalized `HttpStatusError`.
|
|
653
|
+
*/
|
|
654
|
+
export declare function createHttpStatusError<TErrorData = unknown, TStatus extends number = number>(status: TStatus, message: string, response: HttpResponse<unknown>, data?: TErrorData): HttpStatusError<TErrorData, TStatus>;
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/internal/abort.d.ts
|
|
657
|
+
type UseCancellationConfig = {
|
|
658
|
+
abort?: AbortSignal;
|
|
659
|
+
timeout?: never;
|
|
660
|
+
} | {
|
|
661
|
+
abort?: never;
|
|
662
|
+
timeout?: number;
|
|
663
|
+
};
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/internal/endpoint_input.d.ts
|
|
666
|
+
type EndpointInput<TInput extends AnyStruct | undefined> = TInput extends AnyStruct ? StructInput<TInput> : unknown;
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/internal/endpoint_command.d.ts
|
|
669
|
+
type IsEndpointInputOptional<TInput extends AnyStruct | undefined> = [TInput] extends [undefined] ? true : undefined extends EndpointInput<TInput> ? true : false;
|
|
670
|
+
type EndpointCommandBuilder<TInput extends AnyStruct | undefined, TCommand> = IsEndpointInputOptional<TInput> extends true ? (input?: EndpointInput<TInput>) => TCommand : (input: EndpointInput<TInput>) => TCommand;
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/http/http.d.ts
|
|
673
|
+
/**
|
|
674
|
+
* Per-request options for HTTP execution: progress callbacks and cancellation.
|
|
675
|
+
* Cancellation is either `abort` or `timeout` (not both).
|
|
676
|
+
*/
|
|
677
|
+
export type UseRequestConfig = {
|
|
678
|
+
onDownloadProgress?: HttpProgressFn;
|
|
679
|
+
onUploadProgress?: HttpProgressFn;
|
|
680
|
+
} & UseCancellationConfig;
|
|
681
|
+
/**
|
|
682
|
+
* Executable HTTP command produced by a `defineRequest` builder.
|
|
683
|
+
* Carries the request definition and optional typed input for `client.execute`.
|
|
684
|
+
*/
|
|
685
|
+
export interface HttpCommand<TInput extends AnyStruct | undefined, TOutput extends RequestOutputShape | undefined> extends BaseCommand<typeof HTTP_COMMAND> {
|
|
686
|
+
readonly definition: RequestDefinition<TInput, TOutput>;
|
|
687
|
+
readonly input: EndpointInput<TInput> | undefined;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Options passed to `client.execute` / `executeHttpCommand` for a single HTTP call.
|
|
691
|
+
* `signal` combines with `abort` or `timeout`; it is not an alias for `abort`.
|
|
692
|
+
* `abort` and `timeout` are mutually exclusive (`abort` XOR `timeout`).
|
|
693
|
+
*/
|
|
694
|
+
export type HttpExecuteOptions = UseRequestConfig & {
|
|
695
|
+
signal?: AbortSignal;
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* Builder returned by `defineRequest`; call with input to create an `HttpCommand`.
|
|
699
|
+
*/
|
|
700
|
+
export type RequestCommandBuilder<TInput extends AnyStruct | undefined, TOutput extends RequestOutputShape | undefined> = EndpointCommandBuilder<TInput, HttpCommand<TInput, TOutput>>;
|
|
701
|
+
type ResponsePairForStatus<TBody extends AnyStruct, TStatus> = TStatus extends readonly (infer U extends number)[] ? U extends number ? {
|
|
702
|
+
body: TBody;
|
|
703
|
+
status: U;
|
|
704
|
+
} : never : TStatus extends number ? {
|
|
705
|
+
body: TBody;
|
|
706
|
+
status: TStatus;
|
|
141
707
|
} : never;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
export interface ClientOptions {
|
|
173
|
-
host: string;
|
|
174
|
-
interceptors?: InterceptorFn[];
|
|
175
|
-
handler?: HttpHandler;
|
|
176
|
-
}
|
|
177
|
-
export type ClientConfig = {
|
|
178
|
-
host: string;
|
|
179
|
-
handler: HttpHandler;
|
|
180
|
-
interceptors: InterceptorFn[];
|
|
708
|
+
type ResponsePair<TOutput extends RequestOutputShape | undefined> = NonNullable<TOutput> extends readonly (infer TItem)[] ? TItem extends {
|
|
709
|
+
body: infer TBody extends AnyStruct;
|
|
710
|
+
status: infer TStatus;
|
|
711
|
+
} ? ResponsePairForStatus<TBody, TStatus> : never : { [K in keyof NonNullable<TOutput>]: NonNullable<TOutput>[K] extends (infer TBody extends AnyStruct) ? K extends number ? {
|
|
712
|
+
body: TBody;
|
|
713
|
+
status: K;
|
|
714
|
+
} : K extends `${infer TStatus extends number}` ? {
|
|
715
|
+
body: TBody;
|
|
716
|
+
status: TStatus;
|
|
717
|
+
} : never : never; }[keyof NonNullable<TOutput>];
|
|
718
|
+
type HttpStatusErrorByOutput<TOutput extends RequestOutputShape | undefined> = [TOutput] extends [undefined] ? HttpStatusError<undefined> : ResponsePair<TOutput> extends (infer TPair) ? TPair extends {
|
|
719
|
+
body: infer TBody extends AnyStruct;
|
|
720
|
+
status: infer TStatus extends number;
|
|
721
|
+
} ? `${TStatus}` extends `2${string}` ? never : HttpStatusError<Infer<TBody>, TStatus> : never : never;
|
|
722
|
+
type RequestErrorByOutput<TOutput extends RequestOutputShape | undefined> = HttpStatusErrorByOutput<TOutput> | TransportError | DefinitionError;
|
|
723
|
+
type ResponseBodyByStatus<TOutput extends RequestOutputShape | undefined, TOk extends boolean> = ResponsePair<TOutput> extends (infer TPair) ? TPair extends {
|
|
724
|
+
body: infer TBody extends AnyStruct;
|
|
725
|
+
status: infer TStatus extends number;
|
|
726
|
+
} ? `${TStatus}` extends `2${string}` ? TOk extends true ? TBody : never : TOk extends true ? never : TBody : never : never;
|
|
727
|
+
type InferResponseBodyByStatus<TOutput extends RequestOutputShape | undefined, TOk extends boolean> = [TOutput] extends [undefined] ? undefined : [ResponseBodyByStatus<TOutput, TOk>] extends [never] ? unknown : Infer<ResponseBodyByStatus<TOutput, TOk>>;
|
|
728
|
+
/** Inferred success body type for 2xx statuses declared in `TOutput`. */
|
|
729
|
+
export type RequestSuccessData<TOutput extends RequestOutputShape | undefined> = InferResponseBodyByStatus<TOutput, true>;
|
|
730
|
+
/** Inferred error-body type for non-2xx statuses declared in `TOutput`. */
|
|
731
|
+
export type RequestErrorData<TOutput extends RequestOutputShape | undefined> = InferResponseBodyByStatus<TOutput, false>;
|
|
732
|
+
type ResponseDeclaration<TOutput extends RequestOutputShape | undefined> = [TOutput] extends [undefined] ? {
|
|
733
|
+
output?: never;
|
|
734
|
+
responseType?: never;
|
|
735
|
+
} : {
|
|
736
|
+
output: TOutput;
|
|
737
|
+
responseType?: HttpResponseType;
|
|
181
738
|
};
|
|
739
|
+
/**
|
|
740
|
+
* Contract for an HTTP endpoint: method, path, optional input struct, and status-keyed outputs.
|
|
741
|
+
* Pass to `defineRequest` to get a typed command builder.
|
|
742
|
+
*/
|
|
743
|
+
export type RequestDefinition<TInput extends AnyStruct | undefined = undefined, TOutput extends RequestOutputShape | undefined = undefined> = ResponseDeclaration<TOutput> & {
|
|
744
|
+
operation?: string;
|
|
745
|
+
} & ({
|
|
746
|
+
method: string;
|
|
747
|
+
path: string;
|
|
748
|
+
build?: never;
|
|
749
|
+
input?: TInput;
|
|
750
|
+
} | (TInput extends AnyStruct ? {
|
|
751
|
+
method: string;
|
|
752
|
+
path: string;
|
|
753
|
+
build: RequestBuildHandler<TInput>;
|
|
754
|
+
input: TInput;
|
|
755
|
+
} : never));
|
|
756
|
+
/**
|
|
757
|
+
* Await-result tuple for an HTTP call: success `[null, body, response]` or failure `[error, undefined, response?]`.
|
|
758
|
+
*/
|
|
759
|
+
export type HttpAwaitResult<TSuccess = unknown, TErrorData = unknown> = [error: null, result: TSuccess, response: HttpResponse<TSuccess>] | [error: RequestError<TErrorData>, result: undefined, response: HttpResponse<unknown> | undefined];
|
|
760
|
+
type HttpExecuteAwaitResult<TOutput extends RequestOutputShape | undefined> = [error: null, result: RequestSuccessData<TOutput>, response: HttpResponse<RequestSuccessData<TOutput>>] | [error: RequestErrorByOutput<TOutput>, result: undefined, response: HttpResponse<unknown> | undefined];
|
|
761
|
+
/**
|
|
762
|
+
* Declare a typed HTTP request command builder.
|
|
763
|
+
*
|
|
764
|
+
* Pass method, path, optional input struct, and status-keyed output structs.
|
|
765
|
+
* Call the returned builder with input to get an `HttpCommand` for `client.execute`.
|
|
766
|
+
*
|
|
767
|
+
* @param definition - Request contract (method, path, input, output).
|
|
768
|
+
* @returns A builder that creates `HttpCommand` values from input.
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```ts
|
|
772
|
+
* const getUser = defineRequest({
|
|
773
|
+
* method: 'GET',
|
|
774
|
+
* path: '/users/:id',
|
|
775
|
+
* input: struct.request({ path: struct.object({ id: struct.number() }) }),
|
|
776
|
+
* output: [{ status: 200, body: struct.object({ id: struct.number(), name: struct.string() }) }],
|
|
777
|
+
* })
|
|
778
|
+
* ```
|
|
779
|
+
*/
|
|
780
|
+
export declare function defineRequest<TInput extends AnyStruct, const TOutput extends RequestOutputShape | undefined = undefined>(definition: RequestDefinition<TInput, TOutput>): RequestCommandBuilder<TInput, TOutput>;
|
|
781
|
+
export declare function defineRequest<TInput extends AnyStruct | undefined = undefined, const TOutput extends RequestOutputShape | undefined = undefined>(definition: RequestDefinition<TInput, TOutput>): RequestCommandBuilder<TInput, TOutput>;
|
|
782
|
+
/**
|
|
783
|
+
* Run an `HttpCommand` against client config: validate input, send the request, parse the response.
|
|
784
|
+
* Prefer `client.execute(command)` in application code; this is the underlying implementation.
|
|
785
|
+
*
|
|
786
|
+
* @param clientConfig - Resolved HTTP client configuration (endpoint, interceptors, handler).
|
|
787
|
+
* @param command - Command from a `defineRequest` builder.
|
|
788
|
+
* @param options - Per-request progress and cancellation options.
|
|
789
|
+
* @returns An await-result tuple of success body or typed request error.
|
|
790
|
+
*/
|
|
791
|
+
export declare function executeHttpCommand<TInput extends AnyStruct | undefined, TOutput extends RequestOutputShape | undefined>(clientConfig: HttpClientConfig, command: HttpCommand<TInput, TOutput>, options?: HttpExecuteOptions): Promise<HttpExecuteAwaitResult<TOutput>>;
|
|
792
|
+
//#endregion
|
|
793
|
+
//#region src/sse/sse.d.ts
|
|
794
|
+
/** Map of SSE event names to payload structs. Declare `__proto__` with a computed own key. */
|
|
795
|
+
export type EventStructs = {
|
|
796
|
+
[key: string]: AnyStruct;
|
|
797
|
+
};
|
|
798
|
+
type EventName<TKey extends string | number> = `${TKey}`;
|
|
799
|
+
type KnownEventUnion<TEvents extends EventStructs> = { [K in keyof TEvents & (number | string)]: EventName<K> extends 'default' ? never : {
|
|
800
|
+
data: Infer<TEvents[K]>;
|
|
801
|
+
event: EventName<K>;
|
|
802
|
+
id?: string;
|
|
803
|
+
}; }[keyof TEvents & (number | string)];
|
|
804
|
+
type DefaultEventUnion<TEvents extends EventStructs> = 'default' extends keyof TEvents ? {
|
|
805
|
+
data: Infer<TEvents['default']>;
|
|
806
|
+
event: string;
|
|
807
|
+
id?: string;
|
|
808
|
+
} : never;
|
|
809
|
+
/** Parsed SSE event payload inferred from an `EventStructs` map. */
|
|
810
|
+
export type EventStreamData<TEvents extends EventStructs> = TEvents extends EventStructs ? KnownEventUnion<TEvents> | DefaultEventUnion<TEvents> : never;
|
|
811
|
+
interface EventStreamDefinitionBase<TEvents extends EventStructs = EventStructs> {
|
|
812
|
+
events: TEvents;
|
|
813
|
+
maxBufferSize: number;
|
|
814
|
+
maxQueueSize: number;
|
|
815
|
+
method?: string;
|
|
816
|
+
operation?: string;
|
|
817
|
+
/** Optional non-2xx handshake bodies; fills `error.data` when the open status is declared. */
|
|
818
|
+
output?: RequestOutputShape;
|
|
819
|
+
path: string;
|
|
820
|
+
}
|
|
821
|
+
type EventStreamDefinitionWithoutBuild<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs> = EventStreamDefinitionBase<TEvents> & {
|
|
822
|
+
build?: never;
|
|
823
|
+
input?: TInput;
|
|
824
|
+
};
|
|
825
|
+
type EventStreamDefinitionWithBuild<TInput extends AnyStruct, TEvents extends EventStructs = EventStructs> = EventStreamDefinitionBase<TEvents> & {
|
|
826
|
+
build: RequestBuildHandler<TInput, 'sse'>;
|
|
827
|
+
input: TInput;
|
|
828
|
+
};
|
|
829
|
+
/** Contract describing an SSE endpoint: path, events, and buffer/queue limits. */
|
|
830
|
+
export type EventStreamDefinition<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs> = EventStreamDefinitionWithoutBuild<TInput, TEvents> | (TInput extends AnyStruct ? EventStreamDefinitionWithBuild<TInput, TEvents> : never);
|
|
831
|
+
/** Await-result tuple from opening an SSE stream via `client.execute`. */
|
|
832
|
+
export type StreamAwaitResult<TEvent> = [error: null, stream: EventStreamHandle<TEvent>, open: EventStreamOpenInfo] | [error: RequestError<unknown>, stream: undefined, open: EventStreamOpenInfo | undefined];
|
|
833
|
+
/** Executable SSE command produced by an `EventStreamCommandBuilder`. */
|
|
834
|
+
export interface EventStreamCommand<TInput extends AnyStruct | undefined, TEvents extends EventStructs> extends BaseCommand<typeof EVENT_STREAM_COMMAND> {
|
|
835
|
+
readonly endpoint: EventStreamEndpoint<TInput, TEvents>;
|
|
836
|
+
readonly input: EndpointInput<TInput> | undefined;
|
|
837
|
+
}
|
|
838
|
+
/** Per-execute options for SSE commands (abort, timeout). */
|
|
839
|
+
export type EventStreamExecuteOptions = UseCancellationConfig & {
|
|
840
|
+
signal?: AbortSignal;
|
|
841
|
+
};
|
|
842
|
+
/** Builder function that creates `EventStreamCommand` values from endpoint input. */
|
|
843
|
+
export type EventStreamCommandBuilder<TInput extends AnyStruct | undefined, TEvents extends EventStructs> = EndpointCommandBuilder<TInput, EventStreamCommand<TInput, TEvents>>;
|
|
844
|
+
type EventStreamEndpoint<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs> = EventStreamDefinition<TInput, TEvents> & {
|
|
845
|
+
readonly method: string;
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Declare a typed Server-Sent Events command builder.
|
|
849
|
+
*
|
|
850
|
+
* Pass path, event structs, and buffer/queue limits. Call the returned builder
|
|
851
|
+
* with input to get an `EventStreamCommand` for `client.execute`.
|
|
852
|
+
*
|
|
853
|
+
* @param definition - SSE contract (path, events, buffer limits, optional input).
|
|
854
|
+
* @returns A builder that creates `EventStreamCommand` values from input.
|
|
855
|
+
*
|
|
856
|
+
* @example
|
|
857
|
+
* ```ts
|
|
858
|
+
* const useEvents = defineEventStream({
|
|
859
|
+
* maxBufferSize: 1024,
|
|
860
|
+
* maxQueueSize: 16,
|
|
861
|
+
* path: '/events',
|
|
862
|
+
* events: { message: struct.object({ text: struct.string() }) },
|
|
863
|
+
* })
|
|
864
|
+
* ```
|
|
865
|
+
*/
|
|
866
|
+
export declare function defineEventStream<TInput extends AnyStruct, TEvents extends EventStructs = EventStructs>(definition: EventStreamDefinitionWithBuild<TInput, TEvents>): EventStreamCommandBuilder<TInput, TEvents>;
|
|
867
|
+
export declare function defineEventStream<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs>(definition: EventStreamDefinitionWithoutBuild<TInput, TEvents>): EventStreamCommandBuilder<TInput, TEvents>;
|
|
868
|
+
/**
|
|
869
|
+
* Open an SSE command against the given client config.
|
|
870
|
+
*
|
|
871
|
+
* Prefer `client.execute(command)` in application code; this is the low-level entry used by the client.
|
|
872
|
+
*
|
|
873
|
+
* @param clientConfig - Resolved client configuration.
|
|
874
|
+
* @param command - SSE command from an `EventStreamCommandBuilder`.
|
|
875
|
+
* @param options - Optional execute options (abort, timeout).
|
|
876
|
+
* @returns Await-result tuple of `[error, stream, open]`.
|
|
877
|
+
*/
|
|
878
|
+
export declare function executeEventStreamCommand<TInput extends AnyStruct | undefined, TEvents extends EventStructs>(clientConfig: ClientConfig, command: EventStreamCommand<TInput, TEvents>, options?: EventStreamExecuteOptions): Promise<StreamAwaitResult<EventStreamData<TEvents>>>;
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region src/client/command.d.ts
|
|
881
|
+
declare const COMMAND_TYPE: unique symbol;
|
|
882
|
+
declare const HTTP_COMMAND: unique symbol;
|
|
883
|
+
declare const EVENT_STREAM_COMMAND: unique symbol;
|
|
884
|
+
declare const WEB_SOCKET_COMMAND: unique symbol;
|
|
885
|
+
type CommandType = typeof HTTP_COMMAND | typeof EVENT_STREAM_COMMAND | typeof WEB_SOCKET_COMMAND;
|
|
886
|
+
interface BaseCommand<TCommandType extends CommandType> {
|
|
887
|
+
readonly [COMMAND_TYPE]: TCommandType;
|
|
888
|
+
}
|
|
889
|
+
//#endregion
|
|
890
|
+
//#region src/web_socket/codec.d.ts
|
|
891
|
+
interface WebSocketCloseSnapshot {
|
|
892
|
+
cause?: unknown;
|
|
893
|
+
code?: number;
|
|
894
|
+
reason?: string;
|
|
895
|
+
wasClean?: boolean;
|
|
896
|
+
}
|
|
897
|
+
//#endregion
|
|
898
|
+
//#region src/web_socket/web_socket.d.ts
|
|
899
|
+
/** Lifecycle state of a managed WebSocket session. */
|
|
900
|
+
export type WebSocketState = 'aborted' | 'closed' | 'closing' | 'connecting' | 'error' | 'idle' | 'open' | 'reconnecting';
|
|
901
|
+
/** Map of WebSocket message type names to payload structs. */
|
|
902
|
+
export type SocketStructs = {
|
|
903
|
+
[key: string]: AnyStruct;
|
|
904
|
+
};
|
|
905
|
+
export interface NormalizedWebSocketIncoming {
|
|
906
|
+
data: unknown;
|
|
907
|
+
type: string;
|
|
908
|
+
}
|
|
909
|
+
export type NormalizedWebSocketOutgoing = boolean | null | number | string | readonly unknown[] | {
|
|
910
|
+
readonly [key: string]: unknown;
|
|
911
|
+
};
|
|
912
|
+
export type WebSocketIncomingNormalizer = (decoded: unknown) => NormalizedWebSocketIncoming | undefined;
|
|
913
|
+
export type WebSocketOutgoingNormalizer = (type: string, encodedPayload: unknown) => NormalizedWebSocketOutgoing;
|
|
914
|
+
type SimplifySocket<T> = { [K in keyof T]: T[K]; } & {};
|
|
915
|
+
type NormalizeSocketMessage<TKey extends string, TPayload> = TPayload extends {
|
|
916
|
+
[key: string]: unknown;
|
|
917
|
+
} ? SimplifySocket<{
|
|
918
|
+
type: TKey;
|
|
919
|
+
} & TPayload> : {
|
|
920
|
+
data: TPayload;
|
|
921
|
+
type: TKey;
|
|
922
|
+
};
|
|
923
|
+
type SocketSendMessage<TKey extends string, TPayload> = TPayload extends {
|
|
924
|
+
[key: string]: unknown;
|
|
925
|
+
} ? SimplifySocket<{
|
|
926
|
+
type: TKey;
|
|
927
|
+
} & TPayload> | {
|
|
928
|
+
data: TPayload;
|
|
929
|
+
type: TKey;
|
|
930
|
+
} : {
|
|
931
|
+
data: TPayload;
|
|
932
|
+
type: TKey;
|
|
933
|
+
};
|
|
934
|
+
type KnownIncomingSocketUnion<TIncoming extends SocketStructs> = { [K in keyof TIncoming & string as K extends 'default' ? never : K]: NormalizeSocketMessage<K, Infer<TIncoming[K]>>; } extends (infer O) ? O[keyof O] : never;
|
|
935
|
+
type KnownOutgoingSocketUnion<TOutgoing extends SocketStructs> = { [K in keyof TOutgoing & string as K extends 'default' ? never : K]: SocketSendMessage<K, EndpointInput<TOutgoing[K]>>; } extends (infer O) ? O[keyof O] : never;
|
|
936
|
+
type DefaultIncomingSocketUnion<TIncoming extends SocketStructs> = 'default' extends keyof TIncoming ? NormalizeSocketMessage<string, Infer<TIncoming['default']>> : never;
|
|
937
|
+
/** Incoming message shape inferred from an incoming `SocketStructs` map. */
|
|
938
|
+
export type WebSocketIncomingData<TIncoming extends SocketStructs> = [KnownIncomingSocketUnion<TIncoming> | DefaultIncomingSocketUnion<TIncoming>] extends [never] ? never : KnownIncomingSocketUnion<TIncoming> | DefaultIncomingSocketUnion<TIncoming>;
|
|
939
|
+
/** Outgoing message shape inferred from an outgoing `SocketStructs` map. */
|
|
940
|
+
export type WebSocketOutgoingData<TOutgoing extends SocketStructs | undefined> = TOutgoing extends SocketStructs ? [KnownOutgoingSocketUnion<TOutgoing>] extends [never] ? never : KnownOutgoingSocketUnion<TOutgoing> : never;
|
|
941
|
+
interface WebSocketDefinitionBase<TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined> {
|
|
942
|
+
incoming: TIncoming;
|
|
943
|
+
maxIncomingQueueSize: number;
|
|
944
|
+
maxOutgoingQueueSize?: number;
|
|
945
|
+
normalizeIncoming?: WebSocketIncomingNormalizer;
|
|
946
|
+
normalizeOutgoing?: WebSocketOutgoingNormalizer;
|
|
947
|
+
operation?: string;
|
|
948
|
+
outgoing?: TOutgoing;
|
|
949
|
+
path: string;
|
|
950
|
+
protocols?: readonly string[];
|
|
951
|
+
}
|
|
952
|
+
type WebSocketDefinitionWithoutBuild<TInput extends AnyStruct | undefined = undefined, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined> = WebSocketDefinitionBase<TIncoming, TOutgoing> & {
|
|
953
|
+
build?: never;
|
|
954
|
+
input?: TInput;
|
|
955
|
+
};
|
|
956
|
+
type WebSocketDefinitionWithBuild<TInput extends AnyStruct, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined> = WebSocketDefinitionBase<TIncoming, TOutgoing> & {
|
|
957
|
+
build: RequestBuildHandler<TInput, 'webSocket'>;
|
|
958
|
+
input: TInput;
|
|
959
|
+
};
|
|
960
|
+
/** Contract describing a WebSocket endpoint: path, message structs, and queue limits. */
|
|
961
|
+
export type WebSocketDefinition<TInput extends AnyStruct | undefined = undefined, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined> = WebSocketDefinitionWithoutBuild<TInput, TIncoming, TOutgoing> | (TInput extends AnyStruct ? WebSocketDefinitionWithBuild<TInput, TIncoming, TOutgoing> : never);
|
|
962
|
+
/** Connection metadata for the current WebSocket generation. */
|
|
963
|
+
export interface WebSocketConnectionInfo {
|
|
964
|
+
extensions?: string;
|
|
965
|
+
generation: number;
|
|
966
|
+
protocol?: string;
|
|
967
|
+
url?: string;
|
|
968
|
+
}
|
|
969
|
+
/** How a WebSocket session ended: closed, aborted, or error. */
|
|
970
|
+
export type WebSocketCloseInfo = {
|
|
971
|
+
kind: 'closed';
|
|
972
|
+
code?: number;
|
|
973
|
+
reason?: string;
|
|
974
|
+
wasClean?: boolean;
|
|
975
|
+
} | {
|
|
976
|
+
kind: 'aborted';
|
|
977
|
+
cause?: unknown;
|
|
978
|
+
code?: number;
|
|
979
|
+
reason?: string;
|
|
980
|
+
wasClean?: boolean;
|
|
981
|
+
} | {
|
|
982
|
+
kind: 'error';
|
|
983
|
+
cause: unknown;
|
|
984
|
+
code?: number;
|
|
985
|
+
reason?: string;
|
|
986
|
+
wasClean?: boolean;
|
|
987
|
+
};
|
|
988
|
+
/** Typed WebSocket session: send/receive messages, observe state, and close. */
|
|
989
|
+
export interface WebSocketSession<TIncoming = unknown, TOutgoing = never> extends AsyncDisposable {
|
|
990
|
+
readonly bufferedAmount: number;
|
|
991
|
+
readonly connection: WebSocketConnectionInfo;
|
|
992
|
+
readonly closed: Promise<WebSocketCloseInfo>;
|
|
993
|
+
readonly receive: AsyncIterable<TIncoming>;
|
|
994
|
+
readonly state: WebSocketState;
|
|
995
|
+
close(code?: number, reason?: string): void;
|
|
996
|
+
[Symbol.asyncDispose](): PromiseLike<void>;
|
|
997
|
+
onRuntimeError(listener: (error: unknown) => void): () => void;
|
|
998
|
+
onStateChange(listener: (state: WebSocketState) => void): () => void;
|
|
999
|
+
send(message: TOutgoing): void;
|
|
1000
|
+
}
|
|
1001
|
+
/** Await-result tuple from opening a WebSocket via `client.execute`. */
|
|
1002
|
+
export type SocketAwaitResult<TIncoming, TOutgoing = never> = [error: null, socket: WebSocketSession<TIncoming, TOutgoing>, connection: WebSocketConnectionInfo] | [error: RequestError<unknown>, socket: undefined, connection: WebSocketConnectionInfo | undefined];
|
|
1003
|
+
interface UseWebSocketBaseConfig<TIncoming = unknown, TOutgoing = unknown> {
|
|
1004
|
+
beforeConnect?: ClientWebSocketOptions['beforeConnect'];
|
|
1005
|
+
heartbeat?: WebSocketHeartbeatConfig<TIncoming, TOutgoing>;
|
|
1006
|
+
protocols?: readonly string[];
|
|
1007
|
+
reconnect?: ClientWebSocketOptions['reconnect'];
|
|
1008
|
+
}
|
|
1009
|
+
/** Client configuration for WebSocket execute (heartbeat, reconnect, abort). */
|
|
1010
|
+
export type UseWebSocketConfig<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketBaseConfig<TIncoming, TOutgoing> & UseCancellationConfig;
|
|
1011
|
+
/** Per-execute options for WebSocket commands, including an optional `AbortSignal`. */
|
|
1012
|
+
export type WebSocketExecuteOptions<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketConfig<TIncoming, TOutgoing> & {
|
|
1013
|
+
signal?: AbortSignal;
|
|
1014
|
+
};
|
|
1015
|
+
/** Executable WebSocket command produced by a `WebSocketCommandBuilder`. */
|
|
1016
|
+
export interface WebSocketCommand<TInput extends AnyStruct | undefined, TIncoming extends SocketStructs, TOutgoing extends SocketStructs | undefined> extends BaseCommand<typeof WEB_SOCKET_COMMAND> {
|
|
1017
|
+
readonly endpoint: WebSocketEndpoint<TInput, TIncoming, TOutgoing>;
|
|
1018
|
+
readonly input: EndpointInput<TInput> | undefined;
|
|
1019
|
+
}
|
|
1020
|
+
/** Builder function that creates `WebSocketCommand` values from endpoint input. */
|
|
1021
|
+
export type WebSocketCommandBuilder<TInput extends AnyStruct | undefined, TIncoming extends SocketStructs, TOutgoing extends SocketStructs | undefined> = EndpointCommandBuilder<TInput, WebSocketCommand<TInput, TIncoming, TOutgoing>>;
|
|
1022
|
+
type WebSocketEndpoint<TInput extends AnyStruct | undefined = undefined, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined> = WebSocketDefinition<TInput, TIncoming, TOutgoing>;
|
|
1023
|
+
/** Reason recorded when the session is closed via `session.close()`. */
|
|
1024
|
+
export type ManualSocketCloseReason = {
|
|
1025
|
+
code?: number;
|
|
1026
|
+
kind: 'manual-web-socket-close';
|
|
1027
|
+
reason?: string;
|
|
1028
|
+
};
|
|
1029
|
+
/** Heartbeat ping/ack configuration for a live WebSocket session. */
|
|
1030
|
+
export interface WebSocketHeartbeatConfig<TIncoming = unknown, TOutgoing = unknown> {
|
|
1031
|
+
intervalMs: number;
|
|
1032
|
+
isAck?: (message: TIncoming) => boolean;
|
|
1033
|
+
message?: <T = TOutgoing>() => T | unknown;
|
|
1034
|
+
timeoutMs?: number;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Declare a typed WebSocket command builder.
|
|
1038
|
+
*
|
|
1039
|
+
* Pass path, incoming (and optional outgoing) message structs, and queue limits.
|
|
1040
|
+
* Call the returned builder with input to get a `WebSocketCommand` for `client.execute`.
|
|
1041
|
+
*
|
|
1042
|
+
* @param definition - WebSocket contract (path, structs, queue limits, optional input).
|
|
1043
|
+
* @returns A builder that creates `WebSocketCommand` values from input.
|
|
1044
|
+
*
|
|
1045
|
+
* @example
|
|
1046
|
+
* ```ts
|
|
1047
|
+
* const useChat = defineWebSocket({
|
|
1048
|
+
* maxIncomingQueueSize: 16,
|
|
1049
|
+
* path: '/ws/chat',
|
|
1050
|
+
* incoming: { message: struct.object({ text: struct.string() }) },
|
|
1051
|
+
* outgoing: { message: struct.object({ text: struct.string() }) },
|
|
1052
|
+
* })
|
|
1053
|
+
* ```
|
|
1054
|
+
*/
|
|
1055
|
+
export declare function defineWebSocket<TInput extends AnyStruct, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined>(definition: WebSocketDefinitionWithBuild<TInput, TIncoming, TOutgoing>): WebSocketCommandBuilder<TInput, TIncoming, TOutgoing>;
|
|
1056
|
+
export declare function defineWebSocket<TInput extends AnyStruct | undefined = undefined, TIncoming extends SocketStructs = SocketStructs, TOutgoing extends SocketStructs | undefined = undefined>(definition: WebSocketDefinitionWithoutBuild<TInput, TIncoming, TOutgoing>): WebSocketCommandBuilder<TInput, TIncoming, TOutgoing>;
|
|
1057
|
+
/**
|
|
1058
|
+
* Open a WebSocket command against the given client config.
|
|
1059
|
+
*
|
|
1060
|
+
* Prefer `client.execute(command)` in application code; this is the low-level entry used by the client.
|
|
1061
|
+
*
|
|
1062
|
+
* @param clientConfig - Resolved client configuration.
|
|
1063
|
+
* @param command - WebSocket command from a `WebSocketCommandBuilder`.
|
|
1064
|
+
* @param options - Optional execute options (heartbeat, reconnect, abort).
|
|
1065
|
+
* @returns Await-result tuple of `[error, socket, connection]`.
|
|
1066
|
+
*/
|
|
1067
|
+
export declare function executeWebSocketCommand<TInput extends AnyStruct | undefined, TIncoming extends SocketStructs, TOutgoing extends SocketStructs | undefined>(clientConfig: ClientConfig, command: WebSocketCommand<TInput, TIncoming, TOutgoing>, options?: WebSocketExecuteOptions<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>): Promise<SocketAwaitResult<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>>;
|
|
1068
|
+
/** Outcome of a single WebSocket connect attempt used by reconnect logic. */
|
|
1069
|
+
export type SocketLifecycleOutcome = {
|
|
1070
|
+
closeInfo: WebSocketCloseSnapshot;
|
|
1071
|
+
connection?: WebSocketConnectionInfo;
|
|
1072
|
+
cause?: unknown;
|
|
1073
|
+
opened: boolean;
|
|
1074
|
+
};
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region src/interceptor/interceptor.d.ts
|
|
1077
|
+
/**
|
|
1078
|
+
* Continuation that runs the rest of the HTTP interceptor chain (or the handler).
|
|
1079
|
+
*
|
|
1080
|
+
* `next(req)` only goes **inward** — remaining interceptors registered after this one,
|
|
1081
|
+
* then the Fetch handler. It is not a re-dispatch of `client.execute` / `axios(config)`
|
|
1082
|
+
* from the outside of the onion. Call `next` again for a safe replay (for example one
|
|
1083
|
+
* 401 refresh) from the same interceptor; outer layers do not run a second time.
|
|
1084
|
+
*/
|
|
1085
|
+
type HttpInterceptorNext = (req: HttpRequest) => Promise<HttpResponse<unknown>>;
|
|
1086
|
+
/**
|
|
1087
|
+
* HTTP interceptor function: may inspect/modify the request, then call `next`.
|
|
1088
|
+
*/
|
|
1089
|
+
type InterceptorFn = (req: HttpRequest, next: HttpInterceptorNext) => Promise<HttpResponse<unknown>>;
|
|
1090
|
+
/**
|
|
1091
|
+
* Tagged HTTP interceptor for client option lists.
|
|
1092
|
+
*/
|
|
1093
|
+
interface HttpInterceptor {
|
|
1094
|
+
kind: 'http';
|
|
1095
|
+
fn: InterceptorFn;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Wrap an `InterceptorFn` as a tagged `HttpInterceptor`.
|
|
1099
|
+
*
|
|
1100
|
+
* @param fn - HTTP interceptor function.
|
|
1101
|
+
* @returns An `HttpInterceptor` with `kind: 'http'`.
|
|
1102
|
+
*/
|
|
1103
|
+
export declare function createHttpInterceptor(fn: InterceptorFn): HttpInterceptor;
|
|
1104
|
+
/**
|
|
1105
|
+
* Terminal SSE handler that opens an event stream for the given request.
|
|
1106
|
+
*/
|
|
1107
|
+
type SSEHandler = (req: HttpRequest) => Promise<EventStreamHandle<unknown>>;
|
|
1108
|
+
/**
|
|
1109
|
+
* SSE interceptor function: may inspect/modify the request, then call `next`.
|
|
1110
|
+
*/
|
|
1111
|
+
type SSEInterceptorFn = (req: HttpRequest, next: SSEHandler) => Promise<EventStreamHandle<unknown>>;
|
|
1112
|
+
/**
|
|
1113
|
+
* Tagged SSE interceptor for client option lists.
|
|
1114
|
+
*/
|
|
1115
|
+
interface SSEInterceptor {
|
|
1116
|
+
kind: 'sse';
|
|
1117
|
+
fn: SSEInterceptorFn;
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Wrap an `SSEInterceptorFn` as a tagged `SSEInterceptor`.
|
|
1121
|
+
*
|
|
1122
|
+
* @param fn - SSE interceptor function.
|
|
1123
|
+
* @returns An `SSEInterceptor` with `kind: 'sse'`.
|
|
1124
|
+
*/
|
|
1125
|
+
export declare function createSSEInterceptor(fn: SSEInterceptorFn): SSEInterceptor;
|
|
1126
|
+
/**
|
|
1127
|
+
* Minimal WebSocket session surface used by interceptors.
|
|
1128
|
+
*
|
|
1129
|
+
* Structurally compatible with `WebSocketSession` without importing that type
|
|
1130
|
+
* (avoids a circular dependency between interceptors and WebSocket).
|
|
1131
|
+
*/
|
|
1132
|
+
interface WebSocketSessionLike extends AsyncDisposable {
|
|
1133
|
+
readonly bufferedAmount: number;
|
|
1134
|
+
readonly connection: {
|
|
1135
|
+
extensions?: string;
|
|
1136
|
+
generation: number;
|
|
1137
|
+
protocol?: string;
|
|
1138
|
+
url?: string;
|
|
1139
|
+
};
|
|
1140
|
+
readonly closed: Promise<WebSocketCloseInfo>;
|
|
1141
|
+
readonly receive: AsyncIterable<unknown>;
|
|
1142
|
+
readonly state: WebSocketState;
|
|
1143
|
+
close(code?: number, reason?: string): void;
|
|
1144
|
+
[Symbol.asyncDispose](): PromiseLike<void>;
|
|
1145
|
+
onRuntimeError(listener: (error: unknown) => void): () => void;
|
|
1146
|
+
onStateChange(listener: (state: WebSocketState) => void): () => void;
|
|
1147
|
+
send(message: unknown): void;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Terminal WebSocket handler that opens a session for the given request.
|
|
1151
|
+
*/
|
|
1152
|
+
type WebSocketHandler = (req: HttpRequest) => Promise<WebSocketSessionLike>;
|
|
1153
|
+
/**
|
|
1154
|
+
* WebSocket interceptor function: may inspect/modify the request, then call `next`.
|
|
1155
|
+
*/
|
|
1156
|
+
type WebSocketInterceptorFn = (req: HttpRequest, next: WebSocketHandler) => Promise<WebSocketSessionLike>;
|
|
1157
|
+
/**
|
|
1158
|
+
* Tagged WebSocket interceptor for client option lists.
|
|
1159
|
+
*/
|
|
1160
|
+
interface WebSocketInterceptor {
|
|
1161
|
+
kind: 'web-socket';
|
|
1162
|
+
fn: WebSocketInterceptorFn;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Wrap a `WebSocketInterceptorFn` as a tagged `WebSocketInterceptor`.
|
|
1166
|
+
*
|
|
1167
|
+
* @param fn - WebSocket interceptor function.
|
|
1168
|
+
* @returns A `WebSocketInterceptor` with `kind: 'web-socket'`.
|
|
1169
|
+
*/
|
|
1170
|
+
export declare function createWebSocketInterceptor(fn: WebSocketInterceptorFn): WebSocketInterceptor;
|
|
1171
|
+
/**
|
|
1172
|
+
* Any tagged interceptor accepted by client interceptor options.
|
|
1173
|
+
*/
|
|
1174
|
+
type Interceptor = HttpInterceptor | SSEInterceptor | WebSocketInterceptor;
|
|
1175
|
+
//#endregion
|
|
1176
|
+
//#region src/client/config.d.ts
|
|
1177
|
+
/**
|
|
1178
|
+
* Serializes query parameters for the request URL.
|
|
1179
|
+
*
|
|
1180
|
+
* @param params - Normalized `URLSearchParams` built from the request.
|
|
1181
|
+
* @param rawParams - Optional original param object before normalization.
|
|
1182
|
+
* @returns The query string (without a leading `?`).
|
|
1183
|
+
*/
|
|
1184
|
+
type QueryParamsSerializer = (params: URLSearchParams, rawParams?: {
|
|
1185
|
+
[key: string]: unknown;
|
|
1186
|
+
}) => string;
|
|
1187
|
+
/**
|
|
1188
|
+
* Fetch-compatible function used as an HTTP or SSE handle.
|
|
1189
|
+
*
|
|
1190
|
+
* This is the `(input, init?) => Promise<Response>` call signature Defjs invokes,
|
|
1191
|
+
* not `typeof fetch`, so mocks do not need host extras such as `preconnect`.
|
|
1192
|
+
*/
|
|
1193
|
+
type FetchHandle = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
1194
|
+
/**
|
|
1195
|
+
* Minimal WebSocket-like handle used by the client transport.
|
|
1196
|
+
*
|
|
1197
|
+
* Omits browser event-handler properties so custom implementations only need
|
|
1198
|
+
* the send/close/state surface Defjs relies on.
|
|
1199
|
+
*/
|
|
1200
|
+
type WebSocketHandle = Omit<WebSocket, 'binaryType' | 'CLOSED' | 'CLOSING' | 'CONNECTING' | 'dispatchEvent' | 'onclose' | 'onerror' | 'onmessage' | 'onopen' | 'OPEN' | 'readyState'> & {
|
|
1201
|
+
readonly readyState: number;
|
|
1202
|
+
};
|
|
1203
|
+
/** Constructor for a `WebSocketHandle`, including the `OPEN` ready-state constant. */
|
|
1204
|
+
type WebSocketHandleConstructor = {
|
|
1205
|
+
readonly OPEN: number;
|
|
1206
|
+
} & (new (...args: never[]) => WebSocketHandle);
|
|
1207
|
+
/** Optional WebSocket settings applied when creating a client. */
|
|
1208
|
+
interface ClientWebSocketOptions {
|
|
1209
|
+
/** WebSocket constructor; defaults to `globalThis.WebSocket`. */
|
|
1210
|
+
handle?: WebSocketHandleConstructor;
|
|
1211
|
+
/** Hook before each connect/reconnect attempt. */
|
|
1212
|
+
beforeConnect?: (context: {
|
|
1213
|
+
attempt: number;
|
|
1214
|
+
signal: AbortSignal;
|
|
1215
|
+
}) => void | Promise<void>;
|
|
1216
|
+
/** Periodic heartbeat ping and optional ACK matching. */
|
|
1217
|
+
heartbeat?: {
|
|
1218
|
+
/** Delay between heartbeat messages. */
|
|
1219
|
+
intervalMs: number;
|
|
1220
|
+
/** Returns whether an incoming message acknowledges the heartbeat. */
|
|
1221
|
+
isAck?: (message: unknown) => boolean;
|
|
1222
|
+
/** Builds the outbound heartbeat payload. */
|
|
1223
|
+
message?: <T = unknown>() => T | unknown;
|
|
1224
|
+
/** Time to wait for an ACK before treating the connection as unhealthy. */
|
|
1225
|
+
timeoutMs?: number;
|
|
1226
|
+
};
|
|
1227
|
+
/** Subprotocols passed to the WebSocket constructor. */
|
|
1228
|
+
protocols?: readonly string[];
|
|
1229
|
+
/** Automatic reconnect policy after unexpected closes. */
|
|
1230
|
+
reconnect?: {
|
|
1231
|
+
/** Retry budget after the first connect. Defaults to 3 when `reconnect` is set. `0` disables. Omitting this field is not unlimited. */
|
|
1232
|
+
attempts?: number;
|
|
1233
|
+
/** Initial backoff delay in milliseconds. */
|
|
1234
|
+
delayMs?: number;
|
|
1235
|
+
/** Multiplier applied to the delay after each failed attempt. */
|
|
1236
|
+
factor?: number;
|
|
1237
|
+
/** Random jitter factor applied to the delay (0–1). */
|
|
1238
|
+
jitter?: number;
|
|
1239
|
+
/** Upper bound for computed backoff delay. */
|
|
1240
|
+
maxDelayMs?: number;
|
|
1241
|
+
/** Return `false` to skip reconnecting for this close. */
|
|
1242
|
+
shouldReconnect?: (context: {
|
|
1243
|
+
attempt: number;
|
|
1244
|
+
cause?: unknown;
|
|
1245
|
+
code?: number;
|
|
1246
|
+
reason?: string;
|
|
1247
|
+
wasClean?: boolean;
|
|
1248
|
+
}) => boolean;
|
|
1249
|
+
};
|
|
1250
|
+
/** Called when an incoming message has no matching struct (unknown `type`). Struct/JSON failures still use `onRuntimeError`. */
|
|
1251
|
+
onInvalidEvent?: (context: {
|
|
1252
|
+
reason: 'missing-struct';
|
|
1253
|
+
message: {
|
|
1254
|
+
type: string;
|
|
1255
|
+
data: unknown;
|
|
1256
|
+
};
|
|
1257
|
+
}) => unknown;
|
|
1258
|
+
}
|
|
1259
|
+
/** Optional SSE settings applied when creating a client. */
|
|
1260
|
+
interface ClientSSEOptions {
|
|
1261
|
+
/** Fetch implementation used to open the event stream. */
|
|
1262
|
+
handle?: FetchHandle;
|
|
1263
|
+
/** Called when an event has no matching struct or fails validation. */
|
|
1264
|
+
onInvalidEvent?: (context: {
|
|
1265
|
+
reason: 'missing-struct' | 'validation-failed';
|
|
1266
|
+
message: {
|
|
1267
|
+
id: string;
|
|
1268
|
+
event: string;
|
|
1269
|
+
data: string;
|
|
1270
|
+
};
|
|
1271
|
+
cause?: unknown;
|
|
1272
|
+
signal: AbortSignal;
|
|
1273
|
+
}) => unknown;
|
|
1274
|
+
/** Automatic reconnect policy after stream failures. */
|
|
1275
|
+
reconnect?: {
|
|
1276
|
+
/** Retry budget after the first attempt. Defaults to 3 when `reconnect` is set. `0` disables. Omitting this field is not unlimited. */
|
|
1277
|
+
attempts?: number;
|
|
1278
|
+
/** Initial backoff delay in milliseconds. */
|
|
1279
|
+
delayMs?: number;
|
|
1280
|
+
/** Multiplier applied to the delay after each failed attempt. */
|
|
1281
|
+
factor?: number;
|
|
1282
|
+
/** Random jitter factor applied to the delay (0–1). */
|
|
1283
|
+
jitter?: number;
|
|
1284
|
+
/** Upper bound for computed backoff delay. */
|
|
1285
|
+
maxDelayMs?: number;
|
|
1286
|
+
/** Return `false` to skip reconnecting for this failure. */
|
|
1287
|
+
shouldReconnect?: (context: {
|
|
1288
|
+
attempt: number;
|
|
1289
|
+
cause?: unknown;
|
|
1290
|
+
lastEventId: string;
|
|
1291
|
+
open?: {
|
|
1292
|
+
response: {
|
|
1293
|
+
status: number;
|
|
1294
|
+
statusText: string;
|
|
1295
|
+
url: string;
|
|
1296
|
+
};
|
|
1297
|
+
url: string;
|
|
1298
|
+
};
|
|
1299
|
+
}) => boolean | Promise<boolean>;
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
/** Resolved SSE config with a required `handle`. */
|
|
1303
|
+
interface ClientSSEConfig extends ClientSSEOptions {
|
|
1304
|
+
/** Fetch implementation used to open the event stream. */
|
|
1305
|
+
handle: FetchHandle;
|
|
1306
|
+
}
|
|
1307
|
+
/** User-facing HTTP client options before defaults are applied. */
|
|
1308
|
+
interface HttpClientOptions {
|
|
1309
|
+
/** Base URL prepended to relative request paths. */
|
|
1310
|
+
endpoint: string;
|
|
1311
|
+
/** Static default headers merged under command headers for HTTP/SSE. */
|
|
1312
|
+
headers?: Headers;
|
|
1313
|
+
/** HTTP transport overrides. */
|
|
1314
|
+
http?: {
|
|
1315
|
+
handle?: FetchHandle;
|
|
1316
|
+
};
|
|
1317
|
+
/** Interceptors applied in registration order. */
|
|
1318
|
+
interceptors?: Interceptor[];
|
|
1319
|
+
/** Custom query-string serializer. */
|
|
1320
|
+
queryParamsSerializer?: QueryParamsSerializer;
|
|
1321
|
+
/** Default HTTP execute timeout in milliseconds (SSE/WebSocket ignore this). */
|
|
1322
|
+
timeout?: number;
|
|
1323
|
+
/** XSRF cookie/header mapping and optional token provider. */
|
|
1324
|
+
xsrf?: {
|
|
1325
|
+
/** Cookie name that stores the XSRF token. */
|
|
1326
|
+
cookieName?: string;
|
|
1327
|
+
/** Request header name that receives the token. */
|
|
1328
|
+
headerName?: string;
|
|
1329
|
+
/** Supplies a token instead of reading the cookie. */
|
|
1330
|
+
tokenProvider?: (context: {
|
|
1331
|
+
request: HttpRequest;
|
|
1332
|
+
}) => string | null | undefined;
|
|
1333
|
+
};
|
|
1334
|
+
/** When `true`, credentials are included with requests. */
|
|
1335
|
+
withCredentials?: boolean;
|
|
1336
|
+
}
|
|
1337
|
+
/** User-facing options for `createClient`, including SSE and WebSocket. */
|
|
1338
|
+
interface ClientOptions extends HttpClientOptions {
|
|
1339
|
+
/** SSE transport and reconnect options. */
|
|
1340
|
+
sse?: ClientSSEOptions;
|
|
1341
|
+
/** WebSocket transport, heartbeat, and reconnect options. */
|
|
1342
|
+
webSocket?: ClientWebSocketOptions;
|
|
1343
|
+
}
|
|
1344
|
+
/** Resolved HTTP client config after defaults and options are applied. */
|
|
1345
|
+
interface HttpClientConfig {
|
|
1346
|
+
/** Base URL prepended to relative request paths. */
|
|
1347
|
+
endpoint: string;
|
|
1348
|
+
/** Static default headers merged under command headers for HTTP/SSE. */
|
|
1349
|
+
headers?: Headers;
|
|
1350
|
+
/** HTTP transport with a required fetch handle. */
|
|
1351
|
+
http: {
|
|
1352
|
+
handle: FetchHandle;
|
|
1353
|
+
};
|
|
1354
|
+
/** Interceptors applied in registration order. */
|
|
1355
|
+
interceptors: Interceptor[];
|
|
1356
|
+
/** Query-string serializer used for requests. */
|
|
1357
|
+
queryParamsSerializer: QueryParamsSerializer;
|
|
1358
|
+
/** Default HTTP execute timeout in milliseconds (SSE/WebSocket ignore this). */
|
|
1359
|
+
timeout?: number;
|
|
1360
|
+
/** Resolved XSRF settings when enabled. */
|
|
1361
|
+
xsrf?: {
|
|
1362
|
+
/** Cookie name that stores the XSRF token. */
|
|
1363
|
+
cookieName: string;
|
|
1364
|
+
/** Request header name that receives the token. */
|
|
1365
|
+
headerName: string;
|
|
1366
|
+
/** Supplies a token instead of reading the cookie. */
|
|
1367
|
+
tokenProvider?: (context: {
|
|
1368
|
+
request: HttpRequest;
|
|
1369
|
+
}) => string | null | undefined;
|
|
1370
|
+
};
|
|
1371
|
+
/** When `true`, credentials are included with requests. */
|
|
1372
|
+
withCredentials?: boolean;
|
|
1373
|
+
}
|
|
1374
|
+
/** Resolved client config held by instances from `createClient`. */
|
|
1375
|
+
interface ClientConfig extends HttpClientConfig {
|
|
1376
|
+
/** Resolved SSE configuration. */
|
|
1377
|
+
sse: ClientSSEConfig;
|
|
1378
|
+
/** Resolved WebSocket configuration. */
|
|
1379
|
+
webSocket: ClientWebSocketOptions;
|
|
1380
|
+
}
|
|
1381
|
+
//#endregion
|
|
1382
|
+
//#region src/client/option.d.ts
|
|
1383
|
+
/** Mutates `ClientConfig` when applied by `createClient`. */
|
|
1384
|
+
type ClientOption = (config: ClientConfig) => void;
|
|
1385
|
+
/**
|
|
1386
|
+
* Sets the base URL prepended to relative request paths.
|
|
1387
|
+
*
|
|
1388
|
+
* @param endpoint - Absolute or relative base endpoint.
|
|
1389
|
+
* @returns An option that writes `config.endpoint`.
|
|
1390
|
+
*/
|
|
1391
|
+
export declare function withEndpoint(endpoint: string): ClientOption;
|
|
1392
|
+
/**
|
|
1393
|
+
* Sets static default headers for HTTP/SSE requests built by this client.
|
|
1394
|
+
*
|
|
1395
|
+
* Command `struct.request({ headers })` values override the same names. HMAC and
|
|
1396
|
+
* dynamic Bearer tokens still belong in interceptors (they need the serialized body
|
|
1397
|
+
* or a refreshed credential).
|
|
1398
|
+
*
|
|
1399
|
+
* @param headers - `HeadersInit` bag cloned onto the client config.
|
|
1400
|
+
* @returns An option that writes `config.headers`.
|
|
1401
|
+
*/
|
|
1402
|
+
export declare function withHeaders(headers: HeadersInit): ClientOption;
|
|
1403
|
+
/**
|
|
1404
|
+
* Sets the default timeout for HTTP `execute` only.
|
|
1405
|
+
*
|
|
1406
|
+
* Timeout is applied before the interceptor chain (`mergeAbortSignals`). Execute
|
|
1407
|
+
* `{ timeout }` overrides this default. Execute `{ abort }` combines with the
|
|
1408
|
+
* default (abort → `ABORTED`, timer → `TIMEOUT`). SSE and WebSocket ignore this
|
|
1409
|
+
* option. XOR still rejects execute options that pass both `abort` and `timeout`.
|
|
1410
|
+
*
|
|
1411
|
+
* @param ms - Positive safe integer timeout in milliseconds.
|
|
1412
|
+
* @returns An option that writes `config.timeout`.
|
|
1413
|
+
*/
|
|
1414
|
+
export declare function withTimeout(ms: number): ClientOption;
|
|
1415
|
+
/**
|
|
1416
|
+
* Appends interceptors to the client interceptor chain.
|
|
1417
|
+
*
|
|
1418
|
+
* @param interceptors - Interceptors applied in registration order.
|
|
1419
|
+
* @returns An option that pushes onto `config.interceptors`.
|
|
1420
|
+
*/
|
|
1421
|
+
export declare function withInterceptors(...interceptors: Interceptor[]): ClientOption;
|
|
1422
|
+
/**
|
|
1423
|
+
* Replaces the serializer used when encoding query parameters.
|
|
1424
|
+
*
|
|
1425
|
+
* @param serializer - Function that turns params into a query string.
|
|
1426
|
+
* @returns An option that sets `config.queryParamsSerializer`.
|
|
1427
|
+
*/
|
|
1428
|
+
export declare function withQueryParamsSerializer(serializer: QueryParamsSerializer): ClientOption;
|
|
1429
|
+
/**
|
|
1430
|
+
* Overrides the Fetch-compatible function used for HTTP requests.
|
|
1431
|
+
*
|
|
1432
|
+
* @param fetchImpl - `(input, init?) => Promise<Response>`. Not `typeof fetch`, so
|
|
1433
|
+
* a mock does not need host extras such as `preconnect`.
|
|
1434
|
+
* @returns An option that sets `config.http.handle`.
|
|
1435
|
+
*/
|
|
1436
|
+
export declare function withHTTPHandle(fetchImpl: FetchHandle): ClientOption;
|
|
1437
|
+
/**
|
|
1438
|
+
* Overrides the Fetch-compatible function used for SSE connections.
|
|
1439
|
+
*
|
|
1440
|
+
* @param fetchImpl - `(input, init?) => Promise<Response>`. Not `typeof fetch`, so
|
|
1441
|
+
* a mock does not need host extras such as `preconnect`.
|
|
1442
|
+
* @returns An option that sets `config.sse.handle`.
|
|
1443
|
+
*/
|
|
1444
|
+
export declare function withSSEHandle(fetchImpl: FetchHandle): ClientOption;
|
|
1445
|
+
/**
|
|
1446
|
+
* Overrides the WebSocket constructor used for socket connections.
|
|
1447
|
+
*
|
|
1448
|
+
* @param WebSocketImpl - Constructor that returns a `WebSocketHandle`.
|
|
1449
|
+
* @returns An option that sets `config.webSocket.handle`.
|
|
1450
|
+
*/
|
|
1451
|
+
export declare function withWebSocketHandle(WebSocketImpl: WebSocketHandleConstructor): ClientOption;
|
|
1452
|
+
/**
|
|
1453
|
+
* Runs logic before each WebSocket connect or reconnect attempt.
|
|
1454
|
+
*
|
|
1455
|
+
* @param beforeConnect - Hook receiving attempt index and abort signal.
|
|
1456
|
+
* @returns An option that sets `config.webSocket.beforeConnect`.
|
|
1457
|
+
*/
|
|
1458
|
+
export declare function withWebSocketBeforeConnect(beforeConnect: ClientWebSocketOptions['beforeConnect']): ClientOption;
|
|
1459
|
+
/**
|
|
1460
|
+
* Configure WebSocket subprotocols for the connection handshake.
|
|
1461
|
+
*
|
|
1462
|
+
* `protocols` are passed as the second argument to the `WebSocket` constructor
|
|
1463
|
+
* and participate in the RFC 6455 subprotocol negotiation. They are only
|
|
1464
|
+
* meaningful when the server requires a specific protocol (for example,
|
|
1465
|
+
* `['json']` or `['v1']` to select a message encoding version).
|
|
1466
|
+
*
|
|
1467
|
+
* @param protocols - Subprotocol list for the WebSocket constructor.
|
|
1468
|
+
* @returns An option that sets `config.webSocket.protocols`.
|
|
1469
|
+
*/
|
|
1470
|
+
export declare function withWebSocketProtocols(protocols: readonly string[]): ClientOption;
|
|
1471
|
+
/**
|
|
1472
|
+
* Enables WebSocket heartbeat pings and optional ACK detection.
|
|
1473
|
+
*
|
|
1474
|
+
* @param options - Heartbeat interval, payload, timeout, and ACK predicate.
|
|
1475
|
+
* @returns An option that sets `config.webSocket.heartbeat`.
|
|
1476
|
+
*/
|
|
1477
|
+
export declare function withWebSocketHeartbeat(options: ClientWebSocketOptions['heartbeat']): ClientOption;
|
|
1478
|
+
/**
|
|
1479
|
+
* Configures automatic WebSocket reconnection after unexpected closes.
|
|
1480
|
+
*
|
|
1481
|
+
* @param options - Retry budget, backoff, and `shouldReconnect` gate.
|
|
1482
|
+
* @returns An option that sets `config.webSocket.reconnect`.
|
|
1483
|
+
*/
|
|
1484
|
+
export declare function withWebSocketReconnect(options: ClientWebSocketOptions['reconnect']): ClientOption;
|
|
1485
|
+
/**
|
|
1486
|
+
* Handles WebSocket messages whose `type` has no matching incoming struct.
|
|
1487
|
+
*
|
|
1488
|
+
* JSON/Struct decode failures still go to `session.onRuntimeError`. Unknown types
|
|
1489
|
+
* do not tear down the session.
|
|
1490
|
+
*
|
|
1491
|
+
* @param handler - Observer callback; failures are isolated.
|
|
1492
|
+
* @returns An option that sets `config.webSocket.onInvalidEvent`.
|
|
1493
|
+
*/
|
|
1494
|
+
export declare function withWebSocketOnInvalidEvent(handler: ClientWebSocketOptions['onInvalidEvent']): ClientOption;
|
|
1495
|
+
/**
|
|
1496
|
+
* Handles SSE events that lack a matching struct or fail validation.
|
|
1497
|
+
*
|
|
1498
|
+
* @param handler - Callback for invalid events; may throw or return a value.
|
|
1499
|
+
* @returns An option that sets `config.sse.onInvalidEvent`.
|
|
1500
|
+
*/
|
|
1501
|
+
export declare function withSSEOnInvalidEvent(handler: ClientSSEOptions['onInvalidEvent']): ClientOption;
|
|
1502
|
+
/**
|
|
1503
|
+
* Configures automatic SSE reconnection after stream failures.
|
|
1504
|
+
*
|
|
1505
|
+
* @param options - Retry budget, backoff, and `shouldReconnect` gate.
|
|
1506
|
+
* @returns An option that sets `config.sse.reconnect`.
|
|
1507
|
+
*/
|
|
1508
|
+
export declare function withSSEReconnect(options: ClientSSEOptions['reconnect']): ClientOption;
|
|
1509
|
+
/**
|
|
1510
|
+
* Enables XSRF cookie-to-header token forwarding for HTTP requests.
|
|
1511
|
+
*
|
|
1512
|
+
* Defaults to cookie `XSRF-TOKEN` and header `X-XSRF-TOKEN` when names are omitted.
|
|
1513
|
+
*
|
|
1514
|
+
* @param options - Cookie/header names and optional token provider.
|
|
1515
|
+
* @returns An option that sets `config.xsrf`.
|
|
1516
|
+
*/
|
|
1517
|
+
export declare function withXSRF(options?: HttpClientOptions['xsrf']): ClientOption;
|
|
1518
|
+
/**
|
|
1519
|
+
* Sets whether HTTP/SSE requests should include credentials (cookies).
|
|
1520
|
+
*
|
|
1521
|
+
* @param value - When `true`, credentials are sent with cross-origin requests.
|
|
1522
|
+
* @returns An option that sets `config.withCredentials`.
|
|
1523
|
+
*/
|
|
1524
|
+
export declare function withCredentials(value: boolean): ClientOption;
|
|
1525
|
+
//#endregion
|
|
1526
|
+
//#region src/client/client.d.ts
|
|
182
1527
|
declare const CLIENT: unique symbol;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
1528
|
+
/**
|
|
1529
|
+
* Defjs client: holds config and `execute`s HTTP, SSE, and WebSocket commands.
|
|
1530
|
+
*/
|
|
1531
|
+
type Client = {
|
|
1532
|
+
readonly [CLIENT]: ClientConfig;
|
|
1533
|
+
/** Open an SSE command and return stream open/await results. */
|
|
1534
|
+
execute<TInput extends AnyStruct | undefined, TEvents extends EventStructs>(command: EventStreamCommand<TInput, TEvents>, options?: EventStreamExecuteOptions): Promise<StreamAwaitResult<EventStreamData<TEvents>>>;
|
|
1535
|
+
/** Open a WebSocket command and return session await results. */
|
|
1536
|
+
execute<TInput extends AnyStruct | undefined, TIncoming extends SocketStructs, TOutgoing extends SocketStructs | undefined>(command: WebSocketCommand<TInput, TIncoming, TOutgoing>, options?: WebSocketExecuteOptions<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>): Promise<SocketAwaitResult<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>>;
|
|
1537
|
+
/** Run an HTTP command and return an await-result tuple. */
|
|
1538
|
+
execute<TInput extends AnyStruct | undefined, TOutput extends RequestOutputShape | undefined>(command: HttpCommand<TInput, TOutput>, options?: HttpExecuteOptions): ReturnType<typeof executeHttpCommand<TInput, TOutput>>;
|
|
1539
|
+
};
|
|
1540
|
+
/**
|
|
1541
|
+
* Create a Defjs client from option helpers.
|
|
1542
|
+
*
|
|
1543
|
+
* Options are applied in order. Prefer creating the client inside the
|
|
1544
|
+
* request boundary when interceptors close over auth or tenants.
|
|
1545
|
+
*
|
|
1546
|
+
* @param options - Client option helpers such as `withEndpoint`.
|
|
1547
|
+
* @returns A client that can `execute` HTTP, SSE, and WebSocket commands.
|
|
1548
|
+
*
|
|
1549
|
+
* @example
|
|
1550
|
+
* ```ts
|
|
1551
|
+
* const client = createClient(withEndpoint('https://api.example.com'))
|
|
1552
|
+
* ```
|
|
1553
|
+
*/
|
|
1554
|
+
export declare function createClient(...options: ClientOption[]): Client;
|
|
1555
|
+
//#endregion
|
|
1556
|
+
//#region src/http/transport/fetch.d.ts
|
|
1557
|
+
/**
|
|
1558
|
+
* Default HTTP transport: perform `httpRequest` with `fetch` and return an `HttpResponse`.
|
|
1559
|
+
* Used by the client unless `withHTTPHandle` replaces it; also usable in tests and custom handlers.
|
|
1560
|
+
*
|
|
1561
|
+
* @param httpRequest - Normalized request (URL, headers, body, abort, progress hooks).
|
|
1562
|
+
* @param fetchImpl - Fetch implementation; defaults to global `fetch`.
|
|
1563
|
+
* @returns Parsed `HttpResponse`, or a status-0 response when the network/abort fails.
|
|
1564
|
+
*/
|
|
1565
|
+
export declare function fetchHandler(httpRequest: HttpRequest, fetchImpl?: FetchHandle): Promise<HttpResponse<unknown>>;
|
|
1566
|
+
//#endregion
|
|
1567
|
+
//#region src/internal/url.d.ts
|
|
1568
|
+
export declare function createResolvedRequestUrl(baseEndpoint: string, path: string, queryString?: string): URL;
|
|
1569
|
+
//#endregion
|
|
1570
|
+
//#region src/interceptor/basic_auth.d.ts
|
|
1571
|
+
type BasicCredential = {
|
|
1572
|
+
username: string;
|
|
1573
|
+
password: string;
|
|
1574
|
+
};
|
|
1575
|
+
/**
|
|
1576
|
+
* Options for basic-auth interceptors, including a custom credential encoder.
|
|
1577
|
+
*/
|
|
1578
|
+
type BasicAuthInterceptorOptions = {
|
|
1579
|
+
encode?: (credential: BasicCredential) => string;
|
|
1580
|
+
};
|
|
1581
|
+
/**
|
|
1582
|
+
* HTTP interceptor that sets an `Authorization: Basic …` header from credentials.
|
|
1583
|
+
*
|
|
1584
|
+
* @param fn - Factory returning username/password for each request.
|
|
1585
|
+
* @param options - Optional custom encoder (defaults to `btoa`).
|
|
1586
|
+
* @returns An `HttpInterceptor` that injects basic auth.
|
|
1587
|
+
*/
|
|
1588
|
+
export declare function basicAuthHttpInterceptor(fn: () => BasicCredential, options?: BasicAuthInterceptorOptions): HttpInterceptor;
|
|
1589
|
+
/**
|
|
1590
|
+
* SSE interceptor that sets an `Authorization: Basic …` header from credentials.
|
|
1591
|
+
*
|
|
1592
|
+
* @param fn - Factory returning username/password for each request.
|
|
1593
|
+
* @param options - Optional custom encoder (defaults to `btoa`).
|
|
1594
|
+
* @returns An `SSEInterceptor` that injects basic auth.
|
|
1595
|
+
*/
|
|
1596
|
+
export declare function basicAuthSSEInterceptor(fn: () => BasicCredential, options?: BasicAuthInterceptorOptions): SSEInterceptor;
|
|
1597
|
+
//#endregion
|
|
1598
|
+
export type { AnyStruct, BasicAuthInterceptorOptions, Client, ClientConfig, ClientOption, ClientOptions, ClientSSEConfig, ClientSSEOptions, ClientWebSocketOptions, ErrorMap, EventStreamCloseInfo, EventStreamErrorCode, EventStreamHandle, EventStreamOpenInfo, FetchHandle, FlattenedStructError, FormattedStructError, HttpInterceptor, HttpInterceptorNext, HttpProgressEvent, HttpProgressFn, HttpRequest, HttpResponse, HttpResponseType, Infer, Interceptor, InterceptorFn, MakeResponseOptions, ObjectStruct, ParseResult, QueryParamsSerializer, RequestOutputShape, RequestStruct, ResponseGroupItem, SSEHandler, SSEInterceptor, SSEInterceptorFn, Struct, StructInput, StructIssue, StructLike, StructMethods, WebSocketHandle, WebSocketHandleConstructor, WebSocketHandler, WebSocketInterceptor, WebSocketInterceptorFn, WebSocketSessionLike };
|