@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.
@@ -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,CAoEpE"}
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
- if (!isObject(res)) {
25
- throw new RpcError(RpcErrorCode.InternalError, `Malformed JSON-RPC response for "${method}"`);
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
- for (const item of res)
49
- if (isObject(item))
50
- byId.set(item.id, item);
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
- ok: false,
56
- error: new RpcError(RpcErrorCode.InternalError, `No response for "${c.method}"`),
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
  });
@@ -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;gBACpB,MAAM,IAAI,QAAQ,CACjB,YAAY,CAAC,aAAa,EAC1B,oCAAoC,MAAM,GAAG,CAC7C,CAAC;YACH,CAAC;YACD,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;gBAAE,MAAM,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACzD,uEAAuE;YACvE,iEAAiE;YACjE,OAAO,WAAW,EAAE,KAAK;gBACxB,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC/B,CAAC,CAAE,GAAG,CAAC,MAAY,CAAC;QACtB,CAAC;QAED,KAAK,CAAC,KAAK,CACV,KAAgB,EAChB,YAAuC;YAEvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;YACvC,6DAA6D;YAC7D,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CACvC,CAAC;YACF,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE;gBAC1C,MAAM,EAAE,YAAY,EAAE,MAAM;aAC5B,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,QAAQ,CACjB,YAAY,CAAC,aAAa,EAC1B,mCAAmC,CACnC,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoC,CAAC;YACzD,KAAK,MAAM,IAAI,IAAI,GAAG;gBAAE,IAAI,QAAQ,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACpE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;gBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACf,OAAO;wBACN,EAAE,EAAE,KAAK;wBACT,KAAK,EAAE,IAAI,QAAQ,CAClB,YAAY,CAAC,aAAa,EAC1B,oBAAoB,CAAC,CAAC,MAAM,GAAG,CAC/B;qBACD,CAAC;gBACH,CAAC;gBACD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAClC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzD,CAAC;gBACD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACnE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;QACJ,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -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,CA8B/D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CASxD"}
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 rawId = "id" in request ? request.id : undefined;
95
- const id = typeof rawId === "string" || typeof rawId === "number" ? rawId : null;
96
- if (jsonrpc !== "2.0" || !method) {
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),
@@ -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.0",
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
- if (!isObject(res)) {
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
- for (const item of res) if (isObject(item)) byId.set(item.id, item);
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
- return {
136
- ok: false,
137
- error: new RpcError(
138
- RpcErrorCode.InternalError,
139
- `No response for "${c.method}"`,
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 rawId = "id" in request ? request.id : undefined;
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" ? rawId : null;
172
- if (jsonrpc !== "2.0" || !method) {
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),