@bilig/workbook 0.90.0 → 0.90.4

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/README.md CHANGED
@@ -169,8 +169,9 @@ an agent inspected cannot be mutated behind the same handoff object.
169
169
  `verifyPlan` also treats plans as data: malformed, sparse, or accessor-backed
170
170
  handoff objects return an `invalid_plan` issue instead of executing hidden
171
171
  properties or throwing at the caller.
172
- `verifyModel` keeps the same behavior at whole-model scope: invalid manifests
173
- return an invalid verdict with an `invalid_model` error and no actions.
172
+ `verifyModel` keeps the same behavior at whole-model scope: invalid,
173
+ array-backed, or accessor-backed manifests return an invalid verdict with an
174
+ `invalid_model` error and no actions.
174
175
  Its `{ inputs }` option is data-only too: accessor-backed option payloads or
175
176
  per-action inputs produce structured `invalid_action_input` results without
176
177
  running hidden consumer code.
@@ -220,7 +221,10 @@ proof keep nested JSON paths such as `input.rows[1]` and
220
221
  hydration. Plan-data guards only trust own payload fields; inherited
221
222
  prototype fields never satisfy the transport contract. Transported plan arrays
222
223
  must contain own enumerable data entries too; holes, non-enumerable entries, or
223
- accessor-backed entries are rejected without running getters. The hydrated plan
224
+ accessor-backed entries are rejected without running getters. The plan root and
225
+ nested plan entries such as commands, changes, checks, formula labels, and
226
+ expectations must be record-shaped payloads, not arrays with attached fields.
227
+ The hydrated plan
224
228
  exposes `refs: { refsUsed }` instead of the consumer's private model-shaped
225
229
  `refs` object, so transported execution stays generic. A valid
226
230
  `checkPlanData(data)` result returns canonical plan data, stripping caller-owned
@@ -296,6 +300,8 @@ must be own enumerable data entries; holes, non-enumerable entries, or
296
300
  accessor-backed entries are rejected without running getters. Use
297
301
  `checkRuntimeAdapter(planOrRequirements, adapter)` when an agent wants to check
298
302
  `apply`, `read`, and `verifyChecks` coverage before calling the runtime.
303
+ The requirements root object, every requirement entry, and runtime adapter
304
+ objects must be record-shaped payloads, not arrays with attached fields.
299
305
  Runtime requirement descriptions are frozen normalized data too:
300
306
  `describeRuntimeRequirements` and `checkRuntimeRequirements` strip
301
307
  caller-owned extra fields and freeze the returned requirement tree, including
@@ -340,14 +346,18 @@ and the frozen run-result description, and roll back engine ops if post-apply
340
346
  readback or check proof fails.
341
347
  Runtime apply results, undo refs, apply errors, and check verifier output are
342
348
  validated from own fields only; prototype-inherited fields are ignored before
343
- they can become run proof. Adapter-returned ops and verifier proof must be data
344
- properties, including non-enumerable guard fields such as `kind`. Runtime
345
- evidence arrays must contain own enumerable data entries; holes,
346
- non-enumerable entries, and accessors are rejected before any getter can run
347
- during validation, cloning, or preview/apply comparison.
349
+ they can become run proof. Apply-result objects and verifier check objects must
350
+ be plain record-shaped payloads, not arrays with attached fields.
351
+ Adapter-returned ops and verifier proof must be data properties, including
352
+ non-enumerable guard fields such as `kind`. Runtime evidence arrays must contain
353
+ own enumerable data entries; holes, non-enumerable entries, and accessors are
354
+ rejected before any getter can run during validation, cloning, or preview/apply
355
+ comparison.
348
356
  Readback checks attach proof to passed checks, such as
349
357
  `{ source: "readback", value: 12 }` or
350
358
  `{ source: "readback", formula: "Table[Quantity]*Table[Rate]" }`.
359
+ Readback proof objects, check objects, expectations, and formula labels must be
360
+ record-shaped payloads, not arrays with attached fields.
351
361
  Formula readback proof is parsed with `@bilig/formula` and stored in canonical
352
362
  no-leading-`=` form, so harmless runtime differences such as a leading equals
353
363
  sign, whitespace, or redundant parentheses do not make proof fail.
@@ -455,10 +465,11 @@ It returns the same boring `{ status, issues }` shape for receipt fields such as
455
465
  `changedRanges`, `proof`, `metadata`, and `errors`. Feature manifests, command
456
466
  requests, and command receipts are validated from own payload fields only;
457
467
  prototype-inherited fields are ignored. Receipt verdicts are frozen. Receipt ops are frozen after
458
- normalization, changed ranges must be own-field data, and manifest or receipt
459
- arrays must contain own enumerable data entries. Holes, non-enumerable entries,
460
- and accessor-backed ops, undo ops, ranges, or errors are rejected before any
461
- getter can run.
468
+ normalization, changed ranges are canonicalized through the same workbook range
469
+ normalizer used by command scopes, and manifest or receipt arrays must contain
470
+ own enumerable data entries. Holes, non-enumerable entries, invalid range
471
+ addresses, and accessor-backed ops, undo ops, ranges, or errors are rejected
472
+ before any getter can run.
462
473
  Receipt statuses are semantic: `previewed` cannot include applied proof,
463
474
  `applied` cannot include errors and must carry applied evidence, `rejected`
464
475
  cannot claim changed workbook proof, and `noop` cannot claim changed ranges or
@@ -1,11 +1,18 @@
1
1
  import { formatAddress, parseCellAddress } from '@bilig/formula';
2
+ const commandRangeDataFields = Object.freeze(['sheetName', 'startAddress', 'endAddress']);
2
3
  export function normalizeCommandRange(value, path, label = 'Workbook command bundle') {
3
4
  if (!isRecord(value)) {
4
5
  throw new Error(`${label} ${path} must be an object`);
5
6
  }
6
- const sheetName = ownValue(value, 'sheetName');
7
- const startAddress = ownValue(value, 'startAddress');
8
- const endAddress = ownValue(value, 'endAddress');
7
+ for (const field of commandRangeDataFields) {
8
+ const descriptor = Object.getOwnPropertyDescriptor(value, field);
9
+ if (descriptor !== undefined && !('value' in descriptor)) {
10
+ throw new Error(`${label} ${path}.${field} must be a data property`);
11
+ }
12
+ }
13
+ const sheetName = ownDataValue(value, 'sheetName');
14
+ const startAddress = ownDataValue(value, 'startAddress');
15
+ const endAddress = ownDataValue(value, 'endAddress');
9
16
  if (typeof sheetName !== 'string' || typeof startAddress !== 'string' || typeof endAddress !== 'string') {
10
17
  throw new Error(`${label} ${path} must include sheetName, startAddress, and endAddress strings`);
11
18
  }
@@ -76,7 +83,7 @@ function normalizeExactString(value, path, label) {
76
83
  }
77
84
  return normalized;
78
85
  }
79
- function ownValue(value, key) {
86
+ function ownDataValue(value, key) {
80
87
  return Object.getOwnPropertyDescriptor(value, key)?.value;
81
88
  }
82
89
  function isRecord(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"command-ranges.js","sourceRoot":"","sources":["../src/command-ranges.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-ranges.js","sourceRoot":"","sources":["../src/command-ranges.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { CellRangeRef } from '@bilig/protocol';
2
+ export interface WorkbookCommandReceiptRangeIssue {
3
+ readonly path: string;
4
+ readonly message: string;
5
+ }
6
+ export declare function commandReceiptChangedRangeIssues(value: unknown): readonly WorkbookCommandReceiptRangeIssue[];
7
+ export declare function normalizeCommandReceiptChangedRanges(value: unknown): readonly CellRangeRef[] | null;
@@ -0,0 +1,64 @@
1
+ import { normalizeCommandRange } from './command-ranges.js';
2
+ const commandReceiptRangeDataFields = Object.freeze(['sheetName', 'startAddress', 'endAddress']);
3
+ export function commandReceiptChangedRangeIssues(value) {
4
+ if (!Array.isArray(value)) {
5
+ return Object.freeze([rangeIssue('changedRanges', 'Workbook command receipt changed ranges must be an array')]);
6
+ }
7
+ const issues = [];
8
+ for (let index = 0; index < value.length; index += 1) {
9
+ const path = `changedRanges[${String(index)}]`;
10
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
11
+ if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor)) {
12
+ issues.push(rangeIssue(path, 'Workbook command receipt changed ranges must contain only data properties'));
13
+ continue;
14
+ }
15
+ const dataFieldIssue = firstRangeDataFieldIssue(descriptor.value, path);
16
+ if (dataFieldIssue !== null) {
17
+ issues.push(dataFieldIssue);
18
+ continue;
19
+ }
20
+ try {
21
+ normalizeCommandRange(descriptor.value, path, 'Workbook command receipt');
22
+ }
23
+ catch (error) {
24
+ issues.push(rangeIssue(path, errorMessage(error)));
25
+ }
26
+ }
27
+ return Object.freeze(issues);
28
+ }
29
+ function firstRangeDataFieldIssue(value, path) {
30
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
31
+ return null;
32
+ }
33
+ for (const field of commandReceiptRangeDataFields) {
34
+ const descriptor = Object.getOwnPropertyDescriptor(value, field);
35
+ if (descriptor !== undefined && !('value' in descriptor)) {
36
+ return rangeIssue(`${path}.${field}`, `Workbook command receipt ${path}.${field} must be a data property`);
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ export function normalizeCommandReceiptChangedRanges(value) {
42
+ if (commandReceiptChangedRangeIssues(value).length > 0 || !Array.isArray(value)) {
43
+ return null;
44
+ }
45
+ const ranges = [];
46
+ for (let index = 0; index < value.length; index += 1) {
47
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
48
+ if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor)) {
49
+ return null;
50
+ }
51
+ ranges.push(normalizeCommandRange(descriptor.value, `changedRanges[${String(index)}]`, 'Workbook command receipt').range);
52
+ }
53
+ return Object.freeze(ranges);
54
+ }
55
+ function rangeIssue(path, message) {
56
+ return Object.freeze({
57
+ path,
58
+ message,
59
+ });
60
+ }
61
+ function errorMessage(error) {
62
+ return error instanceof Error ? error.message : String(error);
63
+ }
64
+ //# sourceMappingURL=command-receipt-ranges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-receipt-ranges.js","sourceRoot":"","sources":["../src/command-receipt-ranges.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { WorkbookUndoRef } from './result.js';
2
+ export declare function normalizeCommandResultUndoRef(value: unknown, path: string): WorkbookUndoRef;
@@ -0,0 +1,148 @@
1
+ import { isWorkbookOp } from './guards.js';
2
+ export function normalizeCommandResultUndoRef(value, path) {
3
+ if (!isRecord(value)) {
4
+ throw new Error(`Workbook command result ${path} must be an object`);
5
+ }
6
+ const accessorKeys = ownAccessorKeys(value, ['id', 'ops']);
7
+ if (accessorKeys.length > 0) {
8
+ throw new Error(`Workbook command result ${path}.${accessorKeys[0]} must be a data property`);
9
+ }
10
+ const id = ownValue(value, 'id');
11
+ if (typeof id !== 'string') {
12
+ throw new Error(`Workbook command result ${path}.id must be a string`);
13
+ }
14
+ const ops = ownValue(value, 'ops');
15
+ if (ops !== undefined && !Array.isArray(ops)) {
16
+ throw new Error(`Workbook command result ${path}.ops must be an array`);
17
+ }
18
+ if (Array.isArray(ops)) {
19
+ const accessorPath = firstAccessorPath(ops, `${path}.ops`);
20
+ if (accessorPath !== null) {
21
+ throw new Error(`Workbook command result ${accessorPath} must contain only data properties`);
22
+ }
23
+ const normalizedOps = [];
24
+ for (let index = 0; index < ops.length; index += 1) {
25
+ const op = arrayDataValue(ops, index);
26
+ if (op === undefined) {
27
+ throw new Error(`Workbook command result ${path}.ops[${String(index)}] must contain only data properties`);
28
+ }
29
+ normalizedOps.push(normalizeOp(op));
30
+ }
31
+ return Object.freeze({
32
+ id: normalizeExactString(id, `${path}.id`),
33
+ ops: Object.freeze(normalizedOps),
34
+ });
35
+ }
36
+ return Object.freeze({
37
+ id: normalizeExactString(id, `${path}.id`),
38
+ });
39
+ }
40
+ function normalizeOp(value) {
41
+ if (!isWorkbookOp(value)) {
42
+ throw new Error('Workbook command result op is invalid');
43
+ }
44
+ const cloned = cloneData(value);
45
+ if (!isWorkbookOp(cloned)) {
46
+ throw new Error('Workbook command result op clone is invalid');
47
+ }
48
+ return freezeData(cloned);
49
+ }
50
+ function normalizeExactString(value, path) {
51
+ const normalized = value.trim();
52
+ if (normalized === '') {
53
+ throw new Error(`Workbook command result ${path} cannot be empty`);
54
+ }
55
+ if (normalized !== value) {
56
+ throw new Error(`Workbook command result ${path} must not have leading or trailing whitespace`);
57
+ }
58
+ return normalized;
59
+ }
60
+ function arrayDataValue(value, index) {
61
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
62
+ return descriptor !== undefined && descriptor.enumerable && 'value' in descriptor ? descriptor.value : undefined;
63
+ }
64
+ function ownValue(value, key) {
65
+ return Object.getOwnPropertyDescriptor(value, key)?.value;
66
+ }
67
+ function ownAccessorKeys(value, keys) {
68
+ const accessors = [];
69
+ for (const key of keys) {
70
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
71
+ if (descriptor !== undefined && !('value' in descriptor)) {
72
+ accessors.push(key);
73
+ }
74
+ }
75
+ return accessors;
76
+ }
77
+ function isRecord(value) {
78
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
79
+ }
80
+ function firstAccessorPath(value, path, seen = new WeakSet()) {
81
+ if (typeof value !== 'object' || value === null) {
82
+ return null;
83
+ }
84
+ if (seen.has(value)) {
85
+ return null;
86
+ }
87
+ seen.add(value);
88
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
89
+ const childPath = Array.isArray(value) && /^\d+$/.test(key) ? `${path}[${key}]` : `${path}.${key}`;
90
+ if (!('value' in descriptor)) {
91
+ return childPath;
92
+ }
93
+ const nestedPath = firstAccessorPath(descriptor.value, childPath, seen);
94
+ if (nestedPath !== null) {
95
+ return nestedPath;
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ function freezeData(value, seen = new WeakSet()) {
101
+ if (typeof value !== 'object' || value === null) {
102
+ return value;
103
+ }
104
+ if (seen.has(value)) {
105
+ return value;
106
+ }
107
+ seen.add(value);
108
+ Object.values(Object.getOwnPropertyDescriptors(value)).forEach((descriptor) => {
109
+ if ('value' in descriptor) {
110
+ freezeData(descriptor.value, seen);
111
+ }
112
+ });
113
+ return Object.freeze(value);
114
+ }
115
+ function cloneData(value, seen = new WeakMap()) {
116
+ if (typeof value !== 'object' || value === null) {
117
+ return value;
118
+ }
119
+ const existing = seen.get(value);
120
+ if (existing !== undefined) {
121
+ return existing;
122
+ }
123
+ if (Array.isArray(value)) {
124
+ const cloned = [];
125
+ seen.set(value, cloned);
126
+ for (let index = 0; index < value.length; index += 1) {
127
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
128
+ if (descriptor !== undefined && descriptor.enumerable && 'value' in descriptor) {
129
+ cloned[index] = cloneData(descriptor.value, seen);
130
+ }
131
+ }
132
+ return cloned;
133
+ }
134
+ const cloned = Object.create(Object.getPrototypeOf(value));
135
+ seen.set(value, cloned);
136
+ Object.entries(Object.getOwnPropertyDescriptors(value)).forEach(([key, descriptor]) => {
137
+ if (descriptor.enumerable && 'value' in descriptor) {
138
+ Object.defineProperty(cloned, key, {
139
+ configurable: true,
140
+ enumerable: true,
141
+ value: cloneData(descriptor.value, seen),
142
+ writable: true,
143
+ });
144
+ }
145
+ });
146
+ return cloned;
147
+ }
148
+ //# sourceMappingURL=command-result-undo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-result-undo.js","sourceRoot":"","sources":["../src/command-result-undo.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,22 @@
1
1
  import { commandRangeBounds, commandRangeContains, commandRangeLabel, normalizeCommandRange } from './command-ranges.js';
2
+ import { normalizeCommandResultUndoRef } from './command-result-undo.js';
2
3
  import { checkWorkbookCommandReceipt, normalizeWorkbookCommandReceipt, workbookCommandReceiptOpsMatch, workbookCommandReceiptStatuses, } from './features.js';
3
- import { isWorkbookOp } from './guards.js';
4
4
  export const workbookCommandResultStatuses = Object.freeze([
5
5
  'accepted',
6
6
  ...workbookCommandReceiptStatuses,
7
7
  ]);
8
8
  const WORKBOOK_COMMAND_RESULT_STATUS_SET = new Set(workbookCommandResultStatuses);
9
9
  const acceptedResultSettledFields = Object.freeze(['receipts', 'matched', 'changedRanges', 'revision', 'undo', 'errors']);
10
+ const commandResultDataFields = Object.freeze([
11
+ 'status',
12
+ 'bundleId',
13
+ 'targetRevision',
14
+ 'idempotencyKey',
15
+ 'commandCount',
16
+ 'touchedRanges',
17
+ 'touchedCellCount',
18
+ ...acceptedResultSettledFields,
19
+ ]);
10
20
  export const workbookOpCommandFeatureId = 'workbook-op';
11
21
  export function isWorkbookCommandResultStatus(value) {
12
22
  return typeof value === 'string' && WORKBOOK_COMMAND_RESULT_STATUS_SET.has(value);
@@ -45,7 +55,7 @@ export function workbookCommandResultForReceipts(bundle, receipts, options = {})
45
55
  if (revision !== undefined && !isSafeNonNegativeInteger(revision)) {
46
56
  throw new Error('Workbook command result is invalid: revision must be a safe non-negative integer');
47
57
  }
48
- const undo = options.undo === undefined ? undefined : normalizeUndoRef(options.undo, 'undo');
58
+ const undo = options.undo === undefined ? undefined : normalizeCommandResultUndoRef(options.undo, 'undo');
49
59
  const changedRanges = normalizedReceipts.flatMap((receipt) => [...(receipt.changedRanges ?? [])]);
50
60
  const errors = commandResultErrorsForReceipts(normalizedReceipts);
51
61
  return normalizeWorkbookCommandResult({
@@ -83,37 +93,69 @@ export function checkWorkbookCommandResult(value) {
83
93
  });
84
94
  }
85
95
  const issues = [];
86
- const status = ownValue(value, 'status');
96
+ const accessorKeys = new Set(ownAccessorKeys(value, commandResultDataFields));
97
+ accessorKeys.forEach((key) => {
98
+ issues.push(commandResultIssue('invalid_command_result', key, `Workbook command result ${key} must be a data property`));
99
+ });
100
+ const status = accessorKeys.has('status') ? undefined : ownValue(value, 'status');
87
101
  if (!isWorkbookCommandResultStatus(status)) {
88
102
  issues.push(commandResultIssue('invalid_command_result', 'status', 'Workbook command result status is invalid'));
89
103
  }
90
- pushResultOptionalStringIssue(issues, ownValue(value, 'bundleId'), 'bundleId', 'bundle id');
91
- pushResultSafeIntegerIssue(issues, ownValue(value, 'targetRevision'), 'targetRevision', 'target revision', true);
92
- pushResultRequiredStringIssue(issues, ownValue(value, 'idempotencyKey'), 'idempotencyKey', 'idempotency key');
93
- pushResultSafeIntegerIssue(issues, ownValue(value, 'commandCount'), 'commandCount', 'command count', true);
94
- pushResultRangesIssues(issues, ownValue(value, 'touchedRanges'), 'touchedRanges', 'touched ranges');
95
- pushResultSafeIntegerIssue(issues, ownValue(value, 'touchedCellCount'), 'touchedCellCount', 'touched cell count', true);
104
+ if (!accessorKeys.has('bundleId')) {
105
+ pushResultOptionalStringIssue(issues, ownValue(value, 'bundleId'), 'bundleId', 'bundle id');
106
+ }
107
+ if (!accessorKeys.has('targetRevision')) {
108
+ pushResultSafeIntegerIssue(issues, ownValue(value, 'targetRevision'), 'targetRevision', 'target revision', true);
109
+ }
110
+ if (!accessorKeys.has('idempotencyKey')) {
111
+ pushResultRequiredStringIssue(issues, ownValue(value, 'idempotencyKey'), 'idempotencyKey', 'idempotency key');
112
+ }
113
+ if (!accessorKeys.has('commandCount')) {
114
+ pushResultSafeIntegerIssue(issues, ownValue(value, 'commandCount'), 'commandCount', 'command count', true);
115
+ }
116
+ if (!accessorKeys.has('touchedRanges')) {
117
+ pushResultRangesIssues(issues, ownValue(value, 'touchedRanges'), 'touchedRanges', 'touched ranges');
118
+ }
119
+ if (!accessorKeys.has('touchedCellCount')) {
120
+ pushResultSafeIntegerIssue(issues, ownValue(value, 'touchedCellCount'), 'touchedCellCount', 'touched cell count', true);
121
+ }
96
122
  if (status === 'accepted') {
97
123
  pushAcceptedResultSettledFieldIssues(issues, value);
98
124
  }
99
125
  else if (isWorkbookCommandResultStatus(status)) {
100
- pushResultSafeIntegerIssue(issues, ownValue(value, 'revision'), 'revision', 'revision', false);
101
- pushResultReceiptsIssues(issues, ownValue(value, 'receipts'));
102
- const matched = ownValue(value, 'matched');
103
- if (matched !== null && typeof matched !== 'boolean') {
104
- issues.push(commandResultIssue('invalid_command_result', 'matched', 'Workbook command result matched must be boolean or null'));
105
- }
106
- pushResultRangesIssues(issues, ownValue(value, 'changedRanges'), 'changedRanges', 'changed ranges');
107
- const undo = ownValue(value, 'undo');
108
- if (undo !== undefined) {
109
- try {
110
- normalizeUndoRef(undo, 'undo');
126
+ if (!accessorKeys.has('revision')) {
127
+ pushResultSafeIntegerIssue(issues, ownValue(value, 'revision'), 'revision', 'revision', false);
128
+ }
129
+ if (!accessorKeys.has('receipts')) {
130
+ pushResultReceiptsIssues(issues, ownValue(value, 'receipts'));
131
+ }
132
+ if (!accessorKeys.has('matched')) {
133
+ const matched = ownValue(value, 'matched');
134
+ if (matched !== null && typeof matched !== 'boolean') {
135
+ issues.push(commandResultIssue('invalid_command_result', 'matched', 'Workbook command result matched must be boolean or null'));
111
136
  }
112
- catch (error) {
113
- issues.push(commandResultIssue('invalid_undo', 'undo', errorMessage(error)));
137
+ }
138
+ if (!accessorKeys.has('changedRanges')) {
139
+ pushResultRangesIssues(issues, ownValue(value, 'changedRanges'), 'changedRanges', 'changed ranges');
140
+ }
141
+ const undo = accessorKeys.has('undo') ? undefined : ownValue(value, 'undo');
142
+ if (!accessorKeys.has('undo') && undo !== undefined) {
143
+ const undoAccessorKeys = isRecord(undo) ? ownAccessorKeys(undo, ['id', 'ops']) : [];
144
+ undoAccessorKeys.forEach((key) => {
145
+ issues.push(commandResultIssue('invalid_undo', `undo.${key}`, `Workbook command result undo.${key} must be a data property`));
146
+ });
147
+ if (undoAccessorKeys.length === 0) {
148
+ try {
149
+ normalizeCommandResultUndoRef(undo, 'undo');
150
+ }
151
+ catch (error) {
152
+ issues.push(commandResultIssue('invalid_undo', 'undo', errorMessage(error)));
153
+ }
114
154
  }
115
155
  }
116
- pushResultErrorsIssues(issues, ownValue(value, 'errors'));
156
+ if (!accessorKeys.has('errors')) {
157
+ pushResultErrorsIssues(issues, ownValue(value, 'errors'));
158
+ }
117
159
  }
118
160
  if (issues.length > 0) {
119
161
  return Object.freeze({
@@ -545,7 +587,7 @@ function normalizeWorkbookCommandResultData(value) {
545
587
  receipts: Object.freeze(normalizeResultReceipts(ownValue(value, 'receipts'))),
546
588
  matched: matched === true ? true : matched === false ? false : null,
547
589
  changedRanges: Object.freeze(normalizeResultRanges(ownValue(value, 'changedRanges'), 'changedRanges')),
548
- ...(undo !== undefined ? { undo: normalizeUndoRef(undo, 'undo') } : {}),
590
+ ...(undo !== undefined ? { undo: normalizeCommandResultUndoRef(undo, 'undo') } : {}),
549
591
  ...(Array.isArray(errors) ? { errors: Object.freeze(normalizeResultErrors(errors)) } : {}),
550
592
  });
551
593
  }
@@ -569,50 +611,6 @@ function normalizeResultErrors(errors) {
569
611
  return normalizeExactString(entry, `errors[${String(index)}]`);
570
612
  });
571
613
  }
572
- function normalizeUndoRef(value, path) {
573
- if (!isRecord(value)) {
574
- throw new Error(`Workbook command result ${path} must be an object`);
575
- }
576
- const id = ownValue(value, 'id');
577
- if (typeof id !== 'string') {
578
- throw new Error(`Workbook command result ${path}.id must be a string`);
579
- }
580
- const ops = ownValue(value, 'ops');
581
- if (ops !== undefined && !Array.isArray(ops)) {
582
- throw new Error(`Workbook command result ${path}.ops must be an array`);
583
- }
584
- if (Array.isArray(ops)) {
585
- const accessorPath = firstAccessorPath(ops, `${path}.ops`);
586
- if (accessorPath !== null) {
587
- throw new Error(`Workbook command result ${accessorPath} must contain only data properties`);
588
- }
589
- const normalizedOps = [];
590
- for (let index = 0; index < ops.length; index += 1) {
591
- const op = arrayDataValue(ops, index);
592
- if (op === undefined) {
593
- throw new Error(`Workbook command result ${path}.ops[${String(index)}] must contain only data properties`);
594
- }
595
- normalizedOps.push(normalizeOp(op));
596
- }
597
- return Object.freeze({
598
- id: normalizeExactString(id, `${path}.id`),
599
- ops: Object.freeze(normalizedOps),
600
- });
601
- }
602
- return Object.freeze({
603
- id: normalizeExactString(id, `${path}.id`),
604
- });
605
- }
606
- function normalizeOp(value) {
607
- if (!isWorkbookOp(value)) {
608
- throw new Error('Workbook command result op is invalid');
609
- }
610
- const cloned = cloneData(value);
611
- if (!isWorkbookOp(cloned)) {
612
- throw new Error('Workbook command result op clone is invalid');
613
- }
614
- return freezeData(cloned);
615
- }
616
614
  function normalizeExactString(value, path) {
617
615
  const normalized = value.trim();
618
616
  if (normalized === '') {
@@ -630,6 +628,16 @@ function arrayDataValue(value, index) {
630
628
  function ownValue(value, key) {
631
629
  return Object.getOwnPropertyDescriptor(value, key)?.value;
632
630
  }
631
+ function ownAccessorKeys(value, keys) {
632
+ const accessors = [];
633
+ for (const key of keys) {
634
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
635
+ if (descriptor !== undefined && !('value' in descriptor)) {
636
+ accessors.push(key);
637
+ }
638
+ }
639
+ return accessors;
640
+ }
633
641
  function isRecord(value) {
634
642
  return typeof value === 'object' && value !== null && !Array.isArray(value);
635
643
  }
@@ -639,72 +647,4 @@ function isSafeNonNegativeInteger(value) {
639
647
  function errorMessage(error) {
640
648
  return error instanceof Error ? error.message : String(error);
641
649
  }
642
- function firstAccessorPath(value, path, seen = new WeakSet()) {
643
- if (typeof value !== 'object' || value === null) {
644
- return null;
645
- }
646
- if (seen.has(value)) {
647
- return null;
648
- }
649
- seen.add(value);
650
- for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
651
- const childPath = Array.isArray(value) && /^\d+$/.test(key) ? `${path}[${key}]` : `${path}.${key}`;
652
- if (!('value' in descriptor)) {
653
- return childPath;
654
- }
655
- const nestedPath = firstAccessorPath(descriptor.value, childPath, seen);
656
- if (nestedPath !== null) {
657
- return nestedPath;
658
- }
659
- }
660
- return null;
661
- }
662
- function freezeData(value, seen = new WeakSet()) {
663
- if (typeof value !== 'object' || value === null) {
664
- return value;
665
- }
666
- if (seen.has(value)) {
667
- return value;
668
- }
669
- seen.add(value);
670
- Object.values(Object.getOwnPropertyDescriptors(value)).forEach((descriptor) => {
671
- if ('value' in descriptor) {
672
- freezeData(descriptor.value, seen);
673
- }
674
- });
675
- return Object.freeze(value);
676
- }
677
- function cloneData(value, seen = new WeakMap()) {
678
- if (typeof value !== 'object' || value === null) {
679
- return value;
680
- }
681
- const existing = seen.get(value);
682
- if (existing !== undefined) {
683
- return existing;
684
- }
685
- if (Array.isArray(value)) {
686
- const cloned = [];
687
- seen.set(value, cloned);
688
- for (let index = 0; index < value.length; index += 1) {
689
- const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
690
- if (descriptor !== undefined && descriptor.enumerable && 'value' in descriptor) {
691
- cloned[index] = cloneData(descriptor.value, seen);
692
- }
693
- }
694
- return cloned;
695
- }
696
- const cloned = Object.create(Object.getPrototypeOf(value));
697
- seen.set(value, cloned);
698
- Object.entries(Object.getOwnPropertyDescriptors(value)).forEach(([key, descriptor]) => {
699
- if (descriptor.enumerable && 'value' in descriptor) {
700
- Object.defineProperty(cloned, key, {
701
- configurable: true,
702
- enumerable: true,
703
- value: cloneData(descriptor.value, seen),
704
- writable: true,
705
- });
706
- }
707
- });
708
- return cloned;
709
- }
710
650
  //# sourceMappingURL=command-result.js.map