@brightbeamai/chap-coordinator 0.2.10 → 0.2.13

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/patch.cjs CHANGED
@@ -28,6 +28,11 @@ module.exports = __toCommonJS(patch_exports);
28
28
  var PatchError = class extends Error {
29
29
  };
30
30
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
31
+ var ARRAY_INDEX_RE = /^(0|[1-9][0-9]*)$/;
32
+ function arrayIndex(seg) {
33
+ if (!ARRAY_INDEX_RE.test(seg)) throw new PatchError(`Array index expected at ${JSON.stringify(seg)}`);
34
+ return Number(seg);
35
+ }
31
36
  function unescape(token) {
32
37
  return token.replace(/~1/g, "/").replace(/~0/g, "~");
33
38
  }
@@ -52,8 +57,8 @@ function navigate(doc, parts) {
52
57
  for (let i = 0; i < parts.length - 1; i++) {
53
58
  const part = parts[i];
54
59
  if (Array.isArray(parent)) {
55
- const idx = Number(part);
56
- if (!Number.isInteger(idx) || idx < 0 || idx >= parent.length) {
60
+ const idx = arrayIndex(part);
61
+ if (idx >= parent.length) {
57
62
  throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join("/")}`);
58
63
  }
59
64
  parent = parent[idx];
@@ -69,11 +74,7 @@ function navigate(doc, parts) {
69
74
  const last = parts[parts.length - 1];
70
75
  if (Array.isArray(parent)) {
71
76
  if (last === "-") return [parent, "-"];
72
- const idx = Number(last);
73
- if (!Number.isInteger(idx)) {
74
- throw new PatchError(`Array index expected at ${JSON.stringify(last)}`);
75
- }
76
- return [parent, idx];
77
+ return [parent, arrayIndex(last)];
77
78
  }
78
79
  return [parent, last];
79
80
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/patch.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator/patch\n *\n * RFC 6902 JSON Patch implementation, plus a small diff computer that\n * produces a patch from two values. Used by the Coordinator for\n * `decide.override` apply and by the playground UI (in the browser) to\n * compute the patch from a textarea edit.\n *\n * Implements all six RFC 6902 operations (add, remove, replace, move,\n * copy, test) with semantics identical to the Python reference. Path\n * segments that enable prototype pollution in a JavaScript runtime\n * (`__proto__`, `constructor`, `prototype`) are rejected, so the two\n * references accept and reject exactly the same patches.\n */\n\nimport type { JsonPatchOp } from \"./types.js\";\n\nexport class PatchError extends Error {}\n\n// Rejected in every JSON Pointer segment: these enable prototype pollution.\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction unescape(token: string): string {\n return token.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n}\n\nfunction splitPath(path: string): string[] {\n if (path === \"\") return [];\n if (!path.startsWith(\"/\")) {\n throw new PatchError(`JSON Pointer must start with '/': ${JSON.stringify(path)}`);\n }\n const segments = path.slice(1).split(\"/\").map(unescape);\n for (const seg of segments) {\n if (DANGEROUS_KEYS.has(seg)) {\n throw new PatchError(`Refusing unsafe path segment ${JSON.stringify(seg)}`);\n }\n }\n return segments;\n}\n\n/** Navigate to the parent of the target; return [parent, lastKey]. */\nfunction navigate(doc: any, parts: string[]): [any, string | number] {\n if (parts.length === 0) {\n throw new PatchError(\"Cannot operate on root with this helper.\");\n }\n let parent = doc;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (Array.isArray(parent)) {\n const idx = Number(part);\n if (!Number.isInteger(idx) || idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[idx];\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, part)) {\n throw new PatchError(`Path not found: /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[part];\n } else {\n throw new PatchError(`Cannot traverse into ${typeof parent} at ${JSON.stringify(part)}`);\n }\n }\n const last = parts[parts.length - 1];\n if (Array.isArray(parent)) {\n if (last === \"-\") return [parent, \"-\"];\n const idx = Number(last);\n if (!Number.isInteger(idx)) {\n throw new PatchError(`Array index expected at ${JSON.stringify(last)}`);\n }\n return [parent, idx];\n }\n return [parent, last];\n}\n\nfunction getAt(doc: any, path: string): any {\n const parts = splitPath(path);\n if (parts.length === 0) return doc;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") throw new PatchError(\"Cannot read '-' position.\");\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) throw new PatchError(`Index out of range: ${path}`);\n return parent[idx];\n }\n if (\n parent === null ||\n typeof parent !== \"object\" ||\n !Object.prototype.hasOwnProperty.call(parent, key)\n ) {\n throw new PatchError(`Path not found: ${path}`);\n }\n return parent[key as string];\n}\n\nfunction clone<T>(v: T): T {\n return v === undefined ? v : (JSON.parse(JSON.stringify(v)) as T);\n}\n\nfunction deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== \"object\") return a === b;\n const aArr = Array.isArray(a);\n if (aArr !== Array.isArray(b)) return false;\n if (aArr) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.prototype.hasOwnProperty.call(b, k)) return false;\n if (!deepEqual(a[k], b[k])) return false;\n }\n return true;\n}\n\nfunction applyOne(doc: any, op: JsonPatchOp): any {\n const kind = op.op;\n const path = op.path ?? \"\";\n\n if (kind === \"add\") {\n if (!(\"value\" in op)) throw new PatchError(\"'add' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value; // replace whole document\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") {\n parent.push(op.value);\n } else {\n const idx = key as number;\n if (idx < 0 || idx > parent.length) {\n throw new PatchError(`Index out of range for add: ${path}`);\n }\n parent.splice(idx, 0, op.value);\n }\n } else if (parent !== null && typeof parent === \"object\") {\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot add into ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"replace\") {\n if (!(\"value\" in op)) throw new PatchError(\"'replace' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[idx] = op.value;\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot replace in ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"remove\") {\n const parts = splitPath(path);\n if (parts.length === 0) throw new PatchError(\"Cannot remove root.\");\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range for remove: ${path}`);\n }\n parent.splice(idx, 1);\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for remove: ${path}`);\n }\n delete parent[key as string];\n } else {\n throw new PatchError(`Cannot remove from ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"copy\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'copy' requires 'from'\");\n const value = clone(getAt(doc, src));\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"move\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'move' requires 'from'\");\n // RFC 6902 4.4: 'from' MUST NOT be a proper prefix of 'path'.\n if (path.startsWith(src + \"/\")) {\n throw new PatchError(\"'move' cannot move a location into its own child.\");\n }\n const value = clone(getAt(doc, src));\n doc = applyOne(doc, { op: \"remove\", path: src });\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"test\") {\n if (!(\"value\" in op)) throw new PatchError(\"'test' requires 'value'\");\n const actual = getAt(doc, path);\n if (!deepEqual(actual, op.value)) throw new PatchError(`'test' failed at ${path}`);\n return doc;\n }\n\n throw new PatchError(`Unsupported op: ${JSON.stringify(kind)}`);\n}\n\nconst MAX_PATCH_OPS = 1000;\nconst MAX_DOCUMENT_NODES = 100_000;\n\nfunction nodeCount(value: unknown): number {\n if (Array.isArray(value)) {\n let n = 1;\n for (const v of value) n += nodeCount(v);\n return n;\n }\n if (value !== null && typeof value === \"object\") {\n let n = 1;\n for (const v of Object.values(value as Record<string, unknown>)) n += nodeCount(v);\n return n;\n }\n return 1;\n}\n\nexport function applyJsonPatch(doc: unknown, ops: JsonPatchOp[]): unknown {\n if (ops.length > MAX_PATCH_OPS) {\n throw new PatchError(`Patch has too many operations (${ops.length} > ${MAX_PATCH_OPS})`);\n }\n let out: any = JSON.parse(JSON.stringify(doc));\n for (const op of ops) {\n out = applyOne(out, op);\n if (nodeCount(out) > MAX_DOCUMENT_NODES) {\n throw new PatchError(`Patched document exceeds the node limit (${MAX_DOCUMENT_NODES})`);\n }\n }\n return out;\n}\n\n// ============================================================\n// diff: produce a patch that transforms `from` into `to`\n// ============================================================\n\n/**\n * Compute an RFC 6902 patch that, when applied to `from`, produces\n * `to`. Walks objects key-by-key; arrays use a shallow whole-array\n * replace if any element differs. Sufficient for the playground's\n * draft-edit use case where drafts are small JSON objects.\n */\nexport function diffJsonPatch(from: unknown, to: unknown, basePath = \"\"): JsonPatchOp[] {\n const ops: JsonPatchOp[] = [];\n\n if (typeof from !== typeof to || Array.isArray(from) !== Array.isArray(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n return ops;\n }\n\n if (from === null || to === null || typeof from !== \"object\") {\n if (from !== to) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n if (Array.isArray(from) && Array.isArray(to)) {\n if (JSON.stringify(from) !== JSON.stringify(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n const fromObj = from as Record<string, unknown>;\n const toObj = to as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(fromObj), ...Object.keys(toObj)]);\n\n for (const key of allKeys) {\n const escaped = key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n const path = `${basePath}/${escaped}`;\n if (!(key in fromObj)) {\n ops.push({ op: \"add\", path, value: toObj[key] });\n } else if (!(key in toObj)) {\n ops.push({ op: \"remove\", path });\n } else {\n ops.push(...diffJsonPatch(fromObj[key], toObj[key], path));\n }\n }\n\n return ops;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/patch.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator/patch\n *\n * RFC 6902 JSON Patch implementation, plus a small diff computer that\n * produces a patch from two values. Used by the Coordinator for\n * `decide.override` apply and by the playground UI (in the browser) to\n * compute the patch from a textarea edit.\n *\n * Implements all six RFC 6902 operations (add, remove, replace, move,\n * copy, test) with semantics identical to the Python reference. Path\n * segments that enable prototype pollution in a JavaScript runtime\n * (`__proto__`, `constructor`, `prototype`) are rejected, so the two\n * references accept and reject exactly the same patches.\n */\n\nimport type { JsonPatchOp } from \"./types.js\";\n\nexport class PatchError extends Error {}\n\n// Rejected in every JSON Pointer segment: these enable prototype pollution.\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n// An array index is an RFC 6901 array index: \"0\" or a positive integer with no\n// leading zero. A shared strict rule keeps the two references in step -- JS\n// Number() and Python int() otherwise accept disjoint token sets (e.g. \"1e1\",\n// \"0x0a\", \"3.0\", \"\", \"1_0\"), which would apply the same patch differently.\nconst ARRAY_INDEX_RE = /^(0|[1-9][0-9]*)$/;\n\nfunction arrayIndex(seg: string): number {\n if (!ARRAY_INDEX_RE.test(seg)) throw new PatchError(`Array index expected at ${JSON.stringify(seg)}`);\n return Number(seg);\n}\n\nfunction unescape(token: string): string {\n return token.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n}\n\nfunction splitPath(path: string): string[] {\n if (path === \"\") return [];\n if (!path.startsWith(\"/\")) {\n throw new PatchError(`JSON Pointer must start with '/': ${JSON.stringify(path)}`);\n }\n const segments = path.slice(1).split(\"/\").map(unescape);\n for (const seg of segments) {\n if (DANGEROUS_KEYS.has(seg)) {\n throw new PatchError(`Refusing unsafe path segment ${JSON.stringify(seg)}`);\n }\n }\n return segments;\n}\n\n/** Navigate to the parent of the target; return [parent, lastKey]. */\nfunction navigate(doc: any, parts: string[]): [any, string | number] {\n if (parts.length === 0) {\n throw new PatchError(\"Cannot operate on root with this helper.\");\n }\n let parent = doc;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (Array.isArray(parent)) {\n const idx = arrayIndex(part);\n if (idx >= parent.length) {\n throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[idx];\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, part)) {\n throw new PatchError(`Path not found: /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[part];\n } else {\n throw new PatchError(`Cannot traverse into ${typeof parent} at ${JSON.stringify(part)}`);\n }\n }\n const last = parts[parts.length - 1];\n if (Array.isArray(parent)) {\n if (last === \"-\") return [parent, \"-\"];\n return [parent, arrayIndex(last)];\n }\n return [parent, last];\n}\n\nfunction getAt(doc: any, path: string): any {\n const parts = splitPath(path);\n if (parts.length === 0) return doc;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") throw new PatchError(\"Cannot read '-' position.\");\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) throw new PatchError(`Index out of range: ${path}`);\n return parent[idx];\n }\n if (\n parent === null ||\n typeof parent !== \"object\" ||\n !Object.prototype.hasOwnProperty.call(parent, key)\n ) {\n throw new PatchError(`Path not found: ${path}`);\n }\n return parent[key as string];\n}\n\nfunction clone<T>(v: T): T {\n return v === undefined ? v : (JSON.parse(JSON.stringify(v)) as T);\n}\n\nfunction deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== \"object\") return a === b;\n const aArr = Array.isArray(a);\n if (aArr !== Array.isArray(b)) return false;\n if (aArr) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.prototype.hasOwnProperty.call(b, k)) return false;\n if (!deepEqual(a[k], b[k])) return false;\n }\n return true;\n}\n\nfunction applyOne(doc: any, op: JsonPatchOp): any {\n const kind = op.op;\n const path = op.path ?? \"\";\n\n if (kind === \"add\") {\n if (!(\"value\" in op)) throw new PatchError(\"'add' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value; // replace whole document\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") {\n parent.push(op.value);\n } else {\n const idx = key as number;\n if (idx < 0 || idx > parent.length) {\n throw new PatchError(`Index out of range for add: ${path}`);\n }\n parent.splice(idx, 0, op.value);\n }\n } else if (parent !== null && typeof parent === \"object\") {\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot add into ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"replace\") {\n if (!(\"value\" in op)) throw new PatchError(\"'replace' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[idx] = op.value;\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot replace in ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"remove\") {\n const parts = splitPath(path);\n if (parts.length === 0) throw new PatchError(\"Cannot remove root.\");\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range for remove: ${path}`);\n }\n parent.splice(idx, 1);\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for remove: ${path}`);\n }\n delete parent[key as string];\n } else {\n throw new PatchError(`Cannot remove from ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"copy\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'copy' requires 'from'\");\n const value = clone(getAt(doc, src));\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"move\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'move' requires 'from'\");\n // RFC 6902 4.4: 'from' MUST NOT be a proper prefix of 'path'.\n if (path.startsWith(src + \"/\")) {\n throw new PatchError(\"'move' cannot move a location into its own child.\");\n }\n const value = clone(getAt(doc, src));\n doc = applyOne(doc, { op: \"remove\", path: src });\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"test\") {\n if (!(\"value\" in op)) throw new PatchError(\"'test' requires 'value'\");\n const actual = getAt(doc, path);\n if (!deepEqual(actual, op.value)) throw new PatchError(`'test' failed at ${path}`);\n return doc;\n }\n\n throw new PatchError(`Unsupported op: ${JSON.stringify(kind)}`);\n}\n\nconst MAX_PATCH_OPS = 1000;\nconst MAX_DOCUMENT_NODES = 100_000;\n\nfunction nodeCount(value: unknown): number {\n if (Array.isArray(value)) {\n let n = 1;\n for (const v of value) n += nodeCount(v);\n return n;\n }\n if (value !== null && typeof value === \"object\") {\n let n = 1;\n for (const v of Object.values(value as Record<string, unknown>)) n += nodeCount(v);\n return n;\n }\n return 1;\n}\n\nexport function applyJsonPatch(doc: unknown, ops: JsonPatchOp[]): unknown {\n if (ops.length > MAX_PATCH_OPS) {\n throw new PatchError(`Patch has too many operations (${ops.length} > ${MAX_PATCH_OPS})`);\n }\n let out: any = JSON.parse(JSON.stringify(doc));\n for (const op of ops) {\n out = applyOne(out, op);\n if (nodeCount(out) > MAX_DOCUMENT_NODES) {\n throw new PatchError(`Patched document exceeds the node limit (${MAX_DOCUMENT_NODES})`);\n }\n }\n return out;\n}\n\n// ============================================================\n// diff: produce a patch that transforms `from` into `to`\n// ============================================================\n\n/**\n * Compute an RFC 6902 patch that, when applied to `from`, produces\n * `to`. Walks objects key-by-key; arrays use a shallow whole-array\n * replace if any element differs. Sufficient for the playground's\n * draft-edit use case where drafts are small JSON objects.\n */\nexport function diffJsonPatch(from: unknown, to: unknown, basePath = \"\"): JsonPatchOp[] {\n const ops: JsonPatchOp[] = [];\n\n if (typeof from !== typeof to || Array.isArray(from) !== Array.isArray(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n return ops;\n }\n\n if (from === null || to === null || typeof from !== \"object\") {\n if (from !== to) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n if (Array.isArray(from) && Array.isArray(to)) {\n if (JSON.stringify(from) !== JSON.stringify(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n const fromObj = from as Record<string, unknown>;\n const toObj = to as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(fromObj), ...Object.keys(toObj)]);\n\n for (const key of allKeys) {\n const escaped = key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n const path = `${basePath}/${escaped}`;\n if (!(key in fromObj)) {\n ops.push({ op: \"add\", path, value: toObj[key] });\n } else if (!(key in toObj)) {\n ops.push({ op: \"remove\", path });\n } else {\n ops.push(...diffJsonPatch(fromObj[key], toObj[key], path));\n }\n }\n\n return ops;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBO,IAAM,aAAN,cAAyB,MAAM;AAAC;AAGvC,IAAM,iBAAiB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AAMxE,IAAM,iBAAiB;AAEvB,SAAS,WAAW,KAAqB;AACvC,MAAI,CAAC,eAAe,KAAK,GAAG,EAAG,OAAM,IAAI,WAAW,2BAA2B,KAAK,UAAU,GAAG,CAAC,EAAE;AACpG,SAAO,OAAO,GAAG;AACnB;AAEA,SAAS,SAAS,OAAuB;AACvC,SAAO,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG;AACrD;AAEA,SAAS,UAAU,MAAwB;AACzC,MAAI,SAAS,GAAI,QAAO,CAAC;AACzB,MAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,UAAM,IAAI,WAAW,qCAAqC,KAAK,UAAU,IAAI,CAAC,EAAE;AAAA,EAClF;AACA,QAAM,WAAW,KAAK,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,QAAQ;AACtD,aAAW,OAAO,UAAU;AAC1B,QAAI,eAAe,IAAI,GAAG,GAAG;AAC3B,YAAM,IAAI,WAAW,gCAAgC,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,IAC5E;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,SAAS,KAAU,OAAyC;AACnE,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,WAAW,0CAA0C;AAAA,EACjE;AACA,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,YAAM,MAAM,WAAW,IAAI;AAC3B,UAAI,OAAO,OAAO,QAAQ;AACxB,cAAM,IAAI,WAAW,0BAA0B,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE;AAAA,MAClF;AACA,eAAS,OAAO,GAAG;AAAA,IACrB,WAAW,WAAW,QAAQ,OAAO,WAAW,UAAU;AACxD,UAAI,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,IAAI,GAAG;AACvD,cAAM,IAAI,WAAW,oBAAoB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE;AAAA,MAC5E;AACA,eAAS,OAAO,IAAI;AAAA,IACtB,OAAO;AACL,YAAM,IAAI,WAAW,wBAAwB,OAAO,MAAM,OAAO,KAAK,UAAU,IAAI,CAAC,EAAE;AAAA,IACzF;AAAA,EACF;AACA,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,QAAI,SAAS,IAAK,QAAO,CAAC,QAAQ,GAAG;AACrC,WAAO,CAAC,QAAQ,WAAW,IAAI,CAAC;AAAA,EAClC;AACA,SAAO,CAAC,QAAQ,IAAI;AACtB;AAEA,SAAS,MAAM,KAAU,MAAmB;AAC1C,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,CAAC,QAAQ,GAAG,IAAI,SAAS,KAAK,KAAK;AACzC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,QAAI,QAAQ,IAAK,OAAM,IAAI,WAAW,2BAA2B;AACjE,UAAM,MAAM;AACZ,QAAI,MAAM,KAAK,OAAO,OAAO,OAAQ,OAAM,IAAI,WAAW,uBAAuB,IAAI,EAAE;AACvF,WAAO,OAAO,GAAG;AAAA,EACnB;AACA,MACE,WAAW,QACX,OAAO,WAAW,YAClB,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GACjD;AACA,UAAM,IAAI,WAAW,mBAAmB,IAAI,EAAE;AAAA,EAChD;AACA,SAAO,OAAO,GAAa;AAC7B;AAEA,SAAS,MAAS,GAAS;AACzB,SAAO,MAAM,SAAY,IAAK,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC;AAC5D;AAEA,SAAS,UAAU,GAAQ,GAAiB;AAC1C,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,MAAM,QAAQ,MAAM,KAAM,QAAO,MAAM;AAC3C,MAAI,OAAO,MAAM,OAAO,EAAG,QAAO;AAClC,MAAI,OAAO,MAAM,SAAU,QAAO,MAAM;AACxC,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,MAAI,SAAS,MAAM,QAAQ,CAAC,EAAG,QAAO;AACtC,MAAI,MAAM;AACR,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAI,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAG,QAAO;AACtE,WAAO;AAAA,EACT;AACA,QAAM,KAAK,OAAO,KAAK,CAAC;AACxB,QAAM,KAAK,OAAO,KAAK,CAAC;AACxB,MAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,aAAW,KAAK,IAAI;AAClB,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,CAAC,EAAG,QAAO;AACxD,QAAI,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAG,QAAO;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,SAAS,KAAU,IAAsB;AAChD,QAAM,OAAO,GAAG;AAChB,QAAM,OAAO,GAAG,QAAQ;AAExB,MAAI,SAAS,OAAO;AAClB,QAAI,EAAE,WAAW,IAAK,OAAM,IAAI,WAAW,wBAAwB;AACnE,UAAM,QAAQ,UAAU,IAAI;AAC5B,QAAI,MAAM,WAAW,EAAG,QAAO,GAAG;AAClC,UAAM,CAAC,QAAQ,GAAG,IAAI,SAAS,KAAK,KAAK;AACzC,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,UAAI,QAAQ,KAAK;AACf,eAAO,KAAK,GAAG,KAAK;AAAA,MACtB,OAAO;AACL,cAAM,MAAM;AACZ,YAAI,MAAM,KAAK,MAAM,OAAO,QAAQ;AAClC,gBAAM,IAAI,WAAW,+BAA+B,IAAI,EAAE;AAAA,QAC5D;AACA,eAAO,OAAO,KAAK,GAAG,GAAG,KAAK;AAAA,MAChC;AAAA,IACF,WAAW,WAAW,QAAQ,OAAO,WAAW,UAAU;AACxD,aAAO,GAAa,IAAI,GAAG;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,WAAW,mBAAmB,OAAO,MAAM,EAAE;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW;AACtB,QAAI,EAAE,WAAW,IAAK,OAAM,IAAI,WAAW,4BAA4B;AACvE,UAAM,QAAQ,UAAU,IAAI;AAC5B,QAAI,MAAM,WAAW,EAAG,QAAO,GAAG;AAClC,UAAM,CAAC,QAAQ,GAAG,IAAI,SAAS,KAAK,KAAK;AACzC,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,YAAM,MAAM;AACZ,UAAI,MAAM,KAAK,OAAO,OAAO,QAAQ;AACnC,cAAM,IAAI,WAAW,+BAA+B,IAAI,EAAE;AAAA,MAC5D;AACA,aAAO,GAAG,IAAI,GAAG;AAAA,IACnB,WAAW,WAAW,QAAQ,OAAO,WAAW,UAAU;AACxD,UAAI,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AACtD,cAAM,IAAI,WAAW,+BAA+B,IAAI,EAAE;AAAA,MAC5D;AACA,aAAO,GAAa,IAAI,GAAG;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,WAAW,qBAAqB,OAAO,MAAM,EAAE;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,UAAU;AACrB,UAAM,QAAQ,UAAU,IAAI;AAC5B,QAAI,MAAM,WAAW,EAAG,OAAM,IAAI,WAAW,qBAAqB;AAClE,UAAM,CAAC,QAAQ,GAAG,IAAI,SAAS,KAAK,KAAK;AACzC,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,YAAM,MAAM;AACZ,UAAI,MAAM,KAAK,OAAO,OAAO,QAAQ;AACnC,cAAM,IAAI,WAAW,kCAAkC,IAAI,EAAE;AAAA,MAC/D;AACA,aAAO,OAAO,KAAK,CAAC;AAAA,IACtB,WAAW,WAAW,QAAQ,OAAO,WAAW,UAAU;AACxD,UAAI,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AACtD,cAAM,IAAI,WAAW,8BAA8B,IAAI,EAAE;AAAA,MAC3D;AACA,aAAO,OAAO,GAAa;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,WAAW,sBAAsB,OAAO,MAAM,EAAE;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,QAAQ;AACnB,UAAM,MAAM,GAAG;AACf,QAAI,QAAQ,OAAW,OAAM,IAAI,WAAW,wBAAwB;AACpE,UAAM,QAAQ,MAAM,MAAM,KAAK,GAAG,CAAC;AACnC,WAAO,SAAS,KAAK,EAAE,IAAI,OAAO,MAAM,MAAM,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,QAAQ;AACnB,UAAM,MAAM,GAAG;AACf,QAAI,QAAQ,OAAW,OAAM,IAAI,WAAW,wBAAwB;AAEpE,QAAI,KAAK,WAAW,MAAM,GAAG,GAAG;AAC9B,YAAM,IAAI,WAAW,mDAAmD;AAAA,IAC1E;AACA,UAAM,QAAQ,MAAM,MAAM,KAAK,GAAG,CAAC;AACnC,UAAM,SAAS,KAAK,EAAE,IAAI,UAAU,MAAM,IAAI,CAAC;AAC/C,WAAO,SAAS,KAAK,EAAE,IAAI,OAAO,MAAM,MAAM,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,QAAQ;AACnB,QAAI,EAAE,WAAW,IAAK,OAAM,IAAI,WAAW,yBAAyB;AACpE,UAAM,SAAS,MAAM,KAAK,IAAI;AAC9B,QAAI,CAAC,UAAU,QAAQ,GAAG,KAAK,EAAG,OAAM,IAAI,WAAW,oBAAoB,IAAI,EAAE;AACjF,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,WAAW,mBAAmB,KAAK,UAAU,IAAI,CAAC,EAAE;AAChE;AAEA,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAE3B,SAAS,UAAU,OAAwB;AACzC,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,QAAI,IAAI;AACR,eAAW,KAAK,MAAO,MAAK,UAAU,CAAC;AACvC,WAAO;AAAA,EACT;AACA,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,QAAI,IAAI;AACR,eAAW,KAAK,OAAO,OAAO,KAAgC,EAAG,MAAK,UAAU,CAAC;AACjF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,eAAe,KAAc,KAA6B;AACxE,MAAI,IAAI,SAAS,eAAe;AAC9B,UAAM,IAAI,WAAW,kCAAkC,IAAI,MAAM,MAAM,aAAa,GAAG;AAAA,EACzF;AACA,MAAI,MAAW,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AAC7C,aAAW,MAAM,KAAK;AACpB,UAAM,SAAS,KAAK,EAAE;AACtB,QAAI,UAAU,GAAG,IAAI,oBAAoB;AACvC,YAAM,IAAI,WAAW,4CAA4C,kBAAkB,GAAG;AAAA,IACxF;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,cAAc,MAAe,IAAa,WAAW,IAAmB;AACtF,QAAM,MAAqB,CAAC;AAE5B,MAAI,OAAO,SAAS,OAAO,MAAM,MAAM,QAAQ,IAAI,MAAM,MAAM,QAAQ,EAAE,GAAG;AAC1E,QAAI,KAAK,EAAE,IAAI,WAAW,MAAM,YAAY,KAAK,OAAO,GAAG,CAAC;AAC5D,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,QAAQ,OAAO,QAAQ,OAAO,SAAS,UAAU;AAC5D,QAAI,SAAS,IAAI;AACf,UAAI,KAAK,EAAE,IAAI,WAAW,MAAM,YAAY,KAAK,OAAO,GAAG,CAAC;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,EAAE,GAAG;AAC5C,QAAI,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,EAAE,GAAG;AAC/C,UAAI,KAAK,EAAE,IAAI,WAAW,MAAM,YAAY,KAAK,OAAO,GAAG,CAAC;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,QAAM,QAAQ;AACd,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,OAAO,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC;AAExE,aAAW,OAAO,SAAS;AACzB,UAAM,UAAU,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,OAAO,IAAI;AAC3D,UAAM,OAAO,GAAG,QAAQ,IAAI,OAAO;AACnC,QAAI,EAAE,OAAO,UAAU;AACrB,UAAI,KAAK,EAAE,IAAI,OAAO,MAAM,OAAO,MAAM,GAAG,EAAE,CAAC;AAAA,IACjD,WAAW,EAAE,OAAO,QAAQ;AAC1B,UAAI,KAAK,EAAE,IAAI,UAAU,KAAK,CAAC;AAAA,IACjC,OAAO;AACL,UAAI,KAAK,GAAG,cAAc,QAAQ,GAAG,GAAG,MAAM,GAAG,GAAG,IAAI,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
package/dist/patch.js CHANGED
@@ -2,6 +2,11 @@
2
2
  var PatchError = class extends Error {
3
3
  };
4
4
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
5
+ var ARRAY_INDEX_RE = /^(0|[1-9][0-9]*)$/;
6
+ function arrayIndex(seg) {
7
+ if (!ARRAY_INDEX_RE.test(seg)) throw new PatchError(`Array index expected at ${JSON.stringify(seg)}`);
8
+ return Number(seg);
9
+ }
5
10
  function unescape(token) {
6
11
  return token.replace(/~1/g, "/").replace(/~0/g, "~");
7
12
  }
@@ -26,8 +31,8 @@ function navigate(doc, parts) {
26
31
  for (let i = 0; i < parts.length - 1; i++) {
27
32
  const part = parts[i];
28
33
  if (Array.isArray(parent)) {
29
- const idx = Number(part);
30
- if (!Number.isInteger(idx) || idx < 0 || idx >= parent.length) {
34
+ const idx = arrayIndex(part);
35
+ if (idx >= parent.length) {
31
36
  throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join("/")}`);
32
37
  }
33
38
  parent = parent[idx];
@@ -43,11 +48,7 @@ function navigate(doc, parts) {
43
48
  const last = parts[parts.length - 1];
44
49
  if (Array.isArray(parent)) {
45
50
  if (last === "-") return [parent, "-"];
46
- const idx = Number(last);
47
- if (!Number.isInteger(idx)) {
48
- throw new PatchError(`Array index expected at ${JSON.stringify(last)}`);
49
- }
50
- return [parent, idx];
51
+ return [parent, arrayIndex(last)];
51
52
  }
52
53
  return [parent, last];
53
54
  }
package/dist/patch.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/patch.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator/patch\n *\n * RFC 6902 JSON Patch implementation, plus a small diff computer that\n * produces a patch from two values. Used by the Coordinator for\n * `decide.override` apply and by the playground UI (in the browser) to\n * compute the patch from a textarea edit.\n *\n * Implements all six RFC 6902 operations (add, remove, replace, move,\n * copy, test) with semantics identical to the Python reference. Path\n * segments that enable prototype pollution in a JavaScript runtime\n * (`__proto__`, `constructor`, `prototype`) are rejected, so the two\n * references accept and reject exactly the same patches.\n */\n\nimport type { JsonPatchOp } from \"./types.js\";\n\nexport class PatchError extends Error {}\n\n// Rejected in every JSON Pointer segment: these enable prototype pollution.\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction unescape(token: string): string {\n return token.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n}\n\nfunction splitPath(path: string): string[] {\n if (path === \"\") return [];\n if (!path.startsWith(\"/\")) {\n throw new PatchError(`JSON Pointer must start with '/': ${JSON.stringify(path)}`);\n }\n const segments = path.slice(1).split(\"/\").map(unescape);\n for (const seg of segments) {\n if (DANGEROUS_KEYS.has(seg)) {\n throw new PatchError(`Refusing unsafe path segment ${JSON.stringify(seg)}`);\n }\n }\n return segments;\n}\n\n/** Navigate to the parent of the target; return [parent, lastKey]. */\nfunction navigate(doc: any, parts: string[]): [any, string | number] {\n if (parts.length === 0) {\n throw new PatchError(\"Cannot operate on root with this helper.\");\n }\n let parent = doc;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (Array.isArray(parent)) {\n const idx = Number(part);\n if (!Number.isInteger(idx) || idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[idx];\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, part)) {\n throw new PatchError(`Path not found: /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[part];\n } else {\n throw new PatchError(`Cannot traverse into ${typeof parent} at ${JSON.stringify(part)}`);\n }\n }\n const last = parts[parts.length - 1];\n if (Array.isArray(parent)) {\n if (last === \"-\") return [parent, \"-\"];\n const idx = Number(last);\n if (!Number.isInteger(idx)) {\n throw new PatchError(`Array index expected at ${JSON.stringify(last)}`);\n }\n return [parent, idx];\n }\n return [parent, last];\n}\n\nfunction getAt(doc: any, path: string): any {\n const parts = splitPath(path);\n if (parts.length === 0) return doc;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") throw new PatchError(\"Cannot read '-' position.\");\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) throw new PatchError(`Index out of range: ${path}`);\n return parent[idx];\n }\n if (\n parent === null ||\n typeof parent !== \"object\" ||\n !Object.prototype.hasOwnProperty.call(parent, key)\n ) {\n throw new PatchError(`Path not found: ${path}`);\n }\n return parent[key as string];\n}\n\nfunction clone<T>(v: T): T {\n return v === undefined ? v : (JSON.parse(JSON.stringify(v)) as T);\n}\n\nfunction deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== \"object\") return a === b;\n const aArr = Array.isArray(a);\n if (aArr !== Array.isArray(b)) return false;\n if (aArr) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.prototype.hasOwnProperty.call(b, k)) return false;\n if (!deepEqual(a[k], b[k])) return false;\n }\n return true;\n}\n\nfunction applyOne(doc: any, op: JsonPatchOp): any {\n const kind = op.op;\n const path = op.path ?? \"\";\n\n if (kind === \"add\") {\n if (!(\"value\" in op)) throw new PatchError(\"'add' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value; // replace whole document\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") {\n parent.push(op.value);\n } else {\n const idx = key as number;\n if (idx < 0 || idx > parent.length) {\n throw new PatchError(`Index out of range for add: ${path}`);\n }\n parent.splice(idx, 0, op.value);\n }\n } else if (parent !== null && typeof parent === \"object\") {\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot add into ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"replace\") {\n if (!(\"value\" in op)) throw new PatchError(\"'replace' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[idx] = op.value;\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot replace in ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"remove\") {\n const parts = splitPath(path);\n if (parts.length === 0) throw new PatchError(\"Cannot remove root.\");\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range for remove: ${path}`);\n }\n parent.splice(idx, 1);\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for remove: ${path}`);\n }\n delete parent[key as string];\n } else {\n throw new PatchError(`Cannot remove from ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"copy\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'copy' requires 'from'\");\n const value = clone(getAt(doc, src));\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"move\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'move' requires 'from'\");\n // RFC 6902 4.4: 'from' MUST NOT be a proper prefix of 'path'.\n if (path.startsWith(src + \"/\")) {\n throw new PatchError(\"'move' cannot move a location into its own child.\");\n }\n const value = clone(getAt(doc, src));\n doc = applyOne(doc, { op: \"remove\", path: src });\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"test\") {\n if (!(\"value\" in op)) throw new PatchError(\"'test' requires 'value'\");\n const actual = getAt(doc, path);\n if (!deepEqual(actual, op.value)) throw new PatchError(`'test' failed at ${path}`);\n return doc;\n }\n\n throw new PatchError(`Unsupported op: ${JSON.stringify(kind)}`);\n}\n\nconst MAX_PATCH_OPS = 1000;\nconst MAX_DOCUMENT_NODES = 100_000;\n\nfunction nodeCount(value: unknown): number {\n if (Array.isArray(value)) {\n let n = 1;\n for (const v of value) n += nodeCount(v);\n return n;\n }\n if (value !== null && typeof value === \"object\") {\n let n = 1;\n for (const v of Object.values(value as Record<string, unknown>)) n += nodeCount(v);\n return n;\n }\n return 1;\n}\n\nexport function applyJsonPatch(doc: unknown, ops: JsonPatchOp[]): unknown {\n if (ops.length > MAX_PATCH_OPS) {\n throw new PatchError(`Patch has too many operations (${ops.length} > ${MAX_PATCH_OPS})`);\n }\n let out: any = JSON.parse(JSON.stringify(doc));\n for (const op of ops) {\n out = applyOne(out, op);\n if (nodeCount(out) > MAX_DOCUMENT_NODES) {\n throw new PatchError(`Patched document exceeds the node limit (${MAX_DOCUMENT_NODES})`);\n }\n }\n return out;\n}\n\n// ============================================================\n// diff: produce a patch that transforms `from` into `to`\n// ============================================================\n\n/**\n * Compute an RFC 6902 patch that, when applied to `from`, produces\n * `to`. Walks objects key-by-key; arrays use a shallow whole-array\n * replace if any element differs. Sufficient for the playground's\n * draft-edit use case where drafts are small JSON objects.\n */\nexport function diffJsonPatch(from: unknown, to: unknown, basePath = \"\"): JsonPatchOp[] {\n const ops: JsonPatchOp[] = [];\n\n if (typeof from !== typeof to || Array.isArray(from) !== Array.isArray(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n return ops;\n }\n\n if (from === null || to === null || typeof from !== \"object\") {\n if (from !== to) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n if (Array.isArray(from) && Array.isArray(to)) {\n if (JSON.stringify(from) !== JSON.stringify(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n const fromObj = from as Record<string, unknown>;\n const toObj = to as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(fromObj), ...Object.keys(toObj)]);\n\n for (const key of allKeys) {\n const escaped = key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n const path = `${basePath}/${escaped}`;\n if (!(key in fromObj)) {\n ops.push({ op: \"add\", path, value: toObj[key] });\n } else if (!(key in toObj)) {\n ops.push({ op: \"remove\", path });\n } else {\n ops.push(...diffJsonPatch(fromObj[key], toObj[key], path));\n }\n }\n\n return ops;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/patch.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator/patch\n *\n * RFC 6902 JSON Patch implementation, plus a small diff computer that\n * produces a patch from two values. Used by the Coordinator for\n * `decide.override` apply and by the playground UI (in the browser) to\n * compute the patch from a textarea edit.\n *\n * Implements all six RFC 6902 operations (add, remove, replace, move,\n * copy, test) with semantics identical to the Python reference. Path\n * segments that enable prototype pollution in a JavaScript runtime\n * (`__proto__`, `constructor`, `prototype`) are rejected, so the two\n * references accept and reject exactly the same patches.\n */\n\nimport type { JsonPatchOp } from \"./types.js\";\n\nexport class PatchError extends Error {}\n\n// Rejected in every JSON Pointer segment: these enable prototype pollution.\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n// An array index is an RFC 6901 array index: \"0\" or a positive integer with no\n// leading zero. A shared strict rule keeps the two references in step -- JS\n// Number() and Python int() otherwise accept disjoint token sets (e.g. \"1e1\",\n// \"0x0a\", \"3.0\", \"\", \"1_0\"), which would apply the same patch differently.\nconst ARRAY_INDEX_RE = /^(0|[1-9][0-9]*)$/;\n\nfunction arrayIndex(seg: string): number {\n if (!ARRAY_INDEX_RE.test(seg)) throw new PatchError(`Array index expected at ${JSON.stringify(seg)}`);\n return Number(seg);\n}\n\nfunction unescape(token: string): string {\n return token.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n}\n\nfunction splitPath(path: string): string[] {\n if (path === \"\") return [];\n if (!path.startsWith(\"/\")) {\n throw new PatchError(`JSON Pointer must start with '/': ${JSON.stringify(path)}`);\n }\n const segments = path.slice(1).split(\"/\").map(unescape);\n for (const seg of segments) {\n if (DANGEROUS_KEYS.has(seg)) {\n throw new PatchError(`Refusing unsafe path segment ${JSON.stringify(seg)}`);\n }\n }\n return segments;\n}\n\n/** Navigate to the parent of the target; return [parent, lastKey]. */\nfunction navigate(doc: any, parts: string[]): [any, string | number] {\n if (parts.length === 0) {\n throw new PatchError(\"Cannot operate on root with this helper.\");\n }\n let parent = doc;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (Array.isArray(parent)) {\n const idx = arrayIndex(part);\n if (idx >= parent.length) {\n throw new PatchError(`Index out of range at /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[idx];\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, part)) {\n throw new PatchError(`Path not found: /${parts.slice(0, i + 1).join(\"/\")}`);\n }\n parent = parent[part];\n } else {\n throw new PatchError(`Cannot traverse into ${typeof parent} at ${JSON.stringify(part)}`);\n }\n }\n const last = parts[parts.length - 1];\n if (Array.isArray(parent)) {\n if (last === \"-\") return [parent, \"-\"];\n return [parent, arrayIndex(last)];\n }\n return [parent, last];\n}\n\nfunction getAt(doc: any, path: string): any {\n const parts = splitPath(path);\n if (parts.length === 0) return doc;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") throw new PatchError(\"Cannot read '-' position.\");\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) throw new PatchError(`Index out of range: ${path}`);\n return parent[idx];\n }\n if (\n parent === null ||\n typeof parent !== \"object\" ||\n !Object.prototype.hasOwnProperty.call(parent, key)\n ) {\n throw new PatchError(`Path not found: ${path}`);\n }\n return parent[key as string];\n}\n\nfunction clone<T>(v: T): T {\n return v === undefined ? v : (JSON.parse(JSON.stringify(v)) as T);\n}\n\nfunction deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (typeof a !== \"object\") return a === b;\n const aArr = Array.isArray(a);\n if (aArr !== Array.isArray(b)) return false;\n if (aArr) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.prototype.hasOwnProperty.call(b, k)) return false;\n if (!deepEqual(a[k], b[k])) return false;\n }\n return true;\n}\n\nfunction applyOne(doc: any, op: JsonPatchOp): any {\n const kind = op.op;\n const path = op.path ?? \"\";\n\n if (kind === \"add\") {\n if (!(\"value\" in op)) throw new PatchError(\"'add' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value; // replace whole document\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n if (key === \"-\") {\n parent.push(op.value);\n } else {\n const idx = key as number;\n if (idx < 0 || idx > parent.length) {\n throw new PatchError(`Index out of range for add: ${path}`);\n }\n parent.splice(idx, 0, op.value);\n }\n } else if (parent !== null && typeof parent === \"object\") {\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot add into ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"replace\") {\n if (!(\"value\" in op)) throw new PatchError(\"'replace' requires 'value'\");\n const parts = splitPath(path);\n if (parts.length === 0) return op.value;\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[idx] = op.value;\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for replace: ${path}`);\n }\n parent[key as string] = op.value;\n } else {\n throw new PatchError(`Cannot replace in ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"remove\") {\n const parts = splitPath(path);\n if (parts.length === 0) throw new PatchError(\"Cannot remove root.\");\n const [parent, key] = navigate(doc, parts);\n if (Array.isArray(parent)) {\n const idx = key as number;\n if (idx < 0 || idx >= parent.length) {\n throw new PatchError(`Index out of range for remove: ${path}`);\n }\n parent.splice(idx, 1);\n } else if (parent !== null && typeof parent === \"object\") {\n if (!Object.prototype.hasOwnProperty.call(parent, key)) {\n throw new PatchError(`Path not found for remove: ${path}`);\n }\n delete parent[key as string];\n } else {\n throw new PatchError(`Cannot remove from ${typeof parent}`);\n }\n return doc;\n }\n\n if (kind === \"copy\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'copy' requires 'from'\");\n const value = clone(getAt(doc, src));\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"move\") {\n const src = op.from;\n if (src === undefined) throw new PatchError(\"'move' requires 'from'\");\n // RFC 6902 4.4: 'from' MUST NOT be a proper prefix of 'path'.\n if (path.startsWith(src + \"/\")) {\n throw new PatchError(\"'move' cannot move a location into its own child.\");\n }\n const value = clone(getAt(doc, src));\n doc = applyOne(doc, { op: \"remove\", path: src });\n return applyOne(doc, { op: \"add\", path, value });\n }\n\n if (kind === \"test\") {\n if (!(\"value\" in op)) throw new PatchError(\"'test' requires 'value'\");\n const actual = getAt(doc, path);\n if (!deepEqual(actual, op.value)) throw new PatchError(`'test' failed at ${path}`);\n return doc;\n }\n\n throw new PatchError(`Unsupported op: ${JSON.stringify(kind)}`);\n}\n\nconst MAX_PATCH_OPS = 1000;\nconst MAX_DOCUMENT_NODES = 100_000;\n\nfunction nodeCount(value: unknown): number {\n if (Array.isArray(value)) {\n let n = 1;\n for (const v of value) n += nodeCount(v);\n return n;\n }\n if (value !== null && typeof value === \"object\") {\n let n = 1;\n for (const v of Object.values(value as Record<string, unknown>)) n += nodeCount(v);\n return n;\n }\n return 1;\n}\n\nexport function applyJsonPatch(doc: unknown, ops: JsonPatchOp[]): unknown {\n if (ops.length > MAX_PATCH_OPS) {\n throw new PatchError(`Patch has too many operations (${ops.length} > ${MAX_PATCH_OPS})`);\n }\n let out: any = JSON.parse(JSON.stringify(doc));\n for (const op of ops) {\n out = applyOne(out, op);\n if (nodeCount(out) > MAX_DOCUMENT_NODES) {\n throw new PatchError(`Patched document exceeds the node limit (${MAX_DOCUMENT_NODES})`);\n }\n }\n return out;\n}\n\n// ============================================================\n// diff: produce a patch that transforms `from` into `to`\n// ============================================================\n\n/**\n * Compute an RFC 6902 patch that, when applied to `from`, produces\n * `to`. Walks objects key-by-key; arrays use a shallow whole-array\n * replace if any element differs. Sufficient for the playground's\n * draft-edit use case where drafts are small JSON objects.\n */\nexport function diffJsonPatch(from: unknown, to: unknown, basePath = \"\"): JsonPatchOp[] {\n const ops: JsonPatchOp[] = [];\n\n if (typeof from !== typeof to || Array.isArray(from) !== Array.isArray(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n return ops;\n }\n\n if (from === null || to === null || typeof from !== \"object\") {\n if (from !== to) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n if (Array.isArray(from) && Array.isArray(to)) {\n if (JSON.stringify(from) !== JSON.stringify(to)) {\n ops.push({ op: \"replace\", path: basePath || \"/\", value: to });\n }\n return ops;\n }\n\n const fromObj = from as Record<string, unknown>;\n const toObj = to as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(fromObj), ...Object.keys(toObj)]);\n\n for (const key of allKeys) {\n const escaped = key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n const path = `${basePath}/${escaped}`;\n if (!(key in fromObj)) {\n ops.push({ op: \"add\", path, value: toObj[key] });\n } else if (!(key in toObj)) {\n ops.push({ op: \"remove\", path });\n } else {\n ops.push(...diffJsonPatch(fromObj[key], toObj[key], path));\n }\n }\n\n return ops;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightbeamai/chap-coordinator",
3
- "version": "0.2.10",
3
+ "version": "0.2.13",
4
4
  "description": "Collaborative Human-Agent Protocol (CHAP): reference TypeScript implementation. Coordinator with Core + every shipped profile, plus pluggable storage and typed method facade.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Brightbeam AI <oss@brightbeam.com>",