@nifrajs/client 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @nifrajs/client
2
2
 
3
- A browser-safe, **end-to-end-typed** client for [nifra](../../README.md) servers — an
3
+ A browser-safe, **end-to-end-typed** client for [nifra](../../README.md) servers - an
4
4
  Eden-style proxy that **never throws**.
5
5
 
6
6
  ```sh
@@ -17,21 +17,21 @@ const { ok, status, data, error } = await api.users({ id: "42" }).get()
17
17
  // ^? typed from the server route
18
18
  ```
19
19
 
20
- - **Zero codegen.** Types flow from `typeof app` (coupled) — or from a contract via
20
+ - **Zero codegen.** Types flow from `typeof app` (coupled) - or from a contract via
21
21
  `client(contract, url)` (decoupled), with no dependency on the server's source.
22
22
  - **Proxy chaining.** Path segments are properties, `:params` are calls, verbs are
23
23
  methods: `api.users({ id }).posts({ postId }).get()`. The root is `api.index`.
24
24
  - **Result, never exceptions.** Every call resolves to `{ ok, status, data, error }`,
25
25
  so the failure path is in the types. Bodies are positional (`api.users.post({ name })`);
26
26
  pass `{ query, headers, signal }` as call options.
27
- - **Environment-agnostic.** No Bun/Node APIs — runs in the browser, workers, or any
27
+ - **Environment-agnostic.** No Bun/Node APIs - runs in the browser, workers, or any
28
28
  runtime with `fetch`.
29
29
 
30
30
  ESM-only. MIT.
31
31
 
32
32
  ## For AI agents
33
33
 
34
- Start with [`LLM.md`](./LLM.md) — this package's contract card (the exports you call + its footguns),
34
+ Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
35
35
  one cheap read instead of the whole corpus. For the wider framework: the repo's
36
36
  [`AGENTS.md`](../../AGENTS.md) is the copy-paste quick reference, and
37
37
  [`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
package/dist/client.d.ts CHANGED
@@ -3,12 +3,12 @@ import { type BackendMount } from "@nifrajs/core/mount";
3
3
  import { type TransportCodec, type TransportCodecRegistry } from "@nifrajs/core/transport-codec";
4
4
  import type { Treaty, TreatyFromRegistry } from "./treaty.js";
5
5
  /**
6
- * The fetch shape the client needs — looser than `typeof fetch` so an in-process bridge or a
6
+ * The fetch shape the client needs - looser than `typeof fetch` so an in-process bridge or a
7
7
  * test mock satisfies it without the extra members (`.preconnect`, overloads) of the global.
8
8
  */
9
9
  export type FetchFn = (input: string, init?: RequestInit) => Promise<Response>;
10
10
  type MaybePromise<T> = T | Promise<T>;
11
- /** Safe retry policy. Off unless `retry` is set; retries ONLY idempotent methods and transient 5xx —
11
+ /** Safe retry policy. Off unless `retry` is set; retries ONLY idempotent methods and transient 5xx -
12
12
  * never a 4xx/429 and never a non-idempotent method, so a retry can't double a side effect. */
13
13
  export interface ClientRetryOptions {
14
14
  /** Max RETRIES after the first attempt. Default 2. */
@@ -27,7 +27,7 @@ export interface ClientOptions {
27
27
  readonly fetch?: FetchFn;
28
28
  /**
29
29
  * Runs before each request (including each retry). Return a header map to MERGE onto the outgoing
30
- * request — the place to inject a fresh auth token. `await`ed, so async token refresh works.
30
+ * request - the place to inject a fresh auth token. `await`ed, so async token refresh works.
31
31
  */
32
32
  readonly onRequest?: (request: {
33
33
  readonly url: string;
@@ -46,6 +46,22 @@ export interface ClientOptions {
46
46
  readonly timeoutMs?: number;
47
47
  /** Enable safe automatic retries. See {@link ClientRetryOptions}. */
48
48
  readonly retry?: ClientRetryOptions;
49
+ /**
50
+ * Largest response body, in bytes, that will be DECODED into a value. Default 16 MB.
51
+ *
52
+ * Bounds the two paths that build something in memory - a JSON body becoming an object graph, a text
53
+ * body becoming a string - and it bounds them while streaming, cancelling the read the moment the
54
+ * total passes. A 2 GB string costs as much as a 2 GB object, so both answer to one number.
55
+ *
56
+ * A BINARY body is deliberately not bounded by this. That is a download, and a size limit on a
57
+ * download is a bug rather than a defence - the caller asked for the file. Bound one at the call site
58
+ * with a `signal`, or read `content-length` before deciding.
59
+ *
60
+ * This used to live at `transport.maxBytes`, where it could not be reached: `transport` requires a
61
+ * `codec`, so raising your response limit meant opting into a versioned transport representation you
62
+ * had not asked for. That spelling still works and still wins for the transport path.
63
+ */
64
+ readonly maxDecodedBytes?: number;
49
65
  /**
50
66
  * Opt into a versioned transport representation. Plain JSON remains the default. Responses are
51
67
  * decoded through the bounded registry, and WebSocket frames use the same codec.
@@ -60,8 +76,8 @@ export interface ClientOptions {
60
76
  export type InProcessClient<App> = Treaty<App> & BackendMount;
61
77
  export interface InProcessClientOptions extends Omit<ClientOptions, "fetch"> {
62
78
  /**
63
- * Assert every JSON response against the route's declared contract — `schema.response` for 2xx,
64
- * `schema.errors[status]` for declared failures — and THROW on mismatch, so a handler whose real
79
+ * Assert every JSON response against the route's declared contract - `schema.response` for 2xx,
80
+ * `schema.errors[status]` for declared failures - and THROW on mismatch, so a handler whose real
65
81
  * output drifts from its schema fails the test instead of passing silently. Statuses with no
66
82
  * declared schema, non-JSON bodies, and 204/205/HEAD pass through unchecked. Test-focused: the
67
83
  * check parses a clone of each JSON body, a cost that belongs in tests, not production hot paths.
@@ -71,22 +87,22 @@ export interface InProcessClientOptions extends Omit<ClientOptions, "fetch"> {
71
87
  /**
72
88
  * Create an end-to-end-typed client for a nifra server. Two modes:
73
89
  *
74
- * // coupled — typed from the server's type (`typeof app`)
90
+ * // coupled - typed from the server's type (`typeof app`)
75
91
  * const api = client<typeof app>("http://localhost:3000")
76
92
  *
77
- * // decoupled — typed from a contract VALUE, no server import
93
+ * // decoupled - typed from a contract VALUE, no server import
78
94
  * const api = client(contract, "https://api.example.com")
79
95
  *
80
96
  * const { data, error } = await api.users({ id: "1" }).get()
81
97
  *
82
98
  * Both return the same Eden-style proxy. Browser-safe: uses only `fetch` /
83
- * `Proxy` / `URL`, never the server runtime. Never throws — network and non-2xx
99
+ * `Proxy` / `URL`, never the server runtime. Never throws - network and non-2xx
84
100
  * responses surface as a `Result` `error`.
85
101
  */
86
102
  export declare function client<App>(baseUrl: string, options?: ClientOptions): Treaty<App>;
87
103
  export declare function client<const C extends ContractShape>(contract: C, baseUrl: string, options?: ClientOptions): TreatyFromRegistry<RegistryFor<C>>;
88
104
  /**
89
- * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process — no network, full
105
+ * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process - no network, full
90
106
  * lifecycle (validation, middleware, contracts). For SSR loaders. Typed from `App` exactly like
91
107
  * the network client. The `(url, init) → Request` bridge is required because the client calls
92
108
  * `fetch(url, init)` while `app.fetch` takes a `Request`.
@@ -99,9 +115,9 @@ export declare function inProcessClient<App extends {
99
115
  fetch(request: Request): Response | Promise<Response>;
100
116
  }>(app: App, options?: InProcessClientOptions): InProcessClient<App>;
101
117
  /**
102
- * The in-process test client — the Fastify-`inject` / supertest equivalent for nifra. Drives the
118
+ * The in-process test client - the Fastify-`inject` / supertest equivalent for nifra. Drives the
103
119
  * app's own `fetch` directly: no server, no port, no network, the full real lifecycle (validation,
104
- * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw — branch on
120
+ * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw - branch on
105
121
  * `res.ok`. An alias of {@link inProcessClient} with a test-focused name; identical behavior.
106
122
  *
107
123
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { NIFRA_BINARY_HEADER } from "@nifrajs/core/binary";
1
2
  import { NIFRA_BACKEND_MOUNT, } from "@nifrajs/core/mount";
2
- import { createTransportCodecRegistry, decodeTransportResponse, plainJsonCodec, } from "@nifrajs/core/transport-codec";
3
+ import { createTransportCodecRegistry, decodeTransportResponse, plainJsonCodec, readBoundedBytes, } from "@nifrajs/core/transport-codec";
3
4
  import { ResponseContractViolation, withResponseValidation } from "./validate-responses.js";
4
5
  import { NO_SOCKET, openWebSocket } from "./ws.js";
5
6
  const HTTP_VERBS = new Set([
@@ -46,7 +47,7 @@ export function client(arg1, arg2, arg3) {
46
47
  return createProxy(base, "", options);
47
48
  }
48
49
  /**
49
- * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process — no network, full
50
+ * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process - no network, full
50
51
  * lifecycle (validation, middleware, contracts). For SSR loaders. Typed from `App` exactly like
51
52
  * the network client. The `(url, init) → Request` bridge is required because the client calls
52
53
  * `fetch(url, init)` while `app.fetch` takes a `Request`.
@@ -62,8 +63,8 @@ export function inProcessClient(app, options) {
62
63
  const direct = (url, init) => Promise.resolve(app.fetch(new Request(url, init)));
63
64
  const bridge = options?.validateResponses === true ? withResponseValidation(app, direct) : direct;
64
65
  const mount = (request, platform) => Promise.resolve(app.fetch(request, platform));
65
- // NO_SOCKET marks the options so a typed `.ws()` call fails with a real explanation — an
66
- // in-process app has no socket to upgrade — instead of dialing ws://nifra.internal into the void.
66
+ // NO_SOCKET marks the options so a typed `.ws()` call fails with a real explanation - an
67
+ // in-process app has no socket to upgrade - instead of dialing ws://nifra.internal into the void.
67
68
  const proxy = client("http://nifra.internal", {
68
69
  ...options,
69
70
  fetch: bridge,
@@ -80,9 +81,9 @@ export function inProcessClient(app, options) {
80
81
  });
81
82
  }
82
83
  /**
83
- * The in-process test client — the Fastify-`inject` / supertest equivalent for nifra. Drives the
84
+ * The in-process test client - the Fastify-`inject` / supertest equivalent for nifra. Drives the
84
85
  * app's own `fetch` directly: no server, no port, no network, the full real lifecycle (validation,
85
- * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw — branch on
86
+ * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw - branch on
86
87
  * `res.ok`. An alias of {@link inProcessClient} with a test-focused name; identical behavior.
87
88
  *
88
89
  * ```ts
@@ -106,12 +107,12 @@ function createProxy(base, path, options) {
106
107
  return (...args) => execute(base, path, key.toLowerCase(), args, options);
107
108
  }
108
109
  // Typed SSE subscription for `app.sse()` routes. Like `fetch` on the in-process client,
109
- // `subscribe` is a reserved proxy key — a literal `/subscribe` path segment is unreachable
110
+ // `subscribe` is a reserved proxy key - a literal `/subscribe` path segment is unreachable
110
111
  // through the typed proxy (no nifra app defines one reached this way).
111
112
  if (key === "subscribe") {
112
113
  return (onEvent, subscribeOptions) => subscribeSse(base, path, onEvent, subscribeOptions, options);
113
114
  }
114
- // Typed WebSocket handle for `app.ws()` routes — `ws` is a reserved proxy key like `subscribe`.
115
+ // Typed WebSocket handle for `app.ws()` routes - `ws` is a reserved proxy key like `subscribe`.
115
116
  if (key === "ws") {
116
117
  return (wsOptions) => openWebSocket(base, path, {
117
118
  headers: options.headers,
@@ -123,11 +124,11 @@ function createProxy(base, path, options) {
123
124
  return createProxy(base, key === "index" ? path : `${path}/${key}`, options);
124
125
  },
125
126
  apply(_target, _thisArg, args) {
126
- // A param call (`api.users({ id })`): append the single value, encoded — encoding "/"
127
+ // A param call (`api.users({ id })`): append the single value, encoded - encoding "/"
127
128
  // round-trips through the server's decode, so wildcards and params share this one path.
128
129
  // The Treaty type requires the object, but the runtime must stay graceful: a no-arg call
129
- // (`api.users()`) or empty object (`api.users({})`) must NOT throw — the client's contract is
130
- // to never throw — nor synthesize an `"undefined"` path segment. With no value, fall through
130
+ // (`api.users()`) or empty object (`api.users({})`) must NOT throw - the client's contract is
131
+ // to never throw - nor synthesize an `"undefined"` path segment. With no value, fall through
131
132
  // to the bare path, which the server resolves as an ordinary `{ ok: false }` (404) Result.
132
133
  const first = args[0];
133
134
  const value = first !== null && typeof first === "object"
@@ -181,7 +182,7 @@ async function execute(base, path, verb, args, options) {
181
182
  response = await doFetch(url, init);
182
183
  }
183
184
  catch (error) {
184
- // A contract violation is a test assertion (validateResponses), not a call outcome — let it
185
+ // A contract violation is a test assertion (validateResponses), not a call outcome - let it
185
186
  // fail the test instead of degrading into a `Result` the test would happily branch on.
186
187
  if (error instanceof ResponseContractViolation)
187
188
  throw error;
@@ -202,7 +203,20 @@ async function execute(base, path, verb, args, options) {
202
203
  }
203
204
  if (options.onResponse !== undefined)
204
205
  await options.onResponse({ url, method, response });
205
- const data = await parseBody(response, options);
206
+ // A body that breaches the size limit is a RESULT, not a throw. The client's one promise is that
207
+ // every call returns `{ ok, status, data, error }` - `timeoutMs` already honours that, and a cap
208
+ // that threw instead would mean the only way to use it safely was the try/catch the contract exists
209
+ // to remove. `status: 0` is the same shape a timeout and a network failure take: no HTTP answer was
210
+ // understood, so there is no status to report.
211
+ let data;
212
+ try {
213
+ data = await parseBody(response, options);
214
+ }
215
+ catch (cause) {
216
+ if (!isPayloadTooLarge(cause))
217
+ throw cause;
218
+ return { ok: false, status: 0, data: null, error: { error: "response_too_large" } };
219
+ }
206
220
  if (response.ok) {
207
221
  return { ok: true, status: response.status, data, error: null };
208
222
  }
@@ -251,7 +265,7 @@ async function readSseStream(body, onFrame) {
251
265
  if (Number.isFinite(parsed))
252
266
  frame.retry = parsed;
253
267
  }
254
- // `event:` names pass through untyped for now — the contract types the data payload.
268
+ // `event:` names pass through untyped for now - the contract types the data payload.
255
269
  };
256
270
  try {
257
271
  for (;;) {
@@ -279,7 +293,7 @@ async function readSseStream(body, onFrame) {
279
293
  }
280
294
  /**
281
295
  * The `.subscribe()` runtime for `app.sse()` routes. fetch-based (never `EventSource`), so it
282
- * streams over the configured fetcher — network, an in-process bridge, or a test mock — with
296
+ * streams over the configured fetcher - network, an in-process bridge, or a test mock - with
283
297
  * EventSource semantics where they matter: auto-reconnect with backoff + jitter (honoring the
284
298
  * server's `retry:` hint), `Last-Event-ID` resumption, JSON-parsed typed events. Never throws:
285
299
  * failures reach `onError`; a terminal end reaches `onClose`.
@@ -396,19 +410,76 @@ function transportRegistry(options) {
396
410
  ? createTransportCodecRegistry([plainJsonCodec])
397
411
  : createTransportCodecRegistry([plainJsonCodec, codec]);
398
412
  }
413
+ /**
414
+ * Media types whose bytes are text, beyond the `text/*` tree.
415
+ *
416
+ * Anything ending `+xml` or `+json` is textual by the `+suffix` convention, which covers
417
+ * `image/svg+xml` and `application/xhtml+xml` - an SVG is a document, and handing one back as a Blob
418
+ * would break every caller that reads it as a string today.
419
+ */
420
+ const TEXTUAL_TYPES = new Set([
421
+ "application/xml",
422
+ "application/javascript",
423
+ "application/ecmascript",
424
+ "application/x-www-form-urlencoded",
425
+ "application/x-ndjson",
426
+ ]);
427
+ /**
428
+ * True when a body can survive being decoded as UTF-8 text.
429
+ *
430
+ * An ABSENT content-type is treated as textual on purpose: it is what a hand-written `new Response("…")`
431
+ * produces, the old behaviour parsed it as JSON-or-text, and guessing "binary" for an unlabelled body
432
+ * would change more than this is meant to.
433
+ */
434
+ function isTextualBody(contentType) {
435
+ if (contentType === "")
436
+ return true;
437
+ const media = contentType.split(";", 1)[0]?.trim() ?? "";
438
+ return (media.startsWith("text/") ||
439
+ media.endsWith("+xml") ||
440
+ media.endsWith("+json") ||
441
+ TEXTUAL_TYPES.has(media));
442
+ }
443
+ /**
444
+ * The size cap's own error, recognised by name rather than by class.
445
+ *
446
+ * `instanceof` across a package boundary is only as reliable as the module graph: two copies of
447
+ * `@nifrajs/core` in a tree - a linked checkout, a duplicated transitive version - give two distinct
448
+ * classes and the check silently stops matching, turning a handled result back into a thrown error.
449
+ */
450
+ function isPayloadTooLarge(cause) {
451
+ return (cause instanceof Error &&
452
+ cause.name === "TransportCodecError" &&
453
+ cause.message.includes("exceeds maxBytes"));
454
+ }
399
455
  async function parseBody(response, options) {
400
456
  if (response.status === 204)
401
457
  return undefined;
402
458
  const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
459
+ // `bytes()` is an explicit wire contract. Honor it before media-type heuristics: a caller may
460
+ // intentionally download JSON source, CSV, SVG, or plain text as bytes and the typed client promises
461
+ // a Blob for every one of those routes.
462
+ if (response.headers.get(NIFRA_BINARY_HEADER) === "1")
463
+ return await response.blob();
464
+ // One limit for both decoded paths. `transport.maxBytes` is the older spelling and still wins for
465
+ // the transport path, so an app that set it there keeps the number it chose.
466
+ const decodedBytes = options.transport?.maxBytes ?? options.maxDecodedBytes;
467
+ const bound = decodedBytes === undefined ? {} : { maxBytes: decodedBytes };
403
468
  if (contentType.startsWith("application/json") ||
404
469
  contentType.startsWith("application/vnd.nifra.")) {
405
- return await decodeTransportResponse(response, transportRegistry(options), {
406
- ...(options.transport?.maxBytes === undefined
407
- ? {}
408
- : { maxBytes: options.transport.maxBytes }),
409
- });
470
+ return await decodeTransportResponse(response, transportRegistry(options), bound);
410
471
  }
411
- const text = await response.text();
472
+ // A binary body comes back as a Blob rather than through `.text()`. Decoding bytes as UTF-8 does not
473
+ // fail, it SUBSTITUTES: every invalid sequence becomes U+FFFD, so a PNG arrived as a string of
474
+ // replacement characters that could never be turned back into the image. Measured on the way in -
475
+ // `89 50 4e 47 ff d8` came back `ef bf bd 50 4e 47 ef bf bd ef bf bd` - which is the kind of
476
+ // corruption that looks like a broken file rather than a broken client.
477
+ if (!isTextualBody(contentType))
478
+ return await response.blob();
479
+ // Bounded with the same reader JSON uses, but decoded leniently: `.text()` substitutes U+FFFD for a
480
+ // malformed sequence and callers have always seen that, so tightening to a fatal decode here would
481
+ // turn working text responses into failures for a reason nobody asked about.
482
+ const text = new TextDecoder().decode(await readBoundedBytes(response, bound));
412
483
  if (text === "")
413
484
  return undefined;
414
485
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/client — browser-safe, end-to-end-typed client for @nifrajs/core servers.
2
+ * @nifrajs/client - browser-safe, end-to-end-typed client for @nifrajs/core servers.
3
3
  *
4
4
  * `client<typeof app>(url)` returns an Eden-style proxy whose calls are typed
5
5
  * from the server's accumulated route registry, with zero codegen.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/client — browser-safe, end-to-end-typed client for @nifrajs/core servers.
2
+ * @nifrajs/client - browser-safe, end-to-end-typed client for @nifrajs/core servers.
3
3
  *
4
4
  * `client<typeof app>(url)` returns an Eden-style proxy whose calls are typed
5
5
  * from the server's accumulated route registry, with zero codegen.
package/dist/jsonify.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import type { BinaryResponse } from "@nifrajs/core/binary";
1
2
  /**
2
3
  * Maps a value to the shape it takes after a JSON round-trip, so the client's
3
- * `data` type reflects the wire — not the handler's in-memory return.
4
+ * `data` type reflects the wire - not the handler's in-memory return.
4
5
  *
5
6
  * - `Date` → `string`; `undefined` / functions / `bigint` → dropped from objects
6
7
  * - arrays and plain objects recurse; optionality (`?`) is preserved
@@ -8,7 +9,7 @@
8
9
  * Pragmatic by design: `Map`/`Set`/class instances/custom `toJSON` are treated as
9
10
  * plain objects (best-effort), not specially handled. Documented, not magic.
10
11
  */
11
- export type Jsonify<T> = [unknown] extends [T] ? unknown : T extends string | number | boolean | null ? T : T extends Date ? string : T extends bigint ? never : T extends (...args: never[]) => unknown ? never : T extends undefined ? never : T extends ReadonlyArray<infer U> ? Array<Jsonify<U>> : T extends object ? {
12
+ export type Jsonify<T> = [unknown] extends [T] ? unknown : T extends BinaryResponse ? Blob : T extends string | number | boolean | null ? T : T extends Date ? string : T extends bigint ? never : T extends (...args: never[]) => unknown ? never : T extends undefined ? never : T extends ReadonlyArray<infer U> ? Array<Jsonify<U>> : T extends object ? {
12
13
  [K in keyof T as [Jsonify<T[K]>] extends [never] ? never : K]: Jsonify<T[K]>;
13
14
  } : never;
14
15
  //# sourceMappingURL=jsonify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsonify.d.ts","sourceRoot":"","sources":["../src/jsonify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAC1C,OAAO,GACP,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GACxC,CAAC,GACD,CAAC,SAAS,IAAI,GACZ,MAAM,GACN,CAAC,SAAS,MAAM,GACd,KAAK,GACL,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GACrC,KAAK,GACL,CAAC,SAAS,SAAS,GACjB,KAAK,GACL,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACjB,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAChF,KAAK,CAAA"}
1
+ {"version":3,"file":"jsonify.d.ts","sourceRoot":"","sources":["../src/jsonify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D;;;;;;;;;GASG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAC1C,OAAO,GAIP,CAAC,SAAS,cAAc,GACtB,IAAI,GACJ,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GACxC,CAAC,GACD,CAAC,SAAS,IAAI,GACZ,MAAM,GACN,CAAC,SAAS,MAAM,GACd,KAAK,GACL,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GACrC,KAAK,GACL,CAAC,SAAS,SAAS,GACjB,KAAK,GACL,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACjB,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAChF,KAAK,CAAA"}
package/dist/routes.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import type { ContractShape, RegistryFor } from "@nifrajs/core/contract";
2
+ import type { InferOutput, StandardSchemaV1 } from "@nifrajs/core/server";
2
3
  import type { Treaty, TreatyFromRegistry } from "./treaty.js";
3
4
  /**
4
- * The typed client proxy for an API type — either a server type (`typeof app`, coupled) or a
5
+ * The typed client proxy for an API type - either a server type (`typeof app`, coupled) or a
5
6
  * contract value type (decoupled). Graduating a loader from `typeof app` to a versioned
6
7
  * contract is just changing this one type argument; the loader body is identical.
7
8
  */
@@ -10,38 +11,43 @@ export type ApiProxy<Api> = Api extends ContractShape ? TreatyFromRegistry<Regis
10
11
  * Context a route `loader` receives: the route params, the request, a typed in-process `api` (an
11
12
  * {@link ApiProxy} for the app contract `Api`), and the platform `env`. Pair with `inProcessClient`.
12
13
  */
13
- export interface LoaderArgs<Api, Env = unknown> {
14
+ export interface LoaderArgs<Api, Env = unknown, Search = undefined> {
14
15
  readonly params: Record<string, string>;
15
16
  readonly request: Request;
16
- /** Alias of {@link request} — the same `Request`. Mirrors a route handler's `c.req`, so the same name
17
+ /** Alias of {@link request} - the same `Request`. Mirrors a route handler's `c.req`, so the same name
17
18
  * works in loaders/actions and routes (no `ctx.request` vs `c.req` mismatch). */
18
19
  readonly req: Request;
19
20
  readonly api: ApiProxy<Api>;
20
21
  /**
21
- * Platform bindings (Workers `env` — KV/D1/secrets), forwarded from the request `c.env`.
22
- * `undefined` off-edge (Bun/Node/Deno). Declare the shape via the second type argument —
23
- * `LoaderArgs<typeof app, Env>` (the same `Env` the backend's `server<Env>()` uses) — to read it
22
+ * Platform bindings (Workers `env` - KV/D1/secrets), forwarded from the request `c.env`.
23
+ * `undefined` off-edge (Bun/Node/Deno). Declare the shape via the second type argument -
24
+ * `LoaderArgs<typeof app, Env>` (the same `Env` the backend's `server<Env>()` uses) - to read it
24
25
  * typed; otherwise `unknown`. Validate at the trust boundary before use.
25
26
  */
26
27
  readonly env: Env;
27
28
  /** `true` when the request carries a valid draft/preview cookie (when the app sets a `draftSecret`;
28
- * otherwise always `false`). Branch on it to load unpublished content for editors — see `enableDraft`. */
29
+ * otherwise always `false`). Branch on it to load unpublished content for editors - see `enableDraft`. */
29
30
  readonly draft: boolean;
31
+ /** The URL search params, validated server-side (fails closed to the schema's defaults, so it is safe
32
+ * to use directly). Declare a route `searchSchema` and pass its type as the third argument -
33
+ * `LoaderArgs<typeof app, Env, typeof searchSchema>` - to read it typed; otherwise a raw
34
+ * `Record<string, unknown>` of the parsed query. */
35
+ readonly search: Search extends StandardSchemaV1 ? InferOutput<Search> extends Record<string, unknown> ? InferOutput<Search> : never : Record<string, unknown>;
30
36
  }
31
37
  /** The (awaited) return of a `loader`, for typing a page component's `data` prop. */
32
38
  export type LoaderData<L> = L extends (...args: never[]) => infer R ? Awaited<R> : never;
33
39
  /**
34
- * Context a route `action` (a mutation, run on POST) receives — identical to a loader's:
40
+ * Context a route `action` (a mutation, run on POST) receives - identical to a loader's:
35
41
  * route params, the request (read the form/JSON body off this), and the typed in-process
36
42
  * `api` + platform `env`. An action returns either data (surfaced to the page as `actionData`) or a
37
43
  * `Response` (e.g. a `redirect(...)` for the Post/Redirect/Get pattern).
38
44
  */
39
- export type ActionArgs<Api, Env = unknown> = LoaderArgs<Api, Env>;
45
+ export type ActionArgs<Api, Env = unknown, Search = undefined> = LoaderArgs<Api, Env, Search>;
40
46
  /**
41
47
  * The (awaited) data return of an `action`, for typing a page component's `actionData` prop.
42
- * A `Response` return (redirect/custom) is excluded — it never reaches the component. A
48
+ * A `Response` return (redirect/custom) is excluded - it never reaches the component. A
43
49
  * `revalidate(paths, data)` wrapper (from `@nifrajs/web`) is transparent: matched structurally (so this
44
- * stays decoupled from `@nifrajs/web`) and unwrapped to its inner `data` — what the component receives.
50
+ * stays decoupled from `@nifrajs/web`) and unwrapped to its inner `data` - what the component receives.
45
51
  */
46
52
  export type ActionData<A> = A extends (...args: never[]) => infer R ? Awaited<R> extends {
47
53
  readonly __nifraRevalidate: readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAE7D;;;;GAIG;AACH,MAAM,MAAM,QAAQ,CAAC,GAAG,IAAI,GAAG,SAAS,aAAa,GACjD,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GACpC,MAAM,CAAC,GAAG,CAAC,CAAA;AAEf;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB;qFACiF;IACjF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB;8GAC0G;IAC1G,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,qFAAqF;AACrF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;AAExF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,GAC/D,OAAO,CAAC,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;CAAE,GAC1F,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GACpB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAC/B,KAAK,CAAA"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAE7D;;;;GAIG;AACH,MAAM,MAAM,QAAQ,CAAC,GAAG,IAAI,GAAG,SAAS,aAAa,GACjD,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GACpC,MAAM,CAAC,GAAG,CAAC,CAAA;AAEf;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,EAAE,MAAM,GAAG,SAAS;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB;qFACiF;IACjF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB;8GAC0G;IAC1G,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB;;;wDAGoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,SAAS,gBAAgB,GAC5C,WAAW,CAAC,MAAM,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjD,WAAW,CAAC,MAAM,CAAC,GACnB,KAAK,GACP,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5B;AAED,qFAAqF;AACrF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;AAExF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,EAAE,MAAM,GAAG,SAAS,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;AAE7F;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,GAC/D,OAAO,CAAC,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;CAAE,GAC1F,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GACpB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAC/B,KAAK,CAAA"}
package/dist/routes.js CHANGED
@@ -1,12 +1,12 @@
1
1
  export {};
2
2
  // Why a type annotation, not a `createRoutes()` factory: a module-level factory call defeats
3
3
  // the bundler's tree-shaking (the call is retained, dragging the loader into the client bundle).
4
- // `LoaderArgs<Api>` is a pure type — it erases — so the loader stays a plain function the client
4
+ // `LoaderArgs<Api>` is a pure type - it erases - so the loader stays a plain function the client
5
5
  // build can drop entirely. Bind the contract once with a shared alias:
6
6
  //
7
7
  // // app/loaders.ts
8
8
  // export type AppLoader = LoaderArgs<typeof backend> // coupled
9
- // export type AppLoader = LoaderArgs<MyContract> // graduated — same loaders
9
+ // export type AppLoader = LoaderArgs<MyContract> // graduated - same loaders
10
10
  //
11
11
  // // routes/users/[id].tsx
12
12
  // export async function loader({ api, params }: AppLoader) { … } // ctx.api typed
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":";AA0DA,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AACjG,uEAAuE;AACvE,EAAE;AACF,sBAAsB;AACtB,oEAAoE;AACpE,qFAAqF;AACrF,EAAE;AACF,6BAA6B;AAC7B,sFAAsF;AACtF,oFAAoF"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":";AAoEA,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AACjG,uEAAuE;AACvE,EAAE;AACF,sBAAsB;AACtB,oEAAoE;AACpE,qFAAqF;AACrF,EAAE;AACF,6BAA6B;AAC7B,sFAAsF;AACtF,oFAAoF"}
package/dist/treaty.d.ts CHANGED
@@ -5,11 +5,11 @@ import type { Result } from "./result.js";
5
5
  export type RegistryOf<App> = App extends Server<infer R, infer _Ctx> ? R : never;
6
6
  /**
7
7
  * The `query` option's type for a route that declares NO `query` schema. It's a descriptive string
8
- * literal, so passing query params to such a route fails with an error that READS OUT the fix —
9
- * `Type '{ page: string }' is not assignable to type 'add a `query` schema…'` — instead of the opaque
8
+ * literal, so passing query params to such a route fails with an error that READS OUT the fix -
9
+ * `Type '{ page: string }' is not assignable to type 'add a `query` schema…'` - instead of the opaque
10
10
  * `not assignable to type 'never'`. The error surfaces at the call site; the fix is at the route.
11
11
  */
12
- type QueryNotTyped = "add a `query` schema to this route — `{ query: z.object({ … }) }` — so the typed client can accept query params here";
12
+ type QueryNotTyped = "add a `query` schema to this route - `{ query: z.object({ … }) }` - so the typed client can accept query params here";
13
13
  type CallOptions<I extends RouteInfo> = {
14
14
  query?: [I["query"]] extends [never] ? QueryNotTyped : I["query"];
15
15
  headers?: Record<string, string>;
@@ -35,7 +35,7 @@ export interface SubscribeOptions<I extends RouteInfo> {
35
35
  /** Abort to close the subscription (same effect as calling `close()`). */
36
36
  signal?: AbortSignal;
37
37
  /**
38
- * Reconnect after a dropped/errored stream (default true — EventSource semantics, so a proxy
38
+ * Reconnect after a dropped/errored stream (default true - EventSource semantics, so a proxy
39
39
  * closing an idle feed doesn't silently kill it). A FINITE stream should pass `false` so a clean
40
40
  * server-side end completes the subscription instead of replaying it. Delays follow exponential
41
41
  * backoff with jitter, honoring the server's `retry:` hint when sent.
@@ -125,7 +125,7 @@ type RootIndex<R> = "/" extends keyof R ? {
125
125
  readonly index: Methods<R["/"]>;
126
126
  } : unknown;
127
127
  /**
128
- * The Eden-style proxy type for a route registry — the shared core used by both
128
+ * The Eden-style proxy type for a route registry - the shared core used by both
129
129
  * `Treaty<App>` (coupled, from `typeof app`) and `client(contract, url)`
130
130
  * (decoupled, from a contract's `RegistryFor`).
131
131
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nifrajs/client",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Browser-safe, end-to-end-typed client for @nifrajs/core servers (Eden-style proxy).",
5
5
  "keywords": [
6
6
  "bun",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "peerDependencies": {
42
- "@nifrajs/core": "^2.2.0"
42
+ "@nifrajs/core": "^2.3.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@nifrajs/core": "workspace:*",
package/src/client.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { NIFRA_BINARY_HEADER } from "@nifrajs/core/binary"
1
2
  import type { ContractShape, RegistryFor } from "@nifrajs/core/contract"
2
3
  import {
3
4
  type BackendMount,
@@ -8,6 +9,7 @@ import {
8
9
  createTransportCodecRegistry,
9
10
  decodeTransportResponse,
10
11
  plainJsonCodec,
12
+ readBoundedBytes,
11
13
  type TransportCodec,
12
14
  type TransportCodecRegistry,
13
15
  } from "@nifrajs/core/transport-codec"
@@ -28,14 +30,14 @@ const HTTP_VERBS: ReadonlySet<string> = new Set([
28
30
  const BODY_VERBS: ReadonlySet<string> = new Set(["post", "put", "patch"])
29
31
 
30
32
  /**
31
- * The fetch shape the client needs — looser than `typeof fetch` so an in-process bridge or a
33
+ * The fetch shape the client needs - looser than `typeof fetch` so an in-process bridge or a
32
34
  * test mock satisfies it without the extra members (`.preconnect`, overloads) of the global.
33
35
  */
34
36
  export type FetchFn = (input: string, init?: RequestInit) => Promise<Response>
35
37
 
36
38
  type MaybePromise<T> = T | Promise<T>
37
39
 
38
- /** Safe retry policy. Off unless `retry` is set; retries ONLY idempotent methods and transient 5xx —
40
+ /** Safe retry policy. Off unless `retry` is set; retries ONLY idempotent methods and transient 5xx -
39
41
  * never a 4xx/429 and never a non-idempotent method, so a retry can't double a side effect. */
40
42
  export interface ClientRetryOptions {
41
43
  /** Max RETRIES after the first attempt. Default 2. */
@@ -55,7 +57,7 @@ export interface ClientOptions {
55
57
  readonly fetch?: FetchFn
56
58
  /**
57
59
  * Runs before each request (including each retry). Return a header map to MERGE onto the outgoing
58
- * request — the place to inject a fresh auth token. `await`ed, so async token refresh works.
60
+ * request - the place to inject a fresh auth token. `await`ed, so async token refresh works.
59
61
  */
60
62
  readonly onRequest?: (request: {
61
63
  readonly url: string
@@ -74,6 +76,22 @@ export interface ClientOptions {
74
76
  readonly timeoutMs?: number
75
77
  /** Enable safe automatic retries. See {@link ClientRetryOptions}. */
76
78
  readonly retry?: ClientRetryOptions
79
+ /**
80
+ * Largest response body, in bytes, that will be DECODED into a value. Default 16 MB.
81
+ *
82
+ * Bounds the two paths that build something in memory - a JSON body becoming an object graph, a text
83
+ * body becoming a string - and it bounds them while streaming, cancelling the read the moment the
84
+ * total passes. A 2 GB string costs as much as a 2 GB object, so both answer to one number.
85
+ *
86
+ * A BINARY body is deliberately not bounded by this. That is a download, and a size limit on a
87
+ * download is a bug rather than a defence - the caller asked for the file. Bound one at the call site
88
+ * with a `signal`, or read `content-length` before deciding.
89
+ *
90
+ * This used to live at `transport.maxBytes`, where it could not be reached: `transport` requires a
91
+ * `codec`, so raising your response limit meant opting into a versioned transport representation you
92
+ * had not asked for. That spelling still works and still wins for the transport path.
93
+ */
94
+ readonly maxDecodedBytes?: number
77
95
  /**
78
96
  * Opt into a versioned transport representation. Plain JSON remains the default. Responses are
79
97
  * decoded through the bounded registry, and WebSocket frames use the same codec.
@@ -120,8 +138,8 @@ export type InProcessClient<App> = Treaty<App> & BackendMount
120
138
 
121
139
  export interface InProcessClientOptions extends Omit<ClientOptions, "fetch"> {
122
140
  /**
123
- * Assert every JSON response against the route's declared contract — `schema.response` for 2xx,
124
- * `schema.errors[status]` for declared failures — and THROW on mismatch, so a handler whose real
141
+ * Assert every JSON response against the route's declared contract - `schema.response` for 2xx,
142
+ * `schema.errors[status]` for declared failures - and THROW on mismatch, so a handler whose real
125
143
  * output drifts from its schema fails the test instead of passing silently. Statuses with no
126
144
  * declared schema, non-JSON bodies, and 204/205/HEAD pass through unchecked. Test-focused: the
127
145
  * check parses a clone of each JSON body, a cost that belongs in tests, not production hot paths.
@@ -138,16 +156,16 @@ interface CallOptions {
138
156
  /**
139
157
  * Create an end-to-end-typed client for a nifra server. Two modes:
140
158
  *
141
- * // coupled — typed from the server's type (`typeof app`)
159
+ * // coupled - typed from the server's type (`typeof app`)
142
160
  * const api = client<typeof app>("http://localhost:3000")
143
161
  *
144
- * // decoupled — typed from a contract VALUE, no server import
162
+ * // decoupled - typed from a contract VALUE, no server import
145
163
  * const api = client(contract, "https://api.example.com")
146
164
  *
147
165
  * const { data, error } = await api.users({ id: "1" }).get()
148
166
  *
149
167
  * Both return the same Eden-style proxy. Browser-safe: uses only `fetch` /
150
- * `Proxy` / `URL`, never the server runtime. Never throws — network and non-2xx
168
+ * `Proxy` / `URL`, never the server runtime. Never throws - network and non-2xx
151
169
  * responses surface as a `Result` `error`.
152
170
  */
153
171
  export function client<App>(baseUrl: string, options?: ClientOptions): Treaty<App>
@@ -171,7 +189,7 @@ export function client(
171
189
  }
172
190
 
173
191
  /**
174
- * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process — no network, full
192
+ * A {@link client} whose `fetch` calls a nifra app's own `fetch` in-process - no network, full
175
193
  * lifecycle (validation, middleware, contracts). For SSR loaders. Typed from `App` exactly like
176
194
  * the network client. The `(url, init) → Request` bridge is required because the client calls
177
195
  * `fetch(url, init)` while `app.fetch` takes a `Request`.
@@ -190,8 +208,8 @@ export function inProcessClient<
190
208
  const bridge = options?.validateResponses === true ? withResponseValidation(app, direct) : direct
191
209
  const mount: BackendMountHandler = (request, platform) =>
192
210
  Promise.resolve((app.fetch as BackendMountHandler)(request, platform))
193
- // NO_SOCKET marks the options so a typed `.ws()` call fails with a real explanation — an
194
- // in-process app has no socket to upgrade — instead of dialing ws://nifra.internal into the void.
211
+ // NO_SOCKET marks the options so a typed `.ws()` call fails with a real explanation - an
212
+ // in-process app has no socket to upgrade - instead of dialing ws://nifra.internal into the void.
195
213
  const proxy = client<App>("http://nifra.internal", {
196
214
  ...options,
197
215
  fetch: bridge,
@@ -208,9 +226,9 @@ export function inProcessClient<
208
226
  }
209
227
 
210
228
  /**
211
- * The in-process test client — the Fastify-`inject` / supertest equivalent for nifra. Drives the
229
+ * The in-process test client - the Fastify-`inject` / supertest equivalent for nifra. Drives the
212
230
  * app's own `fetch` directly: no server, no port, no network, the full real lifecycle (validation,
213
- * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw — branch on
231
+ * middleware, contracts, auth), and end-to-end types from `App`. Calls never throw - branch on
214
232
  * `res.ok`. An alias of {@link inProcessClient} with a test-focused name; identical behavior.
215
233
  *
216
234
  * ```ts
@@ -235,13 +253,13 @@ function createProxy(base: string, path: string, options: ClientOptions): unknow
235
253
  execute(base, path, key.toLowerCase(), args, options)
236
254
  }
237
255
  // Typed SSE subscription for `app.sse()` routes. Like `fetch` on the in-process client,
238
- // `subscribe` is a reserved proxy key — a literal `/subscribe` path segment is unreachable
256
+ // `subscribe` is a reserved proxy key - a literal `/subscribe` path segment is unreachable
239
257
  // through the typed proxy (no nifra app defines one reached this way).
240
258
  if (key === "subscribe") {
241
259
  return (onEvent: (event: unknown) => void, subscribeOptions?: SubscribeCallOptions) =>
242
260
  subscribeSse(base, path, onEvent, subscribeOptions, options)
243
261
  }
244
- // Typed WebSocket handle for `app.ws()` routes — `ws` is a reserved proxy key like `subscribe`.
262
+ // Typed WebSocket handle for `app.ws()` routes - `ws` is a reserved proxy key like `subscribe`.
245
263
  if (key === "ws") {
246
264
  return (wsOptions?: Parameters<typeof openWebSocket>[2]) =>
247
265
  openWebSocket(
@@ -259,11 +277,11 @@ function createProxy(base: string, path: string, options: ClientOptions): unknow
259
277
  return createProxy(base, key === "index" ? path : `${path}/${key}`, options)
260
278
  },
261
279
  apply(_target, _thisArg, args) {
262
- // A param call (`api.users({ id })`): append the single value, encoded — encoding "/"
280
+ // A param call (`api.users({ id })`): append the single value, encoded - encoding "/"
263
281
  // round-trips through the server's decode, so wildcards and params share this one path.
264
282
  // The Treaty type requires the object, but the runtime must stay graceful: a no-arg call
265
- // (`api.users()`) or empty object (`api.users({})`) must NOT throw — the client's contract is
266
- // to never throw — nor synthesize an `"undefined"` path segment. With no value, fall through
283
+ // (`api.users()`) or empty object (`api.users({})`) must NOT throw - the client's contract is
284
+ // to never throw - nor synthesize an `"undefined"` path segment. With no value, fall through
267
285
  // to the bare path, which the server resolves as an ordinary `{ ok: false }` (404) Result.
268
286
  const first = args[0]
269
287
  const value =
@@ -323,7 +341,7 @@ async function execute(
323
341
  try {
324
342
  response = await doFetch(url, init)
325
343
  } catch (error) {
326
- // A contract violation is a test assertion (validateResponses), not a call outcome — let it
344
+ // A contract violation is a test assertion (validateResponses), not a call outcome - let it
327
345
  // fail the test instead of degrading into a `Result` the test would happily branch on.
328
346
  if (error instanceof ResponseContractViolation) throw error
329
347
  if (methodRetryable && attempt < maxRetries) {
@@ -344,7 +362,18 @@ async function execute(
344
362
 
345
363
  if (options.onResponse !== undefined) await options.onResponse({ url, method, response })
346
364
 
347
- const data = await parseBody(response, options)
365
+ // A body that breaches the size limit is a RESULT, not a throw. The client's one promise is that
366
+ // every call returns `{ ok, status, data, error }` - `timeoutMs` already honours that, and a cap
367
+ // that threw instead would mean the only way to use it safely was the try/catch the contract exists
368
+ // to remove. `status: 0` is the same shape a timeout and a network failure take: no HTTP answer was
369
+ // understood, so there is no status to report.
370
+ let data: unknown
371
+ try {
372
+ data = await parseBody(response, options)
373
+ } catch (cause) {
374
+ if (!isPayloadTooLarge(cause)) throw cause
375
+ return { ok: false, status: 0, data: null, error: { error: "response_too_large" } }
376
+ }
348
377
  if (response.ok) {
349
378
  return { ok: true, status: response.status, data, error: null }
350
379
  }
@@ -411,7 +440,7 @@ async function readSseStream(
411
440
  const parsed = Number(value)
412
441
  if (Number.isFinite(parsed)) frame.retry = parsed
413
442
  }
414
- // `event:` names pass through untyped for now — the contract types the data payload.
443
+ // `event:` names pass through untyped for now - the contract types the data payload.
415
444
  }
416
445
 
417
446
  try {
@@ -437,7 +466,7 @@ async function readSseStream(
437
466
 
438
467
  /**
439
468
  * The `.subscribe()` runtime for `app.sse()` routes. fetch-based (never `EventSource`), so it
440
- * streams over the configured fetcher — network, an in-process bridge, or a test mock — with
469
+ * streams over the configured fetcher - network, an in-process bridge, or a test mock - with
441
470
  * EventSource semantics where they matter: auto-reconnect with backoff + jitter (honoring the
442
471
  * server's `retry:` hint), `Last-Event-ID` resumption, JSON-parsed typed events. Never throws:
443
472
  * failures reach `onError`; a terminal end reaches `onClose`.
@@ -563,20 +592,81 @@ function transportRegistry(options: ClientOptions): TransportCodecRegistry {
563
592
  : createTransportCodecRegistry([plainJsonCodec, codec])
564
593
  }
565
594
 
595
+ /**
596
+ * Media types whose bytes are text, beyond the `text/*` tree.
597
+ *
598
+ * Anything ending `+xml` or `+json` is textual by the `+suffix` convention, which covers
599
+ * `image/svg+xml` and `application/xhtml+xml` - an SVG is a document, and handing one back as a Blob
600
+ * would break every caller that reads it as a string today.
601
+ */
602
+ const TEXTUAL_TYPES = new Set([
603
+ "application/xml",
604
+ "application/javascript",
605
+ "application/ecmascript",
606
+ "application/x-www-form-urlencoded",
607
+ "application/x-ndjson",
608
+ ])
609
+
610
+ /**
611
+ * True when a body can survive being decoded as UTF-8 text.
612
+ *
613
+ * An ABSENT content-type is treated as textual on purpose: it is what a hand-written `new Response("…")`
614
+ * produces, the old behaviour parsed it as JSON-or-text, and guessing "binary" for an unlabelled body
615
+ * would change more than this is meant to.
616
+ */
617
+ function isTextualBody(contentType: string): boolean {
618
+ if (contentType === "") return true
619
+ const media = contentType.split(";", 1)[0]?.trim() ?? ""
620
+ return (
621
+ media.startsWith("text/") ||
622
+ media.endsWith("+xml") ||
623
+ media.endsWith("+json") ||
624
+ TEXTUAL_TYPES.has(media)
625
+ )
626
+ }
627
+
628
+ /**
629
+ * The size cap's own error, recognised by name rather than by class.
630
+ *
631
+ * `instanceof` across a package boundary is only as reliable as the module graph: two copies of
632
+ * `@nifrajs/core` in a tree - a linked checkout, a duplicated transitive version - give two distinct
633
+ * classes and the check silently stops matching, turning a handled result back into a thrown error.
634
+ */
635
+ function isPayloadTooLarge(cause: unknown): boolean {
636
+ return (
637
+ cause instanceof Error &&
638
+ cause.name === "TransportCodecError" &&
639
+ cause.message.includes("exceeds maxBytes")
640
+ )
641
+ }
642
+
566
643
  async function parseBody(response: Response, options: ClientOptions): Promise<unknown> {
567
644
  if (response.status === 204) return undefined
568
645
  const contentType = response.headers.get("content-type")?.toLowerCase() ?? ""
646
+ // `bytes()` is an explicit wire contract. Honor it before media-type heuristics: a caller may
647
+ // intentionally download JSON source, CSV, SVG, or plain text as bytes and the typed client promises
648
+ // a Blob for every one of those routes.
649
+ if (response.headers.get(NIFRA_BINARY_HEADER) === "1") return await response.blob()
650
+ // One limit for both decoded paths. `transport.maxBytes` is the older spelling and still wins for
651
+ // the transport path, so an app that set it there keeps the number it chose.
652
+ const decodedBytes = options.transport?.maxBytes ?? options.maxDecodedBytes
653
+ const bound = decodedBytes === undefined ? {} : { maxBytes: decodedBytes }
569
654
  if (
570
655
  contentType.startsWith("application/json") ||
571
656
  contentType.startsWith("application/vnd.nifra.")
572
657
  ) {
573
- return await decodeTransportResponse(response, transportRegistry(options), {
574
- ...(options.transport?.maxBytes === undefined
575
- ? {}
576
- : { maxBytes: options.transport.maxBytes }),
577
- })
658
+ return await decodeTransportResponse(response, transportRegistry(options), bound)
578
659
  }
579
- const text = await response.text()
660
+ // A binary body comes back as a Blob rather than through `.text()`. Decoding bytes as UTF-8 does not
661
+ // fail, it SUBSTITUTES: every invalid sequence becomes U+FFFD, so a PNG arrived as a string of
662
+ // replacement characters that could never be turned back into the image. Measured on the way in -
663
+ // `89 50 4e 47 ff d8` came back `ef bf bd 50 4e 47 ef bf bd ef bf bd` - which is the kind of
664
+ // corruption that looks like a broken file rather than a broken client.
665
+ if (!isTextualBody(contentType)) return await response.blob()
666
+ // Bounded with the same reader JSON uses, but decoded leniently: `.text()` substitutes U+FFFD for a
667
+ // malformed sequence and callers have always seen that, so tightening to a fatal decode here would
668
+ // turn working text responses into failures for a reason nobody asked about.
669
+ const text = new TextDecoder().decode(await readBoundedBytes(response, bound))
580
670
  if (text === "") return undefined
581
671
  try {
582
672
  return JSON.parse(text)
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/client — browser-safe, end-to-end-typed client for @nifrajs/core servers.
2
+ * @nifrajs/client - browser-safe, end-to-end-typed client for @nifrajs/core servers.
3
3
  *
4
4
  * `client<typeof app>(url)` returns an Eden-style proxy whose calls are typed
5
5
  * from the server's accumulated route registry, with zero codegen.
package/src/jsonify.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import type { BinaryResponse } from "@nifrajs/core/binary"
2
+
1
3
  /**
2
4
  * Maps a value to the shape it takes after a JSON round-trip, so the client's
3
- * `data` type reflects the wire — not the handler's in-memory return.
5
+ * `data` type reflects the wire - not the handler's in-memory return.
4
6
  *
5
7
  * - `Date` → `string`; `undefined` / functions / `bigint` → dropped from objects
6
8
  * - arrays and plain objects recurse; optionality (`?`) is preserved
@@ -10,18 +12,23 @@
10
12
  */
11
13
  export type Jsonify<T> = [unknown] extends [T]
12
14
  ? unknown // `unknown`/`any` (e.g. a route with no response schema) stays opaque
13
- : T extends string | number | boolean | null
14
- ? T
15
- : T extends Date
16
- ? string
17
- : T extends bigint
18
- ? never
19
- : T extends (...args: never[]) => unknown
15
+ : // A route that declared itself binary with `bytes()`. Checked FIRST, before the object arm below
16
+ // would try to describe a `Response`'s own properties and hand the caller a shape that says
17
+ // nothing about the payload. The brand is a phantom symbol, so nothing else can match it.
18
+ T extends BinaryResponse
19
+ ? Blob
20
+ : T extends string | number | boolean | null
21
+ ? T
22
+ : T extends Date
23
+ ? string
24
+ : T extends bigint
20
25
  ? never
21
- : T extends undefined
26
+ : T extends (...args: never[]) => unknown
22
27
  ? never
23
- : T extends ReadonlyArray<infer U>
24
- ? Array<Jsonify<U>>
25
- : T extends object
26
- ? { [K in keyof T as [Jsonify<T[K]>] extends [never] ? never : K]: Jsonify<T[K]> }
27
- : never
28
+ : T extends undefined
29
+ ? never
30
+ : T extends ReadonlyArray<infer U>
31
+ ? Array<Jsonify<U>>
32
+ : T extends object
33
+ ? { [K in keyof T as [Jsonify<T[K]>] extends [never] ? never : K]: Jsonify<T[K]> }
34
+ : never
package/src/routes.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { ContractShape, RegistryFor } from "@nifrajs/core/contract"
2
+ import type { InferOutput, StandardSchemaV1 } from "@nifrajs/core/server"
2
3
  import type { Treaty, TreatyFromRegistry } from "./treaty.ts"
3
4
 
4
5
  /**
5
- * The typed client proxy for an API type — either a server type (`typeof app`, coupled) or a
6
+ * The typed client proxy for an API type - either a server type (`typeof app`, coupled) or a
6
7
  * contract value type (decoupled). Graduating a loader from `typeof app` to a versioned
7
8
  * contract is just changing this one type argument; the loader body is identical.
8
9
  */
@@ -14,41 +15,50 @@ export type ApiProxy<Api> = Api extends ContractShape
14
15
  * Context a route `loader` receives: the route params, the request, a typed in-process `api` (an
15
16
  * {@link ApiProxy} for the app contract `Api`), and the platform `env`. Pair with `inProcessClient`.
16
17
  */
17
- export interface LoaderArgs<Api, Env = unknown> {
18
+ export interface LoaderArgs<Api, Env = unknown, Search = undefined> {
18
19
  readonly params: Record<string, string>
19
20
  readonly request: Request
20
- /** Alias of {@link request} — the same `Request`. Mirrors a route handler's `c.req`, so the same name
21
+ /** Alias of {@link request} - the same `Request`. Mirrors a route handler's `c.req`, so the same name
21
22
  * works in loaders/actions and routes (no `ctx.request` vs `c.req` mismatch). */
22
23
  readonly req: Request
23
24
  readonly api: ApiProxy<Api>
24
25
  /**
25
- * Platform bindings (Workers `env` — KV/D1/secrets), forwarded from the request `c.env`.
26
- * `undefined` off-edge (Bun/Node/Deno). Declare the shape via the second type argument —
27
- * `LoaderArgs<typeof app, Env>` (the same `Env` the backend's `server<Env>()` uses) — to read it
26
+ * Platform bindings (Workers `env` - KV/D1/secrets), forwarded from the request `c.env`.
27
+ * `undefined` off-edge (Bun/Node/Deno). Declare the shape via the second type argument -
28
+ * `LoaderArgs<typeof app, Env>` (the same `Env` the backend's `server<Env>()` uses) - to read it
28
29
  * typed; otherwise `unknown`. Validate at the trust boundary before use.
29
30
  */
30
31
  readonly env: Env
31
32
  /** `true` when the request carries a valid draft/preview cookie (when the app sets a `draftSecret`;
32
- * otherwise always `false`). Branch on it to load unpublished content for editors — see `enableDraft`. */
33
+ * otherwise always `false`). Branch on it to load unpublished content for editors - see `enableDraft`. */
33
34
  readonly draft: boolean
35
+ /** The URL search params, validated server-side (fails closed to the schema's defaults, so it is safe
36
+ * to use directly). Declare a route `searchSchema` and pass its type as the third argument -
37
+ * `LoaderArgs<typeof app, Env, typeof searchSchema>` - to read it typed; otherwise a raw
38
+ * `Record<string, unknown>` of the parsed query. */
39
+ readonly search: Search extends StandardSchemaV1
40
+ ? InferOutput<Search> extends Record<string, unknown>
41
+ ? InferOutput<Search>
42
+ : never
43
+ : Record<string, unknown>
34
44
  }
35
45
 
36
46
  /** The (awaited) return of a `loader`, for typing a page component's `data` prop. */
37
47
  export type LoaderData<L> = L extends (...args: never[]) => infer R ? Awaited<R> : never
38
48
 
39
49
  /**
40
- * Context a route `action` (a mutation, run on POST) receives — identical to a loader's:
50
+ * Context a route `action` (a mutation, run on POST) receives - identical to a loader's:
41
51
  * route params, the request (read the form/JSON body off this), and the typed in-process
42
52
  * `api` + platform `env`. An action returns either data (surfaced to the page as `actionData`) or a
43
53
  * `Response` (e.g. a `redirect(...)` for the Post/Redirect/Get pattern).
44
54
  */
45
- export type ActionArgs<Api, Env = unknown> = LoaderArgs<Api, Env>
55
+ export type ActionArgs<Api, Env = unknown, Search = undefined> = LoaderArgs<Api, Env, Search>
46
56
 
47
57
  /**
48
58
  * The (awaited) data return of an `action`, for typing a page component's `actionData` prop.
49
- * A `Response` return (redirect/custom) is excluded — it never reaches the component. A
59
+ * A `Response` return (redirect/custom) is excluded - it never reaches the component. A
50
60
  * `revalidate(paths, data)` wrapper (from `@nifrajs/web`) is transparent: matched structurally (so this
51
- * stays decoupled from `@nifrajs/web`) and unwrapped to its inner `data` — what the component receives.
61
+ * stays decoupled from `@nifrajs/web`) and unwrapped to its inner `data` - what the component receives.
52
62
  */
53
63
  export type ActionData<A> = A extends (...args: never[]) => infer R
54
64
  ? Awaited<R> extends { readonly __nifraRevalidate: readonly string[]; readonly data: infer D }
@@ -58,12 +68,12 @@ export type ActionData<A> = A extends (...args: never[]) => infer R
58
68
 
59
69
  // Why a type annotation, not a `createRoutes()` factory: a module-level factory call defeats
60
70
  // the bundler's tree-shaking (the call is retained, dragging the loader into the client bundle).
61
- // `LoaderArgs<Api>` is a pure type — it erases — so the loader stays a plain function the client
71
+ // `LoaderArgs<Api>` is a pure type - it erases - so the loader stays a plain function the client
62
72
  // build can drop entirely. Bind the contract once with a shared alias:
63
73
  //
64
74
  // // app/loaders.ts
65
75
  // export type AppLoader = LoaderArgs<typeof backend> // coupled
66
- // export type AppLoader = LoaderArgs<MyContract> // graduated — same loaders
76
+ // export type AppLoader = LoaderArgs<MyContract> // graduated - same loaders
67
77
  //
68
78
  // // routes/users/[id].tsx
69
79
  // export async function loader({ api, params }: AppLoader) { … } // ctx.api typed
package/src/treaty.ts CHANGED
@@ -9,12 +9,12 @@ export type RegistryOf<App> = App extends Server<infer R, infer _Ctx> ? R : neve
9
9
 
10
10
  /**
11
11
  * The `query` option's type for a route that declares NO `query` schema. It's a descriptive string
12
- * literal, so passing query params to such a route fails with an error that READS OUT the fix —
13
- * `Type '{ page: string }' is not assignable to type 'add a `query` schema…'` — instead of the opaque
12
+ * literal, so passing query params to such a route fails with an error that READS OUT the fix -
13
+ * `Type '{ page: string }' is not assignable to type 'add a `query` schema…'` - instead of the opaque
14
14
  * `not assignable to type 'never'`. The error surfaces at the call site; the fix is at the route.
15
15
  */
16
16
  type QueryNotTyped =
17
- "add a `query` schema to this route — `{ query: z.object({ … }) }` — so the typed client can accept query params here"
17
+ "add a `query` schema to this route - `{ query: z.object({ … }) }` - so the typed client can accept query params here"
18
18
 
19
19
  type CallOptions<I extends RouteInfo> = {
20
20
  query?: [I["query"]] extends [never] ? QueryNotTyped : I["query"]
@@ -55,7 +55,7 @@ export interface SubscribeOptions<I extends RouteInfo> {
55
55
  /** Abort to close the subscription (same effect as calling `close()`). */
56
56
  signal?: AbortSignal
57
57
  /**
58
- * Reconnect after a dropped/errored stream (default true — EventSource semantics, so a proxy
58
+ * Reconnect after a dropped/errored stream (default true - EventSource semantics, so a proxy
59
59
  * closing an idle feed doesn't silently kill it). A FINITE stream should pass `false` so a clean
60
60
  * server-side end completes the subscription instead of replaying it. Delays follow exponential
61
61
  * backoff with jitter, honoring the server's `retry:` hint when sent.
@@ -164,7 +164,7 @@ type StaticSegs<R, Prefix extends string> = Exclude<
164
164
  type ParamSeg<R, Prefix extends string> = Extract<NextSegs<R, Prefix>, `:${string}` | `*${string}`>
165
165
 
166
166
  // `unknown` (not `{}`/`never`) is the intersection identity, so empty branches
167
- // don't poison the node — and we never `Prettify` the node (it would strip the
167
+ // don't poison the node - and we never `Prettify` the node (it would strip the
168
168
  // param call-signature and trip TS2456 on the recursion).
169
169
  type MethodsAt<R, Prefix extends string> = Prefix extends keyof R ? Methods<R[Prefix]> : unknown
170
170
 
@@ -190,7 +190,7 @@ type TreatyNode<R, Prefix extends string> = MethodsAt<R, Prefix> &
190
190
  type RootIndex<R> = "/" extends keyof R ? { readonly index: Methods<R["/"]> } : unknown
191
191
 
192
192
  /**
193
- * The Eden-style proxy type for a route registry — the shared core used by both
193
+ * The Eden-style proxy type for a route registry - the shared core used by both
194
194
  * `Treaty<App>` (coupled, from `typeof app`) and `client(contract, url)`
195
195
  * (decoupled, from a contract's `RegistryFor`).
196
196
  */