@c9up/comet 0.1.0 → 0.1.2
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 +55 -10
- package/dist/client.js.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +13 -3
- package/dist/protocol.js.map +1 -1
- package/package.json +2 -1
- package/src/client.ts +64 -11
- package/src/protocol.ts +14 -3
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAGN,QAAQ,EAGR,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,MAAM,WAAW,gBAAgB;IAChC,wDAAwD;IACxD,SAAS,EAAE,YAAY,CAAC;IACxB,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAC;IAC7B,uFAAuF;IACvF,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wFAAwF;AACxF,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAC;CAC7B;AAED,+EAA+E;AAC/E,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,OAAO,IAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAElC,MAAM,WAAW,SAAS;IACzB;;;;;OAKG;IACH,IAAI,CAAC,CAAC,GAAG,OAAO,EACf,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAAC;IACd;;;OAGG;IACH,KAAK,CACJ,KAAK,EAAE,OAAO,EAAE,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAChC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAGN,QAAQ,EAGR,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,MAAM,WAAW,gBAAgB;IAChC,wDAAwD;IACxD,SAAS,EAAE,YAAY,CAAC;IACxB,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAC;IAC7B,uFAAuF;IACvF,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wFAAwF;AACxF,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAC;CAC7B;AAED,+EAA+E;AAC/E,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,OAAO,IAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAElC,MAAM,WAAW,SAAS;IACzB;;;;;OAKG;IACH,IAAI,CAAC,CAAC,GAAG,OAAO,EACf,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAAC;IACd;;;OAGG;IACH,KAAK,CACJ,KAAK,EAAE,OAAO,EAAE,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAChC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAyHpE"}
|
package/dist/client.js
CHANGED
|
@@ -21,11 +21,29 @@ export function createRpcClient(options) {
|
|
|
21
21
|
const res = await transport(url, buildRequest(method, params, id), {
|
|
22
22
|
signal: callOptions?.signal,
|
|
23
23
|
});
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// Envelope conformance (JSON-RPC 2.0 §5): the version must match and the
|
|
25
|
+
// id MUST echo the one we sent — otherwise a stale, mis-routed, or
|
|
26
|
+
// forged response could satisfy the wrong call. Reject before trusting
|
|
27
|
+
// `result`.
|
|
28
|
+
if (!isObject(res) || res.jsonrpc !== "2.0" || res.id !== id) {
|
|
29
|
+
throw new RpcError(RpcErrorCode.InternalError, `Malformed or mismatched JSON-RPC response for "${method}" (bad jsonrpc/id envelope)`);
|
|
30
|
+
}
|
|
31
|
+
// §5: `result` and `error` are mutually exclusive — "Either the
|
|
32
|
+
// result member or error member MUST be included, but both members
|
|
33
|
+
// MUST NOT be included." A response carrying both is malformed, and
|
|
34
|
+
// reading the error out of it is guessing at which half the sender
|
|
35
|
+
// meant. Refused, the way a bad jsonrpc/id envelope already is.
|
|
36
|
+
const hasResult = "result" in res;
|
|
37
|
+
if (hasResult && res.error !== undefined) {
|
|
38
|
+
throw new RpcError(RpcErrorCode.InternalError, `Malformed JSON-RPC response for "${method}" (carries both result and error)`);
|
|
26
39
|
}
|
|
27
40
|
if (res.error !== undefined)
|
|
28
41
|
throw toRpcError(res.error);
|
|
42
|
+
// A conformant success response carries `result` (any JSON value,
|
|
43
|
+
// including null) and no error — neither key present is malformed.
|
|
44
|
+
if (!hasResult) {
|
|
45
|
+
throw new RpcError(RpcErrorCode.InternalError, `JSON-RPC response for "${method}" has neither result nor error`);
|
|
46
|
+
}
|
|
29
47
|
// Result boundary — the same unchecked `T` assertion HTTP clients use,
|
|
30
48
|
// with `parse` as the cast-free, runtime-validated escape hatch.
|
|
31
49
|
return callOptions?.parse
|
|
@@ -44,21 +62,48 @@ export function createRpcClient(options) {
|
|
|
44
62
|
if (!Array.isArray(res)) {
|
|
45
63
|
throw new RpcError(RpcErrorCode.InternalError, "Malformed JSON-RPC batch response");
|
|
46
64
|
}
|
|
65
|
+
// Envelope conformance, per item, exactly as `call` applies it — this
|
|
66
|
+
// checked none of it, so `{ jsonrpc: "1.0", id: 0 }` came back as
|
|
67
|
+
// `{ ok: true, value: undefined }` where the single-call path would
|
|
68
|
+
// have refused it.
|
|
47
69
|
const byId = new Map();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
const duplicated = new Set();
|
|
71
|
+
for (const item of res) {
|
|
72
|
+
if (!isObject(item))
|
|
73
|
+
continue;
|
|
74
|
+
// A repeated id is a malformed batch, and silently keeping the last
|
|
75
|
+
// one lets a response answer a call it was not for.
|
|
76
|
+
if (byId.has(item.id))
|
|
77
|
+
duplicated.add(item.id);
|
|
78
|
+
byId.set(item.id, item);
|
|
79
|
+
}
|
|
51
80
|
return calls.map((c, index) => {
|
|
81
|
+
const fail = (message) => ({
|
|
82
|
+
ok: false,
|
|
83
|
+
error: new RpcError(RpcErrorCode.InternalError, message),
|
|
84
|
+
});
|
|
52
85
|
const envelope = byId.get(index);
|
|
53
|
-
if (!envelope)
|
|
54
|
-
return {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
if (!envelope)
|
|
87
|
+
return fail(`No response for "${c.method}"`);
|
|
88
|
+
if (duplicated.has(index)) {
|
|
89
|
+
return fail(`More than one response carried id ${index}`);
|
|
90
|
+
}
|
|
91
|
+
if (envelope.jsonrpc !== "2.0") {
|
|
92
|
+
return fail(`Malformed JSON-RPC response for "${c.method}" (bad jsonrpc version)`);
|
|
93
|
+
}
|
|
94
|
+
const hasResult = "result" in envelope;
|
|
95
|
+
// §5: mutually exclusive. See the single-call path.
|
|
96
|
+
if (hasResult && envelope.error !== undefined) {
|
|
97
|
+
return fail(`Malformed JSON-RPC response for "${c.method}" (carries both result and error)`);
|
|
58
98
|
}
|
|
59
99
|
if (envelope.error !== undefined) {
|
|
60
100
|
return { ok: false, error: toRpcError(envelope.error) };
|
|
61
101
|
}
|
|
102
|
+
// A conformant success carries `result` — any JSON value, null
|
|
103
|
+
// included — so its absence is malformed, not an undefined value.
|
|
104
|
+
if (!hasResult) {
|
|
105
|
+
return fail(`JSON-RPC response for "${c.method}" has neither result nor error`);
|
|
106
|
+
}
|
|
62
107
|
const value = c.parse ? c.parse(envelope.result) : envelope.result;
|
|
63
108
|
return { ok: true, value };
|
|
64
109
|
});
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACN,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,GACV,MAAM,eAAe,CAAC;AAgEvB,MAAM,UAAU,eAAe,CAAC,OAAyB;IACxD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO;QACN,KAAK,CAAC,IAAI,CACT,MAAc,EACd,MAAgB,EAChB,WAA+B;YAE/B,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC;YACpB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE;gBAClE,MAAM,EAAE,WAAW,EAAE,MAAM;aAC3B,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE/C,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,SAAS,CAAC;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,SAAS,CAAC;CACd;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,EAAE,EAAE,SAAS,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX,uFAAuF;AACvF,qBAAa,QAAS,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBACZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAMzD;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAanD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,OAAO,GACV,GAAG,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAE5D;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,SAAS,GACX,cAAc,CAEhB;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,SAAS,GACX,sBAAsB,CAExB;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,SAAS,EACb,IAAI,CAAC,EAAE,OAAO,GACZ,oBAAoB,CAMtB;AAED,sCAAsC;AACtC,MAAM,MAAM,gBAAgB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,SAAS,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE/C,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,SAAS,CAAC;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,SAAS,CAAC;CACd;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,EAAE,EAAE,SAAS,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX,uFAAuF;AACvF,qBAAa,QAAS,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBACZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAMzD;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAanD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,OAAO,GACV,GAAG,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAE5D;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,SAAS,GACX,cAAc,CAEhB;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,SAAS,GACX,sBAAsB,CAExB;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,SAAS,EACb,IAAI,CAAC,EAAE,OAAO,GACZ,oBAAoB,CAMtB;AAED,sCAAsC;AACtC,MAAM,MAAM,gBAAgB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,SAAS,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAyC/D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CASxD"}
|
package/dist/protocol.js
CHANGED
|
@@ -91,9 +91,19 @@ export function parseRequest(request) {
|
|
|
91
91
|
? request.method
|
|
92
92
|
: undefined;
|
|
93
93
|
const params = "params" in request ? request.params : undefined;
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
94
|
+
const idPresent = "id" in request;
|
|
95
|
+
const rawId = idPresent ? request.id : undefined;
|
|
96
|
+
// When present, `id` MUST be a String, Number, or Null (JSON-RPC 2.0 §4). A
|
|
97
|
+
// present-but-wrongly-typed id (boolean/object/array) is an Invalid Request —
|
|
98
|
+
// NOT silently coerced to null, which would let a malformed envelope execute.
|
|
99
|
+
const idValid = !idPresent ||
|
|
100
|
+
rawId === null ||
|
|
101
|
+
typeof rawId === "string" ||
|
|
102
|
+
typeof rawId === "number";
|
|
103
|
+
const id = rawId === null || typeof rawId === "string" || typeof rawId === "number"
|
|
104
|
+
? rawId
|
|
105
|
+
: null;
|
|
106
|
+
if (jsonrpc !== "2.0" || !method || !idValid) {
|
|
97
107
|
return {
|
|
98
108
|
ok: false,
|
|
99
109
|
response: buildError(RpcErrorCode.InvalidRequest, "Invalid Request", id),
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/comet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Comet — agnostic JSON-RPC 2.0 protocol + isomorphic, transport-injectable client for the Ream framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@biomejs/biome": "^2.4.10",
|
|
24
25
|
"@types/node": "^22.19.15",
|
|
25
26
|
"typescript": "^6.0.2",
|
|
26
27
|
"vitest": "^4.1.2"
|
package/src/client.ts
CHANGED
|
@@ -95,13 +95,37 @@ export function createRpcClient(options: RpcClientOptions): RpcClient {
|
|
|
95
95
|
const res = await transport(url, buildRequest(method, params, id), {
|
|
96
96
|
signal: callOptions?.signal,
|
|
97
97
|
});
|
|
98
|
-
|
|
98
|
+
// Envelope conformance (JSON-RPC 2.0 §5): the version must match and the
|
|
99
|
+
// id MUST echo the one we sent — otherwise a stale, mis-routed, or
|
|
100
|
+
// forged response could satisfy the wrong call. Reject before trusting
|
|
101
|
+
// `result`.
|
|
102
|
+
if (!isObject(res) || res.jsonrpc !== "2.0" || res.id !== id) {
|
|
99
103
|
throw new RpcError(
|
|
100
104
|
RpcErrorCode.InternalError,
|
|
101
|
-
`Malformed JSON-RPC response for "${method}"`,
|
|
105
|
+
`Malformed or mismatched JSON-RPC response for "${method}" (bad jsonrpc/id envelope)`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
// §5: `result` and `error` are mutually exclusive — "Either the
|
|
109
|
+
// result member or error member MUST be included, but both members
|
|
110
|
+
// MUST NOT be included." A response carrying both is malformed, and
|
|
111
|
+
// reading the error out of it is guessing at which half the sender
|
|
112
|
+
// meant. Refused, the way a bad jsonrpc/id envelope already is.
|
|
113
|
+
const hasResult = "result" in res;
|
|
114
|
+
if (hasResult && res.error !== undefined) {
|
|
115
|
+
throw new RpcError(
|
|
116
|
+
RpcErrorCode.InternalError,
|
|
117
|
+
`Malformed JSON-RPC response for "${method}" (carries both result and error)`,
|
|
102
118
|
);
|
|
103
119
|
}
|
|
104
120
|
if (res.error !== undefined) throw toRpcError(res.error);
|
|
121
|
+
// A conformant success response carries `result` (any JSON value,
|
|
122
|
+
// including null) and no error — neither key present is malformed.
|
|
123
|
+
if (!hasResult) {
|
|
124
|
+
throw new RpcError(
|
|
125
|
+
RpcErrorCode.InternalError,
|
|
126
|
+
`JSON-RPC response for "${method}" has neither result nor error`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
105
129
|
// Result boundary — the same unchecked `T` assertion HTTP clients use,
|
|
106
130
|
// with `parse` as the cast-free, runtime-validated escape hatch.
|
|
107
131
|
return callOptions?.parse
|
|
@@ -127,22 +151,51 @@ export function createRpcClient(options: RpcClientOptions): RpcClient {
|
|
|
127
151
|
"Malformed JSON-RPC batch response",
|
|
128
152
|
);
|
|
129
153
|
}
|
|
154
|
+
// Envelope conformance, per item, exactly as `call` applies it — this
|
|
155
|
+
// checked none of it, so `{ jsonrpc: "1.0", id: 0 }` came back as
|
|
156
|
+
// `{ ok: true, value: undefined }` where the single-call path would
|
|
157
|
+
// have refused it.
|
|
130
158
|
const byId = new Map<unknown, Record<string, unknown>>();
|
|
131
|
-
|
|
159
|
+
const duplicated = new Set<unknown>();
|
|
160
|
+
for (const item of res) {
|
|
161
|
+
if (!isObject(item)) continue;
|
|
162
|
+
// A repeated id is a malformed batch, and silently keeping the last
|
|
163
|
+
// one lets a response answer a call it was not for.
|
|
164
|
+
if (byId.has(item.id)) duplicated.add(item.id);
|
|
165
|
+
byId.set(item.id, item);
|
|
166
|
+
}
|
|
132
167
|
return calls.map((c, index) => {
|
|
168
|
+
const fail = (message: string): RpcResult => ({
|
|
169
|
+
ok: false,
|
|
170
|
+
error: new RpcError(RpcErrorCode.InternalError, message),
|
|
171
|
+
});
|
|
133
172
|
const envelope = byId.get(index);
|
|
134
|
-
if (!envelope) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
141
|
-
|
|
173
|
+
if (!envelope) return fail(`No response for "${c.method}"`);
|
|
174
|
+
if (duplicated.has(index)) {
|
|
175
|
+
return fail(`More than one response carried id ${index}`);
|
|
176
|
+
}
|
|
177
|
+
if (envelope.jsonrpc !== "2.0") {
|
|
178
|
+
return fail(
|
|
179
|
+
`Malformed JSON-RPC response for "${c.method}" (bad jsonrpc version)`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const hasResult = "result" in envelope;
|
|
183
|
+
// §5: mutually exclusive. See the single-call path.
|
|
184
|
+
if (hasResult && envelope.error !== undefined) {
|
|
185
|
+
return fail(
|
|
186
|
+
`Malformed JSON-RPC response for "${c.method}" (carries both result and error)`,
|
|
187
|
+
);
|
|
142
188
|
}
|
|
143
189
|
if (envelope.error !== undefined) {
|
|
144
190
|
return { ok: false, error: toRpcError(envelope.error) };
|
|
145
191
|
}
|
|
192
|
+
// A conformant success carries `result` — any JSON value, null
|
|
193
|
+
// included — so its absence is malformed, not an undefined value.
|
|
194
|
+
if (!hasResult) {
|
|
195
|
+
return fail(
|
|
196
|
+
`JSON-RPC response for "${c.method}" has neither result nor error`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
146
199
|
const value = c.parse ? c.parse(envelope.result) : envelope.result;
|
|
147
200
|
return { ok: true, value };
|
|
148
201
|
});
|
package/src/protocol.ts
CHANGED
|
@@ -166,10 +166,21 @@ export function parseRequest(request: unknown): ParsedRpcRequest {
|
|
|
166
166
|
? request.method
|
|
167
167
|
: undefined;
|
|
168
168
|
const params = "params" in request ? request.params : undefined;
|
|
169
|
-
const
|
|
169
|
+
const idPresent = "id" in request;
|
|
170
|
+
const rawId = idPresent ? request.id : undefined;
|
|
171
|
+
// When present, `id` MUST be a String, Number, or Null (JSON-RPC 2.0 §4). A
|
|
172
|
+
// present-but-wrongly-typed id (boolean/object/array) is an Invalid Request —
|
|
173
|
+
// NOT silently coerced to null, which would let a malformed envelope execute.
|
|
174
|
+
const idValid =
|
|
175
|
+
!idPresent ||
|
|
176
|
+
rawId === null ||
|
|
177
|
+
typeof rawId === "string" ||
|
|
178
|
+
typeof rawId === "number";
|
|
170
179
|
const id: JsonRpcId =
|
|
171
|
-
typeof rawId === "string" || typeof rawId === "number"
|
|
172
|
-
|
|
180
|
+
rawId === null || typeof rawId === "string" || typeof rawId === "number"
|
|
181
|
+
? rawId
|
|
182
|
+
: null;
|
|
183
|
+
if (jsonrpc !== "2.0" || !method || !idValid) {
|
|
173
184
|
return {
|
|
174
185
|
ok: false,
|
|
175
186
|
response: buildError(RpcErrorCode.InvalidRequest, "Invalid Request", id),
|