snapreq 0.0.4 → 0.0.5
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/{types → build}/capabilities.d.ts +1 -0
- package/build/capabilities.d.ts.map +1 -0
- package/{src → build}/capabilities.js +11 -12
- package/{types → build}/errors.d.ts +1 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +82 -0
- package/{types → build}/headers.d.ts +1 -0
- package/build/headers.d.ts.map +1 -0
- package/build/headers.js +89 -0
- package/{types → build}/request.d.ts +1 -0
- package/build/request.d.ts.map +1 -0
- package/build/request.js +89 -0
- package/{types → build}/response.d.ts +1 -0
- package/build/response.d.ts.map +1 -0
- package/build/response.js +171 -0
- package/{types → build}/retry.d.ts +1 -0
- package/build/retry.d.ts.map +1 -0
- package/build/retry.js +95 -0
- package/{types → build}/snap-req.d.ts +1 -0
- package/build/snap-req.d.ts.map +1 -0
- package/build/snap-req.js +349 -0
- package/{types → build}/transports/fetch-transport.d.ts +1 -0
- package/build/transports/fetch-transport.d.ts.map +1 -0
- package/build/transports/fetch-transport.js +116 -0
- package/build/transports/fetch.d.ts +2 -0
- package/build/transports/fetch.d.ts.map +1 -0
- package/build/transports/fetch.js +3 -0
- package/{types → build}/transports/node-transport.d.ts +1 -0
- package/build/transports/node-transport.d.ts.map +1 -0
- package/build/transports/node-transport.js +287 -0
- package/build/transports/proxy-bounce-transport.d.ts +27 -0
- package/build/transports/proxy-bounce-transport.d.ts.map +1 -0
- package/build/transports/proxy-bounce-transport.js +116 -0
- package/{types → build}/transports/select.d.ts +1 -0
- package/build/transports/select.d.ts.map +1 -0
- package/build/transports/select.js +69 -0
- package/{types → build}/transports/xhr-transport.d.ts +1 -0
- package/build/transports/xhr-transport.d.ts.map +1 -0
- package/build/transports/xhr-transport.js +93 -0
- package/build/transports/xhr.d.ts +2 -0
- package/build/transports/xhr.d.ts.map +1 -0
- package/build/transports/xhr.js +3 -0
- package/{types → build}/websocket/websocket-channel.d.ts +1 -0
- package/build/websocket/websocket-channel.d.ts.map +1 -0
- package/build/websocket/websocket-channel.js +162 -0
- package/{types → build}/websocket/websocket-client.d.ts +1 -0
- package/build/websocket/websocket-client.d.ts.map +1 -0
- package/build/websocket/websocket-client.js +920 -0
- package/{types → build}/websocket/websocket-connection.d.ts +1 -0
- package/build/websocket/websocket-connection.d.ts.map +1 -0
- package/build/websocket/websocket-connection.js +148 -0
- package/build/websocket.d.ts +3 -0
- package/build/websocket.d.ts.map +1 -0
- package/build/websocket.js +4 -0
- package/package.json +12 -48
- package/src/errors.js +0 -86
- package/src/headers.js +0 -92
- package/src/request.js +0 -104
- package/src/response.js +0 -197
- package/src/retry.js +0 -107
- package/src/snap-req.js +0 -390
- package/src/transports/fetch-transport.js +0 -128
- package/src/transports/node-transport.js +0 -323
- package/src/transports/select.js +0 -73
- package/src/transports/xhr-transport.js +0 -112
- package/src/websocket/websocket-channel.js +0 -176
- package/src/websocket/websocket-client.js +0 -1034
- package/src/websocket/websocket-connection.js +0 -154
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-connection.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-connection.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACE;;;;;;;;;;;OAWG;IACH,qHAVG;QAAsD,MAAM,EAApD,OAAO,uBAAuB,EAAE,OAAO;QAC1B,YAAY,EAAzB,MAAM;QACO,cAAc,EAA3B,MAAM;QACqB,MAAM,GAAjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;QACD,SAAS,GAA3B,MAAM,IAAI;QACiB,SAAS,GAApC,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI;QACD,YAAY,GAA9B,MAAM,IAAI;QACQ,QAAQ,GAA1B,MAAM,IAAI;QACsB,OAAO,GAAvC,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI;KAClC,EAmBA;IAjBC,gDAAoB;IACpB,qBAAgC;IAChC,uBAAoC;IACpC,4BAA0B;IAC1B,kBAXe,IAAI,CAWQ;IAC3B,mBAXgB,GAAG,KAAK,IAAI,CAWD;IAC3B,qBAXe,IAAI,CAWc;IACjC,iBAXe,IAAI,CAWM;IACzB,mBAXkB,MAAM,KAAK,IAAI,CAWV;IACvB,oBAAuB;IACvB,iBAAoB;IAEpB,kFAAkF;IAClF,OADW,OAAO,CAAC,IAAI,CAAC,CAItB;IAFA,yDAA4B;IAC5B,qCAA0B;IAI9B;;;;OAIG;IACH,iBAFa,IAAI,CAWhB;IAED;;;;;OAKG;IACH,qBAHW,GAAG,GACD,IAAI,CAKhB;IAED;;;;OAIG;IACH,uBAFa,IAAI,CAKhB;IAED;;;;OAIG;IACH,kBAFa,IAAI,CAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,IAAI,CAahB;IAED;;;;OAIG;IACH,kBAHW,GAAG,GACD,IAAI,CAYhB;IAED;;;;OAIG;IACH,SAFa,IAAI,CAmBhB;IAED,6DAA6D;IAC7D,YADc,OAAO,CACa;IAElC,2DAA2D;IAC3D,eADc,OAAO,CACoC;CAC1D"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Client-side handle for a 1:1 connection opened via
|
|
4
|
+
* `SnapReqWebSocketClient.openConnection()`. Mirrors the server's connection
|
|
5
|
+
* lifecycle — `onConnect` / `onMessage` / `onClose` plus `sendMessage` /
|
|
6
|
+
* `close`.
|
|
7
|
+
*/
|
|
8
|
+
export default class SnapReqWebSocketConnection {
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} args - Connection arguments.
|
|
11
|
+
* @param {import("./websocket-client.js").default} args.client - Owning client.
|
|
12
|
+
* @param {string} args.connectionId - Generated id unique within the session.
|
|
13
|
+
* @param {string} args.connectionType - Name the server registered the class under.
|
|
14
|
+
* @param {Record<string, any>} [args.params] - Opaque params forwarded to the server.
|
|
15
|
+
* @param {() => void} [args.onConnect] - Fired after the server confirms `connection-opened`.
|
|
16
|
+
* @param {(body: any) => void} [args.onMessage] - Fired on each `connection-message` from the server.
|
|
17
|
+
* @param {() => void} [args.onDisconnect] - Fired when the socket drops; connection is preserved pending resume.
|
|
18
|
+
* @param {() => void} [args.onResume] - Fired when the session successfully resumes after a drop.
|
|
19
|
+
* @param {(reason: string) => void} [args.onClose] - Fired exactly once when the handle closes permanently.
|
|
20
|
+
*/
|
|
21
|
+
constructor({ client, connectionId, connectionType, params, onConnect, onMessage, onDisconnect, onResume, onClose }) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
this.connectionId = connectionId;
|
|
24
|
+
this.connectionType = connectionType;
|
|
25
|
+
this.params = params || {};
|
|
26
|
+
this._onConnect = onConnect;
|
|
27
|
+
this._onMessage = onMessage;
|
|
28
|
+
this._onDisconnect = onDisconnect;
|
|
29
|
+
this._onResume = onResume;
|
|
30
|
+
this._onClose = onClose;
|
|
31
|
+
this._connected = false;
|
|
32
|
+
this._closed = false;
|
|
33
|
+
/** @type {Promise<void>} - Resolves once the server sends `connection-opened`. */
|
|
34
|
+
this.ready = new Promise((resolve, reject) => {
|
|
35
|
+
this._resolveReady = resolve;
|
|
36
|
+
this._rejectReady = reject;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Called by the client dispatcher when `{type: "connection-opened"}` arrives.
|
|
41
|
+
* Fires the user's `onConnect` and resolves `ready`.
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
44
|
+
_handleOpened() {
|
|
45
|
+
if (this._closed || this._connected)
|
|
46
|
+
return;
|
|
47
|
+
this._connected = true;
|
|
48
|
+
try {
|
|
49
|
+
this._onConnect?.();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
this._resolveReady?.();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Called by the client dispatcher for each `connection-message` targeted at
|
|
57
|
+
* this connection id.
|
|
58
|
+
* @param {any} body - Message payload.
|
|
59
|
+
* @returns {void}
|
|
60
|
+
*/
|
|
61
|
+
_handleMessage(body) {
|
|
62
|
+
if (this._closed)
|
|
63
|
+
return;
|
|
64
|
+
this._onMessage?.(body);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Called by the client when the underlying socket drops. The connection stays
|
|
68
|
+
* alive pending session resume.
|
|
69
|
+
* @returns {void}
|
|
70
|
+
*/
|
|
71
|
+
_handleDisconnected() {
|
|
72
|
+
if (this._closed)
|
|
73
|
+
return;
|
|
74
|
+
this._onDisconnect?.();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Called by the client after `session-resumed` confirms the server still has
|
|
78
|
+
* this connection.
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
_handleResumed() {
|
|
82
|
+
if (this._closed)
|
|
83
|
+
return;
|
|
84
|
+
this._onResume?.();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Called by the client dispatcher when the connection closes for any reason.
|
|
88
|
+
* Fires `onClose(reason)` at most once.
|
|
89
|
+
* @param {string} reason - Why the connection closed.
|
|
90
|
+
* @returns {void}
|
|
91
|
+
*/
|
|
92
|
+
_handleClosed(reason) {
|
|
93
|
+
if (this._closed)
|
|
94
|
+
return;
|
|
95
|
+
this._closed = true;
|
|
96
|
+
try {
|
|
97
|
+
this._onClose?.(reason);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (!this._connected) {
|
|
101
|
+
this._rejectReady?.(new Error(`Connection closed before open: ${reason}`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Sends a message to the server side of this connection.
|
|
107
|
+
* @param {any} body - Message payload.
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
sendMessage(body) {
|
|
111
|
+
if (this._closed) {
|
|
112
|
+
throw new Error(`Cannot sendMessage on closed connection ${this.connectionId}`);
|
|
113
|
+
}
|
|
114
|
+
this.client._sendMessage({
|
|
115
|
+
type: "connection-message",
|
|
116
|
+
connectionId: this.connectionId,
|
|
117
|
+
body
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Closes the connection from the client side. Fires `onClose("client_close")`
|
|
122
|
+
* locally and notifies the server. No-op if already closed.
|
|
123
|
+
* @returns {void}
|
|
124
|
+
*/
|
|
125
|
+
close() {
|
|
126
|
+
if (this._closed)
|
|
127
|
+
return;
|
|
128
|
+
// Send the close frame BEFORE flipping _closed so _sendMessage doesn't
|
|
129
|
+
// refuse — and guard against a socket that's already gone so the local
|
|
130
|
+
// teardown still runs.
|
|
131
|
+
try {
|
|
132
|
+
if (this.client.isOpen()) {
|
|
133
|
+
this.client._sendMessage({ type: "connection-close", connectionId: this.connectionId });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Socket may have closed between our check and the send; the server will
|
|
138
|
+
// see the session destroy and clean up regardless.
|
|
139
|
+
}
|
|
140
|
+
this.client._removeConnection(this.connectionId);
|
|
141
|
+
this._handleClosed("client_close");
|
|
142
|
+
}
|
|
143
|
+
/** @returns {boolean} - Whether the connection is closed. */
|
|
144
|
+
isClosed() { return this._closed; }
|
|
145
|
+
/** @returns {boolean} - Whether the connection is open. */
|
|
146
|
+
isConnected() { return this._connected && !this._closed; }
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LWNvbm5lY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2Vic29ja2V0L3dlYnNvY2tldC1jb25uZWN0aW9uLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sMEJBQTBCO0lBQzdDOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsWUFBWSxFQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFDO1FBQy9HLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFBO1FBQ3BCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFBO1FBQ2hDLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFBO1FBQ3BDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLEVBQUUsQ0FBQTtRQUMxQixJQUFJLENBQUMsVUFBVSxHQUFHLFNBQVMsQ0FBQTtRQUMzQixJQUFJLENBQUMsVUFBVSxHQUFHLFNBQVMsQ0FBQTtRQUMzQixJQUFJLENBQUMsYUFBYSxHQUFHLFlBQVksQ0FBQTtRQUNqQyxJQUFJLENBQUMsU0FBUyxHQUFHLFFBQVEsQ0FBQTtRQUN6QixJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQTtRQUN2QixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQTtRQUN2QixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQTtRQUVwQixrRkFBa0Y7UUFDbEYsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMzQyxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQTtZQUM1QixJQUFJLENBQUMsWUFBWSxHQUFHLE1BQU0sQ0FBQTtRQUM1QixDQUFDLENB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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
export { default } from "./websocket/websocket-client.js";
|
|
3
|
+
export * from "./websocket/websocket-client.js";
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3dlYnNvY2tldC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLGlDQUFpQyxDQUFBO0FBQ3ZELGNBQWMsaUNBQWlDLENBQUEifQ==
|
package/package.json
CHANGED
|
@@ -1,67 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snapreq",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Cross-platform HTTP and WebSocket client with one API across Node, web, Expo and React Native",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"types": "./
|
|
6
|
+
"main": "./build/snap-req.js",
|
|
7
|
+
"types": "./build/snap-req.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./
|
|
11
|
-
"default": "./
|
|
12
|
-
},
|
|
13
|
-
"./websocket": {
|
|
14
|
-
"types": "./types/websocket/websocket-client.d.ts",
|
|
15
|
-
"default": "./src/websocket/websocket-client.js"
|
|
16
|
-
},
|
|
17
|
-
"./errors": {
|
|
18
|
-
"types": "./types/errors.d.ts",
|
|
19
|
-
"default": "./src/errors.js"
|
|
20
|
-
},
|
|
21
|
-
"./headers": {
|
|
22
|
-
"types": "./types/headers.d.ts",
|
|
23
|
-
"default": "./src/headers.js"
|
|
24
|
-
},
|
|
25
|
-
"./response": {
|
|
26
|
-
"types": "./types/response.d.ts",
|
|
27
|
-
"default": "./src/response.js"
|
|
28
|
-
},
|
|
29
|
-
"./retry": {
|
|
30
|
-
"types": "./types/retry.d.ts",
|
|
31
|
-
"default": "./src/retry.js"
|
|
32
|
-
},
|
|
33
|
-
"./capabilities": {
|
|
34
|
-
"types": "./types/capabilities.d.ts",
|
|
35
|
-
"default": "./src/capabilities.js"
|
|
36
|
-
},
|
|
37
|
-
"./transports/select": {
|
|
38
|
-
"types": "./types/transports/select.d.ts",
|
|
39
|
-
"default": "./src/transports/select.js"
|
|
40
|
-
},
|
|
41
|
-
"./transports/fetch": {
|
|
42
|
-
"types": "./types/transports/fetch-transport.d.ts",
|
|
43
|
-
"default": "./src/transports/fetch-transport.js"
|
|
44
|
-
},
|
|
45
|
-
"./transports/xhr": {
|
|
46
|
-
"types": "./types/transports/xhr-transport.d.ts",
|
|
47
|
-
"default": "./src/transports/xhr-transport.js"
|
|
10
|
+
"types": "./build/snap-req.d.ts",
|
|
11
|
+
"default": "./build/snap-req.js"
|
|
48
12
|
},
|
|
49
13
|
"./*": {
|
|
50
|
-
"types": "./
|
|
51
|
-
"default": "./
|
|
14
|
+
"types": "./build/*.d.ts",
|
|
15
|
+
"default": "./build/*.js"
|
|
52
16
|
}
|
|
53
17
|
},
|
|
54
18
|
"files": [
|
|
55
|
-
"
|
|
56
|
-
"types/**"
|
|
19
|
+
"build/**"
|
|
57
20
|
],
|
|
58
21
|
"scripts": {
|
|
59
22
|
"all-checks": "npm run typecheck && npm run lint && npm run test",
|
|
60
|
-
"build
|
|
23
|
+
"build": "rm -rf build && tsc",
|
|
61
24
|
"lint": "eslint src spec",
|
|
62
|
-
"
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"prepublishOnly": "npm run build",
|
|
63
27
|
"release:patch": "release-patch",
|
|
64
|
-
"test": "node --test \"spec/**/*-spec.js\"",
|
|
28
|
+
"test": "npm run build && node --test \"spec/**/*-spec.js\"",
|
|
65
29
|
"typecheck": "tsc --noEmit"
|
|
66
30
|
},
|
|
67
31
|
"keywords": [
|
package/src/errors.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
/** Base class for every error thrown by snapreq. */
|
|
4
|
-
export class SnapReqError extends Error {
|
|
5
|
-
/** @param {string} message - Human readable description. */
|
|
6
|
-
constructor(message) {
|
|
7
|
-
super(message)
|
|
8
|
-
this.name = "SnapReqError"
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Thrown when a request completes with a non-2xx status and the caller asked
|
|
14
|
-
* snapreq to treat error statuses as failures (`throwOnError`, the default for
|
|
15
|
-
* the high-level helpers). Carries enough metadata to build a friendly message
|
|
16
|
-
* without re-reading the response.
|
|
17
|
-
*/
|
|
18
|
-
export class SnapReqHttpError extends SnapReqError {
|
|
19
|
-
/**
|
|
20
|
-
* @param {object} options - Error metadata.
|
|
21
|
-
* @param {string} options.message - Human readable description.
|
|
22
|
-
* @param {string} options.method - HTTP method used for the request.
|
|
23
|
-
* @param {string} options.url - Fully resolved request URL.
|
|
24
|
-
* @param {number} options.status - HTTP status code returned by the server.
|
|
25
|
-
* @param {string} [options.statusText] - HTTP status text returned by the server.
|
|
26
|
-
* @param {string} [options.responseText] - Decoded response body, when available.
|
|
27
|
-
* @param {import("./response.js").default} [options.response] - The response that failed.
|
|
28
|
-
*/
|
|
29
|
-
constructor({message, method, url, status, statusText, responseText, response}) {
|
|
30
|
-
super(message)
|
|
31
|
-
this.name = "SnapReqHttpError"
|
|
32
|
-
this.method = method
|
|
33
|
-
this.url = url
|
|
34
|
-
this.status = status
|
|
35
|
-
this.statusText = statusText
|
|
36
|
-
this.responseText = responseText
|
|
37
|
-
this.response = response
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Thrown when a request asks for a capability the active transport cannot
|
|
43
|
-
* provide on the current platform (for example a Unix socket or request-body
|
|
44
|
-
* compression in a browser). The API stays identical across platforms; this
|
|
45
|
-
* error is how snapreq tells you a specific feature had to be left out.
|
|
46
|
-
*/
|
|
47
|
-
export class SnapReqUnsupportedFeatureError extends SnapReqError {
|
|
48
|
-
/**
|
|
49
|
-
* @param {object} options - Error metadata.
|
|
50
|
-
* @param {string} options.feature - The capability that is not supported.
|
|
51
|
-
* @param {string} options.transport - Name of the active transport.
|
|
52
|
-
* @param {string} [options.detail] - Optional extra context.
|
|
53
|
-
*/
|
|
54
|
-
constructor({feature, transport, detail}) {
|
|
55
|
-
super(`The "${transport}" transport does not support ${feature}${detail ? `: ${detail}` : ""}.`)
|
|
56
|
-
this.name = "SnapReqUnsupportedFeatureError"
|
|
57
|
-
this.feature = feature
|
|
58
|
-
this.transport = transport
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Thrown when a request is aborted via an `AbortSignal`. */
|
|
63
|
-
export class SnapReqAbortError extends SnapReqError {
|
|
64
|
-
/** @param {string} [message] - Human readable description. */
|
|
65
|
-
constructor(message = "Request aborted.") {
|
|
66
|
-
super(message)
|
|
67
|
-
this.name = "SnapReqAbortError"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Thrown when a request exceeds its configured timeout. */
|
|
72
|
-
export class SnapReqTimeoutError extends SnapReqError {
|
|
73
|
-
/**
|
|
74
|
-
* @param {object} options - Error metadata.
|
|
75
|
-
* @param {string} options.method - HTTP method used for the request.
|
|
76
|
-
* @param {string} options.url - Fully resolved request URL.
|
|
77
|
-
* @param {number} options.timeoutMs - Timeout in milliseconds.
|
|
78
|
-
*/
|
|
79
|
-
constructor({method, url, timeoutMs}) {
|
|
80
|
-
super(`Request timed out after ${timeoutMs}ms: ${method} ${url}`)
|
|
81
|
-
this.name = "SnapReqTimeoutError"
|
|
82
|
-
this.method = method
|
|
83
|
-
this.url = url
|
|
84
|
-
this.timeoutMs = timeoutMs
|
|
85
|
-
}
|
|
86
|
-
}
|
package/src/headers.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A tiny case-insensitive header bag. Works the same on every platform and
|
|
5
|
-
* avoids depending on the DOM `Headers` global (absent in some runtimes) or on
|
|
6
|
-
* Node's header handling. Header values are always stored as strings.
|
|
7
|
-
*/
|
|
8
|
-
export default class SnapReqHeaders {
|
|
9
|
-
/**
|
|
10
|
-
* @param {Record<string, string | number | string[]> | SnapReqHeaders | Iterable<[string, string]>} [init] - Initial headers.
|
|
11
|
-
*/
|
|
12
|
-
constructor(init) {
|
|
13
|
-
/** @type {Map<string, {name: string, value: string}>} - Keyed by lower-cased name. */
|
|
14
|
-
this._map = new Map()
|
|
15
|
-
|
|
16
|
-
if (!init) return
|
|
17
|
-
|
|
18
|
-
if (init instanceof SnapReqHeaders) {
|
|
19
|
-
for (const [name, value] of init.entries()) this.set(name, value)
|
|
20
|
-
} else if (typeof (/** @type {any} */ (init)[Symbol.iterator]) === "function") {
|
|
21
|
-
for (const [name, value] of /** @type {Iterable<[string, string]>} */ (init)) this.set(name, value)
|
|
22
|
-
} else {
|
|
23
|
-
for (const [name, value] of Object.entries(init)) {
|
|
24
|
-
if (Array.isArray(value)) {
|
|
25
|
-
this.set(name, value.join(", "))
|
|
26
|
-
} else if (value !== undefined && value !== null) {
|
|
27
|
-
this.set(name, String(value))
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @param {string} name - Header name (case-insensitive).
|
|
35
|
-
* @param {string | number} value - Header value.
|
|
36
|
-
* @returns {void}
|
|
37
|
-
*/
|
|
38
|
-
set(name, value) {
|
|
39
|
-
this._map.set(name.toLowerCase(), {name, value: String(value)})
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param {string} name - Header name (case-insensitive).
|
|
44
|
-
* @returns {string | null} - The header value or null when absent.
|
|
45
|
-
*/
|
|
46
|
-
get(name) {
|
|
47
|
-
return this._map.get(name.toLowerCase())?.value ?? null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @param {string} name - Header name (case-insensitive).
|
|
52
|
-
* @returns {boolean} - Whether the header is present.
|
|
53
|
-
*/
|
|
54
|
-
has(name) {
|
|
55
|
-
return this._map.has(name.toLowerCase())
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @param {string} name - Header name (case-insensitive).
|
|
60
|
-
* @returns {void}
|
|
61
|
-
*/
|
|
62
|
-
delete(name) {
|
|
63
|
-
this._map.delete(name.toLowerCase())
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @yields {[string, string]} - Name/value pair preserving original casing.
|
|
68
|
-
* @returns {IterableIterator<[string, string]>} - Name/value pairs preserving original casing.
|
|
69
|
-
*/
|
|
70
|
-
*entries() {
|
|
71
|
-
for (const {name, value} of this._map.values()) yield [name, value]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** @returns {[string, string][]} - Name/value pairs preserving original casing. */
|
|
75
|
-
toArray() {
|
|
76
|
-
return [...this.entries()]
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Plain object form keyed by the original header casing. Suitable for
|
|
81
|
-
* passing straight to `http.request` or `fetch`.
|
|
82
|
-
* @returns {Record<string, string>} - Header object.
|
|
83
|
-
*/
|
|
84
|
-
toObject() {
|
|
85
|
-
/** @type {Record<string, string>} */
|
|
86
|
-
const object = {}
|
|
87
|
-
|
|
88
|
-
for (const {name, value} of this._map.values()) object[name] = value
|
|
89
|
-
|
|
90
|
-
return object
|
|
91
|
-
}
|
|
92
|
-
}
|
package/src/request.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import SnapReqHeaders from "./headers.js"
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {"identity" | "gzip" | "deflate" | "br" | "zstd"} CompressionEncoding
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {object} NormalizedBody
|
|
11
|
-
* @property {"none" | "text" | "bytes" | "stream"} kind - Shape of the body payload.
|
|
12
|
-
* @property {string | Uint8Array | AsyncIterable<Uint8Array> | null} value - The payload itself.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const ABSOLUTE_URL_REGEX = /^[a-z][a-z0-9+.-]*:\/\//i
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Joins a base URL and a path and appends query parameters. `path` may be a
|
|
19
|
-
* fully-qualified URL, in which case the base is ignored.
|
|
20
|
-
* @param {string | undefined} baseUrl - Origin (and optional base path).
|
|
21
|
-
* @param {string} path - Path or absolute URL.
|
|
22
|
-
* @param {Record<string, string | number | boolean | null | undefined> | undefined} query - Query parameters.
|
|
23
|
-
* @returns {string} - Resolved absolute URL.
|
|
24
|
-
*/
|
|
25
|
-
export function buildUrl(baseUrl, path, query) {
|
|
26
|
-
/** @type {string} */
|
|
27
|
-
let resolved
|
|
28
|
-
|
|
29
|
-
if (ABSOLUTE_URL_REGEX.test(path)) {
|
|
30
|
-
resolved = path
|
|
31
|
-
} else if (baseUrl) {
|
|
32
|
-
resolved = `${baseUrl.replace(/\/$/, "")}/${path.replace(/^\//, "")}`
|
|
33
|
-
} else {
|
|
34
|
-
resolved = path
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!query) return resolved
|
|
38
|
-
|
|
39
|
-
const params = new URLSearchParams()
|
|
40
|
-
|
|
41
|
-
for (const [key, value] of Object.entries(query)) {
|
|
42
|
-
if (value !== undefined && value !== null) params.append(key, String(value))
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const queryString = params.toString()
|
|
46
|
-
|
|
47
|
-
if (!queryString) return resolved
|
|
48
|
-
|
|
49
|
-
return resolved.includes("?") ? `${resolved}&${queryString}` : `${resolved}?${queryString}`
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Determines whether a value should be sent as a streamed request body.
|
|
54
|
-
* @param {unknown} body - Candidate body value.
|
|
55
|
-
* @returns {boolean} - Whether the body is a stream.
|
|
56
|
-
*/
|
|
57
|
-
export function isStreamBody(body) {
|
|
58
|
-
return Boolean(
|
|
59
|
-
body &&
|
|
60
|
-
typeof body === "object" &&
|
|
61
|
-
!(body instanceof Uint8Array) &&
|
|
62
|
-
!(body instanceof ArrayBuffer) &&
|
|
63
|
-
(typeof (/** @type {any} */ (body).pipe) === "function" || typeof (/** @type {any} */ (body)[Symbol.asyncIterator]) === "function")
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Normalizes a user-supplied body into one of a small set of shapes and applies
|
|
69
|
-
* a default `Content-Type` header when the caller did not set one.
|
|
70
|
-
* @param {unknown} body - Raw body value.
|
|
71
|
-
* @param {SnapReqHeaders} headers - Headers to receive a default `Content-Type`.
|
|
72
|
-
* @returns {NormalizedBody} - Normalized body descriptor.
|
|
73
|
-
*/
|
|
74
|
-
export function normalizeBody(body, headers) {
|
|
75
|
-
if (body === undefined || body === null) {
|
|
76
|
-
return {kind: "none", value: null}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (body instanceof Uint8Array) {
|
|
80
|
-
if (!headers.has("content-type")) headers.set("Content-Type", "application/octet-stream")
|
|
81
|
-
|
|
82
|
-
return {kind: "bytes", value: body}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (body instanceof ArrayBuffer) {
|
|
86
|
-
if (!headers.has("content-type")) headers.set("Content-Type", "application/octet-stream")
|
|
87
|
-
|
|
88
|
-
return {kind: "bytes", value: new Uint8Array(body)}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (isStreamBody(body)) {
|
|
92
|
-
if (!headers.has("content-type")) headers.set("Content-Type", "application/octet-stream")
|
|
93
|
-
|
|
94
|
-
return {kind: "stream", value: /** @type {AsyncIterable<Uint8Array>} */ (body)}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (typeof body === "string") {
|
|
98
|
-
return {kind: "text", value: body}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (!headers.has("content-type")) headers.set("Content-Type", "application/json")
|
|
102
|
-
|
|
103
|
-
return {kind: "text", value: JSON.stringify(body)}
|
|
104
|
-
}
|