@milaboratories/pl-tree 1.13.2 → 1.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@ import { CommonFieldTraverseOps, CommonTraversalOps, FieldTraversalStep, GetFiel
2
2
  import { ValueAndError, mapValueAndError, mapValueAndErrorIfDefined } from "./value_and_error.js";
3
3
  import { ValueOrError } from "./value_or_error.js";
4
4
  import { PlError, PlTreeEntry, PlTreeEntryAccessor, PlTreeNodeAccessor, PlTreeRootsAccessor, PlTreeRootsEntry, ResourceInfo, TreeAccessorData, TreeAccessorInstanceData, isPlTreeEntry, isPlTreeEntryAccessor, isPlTreeNodeAccessor, isPlTreeRootsAccessor, isPlTreeRootsEntry, treeEntryToResourceInfo } from "./accessors.js";
5
- import { ExtendedResourceData, PlTreeResource, PlTreeState, ResourceDataWithFinalState, TreeStateUpdateError } from "./state.js";
5
+ import { ExtendedResourceData, PlTreeResource, PlTreeState, ResourceDataWithFinalState, ResourceUpdateStat, TreeStateUpdateError } from "./state.js";
6
6
  import { PruningFunction, TraversalMode, TreeLoadingRequest, TreeLoadingStat, constructTreeLoadingRequest, formatTreeLoadingStat, initialTreeLoadingStat, loadTreeState } from "./sync.js";
7
7
  import { InferSnapshot, ResourceSnapshot, ResourceSnapshotSchema, ResourceWithData, ResourceWithMetadata, makeResourceSnapshot, rsSchema, treeEntryToResourceWithData, treeEntryToResourceWithMetadata } from "./snapshot.js";
8
8
  import { ExplicitRootSeed, SharedTypeSeed, SynchronizedTreeOps, SynchronizedTreeState, TreeSeed } from "./synchronized_tree.js";
9
9
  import { ResourceStats, TreeDumpStats, treeDumpStats } from "./dump.js";
10
- export { CommonFieldTraverseOps, CommonTraversalOps, ExplicitRootSeed, ExtendedResourceData, FieldTraversalStep, GetFieldStep, InferSnapshot, PlError, PlTreeEntry, PlTreeEntryAccessor, PlTreeNodeAccessor, PlTreeResource, PlTreeRootsAccessor, PlTreeRootsEntry, PlTreeState, PruningFunction, ResourceDataWithFinalState, ResourceInfo, ResourceSnapshot, ResourceSnapshotSchema, ResourceStats, ResourceTraversalOps, ResourceWithData, ResourceWithMetadata, SharedTypeSeed, SynchronizedTreeOps, SynchronizedTreeState, TraversalMode, TreeAccessorData, TreeAccessorInstanceData, TreeDumpStats, TreeLoadingRequest, TreeLoadingStat, TreeSeed, TreeStateUpdateError, ValueAndError, ValueOrError, constructTreeLoadingRequest, formatTreeLoadingStat, initialTreeLoadingStat, isPlTreeEntry, isPlTreeEntryAccessor, isPlTreeNodeAccessor, isPlTreeRootsAccessor, isPlTreeRootsEntry, loadTreeState, makeResourceSnapshot, mapValueAndError, mapValueAndErrorIfDefined, rsSchema, treeDumpStats, treeEntryToResourceInfo, treeEntryToResourceWithData, treeEntryToResourceWithMetadata };
10
+ export { CommonFieldTraverseOps, CommonTraversalOps, ExplicitRootSeed, ExtendedResourceData, FieldTraversalStep, GetFieldStep, InferSnapshot, PlError, PlTreeEntry, PlTreeEntryAccessor, PlTreeNodeAccessor, PlTreeResource, PlTreeRootsAccessor, PlTreeRootsEntry, PlTreeState, PruningFunction, ResourceDataWithFinalState, ResourceInfo, ResourceSnapshot, ResourceSnapshotSchema, ResourceStats, ResourceTraversalOps, ResourceUpdateStat, ResourceWithData, ResourceWithMetadata, SharedTypeSeed, SynchronizedTreeOps, SynchronizedTreeState, TraversalMode, TreeAccessorData, TreeAccessorInstanceData, TreeDumpStats, TreeLoadingRequest, TreeLoadingStat, TreeSeed, TreeStateUpdateError, ValueAndError, ValueOrError, constructTreeLoadingRequest, formatTreeLoadingStat, initialTreeLoadingStat, isPlTreeEntry, isPlTreeEntryAccessor, isPlTreeNodeAccessor, isPlTreeRootsAccessor, isPlTreeRootsEntry, loadTreeState, makeResourceSnapshot, mapValueAndError, mapValueAndErrorIfDefined, rsSchema, treeDumpStats, treeEntryToResourceInfo, treeEntryToResourceWithData, treeEntryToResourceWithMetadata };
package/dist/state.cjs CHANGED
@@ -299,12 +299,16 @@ var PlTreeState = class {
299
299
  res.resourceRemoved.attachWatcher(watcher);
300
300
  return res;
301
301
  }
302
- updateFromResourceData(resourceData, allowOrphanInputs = false) {
302
+ updateFromResourceData(resourceData, opts = {}) {
303
+ const { allowOrphanInputs = false, stat } = opts;
303
304
  this.checkValid();
304
305
  const incrementRefs = [];
305
306
  const decrementRefs = [];
306
307
  for (const rd of resourceData) {
307
308
  let resource = this.resources.get(rd.id);
309
+ const held = resource !== void 0;
310
+ let changed = false;
311
+ let metadataChanged = false;
308
312
  const statBeforeMutation = resource?.basicState;
309
313
  const unexpectedTransitionError = (reason) => {
310
314
  const { fields, ...rdWithoutFields } = rd;
@@ -313,13 +317,13 @@ var PlTreeState = class {
313
317
  };
314
318
  if (resource !== void 0) {
315
319
  if (resource.finalState) unexpectedTransitionError("resource state can be updated after it is marked as final");
316
- let changed = false;
317
320
  resource.version += 1;
318
321
  if (resource.originalResourceId !== rd.originalResourceId) {
319
322
  if (resource.originalResourceId !== _milaboratories_pl_client.NullSignedResourceId) unexpectedTransitionError("originalResourceId can't change after it is set");
320
323
  resource.originalResourceId = rd.originalResourceId;
321
324
  (0, _milaboratories_ts_helpers.notEmpty)(resource.resourceStateChange).markChanged(`originalResourceId changed for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
322
325
  changed = true;
326
+ if (stat) stat.duplicatesResolved++;
323
327
  }
324
328
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(rd.error) && resource.error !== rd.error) {
325
329
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(resource.error)) unexpectedTransitionError("resource can't change attached error after it is set");
@@ -327,6 +331,7 @@ var PlTreeState = class {
327
331
  incrementRefs.push(resource.error);
328
332
  (0, _milaboratories_ts_helpers.notEmpty)(resource.resourceStateChange).markChanged(`error changed for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
329
333
  changed = true;
334
+ if (stat) stat.errorsAttached++;
330
335
  }
331
336
  for (const fd of rd.fields) {
332
337
  let field = resource.fieldsMap.get(fd.name);
@@ -343,6 +348,8 @@ var PlTreeState = class {
343
348
  } else (0, _milaboratories_ts_helpers.notEmpty)(resource.dynamicFieldListChanged).markChanged(`new ${fd.type} field ${fd.name} added to ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
344
349
  resource.fieldsMap.set(fd.name, field);
345
350
  changed = true;
351
+ metadataChanged = true;
352
+ if (stat) stat.fieldsAdded++;
346
353
  } else {
347
354
  if (field.type !== fd.type) {
348
355
  if (field.type !== "Dynamic") unexpectedTransitionError(`field changed type ${field.type} -> ${fd.type}`);
@@ -365,6 +372,7 @@ var PlTreeState = class {
365
372
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(fd.value)) incrementRefs.push(fd.value);
366
373
  field.change.markChanged(`field ${fd.name} value changed in ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
367
374
  changed = true;
375
+ if (stat) stat.fieldsChanged++;
368
376
  }
369
377
  if (field.error !== fd.error) {
370
378
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(field.error)) decrementRefs.push(field.error);
@@ -391,6 +399,8 @@ var PlTreeState = class {
391
399
  if (field.type === "Input" || field.type === "Service" || field.type === "Output") unexpectedTransitionError(`removal of ${field.type} field ${fieldName}`);
392
400
  field.change.markChanged(`dynamic field ${fieldName} removed from ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
393
401
  fields.delete(fieldName);
402
+ metadataChanged = true;
403
+ if (stat) stat.fieldsRemoved++;
394
404
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(field.value)) decrementRefs.push(field.value);
395
405
  if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(field.error)) decrementRefs.push(field.error);
396
406
  (0, _milaboratories_ts_helpers.notEmpty)(resource.dynamicFieldListChanged).markChanged(`dynamic field ${fieldName} removed from ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
@@ -401,12 +411,14 @@ var PlTreeState = class {
401
411
  resource.inputsLocked = rd.inputsLocked;
402
412
  (0, _milaboratories_ts_helpers.notEmpty)(resource.lockedChange).markChanged(`inputs locked for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
403
413
  changed = true;
414
+ if (stat) stat.locksChanged++;
404
415
  }
405
416
  if (resource.outputsLocked !== rd.outputsLocked) {
406
417
  if (resource.outputsLocked) unexpectedTransitionError("outputs unlocking is not permitted");
407
418
  resource.outputsLocked = rd.outputsLocked;
408
419
  (0, _milaboratories_ts_helpers.notEmpty)(resource.lockedChange).markChanged(`outputs locked for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
409
420
  changed = true;
421
+ if (stat) stat.locksChanged++;
410
422
  }
411
423
  if (resource.resourceReady !== rd.resourceReady) {
412
424
  const readyStateBefore = resource.resourceReady;
@@ -415,15 +427,20 @@ var PlTreeState = class {
415
427
  if (!resource.isReadyOrError) unexpectedTransitionError(`resource can't lose it's ready or error state (ready state before ${readyStateBefore})`);
416
428
  (0, _milaboratories_ts_helpers.notEmpty)(resource.resourceStateChange).markChanged(`ready flag changed to ${rd.resourceReady} for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}`);
417
429
  changed = true;
430
+ if (stat) stat.readyFlips++;
418
431
  }
419
432
  for (const kv of rd.kv) {
420
433
  const current = resource.kv.get(kv.key);
421
434
  if (current === void 0) {
422
435
  resource.kv.set(kv.key, kv.value);
423
436
  (0, _milaboratories_ts_helpers.notEmpty)(resource.kvChangedPerKey).markChanged(kv.key, `kv added for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}: ${kv.key}`);
437
+ changed = true;
438
+ if (stat) stat.kvChanged++;
424
439
  } else if (Buffer.compare(current, kv.value) !== 0) {
425
440
  resource.kv.set(kv.key, kv.value);
426
441
  (0, _milaboratories_ts_helpers.notEmpty)(resource.kvChangedPerKey).markChanged(kv.key, `kv changed for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}: ${kv.key}`);
442
+ changed = true;
443
+ if (stat) stat.kvChanged++;
427
444
  }
428
445
  }
429
446
  if (resource.kv.size > rd.kv.length) {
@@ -432,12 +449,17 @@ var PlTreeState = class {
432
449
  if (!newStateKeys.has(key)) {
433
450
  map.delete(key);
434
451
  (0, _milaboratories_ts_helpers.notEmpty)(resource.kvChangedPerKey).markChanged(key, `kv deleted for ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)}: ${key}`);
452
+ changed = true;
453
+ if (stat) stat.kvChanged++;
435
454
  }
436
455
  });
437
456
  }
438
457
  if (changed) {
439
458
  resource.dataVersion = resource.version;
440
- if (this.isFinalPredicate(resource)) resource.markFinal();
459
+ if (this.isFinalPredicate(resource)) {
460
+ resource.markFinal();
461
+ if (stat) stat.resourcesMarkedFinal++;
462
+ }
441
463
  }
442
464
  } else {
443
465
  resource = new PlTreeResource(rd);
@@ -454,6 +476,16 @@ var PlTreeState = class {
454
476
  this.resources.set(resource.id, resource);
455
477
  this.resourcesAdded.markChanged(`new resource ${(0, _milaboratories_pl_client.resourceIdToString)(resource.id)} added`);
456
478
  }
479
+ if (stat) if (!held) stat.resourcesNew++;
480
+ else if (changed) {
481
+ stat.resourcesChanged++;
482
+ if (!metadataChanged) stat.metadataStableChanged++;
483
+ } else {
484
+ stat.resourcesUnchanged++;
485
+ stat.bytesUnchanged += rd.data?.length ?? 0;
486
+ for (const kv of rd.kv) stat.bytesUnchanged += kv.value.length;
487
+ if (!stat.usedStreaming) stat.bfsRequestsWasted++;
488
+ }
457
489
  }
458
490
  for (const rid of incrementRefs) {
459
491
  const res = this.resources.get(rid);
@@ -1 +1 @@
1
- {"version":3,"file":"state.cjs","names":["ChangeSource","KeyedChangeSource","NullSignedResourceId","PlTreeEntry"],"sources":["../src/state.ts"],"sourcesContent":["import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalSignedResourceId,\n ResourceData,\n SignedResourceId,\n ResourceKind,\n ResourceType,\n} from \"@milaboratories/pl-client\";\nimport {\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n NullSignedResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, KeyedChangeSource } from \"@milaboratories/computable\";\nimport { PlTreeEntry } from \"./accessors\";\nimport type { ValueAndError } from \"./value_and_error\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { cachedDecode, cachedDeserialize, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldTraversalStep, GetFieldStep } from \"./traversal_ops\";\nimport type { FinalResourceDataPredicate } from \"@milaboratories/pl-client\";\n\nexport type ExtendedResourceData = ResourceData & {\n kv: KeyValue[];\n};\n\nexport class TreeStateUpdateError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nclass PlTreeField implements FieldData {\n readonly change = new ChangeSource();\n\n constructor(\n public readonly name: string,\n public type: FieldType,\n public value: OptionalSignedResourceId,\n public error: OptionalSignedResourceId,\n public status: FieldStatus,\n public valueIsFinal: boolean,\n /** Last version of resource this field was observed, used to garbage collect fields in tree patching procedure */\n public resourceVersion: number,\n ) {}\n\n get state(): FieldData {\n return {\n name: this.name,\n type: this.type,\n status: this.status,\n value: this.value,\n error: this.error,\n valueIsFinal: this.valueIsFinal,\n };\n }\n}\n\nconst InitialResourceVersion = 0;\n\nexport type ResourceDataWithFinalState = ResourceData & {\n finalState: boolean;\n};\n\n/** Never store instances of this class, always get fresh instance from {@link PlTreeState} */\nexport class PlTreeResource implements ResourceDataWithFinalState {\n /** Tracks number of other resources referencing this resource. Used to perform garbage collection in tree patching procedure */\n refCount: number = 0;\n\n /** Increments each time resource is checked for difference with new state */\n version: number = InitialResourceVersion;\n /** Set to resource version when resource state, or it's fields have changed */\n dataVersion: number = InitialResourceVersion;\n\n readonly fieldsMap: Map<string, PlTreeField> = new Map();\n\n readonly kv = new Map<string, Uint8Array>();\n\n readonly resourceRemoved = new ChangeSource();\n\n // following change source are removed when resource is marked as final\n\n finalChanged? = new ChangeSource();\n\n resourceStateChange? = new ChangeSource();\n\n lockedChange? = new ChangeSource();\n inputAndServiceFieldListChanged? = new ChangeSource();\n outputFieldListChanged? = new ChangeSource();\n dynamicFieldListChanged? = new ChangeSource();\n\n // kvChangedGlobal? = new ChangeSource();\n kvChangedPerKey? = new KeyedChangeSource();\n\n readonly id: SignedResourceId;\n originalResourceId: OptionalSignedResourceId;\n\n readonly kind: ResourceKind;\n readonly type: ResourceType;\n\n readonly data?: Uint8Array;\n private dataAsString?: string;\n private dataAsJson?: unknown;\n\n error: OptionalSignedResourceId;\n\n inputsLocked: boolean;\n outputsLocked: boolean;\n resourceReady: boolean;\n finalFlag: boolean;\n\n /** Set externally by the tree, using {@link FinalResourceDataPredicate} */\n _finalState: boolean = false;\n\n private readonly logger?: MiLogger;\n\n constructor(initialState: BasicResourceData, logger?: MiLogger) {\n this.id = initialState.id;\n this.originalResourceId = initialState.originalResourceId;\n this.kind = initialState.kind;\n this.type = initialState.type;\n this.data = initialState.data;\n this.error = initialState.error;\n this.inputsLocked = initialState.inputsLocked;\n this.outputsLocked = initialState.outputsLocked;\n this.resourceReady = initialState.resourceReady;\n this.finalFlag = initialState.final;\n this.logger = logger;\n }\n\n // TODO add logging\n\n private info(msg: string) {\n if (this.logger !== undefined) this.logger.info(msg);\n }\n\n private warn(msg: string) {\n if (this.logger !== undefined) this.logger.warn(msg);\n }\n\n get final(): boolean {\n return this.finalFlag;\n }\n\n get finalState(): boolean {\n return this._finalState;\n }\n\n get fields(): FieldData[] {\n return [...this.fieldsMap.values()];\n }\n\n public getField(\n watcher: Watcher,\n _step:\n | (Omit<GetFieldStep, \"errorIfFieldNotFound\"> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, \"errorIfFieldNotSet\"> & { errorIfFieldNotSet: true }),\n onUnstable: (marker: string) => void,\n ): ValueAndError<SignedResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void,\n ): ValueAndError<SignedResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<SignedResourceId> | undefined {\n const step: FieldTraversalStep = typeof _step === \"string\" ? { field: _step } : _step;\n\n const field = this.fieldsMap.get(step.field);\n if (field === undefined) {\n if (step.errorIfFieldNotFound || step.errorIfFieldNotSet)\n throw new Error(\n `Field \"${step.field}\" not found in resource ${resourceIdToString(this.id)}`,\n );\n\n if (!this.inputsLocked) this.inputAndServiceFieldListChanged?.attachWatcher(watcher);\n else if (step.assertFieldType === \"Service\" || step.assertFieldType === \"Input\") {\n if (step.allowPermanentAbsence)\n // stable absence of field\n return undefined;\n else throw new Error(`Service or input field not found ${step.field}.`);\n }\n\n if (!this.outputsLocked) this.outputFieldListChanged?.attachWatcher(watcher);\n else if (step.assertFieldType === \"Output\") {\n if (step.allowPermanentAbsence)\n // stable absence of field\n return undefined;\n else throw new Error(`Output field not found ${step.field}.`);\n }\n\n this.dynamicFieldListChanged?.attachWatcher(watcher);\n if (!this._finalState && !step.stableIfNotFound) onUnstable(\"field_not_found:\" + step.field);\n\n return undefined;\n } else {\n if (step.assertFieldType !== undefined && field.type !== step.assertFieldType)\n throw new Error(\n `Unexpected field type: expected ${step.assertFieldType} but got ${field.type} for the field name ${step.field}`,\n );\n\n const ret = {} as ValueAndError<SignedResourceId>;\n if (isNotNullSignedResourceId(field.value)) ret.value = field.value;\n if (isNotNullSignedResourceId(field.error)) ret.error = field.error;\n if (ret.value === undefined && ret.error === undefined)\n // this method returns value and error of the field, thus those values are considered to be accessed;\n // any existing but not resolved field here is considered to be unstable, in the sense it is\n // considered to acquire some resolved value eventually\n onUnstable(\"field_not_resolved:\" + step.field);\n field.change.attachWatcher(watcher);\n return ret;\n }\n }\n\n public getInputsLocked(watcher: Watcher): boolean {\n if (!this.inputsLocked)\n // reverse transition can't happen, so there is no reason to wait for value to change\n this.resourceStateChange?.attachWatcher(watcher);\n return this.inputsLocked;\n }\n\n public getOutputsLocked(watcher: Watcher): boolean {\n if (!this.outputsLocked)\n // reverse transition can't happen, so there is no reason to wait for value to change\n this.resourceStateChange?.attachWatcher(watcher);\n return this.outputsLocked;\n }\n\n public get isReadyOrError(): boolean {\n return (\n this.error !== NullSignedResourceId ||\n this.resourceReady ||\n this.originalResourceId !== NullSignedResourceId\n );\n }\n\n public getIsFinal(watcher: Watcher): boolean {\n this.finalChanged?.attachWatcher(watcher);\n return this._finalState;\n }\n\n public getIsReadyOrError(watcher: Watcher): boolean {\n if (!this.isReadyOrError)\n // reverse transition can't happen, so there is no reason to wait for value to change if it is already true\n this.resourceStateChange?.attachWatcher(watcher);\n return this.isReadyOrError;\n }\n\n public getError(watcher: Watcher): SignedResourceId | undefined {\n if (isNullSignedResourceId(this.error)) {\n this.resourceStateChange?.attachWatcher(watcher);\n return undefined;\n } else {\n // reverse transition can't happen, so there is no reason to wait for value to change, if error already set\n return this.error;\n }\n }\n\n public listInputFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type === \"Input\" || field.type === \"Service\") ret.push(name);\n });\n if (!this.inputsLocked) this.inputAndServiceFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public listOutputFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type === \"Output\") ret.push(name);\n });\n if (!this.outputsLocked) this.outputFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public listDynamicFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type !== \"Input\" && field.type !== \"Output\") ret.push(name);\n });\n this.dynamicFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public getKeyValue(watcher: Watcher, key: string): Uint8Array | undefined {\n this.kvChangedPerKey?.attachWatcher(key, watcher);\n return this.kv.get(key);\n }\n\n public getKeyValueString(watcher: Watcher, key: string): string | undefined {\n const bytes = this.getKeyValue(watcher, key);\n if (bytes === undefined) return undefined;\n return cachedDecode(bytes);\n }\n\n public getKeyValueAsJson<T = unknown>(watcher: Watcher, key: string): T | undefined {\n const bytes = this.getKeyValue(watcher, key);\n if (bytes === undefined) return undefined;\n return cachedDeserialize(bytes);\n }\n\n public getDataAsString(): string | undefined {\n if (this.data === undefined) return undefined;\n if (this.dataAsString === undefined) this.dataAsString = cachedDecode(this.data);\n return this.dataAsString;\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n if (this.data === undefined) return undefined;\n if (this.dataAsJson === undefined) this.dataAsJson = cachedDeserialize(this.data);\n return this.dataAsJson as T;\n }\n\n verifyReadyState() {\n if (this.resourceReady && !this.inputsLocked)\n throw new Error(\n `ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`,\n );\n }\n\n get basicState(): BasicResourceData {\n return {\n id: this.id,\n kind: this.kind,\n type: this.type,\n data: this.data,\n resourceReady: this.resourceReady,\n inputsLocked: this.inputsLocked,\n outputsLocked: this.outputsLocked,\n error: this.error,\n originalResourceId: this.originalResourceId,\n final: this.finalFlag,\n };\n }\n\n get extendedState(): ExtendedResourceData {\n return {\n ...this.basicState,\n fields: this.fields,\n kv: Array.from(this.kv.entries()).map(([key, value]) => ({ key, value })),\n };\n }\n\n /** Called when {@link FinalResourceDataPredicate} returns true for the state. */\n markFinal() {\n if (this._finalState) return;\n\n this._finalState = true;\n notEmpty(this.finalChanged).markChanged(\"marked final\");\n this.finalChanged = undefined;\n this.resourceStateChange = undefined;\n this.dynamicFieldListChanged = undefined;\n this.inputAndServiceFieldListChanged = undefined;\n this.outputFieldListChanged = undefined;\n this.lockedChange = undefined;\n // this.kvChangedGlobal = undefined;\n this.kvChangedPerKey = undefined;\n }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged(\"marked all changed\"));\n this.finalChanged?.markChanged(\"marked all changed\");\n this.resourceStateChange?.markChanged(\"marked all changed\");\n this.lockedChange?.markChanged(\"marked all changed\");\n this.inputAndServiceFieldListChanged?.markChanged(\"marked all changed\");\n this.outputFieldListChanged?.markChanged(\"marked all changed\");\n this.dynamicFieldListChanged?.markChanged(\"marked all changed\");\n // this.kvChangedGlobal?.markChanged('marked all changed');\n this.kvChangedPerKey?.markAllChanged(\"marked all changed\");\n this.resourceRemoved.markChanged(\"marked all changed\");\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<SignedResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = new ChangeSource();\n /** Marked when the root set changes (roots discovered or removed), so multi-root\n * accessors that read the set recompute. */\n private readonly rootsChanged = new ChangeSource();\n /** Resets to false if any invalid state transitions are registered,\n * after that tree will produce errors for any read or write operations */\n private _isValid: boolean = true;\n private invalidationMessage?: string;\n\n /** The set of roots — resources protected from GC. Originally a single `root`,\n * generalized to a set so several explicit roots and dynamically-discovered shared\n * roots can coexist in one heap. Mutated through {@link setRoots}. */\n public readonly roots: Set<SignedResourceId>;\n\n constructor(\n /** Resources protected from GC. Accepts a single id (single-root, the original\n * contract) or a set of ids (multi-root). */\n roots: SignedResourceId | Set<SignedResourceId>,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\n ) {\n this.roots = roots instanceof Set ? new Set(roots) : new Set([roots]);\n }\n\n /** Backward-compatible single-root accessor. Returns the sole root and THROWS if the\n * tree has zero or more than one root, so a multi-root tree can never be read as if it\n * had one. Mirrors the {@link entry} guard. */\n public get root(): SignedResourceId {\n if (this.roots.size !== 1)\n throw new Error(\n `single-root accessor used on a tree with ${this.roots.size} roots; use the multi-root API`,\n );\n return this.roots.values().next().value!;\n }\n\n public forEachResource(cb: (res: ResourceDataWithFinalState) => void): void {\n this.resources.forEach((v) => cb(v));\n }\n\n private checkValid() {\n if (!this._isValid) throw new Error(this.invalidationMessage ?? \"tree is in invalid state\");\n }\n\n /** Reactive read of the current root set. Attaches the watcher to {@link rootsChanged}\n * so a Computable recomputes when discovered roots appear or disappear. */\n public getRoots(watcher: Watcher): SignedResourceId[] {\n this.checkValid();\n this.rootsChanged.attachWatcher(watcher);\n return [...this.roots];\n }\n\n public get(watcher: Watcher, rid: SignedResourceId): PlTreeResource {\n this.checkValid();\n const res = this.resources.get(rid);\n if (res === undefined) {\n // to make recovery from resource not found possible, considering some\n // race conditions, where computable is created before tree is updated\n this.resourcesAdded.attachWatcher(watcher);\n throw new Error(`resource ${resourceIdToString(rid)} not found in the tree`);\n }\n res.resourceRemoved.attachWatcher(watcher);\n return res;\n }\n\n updateFromResourceData(resourceData: ExtendedResourceData[], allowOrphanInputs: boolean = false) {\n this.checkValid();\n\n // All resources for which recount should be incremented, first are aggregated in this list\n const incrementRefs: SignedResourceId[] = [];\n const decrementRefs: SignedResourceId[] = [];\n\n // patching / creating resources\n for (const rd of resourceData) {\n let resource = this.resources.get(rd.id);\n\n const statBeforeMutation = resource?.basicState;\n const unexpectedTransitionError = (reason: string): never => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { fields, ...rdWithoutFields } = rd;\n this.invalidateTree();\n throw new TreeStateUpdateError(\n `Unexpected resource state transition (${reason}): ${stringifyWithResourceId(\n rdWithoutFields,\n )} -> ${stringifyWithResourceId(statBeforeMutation)}`,\n );\n };\n\n if (resource !== undefined) {\n // updating existing resource\n\n if (resource.finalState)\n unexpectedTransitionError(\"resource state can\\t be updated after it is marked as final\");\n\n let changed = false;\n // updating resource version, even if it was not changed\n resource.version += 1;\n\n // duplicate / original\n if (resource.originalResourceId !== rd.originalResourceId) {\n if (resource.originalResourceId !== NullSignedResourceId)\n unexpectedTransitionError(\"originalResourceId can't change after it is set\");\n resource.originalResourceId = rd.originalResourceId;\n // duplicate status of the resource counts as ready for the external observer\n notEmpty(resource.resourceStateChange).markChanged(\n `originalResourceId changed for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // error\n if (isNotNullSignedResourceId(rd.error) && resource.error !== rd.error) {\n if (isNotNullSignedResourceId(resource.error))\n unexpectedTransitionError(\"resource can't change attached error after it is set\");\n resource.error = rd.error;\n incrementRefs.push(resource.error);\n notEmpty(resource.resourceStateChange).markChanged(\n `error changed for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // updating fields\n for (const fd of rd.fields) {\n let field = resource.fieldsMap.get(fd.name);\n\n if (!field) {\n // new field\n\n field = new PlTreeField(\n fd.name,\n fd.type,\n fd.value,\n fd.error,\n fd.status,\n fd.valueIsFinal,\n resource.version,\n );\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n\n if (fd.type === \"Input\" || fd.type === \"Service\") {\n if (resource.inputsLocked)\n unexpectedTransitionError(\n `adding ${fd.type} (${fd.name}) field while inputs locked`,\n );\n notEmpty(resource.inputAndServiceFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n } else if (fd.type === \"Output\") {\n if (resource.outputsLocked)\n unexpectedTransitionError(\n `adding ${fd.type} (${fd.name}) field while outputs locked`,\n );\n notEmpty(resource.outputFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n }\n\n resource.fieldsMap.set(fd.name, field);\n\n changed = true;\n } else {\n // change of old field\n\n // in principle this transition is possible, see assertions below\n if (field.type !== fd.type) {\n if (field.type !== \"Dynamic\")\n unexpectedTransitionError(`field changed type ${field.type} -> ${fd.type}`);\n notEmpty(resource.dynamicFieldListChanged).markChanged(\n `field ${fd.name} changed type from Dynamic to ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n if (field.type === \"Input\" || field.type === \"Service\") {\n if (resource.inputsLocked)\n unexpectedTransitionError(\n `adding input field \"${fd.name}\", while corresponding list is locked`,\n );\n notEmpty(resource.inputAndServiceFieldListChanged).markChanged(\n `field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n }\n if (field.type === \"Output\") {\n if (resource.outputsLocked)\n unexpectedTransitionError(\n `adding output field \"${fd.name}\", while corresponding list is locked`,\n );\n notEmpty(resource.outputFieldListChanged).markChanged(\n `field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n }\n field.type = fd.type;\n field.change.markChanged(\n `field ${fd.name} type changed to ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullSignedResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged(\n `field ${fd.name} value changed in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged(\n `field ${fd.name} error changed in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged(\n `field ${fd.name} status changed to ${fd.status} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field valueIsFinal flag\n if (field.valueIsFinal !== fd.valueIsFinal) {\n field.valueIsFinal = fd.valueIsFinal;\n field.change.markChanged(\n `field ${fd.name} valueIsFinal changed to ${fd.valueIsFinal} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n field.resourceVersion = resource.version;\n }\n }\n\n // detecting removed fields\n resource.fieldsMap.forEach((field, fieldName, fields) => {\n if (field.resourceVersion !== resource!.version) {\n if (field.type === \"Input\" || field.type === \"Service\" || field.type === \"Output\")\n unexpectedTransitionError(`removal of ${field.type} field ${fieldName}`);\n field.change.markChanged(\n `dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`,\n );\n fields.delete(fieldName);\n\n if (isNotNullSignedResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged(\n `dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`,\n );\n }\n });\n\n // inputsLocked\n if (resource.inputsLocked !== rd.inputsLocked) {\n if (resource.inputsLocked) unexpectedTransitionError(\"inputs unlocking is not permitted\");\n resource.inputsLocked = rd.inputsLocked;\n notEmpty(resource.lockedChange).markChanged(\n `inputs locked for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // outputsLocked\n if (resource.outputsLocked !== rd.outputsLocked) {\n if (resource.outputsLocked)\n unexpectedTransitionError(\"outputs unlocking is not permitted\");\n resource.outputsLocked = rd.outputsLocked;\n notEmpty(resource.lockedChange).markChanged(\n `outputs locked for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // ready flag\n if (resource.resourceReady !== rd.resourceReady) {\n const readyStateBefore = resource.resourceReady;\n resource.resourceReady = rd.resourceReady;\n resource.verifyReadyState();\n if (!resource.isReadyOrError)\n unexpectedTransitionError(\n `resource can't lose it's ready or error state (ready state before ${readyStateBefore})`,\n );\n notEmpty(resource.resourceStateChange).markChanged(\n `ready flag changed to ${rd.resourceReady} for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // syncing kv\n for (const kv of rd.kv) {\n const current = resource.kv.get(kv.key);\n if (current === undefined) {\n resource.kv.set(kv.key, kv.value);\n notEmpty(resource.kvChangedPerKey).markChanged(\n kv.key,\n `kv added for ${resourceIdToString(resource.id)}: ${kv.key}`,\n );\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n notEmpty(resource.kvChangedPerKey).markChanged(\n kv.key,\n `kv changed for ${resourceIdToString(resource.id)}: ${kv.key}`,\n );\n }\n }\n\n if (resource.kv.size > rd.kv.length) {\n // only it this case it makes sense to check for deletions\n const newStateKeys = new Set(rd.kv.map((kv) => kv.key));\n\n // deleting keys not present in resource anymore\n resource.kv.forEach((_value, key, map) => {\n if (!newStateKeys.has(key)) {\n map.delete(key);\n notEmpty(resource!.kvChangedPerKey).markChanged(\n key,\n `kv deleted for ${resourceIdToString(resource!.id)}: ${key}`,\n );\n }\n });\n }\n\n if (changed) {\n // if resource was changed, updating resource data version\n resource.dataVersion = resource.version;\n if (this.isFinalPredicate(resource)) resource.markFinal();\n }\n } else {\n // creating new resource\n\n resource = new PlTreeResource(rd);\n resource.verifyReadyState();\n if (isNotNullSignedResourceId(resource.error)) incrementRefs.push(resource.error);\n for (const fd of rd.fields) {\n const field = new PlTreeField(\n fd.name,\n fd.type,\n fd.value,\n fd.error,\n fd.status,\n fd.valueIsFinal,\n InitialResourceVersion,\n );\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n resource.fieldsMap.set(fd.name, field);\n }\n\n // adding kv\n for (const kv of rd.kv) resource.kv.set(kv.key, kv.value);\n\n // checking that resource is final, and if so, marking it\n if (this.isFinalPredicate(resource)) resource.markFinal();\n\n // adding the resource to the heap\n this.resources.set(resource.id, resource);\n this.resourcesAdded.markChanged(`new resource ${resourceIdToString(resource.id)} added`);\n }\n }\n\n // applying refCount increments\n for (const rid of incrementRefs) {\n const res = this.resources.get(rid);\n if (!res) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan resource ${rid}`);\n }\n res.refCount++;\n }\n\n // recursively applying refCount decrements / doing garbage collection\n this.collectGarbage(decrementRefs);\n\n // checking for orphans (maybe removed in the future)\n if (!allowOrphanInputs) {\n for (const rd of resourceData) {\n if (!this.resources.has(rd.id)) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan input resource ${rd.id}`);\n }\n }\n }\n }\n\n /** Runs the refcount-decrement garbage-collection cascade over the given worklist.\n * A resource reaching refCount 0 that is not a root is removed, and its outgoing\n * references are decremented in turn, until the worklist drains. Factored out of\n * {@link updateFromResourceData} so {@link setRoots} can reuse the same cascade. */\n private collectGarbage(decrementRefs: SignedResourceId[]) {\n let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: SignedResourceId[] = [];\n for (const rid of currentRefs) {\n const res = this.resources.get(rid);\n if (!res) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan resource ${rid}`);\n }\n res.refCount--;\n\n // garbage collection\n if (res.refCount === 0 && !this.roots.has(res.id)) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullSignedResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullSignedResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged(\n `field ${field.name} removed during garbage collection of ${resourceIdToString(res.id)}`,\n );\n });\n if (isNotNullSignedResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged(\n `resource removed during garbage collection: ${resourceIdToString(res.id)}`,\n );\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\n }\n\n /** Replaces the current root set with `newRoots`.\n *\n * Roots that leave the set lose their GC protection: each removed root present in the\n * heap is collected directly (a root sits at refCount 0, so it is never enqueued by an\n * ordinary decrement), and its subtree cascades to collection through the existing\n * refcount GC — the standard removal mechanic, applied to a root. Roots newly added to\n * the set are protected immediately; their resources arrive on the next refresh poll. */\n public setRoots(newRoots: Set<SignedResourceId>) {\n this.checkValid();\n\n const removed: SignedResourceId[] = [];\n for (const rid of this.roots) if (!newRoots.has(rid)) removed.push(rid);\n let added = false;\n for (const rid of newRoots) if (!this.roots.has(rid)) added = true;\n if (removed.length === 0 && !added) return; // no change\n\n // commit the new protected set before collecting, so a removed root is no longer\n // protected while its subtree cascades.\n this.roots.clear();\n for (const rid of newRoots) this.roots.add(rid);\n\n this.rootsChanged.markChanged(\"root set changed\");\n\n for (const rid of removed) {\n const res = this.resources.get(rid);\n if (res === undefined) continue; // root not yet materialized in the heap\n\n // if the (former) root is still referenced by another resource, dropping protection\n // is enough — ordinary refcounting keeps it alive and will collect it later.\n if (res.refCount > 0) continue;\n\n // collect the (now-unprotected) root itself and seed the cascade with the refs it holds\n const seed: SignedResourceId[] = [];\n res.fieldsMap.forEach((field) => {\n if (isNotNullSignedResourceId(field.value)) seed.push(field.value);\n if (isNotNullSignedResourceId(field.error)) seed.push(field.error);\n field.change.markChanged(\n `field ${field.name} removed after root ${resourceIdToString(res.id)} left the root set`,\n );\n });\n if (isNotNullSignedResourceId(res.error)) seed.push(res.error);\n res.resourceRemoved.markChanged(\n `resource removed after leaving the root set: ${resourceIdToString(res.id)}`,\n );\n this.resources.delete(rid);\n\n this.collectGarbage(seed);\n }\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: SignedResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: SignedResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return new PlTreeEntry({ treeProvider: () => this }, rid);\n }\n\n public invalidateTree(msg?: string) {\n this._isValid = false;\n this.invalidationMessage = msg;\n this.rootsChanged.markChanged(\"tree invalidated\");\n this.resources.forEach((res) => {\n res.markAllChanged();\n });\n }\n\n public dumpState(): ExtendedResourceData[] {\n return Array.from(this.resources.values()).map((res) => res.extendedState);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"state.cjs","names":["ChangeSource","KeyedChangeSource","NullSignedResourceId","PlTreeEntry"],"sources":["../src/state.ts"],"sourcesContent":["import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalSignedResourceId,\n ResourceData,\n SignedResourceId,\n ResourceKind,\n ResourceType,\n} from \"@milaboratories/pl-client\";\nimport {\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n NullSignedResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, KeyedChangeSource } from \"@milaboratories/computable\";\nimport { PlTreeEntry } from \"./accessors\";\nimport type { ValueAndError } from \"./value_and_error\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { cachedDecode, cachedDeserialize, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldTraversalStep, GetFieldStep } from \"./traversal_ops\";\nimport type { FinalResourceDataPredicate } from \"@milaboratories/pl-client\";\n\nexport type ExtendedResourceData = ResourceData & {\n kv: KeyValue[];\n};\n\nexport class TreeStateUpdateError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nclass PlTreeField implements FieldData {\n readonly change = new ChangeSource();\n\n constructor(\n public readonly name: string,\n public type: FieldType,\n public value: OptionalSignedResourceId,\n public error: OptionalSignedResourceId,\n public status: FieldStatus,\n public valueIsFinal: boolean,\n /** Last version of resource this field was observed, used to garbage collect fields in tree patching procedure */\n public resourceVersion: number,\n ) {}\n\n get state(): FieldData {\n return {\n name: this.name,\n type: this.type,\n status: this.status,\n value: this.value,\n error: this.error,\n valueIsFinal: this.valueIsFinal,\n };\n }\n}\n\nconst InitialResourceVersion = 0;\n\nexport type ResourceDataWithFinalState = ResourceData & {\n finalState: boolean;\n};\n\n/** Cross-cycle re-fetch duplication counters, populated by {@link PlTreeState.updateFromResourceData}.\n * Separates genuinely new/changed resources from redundant re-fetches of unchanged ones\n * (the delta-skip opportunity: intra-cycle dedup already happens in the loader, so all waste here\n * is cross-cycle). */\nexport interface ResourceUpdateStat {\n /** Resources seen for the first time in this update. */\n resourcesNew: number;\n /** Resources already held whose state actually changed. */\n resourcesChanged: number;\n /** Resources already held that came back unchanged: a pure duplicate re-fetch. */\n resourcesUnchanged: number;\n /** data + KV bytes of the unchanged bucket: wasted downlink. */\n bytesUnchanged: number;\n /** Changed resources whose immutable metadata (type, kind, field set) did not change,\n * i.e. metadata re-streamed even though only a value or flag flipped. */\n metadataStableChanged: number;\n /** Per-resource fetches spent on unchanged resources (BFS only; streaming re-sends them\n * inside one stream, so this stays 0). */\n bfsRequestsWasted: number;\n /** Whether the current load used backend streaming; set by the loader, read here to\n * attribute {@link bfsRequestsWasted}. */\n usedStreaming: boolean;\n // Breakdown of what changed among resourcesChanged (a resource can bump several).\n /** New fields appeared on a held resource. */\n fieldsAdded: number;\n /** Dynamic fields disappeared from a held resource. */\n fieldsRemoved: number;\n /** Existing field value pointer changed (a new value/result was attached). */\n fieldsChanged: number;\n /** KV entries added, changed, or deleted. */\n kvChanged: number;\n /** resourceReady flipped. */\n readyFlips: number;\n /** inputsLocked or outputsLocked transitioned. */\n locksChanged: number;\n /** An error resource was attached. */\n errorsAttached: number;\n /** originalResourceId resolved (duplicate -> original). */\n duplicatesResolved: number;\n /** Held resources that transitioned to final this update. */\n resourcesMarkedFinal: number;\n}\n\n/** Never store instances of this class, always get fresh instance from {@link PlTreeState} */\nexport class PlTreeResource implements ResourceDataWithFinalState {\n /** Tracks number of other resources referencing this resource. Used to perform garbage collection in tree patching procedure */\n refCount: number = 0;\n\n /** Increments each time resource is checked for difference with new state */\n version: number = InitialResourceVersion;\n /** Set to resource version when resource state, or it's fields have changed */\n dataVersion: number = InitialResourceVersion;\n\n readonly fieldsMap: Map<string, PlTreeField> = new Map();\n\n readonly kv = new Map<string, Uint8Array>();\n\n readonly resourceRemoved = new ChangeSource();\n\n // following change source are removed when resource is marked as final\n\n finalChanged? = new ChangeSource();\n\n resourceStateChange? = new ChangeSource();\n\n lockedChange? = new ChangeSource();\n inputAndServiceFieldListChanged? = new ChangeSource();\n outputFieldListChanged? = new ChangeSource();\n dynamicFieldListChanged? = new ChangeSource();\n\n // kvChangedGlobal? = new ChangeSource();\n kvChangedPerKey? = new KeyedChangeSource();\n\n readonly id: SignedResourceId;\n originalResourceId: OptionalSignedResourceId;\n\n readonly kind: ResourceKind;\n readonly type: ResourceType;\n\n readonly data?: Uint8Array;\n private dataAsString?: string;\n private dataAsJson?: unknown;\n\n error: OptionalSignedResourceId;\n\n inputsLocked: boolean;\n outputsLocked: boolean;\n resourceReady: boolean;\n finalFlag: boolean;\n\n /** Set externally by the tree, using {@link FinalResourceDataPredicate} */\n _finalState: boolean = false;\n\n private readonly logger?: MiLogger;\n\n constructor(initialState: BasicResourceData, logger?: MiLogger) {\n this.id = initialState.id;\n this.originalResourceId = initialState.originalResourceId;\n this.kind = initialState.kind;\n this.type = initialState.type;\n this.data = initialState.data;\n this.error = initialState.error;\n this.inputsLocked = initialState.inputsLocked;\n this.outputsLocked = initialState.outputsLocked;\n this.resourceReady = initialState.resourceReady;\n this.finalFlag = initialState.final;\n this.logger = logger;\n }\n\n // TODO add logging\n\n private info(msg: string) {\n if (this.logger !== undefined) this.logger.info(msg);\n }\n\n private warn(msg: string) {\n if (this.logger !== undefined) this.logger.warn(msg);\n }\n\n get final(): boolean {\n return this.finalFlag;\n }\n\n get finalState(): boolean {\n return this._finalState;\n }\n\n get fields(): FieldData[] {\n return [...this.fieldsMap.values()];\n }\n\n public getField(\n watcher: Watcher,\n _step:\n | (Omit<GetFieldStep, \"errorIfFieldNotFound\"> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, \"errorIfFieldNotSet\"> & { errorIfFieldNotSet: true }),\n onUnstable: (marker: string) => void,\n ): ValueAndError<SignedResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void,\n ): ValueAndError<SignedResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<SignedResourceId> | undefined {\n const step: FieldTraversalStep = typeof _step === \"string\" ? { field: _step } : _step;\n\n const field = this.fieldsMap.get(step.field);\n if (field === undefined) {\n if (step.errorIfFieldNotFound || step.errorIfFieldNotSet)\n throw new Error(\n `Field \"${step.field}\" not found in resource ${resourceIdToString(this.id)}`,\n );\n\n if (!this.inputsLocked) this.inputAndServiceFieldListChanged?.attachWatcher(watcher);\n else if (step.assertFieldType === \"Service\" || step.assertFieldType === \"Input\") {\n if (step.allowPermanentAbsence)\n // stable absence of field\n return undefined;\n else throw new Error(`Service or input field not found ${step.field}.`);\n }\n\n if (!this.outputsLocked) this.outputFieldListChanged?.attachWatcher(watcher);\n else if (step.assertFieldType === \"Output\") {\n if (step.allowPermanentAbsence)\n // stable absence of field\n return undefined;\n else throw new Error(`Output field not found ${step.field}.`);\n }\n\n this.dynamicFieldListChanged?.attachWatcher(watcher);\n if (!this._finalState && !step.stableIfNotFound) onUnstable(\"field_not_found:\" + step.field);\n\n return undefined;\n } else {\n if (step.assertFieldType !== undefined && field.type !== step.assertFieldType)\n throw new Error(\n `Unexpected field type: expected ${step.assertFieldType} but got ${field.type} for the field name ${step.field}`,\n );\n\n const ret = {} as ValueAndError<SignedResourceId>;\n if (isNotNullSignedResourceId(field.value)) ret.value = field.value;\n if (isNotNullSignedResourceId(field.error)) ret.error = field.error;\n if (ret.value === undefined && ret.error === undefined)\n // this method returns value and error of the field, thus those values are considered to be accessed;\n // any existing but not resolved field here is considered to be unstable, in the sense it is\n // considered to acquire some resolved value eventually\n onUnstable(\"field_not_resolved:\" + step.field);\n field.change.attachWatcher(watcher);\n return ret;\n }\n }\n\n public getInputsLocked(watcher: Watcher): boolean {\n if (!this.inputsLocked)\n // reverse transition can't happen, so there is no reason to wait for value to change\n this.resourceStateChange?.attachWatcher(watcher);\n return this.inputsLocked;\n }\n\n public getOutputsLocked(watcher: Watcher): boolean {\n if (!this.outputsLocked)\n // reverse transition can't happen, so there is no reason to wait for value to change\n this.resourceStateChange?.attachWatcher(watcher);\n return this.outputsLocked;\n }\n\n public get isReadyOrError(): boolean {\n return (\n this.error !== NullSignedResourceId ||\n this.resourceReady ||\n this.originalResourceId !== NullSignedResourceId\n );\n }\n\n public getIsFinal(watcher: Watcher): boolean {\n this.finalChanged?.attachWatcher(watcher);\n return this._finalState;\n }\n\n public getIsReadyOrError(watcher: Watcher): boolean {\n if (!this.isReadyOrError)\n // reverse transition can't happen, so there is no reason to wait for value to change if it is already true\n this.resourceStateChange?.attachWatcher(watcher);\n return this.isReadyOrError;\n }\n\n public getError(watcher: Watcher): SignedResourceId | undefined {\n if (isNullSignedResourceId(this.error)) {\n this.resourceStateChange?.attachWatcher(watcher);\n return undefined;\n } else {\n // reverse transition can't happen, so there is no reason to wait for value to change, if error already set\n return this.error;\n }\n }\n\n public listInputFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type === \"Input\" || field.type === \"Service\") ret.push(name);\n });\n if (!this.inputsLocked) this.inputAndServiceFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public listOutputFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type === \"Output\") ret.push(name);\n });\n if (!this.outputsLocked) this.outputFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public listDynamicFields(watcher: Watcher): string[] {\n const ret: string[] = [];\n this.fieldsMap.forEach((field, name) => {\n if (field.type !== \"Input\" && field.type !== \"Output\") ret.push(name);\n });\n this.dynamicFieldListChanged?.attachWatcher(watcher);\n\n return ret;\n }\n\n public getKeyValue(watcher: Watcher, key: string): Uint8Array | undefined {\n this.kvChangedPerKey?.attachWatcher(key, watcher);\n return this.kv.get(key);\n }\n\n public getKeyValueString(watcher: Watcher, key: string): string | undefined {\n const bytes = this.getKeyValue(watcher, key);\n if (bytes === undefined) return undefined;\n return cachedDecode(bytes);\n }\n\n public getKeyValueAsJson<T = unknown>(watcher: Watcher, key: string): T | undefined {\n const bytes = this.getKeyValue(watcher, key);\n if (bytes === undefined) return undefined;\n return cachedDeserialize(bytes);\n }\n\n public getDataAsString(): string | undefined {\n if (this.data === undefined) return undefined;\n if (this.dataAsString === undefined) this.dataAsString = cachedDecode(this.data);\n return this.dataAsString;\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n if (this.data === undefined) return undefined;\n if (this.dataAsJson === undefined) this.dataAsJson = cachedDeserialize(this.data);\n return this.dataAsJson as T;\n }\n\n verifyReadyState() {\n if (this.resourceReady && !this.inputsLocked)\n throw new Error(\n `ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`,\n );\n }\n\n get basicState(): BasicResourceData {\n return {\n id: this.id,\n kind: this.kind,\n type: this.type,\n data: this.data,\n resourceReady: this.resourceReady,\n inputsLocked: this.inputsLocked,\n outputsLocked: this.outputsLocked,\n error: this.error,\n originalResourceId: this.originalResourceId,\n final: this.finalFlag,\n };\n }\n\n get extendedState(): ExtendedResourceData {\n return {\n ...this.basicState,\n fields: this.fields,\n kv: Array.from(this.kv.entries()).map(([key, value]) => ({ key, value })),\n };\n }\n\n /** Called when {@link FinalResourceDataPredicate} returns true for the state. */\n markFinal() {\n if (this._finalState) return;\n\n this._finalState = true;\n notEmpty(this.finalChanged).markChanged(\"marked final\");\n this.finalChanged = undefined;\n this.resourceStateChange = undefined;\n this.dynamicFieldListChanged = undefined;\n this.inputAndServiceFieldListChanged = undefined;\n this.outputFieldListChanged = undefined;\n this.lockedChange = undefined;\n // this.kvChangedGlobal = undefined;\n this.kvChangedPerKey = undefined;\n }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged(\"marked all changed\"));\n this.finalChanged?.markChanged(\"marked all changed\");\n this.resourceStateChange?.markChanged(\"marked all changed\");\n this.lockedChange?.markChanged(\"marked all changed\");\n this.inputAndServiceFieldListChanged?.markChanged(\"marked all changed\");\n this.outputFieldListChanged?.markChanged(\"marked all changed\");\n this.dynamicFieldListChanged?.markChanged(\"marked all changed\");\n // this.kvChangedGlobal?.markChanged('marked all changed');\n this.kvChangedPerKey?.markAllChanged(\"marked all changed\");\n this.resourceRemoved.markChanged(\"marked all changed\");\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<SignedResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = new ChangeSource();\n /** Marked when the root set changes (roots discovered or removed), so multi-root\n * accessors that read the set recompute. */\n private readonly rootsChanged = new ChangeSource();\n /** Resets to false if any invalid state transitions are registered,\n * after that tree will produce errors for any read or write operations */\n private _isValid: boolean = true;\n private invalidationMessage?: string;\n\n /** The set of roots — resources protected from GC. Originally a single `root`,\n * generalized to a set so several explicit roots and dynamically-discovered shared\n * roots can coexist in one heap. Mutated through {@link setRoots}. */\n public readonly roots: Set<SignedResourceId>;\n\n constructor(\n /** Resources protected from GC. Accepts a single id (single-root, the original\n * contract) or a set of ids (multi-root). */\n roots: SignedResourceId | Set<SignedResourceId>,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\n ) {\n this.roots = roots instanceof Set ? new Set(roots) : new Set([roots]);\n }\n\n /** Backward-compatible single-root accessor. Returns the sole root and THROWS if the\n * tree has zero or more than one root, so a multi-root tree can never be read as if it\n * had one. Mirrors the {@link entry} guard. */\n public get root(): SignedResourceId {\n if (this.roots.size !== 1)\n throw new Error(\n `single-root accessor used on a tree with ${this.roots.size} roots; use the multi-root API`,\n );\n return this.roots.values().next().value!;\n }\n\n public forEachResource(cb: (res: ResourceDataWithFinalState) => void): void {\n this.resources.forEach((v) => cb(v));\n }\n\n private checkValid() {\n if (!this._isValid) throw new Error(this.invalidationMessage ?? \"tree is in invalid state\");\n }\n\n /** Reactive read of the current root set. Attaches the watcher to {@link rootsChanged}\n * so a Computable recomputes when discovered roots appear or disappear. */\n public getRoots(watcher: Watcher): SignedResourceId[] {\n this.checkValid();\n this.rootsChanged.attachWatcher(watcher);\n return [...this.roots];\n }\n\n public get(watcher: Watcher, rid: SignedResourceId): PlTreeResource {\n this.checkValid();\n const res = this.resources.get(rid);\n if (res === undefined) {\n // to make recovery from resource not found possible, considering some\n // race conditions, where computable is created before tree is updated\n this.resourcesAdded.attachWatcher(watcher);\n throw new Error(`resource ${resourceIdToString(rid)} not found in the tree`);\n }\n res.resourceRemoved.attachWatcher(watcher);\n return res;\n }\n\n updateFromResourceData(\n resourceData: ExtendedResourceData[],\n opts: { allowOrphanInputs?: boolean; stat?: ResourceUpdateStat } = {},\n ) {\n const { allowOrphanInputs = false, stat } = opts;\n this.checkValid();\n\n // All resources for which recount should be incremented, first are aggregated in this list\n const incrementRefs: SignedResourceId[] = [];\n const decrementRefs: SignedResourceId[] = [];\n\n // patching / creating resources\n for (const rd of resourceData) {\n let resource = this.resources.get(rd.id);\n const held = resource !== undefined;\n let changed = false;\n // Structural/metadata change (new or removed field). type and kind are readonly, so\n // they never change; this flag isolates value/flag-only changes from real metadata churn.\n let metadataChanged = false;\n\n const statBeforeMutation = resource?.basicState;\n const unexpectedTransitionError = (reason: string): never => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { fields, ...rdWithoutFields } = rd;\n this.invalidateTree();\n throw new TreeStateUpdateError(\n `Unexpected resource state transition (${reason}): ${stringifyWithResourceId(\n rdWithoutFields,\n )} -> ${stringifyWithResourceId(statBeforeMutation)}`,\n );\n };\n\n if (resource !== undefined) {\n // updating existing resource\n\n if (resource.finalState)\n unexpectedTransitionError(\"resource state can\\t be updated after it is marked as final\");\n\n // updating resource version, even if it was not changed\n resource.version += 1;\n\n // duplicate / original\n if (resource.originalResourceId !== rd.originalResourceId) {\n if (resource.originalResourceId !== NullSignedResourceId)\n unexpectedTransitionError(\"originalResourceId can't change after it is set\");\n resource.originalResourceId = rd.originalResourceId;\n // duplicate status of the resource counts as ready for the external observer\n notEmpty(resource.resourceStateChange).markChanged(\n `originalResourceId changed for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.duplicatesResolved++;\n }\n\n // error\n if (isNotNullSignedResourceId(rd.error) && resource.error !== rd.error) {\n if (isNotNullSignedResourceId(resource.error))\n unexpectedTransitionError(\"resource can't change attached error after it is set\");\n resource.error = rd.error;\n incrementRefs.push(resource.error);\n notEmpty(resource.resourceStateChange).markChanged(\n `error changed for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.errorsAttached++;\n }\n\n // updating fields\n for (const fd of rd.fields) {\n let field = resource.fieldsMap.get(fd.name);\n\n if (!field) {\n // new field\n\n field = new PlTreeField(\n fd.name,\n fd.type,\n fd.value,\n fd.error,\n fd.status,\n fd.valueIsFinal,\n resource.version,\n );\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n\n if (fd.type === \"Input\" || fd.type === \"Service\") {\n if (resource.inputsLocked)\n unexpectedTransitionError(\n `adding ${fd.type} (${fd.name}) field while inputs locked`,\n );\n notEmpty(resource.inputAndServiceFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n } else if (fd.type === \"Output\") {\n if (resource.outputsLocked)\n unexpectedTransitionError(\n `adding ${fd.type} (${fd.name}) field while outputs locked`,\n );\n notEmpty(resource.outputFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged(\n `new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`,\n );\n }\n\n resource.fieldsMap.set(fd.name, field);\n\n changed = true;\n metadataChanged = true;\n if (stat) stat.fieldsAdded++;\n } else {\n // change of old field\n\n // in principle this transition is possible, see assertions below\n if (field.type !== fd.type) {\n if (field.type !== \"Dynamic\")\n unexpectedTransitionError(`field changed type ${field.type} -> ${fd.type}`);\n notEmpty(resource.dynamicFieldListChanged).markChanged(\n `field ${fd.name} changed type from Dynamic to ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n if (field.type === \"Input\" || field.type === \"Service\") {\n if (resource.inputsLocked)\n unexpectedTransitionError(\n `adding input field \"${fd.name}\", while corresponding list is locked`,\n );\n notEmpty(resource.inputAndServiceFieldListChanged).markChanged(\n `field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n }\n if (field.type === \"Output\") {\n if (resource.outputsLocked)\n unexpectedTransitionError(\n `adding output field \"${fd.name}\", while corresponding list is locked`,\n );\n notEmpty(resource.outputFieldListChanged).markChanged(\n `field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n }\n field.type = fd.type;\n field.change.markChanged(\n `field ${fd.name} type changed to ${fd.type} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullSignedResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged(\n `field ${fd.name} value changed in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.fieldsChanged++;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged(\n `field ${fd.name} error changed in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged(\n `field ${fd.name} status changed to ${fd.status} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n // field valueIsFinal flag\n if (field.valueIsFinal !== fd.valueIsFinal) {\n field.valueIsFinal = fd.valueIsFinal;\n field.change.markChanged(\n `field ${fd.name} valueIsFinal changed to ${fd.valueIsFinal} in ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n }\n\n field.resourceVersion = resource.version;\n }\n }\n\n // detecting removed fields\n resource.fieldsMap.forEach((field, fieldName, fields) => {\n if (field.resourceVersion !== resource!.version) {\n if (field.type === \"Input\" || field.type === \"Service\" || field.type === \"Output\")\n unexpectedTransitionError(`removal of ${field.type} field ${fieldName}`);\n field.change.markChanged(\n `dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`,\n );\n fields.delete(fieldName);\n metadataChanged = true;\n if (stat) stat.fieldsRemoved++;\n\n if (isNotNullSignedResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged(\n `dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`,\n );\n }\n });\n\n // inputsLocked\n if (resource.inputsLocked !== rd.inputsLocked) {\n if (resource.inputsLocked) unexpectedTransitionError(\"inputs unlocking is not permitted\");\n resource.inputsLocked = rd.inputsLocked;\n notEmpty(resource.lockedChange).markChanged(\n `inputs locked for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.locksChanged++;\n }\n\n // outputsLocked\n if (resource.outputsLocked !== rd.outputsLocked) {\n if (resource.outputsLocked)\n unexpectedTransitionError(\"outputs unlocking is not permitted\");\n resource.outputsLocked = rd.outputsLocked;\n notEmpty(resource.lockedChange).markChanged(\n `outputs locked for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.locksChanged++;\n }\n\n // ready flag\n if (resource.resourceReady !== rd.resourceReady) {\n const readyStateBefore = resource.resourceReady;\n resource.resourceReady = rd.resourceReady;\n resource.verifyReadyState();\n if (!resource.isReadyOrError)\n unexpectedTransitionError(\n `resource can't lose it's ready or error state (ready state before ${readyStateBefore})`,\n );\n notEmpty(resource.resourceStateChange).markChanged(\n `ready flag changed to ${rd.resourceReady} for ${resourceIdToString(resource.id)}`,\n );\n changed = true;\n if (stat) stat.readyFlips++;\n }\n\n // syncing kv\n for (const kv of rd.kv) {\n const current = resource.kv.get(kv.key);\n if (current === undefined) {\n resource.kv.set(kv.key, kv.value);\n notEmpty(resource.kvChangedPerKey).markChanged(\n kv.key,\n `kv added for ${resourceIdToString(resource.id)}: ${kv.key}`,\n );\n changed = true;\n if (stat) stat.kvChanged++;\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n notEmpty(resource.kvChangedPerKey).markChanged(\n kv.key,\n `kv changed for ${resourceIdToString(resource.id)}: ${kv.key}`,\n );\n changed = true;\n if (stat) stat.kvChanged++;\n }\n }\n\n if (resource.kv.size > rd.kv.length) {\n // only it this case it makes sense to check for deletions\n const newStateKeys = new Set(rd.kv.map((kv) => kv.key));\n\n // deleting keys not present in resource anymore\n resource.kv.forEach((_value, key, map) => {\n if (!newStateKeys.has(key)) {\n map.delete(key);\n notEmpty(resource!.kvChangedPerKey).markChanged(\n key,\n `kv deleted for ${resourceIdToString(resource!.id)}: ${key}`,\n );\n changed = true;\n if (stat) stat.kvChanged++;\n }\n });\n }\n\n if (changed) {\n // if resource was changed, updating resource data version\n resource.dataVersion = resource.version;\n if (this.isFinalPredicate(resource)) {\n resource.markFinal();\n if (stat) stat.resourcesMarkedFinal++;\n }\n }\n } else {\n // creating new resource\n\n resource = new PlTreeResource(rd);\n resource.verifyReadyState();\n if (isNotNullSignedResourceId(resource.error)) incrementRefs.push(resource.error);\n for (const fd of rd.fields) {\n const field = new PlTreeField(\n fd.name,\n fd.type,\n fd.value,\n fd.error,\n fd.status,\n fd.valueIsFinal,\n InitialResourceVersion,\n );\n if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullSignedResourceId(fd.error)) incrementRefs.push(fd.error);\n resource.fieldsMap.set(fd.name, field);\n }\n\n // adding kv\n for (const kv of rd.kv) resource.kv.set(kv.key, kv.value);\n\n // checking that resource is final, and if so, marking it\n if (this.isFinalPredicate(resource)) resource.markFinal();\n\n // adding the resource to the heap\n this.resources.set(resource.id, resource);\n this.resourcesAdded.markChanged(`new resource ${resourceIdToString(resource.id)} added`);\n }\n\n if (stat) {\n if (!held) stat.resourcesNew++;\n else if (changed) {\n stat.resourcesChanged++;\n if (!metadataChanged) stat.metadataStableChanged++;\n } else {\n stat.resourcesUnchanged++;\n stat.bytesUnchanged += rd.data?.length ?? 0;\n for (const kv of rd.kv) stat.bytesUnchanged += kv.value.length;\n if (!stat.usedStreaming) stat.bfsRequestsWasted++;\n }\n }\n }\n\n // applying refCount increments\n for (const rid of incrementRefs) {\n const res = this.resources.get(rid);\n if (!res) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan resource ${rid}`);\n }\n res.refCount++;\n }\n\n // recursively applying refCount decrements / doing garbage collection\n this.collectGarbage(decrementRefs);\n\n // checking for orphans (maybe removed in the future)\n if (!allowOrphanInputs) {\n for (const rd of resourceData) {\n if (!this.resources.has(rd.id)) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan input resource ${rd.id}`);\n }\n }\n }\n }\n\n /** Runs the refcount-decrement garbage-collection cascade over the given worklist.\n * A resource reaching refCount 0 that is not a root is removed, and its outgoing\n * references are decremented in turn, until the worklist drains. Factored out of\n * {@link updateFromResourceData} so {@link setRoots} can reuse the same cascade. */\n private collectGarbage(decrementRefs: SignedResourceId[]) {\n let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: SignedResourceId[] = [];\n for (const rid of currentRefs) {\n const res = this.resources.get(rid);\n if (!res) {\n this.invalidateTree();\n throw new TreeStateUpdateError(`orphan resource ${rid}`);\n }\n res.refCount--;\n\n // garbage collection\n if (res.refCount === 0 && !this.roots.has(res.id)) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullSignedResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullSignedResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged(\n `field ${field.name} removed during garbage collection of ${resourceIdToString(res.id)}`,\n );\n });\n if (isNotNullSignedResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged(\n `resource removed during garbage collection: ${resourceIdToString(res.id)}`,\n );\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\n }\n\n /** Replaces the current root set with `newRoots`.\n *\n * Roots that leave the set lose their GC protection: each removed root present in the\n * heap is collected directly (a root sits at refCount 0, so it is never enqueued by an\n * ordinary decrement), and its subtree cascades to collection through the existing\n * refcount GC — the standard removal mechanic, applied to a root. Roots newly added to\n * the set are protected immediately; their resources arrive on the next refresh poll. */\n public setRoots(newRoots: Set<SignedResourceId>) {\n this.checkValid();\n\n const removed: SignedResourceId[] = [];\n for (const rid of this.roots) if (!newRoots.has(rid)) removed.push(rid);\n let added = false;\n for (const rid of newRoots) if (!this.roots.has(rid)) added = true;\n if (removed.length === 0 && !added) return; // no change\n\n // commit the new protected set before collecting, so a removed root is no longer\n // protected while its subtree cascades.\n this.roots.clear();\n for (const rid of newRoots) this.roots.add(rid);\n\n this.rootsChanged.markChanged(\"root set changed\");\n\n for (const rid of removed) {\n const res = this.resources.get(rid);\n if (res === undefined) continue; // root not yet materialized in the heap\n\n // if the (former) root is still referenced by another resource, dropping protection\n // is enough — ordinary refcounting keeps it alive and will collect it later.\n if (res.refCount > 0) continue;\n\n // collect the (now-unprotected) root itself and seed the cascade with the refs it holds\n const seed: SignedResourceId[] = [];\n res.fieldsMap.forEach((field) => {\n if (isNotNullSignedResourceId(field.value)) seed.push(field.value);\n if (isNotNullSignedResourceId(field.error)) seed.push(field.error);\n field.change.markChanged(\n `field ${field.name} removed after root ${resourceIdToString(res.id)} left the root set`,\n );\n });\n if (isNotNullSignedResourceId(res.error)) seed.push(res.error);\n res.resourceRemoved.markChanged(\n `resource removed after leaving the root set: ${resourceIdToString(res.id)}`,\n );\n this.resources.delete(rid);\n\n this.collectGarbage(seed);\n }\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: SignedResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: SignedResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return new PlTreeEntry({ treeProvider: () => this }, rid);\n }\n\n public invalidateTree(msg?: string) {\n this._isValid = false;\n this.invalidationMessage = msg;\n this.rootsChanged.markChanged(\"tree invalidated\");\n this.resources.forEach((res) => {\n res.markAllChanged();\n });\n }\n\n public dumpState(): ExtendedResourceData[] {\n return Array.from(this.resources.values()).map((res) => res.extendedState);\n }\n}\n"],"mappings":"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"}
package/dist/state.d.ts CHANGED
@@ -30,6 +30,47 @@ declare class PlTreeField implements FieldData {
30
30
  type ResourceDataWithFinalState = ResourceData & {
31
31
  finalState: boolean;
32
32
  };
33
+ /** Cross-cycle re-fetch duplication counters, populated by {@link PlTreeState.updateFromResourceData}.
34
+ * Separates genuinely new/changed resources from redundant re-fetches of unchanged ones
35
+ * (the delta-skip opportunity: intra-cycle dedup already happens in the loader, so all waste here
36
+ * is cross-cycle). */
37
+ interface ResourceUpdateStat {
38
+ /** Resources seen for the first time in this update. */
39
+ resourcesNew: number;
40
+ /** Resources already held whose state actually changed. */
41
+ resourcesChanged: number;
42
+ /** Resources already held that came back unchanged: a pure duplicate re-fetch. */
43
+ resourcesUnchanged: number;
44
+ /** data + KV bytes of the unchanged bucket: wasted downlink. */
45
+ bytesUnchanged: number;
46
+ /** Changed resources whose immutable metadata (type, kind, field set) did not change,
47
+ * i.e. metadata re-streamed even though only a value or flag flipped. */
48
+ metadataStableChanged: number;
49
+ /** Per-resource fetches spent on unchanged resources (BFS only; streaming re-sends them
50
+ * inside one stream, so this stays 0). */
51
+ bfsRequestsWasted: number;
52
+ /** Whether the current load used backend streaming; set by the loader, read here to
53
+ * attribute {@link bfsRequestsWasted}. */
54
+ usedStreaming: boolean;
55
+ /** New fields appeared on a held resource. */
56
+ fieldsAdded: number;
57
+ /** Dynamic fields disappeared from a held resource. */
58
+ fieldsRemoved: number;
59
+ /** Existing field value pointer changed (a new value/result was attached). */
60
+ fieldsChanged: number;
61
+ /** KV entries added, changed, or deleted. */
62
+ kvChanged: number;
63
+ /** resourceReady flipped. */
64
+ readyFlips: number;
65
+ /** inputsLocked or outputsLocked transitioned. */
66
+ locksChanged: number;
67
+ /** An error resource was attached. */
68
+ errorsAttached: number;
69
+ /** originalResourceId resolved (duplicate -> original). */
70
+ duplicatesResolved: number;
71
+ /** Held resources that transitioned to final this update. */
72
+ resourcesMarkedFinal: number;
73
+ }
33
74
  /** Never store instances of this class, always get fresh instance from {@link PlTreeState} */
34
75
  declare class PlTreeResource implements ResourceDataWithFinalState {
35
76
  /** Tracks number of other resources referencing this resource. Used to perform garbage collection in tree patching procedure */
@@ -128,7 +169,10 @@ declare class PlTreeState {
128
169
  * so a Computable recomputes when discovered roots appear or disappear. */
129
170
  getRoots(watcher: Watcher): SignedResourceId[];
130
171
  get(watcher: Watcher, rid: SignedResourceId): PlTreeResource;
131
- updateFromResourceData(resourceData: ExtendedResourceData[], allowOrphanInputs?: boolean): void;
172
+ updateFromResourceData(resourceData: ExtendedResourceData[], opts?: {
173
+ allowOrphanInputs?: boolean;
174
+ stat?: ResourceUpdateStat;
175
+ }): void;
132
176
  /** Runs the refcount-decrement garbage-collection cascade over the given worklist.
133
177
  * A resource reaching refCount 0 that is not a root is removed, and its outgoing
134
178
  * references are decremented in turn, until the worklist drains. Factored out of
@@ -149,5 +193,5 @@ declare class PlTreeState {
149
193
  dumpState(): ExtendedResourceData[];
150
194
  }
151
195
  //#endregion
152
- export { ExtendedResourceData, PlTreeResource, PlTreeState, ResourceDataWithFinalState, TreeStateUpdateError };
196
+ export { ExtendedResourceData, PlTreeResource, PlTreeState, ResourceDataWithFinalState, ResourceUpdateStat, TreeStateUpdateError };
153
197
  //# sourceMappingURL=state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","names":[],"sources":["../src/state.ts"],"mappings":"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"}
1
+ {"version":3,"file":"state.d.ts","names":[],"sources":["../src/state.ts"],"mappings":"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"}
package/dist/state.js CHANGED
@@ -299,12 +299,16 @@ var PlTreeState = class {
299
299
  res.resourceRemoved.attachWatcher(watcher);
300
300
  return res;
301
301
  }
302
- updateFromResourceData(resourceData, allowOrphanInputs = false) {
302
+ updateFromResourceData(resourceData, opts = {}) {
303
+ const { allowOrphanInputs = false, stat } = opts;
303
304
  this.checkValid();
304
305
  const incrementRefs = [];
305
306
  const decrementRefs = [];
306
307
  for (const rd of resourceData) {
307
308
  let resource = this.resources.get(rd.id);
309
+ const held = resource !== void 0;
310
+ let changed = false;
311
+ let metadataChanged = false;
308
312
  const statBeforeMutation = resource?.basicState;
309
313
  const unexpectedTransitionError = (reason) => {
310
314
  const { fields, ...rdWithoutFields } = rd;
@@ -313,13 +317,13 @@ var PlTreeState = class {
313
317
  };
314
318
  if (resource !== void 0) {
315
319
  if (resource.finalState) unexpectedTransitionError("resource state can be updated after it is marked as final");
316
- let changed = false;
317
320
  resource.version += 1;
318
321
  if (resource.originalResourceId !== rd.originalResourceId) {
319
322
  if (resource.originalResourceId !== NullSignedResourceId) unexpectedTransitionError("originalResourceId can't change after it is set");
320
323
  resource.originalResourceId = rd.originalResourceId;
321
324
  notEmpty(resource.resourceStateChange).markChanged(`originalResourceId changed for ${resourceIdToString(resource.id)}`);
322
325
  changed = true;
326
+ if (stat) stat.duplicatesResolved++;
323
327
  }
324
328
  if (isNotNullSignedResourceId(rd.error) && resource.error !== rd.error) {
325
329
  if (isNotNullSignedResourceId(resource.error)) unexpectedTransitionError("resource can't change attached error after it is set");
@@ -327,6 +331,7 @@ var PlTreeState = class {
327
331
  incrementRefs.push(resource.error);
328
332
  notEmpty(resource.resourceStateChange).markChanged(`error changed for ${resourceIdToString(resource.id)}`);
329
333
  changed = true;
334
+ if (stat) stat.errorsAttached++;
330
335
  }
331
336
  for (const fd of rd.fields) {
332
337
  let field = resource.fieldsMap.get(fd.name);
@@ -343,6 +348,8 @@ var PlTreeState = class {
343
348
  } else notEmpty(resource.dynamicFieldListChanged).markChanged(`new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`);
344
349
  resource.fieldsMap.set(fd.name, field);
345
350
  changed = true;
351
+ metadataChanged = true;
352
+ if (stat) stat.fieldsAdded++;
346
353
  } else {
347
354
  if (field.type !== fd.type) {
348
355
  if (field.type !== "Dynamic") unexpectedTransitionError(`field changed type ${field.type} -> ${fd.type}`);
@@ -365,6 +372,7 @@ var PlTreeState = class {
365
372
  if (isNotNullSignedResourceId(fd.value)) incrementRefs.push(fd.value);
366
373
  field.change.markChanged(`field ${fd.name} value changed in ${resourceIdToString(resource.id)}`);
367
374
  changed = true;
375
+ if (stat) stat.fieldsChanged++;
368
376
  }
369
377
  if (field.error !== fd.error) {
370
378
  if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);
@@ -391,6 +399,8 @@ var PlTreeState = class {
391
399
  if (field.type === "Input" || field.type === "Service" || field.type === "Output") unexpectedTransitionError(`removal of ${field.type} field ${fieldName}`);
392
400
  field.change.markChanged(`dynamic field ${fieldName} removed from ${resourceIdToString(resource.id)}`);
393
401
  fields.delete(fieldName);
402
+ metadataChanged = true;
403
+ if (stat) stat.fieldsRemoved++;
394
404
  if (isNotNullSignedResourceId(field.value)) decrementRefs.push(field.value);
395
405
  if (isNotNullSignedResourceId(field.error)) decrementRefs.push(field.error);
396
406
  notEmpty(resource.dynamicFieldListChanged).markChanged(`dynamic field ${fieldName} removed from ${resourceIdToString(resource.id)}`);
@@ -401,12 +411,14 @@ var PlTreeState = class {
401
411
  resource.inputsLocked = rd.inputsLocked;
402
412
  notEmpty(resource.lockedChange).markChanged(`inputs locked for ${resourceIdToString(resource.id)}`);
403
413
  changed = true;
414
+ if (stat) stat.locksChanged++;
404
415
  }
405
416
  if (resource.outputsLocked !== rd.outputsLocked) {
406
417
  if (resource.outputsLocked) unexpectedTransitionError("outputs unlocking is not permitted");
407
418
  resource.outputsLocked = rd.outputsLocked;
408
419
  notEmpty(resource.lockedChange).markChanged(`outputs locked for ${resourceIdToString(resource.id)}`);
409
420
  changed = true;
421
+ if (stat) stat.locksChanged++;
410
422
  }
411
423
  if (resource.resourceReady !== rd.resourceReady) {
412
424
  const readyStateBefore = resource.resourceReady;
@@ -415,15 +427,20 @@ var PlTreeState = class {
415
427
  if (!resource.isReadyOrError) unexpectedTransitionError(`resource can't lose it's ready or error state (ready state before ${readyStateBefore})`);
416
428
  notEmpty(resource.resourceStateChange).markChanged(`ready flag changed to ${rd.resourceReady} for ${resourceIdToString(resource.id)}`);
417
429
  changed = true;
430
+ if (stat) stat.readyFlips++;
418
431
  }
419
432
  for (const kv of rd.kv) {
420
433
  const current = resource.kv.get(kv.key);
421
434
  if (current === void 0) {
422
435
  resource.kv.set(kv.key, kv.value);
423
436
  notEmpty(resource.kvChangedPerKey).markChanged(kv.key, `kv added for ${resourceIdToString(resource.id)}: ${kv.key}`);
437
+ changed = true;
438
+ if (stat) stat.kvChanged++;
424
439
  } else if (Buffer.compare(current, kv.value) !== 0) {
425
440
  resource.kv.set(kv.key, kv.value);
426
441
  notEmpty(resource.kvChangedPerKey).markChanged(kv.key, `kv changed for ${resourceIdToString(resource.id)}: ${kv.key}`);
442
+ changed = true;
443
+ if (stat) stat.kvChanged++;
427
444
  }
428
445
  }
429
446
  if (resource.kv.size > rd.kv.length) {
@@ -432,12 +449,17 @@ var PlTreeState = class {
432
449
  if (!newStateKeys.has(key)) {
433
450
  map.delete(key);
434
451
  notEmpty(resource.kvChangedPerKey).markChanged(key, `kv deleted for ${resourceIdToString(resource.id)}: ${key}`);
452
+ changed = true;
453
+ if (stat) stat.kvChanged++;
435
454
  }
436
455
  });
437
456
  }
438
457
  if (changed) {
439
458
  resource.dataVersion = resource.version;
440
- if (this.isFinalPredicate(resource)) resource.markFinal();
459
+ if (this.isFinalPredicate(resource)) {
460
+ resource.markFinal();
461
+ if (stat) stat.resourcesMarkedFinal++;
462
+ }
441
463
  }
442
464
  } else {
443
465
  resource = new PlTreeResource(rd);
@@ -454,6 +476,16 @@ var PlTreeState = class {
454
476
  this.resources.set(resource.id, resource);
455
477
  this.resourcesAdded.markChanged(`new resource ${resourceIdToString(resource.id)} added`);
456
478
  }
479
+ if (stat) if (!held) stat.resourcesNew++;
480
+ else if (changed) {
481
+ stat.resourcesChanged++;
482
+ if (!metadataChanged) stat.metadataStableChanged++;
483
+ } else {
484
+ stat.resourcesUnchanged++;
485
+ stat.bytesUnchanged += rd.data?.length ?? 0;
486
+ for (const kv of rd.kv) stat.bytesUnchanged += kv.value.length;
487
+ if (!stat.usedStreaming) stat.bfsRequestsWasted++;
488
+ }
457
489
  }
458
490
  for (const rid of incrementRefs) {
459
491
  const res = this.resources.get(rid);