@milaboratories/pl-tree 1.3.6 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,737 @@
1
+ var P = Object.defineProperty;
2
+ var N = (a, e, t) => e in a ? P(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
3
+ var u = (a, e, t) => N(a, typeof e != "symbol" ? e + "" : e, t);
4
+ import { resourceIdToString as m, resourceTypeToString as F, resourceTypesEqual as S, isNotNullResourceId as g, NullResourceId as R, isNullResourceId as A, stringifyWithResourceId as L, isTimeoutOrCancelError as W } from "@milaboratories/pl-client";
5
+ import { ChangeSource as y, PollingComputableHooks as U } from "@milaboratories/computable";
6
+ import { notEmpty as p } from "@milaboratories/ts-helpers";
7
+ import K from "denque";
8
+ import * as J from "node:timers/promises";
9
+ function X(a, e) {
10
+ if (a !== void 0)
11
+ return x(a, e);
12
+ }
13
+ function x(a, e) {
14
+ const t = {};
15
+ return a.value !== void 0 && (t.value = e(a.value)), a.error !== void 0 && (t.error = e(a.error)), t;
16
+ }
17
+ class O extends Error {
18
+ constructor(e) {
19
+ super(e);
20
+ }
21
+ }
22
+ function Z(a) {
23
+ return typeof a == "object" && a !== null && a.__pl_tree_type_marker__ === "PlTreeEntry";
24
+ }
25
+ function ee(a) {
26
+ return typeof a == "object" && a !== null && a.__pl_tree_type_marker__ === "PlTreeEntryAccessor";
27
+ }
28
+ function te(a) {
29
+ return typeof a == "object" && a !== null && a.__pl_tree_type_marker__ === "PlTreeNodeAccessor";
30
+ }
31
+ class k {
32
+ constructor(e, t) {
33
+ u(this, "__pl_tree_type_marker__", "PlTreeEntry");
34
+ this.accessorData = e, this.rid = t;
35
+ }
36
+ createAccessor(e, t) {
37
+ return new E(this.accessorData, this.accessorData.treeProvider(), this.rid, {
38
+ ctx: e,
39
+ guard: t
40
+ });
41
+ }
42
+ toJSON() {
43
+ return this.toString();
44
+ }
45
+ toString() {
46
+ return `[ENTRY:${m(this.rid)}]`;
47
+ }
48
+ }
49
+ function $(a, e, t, r, s) {
50
+ const c = new M(
51
+ a,
52
+ e,
53
+ e.get(t.ctx.watcher, r),
54
+ t
55
+ );
56
+ if (!s.ignoreError) {
57
+ const n = c.getError();
58
+ if (n !== void 0)
59
+ throw new O(
60
+ `error encountered on resource ${m(c.id)} (${F(c.resourceType)}): ${n.getDataAsString()}`
61
+ );
62
+ }
63
+ if (s.assertResourceType !== void 0 && (Array.isArray(s.assertResourceType) ? s.assertResourceType.findIndex((n) => S(n, c.resourceType)) === -1 : !S(s.assertResourceType, c.resourceType)))
64
+ throw new Error(
65
+ `wrong resource type ${F(c.resourceType)} but expected ${s.assertResourceType}`
66
+ );
67
+ return c;
68
+ }
69
+ class E {
70
+ constructor(e, t, r, s) {
71
+ u(this, "__pl_tree_type_marker__", "PlTreeEntryAccessor");
72
+ this.accessorData = e, this.tree = t, this.rid = r, this.instanceData = s;
73
+ }
74
+ node(e = {}) {
75
+ return this.instanceData.guard(), this.accessorData.hooks !== void 0 && this.instanceData.ctx.attacheHooks(this.accessorData.hooks), $(this.accessorData, this.tree, this.instanceData, this.rid, e);
76
+ }
77
+ }
78
+ function re(a, e) {
79
+ return a instanceof k ? e.accessor(a).node().resourceInfo : a;
80
+ }
81
+ class M {
82
+ constructor(e, t, r, s) {
83
+ u(this, "__pl_tree_type_marker__", "PlTreeNodeAccessor");
84
+ u(this, "onUnstableLambda", (e) => {
85
+ this.instanceData.ctx.markUnstable(e);
86
+ });
87
+ this.accessorData = e, this.tree = t, this.resource = r, this.instanceData = s;
88
+ }
89
+ get id() {
90
+ return this.instanceData.guard(), this.resource.id;
91
+ }
92
+ get originalId() {
93
+ return this.instanceData.guard(), this.resource.originalResourceId;
94
+ }
95
+ get resourceType() {
96
+ return this.instanceData.guard(), this.resource.type;
97
+ }
98
+ get resourceInfo() {
99
+ return { id: this.id, type: this.resourceType };
100
+ }
101
+ getResourceFromTree(e, t) {
102
+ return $(this.accessorData, this.tree, this.instanceData, e, t);
103
+ }
104
+ traverse(...e) {
105
+ return this.traverseWithCommon({}, ...e);
106
+ }
107
+ traverseOrError(...e) {
108
+ return this.traverseOrErrorWithCommon({}, ...e);
109
+ }
110
+ traverseWithCommon(e, ...t) {
111
+ const r = this.traverseOrErrorWithCommon(e, ...t);
112
+ if (r !== void 0) {
113
+ if (!r.ok) throw new O(r.error);
114
+ return r.value;
115
+ }
116
+ }
117
+ traverseOrErrorWithCommon(e, ...t) {
118
+ let r = this;
119
+ for (const s of t) {
120
+ const c = typeof s == "string" ? {
121
+ ...e,
122
+ field: s
123
+ } : { ...e, ...s }, n = r.getField(s);
124
+ if (n === void 0 || c.pureFieldErrorToUndefined && n.value === void 0 && n.error !== void 0)
125
+ return;
126
+ if ((!c.ignoreError || n.value === void 0) && n.error !== void 0)
127
+ return {
128
+ ok: !1,
129
+ error: `error in field ${c.field} of ${m(r.id)}: ${n.error.getDataAsString()}`
130
+ };
131
+ if (n.value === void 0) {
132
+ if (c.errorIfFieldNotSet)
133
+ return {
134
+ ok: !1,
135
+ error: `field have no assigned value ${c.field} of ${m(r.id)}`
136
+ };
137
+ this.onUnstableLambda("unpopulated_field:" + c.field);
138
+ return;
139
+ }
140
+ r = n.value;
141
+ }
142
+ return { ok: !0, value: r };
143
+ }
144
+ getField(e) {
145
+ this.instanceData.guard();
146
+ const t = typeof e == "string" ? { field: e } : e, r = this.resource.getField(this.instanceData.ctx.watcher, t, this.onUnstableLambda);
147
+ if (r !== void 0)
148
+ return x(r, (s) => this.getResourceFromTree(s, { ignoreError: !0 }));
149
+ }
150
+ getInputsLocked() {
151
+ this.instanceData.guard();
152
+ const e = this.resource.getInputsLocked(this.instanceData.ctx.watcher);
153
+ return e || this.instanceData.ctx.markUnstable("inputs_unlocked:" + this.resourceType.name), e;
154
+ }
155
+ getOutputsLocked() {
156
+ this.instanceData.guard();
157
+ const e = this.resource.getOutputsLocked(this.instanceData.ctx.watcher);
158
+ return e || this.instanceData.ctx.markUnstable("outputs_unlocked:" + this.resourceType.name), e;
159
+ }
160
+ getIsReadyOrError() {
161
+ this.instanceData.guard();
162
+ const e = this.resource.getIsReadyOrError(this.instanceData.ctx.watcher);
163
+ return e || this.instanceData.ctx.markUnstable("not_ready:" + this.resourceType.name), e;
164
+ }
165
+ getIsFinal() {
166
+ return this.instanceData.guard(), this.resource.getIsFinal(this.instanceData.ctx.watcher);
167
+ }
168
+ getError() {
169
+ this.instanceData.guard();
170
+ const e = this.resource.getError(this.instanceData.ctx.watcher);
171
+ if (e !== void 0)
172
+ return this.getResourceFromTree(e, {});
173
+ }
174
+ getData() {
175
+ return this.resource.data;
176
+ }
177
+ getDataAsString() {
178
+ return this.resource.getDataAsString();
179
+ }
180
+ getDataAsJson() {
181
+ return this.resource.getDataAsJson();
182
+ }
183
+ listInputFields() {
184
+ return this.instanceData.guard(), this.getInputsLocked(), this.resource.listInputFields(this.instanceData.ctx.watcher);
185
+ }
186
+ listOutputFields() {
187
+ return this.instanceData.guard(), this.getOutputsLocked(), this.resource.listOutputFields(this.instanceData.ctx.watcher);
188
+ }
189
+ listDynamicFields() {
190
+ return this.instanceData.guard(), this.resource.listDynamicFields(this.instanceData.ctx.watcher);
191
+ }
192
+ getKeyValue(e, t = !1) {
193
+ this.instanceData.guard();
194
+ const r = this.resource.getKeyValue(this.instanceData.ctx.watcher, e);
195
+ return r === void 0 && t && this.instanceData.ctx.markUnstable("key_not_found_b:" + e), r;
196
+ }
197
+ /** @deprecated */
198
+ getKeyValueString(e) {
199
+ return this.getKeyValueAsString(e);
200
+ }
201
+ getKeyValueAsString(e, t = !1) {
202
+ this.instanceData.guard();
203
+ const r = this.resource.getKeyValueString(this.instanceData.ctx.watcher, e);
204
+ return r === void 0 && t && this.instanceData.ctx.markUnstable("key_not_found_s:" + e), r;
205
+ }
206
+ getKeyValueAsJson(e, t = !1) {
207
+ const r = this.resource.getKeyValueString(this.instanceData.ctx.watcher, e);
208
+ if (r === void 0) {
209
+ t && this.instanceData.ctx.markUnstable("key_not_found_j:" + e);
210
+ return;
211
+ }
212
+ return JSON.parse(r);
213
+ }
214
+ /**
215
+ * Can be used to passe a higher level accessor that will wrap the resource and throw its
216
+ * errors on node resolution.
217
+ * */
218
+ toEntryAccessor() {
219
+ return new E(this.accessorData, this.tree, this.id, this.instanceData);
220
+ }
221
+ /** Can be passed to nested computable. */
222
+ persist() {
223
+ return new k(this.accessorData, this.resource.id);
224
+ }
225
+ }
226
+ class w extends Error {
227
+ constructor(e) {
228
+ super(e);
229
+ }
230
+ }
231
+ class T {
232
+ constructor(e, t, r, s) {
233
+ u(this, "change", new y());
234
+ this.type = e, this.value = t, this.error = r, this.resourceVersion = s;
235
+ }
236
+ }
237
+ const D = 0, _ = new TextDecoder();
238
+ class z {
239
+ constructor(e, t) {
240
+ /** Tracks number of other resources referencing this resource. Used to perform garbage collection in tree patching procedure */
241
+ u(this, "refCount", 0);
242
+ /** Increments each time resource is checked for difference with new state */
243
+ u(this, "version", D);
244
+ /** Set to resource version when resource state, or it's fields have changed */
245
+ u(this, "dataVersion", D);
246
+ u(this, "fields", /* @__PURE__ */ new Map());
247
+ u(this, "kv", /* @__PURE__ */ new Map());
248
+ u(this, "resourceRemoved", new y());
249
+ // following change source are removed when resource is marked as final
250
+ u(this, "finalChanged", new y());
251
+ u(this, "resourceStateChange", new y());
252
+ u(this, "lockedChange", new y());
253
+ u(this, "inputAndServiceFieldListChanged", new y());
254
+ u(this, "outputFieldListChanged", new y());
255
+ u(this, "dynamicFieldListChanged", new y());
256
+ u(this, "kvChanged", new y());
257
+ u(this, "id");
258
+ u(this, "originalResourceId");
259
+ u(this, "kind");
260
+ u(this, "type");
261
+ u(this, "data");
262
+ u(this, "dataAsString");
263
+ u(this, "dataAsJson");
264
+ u(this, "error");
265
+ u(this, "inputsLocked");
266
+ u(this, "outputsLocked");
267
+ u(this, "resourceReady");
268
+ u(this, "finalFlag");
269
+ /** Set externally by the tree, using {@link FinalPredicate} */
270
+ u(this, "_final", !1);
271
+ u(this, "logger");
272
+ this.id = e.id, this.originalResourceId = e.originalResourceId, this.kind = e.kind, this.type = e.type, this.data = e.data, this.error = e.error, this.inputsLocked = e.inputsLocked, this.outputsLocked = e.outputsLocked, this.resourceReady = e.resourceReady, this.finalFlag = e.final, this.logger = t;
273
+ }
274
+ // TODO add logging
275
+ info(e) {
276
+ this.logger !== void 0 && this.logger.info(e);
277
+ }
278
+ warn(e) {
279
+ this.logger !== void 0 && this.logger.warn(e);
280
+ }
281
+ get final() {
282
+ return this._final;
283
+ }
284
+ getField(e, t, r = () => {
285
+ }) {
286
+ var n, i, f;
287
+ const s = typeof t == "string" ? { field: t } : t, c = this.fields.get(s.field);
288
+ if (c === void 0) {
289
+ if (s.errorIfFieldNotFound || s.errorIfFieldNotSet)
290
+ throw new Error(
291
+ `Field "${s.field}" not found in resource ${m(this.id)}`
292
+ );
293
+ if (!this.inputsLocked) (n = this.inputAndServiceFieldListChanged) == null || n.attachWatcher(e);
294
+ else if (s.assertFieldType === "Service" || s.assertFieldType === "Input") {
295
+ if (s.allowPermanentAbsence)
296
+ return;
297
+ throw new Error(`Service or input field not found ${s.field}.`);
298
+ }
299
+ if (!this.outputsLocked) (i = this.outputFieldListChanged) == null || i.attachWatcher(e);
300
+ else if (s.assertFieldType === "Output") {
301
+ if (s.allowPermanentAbsence)
302
+ return;
303
+ throw new Error(`Output field not found ${s.field}.`);
304
+ }
305
+ (f = this.dynamicFieldListChanged) == null || f.attachWatcher(e), !this._final && !s.stableIfNotFound && r("field_not_found:" + s.field);
306
+ return;
307
+ } else {
308
+ if (s.assertFieldType !== void 0 && c.type !== s.assertFieldType)
309
+ throw new Error(
310
+ `Unexpected field type: expected ${s.assertFieldType} but got ${c.type} for the field name ${s.field}`
311
+ );
312
+ const d = {};
313
+ return g(c.value) && (d.value = c.value), g(c.error) && (d.error = c.error), d.value === void 0 && d.error === void 0 && r("field_not_resolved:" + s.field), c.change.attachWatcher(e), d;
314
+ }
315
+ }
316
+ getInputsLocked(e) {
317
+ var t;
318
+ return this.inputsLocked || (t = this.resourceStateChange) == null || t.attachWatcher(e), this.inputsLocked;
319
+ }
320
+ getOutputsLocked(e) {
321
+ var t;
322
+ return this.outputsLocked || (t = this.resourceStateChange) == null || t.attachWatcher(e), this.outputsLocked;
323
+ }
324
+ get isReadyOrError() {
325
+ return this.error !== R || this.resourceReady || this.originalResourceId !== R;
326
+ }
327
+ getIsFinal(e) {
328
+ var t;
329
+ return (t = this.finalChanged) == null || t.attachWatcher(e), this._final;
330
+ }
331
+ getIsReadyOrError(e) {
332
+ var t;
333
+ return this.isReadyOrError || (t = this.resourceStateChange) == null || t.attachWatcher(e), this.isReadyOrError;
334
+ }
335
+ getError(e) {
336
+ var t;
337
+ if (A(this.error)) {
338
+ (t = this.resourceStateChange) == null || t.attachWatcher(e);
339
+ return;
340
+ } else
341
+ return this.error;
342
+ }
343
+ listInputFields(e) {
344
+ var r;
345
+ const t = [];
346
+ return this.fields.forEach((s, c) => {
347
+ (s.type === "Input" || s.type === "Service") && t.push(c);
348
+ }), this.inputsLocked || (r = this.inputAndServiceFieldListChanged) == null || r.attachWatcher(e), t;
349
+ }
350
+ listOutputFields(e) {
351
+ var r;
352
+ const t = [];
353
+ return this.fields.forEach((s, c) => {
354
+ s.type === "Output" && t.push(c);
355
+ }), this.outputsLocked || (r = this.outputFieldListChanged) == null || r.attachWatcher(e), t;
356
+ }
357
+ listDynamicFields(e) {
358
+ var r;
359
+ const t = [];
360
+ return this.fields.forEach((s, c) => {
361
+ s.type !== "Input" && s.type !== "Output" && t.push(c);
362
+ }), (r = this.dynamicFieldListChanged) == null || r.attachWatcher(e), t;
363
+ }
364
+ getKeyValue(e, t) {
365
+ var r;
366
+ return (r = this.kvChanged) == null || r.attachWatcher(e), this.kv.get(t);
367
+ }
368
+ getKeyValueString(e, t) {
369
+ const r = this.getKeyValue(e, t);
370
+ if (r !== void 0)
371
+ return _.decode(r);
372
+ }
373
+ getDataAsString() {
374
+ if (this.data !== void 0)
375
+ return this.dataAsString === void 0 && (this.dataAsString = _.decode(this.data)), this.dataAsString;
376
+ }
377
+ getDataAsJson() {
378
+ if (this.data !== void 0)
379
+ return this.dataAsJson === void 0 && (this.dataAsJson = JSON.parse(this.getDataAsString())), this.dataAsJson;
380
+ }
381
+ verifyReadyState() {
382
+ if (this.resourceReady && !this.inputsLocked)
383
+ throw new Error(`ready without input or output lock: ${L(this.state)}`);
384
+ }
385
+ get state() {
386
+ return {
387
+ id: this.id,
388
+ kind: this.kind,
389
+ type: this.type,
390
+ data: this.data,
391
+ resourceReady: this.resourceReady,
392
+ inputsLocked: this.inputsLocked,
393
+ outputsLocked: this.outputsLocked,
394
+ error: this.error,
395
+ originalResourceId: this.originalResourceId,
396
+ final: this.finalFlag
397
+ };
398
+ }
399
+ markFinal() {
400
+ this._final || (this._final = !0, p(this.finalChanged).markChanged(), this.finalChanged = void 0, this.resourceStateChange = void 0, this.dynamicFieldListChanged = void 0, this.inputAndServiceFieldListChanged = void 0, this.outputFieldListChanged = void 0, this.lockedChange = void 0);
401
+ }
402
+ /** Used for invalidation */
403
+ markAllChanged() {
404
+ var e, t, r, s, c, n, i;
405
+ this.fields.forEach((f) => f.change.markChanged()), (e = this.finalChanged) == null || e.markChanged(), (t = this.resourceStateChange) == null || t.markChanged(), (r = this.lockedChange) == null || r.markChanged(), (s = this.inputAndServiceFieldListChanged) == null || s.markChanged(), (c = this.outputFieldListChanged) == null || c.markChanged(), (n = this.dynamicFieldListChanged) == null || n.markChanged(), (i = this.kvChanged) == null || i.markChanged(), this.resourceRemoved.markChanged();
406
+ }
407
+ }
408
+ class I {
409
+ constructor(e, t = (r) => !1) {
410
+ /** resource heap */
411
+ u(this, "resources", /* @__PURE__ */ new Map());
412
+ u(this, "resourcesAdded", new y());
413
+ /** Resets to false if any invalid state transitions are registered,
414
+ * after that tree will produce errors for any read or write operations */
415
+ u(this, "_isValid", !0);
416
+ u(this, "invalidationMessage");
417
+ this.root = e, this.isFinalPredicate = t;
418
+ }
419
+ forEachResource(e) {
420
+ this.resources.forEach((t) => e(t));
421
+ }
422
+ checkValid() {
423
+ if (!this._isValid) throw new Error(this.invalidationMessage ?? "tree is in invalid state");
424
+ }
425
+ get(e, t) {
426
+ this.checkValid();
427
+ const r = this.resources.get(t);
428
+ if (r === void 0)
429
+ throw this.resourcesAdded.attachWatcher(e), new Error(`resource ${m(t)} not found in the tree`);
430
+ return r.resourceRemoved.attachWatcher(e), r;
431
+ }
432
+ updateFromResourceData(e, t = !1) {
433
+ this.checkValid();
434
+ const r = [], s = [];
435
+ for (const n of e) {
436
+ let i = this.resources.get(n.id);
437
+ const f = i == null ? void 0 : i.state, d = (h) => {
438
+ const { fields: v, ...o } = n;
439
+ throw this.invalidateTree(), new w(
440
+ `Unexpected resource state transition (${h}): ${L(
441
+ o
442
+ )} -> ${L(f)}`
443
+ );
444
+ };
445
+ if (i !== void 0) {
446
+ i.final && d("resource state can be updated after it is marked as final");
447
+ let h = !1;
448
+ i.version += 1, i.originalResourceId !== n.originalResourceId && (i.originalResourceId !== R && d("originalResourceId can't change after it is set"), i.originalResourceId = n.originalResourceId, p(i.resourceStateChange).markChanged(), h = !0), i.error !== n.error && (g(i.error) && d("resource can't change attached error after it is set"), i.error = n.error, r.push(i.error), p(i.resourceStateChange).markChanged(), h = !0);
449
+ for (const o of n.fields) {
450
+ let l = i.fields.get(o.name);
451
+ l ? (l.type !== o.type && (l.type !== "Dynamic" && d(`field changed type ${l.type} -> ${o.type}`), p(i.dynamicFieldListChanged).markChanged(), (l.type === "Input" || l.type === "Service") && (i.inputsLocked && d(
452
+ `adding input field "${o.name}", while corresponding list is locked`
453
+ ), p(i.inputAndServiceFieldListChanged).markChanged()), l.type === "Output" && (i.outputsLocked && d(
454
+ `adding output field "${o.name}", while corresponding list is locked`
455
+ ), p(i.outputFieldListChanged).markChanged()), l.type = o.type, l.change.markChanged(), h = !0), l.value !== o.value && (g(l.value) && s.push(l.value), l.value = o.value, g(o.value) && r.push(o.value), l.change.markChanged(), h = !0), l.error !== o.error && (g(l.error) && s.push(l.error), l.error = o.error, g(o.error) && r.push(o.error), l.change.markChanged(), h = !0), l.resourceVersion = i.version) : (l = new T(o.type, o.value, o.error, i.version), g(o.value) && r.push(o.value), g(o.error) && r.push(o.error), o.type === "Input" || o.type === "Service" ? (i.inputsLocked && d(
456
+ `adding ${o.type} (${o.name}) field while inputs locked`
457
+ ), p(i.inputAndServiceFieldListChanged).markChanged()) : o.type === "Output" ? (i.outputsLocked && d(
458
+ `adding ${o.type} (${o.name}) field while outputs locked`
459
+ ), p(i.outputFieldListChanged).markChanged()) : p(i.dynamicFieldListChanged).markChanged(), i.fields.set(o.name, l), h = !0);
460
+ }
461
+ if (i.fields.forEach((o, l, C) => {
462
+ o.resourceVersion !== i.version && ((o.type === "Input" || o.type === "Service" || o.type === "Output") && d(`removal of ${o.type} field ${l}`), o.change.markChanged(), C.delete(l), g(o.value) && s.push(o.value), g(o.error) && s.push(o.error), p(i.dynamicFieldListChanged).markChanged());
463
+ }), i.inputsLocked !== n.inputsLocked && (i.inputsLocked && d("inputs unlocking is not permitted"), i.inputsLocked = n.inputsLocked, p(i.lockedChange).markChanged(), h = !0), i.outputsLocked !== n.outputsLocked && (i.outputsLocked && d("outputs unlocking is not permitted"), i.outputsLocked = n.outputsLocked, p(i.lockedChange).markChanged(), h = !0), i.resourceReady !== n.resourceReady) {
464
+ const o = i.resourceReady;
465
+ i.resourceReady = n.resourceReady, i.verifyReadyState(), i.isReadyOrError || d(
466
+ `resource can't lose it's ready or error state (ready state before ${o})`
467
+ ), p(i.resourceStateChange).markChanged(), h = !0;
468
+ }
469
+ let v = !1;
470
+ for (const o of n.kv) {
471
+ const l = i.kv.get(o.key);
472
+ (l === void 0 || Buffer.compare(l, o.value) !== 0) && (i.kv.set(o.key, o.value), v = !0);
473
+ }
474
+ if (i.kv.size > n.kv.length) {
475
+ const o = new Set(n.kv.map((l) => l.key));
476
+ i.kv.forEach((l, C, V) => {
477
+ o.has(C) || V.delete(C);
478
+ }), v = !0;
479
+ }
480
+ v && p(i.kvChanged).markChanged(), h && (i.dataVersion = i.version, this.isFinalPredicate(i) && i.markFinal());
481
+ } else {
482
+ i = new z(n), i.verifyReadyState(), g(i.error) && r.push(i.error);
483
+ for (const h of n.fields) {
484
+ const v = new T(h.type, h.value, h.error, D);
485
+ g(h.value) && r.push(h.value), g(h.error) && r.push(h.error), i.fields.set(h.name, v);
486
+ }
487
+ for (const h of n.kv) i.kv.set(h.key, h.value);
488
+ this.resources.set(i.id, i), this.resourcesAdded.markChanged();
489
+ }
490
+ }
491
+ for (const n of r) {
492
+ const i = this.resources.get(n);
493
+ if (!i)
494
+ throw this.invalidateTree(), new w(`orphan resource ${n}`);
495
+ i.refCount++;
496
+ }
497
+ let c = s;
498
+ for (; c.length > 0; ) {
499
+ const n = [];
500
+ for (const i of c) {
501
+ const f = this.resources.get(i);
502
+ if (!f)
503
+ throw this.invalidateTree(), new w(`orphan resource ${i}`);
504
+ f.refCount--, f.refCount === 0 && f.id !== this.root && (f.fields.forEach((d) => {
505
+ g(d.value) && n.push(d.value), g(d.error) && n.push(d.error), d.change.markChanged();
506
+ }), g(f.error) && n.push(f.error), f.resourceRemoved.markChanged(), this.resources.delete(i));
507
+ }
508
+ c = n;
509
+ }
510
+ if (!t) {
511
+ for (const n of e)
512
+ if (!this.resources.has(n.id))
513
+ throw this.invalidateTree(), new w(`orphan input resource ${n.id}`);
514
+ }
515
+ }
516
+ /** @deprecated use "entry" instead */
517
+ accessor(e = this.root) {
518
+ return this.checkValid(), this.entry(e);
519
+ }
520
+ entry(e = this.root) {
521
+ return this.checkValid(), new k({ treeProvider: () => this }, e);
522
+ }
523
+ invalidateTree(e) {
524
+ this._isValid = !1, this.invalidationMessage = e, this.resources.forEach((t) => {
525
+ t.markAllChanged();
526
+ });
527
+ }
528
+ }
529
+ function q(a, e) {
530
+ const t = [], r = /* @__PURE__ */ new Set();
531
+ return a.forEachResource((s) => {
532
+ s.final ? r.add(s.id) : t.push(s.id);
533
+ }), t.length === 0 && r.size === 0 && t.push(a.root), { seedResources: t, finalResources: r, pruningFunction: e };
534
+ }
535
+ async function B(a, e) {
536
+ const { seedResources: t, finalResources: r, pruningFunction: s } = e, c = new K(), n = /* @__PURE__ */ new Set(), i = (d) => {
537
+ if (A(d) || n.has(d) || r.has(d)) return;
538
+ n.add(d);
539
+ const h = a.getResourceDataIfExists(d, !0), v = a.listKeyValuesIfResourceExists(d);
540
+ c.push(
541
+ (async () => {
542
+ const o = await h, l = await v;
543
+ if (o !== void 0) {
544
+ if (l === void 0) throw new Error("Inconsistent replies");
545
+ return { ...o, kv: l };
546
+ }
547
+ })()
548
+ );
549
+ };
550
+ t.forEach((d) => i(d));
551
+ const f = [];
552
+ for (; ; ) {
553
+ const d = c.shift();
554
+ if (d === void 0)
555
+ break;
556
+ let h = await d;
557
+ if (h !== void 0) {
558
+ s !== void 0 && (h = { ...h, fields: s(h) }), i(h.error);
559
+ for (const v of h.fields)
560
+ i(v.value), i(v.error);
561
+ f.push(h);
562
+ }
563
+ }
564
+ return f;
565
+ }
566
+ function ie(a) {
567
+ return a;
568
+ }
569
+ function se(a, e, t) {
570
+ var n;
571
+ const r = a instanceof k ? p(t).accessor(a).node() : a instanceof E ? a.node() : a, c = { ...r.resourceInfo };
572
+ if (e.data !== void 0 && (e.data === "raw" ? c.data = r.getData() : c.data = e.data.parse(r.getDataAsJson())), e.fields !== void 0) {
573
+ const i = {};
574
+ for (const [f, d] of Object.entries(e.fields))
575
+ i[f] = (n = r.traverse({
576
+ field: f,
577
+ errorIfFieldNotSet: d,
578
+ stableIfNotFound: !d
579
+ })) == null ? void 0 : n.id;
580
+ c.fields = i;
581
+ }
582
+ if (e.kv !== void 0) {
583
+ const i = {};
584
+ for (const [f, d] of Object.entries(e.kv)) {
585
+ const h = r.getKeyValue(f);
586
+ if (h === void 0)
587
+ throw new Error(`Key not found ${f}`);
588
+ d === "raw" ? i[f] = h : i[f] = d.parse(JSON.parse(Buffer.from(h).toString("utf-8")));
589
+ }
590
+ c.kv = i;
591
+ }
592
+ return c;
593
+ }
594
+ function ne(a, e, t) {
595
+ if (a instanceof k) {
596
+ const r = t.accessor(a).node(), s = r.resourceInfo, c = e.map((n) => {
597
+ var i, f;
598
+ return [
599
+ n,
600
+ (f = (i = r.getField(n)) == null ? void 0 : i.value) == null ? void 0 : f.id
601
+ ];
602
+ });
603
+ return {
604
+ ...s,
605
+ fields: new Map(c),
606
+ data: r.getData() ?? new Uint8Array()
607
+ };
608
+ }
609
+ return a;
610
+ }
611
+ function ae(a, e, t) {
612
+ if (!(a instanceof k)) return a;
613
+ const r = t.accessor(a).node(), s = r.resourceInfo, c = e.map((n) => [n, r.getKeyValue(n)]);
614
+ return {
615
+ ...s,
616
+ metadata: Object.fromEntries(c)
617
+ };
618
+ }
619
+ class b {
620
+ constructor(e, t, r, s) {
621
+ u(this, "finalPredicate");
622
+ u(this, "state");
623
+ u(this, "pollingInterval");
624
+ u(this, "pruning");
625
+ u(this, "hooks");
626
+ u(this, "abortController", new AbortController());
627
+ u(this, "scheduledOnNextState", []);
628
+ /** If true, main loop will continue polling pl state. */
629
+ u(this, "keepRunning", !1);
630
+ /** Actual state of main loop. */
631
+ u(this, "currentLoop");
632
+ /** If true this tree state is permanently terminaed. */
633
+ u(this, "terminated", !1);
634
+ this.pl = e, this.root = t, this.logger = s;
635
+ const { finalPredicate: c, pruning: n, pollingInterval: i, stopPollingDelay: f } = r;
636
+ this.pruning = n, this.pollingInterval = i, this.finalPredicate = c, this.state = new I(t, c), this.hooks = new U(
637
+ () => this.startUpdating(),
638
+ () => this.stopUpdating(),
639
+ { stopDebounce: f },
640
+ (d, h) => this.scheduleOnNextState(d, h)
641
+ );
642
+ }
643
+ /** @deprecated use "entry" instead */
644
+ accessor(e = this.root) {
645
+ if (this.terminated) throw new Error("tree synchronization is terminated");
646
+ return this.entry(e);
647
+ }
648
+ entry(e = this.root) {
649
+ if (this.terminated) throw new Error("tree synchronization is terminated");
650
+ return new k({ treeProvider: () => this.state, hooks: this.hooks }, e);
651
+ }
652
+ /** Can be used to externally kick off the synchronization polling loop, and
653
+ * await for the first synchronization to happen. */
654
+ async refreshState() {
655
+ if (this.terminated) throw new Error("tree synchronization is terminated");
656
+ await this.hooks.refreshState();
657
+ }
658
+ scheduleOnNextState(e, t) {
659
+ this.terminated ? t(new Error("tree synchronization is terminated")) : this.scheduledOnNextState.push({ resolve: e, reject: t });
660
+ }
661
+ /** Called from observer */
662
+ startUpdating() {
663
+ this.terminated || (this.keepRunning = !0, this.currentLoop === void 0 && (this.currentLoop = this.mainLoop()));
664
+ }
665
+ /** Called from observer */
666
+ stopUpdating() {
667
+ this.keepRunning = !1;
668
+ }
669
+ /** Executed from the main loop, and initialization procedure. */
670
+ async refresh() {
671
+ if (this.terminated) throw new Error("tree synchronization is terminated");
672
+ const e = q(this.state, this.pruning), t = await this.pl.withReadTx("ReadingTree", async (r) => await B(r, e));
673
+ this.state.updateFromResourceData(t, !0);
674
+ }
675
+ async mainLoop() {
676
+ var e, t;
677
+ for (; this.keepRunning; ) {
678
+ let r;
679
+ this.scheduledOnNextState.length > 0 && (r = this.scheduledOnNextState, this.scheduledOnNextState = []);
680
+ try {
681
+ if (await this.refresh(), r !== void 0) for (const s of r) s.resolve();
682
+ } catch (s) {
683
+ if (r !== void 0) for (const c of r) c.reject(s);
684
+ if (s instanceof w) {
685
+ (e = this.logger) == null || e.error(s), this.state.invalidateTree("stat update error"), this.state = new I(this.root, this.finalPredicate);
686
+ continue;
687
+ } else (t = this.logger) == null || t.warn(s);
688
+ }
689
+ if (!this.keepRunning || this.terminated) break;
690
+ try {
691
+ await J.setTimeout(this.pollingInterval, this.abortController.signal);
692
+ } catch (s) {
693
+ if (!W(s)) throw new Error("Unexpected error", { cause: s });
694
+ break;
695
+ }
696
+ }
697
+ this.currentLoop = void 0;
698
+ }
699
+ /**
700
+ * Terminates the internal loop, and permanently destoys all internal state, so
701
+ * all computables using this state will resolve to errors.
702
+ * */
703
+ async terminate() {
704
+ this.keepRunning = !1, this.terminated = !0, this.abortController.abort(), this.currentLoop !== void 0 && (await this.currentLoop, this.state.invalidateTree("synchronization terminated for the tree"));
705
+ }
706
+ /** @deprecated */
707
+ async awaitSyncLoopTermination() {
708
+ this.currentLoop !== void 0 && await this.currentLoop;
709
+ }
710
+ static async init(e, t, r) {
711
+ const s = new b(e, t, r);
712
+ return await s.refresh(), s;
713
+ }
714
+ }
715
+ export {
716
+ O as PlError,
717
+ k as PlTreeEntry,
718
+ E as PlTreeEntryAccessor,
719
+ M as PlTreeNodeAccessor,
720
+ z as PlTreeResource,
721
+ I as PlTreeState,
722
+ b as SynchronizedTreeState,
723
+ w as TreeStateUpdateError,
724
+ q as constructTreeLoadingRequest,
725
+ Z as isPlTreeEntry,
726
+ ee as isPlTreeEntryAccessor,
727
+ te as isPlTreeNodeAccessor,
728
+ B as loadTreeState,
729
+ se as makeResourceSnapshot,
730
+ x as mapValueAndError,
731
+ X as mapValueAndErrorIfDefined,
732
+ ie as rsSchema,
733
+ re as treeEntryToResourceInfo,
734
+ ne as treeEntryToResourceWithData,
735
+ ae as treeEntryToResourceWithMetadata
736
+ };
737
+ //# sourceMappingURL=index.mjs.map