@nifrajs/runner 4.0.2 → 5.1.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/dist/index.d.ts CHANGED
@@ -44,7 +44,11 @@ export interface RunResult {
44
44
  /** HTTP status - present when the app returned a response (absent when it threw). */
45
45
  readonly status?: number;
46
46
  readonly statusText?: string;
47
+ /** Response headers. Repeated `set-cookie` values are joined with `, `, as `Headers.get` does;
48
+ * `setCookie` keeps them apart. */
47
49
  readonly headers?: Readonly<Record<string, string>>;
50
+ /** Each `set-cookie` value, in order - present when the response set at least one cookie. */
51
+ readonly setCookie?: readonly string[];
48
52
  /** Parsed JSON when the response is JSON; otherwise the (possibly truncated) text. */
49
53
  readonly body?: unknown;
50
54
  /** The response body as text, truncated to `maxBodyChars`. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;0EAC0E;AAC1E,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACtD;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uBAAuB;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD;6FACyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,2CAA2C;AAC3C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9F;AAED,MAAM,WAAW,UAAU;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAoHD;8BAC8B;AAC9B,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CA8CpB;AASD;;;GAGG;AACH,wBAAgB,MAAM,CACpB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,EAAE,CAAC,CAMtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;0EAC0E;AAC1E,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACtD;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uBAAuB;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD;6FACyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,2CAA2C;AAC3C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B;uCACmC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,6FAA6F;IAC7F,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9F;AAED,MAAM,WAAW,UAAU;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAwHD;8BAC8B;AAC9B,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CA+CpB;AASD;;;GAGG;AACH,wBAAgB,MAAM,CACpB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,EAAE,CAAC,CAMtB"}
package/dist/index.js CHANGED
@@ -21,17 +21,9 @@ const now = () => typeof performance !== "undefined" && typeof performance.now =
21
21
  ? performance.now()
22
22
  : Date.now();
23
23
  const METHODS_WITHOUT_BODY = new Set(["GET", "HEAD"]);
24
- /** A plain JSON-ish object/array (encode it as JSON) - vs a string/binary body we pass through. */
24
+ /** Any object that is not a native Fetch body; callers check `isRequestBody` first. */
25
25
  function isJsonBody(body) {
26
- if (body === null || typeof body !== "object")
27
- return false;
28
- if (body instanceof Uint8Array || body instanceof ArrayBuffer || body instanceof Blob)
29
- return false;
30
- if (typeof FormData !== "undefined" && body instanceof FormData)
31
- return false;
32
- if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream)
33
- return false;
34
- return true;
26
+ return body !== null && typeof body === "object";
35
27
  }
36
28
  /** Runtime-check the non-JSON body shapes advertised by RequestSpec before crossing Fetch's API. */
37
29
  function isRequestBody(body) {
@@ -55,16 +47,21 @@ function buildRequest(spec, origin) {
55
47
  const headers = new Headers(spec.headers);
56
48
  const init = { method, headers };
57
49
  if (spec.body !== undefined && !METHODS_WITHOUT_BODY.has(method)) {
58
- if (isJsonBody(spec.body)) {
50
+ // A native Fetch body (URLSearchParams, FormData, a typed array) is an object too, so it is
51
+ // matched first and sent with the content type Fetch gives it.
52
+ if (isRequestBody(spec.body)) {
53
+ init.body = spec.body;
54
+ // Node's Request refuses a stream body without it; Bun and browsers accept it either way.
55
+ if (typeof ReadableStream !== "undefined" && spec.body instanceof ReadableStream)
56
+ init.duplex = "half";
57
+ }
58
+ else if (isJsonBody(spec.body)) {
59
59
  if (!headers.has("content-type"))
60
60
  headers.set("content-type", "application/json");
61
61
  init.body = JSON.stringify(spec.body);
62
62
  }
63
63
  else {
64
- if (!isRequestBody(spec.body)) {
65
- throw new TypeError("@nifrajs/runner: body must be a Fetch Request body");
66
- }
67
- init.body = spec.body;
64
+ throw new TypeError("@nifrajs/runner: body must be a Fetch Request body");
68
65
  }
69
66
  }
70
67
  return new Request(url, init);
@@ -72,10 +69,15 @@ function buildRequest(spec, origin) {
72
69
  function headersToObject(headers) {
73
70
  const out = {};
74
71
  headers.forEach((value, key) => {
75
- out[key] = value;
72
+ // Iteration yields each set-cookie on its own, so plain assignment would keep only the last.
73
+ out[key] = key === "set-cookie" && key in out ? `${out[key]}, ${value}` : value;
76
74
  });
77
75
  return out;
78
76
  }
77
+ function setCookieOf(headers) {
78
+ const cookies = headers.getSetCookie();
79
+ return cookies.length === 0 ? {} : { setCookie: cookies };
80
+ }
79
81
  /** Read at most the caller's character budget while enforcing a byte budget before decoding more data. */
80
82
  async function readBoundedText(response, maxChars) {
81
83
  if (response.body === null || maxChars === 0) {
@@ -107,9 +109,8 @@ async function readBoundedText(response, maxChars) {
107
109
  // while the final string slice preserves the public character-count contract.
108
110
  const byteBudget = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, remaining * 4));
109
111
  const allowed = Math.min(value.byteLength, byteBudget);
110
- const chunk = decoder.decode(value.subarray(0, allowed), {
111
- stream: allowed < value.byteLength,
112
- });
112
+ // Always streamed: a character split across two chunks decodes once the second arrives.
113
+ const chunk = decoder.decode(value.subarray(0, allowed), { stream: true });
113
114
  chunks.push(chunk);
114
115
  totalChars += chunk.length;
115
116
  if (allowed < value.byteLength || chunk.length > remaining) {
@@ -165,6 +166,7 @@ export async function runRequest(app, spec, options = {}) {
165
166
  status: res.status,
166
167
  statusText: res.statusText,
167
168
  headers: headersToObject(res.headers),
169
+ ...setCookieOf(res.headers),
168
170
  body,
169
171
  bodyText,
170
172
  ...(captured.truncated ? { truncated: true } : {}),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nifrajs/runner",
3
- "version": "4.0.2",
3
+ "version": "5.1.0",
4
4
  "description": "Run requests through a nifra app's fetch and capture structured results - the engine behind the playground and the agent run/verify tool. Dependency-free; runs in the browser, Bun, Node, Deno, and on the edge.",
5
5
  "keywords": [
6
6
  "bun",
package/src/index.ts CHANGED
@@ -47,7 +47,11 @@ export interface RunResult {
47
47
  /** HTTP status - present when the app returned a response (absent when it threw). */
48
48
  readonly status?: number
49
49
  readonly statusText?: string
50
+ /** Response headers. Repeated `set-cookie` values are joined with `, `, as `Headers.get` does;
51
+ * `setCookie` keeps them apart. */
50
52
  readonly headers?: Readonly<Record<string, string>>
53
+ /** Each `set-cookie` value, in order - present when the response set at least one cookie. */
54
+ readonly setCookie?: readonly string[]
51
55
  /** Parsed JSON when the response is JSON; otherwise the (possibly truncated) text. */
52
56
  readonly body?: unknown
53
57
  /** The response body as text, truncated to `maxBodyChars`. */
@@ -77,14 +81,9 @@ const now = (): number =>
77
81
 
78
82
  const METHODS_WITHOUT_BODY: ReadonlySet<string> = new Set(["GET", "HEAD"])
79
83
 
80
- /** A plain JSON-ish object/array (encode it as JSON) - vs a string/binary body we pass through. */
84
+ /** Any object that is not a native Fetch body; callers check `isRequestBody` first. */
81
85
  function isJsonBody(body: unknown): body is Record<string, unknown> | unknown[] {
82
- if (body === null || typeof body !== "object") return false
83
- if (body instanceof Uint8Array || body instanceof ArrayBuffer || body instanceof Blob)
84
- return false
85
- if (typeof FormData !== "undefined" && body instanceof FormData) return false
86
- if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream) return false
87
- return true
86
+ return body !== null && typeof body === "object"
88
87
  }
89
88
 
90
89
  type RequestBody = Exclude<RequestInit["body"], undefined>
@@ -105,17 +104,21 @@ function buildRequest(spec: RequestSpec, origin: string): Request {
105
104
  const url = /^https?:\/\//i.test(spec.path) ? spec.path : new URL(spec.path, origin).toString()
106
105
 
107
106
  const headers = new Headers(spec.headers as Record<string, string> | undefined)
108
- const init: RequestInit = { method, headers }
107
+ const init: RequestInit & { duplex?: "half" } = { method, headers }
109
108
 
110
109
  if (spec.body !== undefined && !METHODS_WITHOUT_BODY.has(method)) {
111
- if (isJsonBody(spec.body)) {
110
+ // A native Fetch body (URLSearchParams, FormData, a typed array) is an object too, so it is
111
+ // matched first and sent with the content type Fetch gives it.
112
+ if (isRequestBody(spec.body)) {
113
+ init.body = spec.body
114
+ // Node's Request refuses a stream body without it; Bun and browsers accept it either way.
115
+ if (typeof ReadableStream !== "undefined" && spec.body instanceof ReadableStream)
116
+ init.duplex = "half"
117
+ } else if (isJsonBody(spec.body)) {
112
118
  if (!headers.has("content-type")) headers.set("content-type", "application/json")
113
119
  init.body = JSON.stringify(spec.body)
114
120
  } else {
115
- if (!isRequestBody(spec.body)) {
116
- throw new TypeError("@nifrajs/runner: body must be a Fetch Request body")
117
- }
118
- init.body = spec.body
121
+ throw new TypeError("@nifrajs/runner: body must be a Fetch Request body")
119
122
  }
120
123
  }
121
124
  return new Request(url, init)
@@ -124,11 +127,17 @@ function buildRequest(spec: RequestSpec, origin: string): Request {
124
127
  function headersToObject(headers: Headers): Record<string, string> {
125
128
  const out: Record<string, string> = {}
126
129
  headers.forEach((value, key) => {
127
- out[key] = value
130
+ // Iteration yields each set-cookie on its own, so plain assignment would keep only the last.
131
+ out[key] = key === "set-cookie" && key in out ? `${out[key]}, ${value}` : value
128
132
  })
129
133
  return out
130
134
  }
131
135
 
136
+ function setCookieOf(headers: Headers): { readonly setCookie?: readonly string[] } {
137
+ const cookies = headers.getSetCookie()
138
+ return cookies.length === 0 ? {} : { setCookie: cookies }
139
+ }
140
+
132
141
  interface BoundedText {
133
142
  readonly text: string
134
143
  readonly truncated: boolean
@@ -163,9 +172,8 @@ async function readBoundedText(response: Response, maxChars: number): Promise<Bo
163
172
  // while the final string slice preserves the public character-count contract.
164
173
  const byteBudget = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, remaining * 4))
165
174
  const allowed = Math.min(value.byteLength, byteBudget)
166
- const chunk = decoder.decode(value.subarray(0, allowed), {
167
- stream: allowed < value.byteLength,
168
- })
175
+ // Always streamed: a character split across two chunks decodes once the second arrives.
176
+ const chunk = decoder.decode(value.subarray(0, allowed), { stream: true })
169
177
  chunks.push(chunk)
170
178
  totalChars += chunk.length
171
179
  if (allowed < value.byteLength || chunk.length > remaining) {
@@ -225,6 +233,7 @@ export async function runRequest(
225
233
  status: res.status,
226
234
  statusText: res.statusText,
227
235
  headers: headersToObject(res.headers),
236
+ ...setCookieOf(res.headers),
228
237
  body,
229
238
  bodyText,
230
239
  ...(captured.truncated ? { truncated: true } : {}),