@defjs/core 0.4.0 → 0.6.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.
Files changed (5) hide show
  1. package/README.md +25 -71
  2. package/index.d.ts +387 -525
  3. package/index.js +742 -995
  4. package/index.min.js +20 -20
  5. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -37,8 +37,8 @@ interface HttpProgressEvent {
37
37
  * Callbacks may be async and are awaited before the next chunk is processed. A
38
38
  * callback that throws or rejects fails the call with `EXT_OBSERVER_FAILED`,
39
39
  * with the thrown value as `cause`, for downloads and uploads alike. Caller
40
- * cancellation and `timeout` still take precedence and report `NET_ABORTED` or
41
- * `NET_TIMEOUT`.
40
+ * cancellation still takes precedence and reports `NET_ABORTED`, or `NET_TIMEOUT`
41
+ * when the abort reason is a timeout.
42
42
  *
43
43
  * Upload progress for a `Blob`, `File`, `ArrayBuffer`, or `FormData` body is
44
44
  * reported only where the runtime can stream request bodies (Bun, Node). In
@@ -48,8 +48,8 @@ interface HttpProgressEvent {
48
48
  *
49
49
  * On server runtimes, FormData with `onUploadProgress` reads its serialized
50
50
  * stream directly, keeps its multipart boundary, and is sent without a
51
- * library-generated `Content-Length` (chunked over HTTP/1.1), so progress,
52
- * timeout, and abort work without buffering the whole body. It reports an
51
+ * library-generated `Content-Length` (chunked over HTTP/1.1), so progress
52
+ * and abort work without buffering the whole body. It reports an
53
53
  * unknown total unless a valid explicit `Content-Length` supplies it. For an
54
54
  * endpoint that requires `Content-Length`, such as some presigned upload
55
55
  * targets, omit `onUploadProgress`; platform Fetch then sends FormData with its
@@ -78,7 +78,7 @@ type HttpProgressFn = (event: HttpProgressEvent) => Promise<void> | void;
78
78
  * @group http
79
79
  */
80
80
  interface HttpRequest {
81
- abort?: AbortSignal;
81
+ signal?: AbortSignal;
82
82
  /** Trusted absolute base; its origin and directory bound the resolved endpoint path. */
83
83
  baseEndpoint?: string;
84
84
  body?: Blob | ArrayBuffer | FormData | URLSearchParams | ReadableStream<Uint8Array> | object | string | number | boolean | null;
@@ -111,7 +111,6 @@ interface HttpRequest {
111
111
  * unread and does not fall back to `responseType`.
112
112
  */
113
113
  readonly errorResponseType?: HttpResponseType;
114
- timeout?: number;
115
114
  uploadProgress?: HttpProgressFn;
116
115
  withCredentials?: boolean;
117
116
  xsrf?: {
@@ -501,7 +500,7 @@ interface PreservedStruct<T, I, O, OO extends boolean> extends Struct<I, O, OO>,
501
500
  /**
502
501
  * Broad struct constraint that accepts any struct, for endpoint and client generics.
503
502
  *
504
- * Used by generics such as `defineRequest`, `Fault`, and `HttpCommand`. Prefer a concrete `Struct<…>` when you need precise input and output inference.
503
+ * Used by generics such as `defineRequest` and `Fault`. Prefer a concrete `Struct<…>` when you need precise input and output inference.
505
504
  *
506
505
  * @group struct
507
506
  */
@@ -655,7 +654,7 @@ interface IntersectionStruct<T extends readonly StructLike<unknown, unknown, boo
655
654
  * | Class | Meaning |
656
655
  * | ------ | -------------------------------------------------------------- |
657
656
  * | `HTTP` | The peer answered with a non-2xx status. |
658
- * | `REQ` | The request never left: input, execute options, or build. |
657
+ * | `REQ` | The request never left: input, request options, or build. |
659
658
  * | `NET` | No usable response: cancel, timeout, connect, truncated body. |
660
659
  * | `RES` | A response arrived but could not be read as declared. |
661
660
  * | `EXT` | Code you attached to the pipeline threw. |
@@ -762,7 +761,7 @@ export type PreflightFault = Error & {
762
761
  response?: HttpMeta;
763
762
  };
764
763
  /**
765
- * Any failure returned by `client.execute`, expressed by its decoded error-body type.
764
+ * Any failure returned by an operation, expressed by its decoded error-body type.
766
765
  *
767
766
  * `Fault<TErr>` is `FaultOf` applied to `Infer<TErr>`, and `HttpAwaitResult` uses
768
767
  * `FaultOf<TErrorData>`. Pass a decoded type, not a struct: write
@@ -773,7 +772,7 @@ export type PreflightFault = Error & {
773
772
  */
774
773
  export type FaultOf<TData = undefined> = DecodeFault | HttpStatusFaultOf<TData> | PreflightFault;
775
774
  /**
776
- * Union of every failure `client.execute` can return, discriminated by `code`.
775
+ * Union of every failure an operation can return, discriminated by `code`.
777
776
  *
778
777
  * `Fault<TErr>` is {@link FaultOf} applied to the decoded body type, so it is the
779
778
  * union of {@link DecodeFault}, {@link HttpStatusFault}<TErr>, and
@@ -1380,7 +1379,7 @@ interface EventStreamMessage {
1380
1379
  /**
1381
1380
  * Metadata available once an SSE response has opened.
1382
1381
  *
1383
- * `response` is the handshake response and `url` is the resolved request URL. It is the third element of a successful `client.execute` result and the value of `EventStreamHandle.open`.
1382
+ * `response` is the handshake response and `url` is the resolved request URL. It is the third element of a successful event-stream result and the value of `EventStreamHandle.open`.
1384
1383
  *
1385
1384
  * @group sse
1386
1385
  */
@@ -1420,7 +1419,7 @@ type EventStreamCloseInfo = (EventStreamCloseInfoBase & {
1420
1419
  /**
1421
1420
  * Open SSE stream: iterate events, read open metadata, and close early.
1422
1421
  *
1423
- * `EventStreamMessage` is the raw `{ id: string; event: string; data: string }` message. Handles returned by `client.execute` carry parsed {@link EventStreamData}.
1422
+ * `EventStreamMessage` is the raw `{ id: string; event: string; data: string }` message. Handles returned by an event-stream operation carry parsed {@link EventStreamData}.
1424
1423
  *
1425
1424
  * `open` is the startup snapshot ({@link EventStreamOpenInfo}); after a reconnect it can change, so read `stream.open` again. `closed` resolves with an {@link EventStreamCloseInfo} when the stream ends.
1426
1425
  *
@@ -1443,16 +1442,8 @@ interface EventStreamHandle<TEvent = EventStreamMessage> extends AsyncIterable<T
1443
1442
  close(reason?: unknown): void;
1444
1443
  [Symbol.asyncDispose](): PromiseLike<void>;
1445
1444
  }
1446
- type UseCancellationConfig = {
1447
- abort?: AbortSignal;
1448
- timeout?: never;
1449
- } | {
1450
- abort?: never;
1451
- timeout?: number;
1452
- };
1453
- type EndpointInput<TInput extends AnyStruct | undefined> = TInput extends AnyStruct ? StructInput<TInput> : unknown;
1454
- type IsEndpointInputOptional<TInput extends AnyStruct | undefined> = [TInput] extends [undefined] ? true : undefined extends EndpointInput<TInput> ? true : false;
1455
- type EndpointCallable<TInput extends AnyStruct | undefined, TCommand> = [TInput] extends [undefined] ? () => TCommand : IsEndpointInputOptional<TInput> extends true ? (input?: EndpointInput<TInput>) => TCommand : (input: EndpointInput<TInput>) => TCommand;
1445
+ /** Argument list after the client, decided by the input struct. */
1446
+ type EndpointArgs<S extends AnyStruct | undefined> = [S] extends [undefined] ? [] : undefined extends StructInput<S> ? [input?: StructInput<S>] : [input: StructInput<S>];
1456
1447
  /** Object produced by endpoint input parsing. The symbol points at the struct that produced the node. */
1457
1448
  type Typed = {
1458
1449
  readonly [STRUCT]: AnyStruct;
@@ -1570,359 +1561,14 @@ type BuilderInput<S> = S extends CarriedStruct<infer Inner> ? NullishBuilderInpu
1570
1561
  [key: string]: BuilderInput<Value>;
1571
1562
  } : S extends TupleStruct<infer Items> ? { [K in keyof Items]: Items[K] extends StructLike<unknown, unknown, boolean> ? BuilderInput<Items[K]> : Items[K]; } : S extends ArrayStruct<infer Item> ? BuilderInput<Item>[] : S extends ObjectStruct<infer Shape> ? { [K in keyof Shape]: BuilderInput<Shape[K]>; } & Typed : Infer<S>;
1572
1563
  type BuilderField<TInput, TShape> = [TInput] extends [undefined] ? {
1573
- /** Pure, synchronous request builder, evaluated when the command runs. Optional without input. */
1564
+ /** Pure, synchronous request builder, evaluated when the operation runs. Optional without input. */
1574
1565
  builder?: () => TShape;
1575
1566
  } : {
1576
- /** Pure, synchronous function that explicitly places parsed input on the request when the command runs. */
1567
+ /** Pure, synchronous function that explicitly places parsed input on the request when the operation runs. */
1577
1568
  builder: (input: BuilderInput<TInput>) => TShape;
1578
1569
  };
1579
1570
  /** Accepts any concrete builder. `never` keeps the parameter contravariant. */
1580
1571
  type OutboundBuilder = (input: never) => unknown;
1581
- /**
1582
- * Per-request options for HTTP execution: progress callbacks and cancellation.
1583
- *
1584
- * The HTTP-specific part of {@link HttpExecuteOptions}, which adds `signal`.
1585
- * `onDownloadProgress` and `onUploadProgress` are {@link HttpProgressFn}
1586
- * callbacks. They receive an {@link HttpProgressEvent} with `loaded`, `total`,
1587
- * and `lengthComputable`.
1588
- *
1589
- * Cancellation is either `abort` or `timeout`, never both. The type rejects
1590
- * both, and at runtime passing both fails with a `REQ_OPTIONS_INVALID` fault.
1591
- * `timeout` must be a positive safe integer no greater than `2_147_483_647`.
1592
- * It replaces the default set by {@link withTimeout} for that call. `abort`
1593
- * combines with that default instead.
1594
- *
1595
- * @group http
1596
- */
1597
- export type UseRequestConfig = {
1598
- onDownloadProgress?: HttpProgressFn;
1599
- onUploadProgress?: HttpProgressFn;
1600
- } & UseCancellationConfig;
1601
- /**
1602
- * Opaque executable HTTP command produced by a `defineRequest` endpoint.
1603
- *
1604
- * Created by calling a `RequestEndpoint` with input. It carries the request
1605
- * definition and optional typed input for `client.execute`. Treat it as opaque
1606
- * and pass it to `client.execute`.
1607
- *
1608
- * @group http
1609
- */
1610
- export interface HttpCommand<TInput extends AnyStruct | undefined, TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined = undefined> extends BaseCommand<typeof HTTP_COMMAND> {
1611
- readonly definition: RequestDefinition<TInput, TOutput, TError>;
1612
- readonly input: EndpointInput<TInput> | undefined;
1613
- }
1614
- /**
1615
- * Options passed to `client.execute` or `executeHttpCommand` for one HTTP call: progress, `abort` or `timeout`, and `signal`.
1616
- *
1617
- * Cancellation is `abort` or `timeout`, not both (`abort` XOR `timeout`).
1618
- * `signal` combines with either; it is not an alias for `abort`. Valid shapes:
1619
- * `{ timeout }`, `{ abort }`, `{ signal, timeout }`, `{ signal, abort }`.
1620
- * `{ abort, timeout }` is invalid and makes the call resolve with a
1621
- * `REQ_OPTIONS_INVALID` fault. `timeout` must be a positive safe integer in
1622
- * `1..2_147_483_647`.
1623
- *
1624
- * When `timeout` is omitted, the client's `withTimeout` default applies;
1625
- * `abort` combines with that default.
1626
- *
1627
- * @group http
1628
- */
1629
- export type HttpExecuteOptions = UseRequestConfig & {
1630
- signal?: AbortSignal;
1631
- };
1632
- /**
1633
- * Callable endpoint returned by `defineRequest`.
1634
- *
1635
- * Call it to get an `HttpCommand`: with no arguments when the endpoint declares
1636
- * no `input`, with an optional argument when the input struct accepts
1637
- * `undefined`, and otherwise with the struct's input value.
1638
- *
1639
- * @group http
1640
- */
1641
- export type RequestEndpoint<TInput extends AnyStruct | undefined, TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined = undefined> = EndpointCallable<TInput, HttpCommand<TInput, TOutput, TError>>;
1642
- type DeclaredBody<TStruct> = [TStruct] extends [undefined] ? undefined : Infer<TStruct>;
1643
- type DeclaredResponse<TStruct> = [TStruct] extends [undefined] ? HttpMeta : DecodedResponse<Infer<TStruct>>;
1644
- /**
1645
- * Decoded success body for the declared `output` struct, or `undefined` when none is declared.
1646
- *
1647
- * @group http
1648
- */
1649
- export type RequestSuccessData<TOutput extends AnyStruct | undefined> = DeclaredBody<TOutput>;
1650
- /**
1651
- * Decoded error body for the declared `error` struct, or `undefined` when none is declared.
1652
- *
1653
- * @group http
1654
- */
1655
- export type RequestErrorData<TError extends AnyStruct | undefined> = DeclaredBody<TError>;
1656
- type ResponseDeclaration<TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined> = ([TOutput] extends [undefined] ? {
1657
- output?: never;
1658
- } : {
1659
- output: TOutput;
1660
- }) & ([TError] extends [undefined] ? {
1661
- error?: never;
1662
- } : {
1663
- error: TError;
1664
- });
1665
- /**
1666
- * Contract for an HTTP endpoint: method, path, optional input, and the structs that decode its bodies.
1667
- *
1668
- * Declaring `input` requires an explicit `builder` to place the parsed value on
1669
- * the request. `input` only defines the parameters; the builder alone decides
1670
- * where each value goes. Only definitions without `input` may omit `builder`.
1671
- * `output` declares the body for a 2xx response, `error` the body for anything
1672
- * else. Only one of the two ever runs, and omitting one means that body is never
1673
- * read. `ResponseDeclaration` is an internal helper type: `output` and `error`
1674
- * are required only when the matching type parameter is a struct. There is no
1675
- * `responseType`: the struct kind selects how a declared body is read. Pass to
1676
- * `defineRequest` to get a typed endpoint.
1677
- *
1678
- * @group http
1679
- */
1680
- export type RequestDefinition<TInput extends AnyStruct | undefined = undefined, TOutput extends AnyStruct | undefined = undefined, TError extends AnyStruct | undefined = undefined> = ResponseDeclaration<TOutput, TError> & {
1681
- builder?: OutboundBuilder;
1682
- input?: TInput;
1683
- method: string;
1684
- operation?: string;
1685
- path: string;
1686
- };
1687
- /**
1688
- * Await-result tuple for an HTTP call: success is `[null, data, response]`, and failure is `[fault, undefined, undefined]`.
1689
- *
1690
- * `TData` and `TErrorData` are decoded body types. On success the third slot
1691
- * carries `body` only when `output` was declared. On failure it is `undefined`,
1692
- * because the fault already holds whatever response metadata existed.
1693
- *
1694
- * @group http
1695
- */
1696
- export type HttpAwaitResult<TData = undefined, TErrorData = undefined> = [error: null, result: TData, response: [TData] extends [undefined] ? HttpMeta : DecodedResponse<TData>] | [error: FaultOf<TErrorData>, result: undefined, response: undefined];
1697
- type HttpExecuteAwaitResult<TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined> = [error: null, result: RequestSuccessData<TOutput>, response: DeclaredResponse<TOutput>] | [error: Fault<TError>, result: undefined, response: undefined];
1698
- /**
1699
- * Declares a typed HTTP request endpoint.
1700
- *
1701
- * Pass method, path, an optional input struct, and the single `output` and
1702
- * `error` structs. Call the returned endpoint with input to get an `HttpCommand`
1703
- * for `client.execute`.
1704
- *
1705
- * The contract is `method`, `path`, an optional `input` struct, optional
1706
- * `output` and `error` structs, and an optional `operation`. A declared `input`
1707
- * always requires an explicit `builder`. `input` only defines the parameters;
1708
- * the builder alone decides where each value goes. Only definitions without
1709
- * `input` may omit `builder`. `ResponseDeclaration` and `BuilderField` are
1710
- * internal helper types: `output` and `error` are required only when the
1711
- * matching type parameter is a struct, and `builder` is
1712
- * `(input: BuilderInput<TInput>) => HttpRequestShape` when `input` is declared.
1713
- *
1714
- * `output` is one struct for the 2xx body; `error` is one struct for every
1715
- * non-2xx body. Neither is keyed by status. A declaration is an assertion:
1716
- * omitting one means that body is never read.
1717
- *
1718
- * @param definition - Request contract (method, path, input, builder, output).
1719
- * @returns An endpoint that creates `HttpCommand` values from input.
1720
- *
1721
- * The checked example file passes the whole input object as `path`. This snippet maps individual fields into `path` and `query` instead:
1722
- *
1723
- * @example
1724
- * ```ts
1725
- * const getUser = defineRequest({
1726
- * method: 'GET',
1727
- * path: '/users/:id',
1728
- * input: struct.object({ id: struct.number(), verbose: struct.boolean() }),
1729
- * builder: (input) => ({ path: { id: input.id }, query: { verbose: input.verbose } }),
1730
- * output: struct.object({ id: struct.number(), name: struct.string() }),
1731
- * })
1732
- * ```
1733
- * @group http
1734
- * @exampleFile examples/api/define-request.ts#example
1735
- */
1736
- export declare function defineRequest<const M extends string, const P extends string, TInput extends AnyStruct | undefined = undefined, TOutput extends AnyStruct | undefined = undefined, TError extends AnyStruct | undefined = undefined>(definition: ResponseDeclaration<TOutput, TError> & {
1737
- input?: TInput;
1738
- method: M;
1739
- operation?: string;
1740
- path: P;
1741
- } & BuilderField<NoInfer<TInput>, HttpRequestShape<NoInfer<P>, NoInfer<M>>>): RequestEndpoint<TInput, TOutput, TError>;
1742
- /**
1743
- * Runs an `HttpCommand` against client config: validate input, send the request, and parse the response.
1744
- *
1745
- * Low-level entry used by `client.execute`. Prefer `client.execute(command, options)`
1746
- * in application code. `HttpClientConfig` is the HTTP part of `ClientConfig`, so
1747
- * a `ClientConfig` is accepted. `HttpExecuteAwaitResult` is the internal result
1748
- * tuple.
1749
- *
1750
- * The result is `[null, data, response]` or `[fault, undefined, undefined]`.
1751
- * `data` is the decoded `output` body, or `undefined` when none is declared.
1752
- * `response` is `DecodedResponse` when `output` is declared and `HttpMeta`
1753
- * otherwise. The fault is `Fault<TError>`. A non-2xx status is `HTTP_STATUS`
1754
- * when no `error` struct is declared (its `data` is `undefined`) or when the
1755
- * declared body decodes (its `data` is that body). When a declared `error` body
1756
- * cannot be read, the fault is a `RES_*` decode fault instead. On failure the
1757
- * tuple's third slot is `undefined`; the fault carries the response metadata.
1758
- * `options.timeout` falls back to the client's `withTimeout` default when omitted.
1759
- *
1760
- * @param clientConfig - Resolved HTTP client configuration (endpoint, interceptors, handler).
1761
- * @param command - Command from a `defineRequest` endpoint.
1762
- * @param options - Per-request progress and cancellation options.
1763
- * @returns An await-result tuple of success body or typed request error.
1764
- * @group http
1765
- */
1766
- export declare function executeHttpCommand<TInput extends AnyStruct | undefined, TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined>(clientConfig: HttpClientConfig, command: HttpCommand<TInput, TOutput, TError>, options?: HttpExecuteOptions): Promise<HttpExecuteAwaitResult<TOutput, TError>>;
1767
- /**
1768
- * Map from SSE event names to the structs that decode their data.
1769
- *
1770
- * An event with no `event:` field is named `message`. An event whose name has no own entry uses the `default` struct; with neither, the event is skipped and `onInvalidEvent` is called. Declare the event name `__proto__` with a computed own key.
1771
- *
1772
- * A `string` event struct keeps the raw `data` text. Every other kind is JSON text: `JSON.parse`, then the struct. A bare `struct.literal` therefore needs JSON text, not an unquoted token.
1773
- *
1774
- * Reconnect lives on the client (`withSSEReconnect`). SSE `jitter` is a **0-1 multiplicative factor**, same as WebSocket.
1775
- *
1776
- * @group sse
1777
- */
1778
- export type EventStructs = {
1779
- [key: string]: AnyStruct;
1780
- };
1781
- type EventName<TKey extends string | number> = `${TKey}`;
1782
- type KnownEventUnion<TEvents extends EventStructs> = { [K in keyof TEvents & (number | string)]: EventName<K> extends "default" ? never : {
1783
- data: Infer<TEvents[K]>;
1784
- event: EventName<K>;
1785
- id?: string;
1786
- }; }[keyof TEvents & (number | string)];
1787
- type DefaultEventUnion<TEvents extends EventStructs> = "default" extends keyof TEvents ? {
1788
- data: Infer<TEvents["default"]>;
1789
- event: string;
1790
- id?: string;
1791
- } : never;
1792
- /**
1793
- * Union of parsed SSE events inferred from an EventStructs map.
1794
- *
1795
- * For each declared event name except `default`, the union has `{ event: <name>; data: Infer<TEvents[name]>; id?: string }`. When a `default` struct is declared, it adds `{ event: string; data: Infer<TEvents['default']>; id?: string }` for every event name that has no struct of its own. `KnownEventUnion` and `DefaultEventUnion` are internal helper types.
1796
- *
1797
- * @group sse
1798
- */
1799
- export type EventStreamData<TEvents extends EventStructs> = TEvents extends EventStructs ? KnownEventUnion<TEvents> | DefaultEventUnion<TEvents> : never;
1800
- interface EventStreamDefinitionBase<TEvents extends EventStructs = EventStructs> {
1801
- events: TEvents;
1802
- maxBufferSize: number;
1803
- maxQueueSize: number;
1804
- method?: string;
1805
- operation?: string;
1806
- path: string;
1807
- }
1808
- /** Makes `error` required only when an error struct is declared, so omission stays `Fault<undefined>`. */
1809
- type EventStreamErrorField<TError extends AnyStruct | undefined> = [TError] extends [undefined] ? {
1810
- error?: never;
1811
- } : {
1812
- error: TError;
1813
- };
1814
- /**
1815
- * Contract that describes an SSE endpoint for defineEventStream.
1816
- *
1817
- * The composed members are:
1818
- *
1819
- * - `events`, `maxBufferSize`, and `maxQueueSize` (both limits are required positive safe integers), optional `method`, `operation`, and a required `path`.
1820
- *
1821
- * - `error`, required only when `TError` is a struct. It decodes the body of a failed handshake (a non-2xx response). The kind rule is the same as for HTTP: `string` is text, `blob` and `file` are blobs, `arrayBuffer` is bytes, and everything else is JSON.
1822
- *
1823
- * - `input` and `builder`. The request shape matches HTTP, including `body`; `GET` and `HEAD` cannot return a body. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`.
1824
- *
1825
- * `EventStreamDefinitionBase` and `EventStreamErrorField` are internal helper types.
1826
- *
1827
- * @group sse
1828
- */
1829
- export type EventStreamDefinition<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs, TError extends AnyStruct | undefined = undefined> = EventStreamDefinitionBase<TEvents> & EventStreamErrorField<TError> & {
1830
- builder?: OutboundBuilder;
1831
- input?: TInput;
1832
- };
1833
- /**
1834
- * Await-result tuple from opening an SSE stream via `client.execute`.
1835
- *
1836
- * - On success: `[null, stream, open]`. `open` is the returned connection's first successful handshake snapshot for native Defjs handles or wrappers forwarding the same live `open` object; custom handles or wrappers overriding `open` use their current public `open` even after reconnect, while `stream.open` stays live.
1837
- *
1838
- * - On failure: `[fault, undefined, open]`. `open` carries the response snapshot when the failure happened after a response arrived, for example a non-2xx handshake, and is `undefined` otherwise.
1839
- *
1840
- * - `TError` is the declared `error` struct. It types the decoded error body on the fault.
1841
- *
1842
- * @group sse
1843
- */
1844
- export type StreamAwaitResult<TEvent, TError extends AnyStruct | undefined = undefined> = [error: null, stream: EventStreamHandle<TEvent>, open: EventStreamOpenInfo] | [error: Fault<TError>, stream: undefined, open: EventStreamOpenInfo | undefined];
1845
- /**
1846
- * Opaque executable SSE command produced by an `EventStreamEndpoint`.
1847
- *
1848
- * Created by calling an `EventStreamEndpoint` with input. It also has internal symbol-keyed members that identify and run the command. Treat it as opaque and pass it to `client.execute`. `endpoint` is the definition plus `method`, which is always a string (it defaults to `'GET'` when the definition omits it). `ResolvedEventStreamDefinition` names that shape and is not exported.
1849
- *
1850
- * @group sse
1851
- */
1852
- export interface EventStreamCommand<TInput extends AnyStruct | undefined, TEvents extends EventStructs, TError extends AnyStruct | undefined = undefined> extends BaseCommand<typeof EVENT_STREAM_COMMAND> {
1853
- readonly endpoint: ResolvedEventStreamDefinition<TInput, TEvents, TError>;
1854
- readonly input: EndpointInput<TInput> | undefined;
1855
- }
1856
- /**
1857
- * Per-call options for opening an SSE stream: abort or timeout, plus an optional signal.
1858
- *
1859
- * Cancellation is `abort` **or** `timeout`, not both; passing both makes the call resolve with a `REQ_OPTIONS_INVALID` fault. `signal` combines with either and is not an alias for `abort`. `timeout` must be a positive safe integer up to 2147483647.
1860
- *
1861
- * For SSE, `timeout` is a startup deadline. It covers input parsing, the builder, the interceptors, and opening the connection, and stops applying once the stream is open. The client-level `withTimeout` default does not apply to SSE.
1862
- *
1863
- * @group sse
1864
- */
1865
- export type EventStreamExecuteOptions = UseCancellationConfig & {
1866
- signal?: AbortSignal;
1867
- };
1868
- /**
1869
- * Callable endpoint returned by defineEventStream.
1870
- *
1871
- * Returned by `defineEventStream`. Call it to get an `EventStreamCommand`: with no arguments when the endpoint declares no `input`, with an optional argument when the input struct accepts `undefined`, and otherwise with the struct's input value.
1872
- *
1873
- * @group sse
1874
- */
1875
- export type EventStreamEndpoint<TInput extends AnyStruct | undefined, TEvents extends EventStructs, TError extends AnyStruct | undefined = undefined> = EndpointCallable<TInput, EventStreamCommand<TInput, TEvents, TError>>;
1876
- type ResolvedEventStreamDefinition<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs, TError extends AnyStruct | undefined = undefined> = EventStreamDefinition<TInput, TEvents, TError> & {
1877
- readonly method: string;
1878
- };
1879
- /**
1880
- * Declare a typed Server-Sent Events endpoint.
1881
- *
1882
- * Pass path, event structs, and buffer/queue limits. Call the returned endpoint
1883
- * with input to get an `EventStreamCommand` for `client.execute`.
1884
- *
1885
- * - **definition** — `path`, an `events` map, and the required `maxBufferSize` and `maxQueueSize` limits (positive safe integers). Optional `method` (default `'GET'`), `operation`, `input`, and `error`. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`.
1886
- *
1887
- * `EventStreamDefinitionBase`, `EventStreamErrorField`, and `BuilderField` are internal helper types: `error` is required only when `TError` is a struct, and `builder` is `(input: BuilderInput<TInput>) => EventStreamRequestShape` when `input` is declared.
1888
- *
1889
- * @param definition - SSE contract (path, events, buffer limits, optional input).
1890
- * @returns An endpoint that creates `EventStreamCommand` values from input.
1891
- *
1892
- * @group sse
1893
- * @exampleFile examples/api/define-event-stream.ts#example
1894
- */
1895
- export declare function defineEventStream<const P extends string, const M extends string = "GET", TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs, TError extends AnyStruct | undefined = undefined>(definition: Omit<EventStreamDefinitionBase<TEvents>, "method" | "path"> & EventStreamErrorField<TError> & {
1896
- input?: TInput;
1897
- method?: M;
1898
- path: P;
1899
- } & BuilderField<NoInfer<TInput>, EventStreamRequestShape<NoInfer<P>, NoInfer<M>>>): EventStreamEndpoint<TInput, TEvents, TError>;
1900
- /**
1901
- * Open an SSE command against the given client config.
1902
- *
1903
- * Prefer `client.execute(command)` in application code; this is the low-level entry used by the client.
1904
- *
1905
- * The result is `[null, stream, open]` or `[fault, undefined, open | undefined]`. The fault is `Fault<TError>`: the decoded handshake body is on `data` when `error` is declared, and `Fault<undefined>` otherwise.
1906
- *
1907
- * @param clientConfig - Resolved client configuration.
1908
- * @param command - SSE command from an `EventStreamEndpoint`.
1909
- * @param options - Optional execute options (abort, timeout).
1910
- * @returns Await-result tuple of `[error, stream, open]`.
1911
- * @group sse
1912
- */
1913
- export declare function executeEventStreamCommand<TInput extends AnyStruct | undefined, TEvents extends EventStructs, TError extends AnyStruct | undefined = undefined>(clientConfig: ClientConfig, command: EventStreamCommand<TInput, TEvents, TError>, options?: EventStreamExecuteOptions): Promise<StreamAwaitResult<EventStreamData<TEvents>, TError>>;
1914
- declare const COMMAND_TYPE: unique symbol;
1915
- declare const HTTP_COMMAND: unique symbol;
1916
- declare const EVENT_STREAM_COMMAND: unique symbol;
1917
- declare const WEB_SOCKET_COMMAND: unique symbol;
1918
- /** The command's own runner, so `client.execute` never imports a transport the app does not use. */
1919
- declare const COMMAND_EXECUTE: unique symbol;
1920
- type CommandExecutor = (config: ClientConfig, command: never, options?: never) => Promise<unknown>;
1921
- type CommandType = typeof HTTP_COMMAND | typeof EVENT_STREAM_COMMAND | typeof WEB_SOCKET_COMMAND;
1922
- interface BaseCommand<TCommandType extends CommandType> {
1923
- readonly [COMMAND_EXECUTE]: CommandExecutor;
1924
- readonly [COMMAND_TYPE]: TCommandType;
1925
- }
1926
1572
  interface WebSocketCloseSnapshot {
1927
1573
  cause?: unknown;
1928
1574
  code?: number;
@@ -1940,7 +1586,7 @@ interface WebSocketCloseSnapshot {
1940
1586
  * | `reconnecting` | Preparing or waiting for a replacement socket after a close |
1941
1587
  * | `closing` | Closure was requested with `session.close()` or disposal |
1942
1588
  * | `closed` | Terminal: the session ended without an error or cancellation |
1943
- * | `aborted` | Terminal: the session was cancelled through `abort` or `signal` |
1589
+ * | `aborted` | Terminal: the session was cancelled through `signal` |
1944
1590
  * | `error` | Terminal: the session failed, including a startup failure or `timeout` |
1945
1591
  *
1946
1592
  * Observe it with `session.state` and `session.onStateChange`.
@@ -1982,13 +1628,13 @@ interface WebSocketDefinitionBase<TIncoming extends AnyStruct = AnyStruct, TOutg
1982
1628
  *
1983
1629
  * - `maxIncomingQueueSize` is required and must be a positive safe integer. `maxOutgoingQueueSize` must be a non-negative safe integer; it defaults to `0`, which disables queueing of messages sent while the session is `reconnecting`.
1984
1630
  *
1985
- * - `protocols` is the static default subprotocol list. The `protocols` execute option and {@link withWebSocketProtocols} override it.
1631
+ * - `protocols` is the static default subprotocol list. `RequestOptions.protocols` and {@link withWebSocketProtocols} override it.
1986
1632
  *
1987
1633
  * - `operation` is a static, low-cardinality name for telemetry.
1988
1634
  *
1989
- * - `input` is the struct for the command input. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`. The builder may return `path` and `query` only; see {@link WebSocketRequestShape}.
1635
+ * - `input` is the struct for the operation input. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`. The builder may return `path` and `query` only; see {@link WebSocketRequestShape}.
1990
1636
  *
1991
- * Invalid queue limits are reported when the command executes, as a `REQ_OPTIONS_INVALID` fault.
1637
+ * Invalid queue limits are reported when the operation runs, as a `REQ_OPTIONS_INVALID` fault.
1992
1638
  *
1993
1639
  * @group web-socket
1994
1640
  */
@@ -2005,7 +1651,7 @@ export type WebSocketDefinition<TInput extends AnyStruct | undefined = undefined
2005
1651
  *
2006
1652
  * - `generation` counts the physical sockets that reached `open`: `1` after the first open, one more after each reconnect. A snapshot taken before any open has `0`.
2007
1653
  *
2008
- * `session.connection` exposes the session's current public connection info. The `connection` in the execute result preserves the first successful snapshot only for a native Defjs session or a wrapper forwarding the same live `connection` object. Custom sessions and wrappers that transform `connection` instead return their current public `connection`. Sharing `closed` cannot bypass URL sanitization or metadata filtering, and Defjs does not reconstruct first-connection metadata from arbitrary transformations.
1654
+ * `session.connection` exposes the session's current public connection info. The `connection` in the operation result preserves the first successful snapshot only for a native Defjs session or a wrapper forwarding the same live `connection` object. Custom sessions and wrappers that transform `connection` instead return their current public `connection`. Sharing `closed` cannot bypass URL sanitization or metadata filtering, and Defjs does not reconstruct first-connection metadata from arbitrary transformations.
2009
1655
  *
2010
1656
  * @group web-socket
2011
1657
  */
@@ -2093,7 +1739,7 @@ export interface WebSocketSession<TIncoming = unknown, TOutgoing = never> extend
2093
1739
  send(message: TOutgoing): void;
2094
1740
  }
2095
1741
  /**
2096
- * Await-result tuple from opening a WebSocket via `client.execute`.
1742
+ * Await-result tuple from opening a WebSocket.
2097
1743
  *
2098
1744
  * - On success: `[null, session, connection]`. `session.connection` moves forward on reconnect. The tuple's `connection` preserves the first successful snapshot only for a native Defjs session or a wrapper forwarding the same live `connection` object. Custom sessions and wrappers that transform `connection` instead return their current public `connection`. Sharing `closed` cannot bypass URL sanitization or metadata filtering, and Defjs does not reconstruct first-connection metadata from arbitrary transformations.
2099
1745
  *
@@ -2111,83 +1757,33 @@ interface UseWebSocketBaseConfig<TIncoming = unknown, TOutgoing = unknown> {
2111
1757
  reconnect?: ClientWebSocketOptions["reconnect"];
2112
1758
  }
2113
1759
  /**
2114
- * WebSocket execute options without signal.
1760
+ * WebSocket fields of {@link RequestOptions}, plus `signal`.
2115
1761
  *
2116
- * The WebSocket-specific part of {@link WebSocketExecuteOptions}, which adds `signal`.
1762
+ * `beforeConnect`, `heartbeat`, `protocols`, and `reconnect` override the client-level options for one call. `signal` covers the whole session, including after it opens. There is no startup-only deadline and no `abort` field.
2117
1763
  *
2118
- * - `beforeConnect`, `heartbeat`, `protocols`, and `reconnect` override the client-level options for one call.
1764
+ * @group web-socket
1765
+ */
1766
+ export type UseWebSocketConfig<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketBaseConfig<TIncoming, TOutgoing> & {
1767
+ /** Aborts the session, including after it is open. */
1768
+ signal?: AbortSignal;
1769
+ };
1770
+ /**
1771
+ * WebSocket fields read from {@link RequestOptions} for one call.
2119
1772
  *
2120
- * - Cancellation is either `abort` or `timeout`, never both. The type rejects both, and at runtime passing both fails with a `REQ_OPTIONS_INVALID` fault.
1773
+ * See {@link UseWebSocketConfig}. `heartbeat` callbacks are not inferred from the operation; narrow `unknown` messages yourself.
2121
1774
  *
2122
1775
  * @group web-socket
1776
+ * @see {@link WebSocketHeartbeatConfig}
2123
1777
  */
2124
- export type UseWebSocketConfig<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketBaseConfig<TIncoming, TOutgoing> & UseCancellationConfig;
1778
+ export type WebSocketExecuteOptions<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketConfig<TIncoming, TOutgoing>;
2125
1779
  /**
2126
- * Per-call options for executing a WebSocket command.
1780
+ * Operation returned by `defineWebSocket`.
2127
1781
  *
2128
- * {@link UseWebSocketConfig} plus `signal`. Expanded:
2129
- *
2130
- * ```ts
2131
- * type WebSocketExecuteOptions<TIncoming = unknown, TOutgoing = unknown> = {
2132
- * beforeConnect?: (context: {
2133
- * attempt: number;
2134
- * signal: AbortSignal;
2135
- * }) => void | Promise<void>;
2136
- * heartbeat?: WebSocketHeartbeatConfig<TIncoming, TOutgoing>;
2137
- * protocols?: readonly string[];
2138
- * reconnect?: ClientWebSocketOptions["reconnect"];
2139
- * signal?: AbortSignal;
2140
- * } & (
2141
- * { abort?: AbortSignal; timeout?: never } | { abort?: never; timeout?: number }
2142
- * );
2143
- * ```
2144
- *
2145
- * - `abort` and `timeout` are mutually exclusive. The type rejects both, and at runtime passing both fails with a `REQ_OPTIONS_INVALID` fault.
2146
- *
2147
- * - `signal` combines with either one; it is not an alias for `abort`.
2148
- *
2149
- * - `timeout` must be a positive safe integer no greater than `2_147_483_647`. It limits how long opening the session may take and is not applied again on reconnect.
2150
- *
2151
- * - `beforeConnect`, `heartbeat`, `protocols`, and `reconnect` override the client-level options for this call.
2152
- *
2153
- * - When `reconnect` is set, `attempts` defaults to `3` per outage; `0` disables. Successful `open` resets the budget and backoff exponent. Omitting `attempts` does not give unlimited retries within one outage. See {@link withWebSocketReconnect} for validation and final delay caps.
2154
- *
2155
- * See {@link WebSocketHeartbeatConfig}.
1782
+ * The first argument is a {@link Client}. Further arguments are the input only. Calling it opens the session and returns the existing error-first tuple.
2156
1783
  *
2157
1784
  * @group web-socket
2158
1785
  */
2159
- export type WebSocketExecuteOptions<TIncoming = unknown, TOutgoing = unknown> = UseWebSocketConfig<TIncoming, TOutgoing> & {
2160
- signal?: AbortSignal;
2161
- };
2162
- /**
2163
- * Executable command created by calling a WebSocketEndpoint.
2164
- *
2165
- * Created by calling a {@link WebSocketEndpoint}. It holds the endpoint definition and the unparsed input. Pass it to `client.execute` to open a session; nothing connects until then.
2166
- *
2167
- * `BaseCommand` carries symbol-keyed members that route the command to the right transport. They are internal, so treat the command as opaque.
2168
- *
2169
- * @group web-socket
2170
- */
2171
- export interface WebSocketCommand<TInput extends AnyStruct | undefined, TIncoming extends AnyStruct, TOutgoing extends AnyStruct | undefined> extends BaseCommand<typeof WEB_SOCKET_COMMAND> {
2172
- readonly endpoint: WebSocketDefinition<TInput, TIncoming, TOutgoing>;
2173
- readonly input: EndpointInput<TInput> | undefined;
2174
- }
2175
- /**
2176
- * Callable returned by defineWebSocket.
2177
- *
2178
- * Returned by {@link defineWebSocket}. Calling it creates a {@link WebSocketCommand} that you pass to `client.execute`. The call signature depends on `input`:
2179
- *
2180
- * - No `input` declared: `() => WebSocketCommand`.
2181
- *
2182
- * - `input` accepts `undefined`: `(input?: StructInput<TInput>) => WebSocketCommand`.
2183
- *
2184
- * - Otherwise: `(input: StructInput<TInput>) => WebSocketCommand`.
2185
- *
2186
- * Calling the endpoint does not connect. The input is parsed when the command is executed.
2187
- *
2188
- * @group web-socket
2189
- */
2190
- export type WebSocketEndpoint<TInput extends AnyStruct | undefined, TIncoming extends AnyStruct, TOutgoing extends AnyStruct | undefined> = EndpointCallable<TInput, WebSocketCommand<TInput, TIncoming, TOutgoing>>;
1786
+ export type WebSocketEndpoint<Args extends unknown[], Incoming, Outgoing = never> = (client: Client, ...args: Args) => Promise<SocketAwaitResult<Incoming, Outgoing>>;
2191
1787
  /**
2192
1788
  * Close code and reason recorded when a session is closed with session.close.
2193
1789
  *
@@ -2215,7 +1811,7 @@ export type ManualSocketCloseReason = {
2215
1811
  *
2216
1812
  * - `intervalMs` and `timeoutMs` must be positive, finite, and at most `2_147_483_647`.
2217
1813
  *
2218
- * Set it with {@link withWebSocketHeartbeat} or the `heartbeat` execute option.
1814
+ * Set it with {@link withWebSocketHeartbeat} or the `heartbeat` request option.
2219
1815
  *
2220
1816
  * @group web-socket
2221
1817
  */
@@ -2229,14 +1825,14 @@ export interface WebSocketHeartbeatConfig<TIncoming = unknown, TOutgoing = unkno
2229
1825
  * Declare a typed WebSocket endpoint.
2230
1826
  *
2231
1827
  * Pass path, incoming (and optional outgoing) message structs, and queue limits.
2232
- * Call the returned endpoint with input to get a `WebSocketCommand` for `client.execute`.
1828
+ * Call the returned operation with a client and, when declared, the input.
2233
1829
  *
2234
1830
  * - **definition** — `path`, one `incoming` struct, and the required `maxIncomingQueueSize` (a positive safe integer). Optional `outgoing` and `input` structs, static `protocols`, `maxOutgoingQueueSize` (a non-negative safe integer), and `operation`. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`.
2235
1831
  *
2236
1832
  * A WebSocket `builder` may return `path` and `query` only; `headers` and `body` are rejected. `WebSocketDefinitionBase` and `BuilderField` are internal helper types.
2237
1833
  *
2238
1834
  * @param definition - WebSocket contract (path, structs, queue limits, optional input).
2239
- * @returns An endpoint that creates `WebSocketCommand` values from input.
1835
+ * @returns An operation `(client, ...input) => Promise<error-first tuple>`.
2240
1836
  *
2241
1837
  * @group web-socket
2242
1838
  * @exampleFile examples/api/define-web-socket.ts#example
@@ -2244,23 +1840,7 @@ export interface WebSocketHeartbeatConfig<TIncoming = unknown, TOutgoing = unkno
2244
1840
  export declare function defineWebSocket<const P extends string, TInput extends AnyStruct | undefined = undefined, TIncoming extends AnyStruct = AnyStruct, TOutgoing extends AnyStruct | undefined = undefined>(definition: Omit<WebSocketDefinitionBase<TIncoming, TOutgoing>, "path"> & {
2245
1841
  input?: TInput;
2246
1842
  path: P;
2247
- } & BuilderField<NoInfer<TInput>, WebSocketRequestShape<NoInfer<P>>>): WebSocketEndpoint<TInput, TIncoming, TOutgoing>;
2248
- /**
2249
- * Open a WebSocket command against the given client config.
2250
- *
2251
- * Prefer `client.execute(command)` in application code; this is the low-level entry used by the client.
2252
- *
2253
- * The result is `[null, session, connection]` or `[fault, undefined, connection | undefined]`, where the fault is `Fault<undefined>`.
2254
- *
2255
- * WebSocket execute options can override the client's `beforeConnect`, `heartbeat`, `protocols`, and `reconnect`.
2256
- *
2257
- * @param clientConfig - Resolved client configuration.
2258
- * @param command - WebSocket command from a `WebSocketEndpoint`.
2259
- * @param options - Optional execute options (heartbeat, reconnect, abort).
2260
- * @returns Await-result tuple of `[error, socket, connection]`.
2261
- * @group web-socket
2262
- */
2263
- export declare function executeWebSocketCommand<TInput extends AnyStruct | undefined, TIncoming extends AnyStruct, TOutgoing extends AnyStruct | undefined>(clientConfig: ClientConfig, command: WebSocketCommand<TInput, TIncoming, TOutgoing>, options?: WebSocketExecuteOptions<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>): Promise<SocketAwaitResult<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>>;
1843
+ } & BuilderField<NoInfer<TInput>, WebSocketRequestShape<NoInfer<P>>>): WebSocketEndpoint<EndpointArgs<TInput>, WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>;
2264
1844
  /**
2265
1845
  * The outcome of a **single connect attempt**, not the final result of the session.
2266
1846
  *
@@ -2288,8 +1868,8 @@ export type SocketLifecycleOutcome = {
2288
1868
  * Continuation that runs the rest of the HTTP interceptor chain, or the handler.
2289
1869
  *
2290
1870
  * `next(req)` only goes inward: the interceptors registered after this one, then
2291
- * the Fetch handler. It is not a re-dispatch of `client.execute` from the
2292
- * outside of the chain. Call `next` again for a safe
1871
+ * the Fetch handler. It is not a new operation call from outside the chain.
1872
+ * Call `next` again for a safe
2293
1873
  * replay (for example one 401 refresh) from the same interceptor; outer layers
2294
1874
  * do not run a second time. Once the chain has settled, calling `next` rejects
2295
1875
  * with `HTTP interceptor next() cannot be called after the chain has settled`.
@@ -2324,10 +1904,10 @@ interface HttpInterceptor {
2324
1904
  * Returns `{ kind: 'http', fn }`. Call `next(req)` (optionally with a modified
2325
1905
  * request) or short-circuit with `makeResponse`. `next` runs only the
2326
1906
  * interceptors registered after this one and then the fetch handler. HTTP
2327
- * interceptors do not run for SSE or WebSocket commands.
1907
+ * interceptors do not run for SSE or WebSocket operations.
2328
1908
  *
2329
1909
  * A deterministic URL error from `next(req)` rejects the returned promise, so
2330
- * `.then` or `.catch` recovery runs; if it is not recovered, `client.execute`
1910
+ * `.then` or `.catch` recovery runs; if it is not recovered, the operation
2331
1911
  * still reports `REQ_BUILD_FAILED`.
2332
1912
  *
2333
1913
  * @param fn - HTTP interceptor function.
@@ -2369,7 +1949,7 @@ type SSEInterceptorFn = (req: HttpRequest, next: SSEHandler) => Promise<EventStr
2369
1949
  *
2370
1950
  * Created by `createSSEInterceptor`. The `kind` tag lets `withInterceptors`
2371
1951
  * accept HTTP, SSE, and WebSocket interceptors in one list; only `kind: 'sse'`
2372
- * interceptors run for SSE commands.
1952
+ * interceptors run for SSE operations.
2373
1953
  *
2374
1954
  * @group interceptors
2375
1955
  */
@@ -2380,12 +1960,12 @@ interface SSEInterceptor {
2380
1960
  /**
2381
1961
  * Wraps an `SSEInterceptorFn` as a tagged `SSEInterceptor`.
2382
1962
  *
2383
- * Returns `{ kind: 'sse', fn }`. SSE interceptors run only for SSE commands, in
1963
+ * Returns `{ kind: 'sse', fn }`. SSE interceptors run only for SSE operations, in
2384
1964
  * registration order; `next(req)` opens the stream through the remaining
2385
1965
  * interceptors.
2386
1966
  *
2387
1967
  * A deterministic URL error from `next(req)` rejects the returned promise, so
2388
- * `.then` or `.catch` recovery runs; if it is not recovered, `client.execute`
1968
+ * `.then` or `.catch` recovery runs; if it is not recovered, the operation
2389
1969
  * still reports `REQ_BUILD_FAILED`.
2390
1970
  *
2391
1971
  * `EventStreamHandle` extends `AsyncDisposable`. A structural short-circuit
@@ -2448,7 +2028,7 @@ type WebSocketHandler = (req: HttpRequest) => Promise<WebSocketSessionLike>;
2448
2028
  * {@link WebSocketSessionLike} to short-circuit. Wrap it with
2449
2029
  * `createWebSocketInterceptor` to register it through `withInterceptors`.
2450
2030
  *
2451
- * The chain runs once per `execute`. Reconnects happen inside the session it
2031
+ * The chain runs once per operation. Reconnects happen inside the session it
2452
2032
  * returns and do not run it again.
2453
2033
  *
2454
2034
  * @group interceptors
@@ -2459,7 +2039,7 @@ type WebSocketInterceptorFn = (req: HttpRequest, next: WebSocketHandler) => Prom
2459
2039
  *
2460
2040
  * Created by `createWebSocketInterceptor`. The `kind` tag lets
2461
2041
  * `withInterceptors` accept HTTP, SSE, and WebSocket interceptors in one list;
2462
- * only `kind: 'web-socket'` interceptors run for WebSocket commands.
2042
+ * only `kind: 'web-socket'` interceptors run for WebSocket operations.
2463
2043
  *
2464
2044
  * @group interceptors
2465
2045
  */
@@ -2471,7 +2051,7 @@ interface WebSocketInterceptor {
2471
2051
  * Wraps a `WebSocketInterceptorFn` as a tagged `WebSocketInterceptor`.
2472
2052
  *
2473
2053
  * Returns `{ kind: 'web-socket', fn }`. WebSocket interceptors run only for
2474
- * WebSocket commands. `next` and the interceptor return a
2054
+ * WebSocket operations. `next` and the interceptor return a
2475
2055
  * {@link WebSocketSessionLike}, the interceptor-facing session. A wrapper or
2476
2056
  * short-circuit session must forward its `[Symbol.asyncDispose]()` teardown.
2477
2057
  *
@@ -2483,7 +2063,7 @@ export declare function createWebSocketInterceptor(fn: WebSocketInterceptorFn):
2483
2063
  /**
2484
2064
  * Any tagged interceptor accepted by client interceptor options.
2485
2065
  *
2486
- * `kind` (`'http'`, `'sse'`, or `'web-socket'`) selects which commands an
2066
+ * `kind` (`'http'`, `'sse'`, or `'web-socket'`) selects which operations an
2487
2067
  * interceptor runs for. `withInterceptors` accepts any mix; each transport runs
2488
2068
  * only its own kind, in registration order.
2489
2069
  *
@@ -2603,7 +2183,7 @@ interface ClientWebSocketOptions {
2603
2183
  * - **onInvalidEvent** — Called when an event has no matching struct and no `default` struct (`'missing-struct'`), or its data fails validation (`'validation-failed'`). The event is skipped. An error thrown by the hook does not close the stream.
2604
2184
  * - **reconnect** — Opt-in. Without it the stream never reconnects. `attempts` defaults to **3** per outage; `attempts: 0` disables retry. A successful handshake resets the budget, callback `attempt`, and backoff exponent. `delayMs` is the first base delay, 1000 by default, and a server-sent `retry:` value replaces it. `factor` defaults to 1. `jitter` is a 0–1 multiplicative factor and defaults to 0. `maxDelayMs` caps the final delay after jitter and rounding; without a configured cap, the platform limit of `2_147_483_647` ms still applies. A zero base stays zero; valid-number overflow saturates at the caps. Without `shouldReconnect` only `GET`, `HEAD`, `OPTIONS`, `PUT`, and `DELETE` reconnect; with it, its result decides for every method and its context carries `method`. A `ReadableStream` request body never reconnects. Reconnect sends the latest ID as UTF-8 bytes in `Last-Event-ID`; an empty ID clears it and an ID containing NUL is ignored.
2605
2185
  *
2606
- * Reconnect options are validated before interceptors or Fetch: `attempts` is a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` is finite and positive; `jitter` is finite and within 0–1. Invalid values return `REQ_OPTIONS_INVALID` at execute time.
2186
+ * Reconnect options are validated before interceptors or Fetch: `attempts` is a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` is finite and positive; `jitter` is finite and within 0–1. Invalid values return `REQ_OPTIONS_INVALID` when the operation runs.
2607
2187
  *
2608
2188
  * Set these with `withSSEHandle`, `withSSEOnInvalidEvent`, and `withSSEReconnect`. Omitting `withSSEReconnect` disables retry.
2609
2189
  *
@@ -2670,7 +2250,7 @@ interface ClientSSEConfig extends ClientSSEOptions {
2670
2250
  interface HttpClientOptions {
2671
2251
  /** Base URL prepended to relative request paths. */
2672
2252
  endpoint: string;
2673
- /** Static default headers merged under command headers for HTTP/SSE. */
2253
+ /** Static default headers merged under headers returned by the builder for HTTP/SSE. */
2674
2254
  headers?: Headers;
2675
2255
  /** HTTP transport overrides; the default resolves global `fetch` on each call. */
2676
2256
  http?: {
@@ -2680,8 +2260,6 @@ interface HttpClientOptions {
2680
2260
  interceptors?: Interceptor[];
2681
2261
  /** Serializes encoded query objects. Omit to use `URLSearchParams`. */
2682
2262
  querySerializer?: QuerySerializer;
2683
- /** Default HTTP execute timeout in milliseconds (SSE/WebSocket ignore this). */
2684
- timeout?: number;
2685
2263
  /** XSRF cookie/header mapping and optional token provider. */
2686
2264
  xsrf?: {
2687
2265
  /** Cookie name that stores the XSRF token. */
@@ -2699,7 +2277,7 @@ interface HttpClientOptions {
2699
2277
  /**
2700
2278
  * Input-shaped client options, including SSE and WebSocket, that mirror what the option helpers configure.
2701
2279
  *
2702
- * The user-facing shape of the settings before defaults are applied. `createClient` does not accept this object; configure a client with option helpers such as `withEndpoint` and `withTimeout`. {@link ClientConfig} is the resolved counterpart. The HTTP members come from the non-exported `HttpClientOptions` base and are shown inline.
2280
+ * The user-facing shape of the settings before defaults are applied. `createClient` does not accept this object; configure a client with option helpers such as `withEndpoint`. {@link ClientConfig} is the resolved counterpart. The HTTP members come from the non-exported `HttpClientOptions` base and are shown inline.
2703
2281
  *
2704
2282
  * @group client
2705
2283
  */
@@ -2713,7 +2291,7 @@ interface ClientOptions extends HttpClientOptions {
2713
2291
  interface HttpClientConfig {
2714
2292
  /** Base URL prepended to relative request paths. */
2715
2293
  endpoint: string;
2716
- /** Static default headers merged under command headers for HTTP/SSE. */
2294
+ /** Static default headers merged under headers returned by the builder for HTTP/SSE. */
2717
2295
  headers?: Headers;
2718
2296
  /** HTTP transport with a required fetch handle. */
2719
2297
  http: {
@@ -2723,8 +2301,6 @@ interface HttpClientConfig {
2723
2301
  interceptors: Interceptor[];
2724
2302
  /** Serializes encoded query objects. Omit to use `URLSearchParams`. */
2725
2303
  querySerializer?: QuerySerializer;
2726
- /** Default HTTP execute timeout in milliseconds (SSE/WebSocket ignore this). */
2727
- timeout?: number;
2728
2304
  /** Resolved XSRF settings when enabled. */
2729
2305
  xsrf?: {
2730
2306
  /** Cookie name that stores the XSRF token. */
@@ -2766,7 +2342,7 @@ type ClientOption = (config: ClientConfig) => void;
2766
2342
  /**
2767
2343
  * Sets the valid absolute base URL prepended to relative request paths.
2768
2344
  *
2769
- * The default is an empty string, so execution requires an explicit endpoint. Its pathname is kept as a directory; its query and hash are discarded. For WebSocket commands, an `http:` base becomes `ws:` and `https:` becomes `wss:`.
2345
+ * The default is an empty string, so execution requires an explicit endpoint. Its pathname is kept as a directory; its query and hash are discarded. For WebSocket operations, an `http:` base becomes `ws:` and `https:` becomes `wss:`.
2770
2346
  *
2771
2347
  * A missing, relative, or invalid endpoint, or an illegal request path, fails with `REQ_BUILD_FAILED` during building, before any interceptor or transport runs, even when an interceptor would short-circuit. HTTP, SSE, and WebSocket share this rule. The resolved request must keep the base origin and stay under its directory; C0 control characters (including tab, CR, and LF), backslashes, `?`, `#`, and directory escapes in a path are rejected. Scheme-like and protocol-relative forms are rejected even with leading spaces; a plain inner space is allowed and sent as `%20`. An interceptor's final `req.endpoint` is checked against its final `req.baseEndpoint` with the same rule, but it may deliberately replace the base with another valid absolute URL. Deterministic URL errors are never retried.
2772
2348
  *
@@ -2789,22 +2365,10 @@ export declare function withEndpoint(endpoint: string): ClientOption;
2789
2365
  * @group client
2790
2366
  */
2791
2367
  export declare function withHeaders(headers: HeadersInit): ClientOption;
2792
- /**
2793
- * Sets the default timeout, in milliseconds, for HTTP `execute` only.
2794
- *
2795
- * SSE and WebSocket ignore it. `ms` must be a positive safe integer no greater than `2_147_483_647`. Anything else throws `RangeError` immediately, when `withTimeout` is called, not when the client executes.
2796
- *
2797
- * The timer starts before the interceptor chain runs. When it fires, the call returns a `NET_TIMEOUT` fault. Execute `{ timeout }` replaces this default for that call. Execute `{ abort }` combines with the default: an abort gives `NET_ABORTED`, the timer gives `NET_TIMEOUT`. Passing both `abort` and `timeout` to the same `execute` call is still rejected.
2798
- *
2799
- * @param ms - Positive safe integer timeout in milliseconds.
2800
- * @returns An option that writes `config.timeout`.
2801
- * @group client
2802
- */
2803
- export declare function withTimeout(ms: number): ClientOption;
2804
2368
  /**
2805
2369
  * Appends interceptors to the client interceptor chain.
2806
2370
  *
2807
- * Calling it again appends more; it never replaces earlier ones. The first registered interceptor is the outermost layer. HTTP, SSE, and WebSocket interceptors can be mixed in one call. At execute time only the interceptors of the command's transport run, in their registration order.
2371
+ * Calling it again appends more; it never replaces earlier ones. The first registered interceptor is the outermost layer. HTTP, SSE, and WebSocket interceptors can be mixed in one call. When an operation runs, only the interceptors of that transport run, in their registration order.
2808
2372
  *
2809
2373
  * @param interceptors - Interceptors applied in registration order.
2810
2374
  * @returns An option that pushes onto `config.interceptors`.
@@ -2848,7 +2412,7 @@ export declare function withSSEHandle(fetchImpl: FetchHandle): ClientOption;
2848
2412
  /**
2849
2413
  * Replaces the WebSocket constructor used for socket connections.
2850
2414
  *
2851
- * The default is `globalThis.WebSocket`. `WebSocketImpl` is a {@link WebSocketHandleConstructor} that returns a {@link WebSocketHandle}. If no constructor is available, executing a WebSocket command fails with an `ENV_UNSUPPORTED` fault.
2415
+ * The default is `globalThis.WebSocket`. `WebSocketImpl` is a {@link WebSocketHandleConstructor} that returns a {@link WebSocketHandle}. If no constructor is available, a WebSocket operation fails with an `ENV_UNSUPPORTED` fault.
2852
2416
  *
2853
2417
  * @param WebSocketImpl - Constructor that returns a `WebSocketHandle`.
2854
2418
  * @returns An option that sets `config.webSocket.handle`.
@@ -2867,7 +2431,7 @@ export declare function withWebSocketHandle(WebSocketImpl: WebSocketHandleConstr
2867
2431
  * - `attempt` is `0` for the first connect and grows by one for each reconnect.
2868
2432
  * - Pass `signal` into token refreshes and other async work so cancelling the session stops them.
2869
2433
  * - If the hook throws, the attempt fails with an `EXT_HOOK_FAILED` fault.
2870
- * - A `beforeConnect` in the execute options replaces this one for that call.
2434
+ * - A `beforeConnect` in the request options replaces this one for that call.
2871
2435
  *
2872
2436
  * @param beforeConnect - Hook receiving attempt index and abort signal.
2873
2437
  * @returns An option that sets `config.webSocket.beforeConnect`.
@@ -2879,7 +2443,7 @@ export declare function withWebSocketBeforeConnect(beforeConnect: ClientWebSocke
2879
2443
  *
2880
2444
  * They are passed as the second argument to the `WebSocket` constructor only when the list is not empty, so the platform can run the RFC 6455 subprotocol negotiation. They matter only when the server requires a specific subprotocol, for example `['json']` or `['v1']`.
2881
2445
  *
2882
- * Precedence, highest first: the `protocols` execute option, this client option, then `protocols` on the endpoint definition.
2446
+ * Precedence, highest first: the `protocols` request option, this client option, then `protocols` on the endpoint definition.
2883
2447
  *
2884
2448
  * @param protocols - Subprotocol list for the WebSocket constructor.
2885
2449
  * @returns An option that sets `config.webSocket.protocols`.
@@ -2904,8 +2468,8 @@ export declare function withWebSocketProtocols(protocols: readonly string[]): Cl
2904
2468
  * - With `timeoutMs`, an acknowledgement is expected after each heartbeat. `isAck` receives the decoded incoming message; when it returns `true`, the timer is cleared and that message is **not** delivered to `receive`.
2905
2469
  * - If no ack arrives within `timeoutMs`, or a heartbeat cannot be sent, the session fails. This does not trigger a reconnect.
2906
2470
  * - Heartbeat uses the same JSON guard as `session.send`: a value JSON cannot represent after struct encoding causes `TypeError` and ends the logical session.
2907
- * - `intervalMs` and `timeoutMs` must be positive, finite, and at most `2_147_483_647`; otherwise execute fails with `REQ_OPTIONS_INVALID`.
2908
- * - A `heartbeat` in the execute options replaces this one for that call.
2471
+ * - `intervalMs` and `timeoutMs` must be positive, finite, and at most `2_147_483_647`; otherwise the operation fails with `REQ_OPTIONS_INVALID`.
2472
+ * - A `heartbeat` in the request options replaces this one for that call.
2909
2473
  *
2910
2474
  * @param options - Heartbeat interval, payload, timeout, and ACK predicate.
2911
2475
  * @returns An option that sets `config.webSocket.heartbeat`.
@@ -2931,8 +2495,8 @@ export declare function withWebSocketHeartbeat(options: ClientWebSocketOptions["
2931
2495
  * - `attempts` is the retry budget for each outage. It defaults to `3`, and `0` disables reconnection. Successful `open` resets the budget and backoff exponent; the next outage starts at retry 1. Omitting it does not give unlimited retries within one outage. A socket that successfully opens and is immediately closed again by the server can keep reconnecting at the base delay (subject to jitter and caps), because every open resets the budget; use `shouldReconnect` to stop it.
2932
2496
  * - `delayMs` defaults to `1000`, `factor` to `2`, `maxDelayMs` to `30000`, and `jitter` (0 to 1) to `0`. Retry _n_ starts with `delayMs * factor^(n-1)`, capped at `maxDelayMs`; jitter and rounding follow, then the final delay is capped again at `maxDelayMs` and `2_147_483_647` ms. A zero base stays zero; valid-number overflow saturates at those caps.
2933
2497
  * - `shouldReconnect` can return `false` to end the session instead. Without it every close is retried while the budget lasts. It is not called for a manual `session.close()`.
2934
- * - Reconnect options are validated before connecting: `attempts` must be a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` must be finite and positive; `jitter` must be finite and within 0–1. Invalid values make execute fail with `REQ_OPTIONS_INVALID` before connecting. `attempts: 0` disables subsequent retries, but all explicitly supplied reconnect fields are still validated before the initial connection.
2935
- * - A `reconnect` in the execute options replaces this one for that call.
2498
+ * - Reconnect options are validated before connecting: `attempts` must be a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` must be finite and positive; `jitter` must be finite and within 0–1. Invalid values make the operation fail with `REQ_OPTIONS_INVALID` before connecting. `attempts: 0` disables subsequent retries, but all explicitly supplied reconnect fields are still validated before the initial connection.
2499
+ * - A `reconnect` in the request options replaces this one for that call.
2936
2500
  *
2937
2501
  * @param options - Retry budget, backoff, and `shouldReconnect` gate.
2938
2502
  * @returns An option that sets `config.webSocket.reconnect`.
@@ -2993,7 +2557,7 @@ export declare function withSSEOnInvalidEvent(handler: ClientSSEOptions["onInval
2993
2557
  * - `delayMs`, `factor`, `jitter` (0 to 1), and `maxDelayMs` shape the backoff. `factor` defaults to `1` and `jitter` to `0`. `maxDelayMs` caps the final delay after jitter and rounding. Without a configured cap, the platform timer limit of `2_147_483_647` ms still applies. A zero base stays zero; valid-number overflow saturates at the caps.
2994
2558
  * - `delayMs` is only the starting base delay (`1000` by default). A server `retry:` field (digits only, in milliseconds) replaces it for later attempts.
2995
2559
  * - The last event id is sent again as UTF-8 bytes in `Last-Event-ID` on the next attempt. An empty `id:` clears it; an ID containing NUL is ignored.
2996
- * - Reconnect options are validated before interceptors or Fetch: `attempts` must be a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` must be finite and positive; `jitter` must be finite and within 0–1. Invalid values return `REQ_OPTIONS_INVALID` at execute time.
2560
+ * - Reconnect options are validated before interceptors or Fetch: `attempts` must be a non-negative safe integer; `delayMs` must be finite and non-negative; `maxDelayMs` must be a non-negative finite number or positive `Infinity`, which removes the configured cap but not the platform limit of `2_147_483_647` ms; `factor` must be finite and positive; `jitter` must be finite and within 0–1. Invalid values return `REQ_OPTIONS_INVALID` when the operation runs.
2997
2561
  *
2998
2562
  * @param options - Retry budget, backoff, and `shouldReconnect` gate.
2999
2563
  * @returns An option that sets `config.sse.reconnect`.
@@ -3024,41 +2588,221 @@ export declare function withXSRF(options?: HttpClientOptions["xsrf"]): ClientOpt
3024
2588
  * @group client
3025
2589
  */
3026
2590
  export declare function withCredentials(value: boolean): ClientOption;
2591
+ /**
2592
+ * Internal symbol key for a client's base configuration and request options.
2593
+ *
2594
+ * Application code passes the client to an operation. It does not call the client or read this property.
2595
+ *
2596
+ * @group client
2597
+ */
3027
2598
  declare const CLIENT: unique symbol;
3028
2599
  /**
3029
- * A client returned by `createClient` holds the resolved {@link ClientConfig} and executes HTTP, SSE, and WebSocket commands.
2600
+ * Flat per-call options. Each protocol reads the fields it understands and ignores the rest.
2601
+ *
2602
+ * SSE reads only `signal` from request options. SSE reconnect comes from client configuration (`withSSEReconnect`), so `client({ reconnect })` affects WebSocket only.
3030
2603
  *
3031
- * The command type selects the `execute` overload. Failures are returned as faults in the result tuple rather than thrown; the promise rejects only for a value that is not a Defjs command (`Error: Unsupported command`). `[CLIENT]` is an internal symbol key that holds the resolved {@link ClientConfig}; it is not part of the call surface.
2604
+ * `signal` cancels HTTP, SSE, and WebSocket calls. `onUploadProgress` and `onDownloadProgress` apply to HTTP. `beforeConnect`, `protocols`, `heartbeat`, and `reconnect` apply to WebSocket and replace the client setting for that call as a whole value. There is no `timeout` or `abort` field. Pass `AbortSignal.timeout(ms)` as `signal` when a call needs a deadline.
3032
2605
  *
3033
2606
  * @group client
3034
- * @see {@link HttpAwaitResult}
3035
- * @see {@link StreamAwaitResult}
3036
- * @see {@link SocketAwaitResult}
3037
- */
3038
- type Client = {
3039
- /** Internal symbol key for the resolved client configuration. */
3040
- readonly [CLIENT]: ClientConfig;
3041
- /** Open an SSE command and return stream open/await results. */
3042
- execute<TInput extends AnyStruct | undefined, TEvents extends EventStructs, TError extends AnyStruct | undefined = undefined>(command: EventStreamCommand<TInput, TEvents, TError>, options?: EventStreamExecuteOptions): Promise<StreamAwaitResult<EventStreamData<TEvents>, TError>>;
3043
- /** Open a WebSocket command and return session await results. */
3044
- execute<TInput extends AnyStruct | undefined, TIncoming extends AnyStruct, TOutgoing extends AnyStruct | undefined>(command: WebSocketCommand<TInput, TIncoming, TOutgoing>, options?: WebSocketExecuteOptions<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>): Promise<SocketAwaitResult<WebSocketIncomingData<TIncoming>, WebSocketOutgoingData<TOutgoing>>>;
3045
- /** Run an HTTP command and return an await-result tuple. */
3046
- execute<TInput extends AnyStruct | undefined, TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined>(command: HttpCommand<TInput, TOutput, TError>, options?: HttpExecuteOptions): ReturnType<typeof executeHttpCommand<TInput, TOutput, TError>>;
2607
+ */
2608
+ type RequestOptions = {
2609
+ /** Aborts the call. An already aborted signal fails the call before transport. */
2610
+ signal?: AbortSignal;
2611
+ /** Observes HTTP upload progress. */
2612
+ onUploadProgress?: HttpProgressFn;
2613
+ /** Observes HTTP download progress. */
2614
+ onDownloadProgress?: HttpProgressFn;
2615
+ /** Runs before each WebSocket connect attempt for this call. */
2616
+ beforeConnect?: ClientWebSocketOptions["beforeConnect"];
2617
+ /** WebSocket subprotocols for this call. Replaces the client list; it is not appended. */
2618
+ protocols?: readonly string[];
2619
+ /** WebSocket heartbeat for this call. Replaces the client heartbeat as a whole value. */
2620
+ heartbeat?: ClientWebSocketOptions["heartbeat"];
2621
+ /** WebSocket reconnect policy for this call. Replaces the client policy as a whole value. */
2622
+ reconnect?: ClientWebSocketOptions["reconnect"];
3047
2623
  };
2624
+ interface ClientState {
2625
+ readonly config: ClientConfig;
2626
+ readonly options: RequestOptions;
2627
+ }
3048
2628
  /**
3049
- * Creates a Defjs client from option helpers.
2629
+ * Client value that operations accept.
2630
+ *
2631
+ * A client value carries the base configuration and one call's request options. Operations accept it. It is not callable; create one by calling the factory returned by `createClient`. Calling a client value throws a `TypeError` at runtime and fails to compile.
3050
2632
  *
3051
- * Options apply in order: a later option overwrites an earlier one for the same setting, and interceptors accumulate. Prefer creating the client inside the request boundary when interceptors close over auth or tenants. Default HTTP/SSE fetch availability is checked when the interceptor chain invokes transport.
2633
+ * Create a client value per call. Reusing a value that carries `signal` shares that signal between calls.
2634
+ *
2635
+ * @group client
2636
+ * @see {@link createClient}
2637
+ * @see {@link RequestOptions}
2638
+ */
2639
+ interface Client {
2640
+ /** Internal state. Not part of the call surface. */
2641
+ readonly [CLIENT]: ClientState;
2642
+ }
2643
+ /**
2644
+ * Callable root client returned by `createClient`.
2645
+ *
2646
+ * A factory is a {@link Client} that carries no request options, so it can be passed to an operation directly. Calling it with {@link RequestOptions} returns a plain, non-callable `Client` value for one call and performs no I/O. That value cannot be called again: `client()()` fails to compile and throws a `TypeError` at runtime. The seven known fields are copied from the argument into a fresh options object, unknown fields are ignored, and fields whose value is `undefined` are omitted. Nested `heartbeat`, `protocols`, and `reconnect` values are kept by reference. There is no parent overlay: `client()`, `client(undefined)`, and `client({})` all return a client with no request options. A getter that throws escapes the call and is not converted into a fault; the factory stays usable.
2647
+ *
2648
+ * @group client
2649
+ * @see {@link createClient}
2650
+ * @see {@link Client}
2651
+ * @see {@link RequestOptions}
2652
+ */
2653
+ interface DerivableClient extends Client {
2654
+ /** Returns a client value that carries `options` for one call. */
2655
+ (options?: RequestOptions): Client;
2656
+ }
2657
+ /**
2658
+ * Creates a Defjs {@link DerivableClient} from option helpers.
2659
+ *
2660
+ * Options apply in order: a later option overwrites an earlier one for the same setting, and interceptors accumulate. Prefer creating the client inside the request boundary when interceptors close over auth or tenants. Default HTTP/SSE fetch availability is checked when an operation invokes transport.
2661
+ *
2662
+ * The returned factory is a function. Calling it with {@link RequestOptions} returns a {@link Client} value for one call and performs no I/O; see {@link DerivableClient} for the snapshot rules. The factory itself is also a `Client` and carries no request options, so it can be passed to an operation directly. The base configuration is shared by every client value and is not frozen at runtime. It is fixed by convention: nothing in the library changes it, and applications should not either.
3052
2663
  *
3053
2664
  * @param options - Client option helpers such as `withEndpoint`.
3054
- * @returns A client that can `execute` HTTP, SSE, and WebSocket commands.
2665
+ * @returns A callable factory that carries the resolved base configuration.
3055
2666
  *
3056
2667
  * @group client
2668
+ * @see {@link DerivableClient}
3057
2669
  * @see {@link Client}
3058
2670
  * @see {@link ClientOption}
2671
+ * @see {@link RequestOptions}
3059
2672
  * @exampleFile examples/api/create-client.ts#example
3060
2673
  */
3061
- export declare function createClient(...options: ClientOption[]): Client;
2674
+ export declare function createClient(...options: ClientOption[]): DerivableClient;
2675
+ /**
2676
+ * HTTP fields of {@link RequestOptions}: progress callbacks and `signal`.
2677
+ *
2678
+ * `onDownloadProgress` and `onUploadProgress` are {@link HttpProgressFn}
2679
+ * callbacks. They receive an {@link HttpProgressEvent} with `loaded`, `total`,
2680
+ * and `lengthComputable`. Other request fields are ignored by HTTP.
2681
+ *
2682
+ * @group http
2683
+ */
2684
+ export type UseRequestConfig = {
2685
+ /** Aborts the call. */
2686
+ signal?: AbortSignal;
2687
+ /** Observes download progress. */
2688
+ onDownloadProgress?: HttpProgressFn;
2689
+ /** Observes upload progress. */
2690
+ onUploadProgress?: HttpProgressFn;
2691
+ };
2692
+ /**
2693
+ * HTTP fields read from {@link RequestOptions} for one call.
2694
+ *
2695
+ * Progress callbacks and `signal`. There is no `timeout` or `abort`.
2696
+ *
2697
+ * @group http
2698
+ */
2699
+ export type HttpExecuteOptions = UseRequestConfig;
2700
+ /**
2701
+ * Operation returned by `defineRequest`.
2702
+ *
2703
+ * The first argument is a {@link Client}. Further arguments are the input, and only the input: none when the definition declares no `input`, optional when the input struct accepts `undefined`, and required otherwise. Calling it starts the request and returns the error-first tuple.
2704
+ *
2705
+ * @group http
2706
+ */
2707
+ export type RequestEndpoint<Args extends unknown[], Data, ErrorData, Response extends HttpMeta> = (client: Client, ...args: Args) => Promise<[error: null, result: Data, response: Response] | [error: FaultOf<ErrorData>, result: undefined, response: undefined]>;
2708
+ type DeclaredBody<TStruct> = [TStruct] extends [undefined] ? undefined : Infer<TStruct>;
2709
+ type DeclaredResponse<TStruct> = [TStruct] extends [undefined] ? HttpMeta : DecodedResponse<Infer<TStruct>>;
2710
+ /**
2711
+ * Decoded success body for the declared `output` struct, or `undefined` when none is declared.
2712
+ *
2713
+ * @group http
2714
+ */
2715
+ export type RequestSuccessData<TOutput extends AnyStruct | undefined> = DeclaredBody<TOutput>;
2716
+ /**
2717
+ * Decoded error body for the declared `error` struct, or `undefined` when none is declared.
2718
+ *
2719
+ * @group http
2720
+ */
2721
+ export type RequestErrorData<TError extends AnyStruct | undefined> = DeclaredBody<TError>;
2722
+ type ResponseDeclaration<TOutput extends AnyStruct | undefined, TError extends AnyStruct | undefined> = ([TOutput] extends [undefined] ? {
2723
+ output?: never;
2724
+ } : {
2725
+ output: TOutput;
2726
+ }) & ([TError] extends [undefined] ? {
2727
+ error?: never;
2728
+ } : {
2729
+ error: TError;
2730
+ });
2731
+ /**
2732
+ * Contract for an HTTP endpoint: method, path, optional input, and the structs that decode its bodies.
2733
+ *
2734
+ * Declaring `input` requires an explicit `builder` to place the parsed value on
2735
+ * the request. `input` only defines the parameters; the builder alone decides
2736
+ * where each value goes. Only definitions without `input` may omit `builder`.
2737
+ * `output` declares the body for a 2xx response, `error` the body for anything
2738
+ * else. Only one of the two ever runs, and omitting one means that body is never
2739
+ * read. `ResponseDeclaration` is an internal helper type: `output` and `error`
2740
+ * are required only when the matching type parameter is a struct. There is no
2741
+ * `responseType`: the struct kind selects how a declared body is read. Pass to
2742
+ * `defineRequest` to get a typed endpoint.
2743
+ *
2744
+ * @group http
2745
+ */
2746
+ export type RequestDefinition<TInput extends AnyStruct | undefined = undefined, TOutput extends AnyStruct | undefined = undefined, TError extends AnyStruct | undefined = undefined> = ResponseDeclaration<TOutput, TError> & {
2747
+ builder?: OutboundBuilder;
2748
+ input?: TInput;
2749
+ method: string;
2750
+ operation?: string;
2751
+ path: string;
2752
+ };
2753
+ /**
2754
+ * Await-result tuple for an HTTP call: success is `[null, data, response]`, and failure is `[fault, undefined, undefined]`.
2755
+ *
2756
+ * `TData` and `TErrorData` are decoded body types. On success the third slot
2757
+ * carries `body` only when `output` was declared. On failure it is `undefined`,
2758
+ * because the fault already holds whatever response metadata existed.
2759
+ *
2760
+ * @group http
2761
+ */
2762
+ export type HttpAwaitResult<TData = undefined, TErrorData = undefined> = [error: null, result: TData, response: [TData] extends [undefined] ? HttpMeta : DecodedResponse<TData>] | [error: FaultOf<TErrorData>, result: undefined, response: undefined];
2763
+ /**
2764
+ * Declares a typed HTTP request endpoint.
2765
+ *
2766
+ * Pass method, path, an optional input struct, and the single `output` and
2767
+ * `error` structs. Call the returned operation with a client and, when declared, the input.
2768
+ *
2769
+ * The contract is `method`, `path`, an optional `input` struct, optional
2770
+ * `output` and `error` structs, and an optional `operation`. A declared `input`
2771
+ * always requires an explicit `builder`. `input` only defines the parameters;
2772
+ * the builder alone decides where each value goes. Only definitions without
2773
+ * `input` may omit `builder`. `ResponseDeclaration` and `BuilderField` are
2774
+ * internal helper types: `output` and `error` are required only when the
2775
+ * matching type parameter is a struct, and `builder` is
2776
+ * `(input: BuilderInput<TInput>) => HttpRequestShape` when `input` is declared.
2777
+ *
2778
+ * `output` is one struct for the 2xx body; `error` is one struct for every
2779
+ * non-2xx body. Neither is keyed by status. A declaration is an assertion:
2780
+ * omitting one means that body is never read.
2781
+ *
2782
+ * @param definition - Request contract (method, path, input, builder, output).
2783
+ * @returns An operation `(client, ...input) => Promise<error-first tuple>`.
2784
+ *
2785
+ * The checked example file passes the whole input object as `path`. This snippet maps individual fields into `path` and `query` instead:
2786
+ *
2787
+ * @example
2788
+ * ```ts
2789
+ * const getUser = defineRequest({
2790
+ * method: 'GET',
2791
+ * path: '/users/:id',
2792
+ * input: struct.object({ id: struct.number(), verbose: struct.boolean() }),
2793
+ * builder: (input) => ({ path: { id: input.id }, query: { verbose: input.verbose } }),
2794
+ * output: struct.object({ id: struct.number(), name: struct.string() }),
2795
+ * })
2796
+ * ```
2797
+ * @group http
2798
+ * @exampleFile examples/api/define-request.ts#example
2799
+ */
2800
+ export declare function defineRequest<const M extends string, const P extends string, TInput extends AnyStruct | undefined = undefined, TOutput extends AnyStruct | undefined = undefined, TError extends AnyStruct | undefined = undefined>(definition: ResponseDeclaration<TOutput, TError> & {
2801
+ input?: TInput;
2802
+ method: M;
2803
+ operation?: string;
2804
+ path: P;
2805
+ } & BuilderField<NoInfer<TInput>, HttpRequestShape<NoInfer<P>, NoInfer<M>>>): RequestEndpoint<EndpointArgs<TInput>, RequestSuccessData<TOutput>, RequestErrorData<TError>, DeclaredResponse<TOutput>>;
3062
2806
  /**
3063
2807
  * Default HTTP transport: perform `httpRequest` with `fetch` and return an `HttpResponse`.
3064
2808
  *
@@ -3067,7 +2811,7 @@ export declare function createClient(...options: ClientOption[]): Client;
3067
2811
  * global `fetch` resolved at send time. It rejects, rather than resolving with
3068
2812
  * a synthetic response, when no response reached the client.
3069
2813
  *
3070
- * @param httpRequest - Normalized request (URL, headers, body, abort, progress hooks).
2814
+ * @param httpRequest - Normalized request (URL, headers, body, signal, progress hooks).
3071
2815
  * @param fetchImpl - Fetch implementation; defaults to global `fetch`. The library default handle is called as
3072
2816
  * `(url, init)` while the global is untouched, and its body is read in one piece unless download progress is observed. Any other handle receives a
3073
2817
  * `Request` and its body is read chunk by chunk.
@@ -3079,7 +2823,7 @@ export declare function fetchHandler(httpRequest: HttpRequest, fetchImpl?: Fetch
3079
2823
  /**
3080
2824
  * Resolves a relative definition path under the base endpoint's origin and directory into a URL.
3081
2825
  *
3082
- * During `client.execute`, a missing, relative, or invalid base or an illegal
2826
+ * During an operation, a missing, relative, or invalid base or an illegal
3083
2827
  * path becomes `REQ_BUILD_FAILED` before any interceptor or transport runs,
3084
2828
  * including a short-circuiting interceptor, for HTTP, SSE, and WebSocket alike.
3085
2829
  * An interceptor's final `req.endpoint` is also validated against its final
@@ -3122,7 +2866,7 @@ type BasicAuthInterceptorOptions = {
3122
2866
  * `encode`, calling `basicAuthHttpInterceptor` throws
3123
2867
  * `Error: BasicAuthInterceptor is not supported in this environment` when `btoa`
3124
2868
  * is not available in the runtime. Use {@link basicAuthSSEInterceptor} for SSE
3125
- * commands.
2869
+ * operations.
3126
2870
  *
3127
2871
  * @param fn - Factory returning username/password for each request.
3128
2872
  * @param options - Optional custom encoder (defaults to `btoa`).
@@ -3144,4 +2888,122 @@ export declare function basicAuthHttpInterceptor(fn: () => BasicCredential, opti
3144
2888
  * @group interceptors
3145
2889
  */
3146
2890
  export declare function basicAuthSSEInterceptor(fn: () => BasicCredential, options?: BasicAuthInterceptorOptions): SSEInterceptor;
3147
- export type { AnyStruct, BasicAuthInterceptorOptions, BuilderInput, Client, ClientConfig, ClientOption, ClientOptions, ClientSSEConfig, ClientSSEOptions, ClientWebSocketOptions, DecodedResponse, ErrorMap, EventStreamCloseInfo, EventStreamFaultCode, EventStreamHandle, EventStreamOpenInfo, EventStreamRequestShape, FetchHandle, FlattenedStructError, FormattedStructError, HttpInterceptor, HttpInterceptorNext, HttpMeta, HttpProgressEvent, HttpProgressFn, HttpRequest, HttpRequestShape, HttpResponse, HttpResponseType, Infer, Interceptor, InterceptorFn, MakeResponseOptions, ObjectStruct, ParseResult, QuerySerializer, SSEHandler, SSEInterceptor, SSEInterceptorFn, STRUCT, Struct, StructInput, StructIssue, StructLike, StructMethods, WebSocketHandle, WebSocketHandleConstructor, WebSocketHandler, WebSocketInterceptor, WebSocketInterceptorFn, WebSocketRequestShape, WebSocketSessionLike };
2891
+ /**
2892
+ * Map from SSE event names to the structs that decode their data.
2893
+ *
2894
+ * An event with no `event:` field is named `message`. An event whose name has no own entry uses the `default` struct; with neither, the event is skipped and `onInvalidEvent` is called. Declare the event name `__proto__` with a computed own key.
2895
+ *
2896
+ * A `string` event struct keeps the raw `data` text. Every other kind is JSON text: `JSON.parse`, then the struct. A bare `struct.literal` therefore needs JSON text, not an unquoted token.
2897
+ *
2898
+ * Reconnect lives on the client (`withSSEReconnect`). SSE `jitter` is a **0-1 multiplicative factor**, same as WebSocket.
2899
+ *
2900
+ * @group sse
2901
+ */
2902
+ export type EventStructs = {
2903
+ [key: string]: AnyStruct;
2904
+ };
2905
+ type EventName<TKey extends string | number> = `${TKey}`;
2906
+ type KnownEventUnion<TEvents extends EventStructs> = { [K in keyof TEvents & (number | string)]: EventName<K> extends "default" ? never : {
2907
+ data: Infer<TEvents[K]>;
2908
+ event: EventName<K>;
2909
+ id?: string;
2910
+ }; }[keyof TEvents & (number | string)];
2911
+ type DefaultEventUnion<TEvents extends EventStructs> = "default" extends keyof TEvents ? {
2912
+ data: Infer<TEvents["default"]>;
2913
+ event: string;
2914
+ id?: string;
2915
+ } : never;
2916
+ /**
2917
+ * Union of parsed SSE events inferred from an EventStructs map.
2918
+ *
2919
+ * For each declared event name except `default`, the union has `{ event: <name>; data: Infer<TEvents[name]>; id?: string }`. When a `default` struct is declared, it adds `{ event: string; data: Infer<TEvents['default']>; id?: string }` for every event name that has no struct of its own. `KnownEventUnion` and `DefaultEventUnion` are internal helper types.
2920
+ *
2921
+ * @group sse
2922
+ */
2923
+ export type EventStreamData<TEvents extends EventStructs> = TEvents extends EventStructs ? KnownEventUnion<TEvents> | DefaultEventUnion<TEvents> : never;
2924
+ interface EventStreamDefinitionBase<TEvents extends EventStructs = EventStructs> {
2925
+ events: TEvents;
2926
+ maxBufferSize: number;
2927
+ maxQueueSize: number;
2928
+ method?: string;
2929
+ operation?: string;
2930
+ path: string;
2931
+ }
2932
+ /** Makes `error` required only when an error struct is declared, so omission stays `Fault<undefined>`. */
2933
+ type EventStreamErrorField<TError extends AnyStruct | undefined> = [TError] extends [undefined] ? {
2934
+ error?: never;
2935
+ } : {
2936
+ error: TError;
2937
+ };
2938
+ /**
2939
+ * Contract that describes an SSE endpoint for defineEventStream.
2940
+ *
2941
+ * The composed members are:
2942
+ *
2943
+ * - `events`, `maxBufferSize`, and `maxQueueSize` (both limits are required positive safe integers), optional `method`, `operation`, and a required `path`.
2944
+ *
2945
+ * - `error`, required only when `TError` is a struct. It decodes the body of a failed handshake (a non-2xx response). The kind rule is the same as for HTTP: `string` is text, `blob` and `file` are blobs, `arrayBuffer` is bytes, and everything else is JSON.
2946
+ *
2947
+ * - `input` and `builder`. The request shape matches HTTP, including `body`; `GET` and `HEAD` cannot return a body. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`.
2948
+ *
2949
+ * `EventStreamDefinitionBase` and `EventStreamErrorField` are internal helper types.
2950
+ *
2951
+ * @group sse
2952
+ */
2953
+ export type EventStreamDefinition<TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs, TError extends AnyStruct | undefined = undefined> = EventStreamDefinitionBase<TEvents> & EventStreamErrorField<TError> & {
2954
+ builder?: OutboundBuilder;
2955
+ input?: TInput;
2956
+ };
2957
+ /**
2958
+ * Await-result tuple from opening an SSE stream.
2959
+ *
2960
+ * - On success: `[null, stream, open]`. `open` is the returned connection's first successful handshake snapshot for native Defjs handles or wrappers forwarding the same live `open` object; custom handles or wrappers overriding `open` use their current public `open` even after reconnect, while `stream.open` stays live.
2961
+ *
2962
+ * - On failure: `[fault, undefined, open]`. `open` carries the response snapshot when the failure happened after a response arrived, for example a non-2xx handshake, and is `undefined` otherwise.
2963
+ *
2964
+ * - `TError` is the declared `error` struct. It types the decoded error body on the fault.
2965
+ *
2966
+ * @group sse
2967
+ */
2968
+ export type StreamAwaitResult<TEvent, TError extends AnyStruct | undefined = undefined> = [error: null, stream: EventStreamHandle<TEvent>, open: EventStreamOpenInfo] | [error: Fault<TError>, stream: undefined, open: EventStreamOpenInfo | undefined];
2969
+ /**
2970
+ * SSE field of {@link RequestOptions}. HTTP progress and WebSocket fields are ignored.
2971
+ *
2972
+ * `signal` covers the whole stream, including after it opens. There is no startup-only deadline.
2973
+ *
2974
+ * @group sse
2975
+ */
2976
+ export type EventStreamExecuteOptions = {
2977
+ /** Aborts the stream, including after it is open. */
2978
+ signal?: AbortSignal;
2979
+ };
2980
+ /**
2981
+ * Operation returned by `defineEventStream`.
2982
+ *
2983
+ * The first argument is a {@link Client}. Further arguments are the input only. Calling it opens the stream and returns the existing error-first tuple.
2984
+ *
2985
+ * @group sse
2986
+ */
2987
+ export type EventStreamEndpoint<Args extends unknown[], Event, TError extends AnyStruct | undefined = undefined> = (client: Client, ...args: Args) => Promise<StreamAwaitResult<Event, TError>>;
2988
+ /**
2989
+ * Declare a typed Server-Sent Events endpoint.
2990
+ *
2991
+ * Pass path, event structs, and buffer/queue limits. Call the returned operation
2992
+ * with a client and, when declared, the input.
2993
+ *
2994
+ * - **definition** — `path`, an `events` map, and the required `maxBufferSize` and `maxQueueSize` limits (positive safe integers). Optional `method` (default `'GET'`), `operation`, `input`, and `error`. A declared `input` always requires an explicit `builder`. `input` only defines the parameters; the builder alone decides where each value goes. Only definitions without `input` may omit `builder`.
2995
+ *
2996
+ * `EventStreamDefinitionBase`, `EventStreamErrorField`, and `BuilderField` are internal helper types: `error` is required only when `TError` is a struct, and `builder` is `(input: BuilderInput<TInput>) => EventStreamRequestShape` when `input` is declared.
2997
+ *
2998
+ * @param definition - SSE contract (path, events, buffer limits, optional input).
2999
+ * @returns An operation `(client, ...input) => Promise<error-first tuple>`.
3000
+ *
3001
+ * @group sse
3002
+ * @exampleFile examples/api/define-event-stream.ts#example
3003
+ */
3004
+ export declare function defineEventStream<const P extends string, const M extends string = "GET", TInput extends AnyStruct | undefined = undefined, TEvents extends EventStructs = EventStructs, TError extends AnyStruct | undefined = undefined>(definition: Omit<EventStreamDefinitionBase<TEvents>, "method" | "path"> & EventStreamErrorField<TError> & {
3005
+ input?: TInput;
3006
+ method?: M;
3007
+ path: P;
3008
+ } & BuilderField<NoInfer<TInput>, EventStreamRequestShape<NoInfer<P>, NoInfer<M>>>): EventStreamEndpoint<EndpointArgs<TInput>, EventStreamData<TEvents>, TError>;
3009
+ export type { AnyStruct, BasicAuthInterceptorOptions, BuilderInput, Client, ClientConfig, ClientOption, ClientOptions, ClientSSEConfig, ClientSSEOptions, ClientWebSocketOptions, DecodedResponse, DerivableClient, ErrorMap, EventStreamCloseInfo, EventStreamFaultCode, EventStreamHandle, EventStreamOpenInfo, EventStreamRequestShape, FetchHandle, FlattenedStructError, FormattedStructError, HttpInterceptor, HttpInterceptorNext, HttpMeta, HttpProgressEvent, HttpProgressFn, HttpRequest, HttpRequestShape, HttpResponse, HttpResponseType, Infer, Interceptor, InterceptorFn, MakeResponseOptions, ObjectStruct, ParseResult, QuerySerializer, RequestOptions, SSEHandler, SSEInterceptor, SSEInterceptorFn, STRUCT, Struct, StructInput, StructIssue, StructLike, StructMethods, WebSocketHandle, WebSocketHandleConstructor, WebSocketHandler, WebSocketInterceptor, WebSocketInterceptorFn, WebSocketRequestShape, WebSocketSessionLike };