@c9up/ream 0.2.4 → 0.2.6
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 +3 -9
- package/dist/Application.d.ts +85 -5
- package/dist/Application.d.ts.map +1 -1
- package/dist/Application.js +171 -21
- package/dist/Application.js.map +1 -1
- package/dist/ErrorBoundary.d.ts +1 -7
- package/dist/ErrorBoundary.d.ts.map +1 -1
- package/dist/ErrorBoundary.js +31 -31
- package/dist/ErrorBoundary.js.map +1 -1
- package/dist/HttpKernel.js +2 -2
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +18 -49
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +211 -173
- package/dist/Ignitor.js.map +1 -1
- package/dist/env/Env.d.ts +6 -0
- package/dist/env/Env.d.ts.map +1 -1
- package/dist/env/Env.js +6 -0
- package/dist/env/Env.js.map +1 -1
- package/dist/events/Emitter.d.ts +0 -6
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +42 -42
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/native.d.ts +13 -11
- package/dist/events/native.d.ts.map +1 -1
- package/dist/events/native.js.map +1 -1
- package/dist/helpers/compose.d.ts +30 -0
- package/dist/helpers/compose.d.ts.map +1 -0
- package/dist/helpers/compose.js +27 -0
- package/dist/helpers/compose.js.map +1 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/is.d.ts +69 -16
- package/dist/helpers/is.d.ts.map +1 -1
- package/dist/helpers/is.js +79 -16
- package/dist/helpers/is.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.d.ts +9 -3
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +10 -4
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/native/generated.d.ts +243 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/rpc/RpcRouter.js +2 -2
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/services/app.d.ts +6 -0
- package/dist/services/app.d.ts.map +1 -1
- package/dist/services/app.js +8 -0
- package/dist/services/app.js.map +1 -1
- package/dist/services/config.d.ts +15 -0
- package/dist/services/config.d.ts.map +1 -0
- package/dist/services/config.js +18 -0
- package/dist/services/config.js.map +1 -0
- package/dist/services/encryption.d.ts +23 -0
- package/dist/services/encryption.d.ts.map +1 -0
- package/dist/services/encryption.js +33 -0
- package/dist/services/encryption.js.map +1 -0
- package/dist/services/urlBuilder.d.ts +21 -0
- package/dist/services/urlBuilder.d.ts.map +1 -0
- package/dist/services/urlBuilder.js +34 -0
- package/dist/services/urlBuilder.js.map +1 -0
- package/dist/session/drivers/CookieDriver.d.ts +1 -1
- package/dist/session/drivers/CookieDriver.d.ts.map +1 -1
- package/dist/session/drivers/CookieDriver.js +4 -4
- package/dist/session/drivers/CookieDriver.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts +44 -44
- package/dist/testing/ApiResponse.d.ts.map +1 -1
- package/dist/testing/ApiResponse.js +48 -48
- package/dist/testing/ApiResponse.js.map +1 -1
- package/dist/testing/RequestBuilder.d.ts +39 -39
- package/dist/testing/RequestBuilder.d.ts.map +1 -1
- package/dist/testing/RequestBuilder.js +49 -49
- package/dist/testing/RequestBuilder.js.map +1 -1
- package/dist/testing/TestClient.d.ts +5 -5
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +7 -7
- package/dist/testing/TestClient.js.map +1 -1
- package/events.win32-x64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +15 -2
- package/scheduler.win32-x64-msvc.node +0 -0
- package/scripts/build-napi-types.mjs +68 -0
- package/scripts/generate-napi-types.mjs +171 -0
- package/src/Application.ts +221 -21
- package/src/ErrorBoundary.ts +31 -31
- package/src/HttpKernel.ts +2 -2
- package/src/Ignitor.ts +228 -176
- package/src/env/Env.ts +6 -0
- package/src/events/Emitter.ts +42 -42
- package/src/events/native.ts +21 -14
- package/src/helpers/compose.ts +84 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/is.ts +87 -16
- package/src/index.ts +3 -3
- package/src/middleware/Pipeline.ts +10 -4
- package/src/native/generated.ts +291 -0
- package/src/rpc/RpcRouter.ts +2 -2
- package/src/services/app.ts +9 -0
- package/src/services/config.ts +24 -0
- package/src/services/encryption.ts +42 -0
- package/src/services/urlBuilder.ts +41 -0
- package/src/session/drivers/CookieDriver.ts +4 -4
- package/src/testing/ApiResponse.ts +52 -52
- package/src/testing/RequestBuilder.ts +55 -55
- package/src/testing/TestClient.ts +8 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fluent HTTP request builder with assertion methods (
|
|
2
|
+
* Fluent HTTP request builder with assertion methods (`helix` model).
|
|
3
3
|
*
|
|
4
4
|
* await client
|
|
5
5
|
* .get('/api/users/42')
|
|
@@ -54,17 +54,17 @@ export interface AuthStrategy {
|
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* HTTP methods. The common verbs are named; `request(url, method)` also accepts
|
|
57
|
-
* any other method (e.g. `TRACE`, `CONNECT`) —
|
|
57
|
+
* any other method (e.g. `TRACE`, `CONNECT`) — helix parity — via the wider
|
|
58
58
|
* string fallback.
|
|
59
59
|
*/
|
|
60
60
|
export type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'TRACE' | 'CONNECT' | (string & {});
|
|
61
|
-
/** Primitive accepted as a query-string value (mirrors `.qs()` in
|
|
61
|
+
/** Primitive accepted as a query-string value (mirrors `.qs()` in helix). */
|
|
62
62
|
type QueryValue = string | number | boolean;
|
|
63
63
|
/** Query-string map — a value or an array of values (repeated key). */
|
|
64
64
|
export type QueryParams = Record<string, QueryValue | ReadonlyArray<QueryValue>>;
|
|
65
|
-
/** A scalar accepted by `form()`/`fields()` —
|
|
65
|
+
/** A scalar accepted by `form()`/`fields()` — helix parity (arrays repeat the key). */
|
|
66
66
|
export type FieldValue = string | number | boolean | Buffer;
|
|
67
|
-
/** A value accepted by a multipart `field()`/`file()` —
|
|
67
|
+
/** A value accepted by a multipart `field()`/`file()` — helix parity (incl. streams/blobs). */
|
|
68
68
|
export type MultipartValue = string | number | boolean | Buffer | Blob | Readable;
|
|
69
69
|
/**
|
|
70
70
|
* Internal low-level sender — matches what the TestClient exposes.
|
|
@@ -73,10 +73,10 @@ export type MultipartValue = string | number | boolean | Buffer | Blob | Readabl
|
|
|
73
73
|
export type HttpSender = (method: HttpMethod, path: string, init: {
|
|
74
74
|
headers: Record<string, string>;
|
|
75
75
|
body: Buffer;
|
|
76
|
-
/** Per-request socket timeout (ms) —
|
|
76
|
+
/** Per-request socket timeout (ms) — helix `.timeout()`. Sender may honour it. */
|
|
77
77
|
timeoutMs?: number;
|
|
78
78
|
}) => Promise<TestResponse>;
|
|
79
|
-
/** Options for a multipart file part — mirrors Adonis/
|
|
79
|
+
/** Options for a multipart file part — mirrors Adonis/helix's `.file()` options. */
|
|
80
80
|
export interface FilePart {
|
|
81
81
|
/** Filename advertised in the part's `Content-Disposition`. Defaults to the field name / basename. */
|
|
82
82
|
filename?: string;
|
|
@@ -89,83 +89,83 @@ export declare class RequestBuilder {
|
|
|
89
89
|
headers(map: Record<string, string>): this;
|
|
90
90
|
header(name: string, value: string | string[]): this;
|
|
91
91
|
json(data: unknown): this;
|
|
92
|
-
/**
|
|
92
|
+
/** helix `.unsafeJson()` — set a JSON body without any transform (alias of {@link json}). */
|
|
93
93
|
unsafeJson(data: unknown): this;
|
|
94
94
|
body(data: Buffer | string, contentType?: string): this;
|
|
95
95
|
form(data: Record<string, FieldValue | FieldValue[]>): this;
|
|
96
|
-
/**
|
|
96
|
+
/** helix `.unsafeForm()` — set a urlencoded body without transform (alias of {@link form}). */
|
|
97
97
|
unsafeForm(data: Record<string, FieldValue | FieldValue[]>): this;
|
|
98
98
|
/**
|
|
99
|
-
* Add a `multipart/form-data` field — mirrors Adonis/
|
|
99
|
+
* Add a `multipart/form-data` field — mirrors Adonis/helix's `.field()`. Accepts
|
|
100
100
|
* a string/number/boolean, a Buffer, a Blob, a Readable stream, or an array of
|
|
101
101
|
* these (repeated part). Calling `.field()`/`.fields()`/`.file()` switches the
|
|
102
102
|
* body to multipart; the boundary + `Content-Type` header are produced at send
|
|
103
103
|
* time (streams/blobs are drained to Buffers then).
|
|
104
104
|
*/
|
|
105
105
|
field(name: string, value: MultipartValue | MultipartValue[]): this;
|
|
106
|
-
/** Add several multipart fields at once —
|
|
106
|
+
/** Add several multipart fields at once — helix `.fields()`. */
|
|
107
107
|
fields(map: Record<string, MultipartValue | MultipartValue[]>): this;
|
|
108
108
|
/**
|
|
109
|
-
* Attach a file as a `multipart/form-data` part — mirrors Adonis/
|
|
109
|
+
* Attach a file as a `multipart/form-data` part — mirrors Adonis/helix's
|
|
110
110
|
* `.file(field, value, { filename, contentType })`. `value` is a Buffer, a
|
|
111
111
|
* Blob, a Readable stream, OR a string absolute PATH to a file on disk (read at
|
|
112
|
-
* call time,
|
|
112
|
+
* call time, helix parity). The filename defaults to the path basename / field
|
|
113
113
|
* name; streams/blobs are drained to Buffers at send time.
|
|
114
114
|
*/
|
|
115
115
|
file(field: string, value: Buffer | string | Blob | Readable, options?: FilePart): this;
|
|
116
116
|
cookies(map: Record<string, string>): this;
|
|
117
117
|
cookie(name: string, value: string): this;
|
|
118
118
|
/**
|
|
119
|
-
* Append query-string params — mirrors
|
|
119
|
+
* Append query-string params — mirrors helix's `.qs()`. Values are
|
|
120
120
|
* URL-encoded; arrays repeat the key (`?tag=a&tag=b`). Merges with any query
|
|
121
121
|
* string already on the path and with earlier `.qs()` calls.
|
|
122
122
|
*/
|
|
123
123
|
qs(params: QueryParams): this;
|
|
124
124
|
/**
|
|
125
|
-
* Append query params WITHOUT any validation/normalisation —
|
|
125
|
+
* Append query params WITHOUT any validation/normalisation — helix
|
|
126
126
|
* `.unsafeQs({ … })`. Values are still URL-encoded so the wire stays valid, but
|
|
127
127
|
* (unlike `.qs()`) no key filtering is applied; arrays repeat the key.
|
|
128
128
|
*/
|
|
129
129
|
unsafeQs(params: QueryParams): this;
|
|
130
|
-
/** Pass a bearer token as the `Authorization` header —
|
|
130
|
+
/** Pass a bearer token as the `Authorization` header — helix `.bearerToken()`. */
|
|
131
131
|
bearerToken(token: string): this;
|
|
132
|
-
/** Pass HTTP Basic credentials as the `Authorization` header —
|
|
132
|
+
/** Pass HTTP Basic credentials as the `Authorization` header — helix `.basicAuth()`. */
|
|
133
133
|
basicAuth(user: string, password: string): this;
|
|
134
134
|
/**
|
|
135
135
|
* Set the request `Content-Type` from a shorthand (`'json'`, `'form'`, …) or a
|
|
136
|
-
* full MIME type — mirrors
|
|
136
|
+
* full MIME type — mirrors helix's `.type()`.
|
|
137
137
|
*/
|
|
138
138
|
type(mime: string): this;
|
|
139
139
|
/**
|
|
140
140
|
* Set the `Accept` header from a shorthand (`'json'`, `'html'`, …) or a full
|
|
141
|
-
* MIME type — mirrors
|
|
141
|
+
* MIME type — mirrors helix's `.accept()`.
|
|
142
142
|
*/
|
|
143
143
|
accept(mime: string): this;
|
|
144
|
-
/** Per-request timeout in ms —
|
|
144
|
+
/** Per-request timeout in ms — helix `.timeout()`. Honoured by the sender. */
|
|
145
145
|
timeout(ms: number): this;
|
|
146
146
|
/**
|
|
147
|
-
* Follow up to `count` redirects before resolving —
|
|
148
|
-
* Defaults to 5 (
|
|
147
|
+
* Follow up to `count` redirects before resolving — helix `.redirects()`.
|
|
148
|
+
* Defaults to 5 (helix default); pass `0` to disable following.
|
|
149
149
|
*/
|
|
150
150
|
redirects(count: number): this;
|
|
151
|
-
/** No-op: the loopback test server has no TLS —
|
|
151
|
+
/** No-op: the loopback test server has no TLS — helix `.trustLocalhost()`. */
|
|
152
152
|
trustLocalhost(_trust?: boolean): this;
|
|
153
|
-
/** No-op: no TLS on the loopback test server —
|
|
153
|
+
/** No-op: no TLS on the loopback test server — helix `.ca()`. */
|
|
154
154
|
ca(_cert: string): this;
|
|
155
|
-
/** No-op: no TLS on the loopback test server —
|
|
155
|
+
/** No-op: no TLS on the loopback test server — helix `.cert()`. */
|
|
156
156
|
cert(_chain: string): this;
|
|
157
|
-
/** No-op: no TLS on the loopback test server —
|
|
157
|
+
/** No-op: no TLS on the loopback test server — helix `.privateKey()`. */
|
|
158
158
|
privateKey(_key: string): this;
|
|
159
|
-
/** No-op: no TLS on the loopback test server —
|
|
159
|
+
/** No-op: no TLS on the loopback test server — helix `.pfx()`. */
|
|
160
160
|
pfx(_encoded: string | Buffer): this;
|
|
161
|
-
/** No-op: no TLS on the loopback test server —
|
|
161
|
+
/** No-op: no TLS on the loopback test server — helix `.disableTLSCerts()`. */
|
|
162
162
|
disableTLSCerts(): this;
|
|
163
163
|
/**
|
|
164
164
|
* Satisfy blackhole's signed double-submit CSRF check: echo the `XSRF-TOKEN`
|
|
165
165
|
* cookie back in the `X-XSRF-TOKEN` header (the pair the server compares).
|
|
166
166
|
*/
|
|
167
167
|
withCsrf(token?: string): this;
|
|
168
|
-
/**
|
|
168
|
+
/** helix's spelling of {@link withCsrf}. */
|
|
169
169
|
withCsrfToken(token?: string): this;
|
|
170
170
|
/**
|
|
171
171
|
* Attach auth for a user. Uses the strategy passed to `client`'s `auth`
|
|
@@ -191,7 +191,7 @@ export declare class RequestBuilder {
|
|
|
191
191
|
send(): Promise<ApiResponse>;
|
|
192
192
|
/**
|
|
193
193
|
* Thenable — `await client.get('/x')` sends the request and resolves to the
|
|
194
|
-
* {@link ApiResponse} (
|
|
194
|
+
* {@link ApiResponse} (helix parity). Assertion methods return `this`;
|
|
195
195
|
* awaiting one resolves via this `then` to the response after running the checks.
|
|
196
196
|
*/
|
|
197
197
|
then<R1 = ApiResponse, R2 = never>(onFulfilled?: ((value: ApiResponse) => R1 | PromiseLike<R1>) | null, onRejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null): Promise<R1 | R2>;
|
|
@@ -209,34 +209,34 @@ export declare class RequestBuilder {
|
|
|
209
209
|
assertBodyNotContains(subset: unknown): this;
|
|
210
210
|
assertTextIncludes(substring: string): this;
|
|
211
211
|
assertRedirectsTo(path: string): this;
|
|
212
|
-
/** Print the pending request (method/path/headers/body) —
|
|
212
|
+
/** Print the pending request (method/path/headers/body) — helix `request.dump()`. */
|
|
213
213
|
dump(): this;
|
|
214
|
-
/** Print only the pending request body —
|
|
214
|
+
/** Print only the pending request body — helix `request.dumpBody()`. */
|
|
215
215
|
dumpBody(): this;
|
|
216
|
-
/** Print only the pending request headers —
|
|
216
|
+
/** Print only the pending request headers — helix `request.dumpHeaders()`. */
|
|
217
217
|
dumpHeaders(): this;
|
|
218
|
-
/** Print only the pending request cookies —
|
|
218
|
+
/** Print only the pending request cookies — helix `request.dumpCookies()`. */
|
|
219
219
|
dumpCookies(): this;
|
|
220
220
|
/**
|
|
221
221
|
* Serialize `data` with a registered serializer and set it as the request body
|
|
222
222
|
* — the send-side twin of {@link ApiResponse.addParser}. Register serializers
|
|
223
|
-
* via {@link RequestBuilder.addSerializer} (
|
|
223
|
+
* via {@link RequestBuilder.addSerializer} (helix `ApiRequest.addSerializer`).
|
|
224
224
|
*/
|
|
225
225
|
serialize(name: string, data: unknown): this;
|
|
226
226
|
/**
|
|
227
|
-
* Register a shared property (
|
|
227
|
+
* Register a shared property (helix `ApiRequest.macro`) or lazy getter
|
|
228
228
|
* (`ApiRequest.getter`). The callback is invoked with `this` bound to the
|
|
229
|
-
* builder AND the builder as its first arg, so both
|
|
229
|
+
* builder AND the builder as its first arg, so both helix's
|
|
230
230
|
* `function () { return this.header('x') }` and `(req) => …` work.
|
|
231
231
|
*/
|
|
232
232
|
static macro(name: string, value: unknown): void;
|
|
233
233
|
static getter(name: string, fn: (this: RequestBuilder, req: RequestBuilder) => unknown): void;
|
|
234
|
-
/** Register a request body serializer —
|
|
234
|
+
/** Register a request body serializer — helix `ApiRequest.addSerializer`. */
|
|
235
235
|
static addSerializer(name: string, fn: (data: unknown) => {
|
|
236
236
|
body: Buffer;
|
|
237
237
|
contentType: string;
|
|
238
238
|
}): void;
|
|
239
|
-
/** Register a response body parser —
|
|
239
|
+
/** Register a response body parser — helix `ApiRequest.addParser` (delegates to ApiResponse). */
|
|
240
240
|
static addParser(contentType: string, fn: (body: string, headers: Record<string, string>) => unknown): void;
|
|
241
241
|
}
|
|
242
242
|
/** The status-shortcut assertions (lazy) are typed onto the builder. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestBuilder.d.ts","sourceRoot":"","sources":["../../src/testing/RequestBuilder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EACL,WAAW,EAKX,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EACL,WAAW,EACX,SAAS,EACT,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CACzF;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAE7D,MAAM,WAAW,YAAY;IAC3B,8FAA8F;IAC9F,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1F,oDAAoD;IACpD,UAAU,CAAC,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAC5F;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,SAAS,GACT,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAsBjB,
|
|
1
|
+
{"version":3,"file":"RequestBuilder.d.ts","sourceRoot":"","sources":["../../src/testing/RequestBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fluent HTTP request builder with assertion methods (
|
|
2
|
+
* Fluent HTTP request builder with assertion methods (`helix` model).
|
|
3
3
|
*
|
|
4
4
|
* await client
|
|
5
5
|
* .get('/api/users/42')
|
|
@@ -23,7 +23,7 @@ export { ApiResponse, deepEqual, partialMatch, } from './ApiResponse.js';
|
|
|
23
23
|
const CSRF_COOKIE_NAME = 'XSRF-TOKEN';
|
|
24
24
|
/** Header the client echoes the token back in (Axios/Angular default). */
|
|
25
25
|
const CSRF_HEADER_NAME = 'x-xsrf-token';
|
|
26
|
-
/** Content-type / accept shorthands — mirrors
|
|
26
|
+
/** Content-type / accept shorthands — mirrors helix's `.type()`/`.accept()`. */
|
|
27
27
|
const TYPE_SHORTHANDS = {
|
|
28
28
|
json: 'application/json',
|
|
29
29
|
form: 'application/x-www-form-urlencoded',
|
|
@@ -36,14 +36,14 @@ const TYPE_SHORTHANDS = {
|
|
|
36
36
|
function resolveMime(type) {
|
|
37
37
|
return TYPE_SHORTHANDS[type] ?? type;
|
|
38
38
|
}
|
|
39
|
-
/** HTTP statuses that trigger redirect-following (
|
|
39
|
+
/** HTTP statuses that trigger redirect-following (helix `.redirects()`). */
|
|
40
40
|
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
41
|
-
/**
|
|
41
|
+
/** helix follows 5 redirects by default. */
|
|
42
42
|
const DEFAULT_MAX_REDIRECTS = 5;
|
|
43
|
-
/** Consumer-registered macros/getters (
|
|
43
|
+
/** Consumer-registered macros/getters (helix `ApiRequest.macro`/`.getter`). */
|
|
44
44
|
const requestMacros = new Map();
|
|
45
45
|
const requestGetters = new Map();
|
|
46
|
-
/** Consumer-registered request body serializers (
|
|
46
|
+
/** Consumer-registered request body serializers (helix `ApiRequest.addSerializer`), by name. */
|
|
47
47
|
const requestSerializers = new Map();
|
|
48
48
|
// biome-ignore lint/suspicious/noUnsafeDeclarationMerging: the merged interface (StatusAssertions) types the status-shortcut asserts attached from STATUS_ASSERTIONS at load — the same generated-method pattern as EonSchema/Macroable (AdonisJS parity); every member is implemented, so the merge is safe.
|
|
49
49
|
export class RequestBuilder {
|
|
@@ -62,7 +62,7 @@ export class RequestBuilder {
|
|
|
62
62
|
#timeoutMs;
|
|
63
63
|
#maxRedirects = DEFAULT_MAX_REDIRECTS;
|
|
64
64
|
#sent = null;
|
|
65
|
-
// Lazy assertions (
|
|
65
|
+
// Lazy assertions (helix model): each `assert*`/`expect*` registers a check and
|
|
66
66
|
// returns `this` synchronously; the checks run in order when the builder is
|
|
67
67
|
// awaited (`then`) — after the single send.
|
|
68
68
|
#checks = [];
|
|
@@ -81,7 +81,7 @@ export class RequestBuilder {
|
|
|
81
81
|
return this;
|
|
82
82
|
}
|
|
83
83
|
header(name, value) {
|
|
84
|
-
//
|
|
84
|
+
// helix accepts string | string[]; a list is joined into one header value.
|
|
85
85
|
this.#headers[name.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value;
|
|
86
86
|
return this;
|
|
87
87
|
}
|
|
@@ -90,7 +90,7 @@ export class RequestBuilder {
|
|
|
90
90
|
this.#headers['content-type'] = 'application/json';
|
|
91
91
|
return this;
|
|
92
92
|
}
|
|
93
|
-
/**
|
|
93
|
+
/** helix `.unsafeJson()` — set a JSON body without any transform (alias of {@link json}). */
|
|
94
94
|
unsafeJson(data) {
|
|
95
95
|
return this.json(data);
|
|
96
96
|
}
|
|
@@ -101,7 +101,7 @@ export class RequestBuilder {
|
|
|
101
101
|
return this;
|
|
102
102
|
}
|
|
103
103
|
form(data) {
|
|
104
|
-
// Array values repeat the key (`a=1&a=2`) —
|
|
104
|
+
// Array values repeat the key (`a=1&a=2`) — helix parity.
|
|
105
105
|
const pairs = [];
|
|
106
106
|
for (const [k, v] of Object.entries(data)) {
|
|
107
107
|
const values = Array.isArray(v) ? v : [v];
|
|
@@ -113,12 +113,12 @@ export class RequestBuilder {
|
|
|
113
113
|
this.#headers['content-type'] = 'application/x-www-form-urlencoded';
|
|
114
114
|
return this;
|
|
115
115
|
}
|
|
116
|
-
/**
|
|
116
|
+
/** helix `.unsafeForm()` — set a urlencoded body without transform (alias of {@link form}). */
|
|
117
117
|
unsafeForm(data) {
|
|
118
118
|
return this.form(data);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
* Add a `multipart/form-data` field — mirrors Adonis/
|
|
121
|
+
* Add a `multipart/form-data` field — mirrors Adonis/helix's `.field()`. Accepts
|
|
122
122
|
* a string/number/boolean, a Buffer, a Blob, a Readable stream, or an array of
|
|
123
123
|
* these (repeated part). Calling `.field()`/`.fields()`/`.file()` switches the
|
|
124
124
|
* body to multipart; the boundary + `Content-Type` header are produced at send
|
|
@@ -135,7 +135,7 @@ export class RequestBuilder {
|
|
|
135
135
|
}
|
|
136
136
|
return this;
|
|
137
137
|
}
|
|
138
|
-
/** Add several multipart fields at once —
|
|
138
|
+
/** Add several multipart fields at once — helix `.fields()`. */
|
|
139
139
|
fields(map) {
|
|
140
140
|
for (const [name, value] of Object.entries(map)) {
|
|
141
141
|
this.field(name, value);
|
|
@@ -143,10 +143,10 @@ export class RequestBuilder {
|
|
|
143
143
|
return this;
|
|
144
144
|
}
|
|
145
145
|
/**
|
|
146
|
-
* Attach a file as a `multipart/form-data` part — mirrors Adonis/
|
|
146
|
+
* Attach a file as a `multipart/form-data` part — mirrors Adonis/helix's
|
|
147
147
|
* `.file(field, value, { filename, contentType })`. `value` is a Buffer, a
|
|
148
148
|
* Blob, a Readable stream, OR a string absolute PATH to a file on disk (read at
|
|
149
|
-
* call time,
|
|
149
|
+
* call time, helix parity). The filename defaults to the path basename / field
|
|
150
150
|
* name; streams/blobs are drained to Buffers at send time.
|
|
151
151
|
*/
|
|
152
152
|
file(field, value, options = {}) {
|
|
@@ -171,7 +171,7 @@ export class RequestBuilder {
|
|
|
171
171
|
return this;
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
|
-
* Append query-string params — mirrors
|
|
174
|
+
* Append query-string params — mirrors helix's `.qs()`. Values are
|
|
175
175
|
* URL-encoded; arrays repeat the key (`?tag=a&tag=b`). Merges with any query
|
|
176
176
|
* string already on the path and with earlier `.qs()` calls.
|
|
177
177
|
*/
|
|
@@ -188,19 +188,19 @@ export class RequestBuilder {
|
|
|
188
188
|
return this;
|
|
189
189
|
}
|
|
190
190
|
/**
|
|
191
|
-
* Append query params WITHOUT any validation/normalisation —
|
|
191
|
+
* Append query params WITHOUT any validation/normalisation — helix
|
|
192
192
|
* `.unsafeQs({ … })`. Values are still URL-encoded so the wire stays valid, but
|
|
193
193
|
* (unlike `.qs()`) no key filtering is applied; arrays repeat the key.
|
|
194
194
|
*/
|
|
195
195
|
unsafeQs(params) {
|
|
196
196
|
return this.qs(params);
|
|
197
197
|
}
|
|
198
|
-
/** Pass a bearer token as the `Authorization` header —
|
|
198
|
+
/** Pass a bearer token as the `Authorization` header — helix `.bearerToken()`. */
|
|
199
199
|
bearerToken(token) {
|
|
200
200
|
this.#headers.authorization = `Bearer ${token}`;
|
|
201
201
|
return this;
|
|
202
202
|
}
|
|
203
|
-
/** Pass HTTP Basic credentials as the `Authorization` header —
|
|
203
|
+
/** Pass HTTP Basic credentials as the `Authorization` header — helix `.basicAuth()`. */
|
|
204
204
|
basicAuth(user, password) {
|
|
205
205
|
const encoded = Buffer.from(`${user}:${password}`, 'utf8').toString('base64');
|
|
206
206
|
this.#headers.authorization = `Basic ${encoded}`;
|
|
@@ -208,7 +208,7 @@ export class RequestBuilder {
|
|
|
208
208
|
}
|
|
209
209
|
/**
|
|
210
210
|
* Set the request `Content-Type` from a shorthand (`'json'`, `'form'`, …) or a
|
|
211
|
-
* full MIME type — mirrors
|
|
211
|
+
* full MIME type — mirrors helix's `.type()`.
|
|
212
212
|
*/
|
|
213
213
|
type(mime) {
|
|
214
214
|
this.#headers['content-type'] = resolveMime(mime);
|
|
@@ -216,49 +216,49 @@ export class RequestBuilder {
|
|
|
216
216
|
}
|
|
217
217
|
/**
|
|
218
218
|
* Set the `Accept` header from a shorthand (`'json'`, `'html'`, …) or a full
|
|
219
|
-
* MIME type — mirrors
|
|
219
|
+
* MIME type — mirrors helix's `.accept()`.
|
|
220
220
|
*/
|
|
221
221
|
accept(mime) {
|
|
222
222
|
this.#headers.accept = resolveMime(mime);
|
|
223
223
|
return this;
|
|
224
224
|
}
|
|
225
|
-
/** Per-request timeout in ms —
|
|
225
|
+
/** Per-request timeout in ms — helix `.timeout()`. Honoured by the sender. */
|
|
226
226
|
timeout(ms) {
|
|
227
227
|
this.#timeoutMs = ms;
|
|
228
228
|
return this;
|
|
229
229
|
}
|
|
230
230
|
/**
|
|
231
|
-
* Follow up to `count` redirects before resolving —
|
|
232
|
-
* Defaults to 5 (
|
|
231
|
+
* Follow up to `count` redirects before resolving — helix `.redirects()`.
|
|
232
|
+
* Defaults to 5 (helix default); pass `0` to disable following.
|
|
233
233
|
*/
|
|
234
234
|
redirects(count) {
|
|
235
235
|
this.#maxRedirects = Math.max(0, count);
|
|
236
236
|
return this;
|
|
237
237
|
}
|
|
238
|
-
// TLS knobs —
|
|
238
|
+
// TLS knobs — helix parity. The test server is plain HTTP over loopback, so
|
|
239
239
|
// these are inert (there is no TLS handshake to configure); they exist so
|
|
240
|
-
//
|
|
241
|
-
/** No-op: the loopback test server has no TLS —
|
|
240
|
+
// helix-shaped code type-checks and runs unchanged. NAMED as a ream deviation.
|
|
241
|
+
/** No-op: the loopback test server has no TLS — helix `.trustLocalhost()`. */
|
|
242
242
|
trustLocalhost(_trust = true) {
|
|
243
243
|
return this;
|
|
244
244
|
}
|
|
245
|
-
/** No-op: no TLS on the loopback test server —
|
|
245
|
+
/** No-op: no TLS on the loopback test server — helix `.ca()`. */
|
|
246
246
|
ca(_cert) {
|
|
247
247
|
return this;
|
|
248
248
|
}
|
|
249
|
-
/** No-op: no TLS on the loopback test server —
|
|
249
|
+
/** No-op: no TLS on the loopback test server — helix `.cert()`. */
|
|
250
250
|
cert(_chain) {
|
|
251
251
|
return this;
|
|
252
252
|
}
|
|
253
|
-
/** No-op: no TLS on the loopback test server —
|
|
253
|
+
/** No-op: no TLS on the loopback test server — helix `.privateKey()`. */
|
|
254
254
|
privateKey(_key) {
|
|
255
255
|
return this;
|
|
256
256
|
}
|
|
257
|
-
/** No-op: no TLS on the loopback test server —
|
|
257
|
+
/** No-op: no TLS on the loopback test server — helix `.pfx()`. */
|
|
258
258
|
pfx(_encoded) {
|
|
259
259
|
return this;
|
|
260
260
|
}
|
|
261
|
-
/** No-op: no TLS on the loopback test server —
|
|
261
|
+
/** No-op: no TLS on the loopback test server — helix `.disableTLSCerts()`. */
|
|
262
262
|
disableTLSCerts() {
|
|
263
263
|
return this;
|
|
264
264
|
}
|
|
@@ -277,7 +277,7 @@ export class RequestBuilder {
|
|
|
277
277
|
this.#headers[CSRF_HEADER_NAME] = value;
|
|
278
278
|
return this;
|
|
279
279
|
}
|
|
280
|
-
/**
|
|
280
|
+
/** helix's spelling of {@link withCsrf}. */
|
|
281
281
|
withCsrfToken(token) {
|
|
282
282
|
return this.withCsrf(token);
|
|
283
283
|
}
|
|
@@ -318,10 +318,10 @@ export class RequestBuilder {
|
|
|
318
318
|
}
|
|
319
319
|
/**
|
|
320
320
|
* Thenable — `await client.get('/x')` sends the request and resolves to the
|
|
321
|
-
* {@link ApiResponse} (
|
|
321
|
+
* {@link ApiResponse} (helix parity). Assertion methods return `this`;
|
|
322
322
|
* awaiting one resolves via this `then` to the response after running the checks.
|
|
323
323
|
*/
|
|
324
|
-
// biome-ignore lint/suspicious/noThenProperty: the thenable IS the public API — `await client.get('/x')` is the documented
|
|
324
|
+
// biome-ignore lint/suspicious/noThenProperty: the thenable IS the public API — `await client.get('/x')` is the documented helix ergonomic; removing `.then` breaks every await-the-builder call site.
|
|
325
325
|
then(onFulfilled, onRejected) {
|
|
326
326
|
return this.#settle().then(onFulfilled, onRejected);
|
|
327
327
|
}
|
|
@@ -349,14 +349,14 @@ export class RequestBuilder {
|
|
|
349
349
|
}
|
|
350
350
|
expectJson(expected) {
|
|
351
351
|
// ream alias: partial JSON match with its own message (kept for back-compat;
|
|
352
|
-
// `assertBodyContains` is the
|
|
352
|
+
// `assertBodyContains` is the helix-named equivalent).
|
|
353
353
|
return this.#assert((res) => {
|
|
354
354
|
if (!partialMatch(res.json(), expected)) {
|
|
355
355
|
throw new ExpectationError(`JSON partial match failed.\nExpected (partial): ${JSON.stringify(expected)}\nActual: ${capBody(JSON.stringify(res.json()))}`);
|
|
356
356
|
}
|
|
357
357
|
});
|
|
358
358
|
}
|
|
359
|
-
// ──
|
|
359
|
+
// ── helix assertions (lazy — delegate to the response) ─────────────────────
|
|
360
360
|
assertStatus(code) {
|
|
361
361
|
return this.#assert((res) => res.assertStatus(code));
|
|
362
362
|
}
|
|
@@ -387,8 +387,8 @@ export class RequestBuilder {
|
|
|
387
387
|
assertRedirectsTo(path) {
|
|
388
388
|
return this.#assert((res) => res.assertRedirectsTo(path));
|
|
389
389
|
}
|
|
390
|
-
// ── Request debugging (
|
|
391
|
-
/** Print the pending request (method/path/headers/body) —
|
|
390
|
+
// ── Request debugging (helix `request.dump*` — dumps the REQUEST) ──────────
|
|
391
|
+
/** Print the pending request (method/path/headers/body) — helix `request.dump()`. */
|
|
392
392
|
dump() {
|
|
393
393
|
process.stderr.write(`[helix:request.dump] ${this.#method} ${this.#path}\n` +
|
|
394
394
|
`headers: ${JSON.stringify(this.#headers, null, 2)}\n` +
|
|
@@ -396,17 +396,17 @@ export class RequestBuilder {
|
|
|
396
396
|
`body: ${capBody(this.#body.toString('utf8'), 2048)}\n`);
|
|
397
397
|
return this;
|
|
398
398
|
}
|
|
399
|
-
/** Print only the pending request body —
|
|
399
|
+
/** Print only the pending request body — helix `request.dumpBody()`. */
|
|
400
400
|
dumpBody() {
|
|
401
401
|
process.stderr.write(`[helix:request.dumpBody] ${capBody(this.#body.toString('utf8'), 2048)}\n`);
|
|
402
402
|
return this;
|
|
403
403
|
}
|
|
404
|
-
/** Print only the pending request headers —
|
|
404
|
+
/** Print only the pending request headers — helix `request.dumpHeaders()`. */
|
|
405
405
|
dumpHeaders() {
|
|
406
406
|
process.stderr.write(`[helix:request.dumpHeaders] ${JSON.stringify(this.#headers, null, 2)}\n`);
|
|
407
407
|
return this;
|
|
408
408
|
}
|
|
409
|
-
/** Print only the pending request cookies —
|
|
409
|
+
/** Print only the pending request cookies — helix `request.dumpCookies()`. */
|
|
410
410
|
dumpCookies() {
|
|
411
411
|
process.stderr.write(`[helix:request.dumpCookies] ${JSON.stringify(this.#cookies, null, 2)}\n`);
|
|
412
412
|
return this;
|
|
@@ -455,7 +455,7 @@ export class RequestBuilder {
|
|
|
455
455
|
// json()/form()/body(); encode them with a fresh boundary at send time.
|
|
456
456
|
if (this.#multipart.length > 0) {
|
|
457
457
|
const boundary = `----ReamRequestBuilder${crypto.randomUUID().replace(/-/g, '')}`;
|
|
458
|
-
// Drain any stream/blob part to a Buffer before encoding (
|
|
458
|
+
// Drain any stream/blob part to a Buffer before encoding (helix parity).
|
|
459
459
|
const resolved = await Promise.all(this.#multipart.map(async (p) => p.kind === 'field'
|
|
460
460
|
? { kind: 'field', name: p.name, value: await toBuffer(p.value) }
|
|
461
461
|
: {
|
|
@@ -486,7 +486,7 @@ export class RequestBuilder {
|
|
|
486
486
|
body,
|
|
487
487
|
timeoutMs: this.#timeoutMs,
|
|
488
488
|
});
|
|
489
|
-
// Follow redirects up to the configured budget —
|
|
489
|
+
// Follow redirects up to the configured budget — helix `.redirects()` (5 by default).
|
|
490
490
|
const chain = [];
|
|
491
491
|
let followed = 0;
|
|
492
492
|
while (followed < this.#maxRedirects &&
|
|
@@ -519,7 +519,7 @@ export class RequestBuilder {
|
|
|
519
519
|
/**
|
|
520
520
|
* Serialize `data` with a registered serializer and set it as the request body
|
|
521
521
|
* — the send-side twin of {@link ApiResponse.addParser}. Register serializers
|
|
522
|
-
* via {@link RequestBuilder.addSerializer} (
|
|
522
|
+
* via {@link RequestBuilder.addSerializer} (helix `ApiRequest.addSerializer`).
|
|
523
523
|
*/
|
|
524
524
|
serialize(name, data) {
|
|
525
525
|
const serializer = requestSerializers.get(name);
|
|
@@ -532,9 +532,9 @@ export class RequestBuilder {
|
|
|
532
532
|
return this;
|
|
533
533
|
}
|
|
534
534
|
/**
|
|
535
|
-
* Register a shared property (
|
|
535
|
+
* Register a shared property (helix `ApiRequest.macro`) or lazy getter
|
|
536
536
|
* (`ApiRequest.getter`). The callback is invoked with `this` bound to the
|
|
537
|
-
* builder AND the builder as its first arg, so both
|
|
537
|
+
* builder AND the builder as its first arg, so both helix's
|
|
538
538
|
* `function () { return this.header('x') }` and `(req) => …` work.
|
|
539
539
|
*/
|
|
540
540
|
static macro(name, value) {
|
|
@@ -543,11 +543,11 @@ export class RequestBuilder {
|
|
|
543
543
|
static getter(name, fn) {
|
|
544
544
|
requestGetters.set(name, fn);
|
|
545
545
|
}
|
|
546
|
-
/** Register a request body serializer —
|
|
546
|
+
/** Register a request body serializer — helix `ApiRequest.addSerializer`. */
|
|
547
547
|
static addSerializer(name, fn) {
|
|
548
548
|
requestSerializers.set(name, fn);
|
|
549
549
|
}
|
|
550
|
-
/** Register a response body parser —
|
|
550
|
+
/** Register a response body parser — helix `ApiRequest.addParser` (delegates to ApiResponse). */
|
|
551
551
|
static addParser(contentType, fn) {
|
|
552
552
|
ApiResponse.addParser(contentType, fn);
|
|
553
553
|
}
|