@fougere/transport-http 0.12.4-alpha.0 → 0.12.5-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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE1I,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,CA6ElG"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAA2C,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE1J,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, MAX_BODY_BYTES } 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
- const { caller: _established, ...forwarded } = invocation;
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 > MAX_BODY_BYTES)
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: JSON.stringify(request),
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 (${baseUrl})`,
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: `${baseUrl} unreachable: ${err?.message ?? err}`,
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: `${baseUrl} answered HTTP ${res.status} — not a Fougere receiver?`,
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: `${baseUrl} answered non-JSON`,
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 ${MAX_BODY_BYTES} bytes, the limit a receiver takes.`,
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -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,CAuEnH"}
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 }));
@@ -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.12.4-alpha.0",
3
+ "version": "0.12.5-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.4-alpha.0"
41
+ "@fougere/core": "0.12.5-alpha.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "jiti": "^2.6.1",
45
- "@fougere/container": "0.12.4-alpha.0",
46
- "@fougere/schema": "0.12.4-alpha.0",
47
- "@fougere/compiler": "0.12.4-alpha.0"
45
+ "@fougere/schema": "0.12.5-alpha.0",
46
+ "@fougere/container": "0.12.5-alpha.0",
47
+ "@fougere/compiler": "0.12.5-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, MAX_BODY_BYTES, 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
- const { caller: _established, ...forwarded } = invocation;
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 > MAX_BODY_BYTES) 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: JSON.stringify(request),
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 (${baseUrl})`,
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: `${baseUrl} unreachable: ${(err as Error)?.message ?? err}`,
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: `${baseUrl} answered HTTP ${res.status} — not a Fougere receiver?`,
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: `${baseUrl} answered non-JSON`,
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 ${MAX_BODY_BYTES} bytes, the limit a receiver takes.`,
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/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(