@nifrajs/client 2.1.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 +4 -4
- package/dist/client.d.ts +27 -11
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +92 -21
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/jsonify.d.ts +3 -2
- package/dist/jsonify.d.ts.map +1 -1
- package/dist/routes.d.ts +17 -11
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +2 -2
- package/dist/routes.js.map +1 -1
- package/dist/treaty.d.ts +5 -5
- package/package.json +2 -2
- package/src/client.ts +118 -28
- package/src/index.ts +1 -1
- package/src/jsonify.ts +21 -14
- package/src/routes.ts +23 -13
- package/src/treaty.ts +6 -6
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
|
|
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)
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
64
|
-
* `schema.errors[status]` for declared failures
|
|
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
|
|
90
|
+
* // coupled - typed from the server's type (`typeof app`)
|
|
75
91
|
* const api = client<typeof app>("http://localhost:3000")
|
|
76
92
|
*
|
|
77
|
-
* // decoupled
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAgB,MAAM,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAe3E;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAE9E,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAErC;+FAC+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,oGAAoG;IACpG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE;QAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACxC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;KACvB,KAAK,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAA;IACtD,0FAA0F;IAC1F,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;KAC5B,KAAK,YAAY,CAAC,IAAI,CAAC,CAAA;IACxB;4EACwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAA;IACnC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;QAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAA;QAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAgCD,oFAAoF;AACpF,MAAM,MAAM,eAAe,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAA;AAE7D,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC;IAC1E;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CACrC;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;AAClF,wBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAClD,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,aAAa,GACtB,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAerC;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,SAAS;IAAE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,eAAe,CAAC,GAAG,CAAC,CAuBlE;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,wBAAkB,CAAA"}
|
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
|
|
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
|
|
66
|
-
// in-process app has no socket to upgrade
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
130
|
-
// to never throw
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 {
|
package/dist/client.js.map
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
package/dist/jsonify.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
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}
|
|
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`
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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`
|
|
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[];
|
package/dist/routes.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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
|
|
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
|
package/dist/routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":";
|
|
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…'`
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
124
|
-
* `schema.errors[status]` for declared failures
|
|
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
|
|
159
|
+
* // coupled - typed from the server's type (`typeof app`)
|
|
142
160
|
* const api = client<typeof app>("http://localhost:3000")
|
|
143
161
|
*
|
|
144
|
-
* // decoupled
|
|
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
|
|
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
|
|
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
|
|
194
|
-
// in-process app has no socket to upgrade
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
266
|
-
// to never throw
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
26
|
+
: T extends (...args: never[]) => unknown
|
|
22
27
|
? never
|
|
23
|
-
: T extends
|
|
24
|
-
?
|
|
25
|
-
: T extends
|
|
26
|
-
?
|
|
27
|
-
:
|
|
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
|
|
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}
|
|
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`
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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`
|
|
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
|
|
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
|
|
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…'`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
*/
|