@nifrajs/client 4.0.2 → 5.0.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 +5 -2
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +141 -52
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/routes.d.ts +25 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js.map +1 -1
- package/dist/treaty.d.ts +23 -9
- package/dist/treaty.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +137 -48
- package/src/index.ts +3 -0
- package/src/routes.ts +49 -1
- package/src/treaty.ts +48 -14
package/src/treaty.ts
CHANGED
|
@@ -26,17 +26,26 @@ type CallOptions<I extends RouteInfo> = {
|
|
|
26
26
|
* value instead of being treated like an omitted object property by the general `Jsonify` helper. */
|
|
27
27
|
type JsonifyResponses<T> = T extends object ? { [K in keyof T]: Jsonify<T[K]> } : never
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** Where a verb's body goes: slot 0 for POST/PUT/PATCH, `options.body` for DELETE, nowhere else. */
|
|
30
|
+
type BodySlot<M extends string> = M extends "POST" | "PUT" | "PATCH"
|
|
31
|
+
? "positional"
|
|
32
|
+
: M extends "DELETE"
|
|
33
|
+
? "option"
|
|
34
|
+
: "none"
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* A terminal method call. The shape is **verb-aware** so the runtime can read
|
|
33
38
|
* args unambiguously with no route info: body-verbs (POST/PUT/PATCH) always take
|
|
34
39
|
* the body positionally Eden-style (typed `undefined` when the route has no body
|
|
35
|
-
* schema, so it's still slot 0); GET/DELETE/HEAD take only options
|
|
40
|
+
* schema, so it's still slot 0); GET/DELETE/HEAD take only options, and a DELETE
|
|
41
|
+
* whose route declares a body schema requires it as `options.body`. Returns a
|
|
36
42
|
* `Result` whose data is the handler's output as it arrives over the wire
|
|
37
43
|
* (`Jsonify`).
|
|
38
44
|
*/
|
|
39
|
-
type MethodCall<
|
|
45
|
+
type MethodCall<
|
|
46
|
+
I extends RouteInfo,
|
|
47
|
+
Slot extends "positional" | "option" | "none",
|
|
48
|
+
> = Slot extends "positional"
|
|
40
49
|
? [I["body"]] extends [never]
|
|
41
50
|
? (
|
|
42
51
|
body?: undefined,
|
|
@@ -50,11 +59,23 @@ type MethodCall<I extends RouteInfo, BodyVerb extends boolean> = BodyVerb extend
|
|
|
50
59
|
) => Promise<
|
|
51
60
|
Result<Jsonify<I["output"]>, Jsonify<I["errors"]>, JsonifyResponses<I["responses"]>>
|
|
52
61
|
>
|
|
53
|
-
:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
: Slot extends "option"
|
|
63
|
+
? [I["body"]] extends [never]
|
|
64
|
+
? (
|
|
65
|
+
options?: CallOptions<I>,
|
|
66
|
+
) => Promise<
|
|
67
|
+
Result<Jsonify<I["output"]>, Jsonify<I["errors"]>, JsonifyResponses<I["responses"]>>
|
|
68
|
+
>
|
|
69
|
+
: (
|
|
70
|
+
options: CallOptions<I> & { body: I["body"] },
|
|
71
|
+
) => Promise<
|
|
72
|
+
Result<Jsonify<I["output"]>, Jsonify<I["errors"]>, JsonifyResponses<I["responses"]>>
|
|
73
|
+
>
|
|
74
|
+
: (
|
|
75
|
+
options?: CallOptions<I>,
|
|
76
|
+
) => Promise<
|
|
77
|
+
Result<Jsonify<I["output"]>, Jsonify<I["errors"]>, JsonifyResponses<I["responses"]>>
|
|
78
|
+
>
|
|
58
79
|
|
|
59
80
|
// --- typed SSE subscriptions ---
|
|
60
81
|
|
|
@@ -67,8 +88,9 @@ export interface SubscribeOptions<I extends RouteInfo> {
|
|
|
67
88
|
/** Abort to close the subscription (same effect as calling `close()`). */
|
|
68
89
|
signal?: AbortSignal
|
|
69
90
|
/**
|
|
70
|
-
* Reconnect after a dropped/errored stream
|
|
71
|
-
* closing an idle feed doesn't silently kill it)
|
|
91
|
+
* Reconnect after a dropped/errored stream. Default `true` for a GET stream (EventSource semantics,
|
|
92
|
+
* so a proxy closing an idle feed doesn't silently kill it) and `false` for one that posts a body,
|
|
93
|
+
* since a reconnect sends the body again. A FINITE stream should pass `false` so a clean
|
|
72
94
|
* server-side end completes the subscription instead of replaying it. Delays follow exponential
|
|
73
95
|
* backoff with jitter, honoring the server's `retry:` hint when sent.
|
|
74
96
|
*/
|
|
@@ -89,12 +111,24 @@ type SubscribeCall<I extends RouteInfo> = (
|
|
|
89
111
|
options?: SubscribeOptions<I>,
|
|
90
112
|
) => Subscription
|
|
91
113
|
|
|
92
|
-
/**
|
|
93
|
-
type
|
|
114
|
+
/** A POST stream's `.subscribe()`: the route's body is required and is posted on every connect. */
|
|
115
|
+
type SubscribeBodyCall<I extends RouteInfo> = (
|
|
116
|
+
onEvent: (event: Jsonify<SseOf<I>>) => void,
|
|
117
|
+
options: SubscribeOptions<I> & { body: I["body"] },
|
|
118
|
+
) => Subscription
|
|
119
|
+
|
|
120
|
+
/** Routes declared via `app.sse()` grow a `.subscribe()` beside their verbs; one whose schema
|
|
121
|
+
* declares a body is a POST route, and its `.subscribe()` takes that body. */
|
|
122
|
+
type SseMethods<MethodMap> = (MethodMap extends { GET: infer G }
|
|
94
123
|
? [SseOf<G>] extends [never]
|
|
95
124
|
? unknown
|
|
96
125
|
: { subscribe: SubscribeCall<G & RouteInfo> }
|
|
97
|
-
: unknown
|
|
126
|
+
: unknown) &
|
|
127
|
+
(MethodMap extends { POST: infer P }
|
|
128
|
+
? [SseOf<P>] extends [never]
|
|
129
|
+
? unknown
|
|
130
|
+
: { subscribe: SubscribeBodyCall<P & RouteInfo> }
|
|
131
|
+
: unknown)
|
|
98
132
|
|
|
99
133
|
// --- typed WebSocket handles ---
|
|
100
134
|
|
|
@@ -146,7 +180,7 @@ type WsMethods<MethodMap> = MethodMap extends { WS: infer G }
|
|
|
146
180
|
type Methods<MethodMap> = {
|
|
147
181
|
[M in Exclude<keyof MethodMap, "WS"> as Lowercase<M & string>]: MethodCall<
|
|
148
182
|
MethodMap[M] & RouteInfo,
|
|
149
|
-
|
|
183
|
+
BodySlot<M & string>
|
|
150
184
|
>
|
|
151
185
|
} & SseMethods<MethodMap> &
|
|
152
186
|
WsMethods<MethodMap>
|