foottrace 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -71
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lib/cause/explain.js +7 -7
- package/dist/esm/lib/cause/queryMemo.d.ts +18 -0
- package/dist/esm/lib/cause/queryMemo.js +46 -0
- package/dist/esm/lib/cause/recordAdapter.js +12 -19
- package/dist/esm/lib/cause/recordChildren.d.ts +3 -3
- package/dist/esm/lib/cause/recordChildren.js +3 -4
- package/dist/esm/lib/cause/recordCoverage.d.ts +2 -2
- package/dist/esm/lib/cause/recordCoverage.js +1 -1
- package/dist/esm/lib/cause/recordIdentity.js +5 -5
- package/dist/esm/lib/cause/recordLoading.js +3 -3
- package/dist/esm/lib/cause/recordQuery.d.ts +9 -0
- package/dist/esm/lib/cause/recordQuery.js +22 -0
- package/dist/esm/lib/cause/recordScope.js +13 -13
- package/dist/esm/lib/cause/recordValidation.d.ts +4 -4
- package/dist/esm/lib/cause/recordValidation.js +17 -17
- package/dist/esm/lib/cause/session.js +9 -6
- package/dist/esm/lib/cause/storedRecordAdapter.js +16 -10
- package/dist/esm/lib/cause/types.d.ts +2 -1
- package/dist/esm/lib/cause/validation.d.ts +4 -4
- package/dist/esm/lib/cause/validation.js +19 -36
- package/dist/esm/lib/{cause → evidence}/admission.d.ts +5 -1
- package/dist/esm/lib/{cause → evidence}/admission.js +14 -1
- package/dist/esm/lib/evidence/codes.d.ts +33 -0
- package/dist/esm/lib/evidence/codes.js +28 -0
- package/dist/esm/lib/evidence/requirementTypes.d.ts +46 -0
- package/dist/esm/lib/evidence/requirementTypes.js +1 -0
- package/dist/esm/lib/evidence/requirements.d.ts +24 -0
- package/dist/esm/lib/evidence/requirements.js +185 -0
- package/dist/index.js +5 -1
- package/dist/lib/cause/explain.js +6 -6
- package/dist/lib/cause/queryMemo.js +52 -0
- package/dist/lib/cause/recordAdapter.js +10 -17
- package/dist/lib/cause/recordChildren.js +3 -4
- package/dist/lib/cause/recordCoverage.js +1 -1
- package/dist/lib/cause/recordIdentity.js +4 -4
- package/dist/lib/cause/recordLoading.js +2 -2
- package/dist/lib/cause/recordQuery.js +27 -0
- package/dist/lib/cause/recordScope.js +12 -12
- package/dist/lib/cause/recordValidation.js +21 -21
- package/dist/lib/cause/session.js +8 -5
- package/dist/lib/cause/storedRecordAdapter.js +15 -9
- package/dist/lib/cause/validation.js +23 -40
- package/dist/lib/{cause → evidence}/admission.js +14 -1
- package/dist/lib/evidence/codes.js +33 -0
- package/dist/lib/evidence/requirementTypes.js +2 -0
- package/dist/lib/evidence/requirements.js +190 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/lib/cause/queryMemo.d.ts +18 -0
- package/dist/types/lib/cause/recordChildren.d.ts +3 -3
- package/dist/types/lib/cause/recordCoverage.d.ts +2 -2
- package/dist/types/lib/cause/recordQuery.d.ts +9 -0
- package/dist/types/lib/cause/recordValidation.d.ts +4 -4
- package/dist/types/lib/cause/types.d.ts +2 -1
- package/dist/types/lib/cause/validation.d.ts +4 -4
- package/dist/types/lib/{cause → evidence}/admission.d.ts +5 -1
- package/dist/types/lib/evidence/codes.d.ts +33 -0
- package/dist/types/lib/evidence/requirementTypes.d.ts +46 -0
- package/dist/types/lib/evidence/requirements.d.ts +24 -0
- package/package.json +7 -3
- /package/dist/esm/lib/cause/{recordParents.d.ts → recordInspection.d.ts} +0 -0
- /package/dist/esm/lib/cause/{recordParents.js → recordInspection.js} +0 -0
- /package/dist/lib/cause/{recordParents.js → recordInspection.js} +0 -0
- /package/dist/types/lib/cause/{recordParents.d.ts → recordInspection.d.ts} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { boundedList, boundedName, EvidenceRefusal, ownData, spendFields } from './admission.js';
|
|
2
|
+
import { isRequirementReason } from './codes.js';
|
|
3
|
+
/** Fixed per-call ceilings; characters are UTF-16 code units, not serialized transport bytes. */
|
|
4
|
+
export const REQUIREMENT_RESULT_LIMITS = Object.freeze({
|
|
5
|
+
results: 512,
|
|
6
|
+
checks: 16,
|
|
7
|
+
affects: 32,
|
|
8
|
+
refs: 16,
|
|
9
|
+
name: 512,
|
|
10
|
+
fields: 32768,
|
|
11
|
+
characters: 1048576,
|
|
12
|
+
});
|
|
13
|
+
/** No input, field value or originating exception is retained on a refusal. */
|
|
14
|
+
export class RequirementValidationError extends EvidenceRefusal {
|
|
15
|
+
constructor(code = 'invalid-data') {
|
|
16
|
+
super(code, 'REQUIREMENT_RESULTS_INVALID');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const refuse = (code) => new RequirementValidationError(code);
|
|
20
|
+
const descriptors = { translateTrapErrors: true, requireOwnValue: true };
|
|
21
|
+
const own = (value, key) => ownData(value, key, refuse, descriptors);
|
|
22
|
+
const resultKeys = new Set([
|
|
23
|
+
'id',
|
|
24
|
+
'requirementRef',
|
|
25
|
+
'findingRef',
|
|
26
|
+
'windowRef',
|
|
27
|
+
'affects',
|
|
28
|
+
'state',
|
|
29
|
+
'reason',
|
|
30
|
+
'detail',
|
|
31
|
+
'evidenceRefs',
|
|
32
|
+
'checks',
|
|
33
|
+
'actionRefs',
|
|
34
|
+
'validTimeRef',
|
|
35
|
+
'learnedTimeRef',
|
|
36
|
+
]);
|
|
37
|
+
const checkKeys = new Set(['checkRef', 'disposition', 'reason', 'detail', 'evidenceRefs', 'attemptRefs']);
|
|
38
|
+
const dispositions = new Set([
|
|
39
|
+
'checked-pass',
|
|
40
|
+
'checked-fail',
|
|
41
|
+
'unreachable',
|
|
42
|
+
'not-applicable',
|
|
43
|
+
]);
|
|
44
|
+
/** Closed objects expose no unknown payloads. Never invoke data accessors, iterators or toJSON. */
|
|
45
|
+
function object(value, keys, budget) {
|
|
46
|
+
if (!value || typeof value !== 'object')
|
|
47
|
+
throw refuse();
|
|
48
|
+
let prototype;
|
|
49
|
+
let fields;
|
|
50
|
+
try {
|
|
51
|
+
prototype = Object.getPrototypeOf(value);
|
|
52
|
+
fields = Reflect.ownKeys(value);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw refuse();
|
|
56
|
+
}
|
|
57
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
58
|
+
throw refuse();
|
|
59
|
+
if (fields.length > keys.size || fields.some((field) => typeof field !== 'string' || !keys.has(field)))
|
|
60
|
+
throw refuse();
|
|
61
|
+
spendFields(budget, fields.length, refuse);
|
|
62
|
+
// Including optional own fields: an own accessor is never treated as an absent field.
|
|
63
|
+
for (const field of fields)
|
|
64
|
+
own(value, field);
|
|
65
|
+
}
|
|
66
|
+
function list(value, maximum, read, budget) {
|
|
67
|
+
try {
|
|
68
|
+
if (!Array.isArray(value))
|
|
69
|
+
throw refuse();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw refuse();
|
|
73
|
+
}
|
|
74
|
+
const length = own(value, 'length');
|
|
75
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
|
|
76
|
+
throw refuse();
|
|
77
|
+
if (length > maximum)
|
|
78
|
+
throw refuse('node-limit');
|
|
79
|
+
let prototype;
|
|
80
|
+
let keys;
|
|
81
|
+
try {
|
|
82
|
+
prototype = Object.getPrototypeOf(value);
|
|
83
|
+
keys = Reflect.ownKeys(value);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw refuse();
|
|
87
|
+
}
|
|
88
|
+
if (prototype !== Array.prototype)
|
|
89
|
+
throw refuse();
|
|
90
|
+
if (keys.length !== length + 1 ||
|
|
91
|
+
keys.some((key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= length)))
|
|
92
|
+
throw refuse();
|
|
93
|
+
spendFields(budget, length + 1, refuse);
|
|
94
|
+
return boundedList(value, maximum, read, {
|
|
95
|
+
refuse,
|
|
96
|
+
overflow: 'node-limit',
|
|
97
|
+
freeze: true,
|
|
98
|
+
descriptors,
|
|
99
|
+
expectedLength: length,
|
|
100
|
+
translateArrayErrors: true,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function name(value, budget) {
|
|
104
|
+
const result = boundedName(value, REQUIREMENT_RESULT_LIMITS.name, refuse);
|
|
105
|
+
if (/\s/u.test(result))
|
|
106
|
+
throw refuse();
|
|
107
|
+
budget.characters -= result.length;
|
|
108
|
+
if (budget.characters < 0)
|
|
109
|
+
throw refuse('node-limit');
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
function unique(items, key) {
|
|
113
|
+
if (new Set(items.map(key)).size !== items.length)
|
|
114
|
+
throw refuse();
|
|
115
|
+
return items;
|
|
116
|
+
}
|
|
117
|
+
function refs(value, budget, maximum = REQUIREMENT_RESULT_LIMITS.refs) {
|
|
118
|
+
return unique(list(value, maximum, (item) => name(item, budget), budget), (item) => item);
|
|
119
|
+
}
|
|
120
|
+
function reason(value) {
|
|
121
|
+
if (!isRequirementReason(value))
|
|
122
|
+
throw refuse();
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
function optionalName(value, key, budget) {
|
|
126
|
+
const raw = own(value, key);
|
|
127
|
+
return raw === undefined ? undefined : name(raw, budget);
|
|
128
|
+
}
|
|
129
|
+
function detail(value, budget) {
|
|
130
|
+
const id = optionalName(value, 'detail', budget);
|
|
131
|
+
if (id !== undefined && !/^[A-Za-z][A-Za-z0-9_.-]*:.+$/.test(id))
|
|
132
|
+
throw refuse();
|
|
133
|
+
return id;
|
|
134
|
+
}
|
|
135
|
+
function check(value, budget) {
|
|
136
|
+
object(value, checkKeys, budget);
|
|
137
|
+
const checkRef = name(own(value, 'checkRef'), budget), disposition = own(value, 'disposition');
|
|
138
|
+
if (typeof disposition !== 'string' || !dispositions.has(disposition))
|
|
139
|
+
throw refuse();
|
|
140
|
+
const rawReason = own(value, 'reason'), detailId = detail(value, budget);
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
checkRef,
|
|
143
|
+
disposition: disposition,
|
|
144
|
+
...(rawReason === undefined ? {} : { reason: reason(rawReason) }),
|
|
145
|
+
...(detailId === undefined ? {} : { detail: detailId }),
|
|
146
|
+
evidenceRefs: refs(own(value, 'evidenceRefs'), budget),
|
|
147
|
+
attemptRefs: refs(own(value, 'attemptRefs'), budget),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function result(value, budget) {
|
|
151
|
+
object(value, resultKeys, budget);
|
|
152
|
+
const id = name(own(value, 'id'), budget), requirementRef = name(own(value, 'requirementRef'), budget), findingRef = name(own(value, 'findingRef'), budget), windowRef = name(own(value, 'windowRef'), budget), state = own(value, 'state'), rawReason = own(value, 'reason');
|
|
153
|
+
if (state !== 'satisfied' && state !== 'unresolved')
|
|
154
|
+
throw refuse();
|
|
155
|
+
if (state === 'satisfied' && rawReason !== undefined)
|
|
156
|
+
throw refuse();
|
|
157
|
+
const affects = refs(own(value, 'affects'), budget, REQUIREMENT_RESULT_LIMITS.affects);
|
|
158
|
+
if (!affects.length)
|
|
159
|
+
throw refuse();
|
|
160
|
+
const evidenceRefs = refs(own(value, 'evidenceRefs'), budget), checks = unique(list(own(value, 'checks'), REQUIREMENT_RESULT_LIMITS.checks, (item) => check(item, budget), budget), (item) => item.checkRef), actionRefs = refs(own(value, 'actionRefs'), budget), detailId = detail(value, budget), validTimeRef = optionalName(value, 'validTimeRef', budget), learnedTimeRef = optionalName(value, 'learnedTimeRef', budget);
|
|
161
|
+
const binding = {
|
|
162
|
+
id,
|
|
163
|
+
requirementRef,
|
|
164
|
+
findingRef,
|
|
165
|
+
windowRef,
|
|
166
|
+
affects,
|
|
167
|
+
evidenceRefs,
|
|
168
|
+
checks,
|
|
169
|
+
actionRefs,
|
|
170
|
+
...(detailId === undefined ? {} : { detail: detailId }),
|
|
171
|
+
...(validTimeRef === undefined ? {} : { validTimeRef }),
|
|
172
|
+
...(learnedTimeRef === undefined ? {} : { learnedTimeRef }),
|
|
173
|
+
};
|
|
174
|
+
return Object.freeze(state === 'unresolved' ? { ...binding, state, reason: reason(rawReason) } : { ...binding, state });
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Atomically project detached, frozen reference-only records. This is structural admission only.
|
|
178
|
+
* The host must authenticate producers, resolve authorized artifacts, verify current query/run/scope and
|
|
179
|
+
* domain validity, and enforce every unresolved affects reference before rendering any factual claim.
|
|
180
|
+
* Identifier grammar does not classify secrets; producers must supply non-secret identifiers only.
|
|
181
|
+
*/
|
|
182
|
+
export function readRequirementResults(value) {
|
|
183
|
+
const budget = { left: REQUIREMENT_RESULT_LIMITS.fields, characters: REQUIREMENT_RESULT_LIMITS.characters };
|
|
184
|
+
return unique(list(value, REQUIREMENT_RESULT_LIMITS.results, (item) => result(item, budget), budget), (item) => item.id);
|
|
185
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.idPathSegments = exports.joinPath = exports.isExecutionKey = exports.PATH_DELIMITER = exports.EXECUTION_DELIMITER = exports.CommitRangeIndex = exports.HONESTY_CODES = exports.sliceToJSON = exports.sliceForKey = exports.resolveKeysReadSource = exports.keyTimeline = exports.keysReadFromMap = exports.keysReadFromExecutionTree = exports.forwardSliceToJSON = exports.forwardSliceForKey = exports.formatTimeline = exports.formatSlice = exports.formatForwardSlice = exports.elementProvenance = exports.arrayProvenance = exports.formatCausalChain = exports.flattenCausalDAG = exports.causalChain = exports.timeTravel = exports.tagStops = exports.stateAt = exports.splitAxis = exports.readStoredRecord = exports.isCommitBundle = exports.filterStops = exports.commitStopsStrategy = exports.commitStops = exports.recordsPhases = exports.inferLegacyPhases = exports.findLastWriterWithBasis = exports.findLastWriter = exports.findCommits = exports.findCommit = exports.commitValueAtWithBasis = exports.commitValueAt = exports.commitIndexOf = exports.buildCommitIndex = exports.applySmartMerge = exports.UnknownVerbError = exports.parseAttemptId = exports.buildAttemptId = exports.splitStageId = exports.parseRuntimeStageId = exports.createExecutionCounter = exports.buildRuntimeStageId = void 0;
|
|
4
|
-
exports.serveRecord = exports.deepEqual = exports.subflowSegmentsOf = exports.stageIdOf = void 0;
|
|
4
|
+
exports.REQUIREMENT_RESULT_LIMITS = exports.RequirementValidationError = exports.readRequirementResults = exports.serveRecord = exports.deepEqual = exports.subflowSegmentsOf = exports.stageIdOf = void 0;
|
|
5
5
|
var runtimeStageId_js_1 = require("./lib/ids/runtimeStageId.js");
|
|
6
6
|
Object.defineProperty(exports, "buildRuntimeStageId", { enumerable: true, get: function () { return runtimeStageId_js_1.buildRuntimeStageId; } });
|
|
7
7
|
Object.defineProperty(exports, "createExecutionCounter", { enumerable: true, get: function () { return runtimeStageId_js_1.createExecutionCounter; } });
|
|
@@ -69,3 +69,7 @@ var equality_js_1 = require("./lib/memory/equality.js");
|
|
|
69
69
|
Object.defineProperty(exports, "deepEqual", { enumerable: true, get: function () { return equality_js_1.deepEqual; } });
|
|
70
70
|
var freeze_js_1 = require("./lib/capture/freeze.js");
|
|
71
71
|
Object.defineProperty(exports, "serveRecord", { enumerable: true, get: function () { return freeze_js_1.serveRecord; } });
|
|
72
|
+
var requirements_js_1 = require("./lib/evidence/requirements.js");
|
|
73
|
+
Object.defineProperty(exports, "readRequirementResults", { enumerable: true, get: function () { return requirements_js_1.readRequirementResults; } });
|
|
74
|
+
Object.defineProperty(exports, "RequirementValidationError", { enumerable: true, get: function () { return requirements_js_1.RequirementValidationError; } });
|
|
75
|
+
Object.defineProperty(exports, "REQUIREMENT_RESULT_LIMITS", { enumerable: true, get: function () { return requirements_js_1.REQUIREMENT_RESULT_LIMITS; } });
|
|
@@ -7,13 +7,13 @@ const validation_js_1 = require("./validation.js");
|
|
|
7
7
|
const ranking_js_1 = require("./ranking.js");
|
|
8
8
|
/** Read-only deterministic cause localisation and impact. No inference from timestamps or structural ancestry. */
|
|
9
9
|
async function explain(graph, nodeId, options = {}) {
|
|
10
|
-
(0, validation_js_1.
|
|
10
|
+
(0, validation_js_1.graphName)(nodeId);
|
|
11
11
|
const session = new session_js_1.Session(graph, options);
|
|
12
12
|
try {
|
|
13
13
|
const backward = await (0, walk_js_1.walk)(session, [nodeId], 'parents');
|
|
14
14
|
const missing = [...backward.gaps];
|
|
15
15
|
let candidates = (0, walk_js_1.frontier)(backward).map((item) => item.nodeId);
|
|
16
|
-
const rank = (0, validation_js_1.
|
|
16
|
+
const rank = (0, validation_js_1.graphOwn)(options, 'rankRoots');
|
|
17
17
|
if (rank !== undefined) {
|
|
18
18
|
if (typeof rank !== 'function')
|
|
19
19
|
throw new TypeError('CAUSE_CONFIGURATION_INVALID');
|
|
@@ -34,7 +34,7 @@ async function explain(graph, nodeId, options = {}) {
|
|
|
34
34
|
const rootCause = causeComplete && candidates.length === 1 ? candidates[0] : undefined;
|
|
35
35
|
const forward = await (0, walk_js_1.walk)(session, [nodeId], 'children');
|
|
36
36
|
let impactNodes = Object.freeze(forward.nodes.filter((id) => id !== nodeId));
|
|
37
|
-
const impactGaps = [...forward.gaps], rankImpact = (0, validation_js_1.
|
|
37
|
+
const impactGaps = [...forward.gaps], rankImpact = (0, validation_js_1.graphOwn)(options, 'rankImpact');
|
|
38
38
|
if (typeof rankImpact === 'function') {
|
|
39
39
|
const selection = await session.invoke(undefined, () => rankImpact(impactNodes, session.context), (raw) => (0, ranking_js_1.admitRanking)(raw, new Set(impactNodes), {
|
|
40
40
|
exactPermutation: true,
|
|
@@ -73,19 +73,19 @@ async function attentionList(graph, options = {}) {
|
|
|
73
73
|
const session = new session_js_1.Session(graph, options);
|
|
74
74
|
try {
|
|
75
75
|
let seeds = [], missing = [];
|
|
76
|
-
const requested = (0, validation_js_1.
|
|
76
|
+
const requested = (0, validation_js_1.graphOwn)(options, 'nodeIds');
|
|
77
77
|
const admitSeeds = (raw) => {
|
|
78
78
|
// Only inspect the bounded prefix; the unread tail is explicitly incomplete.
|
|
79
79
|
if (!Array.isArray(raw))
|
|
80
80
|
return (0, validation_js_1.nodeIds)(raw, session.limits.maxNodes);
|
|
81
|
-
const length = (0, validation_js_1.
|
|
81
|
+
const length = (0, validation_js_1.graphOwn)(raw, 'length');
|
|
82
82
|
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
|
|
83
83
|
return (0, validation_js_1.nodeIds)(raw, session.limits.maxNodes);
|
|
84
84
|
if (length > session.limits.maxNodes)
|
|
85
85
|
missing.push((0, validation_js_1.gap)('node-limit'));
|
|
86
86
|
const prefix = [];
|
|
87
87
|
for (let i = 0; i < Math.min(length, session.limits.maxNodes); i++)
|
|
88
|
-
prefix.push((0, validation_js_1.
|
|
88
|
+
prefix.push((0, validation_js_1.graphOwn)(raw, String(i)));
|
|
89
89
|
return (0, validation_js_1.nodeIds)(prefix, session.limits.maxNodes);
|
|
90
90
|
};
|
|
91
91
|
if (requested !== undefined) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.endQueryMemo = exports.queryMemo = exports.beginQueryMemo = void 0;
|
|
4
|
+
/** Share bounded derived work within one query without retaining it in the graph's storage cache. */
|
|
5
|
+
class QueryMemo {
|
|
6
|
+
maximumEntries;
|
|
7
|
+
owners = new Map();
|
|
8
|
+
entries = 0;
|
|
9
|
+
closed = false;
|
|
10
|
+
constructor(maximumEntries) {
|
|
11
|
+
this.maximumEntries = maximumEntries;
|
|
12
|
+
}
|
|
13
|
+
remember(owner, key, create) {
|
|
14
|
+
const previous = this.owners.get(owner);
|
|
15
|
+
if (previous?.has(key))
|
|
16
|
+
return previous.get(key);
|
|
17
|
+
if (this.closed || this.entries >= this.maximumEntries)
|
|
18
|
+
return create();
|
|
19
|
+
const value = create();
|
|
20
|
+
// Creation can finish after disposal or re-enter other readers; neither may refill a closed/full memo.
|
|
21
|
+
if (!this.closed && this.entries < this.maximumEntries) {
|
|
22
|
+
const bucket = this.owners.get(owner) ?? new Map();
|
|
23
|
+
if (!bucket.has(key))
|
|
24
|
+
this.entries++;
|
|
25
|
+
bucket.set(key, value);
|
|
26
|
+
this.owners.set(owner, bucket);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
close() {
|
|
31
|
+
this.closed = true;
|
|
32
|
+
this.owners.clear();
|
|
33
|
+
this.entries = 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const queries = new WeakMap();
|
|
37
|
+
/** Reserve one resolution and one inspection per admitted node, shared across all adapter owners. */
|
|
38
|
+
function beginQueryMemo(context, maximumNodes) {
|
|
39
|
+
queries.set(context, new QueryMemo(maximumNodes * 2));
|
|
40
|
+
}
|
|
41
|
+
exports.beginQueryMemo = beginQueryMemo;
|
|
42
|
+
/** Direct graph calls have no managed query lifetime and deliberately remain uncached. */
|
|
43
|
+
function queryMemo(context) {
|
|
44
|
+
return queries.get(context);
|
|
45
|
+
}
|
|
46
|
+
exports.queryMemo = queryMemo;
|
|
47
|
+
/** Clear synchronously without aborting an otherwise successful query's public signal. */
|
|
48
|
+
function endQueryMemo(context) {
|
|
49
|
+
queries.get(context)?.close();
|
|
50
|
+
queries.delete(context);
|
|
51
|
+
}
|
|
52
|
+
exports.endQueryMemo = endQueryMemo;
|
|
@@ -5,38 +5,31 @@ const recordChildren_js_1 = require("./recordChildren.js");
|
|
|
5
5
|
const recordCoverage_js_1 = require("./recordCoverage.js");
|
|
6
6
|
const recordIdentity_js_1 = require("./recordIdentity.js");
|
|
7
7
|
const recordLoading_js_1 = require("./recordLoading.js");
|
|
8
|
-
const
|
|
8
|
+
const recordQuery_js_1 = require("./recordQuery.js");
|
|
9
9
|
const recordScope_js_1 = require("./recordScope.js");
|
|
10
10
|
const recordValidation_js_1 = require("./recordValidation.js");
|
|
11
|
+
/** Give each failed port its own incomplete page rather than sharing a mutable edge array. */
|
|
12
|
+
const unavailableAdjacency = () => ({ edges: [], complete: false });
|
|
11
13
|
var recordScope_js_2 = require("./recordScope.js");
|
|
12
14
|
Object.defineProperty(exports, "recordOptions", { enumerable: true, get: function () { return recordScope_js_2.recordOptions; } });
|
|
13
15
|
/** Common engine for memory and one-scope-at-a-time host storage. Loader functions are trusted executable code. */
|
|
14
16
|
function createLazyRecordGraph(load, options = {}) {
|
|
15
17
|
const limits = (0, recordScope_js_1.recordOptions)(options), loader = (0, recordLoading_js_1.createRecordScopeLoader)(load, limits);
|
|
16
|
-
const
|
|
18
|
+
const query = (0, recordQuery_js_1.createRecordQuery)(loader, limits.maxEdges);
|
|
17
19
|
return Object.freeze({
|
|
18
20
|
nodeId: (address, node) => (0, recordIdentity_js_1.nodeIdFor)(address, node),
|
|
19
21
|
openScope: (address, context) => (0, recordLoading_js_1.openRecordScope)(address, context, loader),
|
|
20
22
|
async parents(nodeId, context) {
|
|
21
|
-
|
|
22
|
-
return 'failure' in node
|
|
23
|
-
? { edges: [], complete: false }
|
|
24
|
-
: (0, recordParents_js_1.inspectRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope)).adjacency;
|
|
23
|
+
return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => query.inspect(node, context).adjacency, unavailableAdjacency);
|
|
25
24
|
},
|
|
26
25
|
async gaps(nodeId, context) {
|
|
27
|
-
|
|
28
|
-
return 'failure' in node
|
|
29
|
-
? (0, recordCoverage_js_1.gapForRecordFailure)(node.failure)
|
|
30
|
-
: (0, recordParents_js_1.inspectRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope)).gaps;
|
|
26
|
+
return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => query.inspect(node, context).gaps, (failure) => (0, recordCoverage_js_1.gapForRecordFailure)(failure.failure));
|
|
31
27
|
},
|
|
32
28
|
async attention(nodeId, context) {
|
|
33
|
-
return (0,
|
|
29
|
+
return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), recordCoverage_js_1.attentionForRecordNode, () => []);
|
|
34
30
|
},
|
|
35
31
|
async children(nodeId, context) {
|
|
36
|
-
|
|
37
|
-
return 'failure' in node
|
|
38
|
-
? { edges: [], complete: false }
|
|
39
|
-
: (0, recordChildren_js_1.childrenForRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope));
|
|
32
|
+
return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => (0, recordChildren_js_1.childrenForRecordNode)(node, limits.maxEdges, query.inspect(node, context)), unavailableAdjacency);
|
|
40
33
|
},
|
|
41
34
|
});
|
|
42
35
|
}
|
|
@@ -45,8 +38,8 @@ exports.createLazyRecordGraph = createLazyRecordGraph;
|
|
|
45
38
|
function createRecordGraph(scopes, options = {}) {
|
|
46
39
|
const limits = (0, recordScope_js_1.recordOptions)(options);
|
|
47
40
|
return createLazyRecordGraph((address) => {
|
|
48
|
-
for (const raw of (0, recordValidation_js_1.
|
|
49
|
-
if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.
|
|
41
|
+
for (const raw of (0, recordValidation_js_1.recordList)(scopes, limits.maxScopes)) {
|
|
42
|
+
if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(raw, 'address'))) === (0, recordValidation_js_1.addressKey)(address))
|
|
50
43
|
return { scope: raw };
|
|
51
44
|
}
|
|
52
45
|
throw new recordValidation_js_1.RecordRefusal('unavailable');
|
|
@@ -5,7 +5,6 @@ const forwardSliceForKey_js_1 = require("../slice/forwardSliceForKey.js");
|
|
|
5
5
|
const recordControl_js_1 = require("./recordControl.js");
|
|
6
6
|
const recordCoverage_js_1 = require("./recordCoverage.js");
|
|
7
7
|
const recordIdentity_js_1 = require("./recordIdentity.js");
|
|
8
|
-
const recordParents_js_1 = require("./recordParents.js");
|
|
9
8
|
const recordScope_js_1 = require("./recordScope.js");
|
|
10
9
|
/** Keep per-write and conservative fed edges distinct while retaining existing cap and deduplication order. */
|
|
11
10
|
function appendFedChildren(scope, root, maximumEdges, edges) {
|
|
@@ -70,10 +69,10 @@ function appendDataChildren(scope, identity, commitIndex, maximumEdges, edges) {
|
|
|
70
69
|
return complete;
|
|
71
70
|
}
|
|
72
71
|
/** Share parent-side coverage checks before appending data then control children in their established order. */
|
|
73
|
-
function childrenForRecordNode(node, maximumEdges,
|
|
72
|
+
function childrenForRecordNode(node, maximumEdges, inspection) {
|
|
74
73
|
const { scope, identity, commitIndex } = node;
|
|
75
|
-
const
|
|
76
|
-
let complete =
|
|
74
|
+
const edges = [];
|
|
75
|
+
let complete = inspection.gaps.length === 0;
|
|
77
76
|
if (!(0, recordCoverage_js_1.allStageReadsCollected)(scope))
|
|
78
77
|
complete = false;
|
|
79
78
|
complete = appendDataChildren(scope, identity, commitIndex, maximumEdges, edges) && complete;
|
|
@@ -25,7 +25,7 @@ exports.gapForRecordFailure = gapForRecordFailure;
|
|
|
25
25
|
/** Return captured mark references without treating an omitted attention map as collected evidence. */
|
|
26
26
|
function attentionForRecordNode(node) {
|
|
27
27
|
// An omitted map stays unknown coverage; it is never replaced by an affirmative empty map.
|
|
28
|
-
return
|
|
28
|
+
return node.scope.marks?.get(node.identity.runtimeStageId) ?? [];
|
|
29
29
|
}
|
|
30
30
|
exports.attentionForRecordNode = attentionForRecordNode;
|
|
31
31
|
/** Emit host and capture gaps before query-derived gaps so existing evidence order stays stable. */
|
|
@@ -14,7 +14,7 @@ function readNodeIdentity(nodeId) {
|
|
|
14
14
|
catch {
|
|
15
15
|
throw new recordValidation_js_1.RecordRefusal();
|
|
16
16
|
}
|
|
17
|
-
const address = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.
|
|
17
|
+
const address = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(fields, 'address')), runtimeStageId = (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(fields, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.recordOwn)(fields, 'commitIdx'), key = (0, recordValidation_js_1.recordOwn)(fields, 'key'), read = (0, recordValidation_js_1.recordOwn)(fields, 'read');
|
|
18
18
|
if (commitIndex !== undefined && (!Number.isSafeInteger(commitIndex) || commitIndex < 0))
|
|
19
19
|
throw new recordValidation_js_1.RecordRefusal();
|
|
20
20
|
if ((read !== undefined && read !== true) || (read === true && key === undefined))
|
|
@@ -23,7 +23,7 @@ function readNodeIdentity(nodeId) {
|
|
|
23
23
|
address,
|
|
24
24
|
runtimeStageId,
|
|
25
25
|
...(commitIndex === undefined ? {} : { commitIdx: commitIndex }),
|
|
26
|
-
...(key === undefined ? {} : { key: (0, recordValidation_js_1.
|
|
26
|
+
...(key === undefined ? {} : { key: (0, recordValidation_js_1.recordName)(key, true) }),
|
|
27
27
|
...(read === true ? { read: true } : {}),
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -31,7 +31,7 @@ exports.readNodeIdentity = readNodeIdentity;
|
|
|
31
31
|
/** Stable field order preserves existing address/execution/key IDs across storage and memory readers. */
|
|
32
32
|
function nodeIdFor(addressInput, node, read) {
|
|
33
33
|
try {
|
|
34
|
-
const address = (0, recordValidation_js_1.addressOf)(addressInput), runtimeStageId = (0, recordValidation_js_1.
|
|
34
|
+
const address = (0, recordValidation_js_1.addressOf)(addressInput), runtimeStageId = (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(node, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.recordOwn)(node, 'commitIdx'), key = (0, recordValidation_js_1.recordOwn)(node, 'key');
|
|
35
35
|
if (commitIndex !== undefined && (!Number.isSafeInteger(commitIndex) || commitIndex < 0))
|
|
36
36
|
throw new recordValidation_js_1.RecordRefusal();
|
|
37
37
|
const nodeId = 'record:' +
|
|
@@ -39,7 +39,7 @@ function nodeIdFor(addressInput, node, read) {
|
|
|
39
39
|
address,
|
|
40
40
|
runtimeStageId,
|
|
41
41
|
...(commitIndex === undefined ? {} : { commitIdx: commitIndex }),
|
|
42
|
-
...(key === undefined ? {} : { key: (0, recordValidation_js_1.
|
|
42
|
+
...(key === undefined ? {} : { key: (0, recordValidation_js_1.recordName)(key, true) }),
|
|
43
43
|
...(read ? { read: true } : {}),
|
|
44
44
|
});
|
|
45
45
|
return nodeId.length <= 2048 ? nodeId : 'record:invalid';
|
|
@@ -13,8 +13,8 @@ function admitLoadedScope(result, request, limits, state) {
|
|
|
13
13
|
}
|
|
14
14
|
let prepared;
|
|
15
15
|
try {
|
|
16
|
-
prepared = (0, recordScope_js_1.prepareRecordScope)((0, recordValidation_js_1.
|
|
17
|
-
const extra = (0, recordValidation_js_1.
|
|
16
|
+
prepared = (0, recordScope_js_1.prepareRecordScope)((0, recordValidation_js_1.recordOwn)(result, 'scope'), request.address, limits.maxCommits, limits.maxFields);
|
|
17
|
+
const extra = (0, recordValidation_js_1.recordList)((0, recordValidation_js_1.recordOwn)(result, 'gaps') ?? [], 32);
|
|
18
18
|
// Coverage belongs to this admitted object, so cached scopes retain the same gap ordering and ownership.
|
|
19
19
|
state.extraGaps.set(prepared, (0, validation_js_1.gaps)(extra.map((code) => ({ code, evidence: [] }))).map((gap) => gap.code));
|
|
20
20
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.whenResolved = exports.createRecordQuery = void 0;
|
|
4
|
+
const queryMemo_js_1 = require("./queryMemo.js");
|
|
5
|
+
const recordIdentity_js_1 = require("./recordIdentity.js");
|
|
6
|
+
const recordInspection_js_1 = require("./recordInspection.js");
|
|
7
|
+
/** Both dependency directions share the same admitted node and canonical inspection within a query. */
|
|
8
|
+
function createRecordQuery(loader, maximumEdges) {
|
|
9
|
+
const resolutionOwner = {}, inspectionOwner = {};
|
|
10
|
+
return {
|
|
11
|
+
resolve(nodeId, context) {
|
|
12
|
+
const resolve = () => (0, recordIdentity_js_1.resolveRecordNode)(nodeId, context, loader), memo = (0, queryMemo_js_1.queryMemo)(context);
|
|
13
|
+
// A retained success must never bypass the loader's existing cancellation check.
|
|
14
|
+
return memo && !context.signal.aborted ? memo.remember(resolutionOwner, nodeId, resolve) : resolve();
|
|
15
|
+
},
|
|
16
|
+
inspect(node, context) {
|
|
17
|
+
const inspect = () => (0, recordInspection_js_1.inspectRecordNode)(node, maximumEdges, loader.extraGapCodes(node.scope));
|
|
18
|
+
return (0, queryMemo_js_1.queryMemo)(context)?.remember(inspectionOwner, node, inspect) ?? inspect();
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
exports.createRecordQuery = createRecordQuery;
|
|
23
|
+
/** Every port maps the same fixed loading failure while projecting only admitted nodes. */
|
|
24
|
+
function whenResolved(node, onNode, onFailure) {
|
|
25
|
+
return 'failure' in node ? onFailure(node) : onNode(node);
|
|
26
|
+
}
|
|
27
|
+
exports.whenResolved = whenResolved;
|
|
@@ -19,11 +19,11 @@ function recordOptions(options) {
|
|
|
19
19
|
if (prototype !== Object.prototype && prototype !== null)
|
|
20
20
|
throw new TypeError();
|
|
21
21
|
return Object.freeze({
|
|
22
|
-
maxCommits: boundedOption((0, recordValidation_js_1.
|
|
23
|
-
maxFields: boundedOption((0, recordValidation_js_1.
|
|
24
|
-
maxEdges: boundedOption((0, recordValidation_js_1.
|
|
25
|
-
maxScopes: boundedOption((0, recordValidation_js_1.
|
|
26
|
-
loadTimeoutMs: boundedOption((0, recordValidation_js_1.
|
|
22
|
+
maxCommits: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxCommits'), 256, 4096),
|
|
23
|
+
maxFields: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxFields'), 20000, 1000000),
|
|
24
|
+
maxEdges: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxEdges'), 64, 256),
|
|
25
|
+
maxScopes: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxScopes'), 32, 256),
|
|
26
|
+
loadTimeoutMs: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'loadTimeoutMs'), 1000, 30000),
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
catch {
|
|
@@ -33,22 +33,22 @@ function recordOptions(options) {
|
|
|
33
33
|
exports.recordOptions = recordOptions;
|
|
34
34
|
/** Spend one shared field budget before canonical readers see any untrusted scope data. */
|
|
35
35
|
function prepareRecordScope(value, address, maximumCommits, maximumFields) {
|
|
36
|
-
if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.
|
|
36
|
+
if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(value, 'address'))) !== (0, recordValidation_js_1.addressKey)(address))
|
|
37
37
|
throw new recordValidation_js_1.RecordRefusal();
|
|
38
|
-
const rawLog = (0, recordValidation_js_1.
|
|
39
|
-
const log = rawLog.map((_, commitIndex) => (0, recordValidation_js_1.bundleOf)((0, recordValidation_js_1.
|
|
40
|
-
const reads = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.
|
|
38
|
+
const rawLog = (0, recordValidation_js_1.recordList)((0, recordValidation_js_1.recordOwn)(value, 'commitLog'), maximumCommits), budget = { left: maximumFields };
|
|
39
|
+
const log = rawLog.map((_, commitIndex) => (0, recordValidation_js_1.bundleOf)((0, recordValidation_js_1.recordOwn)(rawLog, String(commitIndex)), commitIndex, budget));
|
|
40
|
+
const reads = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'reads'), maximumCommits, (value) => {
|
|
41
41
|
const readKeys = (0, recordValidation_js_1.names)(value, 128, true);
|
|
42
42
|
(0, recordValidation_js_1.spend)(budget, readKeys.length);
|
|
43
43
|
return readKeys;
|
|
44
44
|
}, budget);
|
|
45
|
-
const control = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.
|
|
46
|
-
const marks = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.
|
|
45
|
+
const control = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'controlDeps'), maximumCommits, (value) => ({ deciderId: (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(value, 'deciderId')) }), budget);
|
|
46
|
+
const marks = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'attention'), maximumCommits, (value) => {
|
|
47
47
|
const attention = (0, recordValidation_js_1.marksOf)(value);
|
|
48
48
|
(0, recordValidation_js_1.spend)(budget, attention.length + attention.reduce((count, mark) => count + mark.evidence.length, 0));
|
|
49
49
|
return attention;
|
|
50
50
|
}, budget);
|
|
51
|
-
return { address, log, reads, control, marks, complete: (0, recordValidation_js_1.
|
|
51
|
+
return { address, log, reads, control, marks, complete: (0, recordValidation_js_1.recordOwn)(value, 'complete') === true };
|
|
52
52
|
}
|
|
53
53
|
exports.prepareRecordScope = prepareRecordScope;
|
|
54
54
|
/** Preserve both stage reads and stronger per-write prefixes, including their original encounter order. */
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.projectLoaded = exports.mapOf = exports.bundleOf = exports.dataCopy = exports.addressKey = exports.spend = exports.addressOf = exports.
|
|
3
|
+
exports.projectLoaded = exports.mapOf = exports.bundleOf = exports.dataCopy = exports.addressKey = exports.spend = exports.addressOf = exports.recordList = exports.recordName = exports.names = exports.recordOwn = exports.RecordRefusal = exports.marksOf = void 0;
|
|
4
4
|
const validation_js_1 = require("./validation.js");
|
|
5
5
|
Object.defineProperty(exports, "marksOf", { enumerable: true, get: function () { return validation_js_1.attention; } });
|
|
6
|
-
const admission_js_1 = require("
|
|
6
|
+
const admission_js_1 = require("../evidence/admission.js");
|
|
7
7
|
/** Loader refusals stay distinct from graph-port refusals so a failed host load keeps its original classification. */
|
|
8
8
|
class RecordRefusal extends admission_js_1.EvidenceRefusal {
|
|
9
9
|
code;
|
|
@@ -15,19 +15,19 @@ class RecordRefusal extends admission_js_1.EvidenceRefusal {
|
|
|
15
15
|
exports.RecordRefusal = RecordRefusal;
|
|
16
16
|
const refuseRecord = (code) => new RecordRefusal(code);
|
|
17
17
|
const recordDescriptors = { translateTrapErrors: true, requireOwnValue: true };
|
|
18
|
-
function
|
|
18
|
+
function recordOwn(value, key) {
|
|
19
19
|
return (0, admission_js_1.ownData)(value, key, refuseRecord, recordDescriptors);
|
|
20
20
|
}
|
|
21
|
-
exports.
|
|
21
|
+
exports.recordOwn = recordOwn;
|
|
22
22
|
function names(value, maximum = 128, path = false) {
|
|
23
|
-
return
|
|
23
|
+
return recordList(value, maximum).map((item) => recordName(item, path));
|
|
24
24
|
}
|
|
25
25
|
exports.names = names;
|
|
26
|
-
function
|
|
26
|
+
function recordName(value, path = false) {
|
|
27
27
|
return (0, admission_js_1.boundedName)(value, 1024, refuseRecord, path);
|
|
28
28
|
}
|
|
29
|
-
exports.
|
|
30
|
-
function
|
|
29
|
+
exports.recordName = recordName;
|
|
30
|
+
function recordList(value, maximum) {
|
|
31
31
|
return (0, admission_js_1.boundedList)(value, maximum, (item) => item, {
|
|
32
32
|
refuse: refuseRecord,
|
|
33
33
|
overflow: 'node-limit',
|
|
@@ -35,9 +35,9 @@ function list(value, maximum) {
|
|
|
35
35
|
descriptors: recordDescriptors,
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
exports.
|
|
38
|
+
exports.recordList = recordList;
|
|
39
39
|
function addressOf(value) {
|
|
40
|
-
const logRunId =
|
|
40
|
+
const logRunId = recordName(recordOwn(value, 'logRunId')), drillPath = names(recordOwn(value, 'drillPath'), 16);
|
|
41
41
|
if (logRunId.length + drillPath.reduce((n, s) => n + s.length, 0) > 1536)
|
|
42
42
|
throw new RecordRefusal();
|
|
43
43
|
return Object.freeze({ logRunId, drillPath: Object.freeze(drillPath) });
|
|
@@ -71,7 +71,7 @@ function dataCopy(value, budget) {
|
|
|
71
71
|
if (!Array.isArray(v) && p !== Object.prototype && p !== null)
|
|
72
72
|
throw new RecordRefusal();
|
|
73
73
|
if (Array.isArray(v)) {
|
|
74
|
-
const length =
|
|
74
|
+
const length = recordOwn(v, 'length');
|
|
75
75
|
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
|
|
76
76
|
throw new RecordRefusal();
|
|
77
77
|
spend(budget, length);
|
|
@@ -96,7 +96,7 @@ function dataCopy(value, budget) {
|
|
|
96
96
|
for (const key of keys) {
|
|
97
97
|
if (key.length > 1024)
|
|
98
98
|
throw new RecordRefusal('node-limit');
|
|
99
|
-
const v =
|
|
99
|
+
const v = recordOwn(from, key);
|
|
100
100
|
check(v);
|
|
101
101
|
let copy = v;
|
|
102
102
|
if (!leaf(v)) {
|
|
@@ -113,16 +113,16 @@ function dataCopy(value, budget) {
|
|
|
113
113
|
}
|
|
114
114
|
exports.dataCopy = dataCopy;
|
|
115
115
|
function bundleOf(value, idx, budget) {
|
|
116
|
-
const runtimeStageId =
|
|
117
|
-
const trace =
|
|
118
|
-
const t =
|
|
116
|
+
const runtimeStageId = recordName(recordOwn(value, 'runtimeStageId')), stageId = recordName(recordOwn(value, 'stageId'));
|
|
117
|
+
const trace = recordList(recordOwn(value, 'trace'), 128).map((_, i) => {
|
|
118
|
+
const t = recordOwn(recordOwn(value, 'trace'), String(i)), path = recordName(recordOwn(t, 'path'), true), verb = recordOwn(t, 'verb');
|
|
119
119
|
if (!['set', 'merge', 'append', 'delete'].includes(verb))
|
|
120
120
|
throw new RecordRefusal();
|
|
121
|
-
const readKeys =
|
|
121
|
+
const readKeys = recordOwn(t, 'readKeys');
|
|
122
122
|
return { path, verb: verb, ...(readKeys === undefined ? {} : { readKeys: names(readKeys, 128, true) }) };
|
|
123
123
|
});
|
|
124
124
|
spend(budget, trace.length + trace.reduce((n, t) => n + (t.readKeys?.length ?? 0), 0) + 1);
|
|
125
|
-
const overwrite = dataCopy(
|
|
125
|
+
const overwrite = dataCopy(recordOwn(value, 'overwrite'), budget), updates = dataCopy(recordOwn(value, 'updates'), budget);
|
|
126
126
|
if (!overwrite ||
|
|
127
127
|
typeof overwrite !== 'object' ||
|
|
128
128
|
Array.isArray(overwrite) ||
|
|
@@ -130,9 +130,9 @@ function bundleOf(value, idx, budget) {
|
|
|
130
130
|
typeof updates !== 'object' ||
|
|
131
131
|
Array.isArray(updates))
|
|
132
132
|
throw new RecordRefusal();
|
|
133
|
-
const redactedPaths = names(
|
|
134
|
-
const untracked =
|
|
135
|
-
spend(budget, redactedPaths.length + (untracked === undefined ? 0 :
|
|
133
|
+
const redactedPaths = names(recordOwn(value, 'redactedPaths') ?? [], 128, true);
|
|
134
|
+
const untracked = recordOwn(value, 'untrackedSources'), phase = recordOwn(value, 'phase');
|
|
135
|
+
spend(budget, redactedPaths.length + (untracked === undefined ? 0 : recordList(untracked, 128).length));
|
|
136
136
|
return {
|
|
137
137
|
idx,
|
|
138
138
|
stage: stageId,
|
|
@@ -179,7 +179,7 @@ function mapOf(value, limit, read, budget) {
|
|
|
179
179
|
throw new RecordRefusal('node-limit');
|
|
180
180
|
if (budget)
|
|
181
181
|
spend(budget, keys.length);
|
|
182
|
-
return new Map(keys.map((k) => [
|
|
182
|
+
return new Map(keys.map((k) => [recordName(k), read(recordOwn(value, k))]));
|
|
183
183
|
}
|
|
184
184
|
exports.mapOf = mapOf;
|
|
185
185
|
/** Observe native promises by intrinsic without assimilating a data object's then accessor. */
|