@c9up/ream 0.2.5 → 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.
Files changed (76) hide show
  1. package/README.md +3 -9
  2. package/dist/HttpKernel.js +2 -2
  3. package/dist/HttpKernel.js.map +1 -1
  4. package/dist/Ignitor.d.ts +3 -3
  5. package/dist/Ignitor.d.ts.map +1 -1
  6. package/dist/Ignitor.js +33 -0
  7. package/dist/Ignitor.js.map +1 -1
  8. package/dist/helpers/compose.d.ts +30 -0
  9. package/dist/helpers/compose.d.ts.map +1 -0
  10. package/dist/helpers/compose.js +27 -0
  11. package/dist/helpers/compose.js.map +1 -0
  12. package/dist/helpers/index.d.ts +1 -0
  13. package/dist/helpers/index.d.ts.map +1 -1
  14. package/dist/helpers/index.js +1 -0
  15. package/dist/helpers/index.js.map +1 -1
  16. package/dist/helpers/is.d.ts +69 -16
  17. package/dist/helpers/is.d.ts.map +1 -1
  18. package/dist/helpers/is.js +79 -16
  19. package/dist/helpers/is.js.map +1 -1
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/middleware/Pipeline.d.ts +9 -3
  25. package/dist/middleware/Pipeline.d.ts.map +1 -1
  26. package/dist/middleware/Pipeline.js +10 -4
  27. package/dist/middleware/Pipeline.js.map +1 -1
  28. package/dist/rpc/RpcRouter.js +2 -2
  29. package/dist/rpc/RpcRouter.js.map +1 -1
  30. package/dist/services/app.d.ts +6 -0
  31. package/dist/services/app.d.ts.map +1 -1
  32. package/dist/services/app.js +8 -0
  33. package/dist/services/app.js.map +1 -1
  34. package/dist/services/config.d.ts +15 -0
  35. package/dist/services/config.d.ts.map +1 -0
  36. package/dist/services/config.js +18 -0
  37. package/dist/services/config.js.map +1 -0
  38. package/dist/services/encryption.d.ts +23 -0
  39. package/dist/services/encryption.d.ts.map +1 -0
  40. package/dist/services/encryption.js +33 -0
  41. package/dist/services/encryption.js.map +1 -0
  42. package/dist/services/urlBuilder.d.ts +21 -0
  43. package/dist/services/urlBuilder.d.ts.map +1 -0
  44. package/dist/services/urlBuilder.js +34 -0
  45. package/dist/services/urlBuilder.js.map +1 -0
  46. package/dist/testing/ApiResponse.d.ts +44 -44
  47. package/dist/testing/ApiResponse.d.ts.map +1 -1
  48. package/dist/testing/ApiResponse.js +48 -48
  49. package/dist/testing/ApiResponse.js.map +1 -1
  50. package/dist/testing/RequestBuilder.d.ts +39 -39
  51. package/dist/testing/RequestBuilder.d.ts.map +1 -1
  52. package/dist/testing/RequestBuilder.js +49 -49
  53. package/dist/testing/RequestBuilder.js.map +1 -1
  54. package/dist/testing/TestClient.d.ts +5 -5
  55. package/dist/testing/TestClient.d.ts.map +1 -1
  56. package/dist/testing/TestClient.js +7 -7
  57. package/dist/testing/TestClient.js.map +1 -1
  58. package/events.win32-x64-msvc.node +0 -0
  59. package/index.win32-x64-msvc.node +0 -0
  60. package/package.json +13 -1
  61. package/scheduler.win32-x64-msvc.node +0 -0
  62. package/src/HttpKernel.ts +2 -2
  63. package/src/Ignitor.ts +42 -3
  64. package/src/helpers/compose.ts +84 -0
  65. package/src/helpers/index.ts +1 -0
  66. package/src/helpers/is.ts +87 -16
  67. package/src/index.ts +2 -2
  68. package/src/middleware/Pipeline.ts +10 -4
  69. package/src/rpc/RpcRouter.ts +2 -2
  70. package/src/services/app.ts +9 -0
  71. package/src/services/config.ts +24 -0
  72. package/src/services/encryption.ts +42 -0
  73. package/src/services/urlBuilder.ts +41 -0
  74. package/src/testing/ApiResponse.ts +52 -52
  75. package/src/testing/RequestBuilder.ts +55 -55
  76. package/src/testing/TestClient.ts +8 -8
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Fluent HTTP request builder with assertion methods (`@japa/api-client` model).
2
+ * Fluent HTTP request builder with assertion methods (`helix` model).
3
3
  *
4
4
  * await client
5
5
  * .get('/api/users/42')
@@ -84,7 +84,7 @@ export interface AuthStrategy {
84
84
 
85
85
  /**
86
86
  * HTTP methods. The common verbs are named; `request(url, method)` also accepts
87
- * any other method (e.g. `TRACE`, `CONNECT`) — Japa parity — via the wider
87
+ * any other method (e.g. `TRACE`, `CONNECT`) — helix parity — via the wider
88
88
  * string fallback.
89
89
  */
90
90
  export type HttpMethod =
@@ -104,7 +104,7 @@ const CSRF_COOKIE_NAME = 'XSRF-TOKEN'
104
104
  /** Header the client echoes the token back in (Axios/Angular default). */
105
105
  const CSRF_HEADER_NAME = 'x-xsrf-token'
106
106
 
107
- /** Content-type / accept shorthands — mirrors japa/api-client's `.type()`/`.accept()`. */
107
+ /** Content-type / accept shorthands — mirrors helix's `.type()`/`.accept()`. */
108
108
  const TYPE_SHORTHANDS: Record<string, string> = {
109
109
  json: 'application/json',
110
110
  form: 'application/x-www-form-urlencoded',
@@ -119,14 +119,14 @@ function resolveMime(type: string): string {
119
119
  return TYPE_SHORTHANDS[type] ?? type
120
120
  }
121
121
 
122
- /** Primitive accepted as a query-string value (mirrors `.qs()` in japa/api-client). */
122
+ /** Primitive accepted as a query-string value (mirrors `.qs()` in helix). */
123
123
  type QueryValue = string | number | boolean
124
124
  /** Query-string map — a value or an array of values (repeated key). */
125
125
  export type QueryParams = Record<string, QueryValue | ReadonlyArray<QueryValue>>
126
126
 
127
- /** A scalar accepted by `form()`/`fields()` — Japa parity (arrays repeat the key). */
127
+ /** A scalar accepted by `form()`/`fields()` — helix parity (arrays repeat the key). */
128
128
  export type FieldValue = string | number | boolean | Buffer
129
- /** A value accepted by a multipart `field()`/`file()` — Japa parity (incl. streams/blobs). */
129
+ /** A value accepted by a multipart `field()`/`file()` — helix parity (incl. streams/blobs). */
130
130
  export type MultipartValue = string | number | boolean | Buffer | Blob | Readable
131
131
 
132
132
  /**
@@ -139,12 +139,12 @@ export type HttpSender = (
139
139
  init: {
140
140
  headers: Record<string, string>
141
141
  body: Buffer
142
- /** Per-request socket timeout (ms) — Japa `.timeout()`. Sender may honour it. */
142
+ /** Per-request socket timeout (ms) — helix `.timeout()`. Sender may honour it. */
143
143
  timeoutMs?: number
144
144
  },
145
145
  ) => Promise<TestResponse>
146
146
 
147
- /** Options for a multipart file part — mirrors Adonis/japa's `.file()` options. */
147
+ /** Options for a multipart file part — mirrors Adonis/helix's `.file()` options. */
148
148
  export interface FilePart {
149
149
  /** Filename advertised in the part's `Content-Disposition`. Defaults to the field name / basename. */
150
150
  filename?: string
@@ -160,15 +160,15 @@ type MultipartPart =
160
160
  | { kind: 'field'; name: string; value: MultipartValue }
161
161
  | { kind: 'file'; name: string; filename: string; contentType: string; content: MultipartValue }
162
162
 
163
- /** HTTP statuses that trigger redirect-following (Japa `.redirects()`). */
163
+ /** HTTP statuses that trigger redirect-following (helix `.redirects()`). */
164
164
  const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308])
165
- /** Japa follows 5 redirects by default. */
165
+ /** helix follows 5 redirects by default. */
166
166
  const DEFAULT_MAX_REDIRECTS = 5
167
167
 
168
- /** Consumer-registered macros/getters (Japa `ApiRequest.macro`/`.getter`). */
168
+ /** Consumer-registered macros/getters (helix `ApiRequest.macro`/`.getter`). */
169
169
  const requestMacros = new Map<string, unknown>()
170
170
  const requestGetters = new Map<string, (this: RequestBuilder, req: RequestBuilder) => unknown>()
171
- /** Consumer-registered request body serializers (Japa `ApiRequest.addSerializer`), by name. */
171
+ /** Consumer-registered request body serializers (helix `ApiRequest.addSerializer`), by name. */
172
172
  const requestSerializers = new Map<
173
173
  string,
174
174
  (data: unknown) => { body: Buffer; contentType: string }
@@ -194,7 +194,7 @@ export class RequestBuilder {
194
194
  #timeoutMs: number | undefined
195
195
  #maxRedirects = DEFAULT_MAX_REDIRECTS
196
196
  #sent: Promise<ApiResponse> | null = null
197
- // Lazy assertions (japa model): each `assert*`/`expect*` registers a check and
197
+ // Lazy assertions (helix model): each `assert*`/`expect*` registers a check and
198
198
  // returns `this` synchronously; the checks run in order when the builder is
199
199
  // awaited (`then`) — after the single send.
200
200
  #checks: Array<(res: ApiResponse) => void> = []
@@ -222,7 +222,7 @@ export class RequestBuilder {
222
222
  }
223
223
 
224
224
  header(name: string, value: string | string[]): this {
225
- // Japa accepts string | string[]; a list is joined into one header value.
225
+ // helix accepts string | string[]; a list is joined into one header value.
226
226
  this.#headers[name.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value
227
227
  return this
228
228
  }
@@ -233,7 +233,7 @@ export class RequestBuilder {
233
233
  return this
234
234
  }
235
235
 
236
- /** Japa `.unsafeJson()` — set a JSON body without any transform (alias of {@link json}). */
236
+ /** helix `.unsafeJson()` — set a JSON body without any transform (alias of {@link json}). */
237
237
  unsafeJson(data: unknown): this {
238
238
  return this.json(data)
239
239
  }
@@ -245,7 +245,7 @@ export class RequestBuilder {
245
245
  }
246
246
 
247
247
  form(data: Record<string, FieldValue | FieldValue[]>): this {
248
- // Array values repeat the key (`a=1&a=2`) — Japa parity.
248
+ // Array values repeat the key (`a=1&a=2`) — helix parity.
249
249
  const pairs: string[] = []
250
250
  for (const [k, v] of Object.entries(data)) {
251
251
  const values = Array.isArray(v) ? v : [v]
@@ -258,13 +258,13 @@ export class RequestBuilder {
258
258
  return this
259
259
  }
260
260
 
261
- /** Japa `.unsafeForm()` — set a urlencoded body without transform (alias of {@link form}). */
261
+ /** helix `.unsafeForm()` — set a urlencoded body without transform (alias of {@link form}). */
262
262
  unsafeForm(data: Record<string, FieldValue | FieldValue[]>): this {
263
263
  return this.form(data)
264
264
  }
265
265
 
266
266
  /**
267
- * Add a `multipart/form-data` field — mirrors Adonis/japa's `.field()`. Accepts
267
+ * Add a `multipart/form-data` field — mirrors Adonis/helix's `.field()`. Accepts
268
268
  * a string/number/boolean, a Buffer, a Blob, a Readable stream, or an array of
269
269
  * these (repeated part). Calling `.field()`/`.fields()`/`.file()` switches the
270
270
  * body to multipart; the boundary + `Content-Type` header are produced at send
@@ -282,7 +282,7 @@ export class RequestBuilder {
282
282
  return this
283
283
  }
284
284
 
285
- /** Add several multipart fields at once — Japa `.fields()`. */
285
+ /** Add several multipart fields at once — helix `.fields()`. */
286
286
  fields(map: Record<string, MultipartValue | MultipartValue[]>): this {
287
287
  for (const [name, value] of Object.entries(map)) {
288
288
  this.field(name, value)
@@ -291,10 +291,10 @@ export class RequestBuilder {
291
291
  }
292
292
 
293
293
  /**
294
- * Attach a file as a `multipart/form-data` part — mirrors Adonis/japa's
294
+ * Attach a file as a `multipart/form-data` part — mirrors Adonis/helix's
295
295
  * `.file(field, value, { filename, contentType })`. `value` is a Buffer, a
296
296
  * Blob, a Readable stream, OR a string absolute PATH to a file on disk (read at
297
- * call time, Japa parity). The filename defaults to the path basename / field
297
+ * call time, helix parity). The filename defaults to the path basename / field
298
298
  * name; streams/blobs are drained to Buffers at send time.
299
299
  */
300
300
  file(field: string, value: Buffer | string | Blob | Readable, options: FilePart = {}): this {
@@ -322,7 +322,7 @@ export class RequestBuilder {
322
322
  }
323
323
 
324
324
  /**
325
- * Append query-string params — mirrors japa/api-client's `.qs()`. Values are
325
+ * Append query-string params — mirrors helix's `.qs()`. Values are
326
326
  * URL-encoded; arrays repeat the key (`?tag=a&tag=b`). Merges with any query
327
327
  * string already on the path and with earlier `.qs()` calls.
328
328
  */
@@ -338,7 +338,7 @@ export class RequestBuilder {
338
338
  }
339
339
 
340
340
  /**
341
- * Append query params WITHOUT any validation/normalisation — Japa
341
+ * Append query params WITHOUT any validation/normalisation — helix
342
342
  * `.unsafeQs({ … })`. Values are still URL-encoded so the wire stays valid, but
343
343
  * (unlike `.qs()`) no key filtering is applied; arrays repeat the key.
344
344
  */
@@ -346,13 +346,13 @@ export class RequestBuilder {
346
346
  return this.qs(params)
347
347
  }
348
348
 
349
- /** Pass a bearer token as the `Authorization` header — japa `.bearerToken()`. */
349
+ /** Pass a bearer token as the `Authorization` header — helix `.bearerToken()`. */
350
350
  bearerToken(token: string): this {
351
351
  this.#headers.authorization = `Bearer ${token}`
352
352
  return this
353
353
  }
354
354
 
355
- /** Pass HTTP Basic credentials as the `Authorization` header — japa `.basicAuth()`. */
355
+ /** Pass HTTP Basic credentials as the `Authorization` header — helix `.basicAuth()`. */
356
356
  basicAuth(user: string, password: string): this {
357
357
  const encoded = Buffer.from(`${user}:${password}`, 'utf8').toString('base64')
358
358
  this.#headers.authorization = `Basic ${encoded}`
@@ -361,7 +361,7 @@ export class RequestBuilder {
361
361
 
362
362
  /**
363
363
  * Set the request `Content-Type` from a shorthand (`'json'`, `'form'`, …) or a
364
- * full MIME type — mirrors japa/api-client's `.type()`.
364
+ * full MIME type — mirrors helix's `.type()`.
365
365
  */
366
366
  type(mime: string): this {
367
367
  this.#headers['content-type'] = resolveMime(mime)
@@ -370,52 +370,52 @@ export class RequestBuilder {
370
370
 
371
371
  /**
372
372
  * Set the `Accept` header from a shorthand (`'json'`, `'html'`, …) or a full
373
- * MIME type — mirrors japa/api-client's `.accept()`.
373
+ * MIME type — mirrors helix's `.accept()`.
374
374
  */
375
375
  accept(mime: string): this {
376
376
  this.#headers.accept = resolveMime(mime)
377
377
  return this
378
378
  }
379
379
 
380
- /** Per-request timeout in ms — Japa `.timeout()`. Honoured by the sender. */
380
+ /** Per-request timeout in ms — helix `.timeout()`. Honoured by the sender. */
381
381
  timeout(ms: number): this {
382
382
  this.#timeoutMs = ms
383
383
  return this
384
384
  }
385
385
 
386
386
  /**
387
- * Follow up to `count` redirects before resolving — Japa `.redirects()`.
388
- * Defaults to 5 (Japa default); pass `0` to disable following.
387
+ * Follow up to `count` redirects before resolving — helix `.redirects()`.
388
+ * Defaults to 5 (helix default); pass `0` to disable following.
389
389
  */
390
390
  redirects(count: number): this {
391
391
  this.#maxRedirects = Math.max(0, count)
392
392
  return this
393
393
  }
394
394
 
395
- // TLS knobs — Japa parity. The test server is plain HTTP over loopback, so
395
+ // TLS knobs — helix parity. The test server is plain HTTP over loopback, so
396
396
  // these are inert (there is no TLS handshake to configure); they exist so
397
- // Japa-shaped code type-checks and runs unchanged. NAMED as a ream deviation.
398
- /** No-op: the loopback test server has no TLS — Japa `.trustLocalhost()`. */
397
+ // helix-shaped code type-checks and runs unchanged. NAMED as a ream deviation.
398
+ /** No-op: the loopback test server has no TLS — helix `.trustLocalhost()`. */
399
399
  trustLocalhost(_trust = true): this {
400
400
  return this
401
401
  }
402
- /** No-op: no TLS on the loopback test server — Japa `.ca()`. */
402
+ /** No-op: no TLS on the loopback test server — helix `.ca()`. */
403
403
  ca(_cert: string): this {
404
404
  return this
405
405
  }
406
- /** No-op: no TLS on the loopback test server — Japa `.cert()`. */
406
+ /** No-op: no TLS on the loopback test server — helix `.cert()`. */
407
407
  cert(_chain: string): this {
408
408
  return this
409
409
  }
410
- /** No-op: no TLS on the loopback test server — Japa `.privateKey()`. */
410
+ /** No-op: no TLS on the loopback test server — helix `.privateKey()`. */
411
411
  privateKey(_key: string): this {
412
412
  return this
413
413
  }
414
- /** No-op: no TLS on the loopback test server — Japa `.pfx()`. */
414
+ /** No-op: no TLS on the loopback test server — helix `.pfx()`. */
415
415
  pfx(_encoded: string | Buffer): this {
416
416
  return this
417
417
  }
418
- /** No-op: no TLS on the loopback test server — Japa `.disableTLSCerts()`. */
418
+ /** No-op: no TLS on the loopback test server — helix `.disableTLSCerts()`. */
419
419
  disableTLSCerts(): this {
420
420
  return this
421
421
  }
@@ -437,7 +437,7 @@ export class RequestBuilder {
437
437
  return this
438
438
  }
439
439
 
440
- /** japa/api-client's spelling of {@link withCsrf}. */
440
+ /** helix's spelling of {@link withCsrf}. */
441
441
  withCsrfToken(token?: string): this {
442
442
  return this.withCsrf(token)
443
443
  }
@@ -482,10 +482,10 @@ export class RequestBuilder {
482
482
 
483
483
  /**
484
484
  * Thenable — `await client.get('/x')` sends the request and resolves to the
485
- * {@link ApiResponse} (Japa/api-client parity). Assertion methods return `this`;
485
+ * {@link ApiResponse} (helix parity). Assertion methods return `this`;
486
486
  * awaiting one resolves via this `then` to the response after running the checks.
487
487
  */
488
- // biome-ignore lint/suspicious/noThenProperty: the thenable IS the public API — `await client.get('/x')` is the documented Japa/api-client ergonomic; removing `.then` breaks every await-the-builder call site.
488
+ // 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.
489
489
  then<R1 = ApiResponse, R2 = never>(
490
490
  onFulfilled?: ((value: ApiResponse) => R1 | PromiseLike<R1>) | null,
491
491
  onRejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null,
@@ -519,7 +519,7 @@ export class RequestBuilder {
519
519
  }
520
520
  expectJson(expected: unknown): this {
521
521
  // ream alias: partial JSON match with its own message (kept for back-compat;
522
- // `assertBodyContains` is the Japa-named equivalent).
522
+ // `assertBodyContains` is the helix-named equivalent).
523
523
  return this.#assert((res) => {
524
524
  if (!partialMatch(res.json(), expected)) {
525
525
  throw new ExpectationError(
@@ -529,7 +529,7 @@ export class RequestBuilder {
529
529
  })
530
530
  }
531
531
 
532
- // ── Japa assertions (lazy — delegate to the response) ─────────────────────
532
+ // ── helix assertions (lazy — delegate to the response) ─────────────────────
533
533
 
534
534
  assertStatus(code: number): this {
535
535
  return this.#assert((res) => res.assertStatus(code))
@@ -562,9 +562,9 @@ export class RequestBuilder {
562
562
  return this.#assert((res) => res.assertRedirectsTo(path))
563
563
  }
564
564
 
565
- // ── Request debugging (Japa `request.dump*` — dumps the REQUEST) ──────────
565
+ // ── Request debugging (helix `request.dump*` — dumps the REQUEST) ──────────
566
566
 
567
- /** Print the pending request (method/path/headers/body) — Japa `request.dump()`. */
567
+ /** Print the pending request (method/path/headers/body) — helix `request.dump()`. */
568
568
  dump(): this {
569
569
  process.stderr.write(
570
570
  `[helix:request.dump] ${this.#method} ${this.#path}\n` +
@@ -574,17 +574,17 @@ export class RequestBuilder {
574
574
  )
575
575
  return this
576
576
  }
577
- /** Print only the pending request body — Japa `request.dumpBody()`. */
577
+ /** Print only the pending request body — helix `request.dumpBody()`. */
578
578
  dumpBody(): this {
579
579
  process.stderr.write(`[helix:request.dumpBody] ${capBody(this.#body.toString('utf8'), 2048)}\n`)
580
580
  return this
581
581
  }
582
- /** Print only the pending request headers — Japa `request.dumpHeaders()`. */
582
+ /** Print only the pending request headers — helix `request.dumpHeaders()`. */
583
583
  dumpHeaders(): this {
584
584
  process.stderr.write(`[helix:request.dumpHeaders] ${JSON.stringify(this.#headers, null, 2)}\n`)
585
585
  return this
586
586
  }
587
- /** Print only the pending request cookies — Japa `request.dumpCookies()`. */
587
+ /** Print only the pending request cookies — helix `request.dumpCookies()`. */
588
588
  dumpCookies(): this {
589
589
  process.stderr.write(`[helix:request.dumpCookies] ${JSON.stringify(this.#cookies, null, 2)}\n`)
590
590
  return this
@@ -640,7 +640,7 @@ export class RequestBuilder {
640
640
  // json()/form()/body(); encode them with a fresh boundary at send time.
641
641
  if (this.#multipart.length > 0) {
642
642
  const boundary = `----ReamRequestBuilder${crypto.randomUUID().replace(/-/g, '')}`
643
- // Drain any stream/blob part to a Buffer before encoding (Japa parity).
643
+ // Drain any stream/blob part to a Buffer before encoding (helix parity).
644
644
  const resolved: ResolvedPart[] = await Promise.all(
645
645
  this.#multipart.map(async (p) =>
646
646
  p.kind === 'field'
@@ -679,7 +679,7 @@ export class RequestBuilder {
679
679
  timeoutMs: this.#timeoutMs,
680
680
  })
681
681
 
682
- // Follow redirects up to the configured budget — Japa `.redirects()` (5 by default).
682
+ // Follow redirects up to the configured budget — helix `.redirects()` (5 by default).
683
683
  const chain: string[] = []
684
684
  let followed = 0
685
685
  while (
@@ -715,7 +715,7 @@ export class RequestBuilder {
715
715
  /**
716
716
  * Serialize `data` with a registered serializer and set it as the request body
717
717
  * — the send-side twin of {@link ApiResponse.addParser}. Register serializers
718
- * via {@link RequestBuilder.addSerializer} (Japa `ApiRequest.addSerializer`).
718
+ * via {@link RequestBuilder.addSerializer} (helix `ApiRequest.addSerializer`).
719
719
  */
720
720
  serialize(name: string, data: unknown): this {
721
721
  const serializer = requestSerializers.get(name)
@@ -731,9 +731,9 @@ export class RequestBuilder {
731
731
  }
732
732
 
733
733
  /**
734
- * Register a shared property (Japa `ApiRequest.macro`) or lazy getter
734
+ * Register a shared property (helix `ApiRequest.macro`) or lazy getter
735
735
  * (`ApiRequest.getter`). The callback is invoked with `this` bound to the
736
- * builder AND the builder as its first arg, so both Japa's
736
+ * builder AND the builder as its first arg, so both helix's
737
737
  * `function () { return this.header('x') }` and `(req) => …` work.
738
738
  */
739
739
  static macro(name: string, value: unknown): void {
@@ -743,7 +743,7 @@ export class RequestBuilder {
743
743
  requestGetters.set(name, fn)
744
744
  }
745
745
 
746
- /** Register a request body serializer — Japa `ApiRequest.addSerializer`. */
746
+ /** Register a request body serializer — helix `ApiRequest.addSerializer`. */
747
747
  static addSerializer(
748
748
  name: string,
749
749
  fn: (data: unknown) => { body: Buffer; contentType: string },
@@ -751,7 +751,7 @@ export class RequestBuilder {
751
751
  requestSerializers.set(name, fn)
752
752
  }
753
753
 
754
- /** Register a response body parser — Japa `ApiRequest.addParser` (delegates to ApiResponse). */
754
+ /** Register a response body parser — helix `ApiRequest.addParser` (delegates to ApiResponse). */
755
755
  static addParser(
756
756
  contentType: string,
757
757
  fn: (body: string, headers: Record<string, string>) => unknown,
@@ -37,7 +37,7 @@ export { ApiResponse, type TestResponse } from './RequestBuilder.js'
37
37
  * named routes without the full Router.
38
38
  *
39
39
  * A value may be a bare path string OR `{ path, method }` — when the method is
40
- * present, `visit(name)` uses it (Japa route-registry parity, e.g.
40
+ * present, `visit(name)` uses it (helix route-registry parity, e.g.
41
41
  * `visit('users.store').json(...).assertCreated()` issues a POST).
42
42
  */
43
43
  export type RouteEntry = string | { path: string; method?: HttpMethod }
@@ -98,7 +98,7 @@ export class TestClient {
98
98
  return this
99
99
  }
100
100
 
101
- // Verb shortcuts return the RICH builder — the full japa/api-client surface
101
+ // Verb shortcuts return the RICH builder — the full helix surface
102
102
  // (assertOk/assertStatus/assertBody/… + auth/csrf) AND awaitable (`await
103
103
  // client.get('/x')` sends and resolves to the response). One unified builder,
104
104
  // no split between `get()` and `fluent()`.
@@ -129,14 +129,14 @@ export class TestClient {
129
129
  }
130
130
 
131
131
  /**
132
- * HEAD request — japa/api-client's `.head()`. Returns the rich builder so you
132
+ * HEAD request — helix's `.head()`. Returns the rich builder so you
133
133
  * can assert status/headers (a HEAD response carries headers, no body).
134
134
  */
135
135
  head(path: string): RequestBuilder {
136
136
  return this.fluent('HEAD', path)
137
137
  }
138
138
 
139
- /** OPTIONS request — japa/api-client's `.options()`. */
139
+ /** OPTIONS request — helix's `.options()`. */
140
140
  options(path: string): RequestBuilder {
141
141
  return this.fluent('OPTIONS', path)
142
142
  }
@@ -161,7 +161,7 @@ export class TestClient {
161
161
  }
162
162
 
163
163
  /**
164
- * GET a named route — japa/api-client's `.visit()`. Resolves `name` against
164
+ * GET a named route — helix's `.visit()`. Resolves `name` against
165
165
  * the `routes` manifest (`router.namedManifest()`), fills `:param`
166
166
  * placeholders, and returns the rich chainable builder. Throws a clear error
167
167
  * when no manifest was configured or the name is unknown.
@@ -173,14 +173,14 @@ export class TestClient {
173
173
  )
174
174
  }
175
175
  const entry = this.#routes[name]
176
- // Method comes from the registry when the entry carries one (Japa parity),
176
+ // Method comes from the registry when the entry carries one (helix parity),
177
177
  // otherwise GET.
178
178
  const method: HttpMethod = typeof entry === 'object' && entry.method ? entry.method : 'GET'
179
179
  return this.fluent(method, resolveNamedRoute(this.#routes, name, params))
180
180
  }
181
181
 
182
182
  /**
183
- * Generic request — japa/api-client's `client.request(url, method)` (note the
183
+ * Generic request — helix's `client.request(url, method)` (note the
184
184
  * arg order: URL first, method second, defaulting to GET). Returns the same
185
185
  * rich, awaitable builder as the verb shortcuts.
186
186
  */
@@ -294,7 +294,7 @@ async function sendRequest(
294
294
  // and surfaced as flaky `bob accepts` / `non-member 403` failures
295
295
  // in kitchen-sink's workspace.test.ts. 30s matches the helix
296
296
  // `--timeout=60000` per-test budget without masking real hangs. A
297
- // per-request `.timeout(ms)` (Japa) overrides the default.
297
+ // per-request `.timeout(ms)` (helix) overrides the default.
298
298
  socket.setTimeout(timeoutMs && timeoutMs > 0 ? timeoutMs : 30_000, () => {
299
299
  socket.destroy()
300
300
  reject(new Error('TestClient request timed out'))