@gershy/util-http 0.0.1 → 0.0.3
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/cmp/cjs/main.d.ts +56 -2
- package/cmp/cjs/main.js +63 -2
- package/cmp/mjs/main.d.ts +56 -2
- package/cmp/mjs/main.js +63 -2
- package/package.json +2 -2
package/cmp/cjs/main.d.ts
CHANGED
|
@@ -1,4 +1,58 @@
|
|
|
1
1
|
import '../sideEffects.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
export type NetProc = {
|
|
3
|
+
proto: 'ws' | 'wss' | 'http' | 'https';
|
|
4
|
+
addr: string;
|
|
5
|
+
port: number;
|
|
6
|
+
};
|
|
7
|
+
type Built<T> = T | {
|
|
8
|
+
[k: string]: Built<T>;
|
|
9
|
+
};
|
|
10
|
+
export type HttpReq = {
|
|
11
|
+
path: string[];
|
|
12
|
+
method: 'head' | 'get' | 'post' | 'put' | 'patch' | 'delete' | 'sokt';
|
|
13
|
+
cookies: Obj<Built<string>>;
|
|
14
|
+
query?: Obj<Built<string>>;
|
|
15
|
+
body?: Json;
|
|
16
|
+
};
|
|
17
|
+
export type HttpRes = {
|
|
18
|
+
code: number;
|
|
19
|
+
headers?: {
|
|
20
|
+
[key: string]: string | string[];
|
|
21
|
+
};
|
|
22
|
+
body: Json | Buffer;
|
|
23
|
+
};
|
|
24
|
+
export type HttpArgs<Req extends HttpReq, Res extends HttpRes> = {} & {
|
|
25
|
+
$req: Req;
|
|
26
|
+
$res: Res;
|
|
27
|
+
} & {
|
|
28
|
+
netProc: NetProc;
|
|
29
|
+
} & Omit<Req, 'cookies'> & {
|
|
30
|
+
headers?: Obj<string>;
|
|
31
|
+
};
|
|
32
|
+
export type HttpResult<Res extends HttpRes> = {
|
|
33
|
+
reqArgs: {
|
|
34
|
+
url: string;
|
|
35
|
+
method: string;
|
|
36
|
+
headers: [string, string][];
|
|
37
|
+
body: string | null;
|
|
38
|
+
};
|
|
39
|
+
code: number;
|
|
40
|
+
body: Res['body'];
|
|
41
|
+
};
|
|
42
|
+
export type HttpRet<Res extends HttpRes> = Promise<HttpResult<Res>> & {
|
|
43
|
+
end: () => void;
|
|
44
|
+
};
|
|
45
|
+
declare const _default: <Args extends HttpArgs<HttpReq, HttpRes>>(args: Args, params: Pick<Args, "query" | "body">) => Promise<{
|
|
46
|
+
reqArgs: ({
|
|
47
|
+
method: "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "SOKT";
|
|
48
|
+
headers: [string, string][];
|
|
49
|
+
body: string | null;
|
|
50
|
+
} & {
|
|
51
|
+
url: string;
|
|
52
|
+
});
|
|
53
|
+
code: number;
|
|
54
|
+
body: Args["$res"]["body"];
|
|
55
|
+
}> & {
|
|
56
|
+
end: () => void;
|
|
57
|
+
};
|
|
4
58
|
export default _default;
|
package/cmp/cjs/main.js
CHANGED
|
@@ -1,4 +1,65 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
require("@gershy/clearing");
|
|
4
|
-
exports.default =
|
|
3
|
+
const clearing_1 = require("@gershy/clearing");
|
|
4
|
+
exports.default = (args, params) => {
|
|
5
|
+
// Note this function is sovereign - can't reference jargon/http for `formatNetProc` :(
|
|
6
|
+
const { netProc, path, headers = {} } = args;
|
|
7
|
+
const { query = {}, body: reqBody = null } = params;
|
|
8
|
+
const defPorts = { http: 80, https: 443 };
|
|
9
|
+
const url = [
|
|
10
|
+
// E.g. "http://pasta.com"
|
|
11
|
+
`${netProc.proto}:/${''}/${netProc.addr}`,
|
|
12
|
+
// E.g. "http://pasta.com:3000"
|
|
13
|
+
netProc.port !== defPorts[netProc.proto] ? `:${netProc.port.toString(10)}` : null,
|
|
14
|
+
// E.g. "http://pasta.com:3000/path/to/resource"
|
|
15
|
+
path ? `/${path.join('/')}` : null,
|
|
16
|
+
(() => {
|
|
17
|
+
if (query[empty]())
|
|
18
|
+
return null;
|
|
19
|
+
const chains = function* (val, chain = []) {
|
|
20
|
+
if (!(0, clearing_1.isCls)(val, Object))
|
|
21
|
+
return yield { chain, val };
|
|
22
|
+
for (const [k, v] of val)
|
|
23
|
+
yield* chains(v, [...chain, k]);
|
|
24
|
+
};
|
|
25
|
+
// E.g. "http://pasta.com:3000/path/to/resource?query=spaghetti&offset=10"
|
|
26
|
+
return [...chains(query)][map](({ chain, val }) => `${encodeURIComponent(chain.join('.'))}=${encodeURIComponent(val)}`)
|
|
27
|
+
.join('&');
|
|
28
|
+
})()
|
|
29
|
+
].filter(Boolean).join('');
|
|
30
|
+
const reqArgs = {
|
|
31
|
+
method: args.method[upper](),
|
|
32
|
+
headers: headers[toArr]((v, k) => [k.replace(/([A-Z])/g, '-$1')[lower](), v]), // Avoid `camelCase` util - want to keep this sovereign
|
|
33
|
+
body: [Object, Array].some(C => (0, clearing_1.isCls)(reqBody, C)) ? JSON.stringify(reqBody) : reqBody !== null ? `${reqBody}` : null
|
|
34
|
+
};
|
|
35
|
+
const abort = new AbortController();
|
|
36
|
+
const prm = fetch(url, { ...reqArgs, signal: abort.signal }).then(async (res) => {
|
|
37
|
+
const resBody = await (async () => {
|
|
38
|
+
const t = await res.text();
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(t);
|
|
41
|
+
}
|
|
42
|
+
catch (err) { }
|
|
43
|
+
return t;
|
|
44
|
+
})();
|
|
45
|
+
const http = {
|
|
46
|
+
reqArgs: Object.assign(reqArgs, { url, body: reqBody }),
|
|
47
|
+
code: res.status,
|
|
48
|
+
body: resBody
|
|
49
|
+
};
|
|
50
|
+
if (res.status >= 500)
|
|
51
|
+
throw Error('http glitch')[mod](http);
|
|
52
|
+
if (res.status >= 400)
|
|
53
|
+
throw Error('http reject')[mod](http);
|
|
54
|
+
return http; // TODO: Return something like `{ ...http.body, http: { status: res.status } }`? Works as long as `http.body` is Json and not a Buffer
|
|
55
|
+
}, err => {
|
|
56
|
+
while ((0, clearing_1.isCls)(err.cause, Error))
|
|
57
|
+
err = err.cause; // `fetch` natively wraps errors - pretty annoying; unwrap them
|
|
58
|
+
if (err.code === 'ENOTFOUND')
|
|
59
|
+
return err[fire]({ retry: false });
|
|
60
|
+
throw err;
|
|
61
|
+
});
|
|
62
|
+
// Note that fetch abortion errors are suppressed!! By default we short-circuit any logic
|
|
63
|
+
// which depended on the http return value.
|
|
64
|
+
return Object.assign(prm, { end: () => abort.abort(Error('fetch aborted')[suppress]()) });
|
|
65
|
+
};
|
package/cmp/mjs/main.d.ts
CHANGED
|
@@ -1,4 +1,58 @@
|
|
|
1
1
|
import '../sideEffects.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
export type NetProc = {
|
|
3
|
+
proto: 'ws' | 'wss' | 'http' | 'https';
|
|
4
|
+
addr: string;
|
|
5
|
+
port: number;
|
|
6
|
+
};
|
|
7
|
+
type Built<T> = T | {
|
|
8
|
+
[k: string]: Built<T>;
|
|
9
|
+
};
|
|
10
|
+
export type HttpReq = {
|
|
11
|
+
path: string[];
|
|
12
|
+
method: 'head' | 'get' | 'post' | 'put' | 'patch' | 'delete' | 'sokt';
|
|
13
|
+
cookies: Obj<Built<string>>;
|
|
14
|
+
query?: Obj<Built<string>>;
|
|
15
|
+
body?: Json;
|
|
16
|
+
};
|
|
17
|
+
export type HttpRes = {
|
|
18
|
+
code: number;
|
|
19
|
+
headers?: {
|
|
20
|
+
[key: string]: string | string[];
|
|
21
|
+
};
|
|
22
|
+
body: Json | Buffer;
|
|
23
|
+
};
|
|
24
|
+
export type HttpArgs<Req extends HttpReq, Res extends HttpRes> = {} & {
|
|
25
|
+
$req: Req;
|
|
26
|
+
$res: Res;
|
|
27
|
+
} & {
|
|
28
|
+
netProc: NetProc;
|
|
29
|
+
} & Omit<Req, 'cookies'> & {
|
|
30
|
+
headers?: Obj<string>;
|
|
31
|
+
};
|
|
32
|
+
export type HttpResult<Res extends HttpRes> = {
|
|
33
|
+
reqArgs: {
|
|
34
|
+
url: string;
|
|
35
|
+
method: string;
|
|
36
|
+
headers: [string, string][];
|
|
37
|
+
body: string | null;
|
|
38
|
+
};
|
|
39
|
+
code: number;
|
|
40
|
+
body: Res['body'];
|
|
41
|
+
};
|
|
42
|
+
export type HttpRet<Res extends HttpRes> = Promise<HttpResult<Res>> & {
|
|
43
|
+
end: () => void;
|
|
44
|
+
};
|
|
45
|
+
declare const _default: <Args extends HttpArgs<HttpReq, HttpRes>>(args: Args, params: Pick<Args, "query" | "body">) => Promise<{
|
|
46
|
+
reqArgs: ({
|
|
47
|
+
method: "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "SOKT";
|
|
48
|
+
headers: [string, string][];
|
|
49
|
+
body: string | null;
|
|
50
|
+
} & {
|
|
51
|
+
url: string;
|
|
52
|
+
});
|
|
53
|
+
code: number;
|
|
54
|
+
body: Args["$res"]["body"];
|
|
55
|
+
}> & {
|
|
56
|
+
end: () => void;
|
|
57
|
+
};
|
|
4
58
|
export default _default;
|
package/cmp/mjs/main.js
CHANGED
|
@@ -1,2 +1,63 @@
|
|
|
1
|
-
import '@gershy/clearing';
|
|
2
|
-
export default
|
|
1
|
+
import { isCls } from '@gershy/clearing';
|
|
2
|
+
export default (args, params) => {
|
|
3
|
+
// Note this function is sovereign - can't reference jargon/http for `formatNetProc` :(
|
|
4
|
+
const { netProc, path, headers = {} } = args;
|
|
5
|
+
const { query = {}, body: reqBody = null } = params;
|
|
6
|
+
const defPorts = { http: 80, https: 443 };
|
|
7
|
+
const url = [
|
|
8
|
+
// E.g. "http://pasta.com"
|
|
9
|
+
`${netProc.proto}:/${''}/${netProc.addr}`,
|
|
10
|
+
// E.g. "http://pasta.com:3000"
|
|
11
|
+
netProc.port !== defPorts[netProc.proto] ? `:${netProc.port.toString(10)}` : null,
|
|
12
|
+
// E.g. "http://pasta.com:3000/path/to/resource"
|
|
13
|
+
path ? `/${path.join('/')}` : null,
|
|
14
|
+
(() => {
|
|
15
|
+
if (query[empty]())
|
|
16
|
+
return null;
|
|
17
|
+
const chains = function* (val, chain = []) {
|
|
18
|
+
if (!isCls(val, Object))
|
|
19
|
+
return yield { chain, val };
|
|
20
|
+
for (const [k, v] of val)
|
|
21
|
+
yield* chains(v, [...chain, k]);
|
|
22
|
+
};
|
|
23
|
+
// E.g. "http://pasta.com:3000/path/to/resource?query=spaghetti&offset=10"
|
|
24
|
+
return [...chains(query)][map](({ chain, val }) => `${encodeURIComponent(chain.join('.'))}=${encodeURIComponent(val)}`)
|
|
25
|
+
.join('&');
|
|
26
|
+
})()
|
|
27
|
+
].filter(Boolean).join('');
|
|
28
|
+
const reqArgs = {
|
|
29
|
+
method: args.method[upper](),
|
|
30
|
+
headers: headers[toArr]((v, k) => [k.replace(/([A-Z])/g, '-$1')[lower](), v]), // Avoid `camelCase` util - want to keep this sovereign
|
|
31
|
+
body: [Object, Array].some(C => isCls(reqBody, C)) ? JSON.stringify(reqBody) : reqBody !== null ? `${reqBody}` : null
|
|
32
|
+
};
|
|
33
|
+
const abort = new AbortController();
|
|
34
|
+
const prm = fetch(url, { ...reqArgs, signal: abort.signal }).then(async (res) => {
|
|
35
|
+
const resBody = await (async () => {
|
|
36
|
+
const t = await res.text();
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(t);
|
|
39
|
+
}
|
|
40
|
+
catch (err) { }
|
|
41
|
+
return t;
|
|
42
|
+
})();
|
|
43
|
+
const http = {
|
|
44
|
+
reqArgs: Object.assign(reqArgs, { url, body: reqBody }),
|
|
45
|
+
code: res.status,
|
|
46
|
+
body: resBody
|
|
47
|
+
};
|
|
48
|
+
if (res.status >= 500)
|
|
49
|
+
throw Error('http glitch')[mod](http);
|
|
50
|
+
if (res.status >= 400)
|
|
51
|
+
throw Error('http reject')[mod](http);
|
|
52
|
+
return http; // TODO: Return something like `{ ...http.body, http: { status: res.status } }`? Works as long as `http.body` is Json and not a Buffer
|
|
53
|
+
}, err => {
|
|
54
|
+
while (isCls(err.cause, Error))
|
|
55
|
+
err = err.cause; // `fetch` natively wraps errors - pretty annoying; unwrap them
|
|
56
|
+
if (err.code === 'ENOTFOUND')
|
|
57
|
+
return err[fire]({ retry: false });
|
|
58
|
+
throw err;
|
|
59
|
+
});
|
|
60
|
+
// Note that fetch abortion errors are suppressed!! By default we short-circuit any logic
|
|
61
|
+
// which depended on the http return value.
|
|
62
|
+
return Object.assign(prm, { end: () => abort.abort(Error('fetch aborted')[suppress]()) });
|
|
63
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gershy/util-http",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "TODO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"TODO"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"homepage": "https://github.com/gershy/utilHttp#readme",
|
|
17
17
|
"license": "ISC",
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"@gershy/clearing": "^0.0.
|
|
19
|
+
"@gershy/clearing": "^0.0.28"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^24.10.1",
|