@openstage/monadyssey-fetch 3.0.0-beta.7 → 3.0.0-rc.1

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