@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.
- package/LICENSE +24 -0
- package/dist/monadyssey-fetch.d.ts +193 -96
- package/dist/monadyssey-fetch.mjs +151 -70
- package/dist/monadyssey-fetch.mjs.map +1 -1
- package/package.json +12 -8
- package/readme.md +27 -8
- package/dist/monadyssey-fetch.cjs +0 -8
- package/dist/monadyssey-fetch.cjs.map +0 -1
- package/dist/monadyssey-fetch.umd.js +0 -8
- package/dist/monadyssey-fetch.umd.js.map +0 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { IO as e, List as t, Option as n,
|
|
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
|
|
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
|
-
},
|
|
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,
|
|
24
|
-
super(
|
|
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,
|
|
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,
|
|
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,
|
|
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) ?
|
|
47
|
+
return e(this.body) ? n.ofNullable(this.body) : n.empty();
|
|
40
48
|
}
|
|
41
|
-
},
|
|
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 && !
|
|
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
|
-
},
|
|
51
|
-
|
|
52
|
-
|
|
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 =
|
|
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) =>
|
|
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:
|
|
81
|
-
read: (t, n, r) => e.from(p(n), () => h(`Unsupported response type: ${n}`, r, t)).flatMap((
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
},
|
|
87
|
-
|
|
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
|
|
105
|
-
event:
|
|
106
|
-
|
|
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
|
-
},
|
|
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.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
},
|
|
123
|
-
let e = new
|
|
124
|
-
return (n) => n.mapAccumulate(
|
|
125
|
-
|
|
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
|
-
})),
|
|
188
|
+
})), A = class {
|
|
133
189
|
controller = new AbortController();
|
|
134
|
-
frames = new
|
|
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
|
-
},
|
|
162
|
-
let { url:
|
|
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
|
|
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(() =>
|
|
232
|
+
return e.lift(() => S.run(c, S.request(i, {
|
|
175
233
|
...n,
|
|
176
234
|
signal: t.controller.signal
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
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) =>
|
|
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
|
|
187
|
-
} },
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
243
|
-
|
|
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
|
-
}
|
|
247
|
-
|
|
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
|
-
}
|
|
250
|
-
|
|
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 {
|
|
335
|
+
export { N as HttpClient, a as HttpError, E as decodeEvents };
|
|
255
336
|
|
|
256
337
|
//# sourceMappingURL=monadyssey-fetch.mjs.map
|