@fougere/transport-http 0.10.0-alpha.0 → 0.12.0-alpha.0
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/dist/serve/RunningReceiver.d.ts.map +1 -1
- package/dist/serve/RunningReceiver.js +32 -22
- package/dist/serve/RunningReceiver.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/package.json +5 -5
- package/src/serve/RunningReceiver.ts +44 -28
- package/src/server.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunningReceiver.d.ts","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,qDAAqD;AACrD,eAAO,MAAM,cAAc,UAAoC,CAAC;AAEhE,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"RunningReceiver.d.ts","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,qDAAqD;AACrD,eAAO,MAAM,cAAc,UAAoC,CAAC;AAEhE,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,eAAe,CAAC,CAM7F"}
|
|
@@ -4,28 +4,37 @@ import { MAX_BODY_BYTES, CALL_PATH, parseError, tooLarge } from '../policy.js';
|
|
|
4
4
|
/** What a frond binds when nobody says otherwise. */
|
|
5
5
|
export const LOOPBACK_HOSTS = ['127.0.0.1', 'localhost', '::1'];
|
|
6
6
|
export function serve(runner, options = {}) {
|
|
7
|
+
const host = options.host ?? (options.hosts ?? LOOPBACK_HOSTS)[0];
|
|
8
|
+
const refusal = whyNotHere(host, options);
|
|
9
|
+
if (refusal)
|
|
10
|
+
return Promise.reject(refusal);
|
|
11
|
+
return listening(createServer(answering(runner, options)), host, options);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where a receiver binds and what it admits are two questions. `verify` answers the second —
|
|
15
|
+
* without it this receiver takes the `state` it is handed, and `hosts` is all that stands.
|
|
16
|
+
* Loopback or signed: there is no third way to serve.
|
|
17
|
+
*/
|
|
18
|
+
function whyNotHere(host, options) {
|
|
7
19
|
const allowed = options.hosts ?? LOOPBACK_HOSTS;
|
|
8
20
|
if (allowed.length === 0) {
|
|
9
|
-
return
|
|
10
|
-
}
|
|
11
|
-
const host = options.host ?? allowed[0];
|
|
12
|
-
// Where a receiver binds, and what it admits, are two questions now. `verify` answers
|
|
13
|
-
// the second — without it this receiver still takes the `state` it is handed, and
|
|
14
|
-
// `hosts` is all that stands. The default keeps it on the machine; widening it is
|
|
15
|
-
// written down rather than inferred, and a widened receiver wants `requireIdentity`.
|
|
16
|
-
if (!allowed.includes(host)) {
|
|
17
|
-
return Promise.reject(new Error(`A Fougere receiver binds one of [${allowed.join(', ')}], got '${host}' — add it to \`hosts\` to allow it`));
|
|
21
|
+
return new Error('A Fougere receiver needs at least one host to bind, `hosts` is empty');
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return Promise.reject(new Error(`A Fougere receiver on '${host}' is reachable from outside this machine and would believe whatever `
|
|
22
|
-
+ 'state it is handed.\n'
|
|
23
|
-
+ ' - `fougere keys` once, then inject FOUGERE_ROOT_KEY here (and `fougere grant <frond>` for each caller), or\n'
|
|
24
|
-
+ ' - keep it on loopback, or\n'
|
|
25
|
-
+ ' - pass `allowUnsigned: true` if a mesh or an ingress already authenticated the caller.'));
|
|
23
|
+
if (host === undefined || !allowed.includes(host)) {
|
|
24
|
+
return new Error(`A Fougere receiver binds one of [${allowed.join(', ')}], got '${host}' — add it to \`hosts\` to allow it`);
|
|
26
25
|
}
|
|
26
|
+
if (LOOPBACK_HOSTS.includes(host) || options.verify || options.allowUnsigned)
|
|
27
|
+
return undefined;
|
|
28
|
+
return new Error(`A Fougere receiver on '${host}' is reachable from outside this machine and would believe whatever `
|
|
29
|
+
+ 'state it is handed.\n'
|
|
30
|
+
+ ' - `fougere keys` once, then inject FOUGERE_ROOT_KEY here (and `fougere grant <frond>` for each caller), or\n'
|
|
31
|
+
+ ' - keep it on loopback, or\n'
|
|
32
|
+
+ ' - pass `allowUnsigned: true` if a mesh or an ingress already authenticated the caller.');
|
|
33
|
+
}
|
|
34
|
+
/** One path, one method, and a body that is refused before it is read whole. */
|
|
35
|
+
function answering(runner, options) {
|
|
27
36
|
const maxBodyBytes = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
28
|
-
|
|
37
|
+
return async (req, res) => {
|
|
29
38
|
if (req.method !== 'POST' || req.url !== CALL_PATH) {
|
|
30
39
|
res.writeHead(404).end();
|
|
31
40
|
return;
|
|
@@ -43,22 +52,23 @@ export function serve(runner, options = {}) {
|
|
|
43
52
|
}
|
|
44
53
|
let response;
|
|
45
54
|
try {
|
|
46
|
-
|
|
47
|
-
response = await handleRpc(runner, raw, options);
|
|
55
|
+
response = await handleRpc(runner, JSON.parse(Buffer.concat(chunks).toString('utf8')), options);
|
|
48
56
|
}
|
|
49
57
|
catch {
|
|
50
58
|
response = parseError();
|
|
51
59
|
}
|
|
52
60
|
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(response));
|
|
53
|
-
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The port a receiver ended up on — asked of the server, since 0 means "whatever is free". */
|
|
64
|
+
function listening(server, host, options) {
|
|
54
65
|
return new Promise((resolve, reject) => {
|
|
55
66
|
server.once('error', reject);
|
|
56
67
|
server.requestTimeout = options.requestTimeoutMs ?? 15_000;
|
|
57
68
|
server.listen(options.port ?? 0, host, () => {
|
|
58
69
|
const address = server.address();
|
|
59
|
-
const port = typeof address === 'object' && address !== null ? address.port : 0;
|
|
60
70
|
resolve({
|
|
61
|
-
port,
|
|
71
|
+
port: typeof address === 'object' && address !== null ? address.port : 0,
|
|
62
72
|
close: () => new Promise((done, fail) => server.close((err) => (err ? fail(err) : done()))),
|
|
63
73
|
});
|
|
64
74
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunningReceiver.js","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"RunningReceiver.js","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,OAAO,EAAkE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGzI,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAClH;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,OAAO,EAAkE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGzI,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAClH;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsEnH"}
|
package/dist/server.js
CHANGED
|
@@ -31,6 +31,7 @@ export async function handleRpc(runner, raw, options = {}) {
|
|
|
31
31
|
params: sent.params ?? {},
|
|
32
32
|
query: sent.query ?? {},
|
|
33
33
|
input: sent.input,
|
|
34
|
+
runAt: sent.runAt,
|
|
34
35
|
}));
|
|
35
36
|
}
|
|
36
37
|
catch (err) {
|
|
@@ -48,6 +49,7 @@ export async function handleRpc(runner, raw, options = {}) {
|
|
|
48
49
|
input: sent.input,
|
|
49
50
|
state,
|
|
50
51
|
trace: sent.trace,
|
|
52
|
+
...(sent.runAt === undefined ? {} : { runAt: sent.runAt }),
|
|
51
53
|
...(caller ? { caller } : {}),
|
|
52
54
|
};
|
|
53
55
|
try {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/transport-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-alpha.0",
|
|
4
4
|
"description": "The call contract on the wire, in JSON-RPC 2.0 (server + client).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fougere",
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"src"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@fougere/core": "0.
|
|
41
|
+
"@fougere/core": "0.12.0-alpha.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"jiti": "^2.6.1",
|
|
45
|
-
"@fougere/
|
|
46
|
-
"@fougere/
|
|
47
|
-
"@fougere/
|
|
45
|
+
"@fougere/container": "0.12.0-alpha.0",
|
|
46
|
+
"@fougere/schema": "0.12.0-alpha.0",
|
|
47
|
+
"@fougere/compiler": "0.12.0-alpha.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createServer } from 'node:http';
|
|
1
|
+
import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
2
2
|
import type { Transport } from '@fougere/core';
|
|
3
3
|
import type { RpcResponse } from '../jsonrpc/RpcResponse.js';
|
|
4
4
|
import { handleRpc } from '../server.js';
|
|
@@ -14,37 +14,49 @@ export interface RunningReceiver {
|
|
|
14
14
|
export const LOOPBACK_HOSTS = ['127.0.0.1', 'localhost', '::1'];
|
|
15
15
|
|
|
16
16
|
export function serve(runner: Transport, options: ServeOptions = {}): Promise<RunningReceiver> {
|
|
17
|
+
const host = options.host ?? (options.hosts ?? LOOPBACK_HOSTS)[0];
|
|
18
|
+
const refusal = whyNotHere(host, options);
|
|
19
|
+
if (refusal) return Promise.reject(refusal);
|
|
20
|
+
|
|
21
|
+
return listening(createServer(answering(runner, options)), host!, options);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Where a receiver binds and what it admits are two questions. `verify` answers the second —
|
|
26
|
+
* without it this receiver takes the `state` it is handed, and `hosts` is all that stands.
|
|
27
|
+
* Loopback or signed: there is no third way to serve.
|
|
28
|
+
*/
|
|
29
|
+
function whyNotHere(host: string | undefined, options: ServeOptions): Error | undefined {
|
|
17
30
|
const allowed = options.hosts ?? LOOPBACK_HOSTS;
|
|
18
31
|
if (allowed.length === 0) {
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
const host = options.host ?? allowed[0];
|
|
22
|
-
// Where a receiver binds, and what it admits, are two questions now. `verify` answers
|
|
23
|
-
// the second — without it this receiver still takes the `state` it is handed, and
|
|
24
|
-
// `hosts` is all that stands. The default keeps it on the machine; widening it is
|
|
25
|
-
// written down rather than inferred, and a widened receiver wants `requireIdentity`.
|
|
26
|
-
if (!allowed.includes(host)) {
|
|
27
|
-
return Promise.reject(
|
|
28
|
-
new Error(`A Fougere receiver binds one of [${allowed.join(', ')}], got '${host}' — add it to \`hosts\` to allow it`),
|
|
29
|
-
);
|
|
32
|
+
return new Error('A Fougere receiver needs at least one host to bind, `hosts` is empty');
|
|
30
33
|
}
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
`A Fougere receiver on '${host}' is reachable from outside this machine and would believe whatever `
|
|
36
|
-
+ 'state it is handed.\n'
|
|
37
|
-
+ ' - `fougere keys` once, then inject FOUGERE_ROOT_KEY here (and `fougere grant <frond>` for each caller), or\n'
|
|
38
|
-
+ ' - keep it on loopback, or\n'
|
|
39
|
-
+ ' - pass `allowUnsigned: true` if a mesh or an ingress already authenticated the caller.',
|
|
40
|
-
),
|
|
34
|
+
|
|
35
|
+
if (host === undefined || !allowed.includes(host)) {
|
|
36
|
+
return new Error(
|
|
37
|
+
`A Fougere receiver binds one of [${allowed.join(', ')}], got '${host}' — add it to \`hosts\` to allow it`,
|
|
41
38
|
);
|
|
42
39
|
}
|
|
43
40
|
|
|
41
|
+
if (LOOPBACK_HOSTS.includes(host) || options.verify || options.allowUnsigned) return undefined;
|
|
42
|
+
|
|
43
|
+
return new Error(
|
|
44
|
+
`A Fougere receiver on '${host}' is reachable from outside this machine and would believe whatever `
|
|
45
|
+
+ 'state it is handed.\n'
|
|
46
|
+
+ ' - `fougere keys` once, then inject FOUGERE_ROOT_KEY here (and `fougere grant <frond>` for each caller), or\n'
|
|
47
|
+
+ ' - keep it on loopback, or\n'
|
|
48
|
+
+ ' - pass `allowUnsigned: true` if a mesh or an ingress already authenticated the caller.',
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One path, one method, and a body that is refused before it is read whole. */
|
|
53
|
+
function answering(runner: Transport, options: ServeOptions) {
|
|
44
54
|
const maxBodyBytes = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
45
|
-
|
|
55
|
+
|
|
56
|
+
return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {
|
|
46
57
|
if (req.method !== 'POST' || req.url !== CALL_PATH) {
|
|
47
58
|
res.writeHead(404).end();
|
|
59
|
+
|
|
48
60
|
return;
|
|
49
61
|
}
|
|
50
62
|
|
|
@@ -55,6 +67,7 @@ export function serve(runner: Transport, options: ServeOptions = {}): Promise<Ru
|
|
|
55
67
|
size += chunk.length;
|
|
56
68
|
if (size > maxBodyBytes) {
|
|
57
69
|
res.writeHead(413, { 'content-type': 'application/json' }).end(JSON.stringify(tooLarge()));
|
|
70
|
+
|
|
58
71
|
return;
|
|
59
72
|
}
|
|
60
73
|
chunks.push(chunk);
|
|
@@ -62,22 +75,25 @@ export function serve(runner: Transport, options: ServeOptions = {}): Promise<Ru
|
|
|
62
75
|
|
|
63
76
|
let response: RpcResponse;
|
|
64
77
|
try {
|
|
65
|
-
|
|
66
|
-
response = await handleRpc(runner, raw, options);
|
|
78
|
+
response = await handleRpc(runner, JSON.parse(Buffer.concat(chunks).toString('utf8')), options);
|
|
67
79
|
} catch {
|
|
68
80
|
response = parseError();
|
|
69
81
|
}
|
|
82
|
+
|
|
70
83
|
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(response));
|
|
71
|
-
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
72
86
|
|
|
87
|
+
/** The port a receiver ended up on — asked of the server, since 0 means "whatever is free". */
|
|
88
|
+
function listening(server: Server, host: string, options: ServeOptions): Promise<RunningReceiver> {
|
|
73
89
|
return new Promise((resolve, reject) => {
|
|
74
90
|
server.once('error', reject);
|
|
75
91
|
server.requestTimeout = options.requestTimeoutMs ?? 15_000;
|
|
76
92
|
server.listen(options.port ?? 0, host, () => {
|
|
77
93
|
const address = server.address();
|
|
78
|
-
|
|
94
|
+
|
|
79
95
|
resolve({
|
|
80
|
-
port,
|
|
96
|
+
port: typeof address === 'object' && address !== null ? address.port : 0,
|
|
81
97
|
close: () => new Promise<void>((done, fail) => server.close((err) => (err ? fail(err) : done()))),
|
|
82
98
|
});
|
|
83
99
|
});
|
package/src/server.ts
CHANGED
|
@@ -48,6 +48,7 @@ export async function handleRpc(runner: Transport, raw: unknown, options: Receiv
|
|
|
48
48
|
params: sent.params ?? {},
|
|
49
49
|
query: sent.query ?? {},
|
|
50
50
|
input: sent.input,
|
|
51
|
+
runAt: sent.runAt,
|
|
51
52
|
}));
|
|
52
53
|
} catch (err) {
|
|
53
54
|
return refused(id, (err as Error)?.message ?? 'unverifiable identity', entity, op);
|
|
@@ -64,6 +65,7 @@ export async function handleRpc(runner: Transport, raw: unknown, options: Receiv
|
|
|
64
65
|
input: sent.input,
|
|
65
66
|
state,
|
|
66
67
|
trace: sent.trace,
|
|
68
|
+
...(sent.runAt === undefined ? {} : { runAt: sent.runAt }),
|
|
67
69
|
...(caller ? { caller } : {}),
|
|
68
70
|
};
|
|
69
71
|
|