conftree 0.1.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/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/cache/cache.d.ts +23 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +95 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/change-bus.d.ts +16 -0
- package/dist/cache/change-bus.d.ts.map +1 -0
- package/dist/cache/change-bus.js +14 -0
- package/dist/cache/change-bus.js.map +1 -0
- package/dist/core/errors.d.ts +27 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +58 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/types.d.ts +52 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/engine/auditor.d.ts +8 -0
- package/dist/engine/auditor.d.ts.map +1 -0
- package/dist/engine/auditor.js +22 -0
- package/dist/engine/auditor.js.map +1 -0
- package/dist/engine/engine.d.ts +25 -0
- package/dist/engine/engine.d.ts.map +1 -0
- package/dist/engine/engine.js +24 -0
- package/dist/engine/engine.js.map +1 -0
- package/dist/engine/hierarchy-cache-sync.d.ts +4 -0
- package/dist/engine/hierarchy-cache-sync.d.ts.map +1 -0
- package/dist/engine/hierarchy-cache-sync.js +26 -0
- package/dist/engine/hierarchy-cache-sync.js.map +1 -0
- package/dist/engine/resolver.d.ts +24 -0
- package/dist/engine/resolver.d.ts.map +1 -0
- package/dist/engine/resolver.js +195 -0
- package/dist/engine/resolver.js.map +1 -0
- package/dist/engine/writer.d.ts +32 -0
- package/dist/engine/writer.d.ts.map +1 -0
- package/dist/engine/writer.js +178 -0
- package/dist/engine/writer.js.map +1 -0
- package/dist/hierarchy/scope-hierarchy.d.ts +15 -0
- package/dist/hierarchy/scope-hierarchy.d.ts.map +1 -0
- package/dist/hierarchy/scope-hierarchy.js +86 -0
- package/dist/hierarchy/scope-hierarchy.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +895 -0
- package/dist/index.mjs.map +1 -0
- package/dist/storage/memory-storage.d.ts +25 -0
- package/dist/storage/memory-storage.d.ts.map +1 -0
- package/dist/storage/memory-storage.js +176 -0
- package/dist/storage/memory-storage.js.map +1 -0
- package/dist/storage/storage-port.d.ts +93 -0
- package/dist/storage/storage-port.d.ts.map +1 -0
- package/dist/storage/storage-port.js +3 -0
- package/dist/storage/storage-port.js.map +1 -0
- package/dist/typed/registry.d.ts +7 -0
- package/dist/typed/registry.d.ts.map +1 -0
- package/dist/typed/registry.js +3 -0
- package/dist/typed/registry.js.map +1 -0
- package/dist/typed/typed-auditor.d.ts +12 -0
- package/dist/typed/typed-auditor.d.ts.map +1 -0
- package/dist/typed/typed-auditor.js +14 -0
- package/dist/typed/typed-auditor.js.map +1 -0
- package/dist/typed/typed-engine.d.ts +11 -0
- package/dist/typed/typed-engine.d.ts.map +1 -0
- package/dist/typed/typed-engine.js +14 -0
- package/dist/typed/typed-engine.js.map +1 -0
- package/dist/typed/typed-resolver.d.ts +23 -0
- package/dist/typed/typed-resolver.d.ts.map +1 -0
- package/dist/typed/typed-resolver.js +22 -0
- package/dist/typed/typed-resolver.js.map +1 -0
- package/dist/typed/typed-writer.d.ts +32 -0
- package/dist/typed/typed-writer.d.ts.map +1 -0
- package/dist/typed/typed-writer.js +20 -0
- package/dist/typed/typed-writer.js.map +1 -0
- package/package.json +61 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
// src/core/types.ts
|
|
2
|
+
var DEFAULT_SCOPE = { kind: "default", refId: null };
|
|
3
|
+
|
|
4
|
+
// src/core/errors.ts
|
|
5
|
+
var ConfTreeError = class extends Error {
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = new.target.name;
|
|
10
|
+
Error.captureStackTrace?.(this, new.target);
|
|
11
|
+
}
|
|
12
|
+
code;
|
|
13
|
+
};
|
|
14
|
+
var NotFoundError = class extends ConfTreeError {
|
|
15
|
+
constructor(key) {
|
|
16
|
+
super(`Unknown setting definition: "${key}"`, "NOT_FOUND");
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var ScopeError = class extends ConfTreeError {
|
|
20
|
+
constructor(key, scopeKind) {
|
|
21
|
+
super(
|
|
22
|
+
`Setting "${key}" cannot be set or read at scope kind "${scopeKind}"`,
|
|
23
|
+
"SCOPE"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var RequiredError = class extends ConfTreeError {
|
|
28
|
+
constructor(key, scopeKind, scopeRefId) {
|
|
29
|
+
super(
|
|
30
|
+
`Required setting "${key}" has no resolvable value for scope ${scopeKind}:${scopeRefId ?? "null"} and no default is defined`,
|
|
31
|
+
"REQUIRED"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var ValueError = class extends ConfTreeError {
|
|
36
|
+
constructor(message) {
|
|
37
|
+
super(message, "VALUE");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var ConflictError = class extends ConfTreeError {
|
|
41
|
+
constructor(key, scopeKind, scopeRefId) {
|
|
42
|
+
super(
|
|
43
|
+
`Setting "${key}" at scope ${scopeKind}:${scopeRefId ?? "null"} was modified concurrently. Reload the current value and retry.`,
|
|
44
|
+
"CONFLICT"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var CorruptError = class extends ConfTreeError {
|
|
49
|
+
constructor(valueId) {
|
|
50
|
+
super(
|
|
51
|
+
`setting value row ${valueId} has no typed value set: data corruption`,
|
|
52
|
+
"CORRUPT"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var CycleError = class extends ConfTreeError {
|
|
57
|
+
constructor(id, newParentId) {
|
|
58
|
+
super(
|
|
59
|
+
`Cannot attach/move scope "${id}" under "${newParentId}": would create a cycle`,
|
|
60
|
+
"CYCLE"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/cache/change-bus.ts
|
|
66
|
+
var LocalBus = class {
|
|
67
|
+
listeners = /* @__PURE__ */ new Set();
|
|
68
|
+
async publish(event) {
|
|
69
|
+
await Promise.all(
|
|
70
|
+
[...this.listeners].map(
|
|
71
|
+
(listener) => Promise.resolve(listener(event))
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
subscribe(listener) {
|
|
76
|
+
this.listeners.add(listener);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/cache/cache.ts
|
|
81
|
+
var DEFAULT_TTL_MS = 3e4;
|
|
82
|
+
var DEFAULT_MAX_ENTRIES = 5e4;
|
|
83
|
+
var Cache = class {
|
|
84
|
+
constructor(bus, options = {}, hierarchy) {
|
|
85
|
+
this.bus = bus;
|
|
86
|
+
this.options = options;
|
|
87
|
+
this.hierarchy = hierarchy;
|
|
88
|
+
this.bus.subscribe((event) => this.onChange(event));
|
|
89
|
+
}
|
|
90
|
+
bus;
|
|
91
|
+
options;
|
|
92
|
+
hierarchy;
|
|
93
|
+
store = /* @__PURE__ */ new Map();
|
|
94
|
+
get(key, scope) {
|
|
95
|
+
if (this.options.enabled === false) return void 0;
|
|
96
|
+
const cacheKey = this.keyFor(key, scope);
|
|
97
|
+
const entry = this.store.get(cacheKey);
|
|
98
|
+
if (!entry) return void 0;
|
|
99
|
+
if (entry.expiresAt <= Date.now()) {
|
|
100
|
+
this.store.delete(cacheKey);
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
return entry.value;
|
|
104
|
+
}
|
|
105
|
+
set(key, scope, value) {
|
|
106
|
+
if (this.options.enabled === false) return;
|
|
107
|
+
const cacheKey = this.keyFor(key, scope);
|
|
108
|
+
if (!this.store.has(cacheKey) && this.store.size >= (this.options.maxEntries ?? DEFAULT_MAX_ENTRIES)) {
|
|
109
|
+
const oldest = this.store.keys().next().value;
|
|
110
|
+
if (oldest !== void 0) this.store.delete(oldest);
|
|
111
|
+
}
|
|
112
|
+
const ttlMs = this.options.ttlMs ?? DEFAULT_TTL_MS;
|
|
113
|
+
this.store.set(cacheKey, {
|
|
114
|
+
key,
|
|
115
|
+
scopeKind: scope.kind,
|
|
116
|
+
scopeRefId: scope.refId,
|
|
117
|
+
value,
|
|
118
|
+
expiresAt: Date.now() + ttlMs
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
drop(key) {
|
|
122
|
+
for (const [cacheKey, entry] of this.store) {
|
|
123
|
+
if (entry.key === key) this.store.delete(cacheKey);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
dropAll() {
|
|
127
|
+
this.store.clear();
|
|
128
|
+
}
|
|
129
|
+
dropForScopes(scopeRefIds) {
|
|
130
|
+
const targets = new Set(scopeRefIds);
|
|
131
|
+
if (targets.size === 0) return;
|
|
132
|
+
for (const [cacheKey, entry] of this.store) {
|
|
133
|
+
if (entry.scopeRefId !== null && targets.has(entry.scopeRefId)) {
|
|
134
|
+
this.store.delete(cacheKey);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
dropScoped(key, scopeRefIds) {
|
|
139
|
+
const targets = new Set(scopeRefIds);
|
|
140
|
+
for (const [cacheKey, entry] of this.store) {
|
|
141
|
+
if (entry.key === key && entry.scopeRefId !== null && targets.has(entry.scopeRefId)) {
|
|
142
|
+
this.store.delete(cacheKey);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async onChange(event) {
|
|
147
|
+
if (this.hierarchy && event.scopeRefId !== null) {
|
|
148
|
+
const descendants = await this.hierarchy.descendants(event.scopeRefId).catch(() => null);
|
|
149
|
+
if (descendants !== null) {
|
|
150
|
+
this.dropScoped(event.key, descendants);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
this.drop(event.key);
|
|
155
|
+
}
|
|
156
|
+
keyFor(key, scope) {
|
|
157
|
+
return JSON.stringify([key, scope.kind, scope.refId]);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/hierarchy/scope-hierarchy.ts
|
|
162
|
+
var LocalScopeHierarchy = class {
|
|
163
|
+
parentOf = /* @__PURE__ */ new Map();
|
|
164
|
+
childrenOf = /* @__PURE__ */ new Map();
|
|
165
|
+
async chain(id) {
|
|
166
|
+
const result = [];
|
|
167
|
+
const seen = /* @__PURE__ */ new Set();
|
|
168
|
+
let current = id;
|
|
169
|
+
while (current !== null) {
|
|
170
|
+
if (seen.has(current)) break;
|
|
171
|
+
seen.add(current);
|
|
172
|
+
result.push(current);
|
|
173
|
+
current = this.parentOf.get(current) ?? null;
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
async descendants(id) {
|
|
178
|
+
const result = [];
|
|
179
|
+
const stack = [id];
|
|
180
|
+
const seen = /* @__PURE__ */ new Set();
|
|
181
|
+
while (stack.length > 0) {
|
|
182
|
+
const current = stack.pop();
|
|
183
|
+
if (seen.has(current)) continue;
|
|
184
|
+
seen.add(current);
|
|
185
|
+
result.push(current);
|
|
186
|
+
const kids = this.childrenOf.get(current);
|
|
187
|
+
if (kids) stack.push(...kids);
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
async children(id) {
|
|
192
|
+
return [...this.childrenOf.get(id) ?? []];
|
|
193
|
+
}
|
|
194
|
+
async parent(id) {
|
|
195
|
+
return this.parentOf.get(id) ?? null;
|
|
196
|
+
}
|
|
197
|
+
async attach(id, parentId) {
|
|
198
|
+
if (parentId !== null) await this.assertNoCycle(id, parentId);
|
|
199
|
+
this.parentOf.set(id, parentId);
|
|
200
|
+
if (parentId !== null) this.addChild(parentId, id);
|
|
201
|
+
if (!this.childrenOf.has(id)) this.childrenOf.set(id, /* @__PURE__ */ new Set());
|
|
202
|
+
}
|
|
203
|
+
async move(id, newParentId) {
|
|
204
|
+
if (newParentId !== null) await this.assertNoCycle(id, newParentId);
|
|
205
|
+
const oldParent = this.parentOf.get(id) ?? null;
|
|
206
|
+
if (oldParent !== null) this.childrenOf.get(oldParent)?.delete(id);
|
|
207
|
+
this.parentOf.set(id, newParentId);
|
|
208
|
+
if (newParentId !== null) this.addChild(newParentId, id);
|
|
209
|
+
}
|
|
210
|
+
async detach(id) {
|
|
211
|
+
const parentId = this.parentOf.get(id) ?? null;
|
|
212
|
+
const kids = [...this.childrenOf.get(id) ?? []];
|
|
213
|
+
for (const kid of kids) {
|
|
214
|
+
await this.move(kid, parentId);
|
|
215
|
+
}
|
|
216
|
+
if (parentId !== null) this.childrenOf.get(parentId)?.delete(id);
|
|
217
|
+
this.parentOf.delete(id);
|
|
218
|
+
this.childrenOf.delete(id);
|
|
219
|
+
}
|
|
220
|
+
addChild(parentId, id) {
|
|
221
|
+
if (!this.childrenOf.has(parentId))
|
|
222
|
+
this.childrenOf.set(parentId, /* @__PURE__ */ new Set());
|
|
223
|
+
this.childrenOf.get(parentId).add(id);
|
|
224
|
+
}
|
|
225
|
+
async assertNoCycle(id, newParentId) {
|
|
226
|
+
if (id === newParentId || (await this.chain(newParentId)).includes(id)) {
|
|
227
|
+
throw new CycleError(id, newParentId);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// src/storage/memory-storage.ts
|
|
233
|
+
function toTypedColumns(type, value) {
|
|
234
|
+
return {
|
|
235
|
+
bool: type === "BOOLEAN" ? value : null,
|
|
236
|
+
num: type === "NUMERIC" ? value : null,
|
|
237
|
+
text: type === "TEXT" || type === "ENUM" ? value : null,
|
|
238
|
+
json: type === "JSON" ? value : null,
|
|
239
|
+
jsonSet: type === "JSON",
|
|
240
|
+
date: type === "DATE" ? value : null
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
var MemoryStorageAdapter = class {
|
|
244
|
+
defs = [];
|
|
245
|
+
values = [];
|
|
246
|
+
auditLog = [];
|
|
247
|
+
nextId = 1;
|
|
248
|
+
txQueue = Promise.resolve();
|
|
249
|
+
newId(prefix) {
|
|
250
|
+
return `${prefix}-${this.nextId++}`;
|
|
251
|
+
}
|
|
252
|
+
async findDefs(keys) {
|
|
253
|
+
const result = [];
|
|
254
|
+
for (const key of keys) {
|
|
255
|
+
const found = this.latestByStatus(key, ["STABLE", "DEPRECATED"]);
|
|
256
|
+
if (found) result.push(found);
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
async findValues(query) {
|
|
261
|
+
const asOf = query.asOf ?? /* @__PURE__ */ new Date();
|
|
262
|
+
const ids = new Set(query.definitionIds);
|
|
263
|
+
return this.values.filter(
|
|
264
|
+
(v) => ids.has(v.definitionId) && v.scopeKind === query.scopeKind && v.scopeRefId === query.scopeRefId && v.validFrom <= asOf && (v.validTo === null || v.validTo > asOf)
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
async findChainValues(query) {
|
|
268
|
+
const asOf = query.asOf ?? /* @__PURE__ */ new Date();
|
|
269
|
+
const defIds = new Set(query.definitionIds);
|
|
270
|
+
const refIds = new Set(query.chain);
|
|
271
|
+
return this.values.filter(
|
|
272
|
+
(v) => defIds.has(v.definitionId) && v.scopeRefId !== null && refIds.has(v.scopeRefId) && v.validFrom <= asOf && (v.validTo === null || v.validTo > asOf)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
async findDefsByIds(ids) {
|
|
276
|
+
const idSet = new Set(ids);
|
|
277
|
+
return this.defs.filter((d) => idSet.has(d.id));
|
|
278
|
+
}
|
|
279
|
+
async findAnyDef(key) {
|
|
280
|
+
return this.latestVersion(key) ?? null;
|
|
281
|
+
}
|
|
282
|
+
async listValues(query) {
|
|
283
|
+
const now = /* @__PURE__ */ new Date();
|
|
284
|
+
const active = this.values.filter(
|
|
285
|
+
(v) => v.scopeKind === query.scopeKind && v.scopeRefId === query.scopeRefId && v.validFrom <= now && (v.validTo === null || v.validTo > now)
|
|
286
|
+
).sort((a, b) => a.id.localeCompare(b.id));
|
|
287
|
+
const startIndex = query.cursor ? active.findIndex((v) => v.id === query.cursor) + 1 : 0;
|
|
288
|
+
const limit = query.limit ?? active.length - startIndex;
|
|
289
|
+
const page = active.slice(startIndex, startIndex + limit);
|
|
290
|
+
const nextCursor = startIndex + page.length < active.length ? page[page.length - 1]?.id ?? null : null;
|
|
291
|
+
return { values: page, nextCursor };
|
|
292
|
+
}
|
|
293
|
+
async findAudit(query) {
|
|
294
|
+
return this.auditLog.filter(
|
|
295
|
+
(a) => a.definitionId === query.definitionId && (query.scopeKind === void 0 || a.scopeKind === query.scopeKind) && (query.scopeRefId === void 0 || a.scopeRefId === query.scopeRefId)
|
|
296
|
+
).sort((a, b) => a.at.getTime() - b.at.getTime());
|
|
297
|
+
}
|
|
298
|
+
async createDef(input) {
|
|
299
|
+
const existingVersions = this.defs.filter((d) => d.key === input.key);
|
|
300
|
+
const version = existingVersions.length > 0 ? Math.max(...existingVersions.map((d) => d.version)) + 1 : 1;
|
|
301
|
+
const record = {
|
|
302
|
+
id: this.newId("def"),
|
|
303
|
+
key: input.key,
|
|
304
|
+
version,
|
|
305
|
+
label: input.label,
|
|
306
|
+
description: input.description ?? null,
|
|
307
|
+
type: input.type,
|
|
308
|
+
options: input.options ?? [],
|
|
309
|
+
min: input.min ?? null,
|
|
310
|
+
max: input.max ?? null,
|
|
311
|
+
scopes: input.scopes,
|
|
312
|
+
inherit: input.inherit,
|
|
313
|
+
required: input.required,
|
|
314
|
+
secret: input.secret ?? false,
|
|
315
|
+
status: input.status ?? "DRAFT",
|
|
316
|
+
category: input.category ?? null
|
|
317
|
+
};
|
|
318
|
+
this.defs.push(record);
|
|
319
|
+
return record;
|
|
320
|
+
}
|
|
321
|
+
async updateDefStatus(key, status) {
|
|
322
|
+
const current = this.latestVersion(key);
|
|
323
|
+
if (!current) throw new NotFoundError(key);
|
|
324
|
+
current.status = status;
|
|
325
|
+
return current;
|
|
326
|
+
}
|
|
327
|
+
async listDefs(status) {
|
|
328
|
+
const rows = status ? this.defs.filter((d) => d.status === status) : this.defs;
|
|
329
|
+
return [...rows].sort(
|
|
330
|
+
(a, b) => (a.category ?? "").localeCompare(b.category ?? "") || a.key.localeCompare(b.key)
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
async transact(fn) {
|
|
334
|
+
const run = this.txQueue.then(() => fn(this.tx()));
|
|
335
|
+
this.txQueue = run.catch(() => {
|
|
336
|
+
});
|
|
337
|
+
return run;
|
|
338
|
+
}
|
|
339
|
+
latestByStatus(key, statuses) {
|
|
340
|
+
const latest = this.latestVersion(key);
|
|
341
|
+
return latest && statuses.includes(latest.status) ? latest : void 0;
|
|
342
|
+
}
|
|
343
|
+
latestVersion(key) {
|
|
344
|
+
return this.defs.filter((d) => d.key === key).sort((a, b) => b.version - a.version)[0];
|
|
345
|
+
}
|
|
346
|
+
tx() {
|
|
347
|
+
return {
|
|
348
|
+
findDef: async (key) => this.latestByStatus(key, ["STABLE"]) ?? null,
|
|
349
|
+
findValue: async (definitionId, scopeKind, scopeRefId) => this.values.find(
|
|
350
|
+
(v) => v.definitionId === definitionId && v.scopeKind === scopeKind && v.scopeRefId === scopeRefId && v.validTo === null
|
|
351
|
+
) ?? null,
|
|
352
|
+
closeValue: async (id) => {
|
|
353
|
+
const row = this.values.find((v) => v.id === id);
|
|
354
|
+
if (row) row.validTo = /* @__PURE__ */ new Date();
|
|
355
|
+
},
|
|
356
|
+
createValue: async (input) => {
|
|
357
|
+
const record = {
|
|
358
|
+
id: this.newId("val"),
|
|
359
|
+
definitionId: input.definitionId,
|
|
360
|
+
scopeKind: input.scopeKind,
|
|
361
|
+
scopeRefId: input.scopeRefId,
|
|
362
|
+
version: input.version,
|
|
363
|
+
validFrom: /* @__PURE__ */ new Date(),
|
|
364
|
+
validTo: null,
|
|
365
|
+
...toTypedColumns(input.type, input.value)
|
|
366
|
+
};
|
|
367
|
+
this.values.push(record);
|
|
368
|
+
return record;
|
|
369
|
+
},
|
|
370
|
+
createAudit: async (input) => {
|
|
371
|
+
this.auditLog.push({
|
|
372
|
+
...input,
|
|
373
|
+
id: this.newId("audit"),
|
|
374
|
+
at: /* @__PURE__ */ new Date()
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/engine/resolver.ts
|
|
382
|
+
var Resolver = class {
|
|
383
|
+
constructor(storage, hierarchy, cache) {
|
|
384
|
+
this.storage = storage;
|
|
385
|
+
this.hierarchy = hierarchy;
|
|
386
|
+
this.cache = cache;
|
|
387
|
+
}
|
|
388
|
+
storage;
|
|
389
|
+
hierarchy;
|
|
390
|
+
cache;
|
|
391
|
+
async get(key, scope, asOf) {
|
|
392
|
+
const result = await this.getMany([key], scope, asOf);
|
|
393
|
+
return result[key];
|
|
394
|
+
}
|
|
395
|
+
async listAt(scope, opts = {}) {
|
|
396
|
+
const { values, nextCursor } = await this.storage.listValues({
|
|
397
|
+
scopeKind: scope.kind,
|
|
398
|
+
scopeRefId: scope.refId,
|
|
399
|
+
limit: opts.limit,
|
|
400
|
+
cursor: opts.cursor
|
|
401
|
+
});
|
|
402
|
+
if (values.length === 0) return { entries: {}, nextCursor };
|
|
403
|
+
const defs = await this.storage.findDefsByIds([
|
|
404
|
+
...new Set(values.map((v) => v.definitionId))
|
|
405
|
+
]);
|
|
406
|
+
const defById = new Map(defs.map((d) => [d.id, d]));
|
|
407
|
+
const entries = {};
|
|
408
|
+
for (const row of values) {
|
|
409
|
+
const def = defById.get(row.definitionId);
|
|
410
|
+
if (!def) continue;
|
|
411
|
+
entries[def.key] = this.unwrap(def, row);
|
|
412
|
+
}
|
|
413
|
+
return { entries, nextCursor };
|
|
414
|
+
}
|
|
415
|
+
async getMany(keys, scope, asOf) {
|
|
416
|
+
const uniqueKeys = [...new Set(keys)];
|
|
417
|
+
const result = {};
|
|
418
|
+
const uncached = [];
|
|
419
|
+
if (asOf === void 0) {
|
|
420
|
+
for (const key of uniqueKeys) {
|
|
421
|
+
const cached = this.cache?.get(key, scope);
|
|
422
|
+
if (cached !== void 0) result[key] = cached;
|
|
423
|
+
else uncached.push(key);
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
uncached.push(...uniqueKeys);
|
|
427
|
+
}
|
|
428
|
+
if (uncached.length === 0) return result;
|
|
429
|
+
const defByKey = await this.getDefs(uncached);
|
|
430
|
+
for (const key of uncached) {
|
|
431
|
+
this.checkScope(defByKey.get(key), scope);
|
|
432
|
+
}
|
|
433
|
+
const exactDefs = [];
|
|
434
|
+
const chainDefs = [];
|
|
435
|
+
for (const key of uncached) {
|
|
436
|
+
const def = defByKey.get(key);
|
|
437
|
+
const climbsHierarchy = def.inherit !== "INDEPENDENT" && scope.refId !== null && this.hierarchy;
|
|
438
|
+
(climbsHierarchy ? chainDefs : exactDefs).push(def);
|
|
439
|
+
}
|
|
440
|
+
const chain = chainDefs.length > 0 && scope.refId !== null && this.hierarchy ? await this.hierarchy.chain(scope.refId) : [];
|
|
441
|
+
const [exactRows, chainRows] = await Promise.all([
|
|
442
|
+
exactDefs.length > 0 ? this.storage.findValues({
|
|
443
|
+
definitionIds: exactDefs.map((d) => d.id),
|
|
444
|
+
scopeKind: scope.kind,
|
|
445
|
+
scopeRefId: scope.refId,
|
|
446
|
+
asOf
|
|
447
|
+
}) : Promise.resolve([]),
|
|
448
|
+
chainDefs.length > 0 && chain.length > 0 ? this.storage.findChainValues({
|
|
449
|
+
definitionIds: chainDefs.map((d) => d.id),
|
|
450
|
+
chain,
|
|
451
|
+
asOf
|
|
452
|
+
}) : Promise.resolve([])
|
|
453
|
+
]);
|
|
454
|
+
const exactByDef = new Map(exactRows.map((r) => [r.definitionId, r]));
|
|
455
|
+
const chainByDef = /* @__PURE__ */ new Map();
|
|
456
|
+
for (const row of chainRows) {
|
|
457
|
+
const list = chainByDef.get(row.definitionId) ?? [];
|
|
458
|
+
list.push(row);
|
|
459
|
+
chainByDef.set(row.definitionId, list);
|
|
460
|
+
}
|
|
461
|
+
const chainDefIds = new Set(chainDefs.map((d) => d.id));
|
|
462
|
+
const missing = [];
|
|
463
|
+
for (const key of uncached) {
|
|
464
|
+
const def = defByKey.get(key);
|
|
465
|
+
let row;
|
|
466
|
+
if (chainDefIds.has(def.id)) {
|
|
467
|
+
const byRef = new Map(
|
|
468
|
+
(chainByDef.get(def.id) ?? []).map((v) => [
|
|
469
|
+
v.scopeRefId,
|
|
470
|
+
v
|
|
471
|
+
])
|
|
472
|
+
);
|
|
473
|
+
for (const ref of chain) {
|
|
474
|
+
row = byRef.get(ref);
|
|
475
|
+
if (row) break;
|
|
476
|
+
}
|
|
477
|
+
} else {
|
|
478
|
+
row = exactByDef.get(def.id);
|
|
479
|
+
}
|
|
480
|
+
if (row) {
|
|
481
|
+
result[key] = this.unwrap(def, row);
|
|
482
|
+
if (asOf === void 0)
|
|
483
|
+
this.cache?.set(key, scope, result[key]);
|
|
484
|
+
} else {
|
|
485
|
+
missing.push(def);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (missing.length > 0)
|
|
489
|
+
await this.resolveMissing(
|
|
490
|
+
missing,
|
|
491
|
+
scope,
|
|
492
|
+
uncached,
|
|
493
|
+
defByKey,
|
|
494
|
+
result,
|
|
495
|
+
asOf
|
|
496
|
+
);
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
499
|
+
async resolveMissing(missing, scope, keysInOrder, defByKey, result, asOf) {
|
|
500
|
+
const defaultRows = await this.storage.findValues({
|
|
501
|
+
definitionIds: missing.map((d) => d.id),
|
|
502
|
+
scopeKind: DEFAULT_SCOPE.kind,
|
|
503
|
+
scopeRefId: DEFAULT_SCOPE.refId
|
|
504
|
+
});
|
|
505
|
+
const defaultByDef = new Map(
|
|
506
|
+
defaultRows.map((r) => [r.definitionId, r])
|
|
507
|
+
);
|
|
508
|
+
const missingIds = new Set(missing.map((d) => d.id));
|
|
509
|
+
for (const key of keysInOrder) {
|
|
510
|
+
const def = defByKey.get(key);
|
|
511
|
+
if (!missingIds.has(def.id)) continue;
|
|
512
|
+
const row = defaultByDef.get(def.id);
|
|
513
|
+
if (!row) {
|
|
514
|
+
throw new RequiredError(def.key, scope.kind, scope.refId);
|
|
515
|
+
}
|
|
516
|
+
result[key] = this.unwrap(def, row);
|
|
517
|
+
if (asOf === void 0) this.cache?.set(key, scope, result[key]);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async getDefs(keys) {
|
|
521
|
+
const defs = await this.storage.findDefs(keys);
|
|
522
|
+
const byKey = new Map(defs.map((d) => [d.key, d]));
|
|
523
|
+
for (const key of keys) {
|
|
524
|
+
if (!byKey.has(key)) throw new NotFoundError(key);
|
|
525
|
+
}
|
|
526
|
+
return byKey;
|
|
527
|
+
}
|
|
528
|
+
checkScope(def, scope) {
|
|
529
|
+
if (scope.kind === "default") return;
|
|
530
|
+
if (!def.scopes.includes(scope.kind)) {
|
|
531
|
+
throw new ScopeError(def.key, scope.kind);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
unwrap(def, row) {
|
|
535
|
+
switch (def.type) {
|
|
536
|
+
case "BOOLEAN":
|
|
537
|
+
if (row.bool === null) throw new CorruptError(row.id);
|
|
538
|
+
return row.bool;
|
|
539
|
+
case "NUMERIC":
|
|
540
|
+
if (row.num === null) throw new CorruptError(row.id);
|
|
541
|
+
return row.num;
|
|
542
|
+
case "TEXT":
|
|
543
|
+
case "ENUM":
|
|
544
|
+
if (row.text === null) throw new CorruptError(row.id);
|
|
545
|
+
return row.text;
|
|
546
|
+
case "JSON":
|
|
547
|
+
if (!row.jsonSet) throw new CorruptError(row.id);
|
|
548
|
+
return row.json;
|
|
549
|
+
case "DATE":
|
|
550
|
+
if (row.date === null) throw new CorruptError(row.id);
|
|
551
|
+
return row.date;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// src/engine/writer.ts
|
|
557
|
+
var REDACTED = "[redacted]";
|
|
558
|
+
var Writer = class {
|
|
559
|
+
constructor(storage, bus) {
|
|
560
|
+
this.storage = storage;
|
|
561
|
+
this.bus = bus;
|
|
562
|
+
}
|
|
563
|
+
storage;
|
|
564
|
+
bus;
|
|
565
|
+
async set(params) {
|
|
566
|
+
const created = await this.storage.transact(
|
|
567
|
+
(tx) => this.setInTx(tx, params)
|
|
568
|
+
);
|
|
569
|
+
await this.emit(created, params.key);
|
|
570
|
+
return created;
|
|
571
|
+
}
|
|
572
|
+
async setMany(paramsList) {
|
|
573
|
+
const created = await this.storage.transact(async (tx) => {
|
|
574
|
+
const results = [];
|
|
575
|
+
for (const params of paramsList) {
|
|
576
|
+
results.push(await this.setInTx(tx, params));
|
|
577
|
+
}
|
|
578
|
+
return results;
|
|
579
|
+
});
|
|
580
|
+
await Promise.all(
|
|
581
|
+
created.map((row, i) => this.emit(row, paramsList[i].key))
|
|
582
|
+
);
|
|
583
|
+
return created;
|
|
584
|
+
}
|
|
585
|
+
async setInTx(tx, params) {
|
|
586
|
+
const def = await tx.findDef(params.key);
|
|
587
|
+
if (!def) throw new NotFoundError(params.key);
|
|
588
|
+
if (params.scope.kind !== "default" && !def.scopes.includes(params.scope.kind)) {
|
|
589
|
+
throw new ScopeError(def.key, params.scope.kind);
|
|
590
|
+
}
|
|
591
|
+
this.validate(def, params.value);
|
|
592
|
+
const current = await tx.findValue(
|
|
593
|
+
def.id,
|
|
594
|
+
params.scope.kind,
|
|
595
|
+
params.scope.refId
|
|
596
|
+
);
|
|
597
|
+
const currentVersion = current?.version ?? 0;
|
|
598
|
+
const expected = params.expectedVersion ?? 0;
|
|
599
|
+
if (currentVersion !== expected) {
|
|
600
|
+
throw new ConflictError(
|
|
601
|
+
def.key,
|
|
602
|
+
params.scope.kind,
|
|
603
|
+
params.scope.refId
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
if (current) {
|
|
607
|
+
await tx.closeValue(current.id);
|
|
608
|
+
}
|
|
609
|
+
const created = await tx.createValue({
|
|
610
|
+
definitionId: def.id,
|
|
611
|
+
scopeKind: params.scope.kind,
|
|
612
|
+
scopeRefId: params.scope.refId,
|
|
613
|
+
version: currentVersion + 1,
|
|
614
|
+
authorId: params.authorId,
|
|
615
|
+
reason: params.reason,
|
|
616
|
+
type: def.type,
|
|
617
|
+
value: params.value
|
|
618
|
+
});
|
|
619
|
+
await tx.createAudit({
|
|
620
|
+
valueId: created.id,
|
|
621
|
+
definitionId: def.id,
|
|
622
|
+
scopeKind: created.scopeKind,
|
|
623
|
+
scopeRefId: created.scopeRefId,
|
|
624
|
+
action: current ? "superseded" : "created",
|
|
625
|
+
authorId: params.authorId,
|
|
626
|
+
before: current ? this.snapshotOf(def, current) : void 0,
|
|
627
|
+
after: this.snapshotOf(def, created),
|
|
628
|
+
reason: params.reason
|
|
629
|
+
});
|
|
630
|
+
return created;
|
|
631
|
+
}
|
|
632
|
+
async unset(params) {
|
|
633
|
+
const closed = await this.storage.transact(
|
|
634
|
+
(tx) => this.unsetInTx(tx, params)
|
|
635
|
+
);
|
|
636
|
+
if (closed) await this.emit(closed, params.key);
|
|
637
|
+
}
|
|
638
|
+
async unsetInTx(tx, params) {
|
|
639
|
+
const def = await tx.findDef(params.key);
|
|
640
|
+
if (!def) throw new NotFoundError(params.key);
|
|
641
|
+
if (params.scope.kind !== "default" && !def.scopes.includes(params.scope.kind)) {
|
|
642
|
+
throw new ScopeError(def.key, params.scope.kind);
|
|
643
|
+
}
|
|
644
|
+
const current = await tx.findValue(
|
|
645
|
+
def.id,
|
|
646
|
+
params.scope.kind,
|
|
647
|
+
params.scope.refId
|
|
648
|
+
);
|
|
649
|
+
const currentVersion = current?.version ?? 0;
|
|
650
|
+
const expected = params.expectedVersion ?? 0;
|
|
651
|
+
if (currentVersion !== expected) {
|
|
652
|
+
throw new ConflictError(
|
|
653
|
+
def.key,
|
|
654
|
+
params.scope.kind,
|
|
655
|
+
params.scope.refId
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
if (!current) return null;
|
|
659
|
+
await tx.closeValue(current.id);
|
|
660
|
+
await tx.createAudit({
|
|
661
|
+
valueId: current.id,
|
|
662
|
+
definitionId: def.id,
|
|
663
|
+
scopeKind: current.scopeKind,
|
|
664
|
+
scopeRefId: current.scopeRefId,
|
|
665
|
+
action: "unset",
|
|
666
|
+
authorId: params.authorId,
|
|
667
|
+
before: this.snapshotOf(def, current),
|
|
668
|
+
reason: params.reason
|
|
669
|
+
});
|
|
670
|
+
return current;
|
|
671
|
+
}
|
|
672
|
+
async emit(created, key) {
|
|
673
|
+
await this.bus?.publish({
|
|
674
|
+
definitionId: created.definitionId,
|
|
675
|
+
key,
|
|
676
|
+
scopeKind: created.scopeKind,
|
|
677
|
+
scopeRefId: created.scopeRefId
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
validate(def, value) {
|
|
681
|
+
switch (def.type) {
|
|
682
|
+
case "BOOLEAN":
|
|
683
|
+
if (typeof value !== "boolean") {
|
|
684
|
+
throw new ValueError(
|
|
685
|
+
`Setting "${def.key}" expects a boolean`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
break;
|
|
689
|
+
case "NUMERIC": {
|
|
690
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
691
|
+
throw new ValueError(
|
|
692
|
+
`Setting "${def.key}" expects a finite number`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
if (def.min !== null && value < def.min) {
|
|
696
|
+
throw new ValueError(
|
|
697
|
+
`Setting "${def.key}" must be >= ${def.min}, got ${value}`
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
if (def.max !== null && value > def.max) {
|
|
701
|
+
throw new ValueError(
|
|
702
|
+
`Setting "${def.key}" must be <= ${def.max}, got ${value}`
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
case "TEXT":
|
|
708
|
+
if (typeof value !== "string") {
|
|
709
|
+
throw new ValueError(
|
|
710
|
+
`Setting "${def.key}" expects a string`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
case "ENUM":
|
|
715
|
+
if (typeof value !== "string" || !def.options.includes(value)) {
|
|
716
|
+
throw new ValueError(
|
|
717
|
+
`Setting "${def.key}" must be one of: ${def.options.join(", ")}`
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
break;
|
|
721
|
+
case "JSON":
|
|
722
|
+
try {
|
|
723
|
+
JSON.stringify(value);
|
|
724
|
+
} catch {
|
|
725
|
+
throw new ValueError(
|
|
726
|
+
`Setting "${def.key}" expects a JSON-serializable value`
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
break;
|
|
730
|
+
case "DATE":
|
|
731
|
+
if (!(value instanceof Date) || Number.isNaN(value.getTime())) {
|
|
732
|
+
throw new ValueError(
|
|
733
|
+
`Setting "${def.key}" expects a valid Date`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
snapshotOf(def, row) {
|
|
740
|
+
if (def.secret) {
|
|
741
|
+
return {
|
|
742
|
+
scopeKind: row.scopeKind,
|
|
743
|
+
scopeRefId: row.scopeRefId,
|
|
744
|
+
version: row.version,
|
|
745
|
+
value: REDACTED
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
return {
|
|
749
|
+
scopeKind: row.scopeKind,
|
|
750
|
+
scopeRefId: row.scopeRefId,
|
|
751
|
+
version: row.version,
|
|
752
|
+
bool: row.bool,
|
|
753
|
+
num: row.num,
|
|
754
|
+
text: row.text,
|
|
755
|
+
json: row.jsonSet ? row.json : void 0,
|
|
756
|
+
date: row.date
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
// src/engine/auditor.ts
|
|
762
|
+
var Auditor = class {
|
|
763
|
+
constructor(storage) {
|
|
764
|
+
this.storage = storage;
|
|
765
|
+
}
|
|
766
|
+
storage;
|
|
767
|
+
async history(key, scope) {
|
|
768
|
+
const def = await this.storage.findAnyDef(key);
|
|
769
|
+
if (!def) throw new NotFoundError(key);
|
|
770
|
+
return this.storage.findAudit({
|
|
771
|
+
definitionId: def.id,
|
|
772
|
+
scopeKind: scope?.kind,
|
|
773
|
+
scopeRefId: scope?.refId
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
// src/engine/hierarchy-cache-sync.ts
|
|
779
|
+
function withHierarchyInvalidation(hierarchy, cache) {
|
|
780
|
+
return {
|
|
781
|
+
chain: (id) => hierarchy.chain(id),
|
|
782
|
+
descendants: (id) => hierarchy.descendants(id),
|
|
783
|
+
children: (id) => hierarchy.children(id),
|
|
784
|
+
parent: (id) => hierarchy.parent(id),
|
|
785
|
+
attach: async (id, parentId) => {
|
|
786
|
+
await hierarchy.attach(id, parentId);
|
|
787
|
+
cache.dropForScopes(await hierarchy.descendants(id));
|
|
788
|
+
},
|
|
789
|
+
move: async (id, newParentId) => {
|
|
790
|
+
const descendants = await hierarchy.descendants(id);
|
|
791
|
+
await hierarchy.move(id, newParentId);
|
|
792
|
+
cache.dropForScopes(descendants);
|
|
793
|
+
},
|
|
794
|
+
detach: async (id) => {
|
|
795
|
+
const descendants = await hierarchy.descendants(id);
|
|
796
|
+
await hierarchy.detach(id);
|
|
797
|
+
cache.dropForScopes(descendants);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/engine/engine.ts
|
|
803
|
+
function createEngine(options = {}) {
|
|
804
|
+
const storage = options.storage ?? new MemoryStorageAdapter();
|
|
805
|
+
const rawHierarchy = options.hierarchy ?? new LocalScopeHierarchy();
|
|
806
|
+
const bus = options.bus ?? new LocalBus();
|
|
807
|
+
const cacheOptions = options.cache === false ? { enabled: false } : options.cache ?? {};
|
|
808
|
+
const cache = new Cache(bus, cacheOptions, rawHierarchy);
|
|
809
|
+
const hierarchy = withHierarchyInvalidation(rawHierarchy, cache);
|
|
810
|
+
const resolver = new Resolver(storage, hierarchy, cache);
|
|
811
|
+
const writer = new Writer(storage, bus);
|
|
812
|
+
const auditor = new Auditor(storage);
|
|
813
|
+
return { storage, hierarchy, bus, cache, resolver, writer, auditor };
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/typed/typed-resolver.ts
|
|
817
|
+
var TypedResolver = class {
|
|
818
|
+
constructor(resolver) {
|
|
819
|
+
this.resolver = resolver;
|
|
820
|
+
}
|
|
821
|
+
resolver;
|
|
822
|
+
get(key, scope, asOf) {
|
|
823
|
+
return this.resolver.get(key, scope, asOf);
|
|
824
|
+
}
|
|
825
|
+
async getMany(keys, scope, asOf) {
|
|
826
|
+
const result = await this.resolver.getMany([...keys], scope, asOf);
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
async listAt(scope, opts = {}) {
|
|
830
|
+
const page = await this.resolver.listAt(scope, opts);
|
|
831
|
+
return page;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
// src/typed/typed-writer.ts
|
|
836
|
+
var TypedWriter = class {
|
|
837
|
+
constructor(writer) {
|
|
838
|
+
this.writer = writer;
|
|
839
|
+
}
|
|
840
|
+
writer;
|
|
841
|
+
set(params) {
|
|
842
|
+
return this.writer.set(params);
|
|
843
|
+
}
|
|
844
|
+
setMany(paramsList) {
|
|
845
|
+
return this.writer.setMany(paramsList);
|
|
846
|
+
}
|
|
847
|
+
unset(params) {
|
|
848
|
+
return this.writer.unset(params);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
// src/typed/typed-auditor.ts
|
|
853
|
+
var TypedAuditor = class {
|
|
854
|
+
constructor(auditor) {
|
|
855
|
+
this.auditor = auditor;
|
|
856
|
+
}
|
|
857
|
+
auditor;
|
|
858
|
+
history(key, scope) {
|
|
859
|
+
return this.auditor.history(key, scope);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// src/typed/typed-engine.ts
|
|
864
|
+
function createTypedEngine(engine) {
|
|
865
|
+
return {
|
|
866
|
+
resolver: new TypedResolver(engine.resolver),
|
|
867
|
+
writer: new TypedWriter(engine.writer),
|
|
868
|
+
auditor: new TypedAuditor(engine.auditor)
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
export {
|
|
872
|
+
Auditor,
|
|
873
|
+
Cache,
|
|
874
|
+
ConfTreeError,
|
|
875
|
+
ConflictError,
|
|
876
|
+
CorruptError,
|
|
877
|
+
CycleError,
|
|
878
|
+
DEFAULT_SCOPE,
|
|
879
|
+
LocalBus,
|
|
880
|
+
LocalScopeHierarchy,
|
|
881
|
+
MemoryStorageAdapter,
|
|
882
|
+
NotFoundError,
|
|
883
|
+
RequiredError,
|
|
884
|
+
Resolver,
|
|
885
|
+
ScopeError,
|
|
886
|
+
TypedAuditor,
|
|
887
|
+
TypedResolver,
|
|
888
|
+
TypedWriter,
|
|
889
|
+
ValueError,
|
|
890
|
+
Writer,
|
|
891
|
+
createEngine,
|
|
892
|
+
createTypedEngine,
|
|
893
|
+
withHierarchyInvalidation
|
|
894
|
+
};
|
|
895
|
+
//# sourceMappingURL=index.mjs.map
|