@fougere/transport-http 0.12.4-alpha.0 → 0.12.6-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/client.d.ts.map +1 -1
- package/dist/client.js +28 -9
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/policy.d.ts +2 -2
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +2 -2
- package/dist/policy.js.map +1 -1
- package/dist/receive.d.ts +0 -2
- package/dist/receive.d.ts.map +1 -1
- package/dist/receive.js +2 -3
- package/dist/receive.js.map +1 -1
- package/dist/serve/RunningReceiver.js +2 -2
- package/dist/serve/RunningReceiver.js.map +1 -1
- package/dist/serve/ServeOptions.d.ts +0 -2
- package/dist/serve/ServeOptions.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +25 -0
- package/dist/server.js.map +1 -1
- package/package.json +5 -5
- package/src/client.ts +27 -9
- package/src/index.ts +1 -1
- package/src/policy.ts +2 -2
- package/src/receive.ts +2 -5
- package/src/serve/RunningReceiver.ts +2 -3
- package/src/serve/ServeOptions.ts +0 -2
- package/src/server.ts +27 -0
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAwD,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEvK,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAEhG;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CA6B3E;AAED,MAAM,WAAW,oBAAoB;IACnC,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACjE;AAKD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CAoFlG"}
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Sending half — frame the call, POST it, unframe the result. */
|
|
2
|
-
import { FougereError, ErrorCode } from '@fougere/core/contract';
|
|
2
|
+
import { FougereError, ErrorCode, maxBodyBytes, maxFrameBytes } from '@fougere/core/contract';
|
|
3
3
|
/** Frame a call as a JSON-RPC request. */
|
|
4
4
|
export function frameCall(call, invocation, id) {
|
|
5
5
|
return { jsonrpc: '2.0', id, method: `${call.entity}.${call.op}`, params: invocation };
|
|
@@ -54,19 +54,23 @@ export function createHttpTransport(baseUrl, options = {}) {
|
|
|
54
54
|
// receiver choosing between a proof and a claim about the same thing.
|
|
55
55
|
// `caller` is dropped on every hop: it names who signed THIS call, so carrying the
|
|
56
56
|
// one this process was handed would make `shop → catalog → billing` read `shop`.
|
|
57
|
-
// It travels outside the envelope anyway, so a stale one would be unsigned too.
|
|
58
|
-
|
|
57
|
+
// It travels outside the envelope anyway, so a stale one would be unsigned too. `crossed`
|
|
58
|
+
// is the next receiver's to write, for the same reason.
|
|
59
|
+
const { caller: _established, crossed: _received, ...forwarded } = invocation;
|
|
59
60
|
const sent = options.sign
|
|
60
61
|
? { ...forwarded, state: {}, identity: await options.sign({ ...call, ...invocation }) }
|
|
61
62
|
: forwarded;
|
|
62
63
|
const request = frameCall(call, sent, nextId++);
|
|
64
|
+
const body = JSON.stringify(request);
|
|
65
|
+
if (new TextEncoder().encode(body).byteLength > maxFrameBytes())
|
|
66
|
+
throw tooLarge(call, baseUrl);
|
|
63
67
|
for (let attempt = 0;; attempt++) {
|
|
64
68
|
let res;
|
|
65
69
|
try {
|
|
66
70
|
res = await send(url, {
|
|
67
71
|
method: 'POST',
|
|
68
72
|
headers: { 'content-type': 'application/json' },
|
|
69
|
-
body
|
|
73
|
+
body,
|
|
70
74
|
signal: AbortSignal.timeout(timeoutMs),
|
|
71
75
|
});
|
|
72
76
|
}
|
|
@@ -74,7 +78,8 @@ export function createHttpTransport(baseUrl, options = {}) {
|
|
|
74
78
|
if (isTimeout(err)) {
|
|
75
79
|
throw new FougereError({
|
|
76
80
|
code: ErrorCode.GATEWAY_TIMEOUT,
|
|
77
|
-
message: `${call.entity}.${call.op} timed out after ${timeoutMs}ms
|
|
81
|
+
message: `${call.entity}.${call.op} timed out after ${timeoutMs}ms`,
|
|
82
|
+
cause: new Error(`${baseUrl} did not answer in ${timeoutMs}ms`),
|
|
78
83
|
entity: call.entity,
|
|
79
84
|
operation: call.op,
|
|
80
85
|
});
|
|
@@ -83,16 +88,19 @@ export function createHttpTransport(baseUrl, options = {}) {
|
|
|
83
88
|
continue;
|
|
84
89
|
throw new FougereError({
|
|
85
90
|
code: ErrorCode.SERVICE_UNAVAILABLE,
|
|
86
|
-
message: `${
|
|
91
|
+
message: `${call.entity}.${call.op}: the process serving it is unreachable`,
|
|
87
92
|
entity: call.entity,
|
|
88
93
|
operation: call.op,
|
|
89
|
-
cause: err,
|
|
94
|
+
cause: new Error(`${baseUrl} unreachable: ${err?.message ?? err}`, { cause: err }),
|
|
90
95
|
});
|
|
91
96
|
}
|
|
97
|
+
if (res.status === 413)
|
|
98
|
+
throw tooLarge(call, baseUrl);
|
|
92
99
|
if (!res.ok) {
|
|
93
100
|
throw new FougereError({
|
|
94
101
|
code: ErrorCode.BAD_GATEWAY,
|
|
95
|
-
message: `${
|
|
102
|
+
message: `${call.entity}.${call.op}: the receiver answered HTTP ${res.status} — not a Fougere receiver?`,
|
|
103
|
+
cause: new Error(`${baseUrl} answered HTTP ${res.status}`),
|
|
96
104
|
entity: call.entity,
|
|
97
105
|
operation: call.op,
|
|
98
106
|
});
|
|
@@ -104,7 +112,8 @@ export function createHttpTransport(baseUrl, options = {}) {
|
|
|
104
112
|
catch {
|
|
105
113
|
throw new FougereError({
|
|
106
114
|
code: ErrorCode.BAD_GATEWAY,
|
|
107
|
-
message: `${
|
|
115
|
+
message: `${call.entity}.${call.op}: the receiver answered non-JSON`,
|
|
116
|
+
cause: new Error(`${baseUrl} answered non-JSON`),
|
|
108
117
|
entity: call.entity,
|
|
109
118
|
operation: call.op,
|
|
110
119
|
});
|
|
@@ -113,6 +122,16 @@ export function createHttpTransport(baseUrl, options = {}) {
|
|
|
113
122
|
}
|
|
114
123
|
};
|
|
115
124
|
}
|
|
125
|
+
/** A frame over the receiver's limit — said before sending, or when a receiver answers 413. */
|
|
126
|
+
function tooLarge(call, baseUrl) {
|
|
127
|
+
return new FougereError({
|
|
128
|
+
code: ErrorCode.PAYLOAD_TOO_LARGE,
|
|
129
|
+
message: `${call.entity}.${call.op} carries more than the ${maxBodyBytes()} bytes a caller may send (maxBodyBytes).`,
|
|
130
|
+
cause: new Error(`refused for ${baseUrl}`),
|
|
131
|
+
entity: call.entity,
|
|
132
|
+
operation: call.op,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
116
135
|
function isTimeout(err) {
|
|
117
136
|
return err instanceof DOMException && (err.name === 'TimeoutError' || err.name === 'AbortError');
|
|
118
137
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,SAAS,EAA2E,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAA2E,MAAM,wBAAwB,CAAC;AAMvK,0CAA0C;AAC1C,MAAM,UAAU,SAAS,CAAC,IAAe,EAAE,UAA6B,EAAE,EAAU;IAClF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACzF,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,eAAe,CAAC,QAAiB,EAAE,IAAe;IAChE,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,IAAI,OAAO,IAAI,QAAQ,CAAC,EAAE,CAAC;QAChG,MAAM,IAAI,YAAY,CAAC;YACrB,IAAI,EAAE,SAAS,CAAC,WAAW;YAC3B,OAAO,EAAE,kEAAkE;YAC3E,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,EAAE;SACnB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAsC,CAAC;QAC9D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,YAAY,CAAC;gBACrB,IAAI,EAAE,SAAS,CAAC,WAAW;gBAC3B,OAAO,EAAE,uDAAuD;gBAChE,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI,CAAC,EAAE;aACnB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;YAAE,MAAM,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtE,MAAM,IAAI,YAAY,CAAC;YACrB,IAAI,EAAE,SAAS,CAAC,cAAc;YAC9B,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,SAAS,KAAK,CAAC,IAAI,GAAG;YAC/C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,EAAE;SACnB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,CAAC;AACzB,CAAC;AAeD,+EAA+E;AAC/E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AAEhF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,OAAO,GAAyB,EAAE;IACrF,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC;IAC1D,wFAAwF;IACxF,qFAAqF;IACrF,kFAAkF;IAClF,uFAAuF;IACvF,sFAAsF;IACtF,sBAAsB;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;QAChC,6EAA6E;QAC7E,sEAAsE;QACtE,mFAAmF;QACnF,iFAAiF;QACjF,0FAA0F;QAC1F,wDAAwD;QACxD,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC;QAC9E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI;YACvB,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,UAAU,EAAE,CAAC,EAAE;YACvF,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,aAAa,EAAE;YAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAE/F,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;YAClC,IAAI,GAAa,CAAC;YAClB,IAAI,CAAC;gBACH,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE;oBACpB,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBAC/C,IAAI;oBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;iBACvC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnB,MAAM,IAAI,YAAY,CAAC;wBACrB,IAAI,EAAE,SAAS,CAAC,eAAe;wBAC/B,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,oBAAoB,SAAS,IAAI;wBACnE,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,OAAO,sBAAsB,SAAS,IAAI,CAAC;wBAC/D,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,SAAS,EAAE,IAAI,CAAC,EAAE;qBACnB,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,OAAO,GAAG,OAAO,IAAI,mBAAmB,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC5D,MAAM,IAAI,YAAY,CAAC;oBACrB,IAAI,EAAE,SAAS,CAAC,mBAAmB;oBACnC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,yCAAyC;oBAC3E,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,SAAS,EAAE,IAAI,CAAC,EAAE;oBAClB,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,OAAO,iBAAkB,GAAa,EAAE,OAAO,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;iBAC9F,CAAC,CAAC;YACL,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACtD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,YAAY,CAAC;oBACrB,IAAI,EAAE,SAAS,CAAC,WAAW;oBAC3B,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,gCAAgC,GAAG,CAAC,MAAM,4BAA4B;oBACxG,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,OAAO,kBAAkB,GAAG,CAAC,MAAM,EAAE,CAAC;oBAC1D,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,SAAS,EAAE,IAAI,CAAC,EAAE;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,IAAI,QAAqB,CAAC;YAC1B,IAAI,CAAC;gBACH,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAgB,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,YAAY,CAAC;oBACrB,IAAI,EAAE,SAAS,CAAC,WAAW;oBAC3B,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,kCAAkC;oBACpE,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,OAAO,oBAAoB,CAAC;oBAChD,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,SAAS,EAAE,IAAI,CAAC,EAAE;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,OAAO,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,SAAS,QAAQ,CAAC,IAAe,EAAE,OAAe;IAChD,OAAO,IAAI,YAAY,CAAC;QACtB,IAAI,EAAE,SAAS,CAAC,iBAAiB;QACjC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,0BAA0B,YAAY,EAAE,0CAA0C;QACpH,KAAK,EAAE,IAAI,KAAK,CAAC,eAAe,OAAO,EAAE,CAAC;QAC1C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,EAAE;KACnB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,OAAO,GAAG,YAAY,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;AACnG,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAY;IACvC,MAAM,IAAI,GAAI,GAAqC,EAAE,KAAK,EAAE,IAAI,CAAC;IAEjE,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createHttpTransport, frameCall, unframeResponse } from './client.js';
|
|
2
2
|
export { handleRpc } from './server.js';
|
|
3
3
|
export { receive } from './receive.js';
|
|
4
|
-
export {
|
|
4
|
+
export { maxFrameBytes } from './policy.js';
|
|
5
5
|
export { serve, type RunningReceiver } from './serve/RunningReceiver.js';
|
|
6
6
|
export { PARSE_ERROR } from './jsonrpc/RpcErrorShape.js';
|
|
7
7
|
export type { RpcResponse } from './jsonrpc/RpcResponse.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createHttpTransport, frameCall, unframeResponse } from './client.js';
|
|
2
2
|
export { handleRpc } from './server.js';
|
|
3
3
|
export { receive } from './receive.js';
|
|
4
|
-
export {
|
|
4
|
+
export { maxFrameBytes } from './policy.js';
|
|
5
5
|
export { serve } from './serve/RunningReceiver.js';
|
|
6
6
|
export { PARSE_ERROR } from './jsonrpc/RpcErrorShape.js';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAwB,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/policy.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type RpcResponse } from './jsonrpc/RpcResponse.js';
|
|
2
|
-
/** What a receiver
|
|
3
|
-
export {
|
|
2
|
+
/** What a receiver reads before it stops — the caller's limit and the envelope's room, both core's. */
|
|
3
|
+
export { maxFrameBytes } from '@fougere/core';
|
|
4
4
|
/** The path the envelope answers on. A host mounting it elsewhere passes its own. */
|
|
5
5
|
export declare const CALL_PATH = "/_fougere/call";
|
|
6
6
|
/** The answer to a payload that was not JSON. */
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,uGAAuG;AACvG,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,qFAAqF;AACrF,eAAO,MAAM,SAAS,mBAAmB,CAAC;AAE1C,iDAAiD;AACjD,eAAO,MAAM,UAAU,QAAO,WAI5B,CAAC;AAEH,yCAAyC;AACzC,eAAO,MAAM,QAAQ;IAAY,KAAK;CAAwB,CAAC"}
|
package/dist/policy.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** What every receiver of the envelope decides the same way, and what it does not. */
|
|
2
2
|
import { PARSE_ERROR } from './jsonrpc/RpcErrorShape.js';
|
|
3
|
-
/** What a receiver
|
|
4
|
-
export {
|
|
3
|
+
/** What a receiver reads before it stops — the caller's limit and the envelope's room, both core's. */
|
|
4
|
+
export { maxFrameBytes } from '@fougere/core';
|
|
5
5
|
/** The path the envelope answers on. A host mounting it elsewhere passes its own. */
|
|
6
6
|
export const CALL_PATH = '/_fougere/call';
|
|
7
7
|
/** The answer to a payload that was not JSON. */
|
package/dist/policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGzD,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGzD,uGAAuG;AACvG,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,qFAAqF;AACrF,MAAM,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAE1C,iDAAiD;AACjD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAgB,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,KAAK;IACd,EAAE,EAAE,IAAI;IACR,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE;CACrD,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC"}
|
package/dist/receive.d.ts
CHANGED
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
import { type ReceiveOptions } from './server.js';
|
|
9
9
|
import type { Transport } from '@fougere/core/contract';
|
|
10
10
|
export interface ReceiveHttpOptions extends ReceiveOptions {
|
|
11
|
-
/** Maximum JSON-RPC body size. Default: 1 MiB. */
|
|
12
|
-
maxBodyBytes?: number;
|
|
13
11
|
/** The path this facade answers. Default: `/_fougere/call`. */
|
|
14
12
|
path?: string;
|
|
15
13
|
/** Take unsigned calls, deliberately. */
|
package/dist/receive.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../src/receive.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD
|
|
1
|
+
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../src/receive.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AA+CD,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,kBAAuB,GAC/B,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+BzC"}
|
package/dist/receive.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* baseline, measured 2026-08-22.
|
|
7
7
|
*/
|
|
8
8
|
import { handleRpc } from './server.js';
|
|
9
|
-
import {
|
|
9
|
+
import { maxFrameBytes, CALL_PATH, parseError, tooLarge } from './policy.js';
|
|
10
10
|
const json = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
|
|
11
11
|
/** Distinguishes "the body was too large" from any body a caller could actually send. */
|
|
12
12
|
const TOO_LARGE = Symbol('too large');
|
|
@@ -54,13 +54,12 @@ export function receive(runner, options = {}) {
|
|
|
54
54
|
+ ' or say `allowUnsigned: true` — which is right for local development and for a\n'
|
|
55
55
|
+ ' mesh whose sidecar already established the peer.');
|
|
56
56
|
}
|
|
57
|
-
const max = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
58
57
|
const path = options.path ?? CALL_PATH;
|
|
59
58
|
return async (request) => {
|
|
60
59
|
if (request.method !== 'POST' || new URL(request.url).pathname !== path) {
|
|
61
60
|
return new Response(null, { status: 404 });
|
|
62
61
|
}
|
|
63
|
-
const raw = await bodyWithin(request,
|
|
62
|
+
const raw = await bodyWithin(request, maxFrameBytes());
|
|
64
63
|
if (raw === TOO_LARGE)
|
|
65
64
|
return json(tooLarge(), 413);
|
|
66
65
|
let parsed;
|
package/dist/receive.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../src/receive.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAuB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../src/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
2
|
import { handleRpc } from '../server.js';
|
|
3
|
-
import {
|
|
3
|
+
import { maxFrameBytes, 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 = {}) {
|
|
@@ -33,12 +33,12 @@ function whyNotHere(host, options) {
|
|
|
33
33
|
}
|
|
34
34
|
/** One path, one method, and a body that is refused before it is read whole. */
|
|
35
35
|
function answering(runner, options) {
|
|
36
|
-
const maxBodyBytes = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
37
36
|
return async (req, res) => {
|
|
38
37
|
if (req.method !== 'POST' || req.url !== CALL_PATH) {
|
|
39
38
|
res.writeHead(404).end();
|
|
40
39
|
return;
|
|
41
40
|
}
|
|
41
|
+
const maxBodyBytes = maxFrameBytes();
|
|
42
42
|
const chunks = [];
|
|
43
43
|
let size = 0;
|
|
44
44
|
for await (const value of req) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunningReceiver.js","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAGjG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RunningReceiver.js","sourceRoot":"","sources":["../../src/serve/RunningReceiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,8 +8,6 @@ export interface ServeOptions extends ReceiveOptions {
|
|
|
8
8
|
host?: string;
|
|
9
9
|
/** Serve unsigned calls beyond loopback, deliberately. */
|
|
10
10
|
allowUnsigned?: boolean;
|
|
11
|
-
/** Maximum JSON-RPC body size. Default: 1 MiB. */
|
|
12
|
-
maxBodyBytes?: number;
|
|
13
11
|
/** Time allowed to receive a request. Default: 15 seconds. */
|
|
14
12
|
requestTimeoutMs?: number;
|
|
15
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServeOptions.d.ts","sourceRoot":"","sources":["../../src/serve/ServeOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,
|
|
1
|
+
{"version":3,"file":"ServeOptions.d.ts","sourceRoot":"","sources":["../../src/serve/ServeOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
|
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,CA4EnH"}
|
package/dist/server.js
CHANGED
|
@@ -19,6 +19,11 @@ export async function handleRpc(runner, raw, options = {}) {
|
|
|
19
19
|
const op = req.method.slice(dot + 1);
|
|
20
20
|
// Fresh objects — middlewares deposit into state, nothing may be shared.
|
|
21
21
|
const sent = (req.params ?? {});
|
|
22
|
+
const strangers = Object.entries(sent)
|
|
23
|
+
.filter(([key, value]) => value !== undefined && !SENT[key])
|
|
24
|
+
.map(([key]) => key);
|
|
25
|
+
if (strangers.length > 0)
|
|
26
|
+
return malformed(id, strangers, entity, op);
|
|
22
27
|
/** State is ESTABLISHED here, or it is only claimed. */
|
|
23
28
|
let state = sent.state ?? {};
|
|
24
29
|
let caller;
|
|
@@ -51,6 +56,7 @@ export async function handleRpc(runner, raw, options = {}) {
|
|
|
51
56
|
trace: sent.trace,
|
|
52
57
|
...(sent.runAt === undefined ? {} : { runAt: sent.runAt }),
|
|
53
58
|
...(caller ? { caller } : {}),
|
|
59
|
+
crossed: true,
|
|
54
60
|
};
|
|
55
61
|
try {
|
|
56
62
|
return { jsonrpc: '2.0', id, result: await runner({ entity, op }, invocation) };
|
|
@@ -69,6 +75,25 @@ export async function handleRpc(runner, raw, options = {}) {
|
|
|
69
75
|
return { jsonrpc: '2.0', id, error: { code: APP_ERROR, message: data.message, data } };
|
|
70
76
|
}
|
|
71
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The members a caller may send. `caller` and `crossed` are written by the receiver and never claimed, and
|
|
80
|
+
* a key outside the list is refused by name: `body` used to be dropped, and the call then ran
|
|
81
|
+
* with no input and no validation.
|
|
82
|
+
*/
|
|
83
|
+
const SENT = {
|
|
84
|
+
params: true, query: true, input: true, state: true, trace: true, identity: true, runAt: true, caller: false,
|
|
85
|
+
crossed: false,
|
|
86
|
+
};
|
|
87
|
+
function malformed(id, strangers, entity, op) {
|
|
88
|
+
const admitted = Object.keys(SENT).filter((key) => SENT[key]);
|
|
89
|
+
const data = toPublicError(new FougereError({
|
|
90
|
+
code: ErrorCode.BAD_REQUEST,
|
|
91
|
+
message: `Unknown invocation member ${strangers.map((key) => `'${key}'`).join(', ')} — one of ${admitted.join(', ')}.`,
|
|
92
|
+
entity,
|
|
93
|
+
operation: op,
|
|
94
|
+
}));
|
|
95
|
+
return { jsonrpc: '2.0', id, error: { code: APP_ERROR, message: data.message, data } };
|
|
96
|
+
}
|
|
72
97
|
/** An admission refusal, framed like any other failure so a caller reads one vocabulary. */
|
|
73
98
|
function refused(id, why, entity, op) {
|
|
74
99
|
const data = toPublicError(new FougereError({ code: ErrorCode.UNAUTHORIZED, message: `Refused: ${why}`, entity, operation: op }));
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAA2D,MAAM,wBAAwB,CAAC;AACzI,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAcxE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAiB,EAAE,GAAY,EAAE,OAAO,GAAmB,EAAE;IAC3F,MAAM,GAAG,GAAG,GAAiC,CAAC;IAC9C,MAAM,EAAE,GAAG,OAAO,GAAG,EAAE,EAAE,KAAK,QAAQ,IAAI,OAAO,GAAG,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtF,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACnF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,8BAA8B,EAAE,EAAE,CAAC;IAC3G,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,OAAO;YACL,OAAO,EAAE,KAAK;YACd,EAAE;YACF,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,GAAG,CAAC,MAAM,0BAA0B,EAAE;SACnG,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxC,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAErC,yEAAyE;IACzE,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAA+B,CAAC;
|
|
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.12.
|
|
3
|
+
"version": "0.12.6-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.12.
|
|
41
|
+
"@fougere/core": "0.12.6-alpha.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"jiti": "^2.6.1",
|
|
45
|
-
"@fougere/
|
|
46
|
-
"@fougere/
|
|
47
|
-
"@fougere/compiler": "0.12.
|
|
45
|
+
"@fougere/schema": "0.12.6-alpha.0",
|
|
46
|
+
"@fougere/container": "0.12.6-alpha.0",
|
|
47
|
+
"@fougere/compiler": "0.12.6-alpha.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
package/src/client.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Sending half — frame the call, POST it, unframe the result. */
|
|
2
|
-
import { FougereError, ErrorCode, type Transport, type FrondCall, type InvocationContext, type SignedCall } from '@fougere/core/contract';
|
|
2
|
+
import { FougereError, ErrorCode, maxBodyBytes, maxFrameBytes, type Transport, type FrondCall, type InvocationContext, type SignedCall } from '@fougere/core/contract';
|
|
3
3
|
import type { RpcErrorShape } from './jsonrpc/RpcErrorShape.js';
|
|
4
4
|
import type { RpcRequest } from './jsonrpc/RpcRequest.js';
|
|
5
5
|
import type { RpcResponse } from './jsonrpc/RpcResponse.js';
|
|
@@ -76,12 +76,15 @@ export function createHttpTransport(baseUrl: string, options: HttpTransportOptio
|
|
|
76
76
|
// receiver choosing between a proof and a claim about the same thing.
|
|
77
77
|
// `caller` is dropped on every hop: it names who signed THIS call, so carrying the
|
|
78
78
|
// one this process was handed would make `shop → catalog → billing` read `shop`.
|
|
79
|
-
// It travels outside the envelope anyway, so a stale one would be unsigned too.
|
|
80
|
-
|
|
79
|
+
// It travels outside the envelope anyway, so a stale one would be unsigned too. `crossed`
|
|
80
|
+
// is the next receiver's to write, for the same reason.
|
|
81
|
+
const { caller: _established, crossed: _received, ...forwarded } = invocation;
|
|
81
82
|
const sent = options.sign
|
|
82
83
|
? { ...forwarded, state: {}, identity: await options.sign({ ...call, ...invocation }) }
|
|
83
84
|
: forwarded;
|
|
84
85
|
const request = frameCall(call, sent, nextId++);
|
|
86
|
+
const body = JSON.stringify(request);
|
|
87
|
+
if (new TextEncoder().encode(body).byteLength > maxFrameBytes()) throw tooLarge(call, baseUrl);
|
|
85
88
|
|
|
86
89
|
for (let attempt = 0; ; attempt++) {
|
|
87
90
|
let res: Response;
|
|
@@ -89,14 +92,15 @@ export function createHttpTransport(baseUrl: string, options: HttpTransportOptio
|
|
|
89
92
|
res = await send(url, {
|
|
90
93
|
method: 'POST',
|
|
91
94
|
headers: { 'content-type': 'application/json' },
|
|
92
|
-
body
|
|
95
|
+
body,
|
|
93
96
|
signal: AbortSignal.timeout(timeoutMs),
|
|
94
97
|
});
|
|
95
98
|
} catch (err) {
|
|
96
99
|
if (isTimeout(err)) {
|
|
97
100
|
throw new FougereError({
|
|
98
101
|
code: ErrorCode.GATEWAY_TIMEOUT,
|
|
99
|
-
message: `${call.entity}.${call.op} timed out after ${timeoutMs}ms
|
|
102
|
+
message: `${call.entity}.${call.op} timed out after ${timeoutMs}ms`,
|
|
103
|
+
cause: new Error(`${baseUrl} did not answer in ${timeoutMs}ms`),
|
|
100
104
|
entity: call.entity,
|
|
101
105
|
operation: call.op,
|
|
102
106
|
});
|
|
@@ -104,17 +108,19 @@ export function createHttpTransport(baseUrl: string, options: HttpTransportOptio
|
|
|
104
108
|
if (attempt < retries && isConnectionFailure(err)) continue;
|
|
105
109
|
throw new FougereError({
|
|
106
110
|
code: ErrorCode.SERVICE_UNAVAILABLE,
|
|
107
|
-
message: `${
|
|
111
|
+
message: `${call.entity}.${call.op}: the process serving it is unreachable`,
|
|
108
112
|
entity: call.entity,
|
|
109
113
|
operation: call.op,
|
|
110
|
-
cause: err,
|
|
114
|
+
cause: new Error(`${baseUrl} unreachable: ${(err as Error)?.message ?? err}`, { cause: err }),
|
|
111
115
|
});
|
|
112
116
|
}
|
|
113
117
|
|
|
118
|
+
if (res.status === 413) throw tooLarge(call, baseUrl);
|
|
114
119
|
if (!res.ok) {
|
|
115
120
|
throw new FougereError({
|
|
116
121
|
code: ErrorCode.BAD_GATEWAY,
|
|
117
|
-
message: `${
|
|
122
|
+
message: `${call.entity}.${call.op}: the receiver answered HTTP ${res.status} — not a Fougere receiver?`,
|
|
123
|
+
cause: new Error(`${baseUrl} answered HTTP ${res.status}`),
|
|
118
124
|
entity: call.entity,
|
|
119
125
|
operation: call.op,
|
|
120
126
|
});
|
|
@@ -126,7 +132,8 @@ export function createHttpTransport(baseUrl: string, options: HttpTransportOptio
|
|
|
126
132
|
} catch {
|
|
127
133
|
throw new FougereError({
|
|
128
134
|
code: ErrorCode.BAD_GATEWAY,
|
|
129
|
-
message: `${
|
|
135
|
+
message: `${call.entity}.${call.op}: the receiver answered non-JSON`,
|
|
136
|
+
cause: new Error(`${baseUrl} answered non-JSON`),
|
|
130
137
|
entity: call.entity,
|
|
131
138
|
operation: call.op,
|
|
132
139
|
});
|
|
@@ -137,6 +144,17 @@ export function createHttpTransport(baseUrl: string, options: HttpTransportOptio
|
|
|
137
144
|
};
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
/** A frame over the receiver's limit — said before sending, or when a receiver answers 413. */
|
|
148
|
+
function tooLarge(call: FrondCall, baseUrl: string): FougereError {
|
|
149
|
+
return new FougereError({
|
|
150
|
+
code: ErrorCode.PAYLOAD_TOO_LARGE,
|
|
151
|
+
message: `${call.entity}.${call.op} carries more than the ${maxBodyBytes()} bytes a caller may send (maxBodyBytes).`,
|
|
152
|
+
cause: new Error(`refused for ${baseUrl}`),
|
|
153
|
+
entity: call.entity,
|
|
154
|
+
operation: call.op,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
140
158
|
function isTimeout(err: unknown): boolean {
|
|
141
159
|
return err instanceof DOMException && (err.name === 'TimeoutError' || err.name === 'AbortError');
|
|
142
160
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createHttpTransport, frameCall, unframeResponse } from './client.js';
|
|
2
2
|
export { handleRpc } from './server.js';
|
|
3
3
|
export { receive } from './receive.js';
|
|
4
|
-
export {
|
|
4
|
+
export { maxFrameBytes } from './policy.js';
|
|
5
5
|
export { serve, type RunningReceiver } from './serve/RunningReceiver.js';
|
|
6
6
|
export { PARSE_ERROR } from './jsonrpc/RpcErrorShape.js';
|
|
7
7
|
export type { RpcResponse } from './jsonrpc/RpcResponse.js';
|
package/src/policy.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { PARSE_ERROR } from './jsonrpc/RpcErrorShape.js';
|
|
3
3
|
import { type RpcResponse } from './jsonrpc/RpcResponse.js';
|
|
4
4
|
|
|
5
|
-
/** What a receiver
|
|
6
|
-
export {
|
|
5
|
+
/** What a receiver reads before it stops — the caller's limit and the envelope's room, both core's. */
|
|
6
|
+
export { maxFrameBytes } from '@fougere/core';
|
|
7
7
|
|
|
8
8
|
/** The path the envelope answers on. A host mounting it elsewhere passes its own. */
|
|
9
9
|
export const CALL_PATH = '/_fougere/call';
|
package/src/receive.ts
CHANGED
|
@@ -6,12 +6,10 @@
|
|
|
6
6
|
* baseline, measured 2026-08-22.
|
|
7
7
|
*/
|
|
8
8
|
import { handleRpc, type ReceiveOptions } from './server.js';
|
|
9
|
-
import {
|
|
9
|
+
import { maxFrameBytes, CALL_PATH, parseError, tooLarge } from './policy.js';
|
|
10
10
|
import type { Transport } from '@fougere/core/contract';
|
|
11
11
|
|
|
12
12
|
export interface ReceiveHttpOptions extends ReceiveOptions {
|
|
13
|
-
/** Maximum JSON-RPC body size. Default: 1 MiB. */
|
|
14
|
-
maxBodyBytes?: number;
|
|
15
13
|
/** The path this facade answers. Default: `/_fougere/call`. */
|
|
16
14
|
path?: string;
|
|
17
15
|
/** Take unsigned calls, deliberately. */
|
|
@@ -78,7 +76,6 @@ export function receive(
|
|
|
78
76
|
);
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
const max = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
82
79
|
const path = options.path ?? CALL_PATH;
|
|
83
80
|
|
|
84
81
|
return async (request) => {
|
|
@@ -86,7 +83,7 @@ export function receive(
|
|
|
86
83
|
return new Response(null, { status: 404 });
|
|
87
84
|
}
|
|
88
85
|
|
|
89
|
-
const raw = await bodyWithin(request,
|
|
86
|
+
const raw = await bodyWithin(request, maxFrameBytes());
|
|
90
87
|
if (raw === TOO_LARGE) return json(tooLarge(), 413);
|
|
91
88
|
|
|
92
89
|
let parsed: unknown;
|
|
@@ -2,7 +2,7 @@ import { createServer, type IncomingMessage, type Server, type ServerResponse }
|
|
|
2
2
|
import type { Transport } from '@fougere/core';
|
|
3
3
|
import type { RpcResponse } from '../jsonrpc/RpcResponse.js';
|
|
4
4
|
import { handleRpc } from '../server.js';
|
|
5
|
-
import {
|
|
5
|
+
import { maxFrameBytes, CALL_PATH, parseError, tooLarge } from '../policy.js';
|
|
6
6
|
import type { ServeOptions } from './ServeOptions.js';
|
|
7
7
|
|
|
8
8
|
export interface RunningReceiver {
|
|
@@ -51,8 +51,6 @@ function whyNotHere(host: string | undefined, options: ServeOptions): Error | un
|
|
|
51
51
|
|
|
52
52
|
/** One path, one method, and a body that is refused before it is read whole. */
|
|
53
53
|
function answering(runner: Transport, options: ServeOptions) {
|
|
54
|
-
const maxBodyBytes = options.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
55
|
-
|
|
56
54
|
return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {
|
|
57
55
|
if (req.method !== 'POST' || req.url !== CALL_PATH) {
|
|
58
56
|
res.writeHead(404).end();
|
|
@@ -60,6 +58,7 @@ function answering(runner: Transport, options: ServeOptions) {
|
|
|
60
58
|
return;
|
|
61
59
|
}
|
|
62
60
|
|
|
61
|
+
const maxBodyBytes = maxFrameBytes();
|
|
63
62
|
const chunks: Buffer[] = [];
|
|
64
63
|
let size = 0;
|
|
65
64
|
for await (const value of req) {
|
|
@@ -9,8 +9,6 @@ export interface ServeOptions extends ReceiveOptions {
|
|
|
9
9
|
host?: string;
|
|
10
10
|
/** Serve unsigned calls beyond loopback, deliberately. */
|
|
11
11
|
allowUnsigned?: boolean;
|
|
12
|
-
/** Maximum JSON-RPC body size. Default: 1 MiB. */
|
|
13
|
-
maxBodyBytes?: number;
|
|
14
12
|
/** Time allowed to receive a request. Default: 15 seconds. */
|
|
15
13
|
requestTimeoutMs?: number;
|
|
16
14
|
}
|
package/src/server.ts
CHANGED
|
@@ -35,6 +35,10 @@ export async function handleRpc(runner: Transport, raw: unknown, options: Receiv
|
|
|
35
35
|
|
|
36
36
|
// Fresh objects — middlewares deposit into state, nothing may be shared.
|
|
37
37
|
const sent = (req.params ?? {}) as Partial<InvocationContext>;
|
|
38
|
+
const strangers = Object.entries(sent)
|
|
39
|
+
.filter(([key, value]) => value !== undefined && !SENT[key as keyof InvocationContext])
|
|
40
|
+
.map(([key]) => key);
|
|
41
|
+
if (strangers.length > 0) return malformed(id, strangers, entity, op);
|
|
38
42
|
|
|
39
43
|
/** State is ESTABLISHED here, or it is only claimed. */
|
|
40
44
|
let state: Record<string, unknown> = sent.state ?? {};
|
|
@@ -67,6 +71,7 @@ export async function handleRpc(runner: Transport, raw: unknown, options: Receiv
|
|
|
67
71
|
trace: sent.trace,
|
|
68
72
|
...(sent.runAt === undefined ? {} : { runAt: sent.runAt }),
|
|
69
73
|
...(caller ? { caller } : {}),
|
|
74
|
+
crossed: true,
|
|
70
75
|
};
|
|
71
76
|
|
|
72
77
|
try {
|
|
@@ -87,6 +92,28 @@ export async function handleRpc(runner: Transport, raw: unknown, options: Receiv
|
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
|
|
95
|
+
/**
|
|
96
|
+
* The members a caller may send. `caller` and `crossed` are written by the receiver and never claimed, and
|
|
97
|
+
* a key outside the list is refused by name: `body` used to be dropped, and the call then ran
|
|
98
|
+
* with no input and no validation.
|
|
99
|
+
*/
|
|
100
|
+
const SENT = {
|
|
101
|
+
params: true, query: true, input: true, state: true, trace: true, identity: true, runAt: true, caller: false,
|
|
102
|
+
crossed: false,
|
|
103
|
+
} satisfies Record<keyof InvocationContext, boolean>;
|
|
104
|
+
|
|
105
|
+
function malformed(id: string | number, strangers: string[], entity: string, op: string): RpcResponse {
|
|
106
|
+
const admitted = Object.keys(SENT).filter((key) => SENT[key as keyof InvocationContext]);
|
|
107
|
+
const data = toPublicError(new FougereError({
|
|
108
|
+
code: ErrorCode.BAD_REQUEST,
|
|
109
|
+
message: `Unknown invocation member ${strangers.map((key) => `'${key}'`).join(', ')} — one of ${admitted.join(', ')}.`,
|
|
110
|
+
entity,
|
|
111
|
+
operation: op,
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
return { jsonrpc: '2.0', id, error: { code: APP_ERROR, message: data.message, data } };
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
/** An admission refusal, framed like any other failure so a caller reads one vocabulary. */
|
|
91
118
|
function refused(id: string | number, why: string, entity: string, op: string): RpcResponse {
|
|
92
119
|
const data = toPublicError(
|