@openstage/monadyssey-fetch 3.0.0-beta.8 → 3.0.0-rc.2

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.
@@ -1,10 +1,17 @@
1
- import { IO as e, List as t, Option as n, Some as r, Stream as i } from "@openstage/monadyssey-core";
2
- //#region src/http-error.ts
3
- var a = {
1
+ import { IO as e, List as t, Option as n, Stream as r } from "@openstage/monadyssey-core";
2
+ // src/http-error.ts
3
+ var i = (e) => {
4
+ try {
5
+ return Object.fromEntries(Array.from(e.headers.entries()).filter(([e]) => e !== "set-cookie" && e !== "set-cookie2"));
6
+ } catch {
7
+ return {};
8
+ }
9
+ }, a = {
4
10
  describe: (e) => e instanceof Error ? e.message : typeof e == "string" ? e : typeof e == "object" && e && "message" in e ? String(e.message) : "An unknown error occurred.",
5
11
  format: (e, t, n, r, i) => {
6
12
  switch (e) {
7
13
  case "response": return `Request to '${t}' failed with status ${n} and message: ${r}.`;
14
+ case "decode": return `Response from '${t}' (status ${n}) could not be decoded: ${r}.`;
8
15
  case "request": return `Request to '${t}' could not be sent: ${r}.`;
9
16
  case "timeout": return `Request to '${t}' timed out after ${i} ms.`;
10
17
  case "aborted": return `Request to '${t}' was aborted before a response arrived: ${r}.`;
@@ -29,6 +36,9 @@ var a = {
29
36
  static timeout(t, n) {
30
37
  return new e(0, `Request timed out after ${n} ms`, null, t, void 0, "timeout", void 0, n);
31
38
  }
39
+ static decode(t, n, r) {
40
+ return new e(n.status, a.describe(r), null, t, i(n), "decode", r);
41
+ }
32
42
  static request(t, n) {
33
43
  return new e(0, a.describe(n), null, t, void 0, "request", n);
34
44
  }
@@ -36,7 +46,7 @@ var a = {
36
46
  return new e(0, a.describe(n), null, t, void 0, "aborted", n);
37
47
  }
38
48
  bodyAs(e) {
39
- return e(this.body) ? r.of(this.body) : n.empty();
49
+ return e(this.body) ? n.ofNullable(this.body) : n.empty();
40
50
  }
41
51
  }, s = (e) => typeof e != "object" || !e || e instanceof FormData || e instanceof Blob || e instanceof ArrayBuffer || e instanceof URLSearchParams || typeof ReadableStream < "u" && e instanceof ReadableStream || ArrayBuffer.isView(e), c = (e) => Object.fromEntries(Object.entries(e).filter((e) => e[1] !== void 0).map(([e, t]) => [e.toLowerCase(), t])), l = (e, t) => {
42
52
  if (t instanceof FormData) {
@@ -47,7 +57,10 @@ var a = {
47
57
  ...e,
48
58
  "content-type": "application/json"
49
59
  } : e;
50
- }, u = (e, t, n) => e === "GET" || e === "HEAD" || t == null ? void 0 : s(t) ? t : n["content-type"] === "application/json" ? JSON.stringify(t) : t, d = {
60
+ }, u = (e) => {
61
+ let t = e.split(";")[0].trim().toLowerCase();
62
+ return t === "application/json" || t.endsWith("+json");
63
+ }, d = (e, t, n) => e === "GET" || e === "HEAD" || t == null ? void 0 : s(t) ? t : u(n["content-type"]) ? JSON.stringify(t) : t, f = {
51
64
  isNativeBody: s,
52
65
  normalizeHeaders: c,
53
66
  prepare: (e, t, n) => {
@@ -59,32 +72,62 @@ var a = {
59
72
  method: e,
60
73
  headers: r,
61
74
  credentials: t.credentials ?? n.credentials,
62
- body: u(e, t.body, r)
75
+ body: d(e, t.body, r)
63
76
  };
64
77
  }
65
- }, f = {
78
+ }, p = {
66
79
  json: (e) => e.json(),
67
80
  text: (e) => e.text(),
68
81
  blob: (e) => e.blob(),
69
82
  arrayBuffer: (e) => e.arrayBuffer(),
70
83
  formData: (e) => e.formData()
71
- }, p = (e) => Object.prototype.hasOwnProperty.call(f, e) ? n.of(f[e]) : n.empty(), m = (e) => {
72
- try {
73
- return Object.fromEntries(e.headers.entries());
74
- } catch {
75
- return {};
76
- }
77
- }, h = (e, t, n) => new o(n.status, a.describe(e), null, t, m(n), "response", e), g = (e, t, n) => new o(e.status, e.statusText, t, n, m(e)), _ = {
78
- headers: m,
79
- error: h,
80
- failure: g,
81
- read: (t, n, r) => e.from(p(n), () => h(`Unsupported response type: ${n}`, r, t)).flatMap((n) => e.lift(() => t.status === 204 || t.status === 205 ? null : n(t), (e) => h(e, r, t))),
82
- settle: (t, n, r) => t.ok ? e.of(n) : e.fail(g(t, n, r))
83
- }, v = (e) => typeof e == "object" && !!e && "name" in e && e.name === "AbortError", y = {
84
- error: (e, t) => e instanceof o ? e : v(e) ? o.aborted(t, e) : o.network(t, e),
84
+ }, m = (e) => Object.prototype.hasOwnProperty.call(p, e) ? n.of(p[e]) : n.empty(), h = i, g = (e, t, n) => o.decode(t, n, e), _ = Symbol("HttpResponse.noBody"), v = (e, t, n) => new o(e.status, e.statusText, t, n, h(e)), y = async (e) => {
85
+ if (typeof e.text != "function") return e.json();
86
+ let t = await e.text();
87
+ return t.trim() === "" ? _ : JSON.parse(t);
88
+ }, b = {
89
+ headers: h,
90
+ error: g,
91
+ failure: v,
92
+ read: (t, n, r, i) => e.from(m(n), () => g(`Unsupported response type: ${n}`, r, t)).flatMap((a) => e.lift(async () => t.status === 204 || t.status === 205 || i === "HEAD" ? _ : n === "json" ? y(t) : a(t), (e) => g(e, r, t))),
93
+ readFailure: (t, n, r) => e.promise(async () => {
94
+ try {
95
+ if (n !== "json") return await m(n).fold(async () => null, (e) => e(t));
96
+ if (typeof t.text != "function") return await t.json();
97
+ let e = await t.text();
98
+ if (e.trim() === "") return null;
99
+ try {
100
+ return JSON.parse(e);
101
+ } catch {
102
+ return e;
103
+ }
104
+ } catch {
105
+ return null;
106
+ }
107
+ }).flatMap((n) => e.fail(v(t, n, r)))
108
+ }, x = (e) => typeof e == "object" && !!e && "name" in e && e.name === "AbortError", S = {
109
+ error: (e, t) => e instanceof o ? e : x(e) ? o.aborted(t, e) : o.network(t, e),
85
110
  isRetryable: (e) => e.kind === "network" || e.kind === "response" && e.status >= 500
86
- }, b = { run: (e, t, n) => e.reduceRight((e, t) => (n) => t.intercept(n, e), n)(t) }, x = (e) => {
87
- let t, n, r, i = [];
111
+ }, C = {
112
+ run: (e, t, n) => e.reduceRight((e, t) => (n) => t.intercept(n, e), n)(t),
113
+ request: (e, t) => {
114
+ let n;
115
+ try {
116
+ n = new Headers(t.headers);
117
+ } catch (t) {
118
+ throw o.request(e, t);
119
+ }
120
+ return {
121
+ url: e,
122
+ init: {
123
+ ...t,
124
+ headers: n
125
+ }
126
+ };
127
+ },
128
+ fetch: (e) => fetch(e.url, e.init)
129
+ }, w = (e) => {
130
+ let t = "", n, r, i = [];
88
131
  for (let a of e.split("\n")) {
89
132
  if (a === "" || a.startsWith(":")) continue;
90
133
  let e = a.indexOf(":"), o = e === -1 ? a : a.slice(0, e), s = e === -1 ? "" : a.slice(e + 1);
@@ -96,45 +139,73 @@ var a = {
96
139
  i.push(s);
97
140
  break;
98
141
  case "id":
99
- n = s;
142
+ s.includes("\0") || (n = s);
100
143
  break;
101
144
  case "retry": /^\d+$/.test(s) && (r = Number.parseInt(s, 10));
102
145
  }
103
146
  }
104
- return i.length === 0 ? null : {
105
- event: t ?? "message",
106
- data: i.join("\n"),
147
+ return {
148
+ event: i.length === 0 ? null : {
149
+ event: t || "message",
150
+ data: i.join("\n"),
151
+ ...n === void 0 ? {} : { id: n },
152
+ ...r === void 0 ? {} : { retry: r }
153
+ },
107
154
  ...n === void 0 ? {} : { id: n },
108
155
  ...r === void 0 ? {} : { retry: r }
109
156
  };
110
- }, S = class {
157
+ }, T = (e, t) => {
158
+ let { id: n, ...r } = e;
159
+ return t === void 0 ? r : {
160
+ ...r,
161
+ id: t
162
+ };
163
+ }, E = class {
164
+ limit;
111
165
  decoder = new TextDecoder("utf-8");
112
166
  buffered = "";
167
+ constructor(e = Infinity) {
168
+ this.limit = e;
169
+ }
170
+ skipLeadingLF = !1;
113
171
  push(e) {
114
- let t = this.buffered + this.decoder.decode(e, { stream: !0 }), n = !1;
115
- t.endsWith("\r") && (t = t.slice(0, -1), n = !0), t = t.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
116
- let r = t.split("\n\n"), i = r.pop() ?? "";
117
- return n && (i += "\r"), this.buffered = i, r.map(x).filter((e) => e !== null);
172
+ let t = this.decoder.decode(e, { stream: !0 });
173
+ if (t.length === 0) return [];
174
+ this.skipLeadingLF && t.startsWith("\n") && (t = t.slice(1)), this.skipLeadingLF = t.endsWith("\r");
175
+ let n = Math.max(0, this.buffered.length - 1);
176
+ if (t = this.buffered + t.replace(/\r\n/g, "\n").replace(/\r/g, "\n"), t.indexOf("\n\n", n) === -1) return this.buffered = t, this.checkLimit(), [];
177
+ let r = t.split("\n\n");
178
+ return this.buffered = r.pop() ?? "", this.checkLimit(), r.map(w);
118
179
  }
119
180
  reset() {
120
- this.decoder = new TextDecoder("utf-8"), this.buffered = "";
181
+ this.decoder = new TextDecoder("utf-8"), this.buffered = "", this.skipLeadingLF = !1;
182
+ }
183
+ checkLimit() {
184
+ if (this.buffered.length > this.limit) throw RangeError(`An event block exceeds the ${this.limit}-character limit without ending`);
121
185
  }
122
- }, C = () => {
123
- let e = new S();
124
- return (n) => n.mapAccumulate(null, (n) => [null, t.from(e.push(n))]);
125
- }, w = 100, T = (t) => e.cancellable((e) => new Promise((n) => {
186
+ }, D = () => {
187
+ let e = new E();
188
+ return (n) => n.mapAccumulate(void 0, (n, r) => {
189
+ let i = [], a = n;
190
+ for (let t of e.push(r)) t.id !== void 0 && (a = t.id), t.event !== null && i.push(T(t.event, a));
191
+ return [a, t.from(i)];
192
+ });
193
+ }, O = 100, k = 2147483647, A = 1048576, j = (e) => Array.from(new TextEncoder().encode(e), (e) => String.fromCharCode(e)).join(""), M = (t) => e.promise((e) => new Promise((n) => {
126
194
  let r = () => {
127
195
  clearTimeout(i), n();
128
196
  }, i = setTimeout(() => {
129
197
  e.removeEventListener("abort", r), n();
130
- }, t);
198
+ }, Math.min(t, k));
131
199
  e.addEventListener("abort", r, { once: !0 });
132
- })), E = class {
200
+ })), N = class {
133
201
  controller = new AbortController();
134
- frames = new S();
202
+ frames = new E(A);
135
203
  pending = [];
136
204
  lastEventId = void 0;
137
205
  retryMs;
206
+ serverRetryMs = void 0;
207
+ reconnects = 0;
208
+ status = 200;
138
209
  connection = null;
139
210
  unlinkParent;
140
211
  constructor(e, t) {
@@ -145,11 +216,12 @@ var a = {
145
216
  get reader() {
146
217
  return this.connection?.reader ?? null;
147
218
  }
148
- attach(e) {
149
- let t = () => e.cancel().catch(() => {});
150
- this.controller.signal.addEventListener("abort", t, { once: !0 }), this.connection = {
219
+ attach(e, t) {
220
+ this.status = t;
221
+ let n = () => e.cancel().catch(() => {});
222
+ this.controller.signal.addEventListener("abort", n, { once: !0 }), this.connection = {
151
223
  reader: e,
152
- unlink: () => this.controller.signal.removeEventListener("abort", t)
224
+ unlink: () => this.controller.signal.removeEventListener("abort", n)
153
225
  }, this.frames.reset();
154
226
  }
155
227
  closeConnection() {
@@ -158,33 +230,57 @@ var a = {
158
230
  close() {
159
231
  this.closeConnection(), this.unlinkParent(), this.controller.abort();
160
232
  }
161
- }, D = { stream: (t) => {
162
- let { url: r, headers: a, defaultHeaders: o, credentials: s, interceptors: c, reconnect: l, retry: u } = t, f = (t) => {
163
- let n = d.prepare("GET", {
233
+ }, P = (e) => e.split(";")[0].trim().toLowerCase(), F = { stream: (t) => {
234
+ let { url: i, headers: a, defaultHeaders: s, credentials: c, interceptors: l, reconnect: u, retry: d } = t, p = (t) => {
235
+ let n = f.prepare("GET", {
164
236
  headers: {
165
237
  ...a,
166
238
  accept: "text/event-stream",
167
- ...t.lastEventId === void 0 ? {} : { "last-event-id": t.lastEventId }
239
+ ...t.lastEventId ? { "last-event-id": j(t.lastEventId) } : {}
168
240
  },
169
- credentials: s
241
+ credentials: c
170
242
  }, {
171
- headers: o,
172
- credentials: s
243
+ headers: s,
244
+ credentials: c
173
245
  });
174
- return e.lift(() => b.run(c, {
246
+ return e.lift(() => C.run(l, C.request(i, {
175
247
  ...n,
248
+ cache: "no-store",
176
249
  signal: t.controller.signal
177
- }, (e) => fetch(r, e)), (e) => y.error(e, r)).flatMap((t) => t.ok ? e.of(t) : _.read(t, "text", r).flatMapErr(() => e.of(null)).flatMap((n) => e.fail(_.failure(t, n, r)))).flatMap((t) => t.body === null ? e.fail(_.error("Response has no body", r, t)) : e.of(t.body.getReader()));
178
- }, p = (t) => e.lift(() => t.read(), (e) => y.error(e, r)), m = e.of(n.empty()), h = (e) => T(e.retryMs).flatMap(() => g(e)), g = (t) => {
179
- if (t.pending.length > 0) {
250
+ }), C.fetch), (e) => S.error(e, i)).flatMap((t) => t.ok ? e.of(t) : b.readFailure(t, "text", i)).flatMap((t) => {
251
+ if (t.status === 204) return t.body?.cancel().catch(() => {}), e.of(null);
252
+ let n = t.headers.get("content-type");
253
+ return n !== null && P(n) !== "text/event-stream" ? (t.body?.cancel().catch(() => {}), e.fail(b.error(`Expected text/event-stream, got ${n}`, i, t))) : t.body === null ? e.fail(b.error("Response has no body", i, t)) : e.of({
254
+ reader: t.body.getReader(),
255
+ status: t.status
256
+ });
257
+ });
258
+ }, m = (t) => e.lift(() => t.read(), (e) => S.error(e, i)), h = e.of(n.empty()), g = (e, t) => {
259
+ if (u === !1) return t;
260
+ let n = e.reconnects + 1;
261
+ if (u !== !0 && !u.allowsAttempt(n)) return t;
262
+ let r = e.serverRetryMs ?? (u === !0 ? e.retryMs : u.delayAfter(n));
263
+ return e.reconnects = n, M(r).flatMap(() => _(e));
264
+ }, _ = (t) => {
265
+ for (; t.pending.length > 0;) {
180
266
  let r = t.pending.shift();
181
- return r.id !== void 0 && (t.lastEventId = r.id), r.retry !== void 0 && (t.retryMs = Math.max(r.retry, w)), e.of(n.of([r, t]));
267
+ if (r.id !== void 0 && (t.lastEventId = r.id), r.retry !== void 0 && (t.serverRetryMs = Math.max(r.retry, O)), r.event !== null) return t.reconnects = 0, e.of(n.of([T(r.event, t.lastEventId), t]));
182
268
  }
183
269
  let r = t.reader;
184
- return r === null ? f(t).foldM((n) => l && y.isRetryable(n) ? h(t) : e.fail(n), (e) => (t.attach(e), g(t))) : p(r).foldM((n) => (t.closeConnection(), l && y.isRetryable(n) ? h(t) : e.fail(n)), (e) => e.done ? (t.closeConnection(), l ? h(t) : m) : (t.pending.push(...t.frames.push(e.value)), g(t)));
270
+ return r === null ? p(t).foldM((n) => S.isRetryable(n) ? g(t, e.fail(n)) : e.fail(n), (e) => e === null ? h : (t.attach(e.reader, e.status), _(t))) : m(r).foldM((n) => (t.closeConnection(), S.isRetryable(n) ? g(t, e.fail(n)) : e.fail(n)), (n) => {
271
+ if (n.done) return t.closeConnection(), g(t, h);
272
+ let r;
273
+ try {
274
+ r = t.frames.push(n.value);
275
+ } catch (n) {
276
+ return t.closeConnection(), e.fail(new o(t.status, String(n.message), null, i, void 0, "decode", n));
277
+ }
278
+ for (let e of r) t.pending.push(e);
279
+ return _(t);
280
+ });
185
281
  };
186
- return i.bracket(e.cancellable((e) => new E(u, e)), (e) => i.unfoldEval(e, g), (t) => e.lift(() => t.close()));
187
- } }, O = class {
282
+ return r.bracket(e.promise(async (e) => new N(d, e)), (e) => r.unfoldEval(e, _), (t) => e.sync(() => t.close()));
283
+ } }, I = class {
188
284
  interceptors;
189
285
  baseUrl;
190
286
  defaultHeaders;
@@ -193,35 +289,44 @@ var a = {
193
289
  constructor(e = {}) {
194
290
  this.interceptors = Object.freeze([...e.interceptors ?? []]), this.baseUrl = e.baseUrl, this.defaultHeaders = e.defaultHeaders ?? {}, this.defaultTimeout = e.timeout, this.defaultCredentials = e.credentials ?? "same-origin";
195
291
  }
196
- get(e, t) {
292
+ get(e, t = {}) {
197
293
  return this.request(e, "GET", t);
198
294
  }
199
- post(e, t, n) {
295
+ post(e, t, n = {}) {
200
296
  return this.request(e, "POST", {
201
297
  ...n,
202
298
  body: t
203
299
  });
204
300
  }
205
- put(e, t, n) {
301
+ put(e, t, n = {}) {
206
302
  return this.request(e, "PUT", {
207
303
  ...n,
208
304
  body: t
209
305
  });
210
306
  }
211
- patch(e, t, n) {
307
+ patch(e, t, n = {}) {
212
308
  return this.request(e, "PATCH", {
213
309
  ...n,
214
310
  body: t
215
311
  });
216
312
  }
217
- delete(e, t) {
313
+ delete(e, t = {}) {
218
314
  return this.request(e, "DELETE", t);
219
315
  }
220
316
  fetch(e, t, n = {}) {
221
317
  return this.request(e, t, n);
222
318
  }
319
+ send(t, n, r) {
320
+ let i = this.resolveUrl(n), a = r ?? {};
321
+ return this.withTimeout(i, a.timeout, this.exchange(i, t, a).flatMap((t) => t.ok ? e.sync(() => void t.body?.cancel().catch(() => {})) : b.readFailure(t, "json", i)));
322
+ }
323
+ raw(t, n, r) {
324
+ let i = this.resolveUrl(n), a = r ?? {};
325
+ return this.withTimeout(i, a.timeout, this.exchange(i, t, a).flatMap((t) => t.ok ? e.of(t) : b.readFailure(t, "json", i)));
326
+ }
223
327
  sse(e, t = {}) {
224
- return D.stream({
328
+ if (t.retry !== void 0 && !(t.retry >= 0)) throw RangeError(`HttpClient.sse: retry must be a non-negative number of milliseconds, got ${t.retry}`);
329
+ return F.stream({
225
330
  url: this.resolveUrl(e),
226
331
  headers: t.headers ?? {},
227
332
  defaultHeaders: this.defaultHeaders,
@@ -232,25 +337,28 @@ var a = {
232
337
  });
233
338
  }
234
339
  resolveUrl(e) {
235
- if (!this.baseUrl) return e;
236
- try {
237
- return new URL(e), e;
238
- } catch {
239
- return `${this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl}${e.startsWith("/") ? e : `/${e}`}`;
240
- }
340
+ return !this.baseUrl || /^[a-z][a-z\d+.-]*:\/\//i.test(e) || /^(data|blob):/i.test(e) ? e : `${this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl}${e.startsWith("/") ? e : `/${e}`}`;
241
341
  }
242
- request(t, n, r = {}) {
243
- let i = this.resolveUrl(t), a = r.timeout ?? this.defaultTimeout, { responseType: s = "json", observe: c = "body", transform: l = (e) => e } = r, u = {
342
+ exchange(t, n, r) {
343
+ if ((n === "GET" || n === "HEAD") && r.body != null) throw TypeError(`A ${n} request cannot have a body (${t})`);
344
+ let i = {
244
345
  headers: this.defaultHeaders,
245
346
  credentials: this.defaultCredentials
246
- }, f = e.lift(() => d.prepare(n, r, u), (e) => o.request(i, e)), p = (t) => e.cancellable((e) => b.run(this.interceptors, {
247
- ...t,
347
+ };
348
+ return e.lift(() => f.prepare(n, r, i), (e) => o.request(t, e)).flatMap((n) => e.cancellable((e) => C.run(this.interceptors, C.request(t, {
349
+ ...n,
248
350
  signal: e
249
- }, (e) => fetch(i, e)), (e) => y.error(e, i)), m = (t) => _.read(t, s, i).flatMap((e) => _.settle(t, e, i)).flatMap((n) => e.lift(() => l(n), (e) => _.error(e, i, t))), h = f.flatMap(p).flatMap((t) => t.ok && c === "response" ? e.of(t) : m(t));
250
- return a == null ? h : h.timeout(a, () => o.timeout(i, a));
351
+ }), C.fetch), (e) => S.error(e, t)));
352
+ }
353
+ withTimeout(e, t, n) {
354
+ let r = t ?? this.defaultTimeout;
355
+ return r == null ? n : n.timeout(r, () => o.timeout(e, r));
356
+ }
357
+ request(t, r, i) {
358
+ let a = this.resolveUrl(t), { responseType: s = "json", transform: c = (e) => e, empty: l = "error" } = i;
359
+ return this.withTimeout(a, i.timeout, this.exchange(a, r, i).flatMap((t) => t.ok ? b.read(t, s, a, r).flatMap((r) => r === _ ? l === "option" ? e.of(n.empty()) : e.fail(o.decode(a, t, `expected a response body, got none (status ${t.status}); use send() or { empty: "option" }`)) : e.lift(() => c(r), (e) => o.decode(a, t, e)).map((e) => l === "option" ? n.ofNullable(e) : e)) : b.readFailure(t, s, a)));
251
360
  }
252
361
  };
253
- //#endregion
254
- export { O as HttpClient, o as HttpError, C as decodeEvents };
362
+ export { I as HttpClient, o as HttpError, D as decodeEvents };
255
363
 
256
364
  //# sourceMappingURL=monadyssey-fetch.mjs.map