@juit/lib-fetch-mock 1.0.3 → 1.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/README.md CHANGED
@@ -5,6 +5,7 @@ This package allows to quicly mock the global `fetch` distributed with Node 18
5
5
  (and greater).
6
6
 
7
7
  * [Request Handlers](#request-handlers)
8
+ * [Wrapping Mocks](#wrapping-mocks)
8
9
  * [Request Interception](#request-interception)
9
10
  * [License](LICENSE.md)
10
11
  * [Copyright](NOTICE.md)
@@ -55,6 +56,33 @@ The functions `sendStatus(...)`, `sendJson(...)`, `sendText(...)` and
55
56
  `sendData(...)` can be used to generate simple responses for mocking.
56
57
 
57
58
 
59
+ ### Wrapping Mocks
60
+
61
+ Mock instances can be wrapped to support in testing. For example:
62
+
63
+ ```ts
64
+ const handler1 = new FetchMock()
65
+ handler1.on('GET', '/foo', (_) => new Response('FOO'))
66
+ handler1.on('GET', '/baz', (_) => new Response('FOO'))
67
+
68
+ const handler2 = new FetchMock()
69
+ handler2.on('GET', '/foo', (_) => new Response('Another FOO'))
70
+ handler2.on('GET', '/bar', (_) => new Response('BAR'))
71
+
72
+ handler1.install()
73
+ handler2.install() // this will be the _top most_ as it's installed later
74
+ ```
75
+
76
+ The last installed `FetchMock` instance will be the _top-most_ capturing all
77
+ requests and forwarding requests to sub-mocks only when not matched.
78
+
79
+ In the example above:
80
+
81
+ * requests for `/foo` will be intercepted by `handler2` and _not_ forwarded to `handler1`
82
+ * requests for `/bar` will be handled locally
83
+ * requests for `/baz` will simply be forwarded to `handler1`
84
+
85
+
58
86
  ### Request Interception
59
87
 
60
88
  As in some case it's easier to _await_ in tests for a specific request (rather
package/dist/index.cjs CHANGED
@@ -28,17 +28,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
33
  FetchMock: () => FetchMock,
34
34
  sendData: () => sendData,
35
35
  sendJson: () => sendJson,
36
36
  sendStatus: () => sendStatus,
37
37
  sendText: () => sendText
38
38
  });
39
- module.exports = __toCommonJS(src_exports);
40
- var import_node_http = require("node:http");
39
+ module.exports = __toCommonJS(index_exports);
41
40
  var import_node_assert = __toESM(require("node:assert"));
41
+ var import_node_http = require("node:http");
42
42
  var mockSymbol = Symbol.for("juit.fetch.mock");
43
43
  process.on("exit", () => process.exit(process.exitCode));
44
44
  var FetchMockImpl = class {
@@ -61,7 +61,11 @@ var FetchMockImpl = class {
61
61
  response = typeof result === "number" ? sendStatus(result) : result;
62
62
  break;
63
63
  }
64
- return response || sendStatus(404);
64
+ if (response) return response;
65
+ if (this._fetch[mockSymbol]) {
66
+ return this._fetch[mockSymbol].$fetch(info, init);
67
+ }
68
+ return sendStatus(404);
65
69
  }
66
70
  /* === HANDLERS =========================================================== */
67
71
  on(method, path, handler) {
@@ -107,7 +111,14 @@ var FetchMockImpl = class {
107
111
  install() {
108
112
  if (mockSymbol in globalThis.fetch) {
109
113
  if (globalThis.fetch[mockSymbol] === this) return this;
110
- import_node_assert.default.fail("Global `fetch` already mocked");
114
+ }
115
+ let fn = globalThis.fetch;
116
+ while (fn && fn[mockSymbol]) {
117
+ if (fn[mockSymbol] === this) {
118
+ throw new Error("Global `fetch` already mocked by this instance");
119
+ } else {
120
+ fn = fn[mockSymbol]._fetch;
121
+ }
111
122
  }
112
123
  this._fetch = globalThis.fetch;
113
124
  globalThis.fetch = this.$fetch.bind(this);
@@ -116,9 +127,20 @@ var FetchMockImpl = class {
116
127
  }
117
128
  destroy() {
118
129
  if (!(mockSymbol in globalThis.fetch)) return;
119
- const instance = globalThis.fetch[mockSymbol];
120
- (0, import_node_assert.default)(instance === this, "Attempting to disable non-enabled mock instance");
121
- globalThis.fetch = this._fetch;
130
+ if (!this._fetch) return;
131
+ let parent = void 0;
132
+ let fn = globalThis.fetch;
133
+ while (fn[mockSymbol]) {
134
+ if (fn[mockSymbol] === this) {
135
+ if (!parent) globalThis.fetch = this._fetch;
136
+ else parent._fetch = this._fetch;
137
+ break;
138
+ } else {
139
+ parent = fn[mockSymbol];
140
+ fn = fn[mockSymbol]._fetch;
141
+ }
142
+ }
143
+ this._fetch = void 0;
122
144
  }
123
145
  };
124
146
  var FetchMock = FetchMockImpl;
@@ -183,7 +205,7 @@ function sendJson(data, status = 200) {
183
205
  });
184
206
  }
185
207
  function sendData(data, status = 200) {
186
- return new Response(data, {
208
+ return new Response(Buffer.from(data), {
187
209
  headers: { "content-type": "application/octet-stream" },
188
210
  statusText: import_node_http.STATUS_CODES[status],
189
211
  status
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": ["assert", "info", "init"]
6
6
  }
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // index.ts
2
- import { STATUS_CODES } from "node:http";
3
2
  import assert from "node:assert";
3
+ import { STATUS_CODES } from "node:http";
4
4
  var mockSymbol = Symbol.for("juit.fetch.mock");
5
5
  process.on("exit", () => process.exit(process.exitCode));
6
6
  var FetchMockImpl = class {
@@ -23,7 +23,11 @@ var FetchMockImpl = class {
23
23
  response = typeof result === "number" ? sendStatus(result) : result;
24
24
  break;
25
25
  }
26
- return response || sendStatus(404);
26
+ if (response) return response;
27
+ if (this._fetch[mockSymbol]) {
28
+ return this._fetch[mockSymbol].$fetch(info, init);
29
+ }
30
+ return sendStatus(404);
27
31
  }
28
32
  /* === HANDLERS =========================================================== */
29
33
  on(method, path, handler) {
@@ -69,7 +73,14 @@ var FetchMockImpl = class {
69
73
  install() {
70
74
  if (mockSymbol in globalThis.fetch) {
71
75
  if (globalThis.fetch[mockSymbol] === this) return this;
72
- assert.fail("Global `fetch` already mocked");
76
+ }
77
+ let fn = globalThis.fetch;
78
+ while (fn && fn[mockSymbol]) {
79
+ if (fn[mockSymbol] === this) {
80
+ throw new Error("Global `fetch` already mocked by this instance");
81
+ } else {
82
+ fn = fn[mockSymbol]._fetch;
83
+ }
73
84
  }
74
85
  this._fetch = globalThis.fetch;
75
86
  globalThis.fetch = this.$fetch.bind(this);
@@ -78,9 +89,20 @@ var FetchMockImpl = class {
78
89
  }
79
90
  destroy() {
80
91
  if (!(mockSymbol in globalThis.fetch)) return;
81
- const instance = globalThis.fetch[mockSymbol];
82
- assert(instance === this, "Attempting to disable non-enabled mock instance");
83
- globalThis.fetch = this._fetch;
92
+ if (!this._fetch) return;
93
+ let parent = void 0;
94
+ let fn = globalThis.fetch;
95
+ while (fn[mockSymbol]) {
96
+ if (fn[mockSymbol] === this) {
97
+ if (!parent) globalThis.fetch = this._fetch;
98
+ else parent._fetch = this._fetch;
99
+ break;
100
+ } else {
101
+ parent = fn[mockSymbol];
102
+ fn = fn[mockSymbol]._fetch;
103
+ }
104
+ }
105
+ this._fetch = void 0;
84
106
  }
85
107
  };
86
108
  var FetchMock = FetchMockImpl;
@@ -145,7 +167,7 @@ function sendJson(data, status = 200) {
145
167
  });
146
168
  }
147
169
  function sendData(data, status = 200) {
148
- return new Response(data, {
170
+ return new Response(Buffer.from(data), {
149
171
  headers: { "content-type": "application/octet-stream" },
150
172
  statusText: STATUS_CODES[status],
151
173
  status
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "mappings": "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",
4
+ "mappings": ";AAAA,OAAO,YAAY;AACnB,SAAS,oBAAoB;AAE7B,IAAM,aAAa,OAAO,IAAI,iBAAiB;AAsB/C,QAAQ,GAAG,QAAQ,MAAM,QAAQ,KAAK,QAAQ,QAAQ,CAAC;AA8BvD,IAAM,gBAAN,MAAyC;AAAA,EAC/B,YAA4B,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EAER,YAAY,SAAoC;AAC9C,SAAK,WAAW,IAAI,IAAI,WAAW,cAAc;AAAA,EACnD;AAAA;AAAA,EAIA,MAAc,OACV,MACA,MACiB;AACnB,WAAO,KAAK,QAAQ,kDAAkD;AAMtE,UAAM,YAAY,KAAK;AACvB,UAAM,eAAe,CACjBA,OACAC,UACoB,UAAU,KAAK,YAAYD,OAAMC,KAAI;AAE7D,UAAM,UAAW,gBAAgB,OAAS,OAAO,SAAS,WACxD,IAAI,QAAQ,IAAI,IAAI,MAAM,KAAK,QAAQ,GAAG,IAAI,IAC9C,IAAI,QAAQ,MAAM,IAAI;AAExB,QAAI,WAAiC;AAErC,eAAW,WAAW,KAAK,WAAW;AACpC,YAAM,SAAS,MAAM,QAAQ,SAAS,YAAY;AAClD,UAAK,WAAW,UAAe,WAAW,KAAO;AAEjD,iBAAY,OAAO,WAAW,WAAY,WAAW,MAAM,IAAI;AAC/D;AAAA,IACF;AAGA,QAAI,SAAU,QAAO;AAGrB,QAAI,KAAK,OAAO,UAAU,GAAG;AAC3B,aAAO,KAAK,OAAO,UAAU,EAAE,OAAO,MAAM,IAAI;AAAA,IAClD;AAGA,WAAO,WAAW,GAAG;AAAA,EACvB;AAAA;AAAA,EAIA,GAAG,QAAgB,MAAuB,SAA6B;AACrE,SAAK,UAAU,KAAK,CAAC,SAAS,UAAU;AACtC,UAAI,QAAQ,WAAW,OAAO,YAAY,EAAG;AAE7C,YAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE;AACtC,UAAM,OAAO,SAAS,YAAc,SAAS,YACvC,gBAAgB,UAAW,SAAS,MAAM,IAAI,GAAI;AACtD,eAAO,QAAQ,SAAS,KAAK;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,SAA6B;AAClC,SAAK,UAAU,KAAK,OAAO;AAC3B,WAAO;AAAA,EACT;AAAA,EAEA,QAAc;AACZ,SAAK,YAAY,CAAC;AAClB,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,YAA4C;AAC1C,UAAM,QAAqC,CAAC;AAC5C,UAAM,KAAK,IAAI,SAA0B,CAAC;AAE1C,UAAM,OAAuC,MAAM;AACjD,aAAO,IAAI,QAAyB,CAAC,SAAS,WAAW;AACvD,cAAM,CAAC,EAAG,QAAQ,KAAK,CAAC,YAAY;AAClC,gBAAM,OAAO,GAAG,CAAC;AACjB,kBAAQ,OAAO;AAAA,QACjB,GAAG,MAAM;AAAA,MACX,CAAC;AAAA,IACH;AAEA,SAAK,UAAU,KAAK,CAAC,SAAkB,UAA4C;AACjF,YAAM,KAAK,IAAI,SAA0B,CAAC;AAE1C,YAAM,mBAAmB,IAAI,SAAmB;AAChD,YAAM,kBAAkB,IAAI,oBAAoB,SAAS,kBAAkB,KAAK;AAChF,YAAM,MAAM,SAAS,CAAC,EAAG,QAAQ,eAAe;AAChD,aAAO,iBAAiB;AAAA,IAC1B,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,UAAgB;AAEd,QAAI,cAAc,WAAW,OAAO;AAClC,UAAK,WAAmB,MAAM,UAAU,MAAM,KAAM,QAAO;AAAA,IAC7D;AAGA,QAAI,KAA2C,WAAW;AAC1D,WAAO,MAAM,GAAG,UAAU,GAAG;AAC3B,UAAI,GAAG,UAAU,MAAM,MAAM;AAC3B,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE,OAAO;AACL,aAAK,GAAG,UAAU,EAAE;AAAA,MACtB;AAAA,IACF;AAGA,SAAK,SAAS,WAAW;AAGzB,eAAW,QAAQ,KAAK,OAAO,KAAK,IAAI;AACxC,WAAO,eAAe,WAAW,OAAO,YAAY,EAAE,OAAO,KAAK,CAAC;AACnE,WAAO;AAAA,EACT;AAAA,EAEA,UAAgB;AAEd,QAAI,EAAG,cAAc,WAAW,OAAQ;AAGxC,QAAI,CAAE,KAAK,OAAQ;AAGnB,QAAI,SAAoC;AACxC,QAAI,KAAK,WAAW;AAGpB,WAAO,GAAG,UAAU,GAAG;AACrB,UAAI,GAAG,UAAU,MAAM,MAAM;AAC3B,YAAI,CAAE,OAAQ,YAAW,QAAQ,KAAK;AAAA,YACjC,QAAO,SAAS,KAAK;AAC1B;AAAA,MACF,OAAO;AACL,iBAAS,GAAG,UAAU;AACtB,aAAK,GAAG,UAAU,EAAE;AAAA,MACtB;AAAA,IACF;AAGA,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,IAAM,YAAkC;AA8B/C,IAAM,WAAN,MAAkB;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EAET,cAAc;AACZ,QAAI;AACJ,QAAI;AAEJ,SAAK,UAAU,IAAI,QAAW,CAAC,UAAU,aAAa;AACpD,gBAAU;AACV,eAAS;AAAA,IACX,CAAC;AAED,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AACF;AAGA,IAAM,sBAAN,cAAkC,QAAmC;AAAA,EACnE,YACI,SACiB,WACA,QACnB;AACA,UAAM,OAAO;AAHM;AACA;AAAA,EAGrB;AAAA,EAEA,KAAK,SAAuB;AAC1B,SAAK,UAAU,OAAO,WAAW,IAAI,MAAM,UAAU,KAAK,GAAG,EAAE,CAAC;AAAA,EAClE;AAAA,EAEA,SAAS,MAA4B;AACnC,SAAK,UAAU,QAAQ,KAAK,OAAO,GAAG,IAAI,CAAC;AAAA,EAC7C;AAAA,EAEA,KAAK,UAAmD;AACtD,SAAK,UAAU,QAAQ,YAAY,IAAI,SAAS,CAAC;AAAA,EACnD;AAAA,EAEA,WAAW,QAAsB;AAC/B,SAAK,UAAU,QAAQ,WAAW,MAAM,CAAC;AAAA,EAC3C;AAAA,EAEA,SAAS,MAAc,SAAiB,KAAW;AACjD,SAAK,UAAU,QAAQ,SAAS,MAAM,MAAM,CAAC;AAAA,EAC/C;AAAA,EAEA,SAAS,MAAW,SAAiB,KAAW;AAC9C,SAAK,UAAU,QAAQ,SAAS,MAAM,MAAM,CAAC;AAAA,EAC/C;AAAA,EAEA,SAAS,MAAkB,SAAS,KAAW;AAC7C,SAAK,UAAU,QAAQ,SAAS,MAAM,MAAM,CAAC;AAAA,EAC/C;AACF;AAOO,SAAS,WACZ,QACA,aAAa,aAAa,MAAM,GACxB;AACV,SAAO,IAAI,SAAS,QAAW,EAAE,QAAQ,WAAW,CAAC;AACvD;AAGO,SAAS,SAAS,MAAc,SAAS,KAAe;AAC7D,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,IACvD,YAAY,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF,CAAC;AACH;AAGO,SAAS,SAAS,MAAe,SAAS,KAAe;AAC9D,SAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,IACxC,SAAS,EAAE,gBAAgB,kCAAkC;AAAA,IAC7D,YAAY,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF,CAAC;AACH;AAGO,SAAS,SAAS,MAAkB,SAAS,KAAe;AACjE,SAAO,IAAI,SAAS,OAAO,KAAK,IAAI,GAAG;AAAA,IACrC,SAAS,EAAE,gBAAgB,2BAA2B;AAAA,IACtD,YAAY,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF,CAAC;AACH;",
5
5
  "names": ["info", "init"]
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juit/lib-fetch-mock",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Easy Mocking of Node.js' own `fetch`",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -28,8 +28,8 @@
28
28
  "author": "Juit Developers <developers@juit.com>",
29
29
  "license": "Apache-2.0",
30
30
  "devDependencies": {
31
- "@plugjs/build": "^0.6.0",
32
- "typescript": "^5.5.2"
31
+ "@plugjs/build": "^0.6.65",
32
+ "typescript": "^5.9.3"
33
33
  },
34
34
  "files": [
35
35
  "*.md",
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { STATUS_CODES } from 'node:http'
2
1
  import assert from 'node:assert'
2
+ import { STATUS_CODES } from 'node:http'
3
3
 
4
4
  const mockSymbol = Symbol.for('juit.fetch.mock')
5
5
 
6
6
  type FetchFunction = typeof globalThis.fetch
7
7
  type FetchArguments = Parameters<FetchFunction>
8
+ type MaybeMockedFetchFunction = FetchFunction & { [mockSymbol]?: FetchMockImpl }
8
9
 
9
10
  type FetchHandlerResult = Response | number | void | null | undefined
10
11
  type FetchHandler = (request: Request, fetch: FetchFunction) => FetchHandlerResult | Promise<FetchHandlerResult>
@@ -54,7 +55,7 @@ export interface FetchMockConstructor {
54
55
 
55
56
  class FetchMockImpl implements FetchMock {
56
57
  private _handlers: FetchHandler[] = []
57
- private _fetch?: FetchFunction
58
+ private _fetch?: MaybeMockedFetchFunction
58
59
  private _baseurl: URL
59
60
 
60
61
  constructor(baseurl?: string | URL | undefined) {
@@ -80,8 +81,8 @@ class FetchMockImpl implements FetchMock {
80
81
  ): Promise<Response> => realFetch.call(globalThis, info, init)
81
82
 
82
83
  const request = (info instanceof URL) || (typeof info === 'string') ?
83
- new Request(new URL(info, this._baseurl), init) :
84
- new Request(info, init)
84
+ new Request(new URL(info, this._baseurl), init) :
85
+ new Request(info, init)
85
86
 
86
87
  let response: Response | undefined = undefined
87
88
 
@@ -93,7 +94,16 @@ class FetchMockImpl implements FetchMock {
93
94
  break
94
95
  }
95
96
 
96
- return response || sendStatus(404)
97
+ // If we have a response from this mock, return it
98
+ if (response) return response
99
+
100
+ // If we are wrapping another mock, call it
101
+ if (this._fetch[mockSymbol]) {
102
+ return this._fetch[mockSymbol].$fetch(info, init)
103
+ }
104
+
105
+ // Otherwise, return not found (404)
106
+ return sendStatus(404)
97
107
  }
98
108
 
99
109
  /* === HANDLERS =========================================================== */
@@ -152,23 +162,55 @@ class FetchMockImpl implements FetchMock {
152
162
  /* === INSTALL / DESTROY ================================================== */
153
163
 
154
164
  install(): this {
165
+ // Ignore this if we are already installed at the root of the mock chain
155
166
  if (mockSymbol in globalThis.fetch) {
156
167
  if ((globalThis as any).fetch[mockSymbol] === this) return this
157
- assert.fail('Global `fetch` already mocked')
158
168
  }
159
169
 
170
+ // If we are already installed somewhere in the mock chain, fail
171
+ let fn: MaybeMockedFetchFunction | undefined = globalThis.fetch
172
+ while (fn && fn[mockSymbol]) {
173
+ if (fn[mockSymbol] === this) {
174
+ throw new Error('Global `fetch` already mocked by this instance')
175
+ } else {
176
+ fn = fn[mockSymbol]._fetch
177
+ }
178
+ }
179
+
180
+ // Save the current fetch (either the real one, or another mock)
160
181
  this._fetch = globalThis.fetch
161
182
 
183
+ // Install our fetch handler
162
184
  globalThis.fetch = this.$fetch.bind(this)
163
185
  Object.defineProperty(globalThis.fetch, mockSymbol, { value: this })
164
186
  return this
165
187
  }
166
188
 
167
189
  destroy(): void {
190
+ // If we're not mocked *globally*, just return
168
191
  if (! (mockSymbol in globalThis.fetch)) return
169
- const instance = (globalThis as any).fetch[mockSymbol]
170
- assert(instance === this, 'Attempting to disable non-enabled mock instance')
171
- globalThis.fetch = this._fetch!
192
+
193
+ // If we have never been installed, do nothing
194
+ if (! this._fetch) return
195
+
196
+ // Start looking into our chain of mocks
197
+ let parent: FetchMockImpl | undefined = undefined
198
+ let fn = globalThis.fetch as MaybeMockedFetchFunction
199
+
200
+ // Walk the chain of mocks until we find ourselves
201
+ while (fn[mockSymbol]) {
202
+ if (fn[mockSymbol] === this) {
203
+ if (! parent) globalThis.fetch = this._fetch
204
+ else parent._fetch = this._fetch
205
+ break
206
+ } else {
207
+ parent = fn[mockSymbol]
208
+ fn = fn[mockSymbol]._fetch as MaybeMockedFetchFunction
209
+ }
210
+ }
211
+
212
+ // Forget our saved fetch
213
+ this._fetch = undefined
172
214
  }
173
215
  }
174
216
 
@@ -292,7 +334,7 @@ export function sendJson(data: unknown, status = 200): Response {
292
334
 
293
335
  /** Create a `Response` with the specified binary body and an optional status */
294
336
  export function sendData(data: Uint8Array, status = 200): Response {
295
- return new Response(data, {
337
+ return new Response(Buffer.from(data), {
296
338
  headers: { 'content-type': 'application/octet-stream' },
297
339
  statusText: STATUS_CODES[status],
298
340
  status,