@milaboratories/pl-tree 1.6.11 → 1.6.12

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/value_and_error.ts","../src/accessors.ts","../src/state.ts","../src/sync.ts","../src/snapshot.ts","../src/synchronized_tree.ts","../src/dump.ts"],"sourcesContent":["export interface ValueAndError<T> {\n value?: T;\n error?: T;\n}\n\nexport function mapValueAndErrorIfDefined<T1, T2>(\n input: ValueAndError<T1> | undefined,\n mapping: (v: T1) => T2,\n): ValueAndError<T2> | undefined {\n if (input === undefined) return undefined;\n else return mapValueAndError(input, mapping);\n}\n\nexport function mapValueAndError<T1, T2>(input: ValueAndError<T1>, mapping: (v: T1) => T2) {\n const ret = {} as ValueAndError<T2>;\n if (input.value !== undefined) ret.value = mapping(input.value);\n if (input.error !== undefined) ret.error = mapping(input.error);\n return ret;\n}\n","import type { PlTreeResource, PlTreeState } from './state';\nimport type {\n AccessorProvider,\n ComputableCtx,\n ComputableHooks,\n UsageGuard,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType,\n OptionalResourceId } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n resourceTypesEqual,\n resourceTypeToString,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n NullResourceId,\n} from '@milaboratories/pl-client';\nimport type { ValueAndError } from './value_and_error';\nimport { mapValueAndError } from './value_and_error';\nimport type {\n CommonFieldTraverseOps,\n FieldTraversalStep,\n GetFieldStep,\n ResourceTraversalOps,\n} from './traversal_ops';\nimport type { ValueOrError } from './value_or_error';\nimport { parsePlError } from '@milaboratories/pl-errors';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n/** Error encountered during traversal in field or resource. */\nexport class PlError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport type TreeAccessorData = {\n readonly treeProvider: () => PlTreeState;\n readonly hooks?: ComputableHooks;\n};\n\nexport type TreeAccessorInstanceData = {\n readonly guard: UsageGuard;\n readonly ctx: ComputableCtx;\n};\n\nexport function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'\n );\n}\n\nexport function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'\n );\n}\n\nexport function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'\n );\n}\n\n/** Main entry point for using PlTree in reactive setting */\nexport class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntry';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n public readonly rid: ResourceId,\n ) {}\n\n public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {\n ctx,\n guard,\n });\n }\n\n public toJSON(): string {\n return this.toString();\n }\n\n public toString(): string {\n return `[ENTRY:${resourceIdToString(this.rid)}]`;\n }\n}\n\nfunction getResourceFromTree(\n accessorData: TreeAccessorData,\n tree: PlTreeState,\n instanceData: TreeAccessorInstanceData,\n rid: ResourceId,\n ops: ResourceTraversalOps,\n): PlTreeNodeAccessor {\n const acc = new PlTreeNodeAccessor(\n accessorData,\n tree,\n tree.get(instanceData.ctx.watcher, rid),\n instanceData,\n );\n\n if (!ops.ignoreError) {\n const err = acc.getError();\n if (err !== undefined)\n throw parsePlError(notEmpty(err.getDataAsString()), acc.id, acc.resourceType);\n }\n\n if (\n ops.assertResourceType !== undefined\n && (Array.isArray(ops.assertResourceType)\n ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1\n : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,\n );\n\n return acc;\n}\n\nexport class PlTreeEntryAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntryAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly rid: ResourceId,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {\n this.instanceData.guard();\n\n // this is the only entry point to acquire a PlTreeNodeAccessor,\n // so this is the only point where we should attach the hooks\n if (this.accessorData.hooks !== undefined)\n this.instanceData.ctx.attacheHooks(this.accessorData.hooks);\n\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, this.rid, ops);\n }\n}\n\n/**\n * Helper type to simplify implementation of APIs requiring type information.\n * */\nexport type ResourceInfo = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n};\n\n/**\n * Can be called only when a ctx is provided, because pl tree entry is a computable entity.\n * @deprecated\n * */\nexport function treeEntryToResourceInfo(res: PlTreeEntry | ResourceInfo, ctx: ComputableCtx) {\n if (res instanceof PlTreeEntry) return ctx.accessor(res).node().resourceInfo;\n\n return res;\n}\n\n/**\n * API contracts:\n * - API never return {@link NullResourceId}, absence of link is always modeled as `undefined`\n *\n * Important: never store instances of this class, always get fresh instance from {@link PlTreeState} accessor.\n * */\nexport class PlTreeNodeAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeNodeAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly resource: PlTreeResource,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n public get id(): ResourceId {\n this.instanceData.guard();\n return this.resource.id;\n }\n\n public get originalId(): OptionalResourceId {\n this.instanceData.guard();\n return this.resource.originalResourceId;\n }\n\n public get resourceType(): ResourceType {\n this.instanceData.guard();\n return this.resource.type;\n }\n\n public get resourceInfo(): ResourceInfo {\n return { id: this.id, type: this.resourceType };\n }\n\n private getResourceFromTree(rid: ResourceId, ops: ResourceTraversalOps): PlTreeNodeAccessor {\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, rid, ops);\n }\n\n public traverse(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): PlTreeNodeAccessor;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined {\n return this.traverseWithCommon({}, ...steps);\n }\n\n public traverseOrError(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): ValueOrError<PlTreeNodeAccessor, Error>;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n return this.traverseOrErrorWithCommon({}, ...steps);\n }\n\n public traverseWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): PlTreeNodeAccessor | undefined {\n const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);\n if (result === undefined) return undefined;\n\n if (!result.ok) throw result.error;\n return result.value;\n }\n\n public traverseOrErrorWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: PlTreeNodeAccessor = this;\n\n for (const _step of steps) {\n const step: FieldTraversalStep\n = typeof _step === 'string'\n ? {\n ...commonOptions,\n field: _step,\n }\n : { ...commonOptions, ..._step };\n\n const next = current.getField(_step);\n\n if (next === undefined) return undefined;\n\n if (step.pureFieldErrorToUndefined && next.value === undefined && next.error !== undefined)\n return undefined;\n\n if ((!step.ignoreError || next.value === undefined) && next.error !== undefined)\n return {\n ok: false,\n\n // FIXME: in next tickets we'll allow Errors to be thrown.\n error: parsePlError(\n notEmpty(next.error.getDataAsString()),\n current.id, current.resourceType, step.field,\n ),\n };\n\n if (next.value === undefined) {\n if (step.errorIfFieldNotSet)\n return {\n ok: false,\n error: new Error(`field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`),\n };\n // existing but unpopulated field is unstable because it must be resolved at some point\n this.onUnstableLambda('unpopulated_field:' + step.field);\n return undefined;\n }\n\n current = next.value;\n }\n return { ok: true, value: current };\n }\n\n private readonly onUnstableLambda = (marker: string) => {\n this.instanceData.ctx.markUnstable(marker);\n };\n\n public getField(\n _step:\n | (Omit<GetFieldStep, 'errorIfFieldNotFound'> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, 'errorIfFieldNotSet'> & { errorIfFieldNotSet: true })\n ): ValueAndError<PlTreeNodeAccessor>;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined {\n this.instanceData.guard();\n const step: GetFieldStep = typeof _step === 'string' ? { field: _step } : _step;\n\n const ve = this.resource.getField(this.instanceData.ctx.watcher, step, this.onUnstableLambda);\n\n if (ve === undefined) return undefined;\n\n return mapValueAndError(ve, (rid) => this.getResourceFromTree(rid, { ignoreError: true }));\n }\n\n public getInputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getInputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('inputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getOutputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getOutputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('outputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getIsReadyOrError(): boolean {\n this.instanceData.guard();\n const result = this.resource.getIsReadyOrError(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('not_ready:' + this.resourceType.name);\n return result;\n }\n\n public getIsFinal() {\n this.instanceData.guard();\n return this.resource.getIsFinal(this.instanceData.ctx.watcher);\n }\n\n public getError(): PlTreeNodeAccessor | undefined {\n this.instanceData.guard();\n const rid = this.resource.getError(this.instanceData.ctx.watcher);\n if (rid === undefined)\n // absence of error always considered as stable\n return undefined;\n return this.getResourceFromTree(rid, {});\n }\n\n public getData(): Uint8Array | undefined {\n return this.resource.data;\n }\n\n public getDataAsString(): string | undefined {\n return this.resource.getDataAsString();\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n return this.resource.getDataAsJson<T>();\n }\n\n public listInputFields(): string[] {\n this.instanceData.guard();\n this.getInputsLocked(); // will set unstable if not locked\n return this.resource.listInputFields(this.instanceData.ctx.watcher);\n }\n\n public listOutputFields(): string[] {\n this.instanceData.guard();\n this.getOutputsLocked(); // will set unstable if not locked\n return this.resource.listOutputFields(this.instanceData.ctx.watcher);\n }\n\n public listDynamicFields(): string[] {\n this.instanceData.guard();\n return this.resource.listDynamicFields(this.instanceData.ctx.watcher);\n }\n\n public getKeyValue(key: string, unstableIfNotFound: boolean = false): Uint8Array | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValue(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_b:' + key);\n return result;\n }\n\n /** @deprecated */\n public getKeyValueString(key: string): string | undefined {\n return this.getKeyValueAsString(key);\n }\n\n public getKeyValueAsString(key: string, unstableIfNotFound: boolean = false): string | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_s:' + key);\n return result;\n }\n\n public getKeyValueAsJson<T = unknown>(\n key: string,\n unstableIfNotFound: boolean = false,\n ): T | undefined {\n const result = this.resource.getKeyValueAsJson<T>(this.instanceData.ctx.watcher, key);\n if (result === undefined) {\n if (unstableIfNotFound) this.instanceData.ctx.markUnstable('key_not_found_j:' + key);\n return undefined;\n }\n return result;\n }\n\n /**\n * Can be used to pass a higher level accessor that will wrap the resource and throw its\n * errors on node resolution.\n * */\n public toEntryAccessor(): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.tree, this.id, this.instanceData);\n }\n\n /** Can be passed to nested computable. */\n public persist(): PlTreeEntry {\n return new PlTreeEntry(this.accessorData, this.resource.id);\n }\n}\n","import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalResourceId,\n ResourceData,\n ResourceId,\n ResourceKind,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n isNotNullResourceId,\n isNullResourceId,\n NullResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } 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: OptionalResourceId,\n public error: OptionalResourceId,\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 kvChanged? = new ChangeSource();\n\n readonly id: ResourceId;\n originalResourceId: OptionalResourceId;\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: OptionalResourceId;\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<ResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void\n ): ValueAndError<ResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<ResourceId> | 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<ResourceId>;\n if (isNotNullResourceId(field.value)) ret.value = field.value;\n if (isNotNullResourceId(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 !== NullResourceId\n || this.resourceReady\n || this.originalResourceId !== NullResourceId\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): ResourceId | undefined {\n if (isNullResourceId(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.kvChanged?.attachWatcher(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) as T;\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(`ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`);\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();\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 }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged());\n this.finalChanged?.markChanged();\n this.resourceStateChange?.markChanged();\n this.lockedChange?.markChanged();\n this.inputAndServiceFieldListChanged?.markChanged();\n this.outputFieldListChanged?.markChanged();\n this.dynamicFieldListChanged?.markChanged();\n this.kvChanged?.markChanged();\n this.resourceRemoved.markChanged();\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<ResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = 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 constructor(\n /** This will be the only resource not deleted during GC round */\n public readonly root: ResourceId,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\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 public get(watcher: Watcher, rid: ResourceId): 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: ResourceId[] = [];\n const decrementRefs: ResourceId[] = [];\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 !== NullResourceId)\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 changed = true;\n }\n\n // error\n if (resource.error !== rd.error) {\n if (isNotNullResourceId(resource.error))\n unexpectedTransitionError('resource can\\'t change attached error after it is set');\n resource.error = rd.error;\n incrementRefs.push(resource.error as ResourceId);\n notEmpty(resource.resourceStateChange).markChanged();\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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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 } 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 } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged();\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 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 }\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 }\n field.type = fd.type;\n field.change.markChanged();\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged();\n changed = true;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged();\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged();\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 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 fields.delete(fieldName);\n\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged();\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 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 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 changed = true;\n }\n\n // syncing kv\n let kvChanged = false;\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 kvChanged = true;\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n kvChanged = true;\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)) map.delete(key);\n });\n\n kvChanged = true;\n }\n\n if (kvChanged) notEmpty(resource.kvChanged).markChanged();\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 (isNotNullResourceId(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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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();\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 let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: ResourceId[] = [];\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 && res.id !== this.root) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged();\n });\n if (isNotNullResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged();\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\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 /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = 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.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","import type {\n FieldData,\n OptionalResourceId,\n PlTransaction,\n ResourceId,\n} from '@milaboratories/pl-client';\nimport {\n isNullResourceId,\n} from '@milaboratories/pl-client';\nimport Denque from 'denque';\nimport type { ExtendedResourceData, PlTreeState } from './state';\nimport { msToHumanReadable } from '@milaboratories/ts-helpers';\n\n/** Applied to list of fields in resource data. */\nexport type PruningFunction = (resource: ExtendedResourceData) => FieldData[];\n\nexport interface TreeLoadingRequest {\n /** Resource to prime the traversal algorithm. It is ok, if some of them\n * doesn't exist anymore. Should not contain elements from final resource\n * set. */\n readonly seedResources: ResourceId[];\n\n /** Resource ids for which state is already known and not expected to change.\n * Algorithm will not continue traversal over those ids, and states will not\n * be retrieved for them. */\n readonly finalResources: Set<ResourceId>;\n\n /** This function is applied to each resource data field list, before\n * using it continue traversal. This modification also is applied to\n * output data to make result self-consistent in terms that it will contain\n * all referenced resources, this is required to be able to pass it to tree\n * to update the state. */\n readonly pruningFunction?: PruningFunction;\n}\n\n/** Given the current tree state, build the request object to pass to\n * {@link loadTreeState} to load updated state. */\nexport function constructTreeLoadingRequest(\n tree: PlTreeState,\n pruningFunction?: PruningFunction,\n): TreeLoadingRequest {\n const seedResources: ResourceId[] = [];\n const finalResources = new Set<ResourceId>();\n tree.forEachResource((res) => {\n if (res.finalState) finalResources.add(res.id);\n else seedResources.push(res.id);\n });\n\n // if tree is empty, seeding tree reconstruction from the specified root\n if (seedResources.length === 0 && finalResources.size === 0) seedResources.push(tree.root);\n\n return { seedResources, finalResources, pruningFunction };\n}\n\nexport type TreeLoadingStat = {\n requests: number;\n roundTrips: number;\n retrievedResources: number;\n retrievedFields: number;\n retrievedKeyValues: number;\n retrievedResourceDataBytes: number;\n retrievedKeyValueBytes: number;\n prunedFields: number;\n finalResourcesSkipped: number;\n millisSpent: number;\n};\n\nexport function initialTreeLoadingStat(): TreeLoadingStat {\n return {\n requests: 0,\n roundTrips: 0,\n retrievedResources: 0,\n retrievedFields: 0,\n retrievedKeyValues: 0,\n retrievedResourceDataBytes: 0,\n retrievedKeyValueBytes: 0,\n prunedFields: 0,\n finalResourcesSkipped: 0,\n millisSpent: 0,\n };\n}\n\nexport function formatTreeLoadingStat(stat: TreeLoadingStat): string {\n let result = `Requests: ${stat.requests}\\n`;\n result += `Total time: ${msToHumanReadable(stat.millisSpent)}\\n`;\n result += `Round-trips: ${stat.roundTrips}\\n`;\n result += `Resources: ${stat.retrievedResources}\\n`;\n result += `Fields: ${stat.retrievedFields}\\n`;\n result += `KV: ${stat.retrievedKeyValues}\\n`;\n result += `Data Bytes: ${stat.retrievedResourceDataBytes}\\n`;\n result += `KV Bytes: ${stat.retrievedKeyValueBytes}\\n`;\n result += `Pruned fields: ${stat.prunedFields}\\n`;\n result += `Final resources skipped: ${stat.finalResourcesSkipped}`;\n return result;\n}\n\n/** Given the transaction (preferably read-only) and loading request, executes\n * the tree traversal algorithm, and collects fresh states of resources\n * to update the tree state. */\nexport async function loadTreeState(\n tx: PlTransaction,\n loadingRequest: TreeLoadingRequest,\n stats?: TreeLoadingStat,\n): Promise<ExtendedResourceData[]> {\n // saving start timestamp to add time spent in this function to the stats at the end of the method\n const startTimestamp = Date.now();\n\n // counting the request\n if (stats) stats.requests++;\n\n const { seedResources, finalResources, pruningFunction } = loadingRequest;\n\n // Main idea of using a queue here is that responses will arrive in the same order as they were\n // sent, so we can only wait for the earliest sent unprocessed response promise at any given moment.\n // In such a way logic become linear without recursion, and at the same time deal with data\n // as soon as it arrives.\n\n const pending = new Denque<Promise<ExtendedResourceData | undefined>>();\n\n // vars to calculate number of roundtrips for stats\n let roundTripToggle: boolean = true;\n let numberOfRoundTrips = 0;\n\n // tracking resources we already requested\n const requested = new Set<ResourceId>();\n const requestState = (rid: OptionalResourceId) => {\n if (isNullResourceId(rid) || requested.has(rid)) return;\n\n // separate check to collect stats\n if (finalResources.has(rid)) {\n if (stats) stats.finalResourcesSkipped++;\n return;\n }\n\n // adding the id, so we will not request it's state again if somebody else\n // references the same resource\n requested.add(rid);\n\n // requesting resource and all kv records\n const resourceData = tx.getResourceDataIfExists(rid, true);\n const kvData = tx.listKeyValuesIfResourceExists(rid);\n\n // counting round-trip (begin)\n const addRT = roundTripToggle;\n if (roundTripToggle) roundTripToggle = false;\n\n // pushing combined promise\n pending.push(\n (async () => {\n const [resource, kv] = await Promise.all([resourceData, kvData]);\n\n // counting round-trip, actually incrementing counter and returning toggle back, so the next request can acquire it\n if (addRT) {\n numberOfRoundTrips++;\n roundTripToggle = true;\n }\n\n if (resource === undefined) return undefined;\n\n if (kv === undefined) throw new Error('Inconsistent replies');\n\n return { ...resource, kv };\n })(),\n );\n };\n\n // sending seed requests\n seedResources.forEach((rid) => requestState(rid));\n\n const result: ExtendedResourceData[] = [];\n while (true) {\n // taking next pending request\n const nextResourcePromise = pending.shift();\n if (nextResourcePromise === undefined)\n // this means we have no pending requests and traversal is over\n break;\n\n // at this point we pause and wait for the nest requested resource state to arrive\n let nextResource = await nextResourcePromise;\n if (nextResource === undefined)\n // ignoring resources that were not found (this may happen for seed resource ids)\n continue;\n\n if (pruningFunction !== undefined) {\n // apply field pruning, if requested\n const fieldsAfterPruning = pruningFunction(nextResource);\n // collecting stats\n if (stats) stats.prunedFields += nextResource.fields.length - fieldsAfterPruning.length;\n nextResource = { ...nextResource, fields: fieldsAfterPruning };\n }\n\n // continue traversal over the referenced resource\n requestState(nextResource.error);\n for (const field of nextResource.fields) {\n requestState(field.value);\n requestState(field.error);\n }\n\n // collecting stats\n if (stats) {\n stats.retrievedResources++;\n stats.retrievedFields += nextResource.fields.length;\n stats.retrievedKeyValues += nextResource.kv.length;\n stats.retrievedResourceDataBytes += nextResource.data?.length ?? 0;\n for (const kv of nextResource.kv) stats.retrievedKeyValueBytes += kv.value.length;\n }\n\n // aggregating the state\n result.push(nextResource);\n }\n\n // adding the time we spent in this method to stats\n if (stats) {\n stats.millisSpent += Date.now() - startTimestamp;\n stats.roundTrips += numberOfRoundTrips;\n }\n\n return result;\n}\n","import type { ResourceId, ResourceType } from '@milaboratories/pl-client';\nimport type { Optional, Writable } from 'utility-types';\nimport type { ZodType, z } from 'zod';\nimport type { PlTreeNodeAccessor } from './accessors';\nimport { PlTreeEntry, PlTreeEntryAccessor } from './accessors';\nimport type { ComputableCtx } from '@milaboratories/computable';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n\n/**\n * A DTO that can be generated from a tree node to make a snapshot of specific parts of it's state.\n * Such snapshots can then be used in core that requires this information without the need of\n * retrieving state from the tree.\n */\nexport type ResourceSnapshot<\n Data = undefined,\n Fields extends Record<string, ResourceId | undefined> | undefined = undefined,\n KV extends Record<string, unknown> | undefined = undefined,\n> = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** The most generic type of ResourceSnapshot. */\ntype ResourceSnapshotGeneric = ResourceSnapshot<\n unknown,\n Record<string, ResourceId | undefined> | undefined,\n Record<string, unknown> | undefined\n>;\n\n/** Request that we'll pass to getResourceSnapshot function. We infer the type of ResourceSnapshot from this. */\nexport type ResourceSnapshotSchema<\n Data extends ZodType | 'raw' | undefined = undefined,\n Fields extends Record<string, boolean> | undefined = undefined,\n KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n> = {\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** Creates ResourceSnapshotSchema. It converts an optional schema type to schema type. */\nexport function rsSchema<\n const Data extends ZodType | 'raw' | undefined = undefined,\n const Fields extends Record<string, boolean> | undefined = undefined,\n const KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n>(\n schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>,\n): ResourceSnapshotSchema<Data, Fields, KV> {\n return schema as any;\n}\n\n/** The most generic type of ResourceSnapshotSchema. */\ntype ResourceSnapshotSchemaGeneric = ResourceSnapshotSchema<\n ZodType | 'raw' | undefined,\n Record<string, boolean> | undefined,\n Record<string, ZodType | 'raw'> | undefined\n>;\n\n/**\n * If Data is 'raw' in schema, we'll get bytes,\n * if it's Zod, we'll parse it via zod.\n * Or else we just got undefined in the field.\n */\ntype InferDataType<Data extends ZodType | 'raw' | undefined> = Data extends 'raw'\n ? Uint8Array\n : Data extends ZodType\n ? z.infer<Data>\n : undefined;\n\n/**\n * If Fields is a record of field names to booleans,\n * then if the value of the field is true, we'll require this field and throw a Error if it wasn't found.\n * If it's false and doesn't exist, we'll return undefined.\n * If Fields type is undefined, we won't set fields at all.\n */\ntype InferFieldsType<Fields extends Record<string, boolean> | undefined> = Fields extends undefined\n ? undefined\n : {\n [FieldName in keyof Fields]: Fields[FieldName] extends true\n ? ResourceId\n : ResourceId | undefined;\n };\n\n/**\n * If KV is undefined, won't set it.\n * If one of values is Zod, we'll get KV and converts it to Zod schema.\n * If the value is 'raw', just returns bytes.\n */\ntype InferKVType<KV extends Record<string, ZodType | 'raw'> | undefined> = KV extends undefined\n ? undefined\n : {\n [FieldName in keyof KV]: KV[FieldName] extends ZodType ? z.infer<KV[FieldName]> : Uint8Array;\n };\n\n/** Infer ResourceSnapshot from ResourceShapshotSchema, S can be any ResourceSnapshotSchema. */\nexport type InferSnapshot<S extends ResourceSnapshotSchemaGeneric> = ResourceSnapshot<\n InferDataType<S['data']>,\n InferFieldsType<S['fields']>,\n InferKVType<S['kv']>\n>;\n\n/** Gets a ResourceSnapshot from PlTreeEntry. */\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry,\n schema: Schema,\n ctx: ComputableCtx\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry | PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema,\n ctx?: ComputableCtx,\n): InferSnapshot<Schema> {\n const node\n = res instanceof PlTreeEntry\n ? notEmpty(ctx).accessor(res).node()\n : res instanceof PlTreeEntryAccessor\n ? res.node()\n : res;\n const info = node.resourceInfo;\n const result: Optional<Writable<ResourceSnapshotGeneric>, 'data' | 'fields' | 'kv'> = { ...info };\n\n if (schema.data !== undefined) {\n if (schema.data === 'raw') result.data = node.getData();\n else result.data = schema.data.parse(node.getDataAsJson());\n }\n\n if (schema.fields !== undefined) {\n const fields: Record<string, ResourceId | undefined> = {};\n // even if field is not defined, corresponding object field\n // with \"undefined\" value will still be added\n for (const [fieldName, required] of Object.entries(schema.fields))\n fields[fieldName] = node.traverse({\n field: fieldName,\n errorIfFieldNotSet: required,\n stableIfNotFound: !required,\n })?.id;\n result.fields = fields;\n }\n\n if (schema.kv !== undefined) {\n const kv: Record<string, unknown> = {};\n for (const [fieldName, type] of Object.entries(schema.kv)) {\n const value = node.getKeyValue(fieldName);\n\n if (value === undefined) {\n throw new Error(`Key not found ${fieldName}`);\n } else if (type === 'raw') {\n kv[fieldName] = value;\n } else {\n kv[fieldName] = type.parse(JSON.parse(Buffer.from(value).toString('utf-8')));\n }\n }\n result.kv = kv;\n }\n\n return result as any;\n}\n\n/** @deprecated */\nexport type ResourceWithData = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly fields: Map<string, ResourceId | undefined>;\n readonly data?: Uint8Array;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithData(\n res: PlTreeEntry | ResourceWithData,\n fields: string[],\n ctx: ComputableCtx,\n): ResourceWithData {\n if (res instanceof PlTreeEntry) {\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n\n const fValues: [string, ResourceId | undefined][] = fields.map((name) => [\n name,\n node.getField(name)?.value?.id,\n ]);\n\n return {\n ...info,\n fields: new Map(fValues),\n data: node.getData() ?? new Uint8Array(),\n };\n }\n\n return res;\n}\n\n/** @deprecated */\nexport type ResourceWithMetadata = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly metadata: Record<string, any>;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithMetadata(\n res: PlTreeEntry | ResourceWithMetadata,\n mdKeys: string[],\n ctx: ComputableCtx,\n): ResourceWithMetadata {\n if (!(res instanceof PlTreeEntry)) return res;\n\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n const mdEntries: [string, any][] = mdKeys.map((k) => [k, node.getKeyValue(k)]);\n\n return {\n ...info,\n metadata: Object.fromEntries(mdEntries),\n };\n}\n","import { PollingComputableHooks } from '@milaboratories/computable';\nimport { PlTreeEntry } from './accessors';\nimport type {\n FinalResourceDataPredicate,\n PlClient,\n ResourceId,\n TxOps,\n} from '@milaboratories/pl-client';\nimport {\n isTimeoutOrCancelError,\n} from '@milaboratories/pl-client';\nimport type { ExtendedResourceData } from './state';\nimport { PlTreeState, TreeStateUpdateError } from './state';\nimport type {\n PruningFunction,\n TreeLoadingStat,\n} from './sync';\nimport {\n constructTreeLoadingRequest,\n initialTreeLoadingStat,\n loadTreeState,\n} from './sync';\nimport * as tp from 'node:timers/promises';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\n\ntype StatLoggingMode = 'cumulative' | 'per-request';\n\nexport type SynchronizedTreeOps = {\n /** Override final predicate from the PlClient */\n finalPredicateOverride?: FinalResourceDataPredicate;\n\n /** Pruning function to limit set of fields through which tree will\n * traverse during state synchronization */\n pruning?: PruningFunction;\n\n /** Interval after last sync to sleep before the next one */\n pollingInterval: number;\n /** For how long to continue polling after the last derived value access */\n stopPollingDelay: number;\n\n /** If one of the values, tree will log stats of each polling request */\n logStat?: StatLoggingMode;\n\n /** Timeout for initial tree loading. If not specified, will use default for RO tx from pl-client. */\n initialTreeLoadingTimeout?: number;\n};\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nexport class SynchronizedTreeState {\n private readonly finalPredicate: FinalResourceDataPredicate;\n private state: PlTreeState;\n private readonly pollingInterval: number;\n private readonly pruning?: PruningFunction;\n private readonly logStat?: StatLoggingMode;\n private readonly hooks: PollingComputableHooks;\n private readonly abortController = new AbortController();\n\n private constructor(\n private readonly pl: PlClient,\n private readonly root: ResourceId,\n ops: SynchronizedTreeOps,\n private readonly logger?: MiLogger,\n ) {\n const { finalPredicateOverride, pruning, pollingInterval, stopPollingDelay, logStat } = ops;\n this.pruning = pruning;\n this.pollingInterval = pollingInterval;\n this.finalPredicate = finalPredicateOverride ?? pl.finalPredicate;\n this.logStat = logStat;\n this.state = new PlTreeState(root, this.finalPredicate);\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return new PlTreeEntry({ treeProvider: () => this.state, hooks: this.hooks }, rid);\n }\n\n /** Can be used to externally kick off the synchronization polling loop, and\n * await for the first synchronization to happen. */\n public async refreshState(): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n await this.hooks.refreshState();\n }\n\n private currentLoopDelayInterrupt: AbortController | undefined = undefined;\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n /** Called from computable hooks when external observer asks for state refresh */\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n if (this.terminated) reject(new Error('tree synchronization is terminated'));\n else {\n this.scheduledOnNextState.push({ resolve, reject });\n if (this.currentLoopDelayInterrupt) {\n this.currentLoopDelayInterrupt.abort();\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n /** Called from observer */\n private startUpdating(): void {\n if (this.terminated) return;\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n /** Executed from the main loop, and initialization procedure. */\n private async refresh(stats?: TreeLoadingStat, txOps?: TxOps): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n const request = constructTreeLoadingRequest(this.state, this.pruning);\n const data = await this.pl.withReadTx('ReadingTree', async (tx) => {\n return await loadTreeState(tx, request, stats);\n }, txOps);\n this.state.updateFromResourceData(data, true);\n }\n\n /** If true this tree state is permanently terminaed. */\n private terminated = false;\n\n private async mainLoop() {\n // will hold request stats\n let stat = this.logStat ? initialTreeLoadingStat() : undefined;\n\n let lastUpdate = Date.now();\n\n while (true) {\n if (!this.keepRunning || this.terminated) break;\n\n // saving those who want to be notified about new state here\n // because those who will be added during the tree retrieval\n // should be notified only on the next round\n let toNotify: ScheduledRefresh[] | undefined = undefined;\n if (this.scheduledOnNextState.length > 0) {\n toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n }\n\n try {\n // resetting stats if we were asked to collect non-cumulative stats\n if (this.logStat === 'per-request') stat = initialTreeLoadingStat();\n\n // actual tree synchronization\n await this.refresh(stat);\n\n // logging stats if we were asked to\n if (stat && this.logger) this.logger.info(`Tree stat (success, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we got new state\n if (toNotify !== undefined) for (const n of toNotify) n.resolve();\n } catch (e: any) {\n // logging stats if we were asked to (even if error occured)\n if (stat && this.logger) this.logger.info(`Tree stat (error, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we failed to refresh the state\n if (toNotify !== undefined) for (const n of toNotify) n.reject(e);\n\n // catching tree update errors, as they may leave our tree in inconsistent state\n if (e instanceof TreeStateUpdateError) {\n // important error logging, this should never happen\n this.logger?.error(e);\n\n // marking everybody who used previous state as changed\n this.state.invalidateTree('stat update error');\n // creating new tree\n this.state = new PlTreeState(this.root, this.finalPredicate);\n\n // scheduling state update without delay\n continue;\n\n // unfortunately external observer may still see tree in its default\n // empty state, though this is best we can do in this exceptional\n // situation, and hope on caching layers inside computables to present\n // some stale state until we reconstruct the tree again\n } else this.logger?.warn(e);\n }\n\n if (!this.keepRunning || this.terminated) break;\n\n if (this.scheduledOnNextState.length === 0) {\n try {\n this.currentLoopDelayInterrupt = new AbortController();\n await tp.setTimeout(this.pollingInterval,\n AbortSignal.any([this.abortController.signal, this.currentLoopDelayInterrupt.signal]));\n } catch (e: unknown) {\n if (!isTimeoutOrCancelError(e)) throw new Error('Unexpected error', { cause: e });\n break;\n } finally {\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n // reset only as a very last line\n this.currentLoop = undefined;\n }\n\n /**\n * Dumps the current state of the tree.\n * @returns An array of ExtendedResourceData objects representing the current state of the tree.\n */\n public dumpState(): ExtendedResourceData[] {\n return this.state.dumpState();\n }\n\n /**\n * Terminates the internal loop, and permanently destoys all internal state, so\n * all computables using this state will resolve to errors.\n * */\n public async terminate(): Promise<void> {\n this.keepRunning = false;\n this.terminated = true;\n this.abortController.abort();\n\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n\n this.state.invalidateTree('synchronization terminated for the tree');\n }\n\n /** @deprecated */\n public async awaitSyncLoopTermination(): Promise<void> {\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n }\n\n public static async init(\n pl: PlClient,\n root: ResourceId,\n ops: SynchronizedTreeOps,\n logger?: MiLogger,\n ) {\n const tree = new SynchronizedTreeState(pl, root, ops, logger);\n\n const stat = ops.logStat ? initialTreeLoadingStat() : undefined;\n\n let ok = false;\n\n try {\n await tree.refresh(stat, {\n timeout: ops.initialTreeLoadingTimeout,\n });\n ok = true;\n } finally {\n // logging stats if we were asked to (even if error occured)\n if (stat && logger)\n logger.info(\n `Tree stat (initial load, ${ok ? 'success' : 'failure'}): ${JSON.stringify(stat)}`,\n );\n }\n\n return tree;\n }\n}\n","import type { ExtendedResourceData } from './state';\n\nexport type ResourceStats = {\n /** Number of resources of this type */\n count: number;\n /** Total number of bytes in the field names of all resources of this type */\n fieldNameBytes: number;\n /** Total number of fields in all resources of this type */\n fieldsCount: number;\n /** Total number of bytes in the data of all resources of this type */\n dataBytes: number;\n /** Total number of key-value records in all resources of this type */\n kvCount: number;\n /** Total number of bytes in the key-value records of all resources of this type */\n kvBytes: number;\n};\n\n/**\n * A map of resource type statistics, keyed by the resource type name and version.\n *\n * @type {Record<string, ResourceStats>}\n */\nexport type TreeDumpStats = {\n total: ResourceStats;\n byResourceType: Record<`${string}/${string}`, ResourceStats>;\n};\n\n/**\n * Analyzes a collection of resources and generates statistics grouped by resource type.\n *\n * This function processes an array of ExtendedResourceData and calculates various metrics\n * for each unique resource type, including:\n * - Count of resources\n * - Total bytes in field names\n * - Total number of fields\n * - Total bytes in resource data\n * - Total number of key-value records\n * - Total bytes in key-value records\n *\n * The statistics are organized by resource type using a key in the format \"typeName/version\".\n *\n * @param dumpStats - Array of ExtendedResourceData objects to analyze\n * @returns A DumpStats object containing statistics for each resource type\n * @example\n * ```typescript\n * const resources = [...]; // Array of ExtendedResourceData\n * const stats = treeDumpStats(resources);\n * // stats = {\n * // \"MyResource/1\": {\n * // count: 5,\n * // fieldNameBytes: 150,\n * // fieldsCount: 10,\n * // dataBytes: 1024,\n * // kvCount: 3,\n * // kvBytes: 256\n * // },\n * // ...\n * // }\n * ```\n */\nexport function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {\n const stats: TreeDumpStats = {\n total: {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n },\n byResourceType: {},\n };\n\n for (const resource of dumpStats) {\n const typeKey = `${resource.type.name}/${resource.type.version}` as const;\n if (!stats.byResourceType[typeKey]) {\n stats.byResourceType[typeKey] = {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n };\n }\n\n const typeStats = stats.byResourceType[typeKey];\n typeStats.count++;\n stats.total.count++;\n\n for (const field of resource.fields) {\n typeStats.fieldNameBytes += field.name.length;\n typeStats.fieldsCount++;\n stats.total.fieldNameBytes += field.name.length;\n stats.total.fieldsCount++;\n }\n\n if (resource.data) {\n const dataLength = resource.data?.length ?? 0;\n typeStats.dataBytes += dataLength;\n stats.total.dataBytes += dataLength;\n }\n\n typeStats.kvCount += resource.kv.length;\n stats.total.kvCount += resource.kv.length;\n\n for (const kv of resource.kv) {\n const kvLength = kv.key.length + kv.value.length;\n typeStats.kvBytes += kvLength;\n stats.total.kvBytes += kvLength;\n }\n }\n\n return stats;\n}\n"],"names":["mapValueAndErrorIfDefined","input","mapping","mapValueAndError","ret","PlError","message","isPlTreeEntry","obj","isPlTreeEntryAccessor","isPlTreeNodeAccessor","PlTreeEntry","accessorData","rid","__publicField","ctx","guard","PlTreeEntryAccessor","resourceIdToString","getResourceFromTree","tree","instanceData","ops","acc","PlTreeNodeAccessor","err","parsePlError","notEmpty","rt","resourceTypesEqual","resourceTypeToString","treeEntryToResourceInfo","res","resource","marker","steps","commonOptions","result","current","_step","step","next","ve","key","unstableIfNotFound","TreeStateUpdateError","PlTreeField","name","type","value","error","status","valueIsFinal","resourceVersion","ChangeSource","InitialResourceVersion","PlTreeResource","initialState","logger","msg","watcher","onUnstable","field","_a","_b","_c","isNotNullResourceId","NullResourceId","isNullResourceId","bytes","cachedDecode","cachedDeserialize","stringifyWithResourceId","_d","_e","_f","_g","PlTreeState","root","isFinalPredicate","cb","v","resourceData","allowOrphanInputs","incrementRefs","decrementRefs","rd","statBeforeMutation","unexpectedTransitionError","reason","fields","rdWithoutFields","changed","fd","fieldName","readyStateBefore","kvChanged","kv","newStateKeys","_value","map","currentRefs","nextRefs","constructTreeLoadingRequest","pruningFunction","seedResources","finalResources","initialTreeLoadingStat","formatTreeLoadingStat","stat","msToHumanReadable","loadTreeState","tx","loadingRequest","stats","startTimestamp","pending","Denque","roundTripToggle","numberOfRoundTrips","requested","requestState","kvData","addRT","nextResourcePromise","nextResource","fieldsAfterPruning","rsSchema","schema","makeResourceSnapshot","node","required","treeEntryToResourceWithData","info","fValues","treeEntryToResourceWithMetadata","mdKeys","mdEntries","k","SynchronizedTreeState","pl","finalPredicateOverride","pruning","pollingInterval","stopPollingDelay","logStat","PollingComputableHooks","resolve","reject","txOps","request","data","lastUpdate","toNotify","n","e","tp","isTimeoutOrCancelError","ok","treeDumpStats","dumpStats","typeKey","typeStats","dataLength","kvLength"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/value_and_error.ts","../src/accessors.ts","../src/state.ts","../src/sync.ts","../src/snapshot.ts","../src/synchronized_tree.ts","../src/dump.ts"],"sourcesContent":["export interface ValueAndError<T> {\n value?: T;\n error?: T;\n}\n\nexport function mapValueAndErrorIfDefined<T1, T2>(\n input: ValueAndError<T1> | undefined,\n mapping: (v: T1) => T2,\n): ValueAndError<T2> | undefined {\n if (input === undefined) return undefined;\n else return mapValueAndError(input, mapping);\n}\n\nexport function mapValueAndError<T1, T2>(input: ValueAndError<T1>, mapping: (v: T1) => T2) {\n const ret = {} as ValueAndError<T2>;\n if (input.value !== undefined) ret.value = mapping(input.value);\n if (input.error !== undefined) ret.error = mapping(input.error);\n return ret;\n}\n","import type { PlTreeResource, PlTreeState } from './state';\nimport type {\n AccessorProvider,\n ComputableCtx,\n ComputableHooks,\n UsageGuard,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType,\n OptionalResourceId } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n resourceTypesEqual,\n resourceTypeToString,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n NullResourceId,\n} from '@milaboratories/pl-client';\nimport type { ValueAndError } from './value_and_error';\nimport { mapValueAndError } from './value_and_error';\nimport type {\n CommonFieldTraverseOps,\n FieldTraversalStep,\n GetFieldStep,\n ResourceTraversalOps,\n} from './traversal_ops';\nimport type { ValueOrError } from './value_or_error';\nimport { parsePlError } from '@milaboratories/pl-errors';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n/** Error encountered during traversal in field or resource. */\nexport class PlError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport type TreeAccessorData = {\n readonly treeProvider: () => PlTreeState;\n readonly hooks?: ComputableHooks;\n};\n\nexport type TreeAccessorInstanceData = {\n readonly guard: UsageGuard;\n readonly ctx: ComputableCtx;\n};\n\nexport function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'\n );\n}\n\nexport function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'\n );\n}\n\nexport function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'\n );\n}\n\n/** Main entry point for using PlTree in reactive setting */\nexport class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntry';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n public readonly rid: ResourceId,\n ) {}\n\n public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {\n ctx,\n guard,\n });\n }\n\n public toJSON(): string {\n return this.toString();\n }\n\n public toString(): string {\n return `[ENTRY:${resourceIdToString(this.rid)}]`;\n }\n}\n\nfunction getResourceFromTree(\n accessorData: TreeAccessorData,\n tree: PlTreeState,\n instanceData: TreeAccessorInstanceData,\n rid: ResourceId,\n ops: ResourceTraversalOps,\n): PlTreeNodeAccessor {\n const acc = new PlTreeNodeAccessor(\n accessorData,\n tree,\n tree.get(instanceData.ctx.watcher, rid),\n instanceData,\n );\n\n if (!ops.ignoreError) {\n const err = acc.getError();\n if (err !== undefined)\n throw parsePlError(notEmpty(err.getDataAsString()), acc.id, acc.resourceType);\n }\n\n if (\n ops.assertResourceType !== undefined\n && (Array.isArray(ops.assertResourceType)\n ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1\n : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,\n );\n\n return acc;\n}\n\nexport class PlTreeEntryAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntryAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly rid: ResourceId,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {\n this.instanceData.guard();\n\n // this is the only entry point to acquire a PlTreeNodeAccessor,\n // so this is the only point where we should attach the hooks\n if (this.accessorData.hooks !== undefined)\n this.instanceData.ctx.attacheHooks(this.accessorData.hooks);\n\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, this.rid, ops);\n }\n}\n\n/**\n * Helper type to simplify implementation of APIs requiring type information.\n * */\nexport type ResourceInfo = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n};\n\n/**\n * Can be called only when a ctx is provided, because pl tree entry is a computable entity.\n * @deprecated\n * */\nexport function treeEntryToResourceInfo(res: PlTreeEntry | ResourceInfo, ctx: ComputableCtx) {\n if (res instanceof PlTreeEntry) return ctx.accessor(res).node().resourceInfo;\n\n return res;\n}\n\n/**\n * API contracts:\n * - API never return {@link NullResourceId}, absence of link is always modeled as `undefined`\n *\n * Important: never store instances of this class, always get fresh instance from {@link PlTreeState} accessor.\n * */\nexport class PlTreeNodeAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeNodeAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly resource: PlTreeResource,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n public get id(): ResourceId {\n this.instanceData.guard();\n return this.resource.id;\n }\n\n public get originalId(): OptionalResourceId {\n this.instanceData.guard();\n return this.resource.originalResourceId;\n }\n\n public get resourceType(): ResourceType {\n this.instanceData.guard();\n return this.resource.type;\n }\n\n public get resourceInfo(): ResourceInfo {\n return { id: this.id, type: this.resourceType };\n }\n\n private getResourceFromTree(rid: ResourceId, ops: ResourceTraversalOps): PlTreeNodeAccessor {\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, rid, ops);\n }\n\n public traverse(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): PlTreeNodeAccessor;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined {\n return this.traverseWithCommon({}, ...steps);\n }\n\n public traverseOrError(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): ValueOrError<PlTreeNodeAccessor, Error>;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n return this.traverseOrErrorWithCommon({}, ...steps);\n }\n\n public traverseWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): PlTreeNodeAccessor | undefined {\n const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);\n if (result === undefined) return undefined;\n\n if (!result.ok) throw result.error;\n return result.value;\n }\n\n public traverseOrErrorWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: PlTreeNodeAccessor = this;\n\n for (const _step of steps) {\n const step: FieldTraversalStep\n = typeof _step === 'string'\n ? {\n ...commonOptions,\n field: _step,\n }\n : { ...commonOptions, ..._step };\n\n const next = current.getField(_step);\n\n if (next === undefined) return undefined;\n\n if (step.pureFieldErrorToUndefined && next.value === undefined && next.error !== undefined)\n return undefined;\n\n if ((!step.ignoreError || next.value === undefined) && next.error !== undefined)\n return {\n ok: false,\n\n // FIXME: in next tickets we'll allow Errors to be thrown.\n error: parsePlError(\n notEmpty(next.error.getDataAsString()),\n current.id, current.resourceType, step.field,\n ),\n };\n\n if (next.value === undefined) {\n if (step.errorIfFieldNotSet)\n return {\n ok: false,\n error: new Error(`field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`),\n };\n // existing but unpopulated field is unstable because it must be resolved at some point\n this.onUnstableLambda('unpopulated_field:' + step.field);\n return undefined;\n }\n\n current = next.value;\n }\n return { ok: true, value: current };\n }\n\n private readonly onUnstableLambda = (marker: string) => {\n this.instanceData.ctx.markUnstable(marker);\n };\n\n public getField(\n _step:\n | (Omit<GetFieldStep, 'errorIfFieldNotFound'> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, 'errorIfFieldNotSet'> & { errorIfFieldNotSet: true })\n ): ValueAndError<PlTreeNodeAccessor>;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined {\n this.instanceData.guard();\n const step: GetFieldStep = typeof _step === 'string' ? { field: _step } : _step;\n\n const ve = this.resource.getField(this.instanceData.ctx.watcher, step, this.onUnstableLambda);\n\n if (ve === undefined) return undefined;\n\n return mapValueAndError(ve, (rid) => this.getResourceFromTree(rid, { ignoreError: true }));\n }\n\n public getInputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getInputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('inputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getOutputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getOutputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('outputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getIsReadyOrError(): boolean {\n this.instanceData.guard();\n const result = this.resource.getIsReadyOrError(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('not_ready:' + this.resourceType.name);\n return result;\n }\n\n public getIsFinal() {\n this.instanceData.guard();\n return this.resource.getIsFinal(this.instanceData.ctx.watcher);\n }\n\n public getError(): PlTreeNodeAccessor | undefined {\n this.instanceData.guard();\n const rid = this.resource.getError(this.instanceData.ctx.watcher);\n if (rid === undefined)\n // absence of error always considered as stable\n return undefined;\n return this.getResourceFromTree(rid, {});\n }\n\n public getData(): Uint8Array | undefined {\n return this.resource.data;\n }\n\n public getDataAsString(): string | undefined {\n return this.resource.getDataAsString();\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n return this.resource.getDataAsJson<T>();\n }\n\n public listInputFields(): string[] {\n this.instanceData.guard();\n this.getInputsLocked(); // will set unstable if not locked\n return this.resource.listInputFields(this.instanceData.ctx.watcher);\n }\n\n public listOutputFields(): string[] {\n this.instanceData.guard();\n this.getOutputsLocked(); // will set unstable if not locked\n return this.resource.listOutputFields(this.instanceData.ctx.watcher);\n }\n\n public listDynamicFields(): string[] {\n this.instanceData.guard();\n return this.resource.listDynamicFields(this.instanceData.ctx.watcher);\n }\n\n public getKeyValue(key: string, unstableIfNotFound: boolean = false): Uint8Array | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValue(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_b:' + key);\n return result;\n }\n\n /** @deprecated */\n public getKeyValueString(key: string): string | undefined {\n return this.getKeyValueAsString(key);\n }\n\n public getKeyValueAsString(key: string, unstableIfNotFound: boolean = false): string | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_s:' + key);\n return result;\n }\n\n public getKeyValueAsJson<T = unknown>(\n key: string,\n unstableIfNotFound: boolean = false,\n ): T | undefined {\n const result = this.resource.getKeyValueAsJson<T>(this.instanceData.ctx.watcher, key);\n if (result === undefined) {\n if (unstableIfNotFound) this.instanceData.ctx.markUnstable('key_not_found_j:' + key);\n return undefined;\n }\n return result;\n }\n\n /**\n * Can be used to pass a higher level accessor that will wrap the resource and throw its\n * errors on node resolution.\n * */\n public toEntryAccessor(): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.tree, this.id, this.instanceData);\n }\n\n /** Can be passed to nested computable. */\n public persist(): PlTreeEntry {\n return new PlTreeEntry(this.accessorData, this.resource.id);\n }\n}\n","import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalResourceId,\n ResourceData,\n ResourceId,\n ResourceKind,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n isNotNullResourceId,\n isNullResourceId,\n NullResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } 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: OptionalResourceId,\n public error: OptionalResourceId,\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 kvChanged? = new ChangeSource();\n\n readonly id: ResourceId;\n originalResourceId: OptionalResourceId;\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: OptionalResourceId;\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<ResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void\n ): ValueAndError<ResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<ResourceId> | 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<ResourceId>;\n if (isNotNullResourceId(field.value)) ret.value = field.value;\n if (isNotNullResourceId(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 !== NullResourceId\n || this.resourceReady\n || this.originalResourceId !== NullResourceId\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): ResourceId | undefined {\n if (isNullResourceId(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.kvChanged?.attachWatcher(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(`ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`);\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();\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 }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged());\n this.finalChanged?.markChanged();\n this.resourceStateChange?.markChanged();\n this.lockedChange?.markChanged();\n this.inputAndServiceFieldListChanged?.markChanged();\n this.outputFieldListChanged?.markChanged();\n this.dynamicFieldListChanged?.markChanged();\n this.kvChanged?.markChanged();\n this.resourceRemoved.markChanged();\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<ResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = 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 constructor(\n /** This will be the only resource not deleted during GC round */\n public readonly root: ResourceId,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\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 public get(watcher: Watcher, rid: ResourceId): 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: ResourceId[] = [];\n const decrementRefs: ResourceId[] = [];\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 !== NullResourceId)\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 changed = true;\n }\n\n // error\n if (resource.error !== rd.error) {\n if (isNotNullResourceId(resource.error))\n unexpectedTransitionError('resource can\\'t change attached error after it is set');\n resource.error = rd.error;\n incrementRefs.push(resource.error as ResourceId);\n notEmpty(resource.resourceStateChange).markChanged();\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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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 } 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 } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged();\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 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 }\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 }\n field.type = fd.type;\n field.change.markChanged();\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged();\n changed = true;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged();\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged();\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 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 fields.delete(fieldName);\n\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged();\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 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 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 changed = true;\n }\n\n // syncing kv\n let kvChanged = false;\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 kvChanged = true;\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n kvChanged = true;\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)) map.delete(key);\n });\n\n kvChanged = true;\n }\n\n if (kvChanged) notEmpty(resource.kvChanged).markChanged();\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 (isNotNullResourceId(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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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();\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 let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: ResourceId[] = [];\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 && res.id !== this.root) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged();\n });\n if (isNotNullResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged();\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\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 /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = 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.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","import type {\n FieldData,\n OptionalResourceId,\n PlTransaction,\n ResourceId,\n} from '@milaboratories/pl-client';\nimport {\n isNullResourceId,\n} from '@milaboratories/pl-client';\nimport Denque from 'denque';\nimport type { ExtendedResourceData, PlTreeState } from './state';\nimport { msToHumanReadable } from '@milaboratories/ts-helpers';\n\n/** Applied to list of fields in resource data. */\nexport type PruningFunction = (resource: ExtendedResourceData) => FieldData[];\n\nexport interface TreeLoadingRequest {\n /** Resource to prime the traversal algorithm. It is ok, if some of them\n * doesn't exist anymore. Should not contain elements from final resource\n * set. */\n readonly seedResources: ResourceId[];\n\n /** Resource ids for which state is already known and not expected to change.\n * Algorithm will not continue traversal over those ids, and states will not\n * be retrieved for them. */\n readonly finalResources: Set<ResourceId>;\n\n /** This function is applied to each resource data field list, before\n * using it continue traversal. This modification also is applied to\n * output data to make result self-consistent in terms that it will contain\n * all referenced resources, this is required to be able to pass it to tree\n * to update the state. */\n readonly pruningFunction?: PruningFunction;\n}\n\n/** Given the current tree state, build the request object to pass to\n * {@link loadTreeState} to load updated state. */\nexport function constructTreeLoadingRequest(\n tree: PlTreeState,\n pruningFunction?: PruningFunction,\n): TreeLoadingRequest {\n const seedResources: ResourceId[] = [];\n const finalResources = new Set<ResourceId>();\n tree.forEachResource((res) => {\n if (res.finalState) finalResources.add(res.id);\n else seedResources.push(res.id);\n });\n\n // if tree is empty, seeding tree reconstruction from the specified root\n if (seedResources.length === 0 && finalResources.size === 0) seedResources.push(tree.root);\n\n return { seedResources, finalResources, pruningFunction };\n}\n\nexport type TreeLoadingStat = {\n requests: number;\n roundTrips: number;\n retrievedResources: number;\n retrievedFields: number;\n retrievedKeyValues: number;\n retrievedResourceDataBytes: number;\n retrievedKeyValueBytes: number;\n prunedFields: number;\n finalResourcesSkipped: number;\n millisSpent: number;\n};\n\nexport function initialTreeLoadingStat(): TreeLoadingStat {\n return {\n requests: 0,\n roundTrips: 0,\n retrievedResources: 0,\n retrievedFields: 0,\n retrievedKeyValues: 0,\n retrievedResourceDataBytes: 0,\n retrievedKeyValueBytes: 0,\n prunedFields: 0,\n finalResourcesSkipped: 0,\n millisSpent: 0,\n };\n}\n\nexport function formatTreeLoadingStat(stat: TreeLoadingStat): string {\n let result = `Requests: ${stat.requests}\\n`;\n result += `Total time: ${msToHumanReadable(stat.millisSpent)}\\n`;\n result += `Round-trips: ${stat.roundTrips}\\n`;\n result += `Resources: ${stat.retrievedResources}\\n`;\n result += `Fields: ${stat.retrievedFields}\\n`;\n result += `KV: ${stat.retrievedKeyValues}\\n`;\n result += `Data Bytes: ${stat.retrievedResourceDataBytes}\\n`;\n result += `KV Bytes: ${stat.retrievedKeyValueBytes}\\n`;\n result += `Pruned fields: ${stat.prunedFields}\\n`;\n result += `Final resources skipped: ${stat.finalResourcesSkipped}`;\n return result;\n}\n\n/** Given the transaction (preferably read-only) and loading request, executes\n * the tree traversal algorithm, and collects fresh states of resources\n * to update the tree state. */\nexport async function loadTreeState(\n tx: PlTransaction,\n loadingRequest: TreeLoadingRequest,\n stats?: TreeLoadingStat,\n): Promise<ExtendedResourceData[]> {\n // saving start timestamp to add time spent in this function to the stats at the end of the method\n const startTimestamp = Date.now();\n\n // counting the request\n if (stats) stats.requests++;\n\n const { seedResources, finalResources, pruningFunction } = loadingRequest;\n\n // Main idea of using a queue here is that responses will arrive in the same order as they were\n // sent, so we can only wait for the earliest sent unprocessed response promise at any given moment.\n // In such a way logic become linear without recursion, and at the same time deal with data\n // as soon as it arrives.\n\n const pending = new Denque<Promise<ExtendedResourceData | undefined>>();\n\n // vars to calculate number of roundtrips for stats\n let roundTripToggle: boolean = true;\n let numberOfRoundTrips = 0;\n\n // tracking resources we already requested\n const requested = new Set<ResourceId>();\n const requestState = (rid: OptionalResourceId) => {\n if (isNullResourceId(rid) || requested.has(rid)) return;\n\n // separate check to collect stats\n if (finalResources.has(rid)) {\n if (stats) stats.finalResourcesSkipped++;\n return;\n }\n\n // adding the id, so we will not request it's state again if somebody else\n // references the same resource\n requested.add(rid);\n\n // requesting resource and all kv records\n const resourceData = tx.getResourceDataIfExists(rid, true);\n const kvData = tx.listKeyValuesIfResourceExists(rid);\n\n // counting round-trip (begin)\n const addRT = roundTripToggle;\n if (roundTripToggle) roundTripToggle = false;\n\n // pushing combined promise\n pending.push(\n (async () => {\n const [resource, kv] = await Promise.all([resourceData, kvData]);\n\n // counting round-trip, actually incrementing counter and returning toggle back, so the next request can acquire it\n if (addRT) {\n numberOfRoundTrips++;\n roundTripToggle = true;\n }\n\n if (resource === undefined) return undefined;\n\n if (kv === undefined) throw new Error('Inconsistent replies');\n\n return { ...resource, kv };\n })(),\n );\n };\n\n // sending seed requests\n seedResources.forEach((rid) => requestState(rid));\n\n const result: ExtendedResourceData[] = [];\n while (true) {\n // taking next pending request\n const nextResourcePromise = pending.shift();\n if (nextResourcePromise === undefined)\n // this means we have no pending requests and traversal is over\n break;\n\n // at this point we pause and wait for the nest requested resource state to arrive\n let nextResource = await nextResourcePromise;\n if (nextResource === undefined)\n // ignoring resources that were not found (this may happen for seed resource ids)\n continue;\n\n if (pruningFunction !== undefined) {\n // apply field pruning, if requested\n const fieldsAfterPruning = pruningFunction(nextResource);\n // collecting stats\n if (stats) stats.prunedFields += nextResource.fields.length - fieldsAfterPruning.length;\n nextResource = { ...nextResource, fields: fieldsAfterPruning };\n }\n\n // continue traversal over the referenced resource\n requestState(nextResource.error);\n for (const field of nextResource.fields) {\n requestState(field.value);\n requestState(field.error);\n }\n\n // collecting stats\n if (stats) {\n stats.retrievedResources++;\n stats.retrievedFields += nextResource.fields.length;\n stats.retrievedKeyValues += nextResource.kv.length;\n stats.retrievedResourceDataBytes += nextResource.data?.length ?? 0;\n for (const kv of nextResource.kv) stats.retrievedKeyValueBytes += kv.value.length;\n }\n\n // aggregating the state\n result.push(nextResource);\n }\n\n // adding the time we spent in this method to stats\n if (stats) {\n stats.millisSpent += Date.now() - startTimestamp;\n stats.roundTrips += numberOfRoundTrips;\n }\n\n return result;\n}\n","import type { ResourceId, ResourceType } from '@milaboratories/pl-client';\nimport type { Optional, Writable } from 'utility-types';\nimport type { ZodType, z } from 'zod';\nimport type { PlTreeNodeAccessor } from './accessors';\nimport { PlTreeEntry, PlTreeEntryAccessor } from './accessors';\nimport type { ComputableCtx } from '@milaboratories/computable';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n\n/**\n * A DTO that can be generated from a tree node to make a snapshot of specific parts of it's state.\n * Such snapshots can then be used in core that requires this information without the need of\n * retrieving state from the tree.\n */\nexport type ResourceSnapshot<\n Data = undefined,\n Fields extends Record<string, ResourceId | undefined> | undefined = undefined,\n KV extends Record<string, unknown> | undefined = undefined,\n> = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** The most generic type of ResourceSnapshot. */\ntype ResourceSnapshotGeneric = ResourceSnapshot<\n unknown,\n Record<string, ResourceId | undefined> | undefined,\n Record<string, unknown> | undefined\n>;\n\n/** Request that we'll pass to getResourceSnapshot function. We infer the type of ResourceSnapshot from this. */\nexport type ResourceSnapshotSchema<\n Data extends ZodType | 'raw' | undefined = undefined,\n Fields extends Record<string, boolean> | undefined = undefined,\n KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n> = {\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** Creates ResourceSnapshotSchema. It converts an optional schema type to schema type. */\nexport function rsSchema<\n const Data extends ZodType | 'raw' | undefined = undefined,\n const Fields extends Record<string, boolean> | undefined = undefined,\n const KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n>(\n schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>,\n): ResourceSnapshotSchema<Data, Fields, KV> {\n return schema as any;\n}\n\n/** The most generic type of ResourceSnapshotSchema. */\ntype ResourceSnapshotSchemaGeneric = ResourceSnapshotSchema<\n ZodType | 'raw' | undefined,\n Record<string, boolean> | undefined,\n Record<string, ZodType | 'raw'> | undefined\n>;\n\n/**\n * If Data is 'raw' in schema, we'll get bytes,\n * if it's Zod, we'll parse it via zod.\n * Or else we just got undefined in the field.\n */\ntype InferDataType<Data extends ZodType | 'raw' | undefined> = Data extends 'raw'\n ? Uint8Array\n : Data extends ZodType\n ? z.infer<Data>\n : undefined;\n\n/**\n * If Fields is a record of field names to booleans,\n * then if the value of the field is true, we'll require this field and throw a Error if it wasn't found.\n * If it's false and doesn't exist, we'll return undefined.\n * If Fields type is undefined, we won't set fields at all.\n */\ntype InferFieldsType<Fields extends Record<string, boolean> | undefined> = Fields extends undefined\n ? undefined\n : {\n [FieldName in keyof Fields]: Fields[FieldName] extends true\n ? ResourceId\n : ResourceId | undefined;\n };\n\n/**\n * If KV is undefined, won't set it.\n * If one of values is Zod, we'll get KV and converts it to Zod schema.\n * If the value is 'raw', just returns bytes.\n */\ntype InferKVType<KV extends Record<string, ZodType | 'raw'> | undefined> = KV extends undefined\n ? undefined\n : {\n [FieldName in keyof KV]: KV[FieldName] extends ZodType ? z.infer<KV[FieldName]> : Uint8Array;\n };\n\n/** Infer ResourceSnapshot from ResourceShapshotSchema, S can be any ResourceSnapshotSchema. */\nexport type InferSnapshot<S extends ResourceSnapshotSchemaGeneric> = ResourceSnapshot<\n InferDataType<S['data']>,\n InferFieldsType<S['fields']>,\n InferKVType<S['kv']>\n>;\n\n/** Gets a ResourceSnapshot from PlTreeEntry. */\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry,\n schema: Schema,\n ctx: ComputableCtx\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry | PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema,\n ctx?: ComputableCtx,\n): InferSnapshot<Schema> {\n const node\n = res instanceof PlTreeEntry\n ? notEmpty(ctx).accessor(res).node()\n : res instanceof PlTreeEntryAccessor\n ? res.node()\n : res;\n const info = node.resourceInfo;\n const result: Optional<Writable<ResourceSnapshotGeneric>, 'data' | 'fields' | 'kv'> = { ...info };\n\n if (schema.data !== undefined) {\n if (schema.data === 'raw') result.data = node.getData();\n else result.data = schema.data.parse(node.getDataAsJson());\n }\n\n if (schema.fields !== undefined) {\n const fields: Record<string, ResourceId | undefined> = {};\n // even if field is not defined, corresponding object field\n // with \"undefined\" value will still be added\n for (const [fieldName, required] of Object.entries(schema.fields))\n fields[fieldName] = node.traverse({\n field: fieldName,\n errorIfFieldNotSet: required,\n stableIfNotFound: !required,\n })?.id;\n result.fields = fields;\n }\n\n if (schema.kv !== undefined) {\n const kv: Record<string, unknown> = {};\n for (const [fieldName, type] of Object.entries(schema.kv)) {\n const value = node.getKeyValue(fieldName);\n\n if (value === undefined) {\n throw new Error(`Key not found ${fieldName}`);\n } else if (type === 'raw') {\n kv[fieldName] = value;\n } else {\n kv[fieldName] = type.parse(JSON.parse(Buffer.from(value).toString('utf-8')));\n }\n }\n result.kv = kv;\n }\n\n return result as any;\n}\n\n/** @deprecated */\nexport type ResourceWithData = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly fields: Map<string, ResourceId | undefined>;\n readonly data?: Uint8Array;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithData(\n res: PlTreeEntry | ResourceWithData,\n fields: string[],\n ctx: ComputableCtx,\n): ResourceWithData {\n if (res instanceof PlTreeEntry) {\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n\n const fValues: [string, ResourceId | undefined][] = fields.map((name) => [\n name,\n node.getField(name)?.value?.id,\n ]);\n\n return {\n ...info,\n fields: new Map(fValues),\n data: node.getData() ?? new Uint8Array(),\n };\n }\n\n return res;\n}\n\n/** @deprecated */\nexport type ResourceWithMetadata = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly metadata: Record<string, any>;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithMetadata(\n res: PlTreeEntry | ResourceWithMetadata,\n mdKeys: string[],\n ctx: ComputableCtx,\n): ResourceWithMetadata {\n if (!(res instanceof PlTreeEntry)) return res;\n\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n const mdEntries: [string, any][] = mdKeys.map((k) => [k, node.getKeyValue(k)]);\n\n return {\n ...info,\n metadata: Object.fromEntries(mdEntries),\n };\n}\n","import { PollingComputableHooks } from '@milaboratories/computable';\nimport { PlTreeEntry } from './accessors';\nimport type {\n FinalResourceDataPredicate,\n PlClient,\n ResourceId,\n TxOps,\n} from '@milaboratories/pl-client';\nimport {\n isTimeoutOrCancelError,\n} from '@milaboratories/pl-client';\nimport type { ExtendedResourceData } from './state';\nimport { PlTreeState, TreeStateUpdateError } from './state';\nimport type {\n PruningFunction,\n TreeLoadingStat,\n} from './sync';\nimport {\n constructTreeLoadingRequest,\n initialTreeLoadingStat,\n loadTreeState,\n} from './sync';\nimport * as tp from 'node:timers/promises';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\n\ntype StatLoggingMode = 'cumulative' | 'per-request';\n\nexport type SynchronizedTreeOps = {\n /** Override final predicate from the PlClient */\n finalPredicateOverride?: FinalResourceDataPredicate;\n\n /** Pruning function to limit set of fields through which tree will\n * traverse during state synchronization */\n pruning?: PruningFunction;\n\n /** Interval after last sync to sleep before the next one */\n pollingInterval: number;\n /** For how long to continue polling after the last derived value access */\n stopPollingDelay: number;\n\n /** If one of the values, tree will log stats of each polling request */\n logStat?: StatLoggingMode;\n\n /** Timeout for initial tree loading. If not specified, will use default for RO tx from pl-client. */\n initialTreeLoadingTimeout?: number;\n};\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nexport class SynchronizedTreeState {\n private readonly finalPredicate: FinalResourceDataPredicate;\n private state: PlTreeState;\n private readonly pollingInterval: number;\n private readonly pruning?: PruningFunction;\n private readonly logStat?: StatLoggingMode;\n private readonly hooks: PollingComputableHooks;\n private readonly abortController = new AbortController();\n\n private constructor(\n private readonly pl: PlClient,\n private readonly root: ResourceId,\n ops: SynchronizedTreeOps,\n private readonly logger?: MiLogger,\n ) {\n const { finalPredicateOverride, pruning, pollingInterval, stopPollingDelay, logStat } = ops;\n this.pruning = pruning;\n this.pollingInterval = pollingInterval;\n this.finalPredicate = finalPredicateOverride ?? pl.finalPredicate;\n this.logStat = logStat;\n this.state = new PlTreeState(root, this.finalPredicate);\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return new PlTreeEntry({ treeProvider: () => this.state, hooks: this.hooks }, rid);\n }\n\n /** Can be used to externally kick off the synchronization polling loop, and\n * await for the first synchronization to happen. */\n public async refreshState(): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n await this.hooks.refreshState();\n }\n\n private currentLoopDelayInterrupt: AbortController | undefined = undefined;\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n /** Called from computable hooks when external observer asks for state refresh */\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n if (this.terminated) reject(new Error('tree synchronization is terminated'));\n else {\n this.scheduledOnNextState.push({ resolve, reject });\n if (this.currentLoopDelayInterrupt) {\n this.currentLoopDelayInterrupt.abort();\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n /** Called from observer */\n private startUpdating(): void {\n if (this.terminated) return;\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n /** Executed from the main loop, and initialization procedure. */\n private async refresh(stats?: TreeLoadingStat, txOps?: TxOps): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n const request = constructTreeLoadingRequest(this.state, this.pruning);\n const data = await this.pl.withReadTx('ReadingTree', async (tx) => {\n return await loadTreeState(tx, request, stats);\n }, txOps);\n this.state.updateFromResourceData(data, true);\n }\n\n /** If true this tree state is permanently terminaed. */\n private terminated = false;\n\n private async mainLoop() {\n // will hold request stats\n let stat = this.logStat ? initialTreeLoadingStat() : undefined;\n\n let lastUpdate = Date.now();\n\n while (true) {\n if (!this.keepRunning || this.terminated) break;\n\n // saving those who want to be notified about new state here\n // because those who will be added during the tree retrieval\n // should be notified only on the next round\n let toNotify: ScheduledRefresh[] | undefined = undefined;\n if (this.scheduledOnNextState.length > 0) {\n toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n }\n\n try {\n // resetting stats if we were asked to collect non-cumulative stats\n if (this.logStat === 'per-request') stat = initialTreeLoadingStat();\n\n // actual tree synchronization\n await this.refresh(stat);\n\n // logging stats if we were asked to\n if (stat && this.logger) this.logger.info(`Tree stat (success, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we got new state\n if (toNotify !== undefined) for (const n of toNotify) n.resolve();\n } catch (e: any) {\n // logging stats if we were asked to (even if error occured)\n if (stat && this.logger) this.logger.info(`Tree stat (error, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we failed to refresh the state\n if (toNotify !== undefined) for (const n of toNotify) n.reject(e);\n\n // catching tree update errors, as they may leave our tree in inconsistent state\n if (e instanceof TreeStateUpdateError) {\n // important error logging, this should never happen\n this.logger?.error(e);\n\n // marking everybody who used previous state as changed\n this.state.invalidateTree('stat update error');\n // creating new tree\n this.state = new PlTreeState(this.root, this.finalPredicate);\n\n // scheduling state update without delay\n continue;\n\n // unfortunately external observer may still see tree in its default\n // empty state, though this is best we can do in this exceptional\n // situation, and hope on caching layers inside computables to present\n // some stale state until we reconstruct the tree again\n } else this.logger?.warn(e);\n }\n\n if (!this.keepRunning || this.terminated) break;\n\n if (this.scheduledOnNextState.length === 0) {\n try {\n this.currentLoopDelayInterrupt = new AbortController();\n await tp.setTimeout(this.pollingInterval,\n AbortSignal.any([this.abortController.signal, this.currentLoopDelayInterrupt.signal]));\n } catch (e: unknown) {\n if (!isTimeoutOrCancelError(e)) throw new Error('Unexpected error', { cause: e });\n break;\n } finally {\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n // reset only as a very last line\n this.currentLoop = undefined;\n }\n\n /**\n * Dumps the current state of the tree.\n * @returns An array of ExtendedResourceData objects representing the current state of the tree.\n */\n public dumpState(): ExtendedResourceData[] {\n return this.state.dumpState();\n }\n\n /**\n * Terminates the internal loop, and permanently destoys all internal state, so\n * all computables using this state will resolve to errors.\n * */\n public async terminate(): Promise<void> {\n this.keepRunning = false;\n this.terminated = true;\n this.abortController.abort();\n\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n\n this.state.invalidateTree('synchronization terminated for the tree');\n }\n\n /** @deprecated */\n public async awaitSyncLoopTermination(): Promise<void> {\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n }\n\n public static async init(\n pl: PlClient,\n root: ResourceId,\n ops: SynchronizedTreeOps,\n logger?: MiLogger,\n ) {\n const tree = new SynchronizedTreeState(pl, root, ops, logger);\n\n const stat = ops.logStat ? initialTreeLoadingStat() : undefined;\n\n let ok = false;\n\n try {\n await tree.refresh(stat, {\n timeout: ops.initialTreeLoadingTimeout,\n });\n ok = true;\n } finally {\n // logging stats if we were asked to (even if error occured)\n if (stat && logger)\n logger.info(\n `Tree stat (initial load, ${ok ? 'success' : 'failure'}): ${JSON.stringify(stat)}`,\n );\n }\n\n return tree;\n }\n}\n","import type { ExtendedResourceData } from './state';\n\nexport type ResourceStats = {\n /** Number of resources of this type */\n count: number;\n /** Total number of bytes in the field names of all resources of this type */\n fieldNameBytes: number;\n /** Total number of fields in all resources of this type */\n fieldsCount: number;\n /** Total number of bytes in the data of all resources of this type */\n dataBytes: number;\n /** Total number of key-value records in all resources of this type */\n kvCount: number;\n /** Total number of bytes in the key-value records of all resources of this type */\n kvBytes: number;\n};\n\n/**\n * A map of resource type statistics, keyed by the resource type name and version.\n *\n * @type {Record<string, ResourceStats>}\n */\nexport type TreeDumpStats = {\n total: ResourceStats;\n byResourceType: Record<`${string}/${string}`, ResourceStats>;\n};\n\n/**\n * Analyzes a collection of resources and generates statistics grouped by resource type.\n *\n * This function processes an array of ExtendedResourceData and calculates various metrics\n * for each unique resource type, including:\n * - Count of resources\n * - Total bytes in field names\n * - Total number of fields\n * - Total bytes in resource data\n * - Total number of key-value records\n * - Total bytes in key-value records\n *\n * The statistics are organized by resource type using a key in the format \"typeName/version\".\n *\n * @param dumpStats - Array of ExtendedResourceData objects to analyze\n * @returns A DumpStats object containing statistics for each resource type\n * @example\n * ```typescript\n * const resources = [...]; // Array of ExtendedResourceData\n * const stats = treeDumpStats(resources);\n * // stats = {\n * // \"MyResource/1\": {\n * // count: 5,\n * // fieldNameBytes: 150,\n * // fieldsCount: 10,\n * // dataBytes: 1024,\n * // kvCount: 3,\n * // kvBytes: 256\n * // },\n * // ...\n * // }\n * ```\n */\nexport function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {\n const stats: TreeDumpStats = {\n total: {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n },\n byResourceType: {},\n };\n\n for (const resource of dumpStats) {\n const typeKey = `${resource.type.name}/${resource.type.version}` as const;\n if (!stats.byResourceType[typeKey]) {\n stats.byResourceType[typeKey] = {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n };\n }\n\n const typeStats = stats.byResourceType[typeKey];\n typeStats.count++;\n stats.total.count++;\n\n for (const field of resource.fields) {\n typeStats.fieldNameBytes += field.name.length;\n typeStats.fieldsCount++;\n stats.total.fieldNameBytes += field.name.length;\n stats.total.fieldsCount++;\n }\n\n if (resource.data) {\n const dataLength = resource.data?.length ?? 0;\n typeStats.dataBytes += dataLength;\n stats.total.dataBytes += dataLength;\n }\n\n typeStats.kvCount += resource.kv.length;\n stats.total.kvCount += resource.kv.length;\n\n for (const kv of resource.kv) {\n const kvLength = kv.key.length + kv.value.length;\n typeStats.kvBytes += kvLength;\n stats.total.kvBytes += kvLength;\n }\n }\n\n return stats;\n}\n"],"names":["mapValueAndErrorIfDefined","input","mapping","mapValueAndError","ret","PlError","message","isPlTreeEntry","obj","isPlTreeEntryAccessor","isPlTreeNodeAccessor","PlTreeEntry","accessorData","rid","__publicField","ctx","guard","PlTreeEntryAccessor","resourceIdToString","getResourceFromTree","tree","instanceData","ops","acc","PlTreeNodeAccessor","err","parsePlError","notEmpty","rt","resourceTypesEqual","resourceTypeToString","treeEntryToResourceInfo","res","resource","marker","steps","commonOptions","result","current","_step","step","next","ve","key","unstableIfNotFound","TreeStateUpdateError","PlTreeField","name","type","value","error","status","valueIsFinal","resourceVersion","ChangeSource","InitialResourceVersion","PlTreeResource","initialState","logger","msg","watcher","onUnstable","field","_a","_b","_c","isNotNullResourceId","NullResourceId","isNullResourceId","bytes","cachedDecode","cachedDeserialize","stringifyWithResourceId","_d","_e","_f","_g","PlTreeState","root","isFinalPredicate","cb","v","resourceData","allowOrphanInputs","incrementRefs","decrementRefs","rd","statBeforeMutation","unexpectedTransitionError","reason","fields","rdWithoutFields","changed","fd","fieldName","readyStateBefore","kvChanged","kv","newStateKeys","_value","map","currentRefs","nextRefs","constructTreeLoadingRequest","pruningFunction","seedResources","finalResources","initialTreeLoadingStat","formatTreeLoadingStat","stat","msToHumanReadable","loadTreeState","tx","loadingRequest","stats","startTimestamp","pending","Denque","roundTripToggle","numberOfRoundTrips","requested","requestState","kvData","addRT","nextResourcePromise","nextResource","fieldsAfterPruning","rsSchema","schema","makeResourceSnapshot","node","required","treeEntryToResourceWithData","info","fValues","treeEntryToResourceWithMetadata","mdKeys","mdEntries","k","SynchronizedTreeState","pl","finalPredicateOverride","pruning","pollingInterval","stopPollingDelay","logStat","PollingComputableHooks","resolve","reject","txOps","request","data","lastUpdate","toNotify","n","e","tp","isTimeoutOrCancelError","ok","treeDumpStats","dumpStats","typeKey","typeStats","dataLength","kvLength"],"mappings":"wuBAKgB,SAAAA,EACdC,EACAC,EAC+B,CAC3B,GAAAD,IAAU,OACT,OAAOE,EAAiBF,EAAOC,CAAO,CAC7C,CAEgB,SAAAC,EAAyBF,EAA0BC,EAAwB,CACzF,MAAME,EAAM,CAAC,EACb,OAAIH,EAAM,QAAU,WAAe,MAAQC,EAAQD,EAAM,KAAK,GAC1DA,EAAM,QAAU,WAAe,MAAQC,EAAQD,EAAM,KAAK,GACvDG,CACT,CCYO,MAAMC,UAAgB,KAAM,CACjC,YAAYC,EAAiB,CAC3B,MAAMA,CAAO,CAAA,CAEjB,CAYO,SAASC,EAAcC,EAAkC,CAC9D,OACE,OAAOA,GAAQ,UACZA,IAAQ,MACPA,EAAY,0BAA+B,aAEnD,CAEO,SAASC,EAAsBD,EAA0C,CAC9E,OACE,OAAOA,GAAQ,UACZA,IAAQ,MACPA,EAAY,0BAA+B,qBAEnD,CAEO,SAASE,EAAqBF,EAAyC,CAC5E,OACE,OAAOA,GAAQ,UACZA,IAAQ,MACPA,EAAY,0BAA+B,oBAEnD,CAGO,MAAMG,CAA6D,CAGxE,YACmBC,EACDC,EAChB,CALeC,EAAA,+BAA0B,eAGxB,KAAA,aAAAF,EACD,KAAA,IAAAC,CAAA,CAGX,eAAeE,EAAoBC,EAAwC,CACzE,OAAA,IAAIC,EAAoB,KAAK,aAAc,KAAK,aAAa,aAAA,EAAgB,KAAK,IAAK,CAC5F,IAAAF,EACA,MAAAC,CAAA,CACD,CAAA,CAGI,QAAiB,CACtB,OAAO,KAAK,SAAS,CAAA,CAGhB,UAAmB,CACxB,MAAO,UAAUE,EAAA,mBAAmB,KAAK,GAAG,CAAC,GAAA,CAEjD,CAEA,SAASC,EACPP,EACAQ,EACAC,EACAR,EACAS,EACoB,CACpB,MAAMC,EAAM,IAAIC,EACdZ,EACAQ,EACAA,EAAK,IAAIC,EAAa,IAAI,QAASR,CAAG,EACtCQ,CACF,EAEI,GAAA,CAACC,EAAI,YAAa,CACd,MAAAG,EAAMF,EAAI,SAAS,EACzB,GAAIE,IAAQ,OACJ,MAAAC,EAAA,aAAaC,WAASF,EAAI,gBAAA,CAAiB,EAAGF,EAAI,GAAIA,EAAI,YAAY,CAAA,CAI9E,GAAAD,EAAI,qBAAuB,SACvB,MAAM,QAAQA,EAAI,kBAAkB,EACpCA,EAAI,mBAAmB,UAAWM,GAAOC,EAAmB,mBAAAD,EAAIL,EAAI,YAAY,CAAC,IAAM,GACvF,CAACM,EAAmB,mBAAAP,EAAI,mBAAoBC,EAAI,YAAY,GAEhE,MAAM,IAAI,MAER,uBAAuBO,EAAAA,qBAAqBP,EAAI,YAAY,CAAC,iBAAiBD,EAAI,kBAAkB,EACtG,EAEK,OAAAC,CACT,CAEO,MAAMN,CAAoB,CAG/B,YACmBL,EACAQ,EACAP,EACAQ,EACjB,CAPeP,EAAA,+BAA0B,uBAGxB,KAAA,aAAAF,EACA,KAAA,KAAAQ,EACA,KAAA,IAAAP,EACA,KAAA,aAAAQ,CAAA,CAGnB,KAAKC,EAA4B,GAAwB,CACvD,YAAK,aAAa,MAAM,EAIpB,KAAK,aAAa,QAAU,QAC9B,KAAK,aAAa,IAAI,aAAa,KAAK,aAAa,KAAK,EAErDH,EAAoB,KAAK,aAAc,KAAK,KAAM,KAAK,aAAc,KAAK,IAAKG,CAAG,CAAA,CAE7F,CAcgB,SAAAS,EAAwBC,EAAiCjB,EAAoB,CACvF,OAAAiB,aAAerB,EAAoBI,EAAI,SAASiB,CAAG,EAAE,OAAO,aAEzDA,CACT,CAQO,MAAMR,CAAmB,CAG9B,YACmBZ,EACAQ,EACAa,EACAZ,EACjB,CAPeP,EAAA,+BAA0B,sBAyH1BA,EAAA,wBAAoBoB,GAAmB,CACjD,KAAA,aAAa,IAAI,aAAaA,CAAM,CAC3C,GAxHmB,KAAA,aAAAtB,EACA,KAAA,KAAAQ,EACA,KAAA,SAAAa,EACA,KAAA,aAAAZ,CAAA,CAGnB,IAAW,IAAiB,CAC1B,YAAK,aAAa,MAAM,EACjB,KAAK,SAAS,EAAA,CAGvB,IAAW,YAAiC,CAC1C,YAAK,aAAa,MAAM,EACjB,KAAK,SAAS,kBAAA,CAGvB,IAAW,cAA6B,CACtC,YAAK,aAAa,MAAM,EACjB,KAAK,SAAS,IAAA,CAGvB,IAAW,cAA6B,CACtC,MAAO,CAAE,GAAI,KAAK,GAAI,KAAM,KAAK,YAAa,CAAA,CAGxC,oBAAoBR,EAAiBS,EAA+C,CACnF,OAAAH,EAAoB,KAAK,aAAc,KAAK,KAAM,KAAK,aAAcN,EAAKS,CAAG,CAAA,CAW/E,YAAYa,EAAwE,CACzF,OAAO,KAAK,mBAAmB,CAAC,EAAG,GAAGA,CAAK,CAAA,CAatC,mBACFA,EACkD,CACrD,OAAO,KAAK,0BAA0B,CAAC,EAAG,GAAGA,CAAK,CAAA,CAG7C,mBACLC,KACGD,EAC6B,CAChC,MAAME,EAAS,KAAK,0BAA0BD,EAAe,GAAGD,CAAK,EACjE,GAAAE,IAAW,OAEf,IAAI,CAACA,EAAO,GAAI,MAAMA,EAAO,MAC7B,OAAOA,EAAO,MAAA,CAGT,0BACLD,KACGD,EACkD,CAErD,IAAIG,EAA8B,KAElC,UAAWC,KAASJ,EAAO,CACnB,MAAAK,EACF,OAAOD,GAAU,SACf,CACE,GAAGH,EACH,MAAOG,CAAA,EAET,CAAE,GAAGH,EAAe,GAAGG,CAAM,EAE7BE,EAAOH,EAAQ,SAASC,CAAK,EAInC,GAFIE,IAAS,QAETD,EAAK,2BAA6BC,EAAK,QAAU,QAAaA,EAAK,QAAU,OACxE,OAET,IAAK,CAACD,EAAK,aAAeC,EAAK,QAAU,SAAcA,EAAK,QAAU,OAC7D,MAAA,CACL,GAAI,GAGJ,MAAOf,EAAA,aACLC,EAAAA,SAASc,EAAK,MAAM,iBAAiB,EACrCH,EAAQ,GAAIA,EAAQ,aAAcE,EAAK,KAAA,CAE3C,EAEE,GAAAC,EAAK,QAAU,OAAW,CAC5B,GAAID,EAAK,mBACA,MAAA,CACL,GAAI,GACJ,MAAO,IAAI,MAAM,gCAAgCA,EAAK,KAAK,OAAOtB,EAAmB,mBAAAoB,EAAQ,EAAE,CAAC,EAAE,CACpG,EAEG,KAAA,iBAAiB,qBAAuBE,EAAK,KAAK,EAChD,MAAA,CAGTF,EAAUG,EAAK,KAAA,CAEjB,MAAO,CAAE,GAAI,GAAM,MAAOH,CAAQ,CAAA,CAa7B,SAASC,EAA6E,CAC3F,KAAK,aAAa,MAAM,EACxB,MAAMC,EAAqB,OAAOD,GAAU,SAAW,CAAE,MAAOA,GAAUA,EAEpEG,EAAK,KAAK,SAAS,SAAS,KAAK,aAAa,IAAI,QAASF,EAAM,KAAK,gBAAgB,EAExF,GAAAE,IAAO,OAEJ,OAAAvC,EAAiBuC,EAAK7B,GAAQ,KAAK,oBAAoBA,EAAK,CAAE,YAAa,EAAK,CAAC,CAAC,CAAA,CAGpF,iBAA2B,CAChC,KAAK,aAAa,MAAM,EACxB,MAAMwB,EAAS,KAAK,SAAS,gBAAgB,KAAK,aAAa,IAAI,OAAO,EACtE,OAACA,GAAa,KAAA,aAAa,IAAI,aAAa,mBAAqB,KAAK,aAAa,IAAI,EACpFA,CAAA,CAGF,kBAA4B,CACjC,KAAK,aAAa,MAAM,EACxB,MAAMA,EAAS,KAAK,SAAS,iBAAiB,KAAK,aAAa,IAAI,OAAO,EACvE,OAACA,GAAa,KAAA,aAAa,IAAI,aAAa,oBAAsB,KAAK,aAAa,IAAI,EACrFA,CAAA,CAGF,mBAA6B,CAClC,KAAK,aAAa,MAAM,EACxB,MAAMA,EAAS,KAAK,SAAS,kBAAkB,KAAK,aAAa,IAAI,OAAO,EACxE,OAACA,GAAa,KAAA,aAAa,IAAI,aAAa,aAAe,KAAK,aAAa,IAAI,EAC9EA,CAAA,CAGF,YAAa,CAClB,YAAK,aAAa,MAAM,EACjB,KAAK,SAAS,WAAW,KAAK,aAAa,IAAI,OAAO,CAAA,CAGxD,UAA2C,CAChD,KAAK,aAAa,MAAM,EACxB,MAAMxB,EAAM,KAAK,SAAS,SAAS,KAAK,aAAa,IAAI,OAAO,EAChE,GAAIA,IAAQ,OAGZ,OAAO,KAAK,oBAAoBA,EAAK,EAAE,CAAA,CAGlC,SAAkC,CACvC,OAAO,KAAK,SAAS,IAAA,CAGhB,iBAAsC,CACpC,OAAA,KAAK,SAAS,gBAAgB,CAAA,CAGhC,eAA4C,CAC1C,OAAA,KAAK,SAAS,cAAiB,CAAA,CAGjC,iBAA4B,CACjC,YAAK,aAAa,MAAM,EACxB,KAAK,gBAAgB,EACd,KAAK,SAAS,gBAAgB,KAAK,aAAa,IAAI,OAAO,CAAA,CAG7D,kBAA6B,CAClC,YAAK,aAAa,MAAM,EACxB,KAAK,iBAAiB,EACf,KAAK,SAAS,iBAAiB,KAAK,aAAa,IAAI,OAAO,CAAA,CAG9D,mBAA8B,CACnC,YAAK,aAAa,MAAM,EACjB,KAAK,SAAS,kBAAkB,KAAK,aAAa,IAAI,OAAO,CAAA,CAG/D,YAAY8B,EAAaC,EAA8B,GAA+B,CAC3F,KAAK,aAAa,MAAM,EAClB,MAAAP,EAAS,KAAK,SAAS,YAAY,KAAK,aAAa,IAAI,QAASM,CAAG,EAC3E,OAAIN,IAAW,QAAaO,GAC1B,KAAK,aAAa,IAAI,aAAa,mBAAqBD,CAAG,EACtDN,CAAA,CAIF,kBAAkBM,EAAiC,CACjD,OAAA,KAAK,oBAAoBA,CAAG,CAAA,CAG9B,oBAAoBA,EAAaC,EAA8B,GAA2B,CAC/F,KAAK,aAAa,MAAM,EAClB,MAAAP,EAAS,KAAK,SAAS,kBAAkB,KAAK,aAAa,IAAI,QAASM,CAAG,EACjF,OAAIN,IAAW,QAAaO,GAC1B,KAAK,aAAa,IAAI,aAAa,mBAAqBD,CAAG,EACtDN,CAAA,CAGF,kBACLM,EACAC,EAA8B,GACf,CACT,MAAAP,EAAS,KAAK,SAAS,kBAAqB,KAAK,aAAa,IAAI,QAASM,CAAG,EACpF,GAAIN,IAAW,OAAW,CACpBO,GAAyB,KAAA,aAAa,IAAI,aAAa,mBAAqBD,CAAG,EAC5E,MAAA,CAEF,OAAAN,CAAA,CAOF,iBAAuC,CACrC,OAAA,IAAIpB,EAAoB,KAAK,aAAc,KAAK,KAAM,KAAK,GAAI,KAAK,YAAY,CAAA,CAIlF,SAAuB,CAC5B,OAAO,IAAIN,EAAY,KAAK,aAAc,KAAK,SAAS,EAAE,CAAA,CAE9D,CC5YO,MAAMkC,UAA6B,KAAM,CAC9C,YAAYvC,EAAiB,CAC3B,MAAMA,CAAO,CAAA,CAEjB,CAEA,MAAMwC,CAAiC,CAGrC,YACkBC,EACTC,EACAC,EACAC,EACAC,EACAC,EAEAC,EACP,CAXOvC,EAAA,cAAS,IAAIwC,EAAAA,cAGJ,KAAA,KAAAP,EACT,KAAA,KAAAC,EACA,KAAA,MAAAC,EACA,KAAA,MAAAC,EACA,KAAA,OAAAC,EACA,KAAA,aAAAC,EAEA,KAAA,gBAAAC,CAAA,CAGT,IAAI,OAAmB,CACd,MAAA,CACL,KAAM,KAAK,KACX,KAAM,KAAK,KACX,OAAQ,KAAK,OACb,MAAO,KAAK,MACZ,MAAO,KAAK,MACZ,aAAc,KAAK,YACrB,CAAA,CAEJ,CAEA,MAAME,EAAyB,EAOxB,MAAMC,CAAqD,CAkDhE,YAAYC,EAAiCC,EAAmB,CAhDhE5C,EAAA,gBAAmB,GAGnBA,EAAA,eAAkByC,GAElBzC,EAAA,mBAAsByC,GAEbzC,EAAA,qBAA0C,KAE1CA,EAAA,cAAS,KAETA,EAAA,uBAAkB,IAAIwC,EAAAA,cAI/BxC,EAAA,oBAAgB,IAAIwC,EAAAA,cAEpBxC,EAAA,2BAAuB,IAAIwC,EAAAA,cAE3BxC,EAAA,oBAAgB,IAAIwC,EAAAA,cACpBxC,EAAA,uCAAmC,IAAIwC,EAAAA,cACvCxC,EAAA,8BAA0B,IAAIwC,EAAAA,cAC9BxC,EAAA,+BAA2B,IAAIwC,EAAAA,cAE/BxC,EAAA,iBAAa,IAAIwC,EAAAA,cAERxC,EAAA,WACTA,EAAA,2BAESA,EAAA,aACAA,EAAA,aAEAA,EAAA,aACDA,EAAA,qBACAA,EAAA,mBAERA,EAAA,cAEAA,EAAA,qBACAA,EAAA,sBACAA,EAAA,sBACAA,EAAA,kBAGAA,EAAA,mBAAuB,IAENA,EAAA,eAGf,KAAK,GAAK2C,EAAa,GACvB,KAAK,mBAAqBA,EAAa,mBACvC,KAAK,KAAOA,EAAa,KACzB,KAAK,KAAOA,EAAa,KACzB,KAAK,KAAOA,EAAa,KACzB,KAAK,MAAQA,EAAa,MAC1B,KAAK,aAAeA,EAAa,aACjC,KAAK,cAAgBA,EAAa,cAClC,KAAK,cAAgBA,EAAa,cAClC,KAAK,UAAYA,EAAa,MAC9B,KAAK,OAASC,CAAA,CAKR,KAAKC,EAAa,CACpB,KAAK,SAAW,QAAgB,KAAA,OAAO,KAAKA,CAAG,CAAA,CAG7C,KAAKA,EAAa,CACpB,KAAK,SAAW,QAAgB,KAAA,OAAO,KAAKA,CAAG,CAAA,CAGrD,IAAI,OAAiB,CACnB,OAAO,KAAK,SAAA,CAGd,IAAI,YAAsB,CACxB,OAAO,KAAK,WAAA,CAGd,IAAI,QAAsB,CACxB,MAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CAAA,CAe7B,SACLC,EACArB,EACAsB,EAAuC,IAAM,CAAA,EACN,WACvC,MAAMrB,EAA2B,OAAOD,GAAU,SAAW,CAAE,MAAOA,GAAUA,EAE1EuB,EAAQ,KAAK,UAAU,IAAItB,EAAK,KAAK,EAC3C,GAAIsB,IAAU,OAAW,CACnB,GAAAtB,EAAK,sBAAwBA,EAAK,mBACpC,MAAM,IAAI,MACR,UAAUA,EAAK,KAAK,2BAA2BtB,qBAAmB,KAAK,EAAE,CAAC,EAC5E,EAEF,GAAI,CAAC,KAAK,cAAmB6C,EAAA,KAAA,kCAAA,MAAAA,EAAiC,cAAcH,WACnEpB,EAAK,kBAAoB,WAAaA,EAAK,kBAAoB,QAAS,CAC/E,GAAIA,EAAK,sBAEA,aACE,IAAI,MAAM,oCAAoCA,EAAK,KAAK,GAAG,CAAA,CAGxE,GAAI,CAAC,KAAK,eAAoBwB,EAAA,KAAA,yBAAA,MAAAA,EAAwB,cAAcJ,WAC3DpB,EAAK,kBAAoB,SAAU,CAC1C,GAAIA,EAAK,sBAEA,aACE,IAAI,MAAM,0BAA0BA,EAAK,KAAK,GAAG,CAAA,EAGzDyB,EAAA,KAAA,0BAAA,MAAAA,EAAyB,cAAcL,GACxC,CAAC,KAAK,aAAe,CAACpB,EAAK,kBAAkBqB,EAAW,mBAAqBrB,EAAK,KAAK,EAEpF,MAAA,KACF,CACL,GAAIA,EAAK,kBAAoB,QAAasB,EAAM,OAAStB,EAAK,gBAC5D,MAAM,IAAI,MACR,mCAAmCA,EAAK,eAAe,YAAYsB,EAAM,IAAI,uBAAuBtB,EAAK,KAAK,EAChH,EAEF,MAAMpC,EAAM,CAAC,EACb,OAAI8D,EAAAA,oBAAoBJ,EAAM,KAAK,IAAG1D,EAAI,MAAQ0D,EAAM,OACpDI,EAAAA,oBAAoBJ,EAAM,KAAK,IAAG1D,EAAI,MAAQ0D,EAAM,OACpD1D,EAAI,QAAU,QAAaA,EAAI,QAAU,QAIhCyD,EAAA,sBAAwBrB,EAAK,KAAK,EACzCsB,EAAA,OAAO,cAAcF,CAAO,EAC3BxD,CAAA,CACT,CAGK,gBAAgBwD,EAA2B,OAChD,OAAK,KAAK,eAEHG,EAAA,KAAA,sBAAA,MAAAA,EAAqB,cAAcH,GACnC,KAAK,YAAA,CAGP,iBAAiBA,EAA2B,OACjD,OAAK,KAAK,gBAEHG,EAAA,KAAA,sBAAA,MAAAA,EAAqB,cAAcH,GACnC,KAAK,aAAA,CAGd,IAAW,gBAA0B,CACnC,OACE,KAAK,QAAUO,EAAA,gBACZ,KAAK,eACL,KAAK,qBAAuBA,EAAA,cAAA,CAI5B,WAAWP,EAA2B,OACtC,OAAAG,EAAA,KAAA,eAAA,MAAAA,EAAc,cAAcH,GAC1B,KAAK,WAAA,CAGP,kBAAkBA,EAA2B,OAClD,OAAK,KAAK,iBAEHG,EAAA,KAAA,sBAAA,MAAAA,EAAqB,cAAcH,GACnC,KAAK,cAAA,CAGP,SAASA,EAA0C,OACpD,GAAAQ,EAAA,iBAAiB,KAAK,KAAK,EAAG,EAC3BL,EAAA,KAAA,sBAAA,MAAAA,EAAqB,cAAcH,GACjC,MAAA,KAGP,QAAO,KAAK,KACd,CAGK,gBAAgBA,EAA4B,OACjD,MAAMxD,EAAgB,CAAC,EACvB,YAAK,UAAU,QAAQ,CAAC0D,EAAOf,IAAS,EAClCe,EAAM,OAAS,SAAWA,EAAM,OAAS,YAAW1D,EAAI,KAAK2C,CAAI,CAAA,CACtE,EACI,KAAK,eAAmBgB,EAAA,KAAA,kCAAA,MAAAA,EAAiC,cAAcH,GAErExD,CAAA,CAGF,iBAAiBwD,EAA4B,OAClD,MAAMxD,EAAgB,CAAC,EACvB,YAAK,UAAU,QAAQ,CAAC0D,EAAOf,IAAS,CAClCe,EAAM,OAAS,UAAU1D,EAAI,KAAK2C,CAAI,CAAA,CAC3C,EACI,KAAK,gBAAoBgB,EAAA,KAAA,yBAAA,MAAAA,EAAwB,cAAcH,GAE7DxD,CAAA,CAGF,kBAAkBwD,EAA4B,OACnD,MAAMxD,EAAgB,CAAC,EACvB,YAAK,UAAU,QAAQ,CAAC0D,EAAOf,IAAS,CAClCe,EAAM,OAAS,SAAWA,EAAM,OAAS,UAAU1D,EAAI,KAAK2C,CAAI,CAAA,CACrE,GACIgB,EAAA,KAAA,0BAAA,MAAAA,EAAyB,cAAcH,GAErCxD,CAAA,CAGF,YAAYwD,EAAkBjB,EAAqC,OACnE,OAAAoB,EAAA,KAAA,YAAA,MAAAA,EAAW,cAAcH,GACvB,KAAK,GAAG,IAAIjB,CAAG,CAAA,CAGjB,kBAAkBiB,EAAkBjB,EAAiC,CAC1E,MAAM0B,EAAQ,KAAK,YAAYT,EAASjB,CAAG,EACvC,GAAA0B,IAAU,OACd,OAAOC,EAAAA,aAAaD,CAAK,CAAA,CAGpB,kBAA+BT,EAAkBjB,EAA4B,CAClF,MAAM0B,EAAQ,KAAK,YAAYT,EAASjB,CAAG,EACvC,GAAA0B,IAAU,OACd,OAAOE,EAAAA,kBAAkBF,CAAK,CAAA,CAGzB,iBAAsC,CACvC,GAAA,KAAK,OAAS,OAClB,OAAI,KAAK,eAAiB,cAAgB,aAAeC,EAAA,aAAa,KAAK,IAAI,GACxE,KAAK,YAAA,CAGP,eAA4C,CAC7C,GAAA,KAAK,OAAS,OAClB,OAAI,KAAK,aAAe,cAAgB,WAAaC,EAAA,kBAAkB,KAAK,IAAI,GACzE,KAAK,UAAA,CAGd,kBAAmB,CACb,GAAA,KAAK,eAAiB,CAAC,KAAK,aAC9B,MAAM,IAAI,MAAM,uCAAuCC,0BAAwB,KAAK,UAAU,CAAC,EAAE,CAAA,CAGrG,IAAI,YAAgC,CAC3B,MAAA,CACL,GAAI,KAAK,GACT,KAAM,KAAK,KACX,KAAM,KAAK,KACX,KAAM,KAAK,KACX,cAAe,KAAK,cACpB,aAAc,KAAK,aACnB,cAAe,KAAK,cACpB,MAAO,KAAK,MACZ,mBAAoB,KAAK,mBACzB,MAAO,KAAK,SACd,CAAA,CAGF,IAAI,eAAsC,CACjC,MAAA,CACL,GAAG,KAAK,WACR,OAAQ,KAAK,OACb,GAAI,MAAM,KAAK,KAAK,GAAG,SAAS,EAAE,IAAI,CAAC,CAAC7B,EAAKM,CAAK,KAAO,CAAE,IAAAN,EAAK,MAAAM,GAAQ,CAC1E,CAAA,CAIF,WAAY,CACN,KAAK,cAET,KAAK,YAAc,GACVtB,EAAAA,SAAA,KAAK,YAAY,EAAE,YAAY,EACxC,KAAK,aAAe,OACpB,KAAK,oBAAsB,OAC3B,KAAK,wBAA0B,OAC/B,KAAK,gCAAkC,OACvC,KAAK,uBAAyB,OAC9B,KAAK,aAAe,OAAA,CAItB,gBAAiB,mBACf,KAAK,UAAU,QAASmC,GAAUA,EAAM,OAAO,aAAa,GAC5DC,EAAA,KAAK,eAAL,MAAAA,EAAmB,eACnBC,EAAA,KAAK,sBAAL,MAAAA,EAA0B,eAC1BC,EAAA,KAAK,eAAL,MAAAA,EAAmB,eACnBQ,EAAA,KAAK,kCAAL,MAAAA,EAAsC,eACtCC,EAAA,KAAK,yBAAL,MAAAA,EAA6B,eAC7BC,EAAA,KAAK,0BAAL,MAAAA,EAA8B,eAC9BC,EAAA,KAAK,YAAL,MAAAA,EAAgB,cAChB,KAAK,gBAAgB,YAAY,CAAA,CAErC,CAEO,MAAMC,CAAY,CASvB,YAEkBC,EACAC,EAChB,CAXMjE,EAAA,qBAAiD,KACxCA,EAAA,sBAAiB,IAAIwC,EAAAA,cAG9BxC,EAAA,gBAAoB,IACpBA,EAAA,4BAIU,KAAA,KAAAgE,EACA,KAAA,iBAAAC,CAAA,CAGX,gBAAgBC,EAAqD,CAC1E,KAAK,UAAU,QAASC,GAAMD,EAAGC,CAAC,CAAC,CAAA,CAG7B,YAAa,CACf,GAAA,CAAC,KAAK,SAAU,MAAM,IAAI,MAAM,KAAK,qBAAuB,0BAA0B,CAAA,CAGrF,IAAIrB,EAAkB/C,EAAiC,CAC5D,KAAK,WAAW,EAChB,MAAMmB,EAAM,KAAK,UAAU,IAAInB,CAAG,EAClC,GAAImB,IAAQ,OAGL,WAAA,eAAe,cAAc4B,CAAO,EACnC,IAAI,MAAM,YAAY1C,EAAmB,mBAAAL,CAAG,CAAC,wBAAwB,EAEzE,OAAAmB,EAAA,gBAAgB,cAAc4B,CAAO,EAClC5B,CAAA,CAGT,uBAAuBkD,EAAsCC,EAA6B,GAAO,CAC/F,KAAK,WAAW,EAGhB,MAAMC,EAA8B,CAAC,EAC/BC,EAA8B,CAAC,EAGrC,UAAWC,KAAMJ,EAAc,CAC7B,IAAIjD,EAAW,KAAK,UAAU,IAAIqD,EAAG,EAAE,EAEvC,MAAMC,EAAqBtD,GAAA,YAAAA,EAAU,WAC/BuD,EAA6BC,GAA0B,CAE3D,KAAM,CAAE,OAAAC,EAAQ,GAAGC,CAAA,EAAoBL,EACvC,WAAK,eAAe,EACd,IAAIzC,EACR,yCAAyC4C,CAAM,MAAMjB,EAAA,wBACnDmB,CAAA,CACD,OAAOnB,0BAAwBe,CAAkB,CAAC,EACrD,CACF,EAEA,GAAItD,IAAa,OAAW,CAGtBA,EAAS,YACXuD,EAA0B,4DAA6D,EAEzF,IAAII,EAAU,GAEd3D,EAAS,SAAW,EAGhBA,EAAS,qBAAuBqD,EAAG,qBACjCrD,EAAS,qBAAuBkC,EAAA,gBAClCqB,EAA0B,iDAAkD,EAC9EvD,EAAS,mBAAqBqD,EAAG,mBAExB3D,EAAAA,SAAAM,EAAS,mBAAmB,EAAE,YAAY,EACzC2D,EAAA,IAIR3D,EAAS,QAAUqD,EAAG,QACpBpB,EAAA,oBAAoBjC,EAAS,KAAK,GACpCuD,EAA0B,sDAAuD,EACnFvD,EAAS,MAAQqD,EAAG,MACNF,EAAA,KAAKnD,EAAS,KAAmB,EACtCN,EAAAA,SAAAM,EAAS,mBAAmB,EAAE,YAAY,EACzC2D,EAAA,IAID,UAAAC,KAAMP,EAAG,OAAQ,CAC1B,IAAIxB,EAAQ7B,EAAS,UAAU,IAAI4D,EAAG,IAAI,EAErC/B,GAsCCA,EAAM,OAAS+B,EAAG,OAChB/B,EAAM,OAAS,WACjB0B,EAA0B,sBAAsB1B,EAAM,IAAI,OAAO+B,EAAG,IAAI,EAAE,EACnElE,EAAAA,SAAAM,EAAS,uBAAuB,EAAE,YAAY,GACnD6B,EAAM,OAAS,SAAWA,EAAM,OAAS,aACvC7B,EAAS,cACXuD,EACE,uBAAuBK,EAAG,IAAI,uCAChC,EACOlE,EAAAA,SAAAM,EAAS,+BAA+B,EAAE,YAAY,GAE7D6B,EAAM,OAAS,WACb7B,EAAS,eACXuD,EACE,wBAAwBK,EAAG,IAAI,uCACjC,EACOlE,EAAAA,SAAAM,EAAS,sBAAsB,EAAE,YAAY,GAExD6B,EAAM,KAAO+B,EAAG,KAChB/B,EAAM,OAAO,YAAY,EACf8B,EAAA,IAIR9B,EAAM,QAAU+B,EAAG,QACjB3B,EAAAA,oBAAoBJ,EAAM,KAAK,GAAiBuB,EAAA,KAAKvB,EAAM,KAAK,EACpEA,EAAM,MAAQ+B,EAAG,MACb3B,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAC9D/B,EAAM,OAAO,YAAY,EACf8B,EAAA,IAIR9B,EAAM,QAAU+B,EAAG,QACjB3B,EAAAA,oBAAoBJ,EAAM,KAAK,GAAiBuB,EAAA,KAAKvB,EAAM,KAAK,EACpEA,EAAM,MAAQ+B,EAAG,MACb3B,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAC9D/B,EAAM,OAAO,YAAY,EACf8B,EAAA,IAIR9B,EAAM,SAAW+B,EAAG,SACtB/B,EAAM,OAAS+B,EAAG,OAClB/B,EAAM,OAAO,YAAY,EACf8B,EAAA,IAIR9B,EAAM,eAAiB+B,EAAG,eAC5B/B,EAAM,aAAe+B,EAAG,aACxB/B,EAAM,OAAO,YAAY,EACf8B,EAAA,IAGZ9B,EAAM,gBAAkB7B,EAAS,UA1FjC6B,EAAQ,IAAIhB,EACV+C,EAAG,KACHA,EAAG,KACHA,EAAG,MACHA,EAAG,MACHA,EAAG,OACHA,EAAG,aACH5D,EAAS,OACX,EACIiC,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAC1D3B,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAE1DA,EAAG,OAAS,SAAWA,EAAG,OAAS,WACjC5D,EAAS,cACXuD,EACE,UAAUK,EAAG,IAAI,KAAKA,EAAG,IAAI,6BAC/B,EACOlE,EAAAA,SAAAM,EAAS,+BAA+B,EAAE,YAAY,GACtD4D,EAAG,OAAS,UACjB5D,EAAS,eACXuD,EACE,UAAUK,EAAG,IAAI,KAAKA,EAAG,IAAI,8BAC/B,EACOlE,EAAAA,SAAAM,EAAS,sBAAsB,EAAE,YAAY,GAE7CN,EAAAA,SAAAM,EAAS,uBAAuB,EAAE,YAAY,EAGzDA,EAAS,UAAU,IAAI4D,EAAG,KAAM/B,CAAK,EAE3B8B,EAAA,GA6DZ,CAoCE,GAhCJ3D,EAAS,UAAU,QAAQ,CAAC6B,EAAOgC,EAAWJ,IAAW,CACnD5B,EAAM,kBAAoB7B,EAAU,WAClC6B,EAAM,OAAS,SAAWA,EAAM,OAAS,WAAaA,EAAM,OAAS,WACvE0B,EAA0B,cAAc1B,EAAM,IAAI,UAAUgC,CAAS,EAAE,EACzEhC,EAAM,OAAO,YAAY,EACzB4B,EAAO,OAAOI,CAAS,EAEnB5B,EAAAA,oBAAoBJ,EAAM,KAAK,GAAiBuB,EAAA,KAAKvB,EAAM,KAAK,EAChEI,EAAAA,oBAAoBJ,EAAM,KAAK,GAAiBuB,EAAA,KAAKvB,EAAM,KAAK,EAE3DnC,EAAAA,SAAAM,EAAU,uBAAuB,EAAE,YAAY,EAC1D,CACD,EAGGA,EAAS,eAAiBqD,EAAG,eAC3BrD,EAAS,cAAcuD,EAA0B,mCAAmC,EACxFvD,EAAS,aAAeqD,EAAG,aAClB3D,EAAAA,SAAAM,EAAS,YAAY,EAAE,YAAY,EAClC2D,EAAA,IAIR3D,EAAS,gBAAkBqD,EAAG,gBAC5BrD,EAAS,eACXuD,EAA0B,oCAAoC,EAChEvD,EAAS,cAAgBqD,EAAG,cACnB3D,EAAAA,SAAAM,EAAS,YAAY,EAAE,YAAY,EAClC2D,EAAA,IAIR3D,EAAS,gBAAkBqD,EAAG,cAAe,CAC/C,MAAMS,EAAmB9D,EAAS,cAClCA,EAAS,cAAgBqD,EAAG,cAC5BrD,EAAS,iBAAiB,EACrBA,EAAS,gBACZuD,EACE,qEAAqEO,CAAgB,GACvF,EACOpE,EAAAA,SAAAM,EAAS,mBAAmB,EAAE,YAAY,EACzC2D,EAAA,EAAA,CAIZ,IAAII,EAAY,GACL,UAAAC,KAAMX,EAAG,GAAI,CACtB,MAAMhD,EAAUL,EAAS,GAAG,IAAIgE,EAAG,GAAG,GAClC3D,IAAY,QAGL,OAAO,QAAQA,EAAS2D,EAAG,KAAK,IAAM,KAC/ChE,EAAS,GAAG,IAAIgE,EAAG,IAAKA,EAAG,KAAK,EACpBD,EAAA,GACd,CAGF,GAAI/D,EAAS,GAAG,KAAOqD,EAAG,GAAG,OAAQ,CAE7B,MAAAY,EAAe,IAAI,IAAIZ,EAAG,GAAG,IAAKW,GAAOA,EAAG,GAAG,CAAC,EAGtDhE,EAAS,GAAG,QAAQ,CAACkE,EAAQxD,EAAKyD,IAAQ,CACnCF,EAAa,IAAIvD,CAAG,GAAGyD,EAAI,OAAOzD,CAAG,CAAA,CAC3C,EAEWqD,EAAA,EAAA,CAGVA,GAAWrE,EAAA,SAASM,EAAS,SAAS,EAAE,YAAY,EAEpD2D,IAEF3D,EAAS,YAAcA,EAAS,QAC5B,KAAK,iBAAiBA,CAAQ,KAAY,UAAU,EAC1D,KACK,CAGMA,EAAA,IAAIuB,EAAe8B,CAAE,EAChCrD,EAAS,iBAAiB,EACtBiC,EAAAA,oBAAoBjC,EAAS,KAAK,GAAiBmD,EAAA,KAAKnD,EAAS,KAAK,EAC/D,UAAA4D,KAAMP,EAAG,OAAQ,CAC1B,MAAMxB,EAAQ,IAAIhB,EAChB+C,EAAG,KACHA,EAAG,KACHA,EAAG,MACHA,EAAG,MACHA,EAAG,OACHA,EAAG,aACHtC,CACF,EACIW,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAC1D3B,EAAAA,oBAAoB2B,EAAG,KAAK,GAAiBT,EAAA,KAAKS,EAAG,KAAK,EAC9D5D,EAAS,UAAU,IAAI4D,EAAG,KAAM/B,CAAK,CAAA,CAI5B,UAAAmC,KAAMX,EAAG,GAAIrD,EAAS,GAAG,IAAIgE,EAAG,IAAKA,EAAG,KAAK,EAGpD,KAAK,iBAAiBhE,CAAQ,KAAY,UAAU,EAGxD,KAAK,UAAU,IAAIA,EAAS,GAAIA,CAAQ,EACxC,KAAK,eAAe,YAAY,CAAA,CAClC,CAIF,UAAWpB,KAAOuE,EAAe,CAC/B,MAAMpD,EAAM,KAAK,UAAU,IAAInB,CAAG,EAClC,GAAI,CAACmB,EACH,WAAK,eAAe,EACd,IAAIa,EAAqB,mBAAmBhC,CAAG,EAAE,EAErDmB,EAAA,UAAA,CAIN,IAAIqE,EAAchB,EACX,KAAAgB,EAAY,OAAS,GAAG,CAC7B,MAAMC,EAAyB,CAAC,EAChC,UAAWzF,KAAOwF,EAAa,CAC7B,MAAMrE,EAAM,KAAK,UAAU,IAAInB,CAAG,EAClC,GAAI,CAACmB,EACH,WAAK,eAAe,EACd,IAAIa,EAAqB,mBAAmBhC,CAAG,EAAE,EAErDmB,EAAA,WAGAA,EAAI,WAAa,GAAKA,EAAI,KAAO,KAAK,OAEpCA,EAAA,UAAU,QAAS8B,GAAU,CAC3BI,EAAAA,oBAAoBJ,EAAM,KAAK,GAAYwC,EAAA,KAAKxC,EAAM,KAAK,EAC3DI,EAAAA,oBAAoBJ,EAAM,KAAK,GAAYwC,EAAA,KAAKxC,EAAM,KAAK,EAC/DA,EAAM,OAAO,YAAY,CAAA,CAC1B,EACGI,EAAAA,oBAAoBlC,EAAI,KAAK,GAAYsE,EAAA,KAAKtE,EAAI,KAAK,EAC3DA,EAAI,gBAAgB,YAAY,EAC3B,KAAA,UAAU,OAAOnB,CAAG,EAC3B,CAEYwF,EAAAC,CAAA,CAIhB,GAAI,CAACnB,GACH,UAAWG,KAAMJ,EACf,GAAI,CAAC,KAAK,UAAU,IAAII,EAAG,EAAE,EAC3B,WAAK,eAAe,EACd,IAAIzC,EAAqB,yBAAyByC,EAAG,EAAE,EAAE,EAGrE,CAIK,SAASzE,EAAkB,KAAK,KAAmB,CACxD,YAAK,WAAW,EACT,KAAK,MAAMA,CAAG,CAAA,CAGhB,MAAMA,EAAkB,KAAK,KAAmB,CACrD,YAAK,WAAW,EACT,IAAIF,EAAY,CAAE,aAAc,IAAM,IAAA,EAAQE,CAAG,CAAA,CAGnD,eAAe8C,EAAc,CAClC,KAAK,SAAW,GAChB,KAAK,oBAAsBA,EACtB,KAAA,UAAU,QAAS3B,GAAQ,CAC9BA,EAAI,eAAe,CAAA,CACpB,CAAA,CAGI,WAAoC,CAClC,OAAA,MAAM,KAAK,KAAK,UAAU,QAAQ,EAAE,IAAKA,GAAQA,EAAI,aAAa,CAAA,CAE7E,CC1sBgB,SAAAuE,EACdnF,EACAoF,EACoB,CACpB,MAAMC,EAA8B,CAAC,EAC/BC,MAAqB,IACtB,OAAAtF,EAAA,gBAAiBY,GAAQ,CACxBA,EAAI,WAA2B0E,EAAA,IAAI1E,EAAI,EAAE,EACxCyE,EAAc,KAAKzE,EAAI,EAAE,CAAA,CAC/B,EAGGyE,EAAc,SAAW,GAAKC,EAAe,OAAS,GAAGD,EAAc,KAAKrF,EAAK,IAAI,EAElF,CAAE,cAAAqF,EAAe,eAAAC,EAAgB,gBAAAF,CAAgB,CAC1D,CAeO,SAASG,GAA0C,CACjD,MAAA,CACL,SAAU,EACV,WAAY,EACZ,mBAAoB,EACpB,gBAAiB,EACjB,mBAAoB,EACpB,2BAA4B,EAC5B,uBAAwB,EACxB,aAAc,EACd,sBAAuB,EACvB,YAAa,CACf,CACF,CAEO,SAASC,EAAsBC,EAA+B,CAC/D,IAAAxE,EAAS,aAAawE,EAAK,QAAQ;AAAA,EACvC,OAAAxE,GAAU,eAAeyE,oBAAkBD,EAAK,WAAW,CAAC;AAAA,EAClDxE,GAAA,gBAAgBwE,EAAK,UAAU;AAAA,EAC/BxE,GAAA,cAAcwE,EAAK,kBAAkB;AAAA,EACrCxE,GAAA,WAAWwE,EAAK,eAAe;AAAA,EAC/BxE,GAAA,OAAOwE,EAAK,kBAAkB;AAAA,EAC9BxE,GAAA,eAAewE,EAAK,0BAA0B;AAAA,EAC9CxE,GAAA,aAAawE,EAAK,sBAAsB;AAAA,EACxCxE,GAAA,kBAAkBwE,EAAK,YAAY;AAAA,EACnCxE,GAAA,4BAA4BwE,EAAK,qBAAqB,GACzDxE,CACT,CAKsB,eAAA0E,EACpBC,EACAC,EACAC,EACiC,OAE3B,MAAAC,EAAiB,KAAK,IAAI,EAG5BD,GAAaA,EAAA,WAEjB,KAAM,CAAE,cAAAT,EAAe,eAAAC,EAAgB,gBAAAF,CAAoB,EAAAS,EAOrDG,EAAU,IAAIC,EAGpB,IAAIC,EAA2B,GAC3BC,EAAqB,EAGnB,MAAAC,MAAgB,IAChBC,EAAgB5G,GAA4B,CAChD,GAAIuD,EAAAA,iBAAiBvD,CAAG,GAAK2G,EAAU,IAAI3G,CAAG,EAAG,OAG7C,GAAA6F,EAAe,IAAI7F,CAAG,EAAG,CACvBqG,GAAaA,EAAA,wBACjB,MAAA,CAKFM,EAAU,IAAI3G,CAAG,EAGjB,MAAMqE,EAAe8B,EAAG,wBAAwBnG,EAAK,EAAI,EACnD6G,EAASV,EAAG,8BAA8BnG,CAAG,EAG7C8G,EAAQL,EACVA,IAAmCA,EAAA,IAG/BF,EAAA,MACL,SAAY,CACL,KAAA,CAACnF,EAAUgE,CAAE,EAAI,MAAM,QAAQ,IAAI,CAACf,EAAcwC,CAAM,CAAC,EAQ3D,GALAC,IACFJ,IACkBD,EAAA,IAGhBrF,IAAa,OAEjB,IAAIgE,IAAO,OAAiB,MAAA,IAAI,MAAM,sBAAsB,EAErD,MAAA,CAAE,GAAGhE,EAAU,GAAAgE,CAAG,EACxB,GAAA,CACL,CACF,EAGAQ,EAAc,QAAS5F,GAAQ4G,EAAa5G,CAAG,CAAC,EAEhD,MAAMwB,EAAiC,CAAC,EACxC,OAAa,CAEL,MAAAuF,EAAsBR,EAAQ,MAAM,EAC1C,GAAIQ,IAAwB,OAE1B,MAGF,IAAIC,EAAe,MAAMD,EACzB,GAAIC,IAAiB,OAIrB,IAAIrB,IAAoB,OAAW,CAE3B,MAAAsB,EAAqBtB,EAAgBqB,CAAY,EAEnDX,IAAaA,EAAA,cAAgBW,EAAa,OAAO,OAASC,EAAmB,QACjFD,EAAe,CAAE,GAAGA,EAAc,OAAQC,CAAmB,CAAA,CAI/DL,EAAaI,EAAa,KAAK,EACpB,UAAA/D,KAAS+D,EAAa,OAC/BJ,EAAa3D,EAAM,KAAK,EACxB2D,EAAa3D,EAAM,KAAK,EAI1B,GAAIoD,EAAO,CACHA,EAAA,qBACAA,EAAA,iBAAmBW,EAAa,OAAO,OACvCX,EAAA,oBAAsBW,EAAa,GAAG,OACtCX,EAAA,8BAA8BnD,EAAA8D,EAAa,OAAb,YAAA9D,EAAmB,SAAU,EACjE,UAAWkC,KAAM4B,EAAa,GAAUX,EAAA,wBAA0BjB,EAAG,MAAM,MAAA,CAI7E5D,EAAO,KAAKwF,CAAY,EAAA,CAI1B,OAAIX,IACIA,EAAA,aAAe,KAAK,IAAQ,EAAAC,EAClCD,EAAM,YAAcK,GAGflF,CACT,CC9KO,SAAS0F,EAKdC,EAC0C,CACnC,OAAAA,CACT,CA8DgB,SAAAC,EACdjG,EACAgG,EACAjH,EACuB,OACvB,MAAMmH,EACFlG,aAAerB,EACbgB,EAAAA,SAASZ,CAAG,EAAE,SAASiB,CAAG,EAAE,KAC5B,EAAAA,aAAef,EACbe,EAAI,OACJA,EAEFK,EAAgF,CAAE,GAD3E6F,EAAK,YAC8E,EAO5F,GALAF,EAAO,OAAS,SACdA,EAAO,OAAS,MAAc3F,EAAA,KAAO6F,EAAK,QAAQ,IAC1C,KAAOF,EAAO,KAAK,MAAME,EAAK,eAAe,GAGvDF,EAAO,SAAW,OAAW,CAC/B,MAAMtC,EAAiD,CAAC,EAGxD,SAAW,CAACI,EAAWqC,CAAQ,IAAK,OAAO,QAAQH,EAAO,MAAM,EACvDtC,EAAAI,CAAS,GAAI/B,EAAAmE,EAAK,SAAS,CAChC,MAAOpC,EACP,mBAAoBqC,EACpB,iBAAkB,CAACA,CACpB,CAAA,IAJmB,YAAApE,EAIhB,GACN1B,EAAO,OAASqD,CAAA,CAGd,GAAAsC,EAAO,KAAO,OAAW,CAC3B,MAAM/B,EAA8B,CAAC,EAC1B,SAAA,CAACH,EAAW9C,CAAI,IAAK,OAAO,QAAQgF,EAAO,EAAE,EAAG,CACnD,MAAA/E,EAAQiF,EAAK,YAAYpC,CAAS,EAExC,GAAI7C,IAAU,OACZ,MAAM,IAAI,MAAM,iBAAiB6C,CAAS,EAAE,EACnC9C,IAAS,MAClBiD,EAAGH,CAAS,EAAI7C,EAEhBgD,EAAGH,CAAS,EAAI9C,EAAK,MAAM,KAAK,MAAM,OAAO,KAAKC,CAAK,EAAE,SAAS,OAAO,CAAC,CAAC,CAC7E,CAEFZ,EAAO,GAAK4D,CAAA,CAGP,OAAA5D,CACT,CAWgB,SAAA+F,GACdpG,EACA0D,EACA3E,EACkB,CAClB,GAAIiB,aAAerB,EAAa,CAC9B,MAAMuH,EAAOnH,EAAI,SAASiB,CAAG,EAAE,KAAK,EAC9BqG,EAAOH,EAAK,aAEZI,EAA8C5C,EAAO,IAAK3C,GAAS,SAAA,OACvEA,GACAiB,GAAAD,EAAAmE,EAAK,SAASnF,CAAI,IAAlB,YAAAgB,EAAqB,QAArB,YAAAC,EAA4B,EAAA,EAC7B,EAEM,MAAA,CACL,GAAGqE,EACH,OAAQ,IAAI,IAAIC,CAAO,EACvB,KAAMJ,EAAK,QAAQ,GAAK,IAAI,UAC9B,CAAA,CAGK,OAAAlG,CACT,CAUgB,SAAAuG,GACdvG,EACAwG,EACAzH,EACsB,CAClB,GAAA,EAAEiB,aAAerB,GAAqB,OAAAqB,EAE1C,MAAMkG,EAAOnH,EAAI,SAASiB,CAAG,EAAE,KAAK,EAC9BqG,EAAOH,EAAK,aACZO,EAA6BD,EAAO,IAAKE,GAAM,CAACA,EAAGR,EAAK,YAAYQ,CAAC,CAAC,CAAC,EAEtE,MAAA,CACL,GAAGL,EACH,SAAU,OAAO,YAAYI,CAAS,CACxC,CACF,CCzKO,MAAME,CAAsB,CASzB,YACWC,EACA9D,EACjBxD,EACiBoC,EACjB,CAbe5C,EAAA,uBACTA,EAAA,cACSA,EAAA,wBACAA,EAAA,gBACAA,EAAA,gBACAA,EAAA,cACAA,EAAA,uBAAkB,IAAI,iBAwC/BA,EAAA,kCACAA,EAAA,4BAA2C,CAAC,GA2B5CA,EAAA,mBAAc,IAEdA,EAAA,oBAaAA,EAAA,kBAAa,IAhFF,KAAA,GAAA8H,EACA,KAAA,KAAA9D,EAEA,KAAA,OAAApB,EAEjB,KAAM,CAAE,uBAAAmF,EAAwB,QAAAC,EAAS,gBAAAC,EAAiB,iBAAAC,EAAkB,QAAAC,GAAY3H,EACxF,KAAK,QAAUwH,EACf,KAAK,gBAAkBC,EAClB,KAAA,eAAiBF,GAA0BD,EAAG,eACnD,KAAK,QAAUK,EACf,KAAK,MAAQ,IAAIpE,EAAYC,EAAM,KAAK,cAAc,EACtD,KAAK,MAAQ,IAAIoE,EAAA,uBACf,IAAM,KAAK,cAAc,EACzB,IAAM,KAAK,aAAa,EACxB,CAAE,aAAcF,CAAiB,EACjC,CAACG,EAASC,IAAW,KAAK,oBAAoBD,EAASC,CAAM,CAC/D,CAAA,CAIK,SAASvI,EAAkB,KAAK,KAAmB,CACxD,GAAI,KAAK,WAAkB,MAAA,IAAI,MAAM,oCAAoC,EAClE,OAAA,KAAK,MAAMA,CAAG,CAAA,CAGhB,MAAMA,EAAkB,KAAK,KAAmB,CACrD,GAAI,KAAK,WAAkB,MAAA,IAAI,MAAM,oCAAoC,EAClE,OAAA,IAAIF,EAAY,CAAE,aAAc,IAAM,KAAK,MAAO,MAAO,KAAK,KAAM,EAAGE,CAAG,CAAA,CAKnF,MAAa,cAA8B,CACzC,GAAI,KAAK,WAAkB,MAAA,IAAI,MAAM,oCAAoC,EACnE,MAAA,KAAK,MAAM,aAAa,CAAA,CAOxB,oBAAoBsI,EAAqBC,EAAkC,CAC7E,KAAK,WAAYA,EAAO,IAAI,MAAM,oCAAoC,CAAC,GAEzE,KAAK,qBAAqB,KAAK,CAAE,QAAAD,EAAS,OAAAC,EAAQ,EAC9C,KAAK,4BACP,KAAK,0BAA0B,MAAM,EACrC,KAAK,0BAA4B,QAErC,CAIM,eAAsB,CACxB,KAAK,aACT,KAAK,YAAc,GACf,KAAK,cAAgB,SAAgB,KAAA,YAAc,KAAK,SAAS,GAAA,CAI/D,cAAqB,CAC3B,KAAK,YAAc,EAAA,CASrB,MAAc,QAAQlC,EAAyBmC,EAA8B,CAC3E,GAAI,KAAK,WAAkB,MAAA,IAAI,MAAM,oCAAoC,EACzE,MAAMC,EAAU/C,EAA4B,KAAK,MAAO,KAAK,OAAO,EAC9DgD,EAAO,MAAM,KAAK,GAAG,WAAW,cAAe,MAAOvC,GACnD,MAAMD,EAAcC,EAAIsC,EAASpC,CAAK,EAC5CmC,CAAK,EACH,KAAA,MAAM,uBAAuBE,EAAM,EAAI,CAAA,CAM9C,MAAc,UAAW,SAEvB,IAAI1C,EAAO,KAAK,QAAUF,EAA2B,EAAA,OAEjD6C,EAAa,KAAK,IAAI,EAE1B,KACM,GAAC,KAAK,aAAe,KAAK,aADnB,CAMX,IAAIC,EACA,KAAK,qBAAqB,OAAS,IACrCA,EAAW,KAAK,qBAChB,KAAK,qBAAuB,CAAC,GAG3B,GAAA,CAYF,GAVI,KAAK,UAAY,gBAAe5C,EAAOF,EAAuB,GAG5D,MAAA,KAAK,QAAQE,CAAI,EAGnBA,GAAQ,KAAK,QAAa,KAAA,OAAO,KAAK,6BAA6B,KAAK,IAAI,EAAI2C,CAAU,QAAQ,KAAK,UAAU3C,CAAI,CAAC,EAAE,EAC5H2C,EAAa,KAAK,IAAI,EAGlBC,IAAa,OAAW,UAAWC,KAAKD,IAAY,QAAQ,QACzDE,EAAQ,CAMf,GAJI9C,GAAQ,KAAK,QAAa,KAAA,OAAO,KAAK,2BAA2B,KAAK,IAAI,EAAI2C,CAAU,QAAQ,KAAK,UAAU3C,CAAI,CAAC,EAAE,EAC1H2C,EAAa,KAAK,IAAI,EAGlBC,IAAa,OAAW,UAAWC,KAAKD,EAAUC,EAAE,OAAOC,CAAC,EAGhE,GAAIA,aAAa9G,EAAsB,EAEhCkB,EAAA,KAAA,SAAA,MAAAA,EAAQ,MAAM4F,GAGd,KAAA,MAAM,eAAe,mBAAmB,EAE7C,KAAK,MAAQ,IAAI9E,EAAY,KAAK,KAAM,KAAK,cAAc,EAG3D,QAMK,MAAAb,EAAA,KAAK,SAAL,MAAAA,EAAa,KAAK2F,EAAC,CAG5B,GAAI,CAAC,KAAK,aAAe,KAAK,WAAY,MAEtC,GAAA,KAAK,qBAAqB,SAAW,EACnC,GAAA,CACG,KAAA,0BAA4B,IAAI,gBACrC,MAAMC,EAAG,WAAW,KAAK,gBACvB,YAAY,IAAI,CAAC,KAAK,gBAAgB,OAAQ,KAAK,0BAA0B,MAAM,CAAC,CAAC,QAChFD,EAAY,CACf,GAAA,CAACE,EAAAA,uBAAuBF,CAAC,EAAG,MAAM,IAAI,MAAM,mBAAoB,CAAE,MAAOA,EAAG,EAChF,KAAA,QACA,CACA,KAAK,0BAA4B,MAAA,CAErC,CAIF,KAAK,YAAc,MAAA,CAOd,WAAoC,CAClC,OAAA,KAAK,MAAM,UAAU,CAAA,CAO9B,MAAa,WAA2B,CACtC,KAAK,YAAc,GACnB,KAAK,WAAa,GAClB,KAAK,gBAAgB,MAAM,EAEvB,KAAK,cAAgB,SACzB,MAAM,KAAK,YAEN,KAAA,MAAM,eAAe,yCAAyC,EAAA,CAIrE,MAAa,0BAA0C,CACjD,KAAK,cAAgB,QACzB,MAAM,KAAK,WAAA,CAGb,aAAoB,KAClBf,EACA9D,EACAxD,EACAoC,EACA,CACA,MAAMtC,EAAO,IAAIuH,EAAsBC,EAAI9D,EAAMxD,EAAKoC,CAAM,EAEtDmD,EAAOvF,EAAI,QAAUqF,EAA2B,EAAA,OAEtD,IAAImD,EAAK,GAEL,GAAA,CACI,MAAA1I,EAAK,QAAQyF,EAAM,CACvB,QAASvF,EAAI,yBAAA,CACd,EACIwI,EAAA,EAAA,QACL,CAEIjD,GAAQnD,GACHA,EAAA,KACL,4BAA4BoG,EAAK,UAAY,SAAS,MAAM,KAAK,UAAUjD,CAAI,CAAC,EAClF,CAAA,CAGG,OAAAzF,CAAA,CAEX,CC3NO,SAAS2I,GAAcC,EAAkD,OAC9E,MAAM9C,EAAuB,CAC3B,MAAO,CACL,MAAO,EACP,eAAgB,EAChB,YAAa,EACb,UAAW,EACX,QAAS,EACT,QAAS,CACX,EACA,eAAgB,CAAA,CAClB,EAEA,UAAWjF,KAAY+H,EAAW,CAC1B,MAAAC,EAAU,GAAGhI,EAAS,KAAK,IAAI,IAAIA,EAAS,KAAK,OAAO,GACzDiF,EAAM,eAAe+C,CAAO,IACzB/C,EAAA,eAAe+C,CAAO,EAAI,CAC9B,MAAO,EACP,eAAgB,EAChB,YAAa,EACb,UAAW,EACX,QAAS,EACT,QAAS,CACX,GAGI,MAAAC,EAAYhD,EAAM,eAAe+C,CAAO,EACpCC,EAAA,QACVhD,EAAM,MAAM,QAED,UAAApD,KAAS7B,EAAS,OACjBiI,EAAA,gBAAkBpG,EAAM,KAAK,OAC7BoG,EAAA,cACJhD,EAAA,MAAM,gBAAkBpD,EAAM,KAAK,OACzCoD,EAAM,MAAM,cAGd,GAAIjF,EAAS,KAAM,CACX,MAAAkI,IAAapG,EAAA9B,EAAS,OAAT,YAAA8B,EAAe,SAAU,EAC5CmG,EAAU,WAAaC,EACvBjD,EAAM,MAAM,WAAaiD,CAAA,CAGjBD,EAAA,SAAWjI,EAAS,GAAG,OAC3BiF,EAAA,MAAM,SAAWjF,EAAS,GAAG,OAExB,UAAAgE,KAAMhE,EAAS,GAAI,CAC5B,MAAMmI,EAAWnE,EAAG,IAAI,OAASA,EAAG,MAAM,OAC1CiE,EAAU,SAAWE,EACrBlD,EAAM,MAAM,SAAWkD,CAAA,CACzB,CAGK,OAAAlD,CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/value_and_error.ts","../src/accessors.ts","../src/state.ts","../src/sync.ts","../src/snapshot.ts","../src/synchronized_tree.ts","../src/dump.ts"],"sourcesContent":["export interface ValueAndError<T> {\n value?: T;\n error?: T;\n}\n\nexport function mapValueAndErrorIfDefined<T1, T2>(\n input: ValueAndError<T1> | undefined,\n mapping: (v: T1) => T2,\n): ValueAndError<T2> | undefined {\n if (input === undefined) return undefined;\n else return mapValueAndError(input, mapping);\n}\n\nexport function mapValueAndError<T1, T2>(input: ValueAndError<T1>, mapping: (v: T1) => T2) {\n const ret = {} as ValueAndError<T2>;\n if (input.value !== undefined) ret.value = mapping(input.value);\n if (input.error !== undefined) ret.error = mapping(input.error);\n return ret;\n}\n","import type { PlTreeResource, PlTreeState } from './state';\nimport type {\n AccessorProvider,\n ComputableCtx,\n ComputableHooks,\n UsageGuard,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType,\n OptionalResourceId } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n resourceTypesEqual,\n resourceTypeToString,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n NullResourceId,\n} from '@milaboratories/pl-client';\nimport type { ValueAndError } from './value_and_error';\nimport { mapValueAndError } from './value_and_error';\nimport type {\n CommonFieldTraverseOps,\n FieldTraversalStep,\n GetFieldStep,\n ResourceTraversalOps,\n} from './traversal_ops';\nimport type { ValueOrError } from './value_or_error';\nimport { parsePlError } from '@milaboratories/pl-errors';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n/** Error encountered during traversal in field or resource. */\nexport class PlError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport type TreeAccessorData = {\n readonly treeProvider: () => PlTreeState;\n readonly hooks?: ComputableHooks;\n};\n\nexport type TreeAccessorInstanceData = {\n readonly guard: UsageGuard;\n readonly ctx: ComputableCtx;\n};\n\nexport function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'\n );\n}\n\nexport function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'\n );\n}\n\nexport function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'\n );\n}\n\n/** Main entry point for using PlTree in reactive setting */\nexport class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntry';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n public readonly rid: ResourceId,\n ) {}\n\n public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {\n ctx,\n guard,\n });\n }\n\n public toJSON(): string {\n return this.toString();\n }\n\n public toString(): string {\n return `[ENTRY:${resourceIdToString(this.rid)}]`;\n }\n}\n\nfunction getResourceFromTree(\n accessorData: TreeAccessorData,\n tree: PlTreeState,\n instanceData: TreeAccessorInstanceData,\n rid: ResourceId,\n ops: ResourceTraversalOps,\n): PlTreeNodeAccessor {\n const acc = new PlTreeNodeAccessor(\n accessorData,\n tree,\n tree.get(instanceData.ctx.watcher, rid),\n instanceData,\n );\n\n if (!ops.ignoreError) {\n const err = acc.getError();\n if (err !== undefined)\n throw parsePlError(notEmpty(err.getDataAsString()), acc.id, acc.resourceType);\n }\n\n if (\n ops.assertResourceType !== undefined\n && (Array.isArray(ops.assertResourceType)\n ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1\n : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,\n );\n\n return acc;\n}\n\nexport class PlTreeEntryAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntryAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly rid: ResourceId,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {\n this.instanceData.guard();\n\n // this is the only entry point to acquire a PlTreeNodeAccessor,\n // so this is the only point where we should attach the hooks\n if (this.accessorData.hooks !== undefined)\n this.instanceData.ctx.attacheHooks(this.accessorData.hooks);\n\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, this.rid, ops);\n }\n}\n\n/**\n * Helper type to simplify implementation of APIs requiring type information.\n * */\nexport type ResourceInfo = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n};\n\n/**\n * Can be called only when a ctx is provided, because pl tree entry is a computable entity.\n * @deprecated\n * */\nexport function treeEntryToResourceInfo(res: PlTreeEntry | ResourceInfo, ctx: ComputableCtx) {\n if (res instanceof PlTreeEntry) return ctx.accessor(res).node().resourceInfo;\n\n return res;\n}\n\n/**\n * API contracts:\n * - API never return {@link NullResourceId}, absence of link is always modeled as `undefined`\n *\n * Important: never store instances of this class, always get fresh instance from {@link PlTreeState} accessor.\n * */\nexport class PlTreeNodeAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeNodeAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly resource: PlTreeResource,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n public get id(): ResourceId {\n this.instanceData.guard();\n return this.resource.id;\n }\n\n public get originalId(): OptionalResourceId {\n this.instanceData.guard();\n return this.resource.originalResourceId;\n }\n\n public get resourceType(): ResourceType {\n this.instanceData.guard();\n return this.resource.type;\n }\n\n public get resourceInfo(): ResourceInfo {\n return { id: this.id, type: this.resourceType };\n }\n\n private getResourceFromTree(rid: ResourceId, ops: ResourceTraversalOps): PlTreeNodeAccessor {\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, rid, ops);\n }\n\n public traverse(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): PlTreeNodeAccessor;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined {\n return this.traverseWithCommon({}, ...steps);\n }\n\n public traverseOrError(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): ValueOrError<PlTreeNodeAccessor, Error>;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n return this.traverseOrErrorWithCommon({}, ...steps);\n }\n\n public traverseWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): PlTreeNodeAccessor | undefined {\n const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);\n if (result === undefined) return undefined;\n\n if (!result.ok) throw result.error;\n return result.value;\n }\n\n public traverseOrErrorWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: PlTreeNodeAccessor = this;\n\n for (const _step of steps) {\n const step: FieldTraversalStep\n = typeof _step === 'string'\n ? {\n ...commonOptions,\n field: _step,\n }\n : { ...commonOptions, ..._step };\n\n const next = current.getField(_step);\n\n if (next === undefined) return undefined;\n\n if (step.pureFieldErrorToUndefined && next.value === undefined && next.error !== undefined)\n return undefined;\n\n if ((!step.ignoreError || next.value === undefined) && next.error !== undefined)\n return {\n ok: false,\n\n // FIXME: in next tickets we'll allow Errors to be thrown.\n error: parsePlError(\n notEmpty(next.error.getDataAsString()),\n current.id, current.resourceType, step.field,\n ),\n };\n\n if (next.value === undefined) {\n if (step.errorIfFieldNotSet)\n return {\n ok: false,\n error: new Error(`field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`),\n };\n // existing but unpopulated field is unstable because it must be resolved at some point\n this.onUnstableLambda('unpopulated_field:' + step.field);\n return undefined;\n }\n\n current = next.value;\n }\n return { ok: true, value: current };\n }\n\n private readonly onUnstableLambda = (marker: string) => {\n this.instanceData.ctx.markUnstable(marker);\n };\n\n public getField(\n _step:\n | (Omit<GetFieldStep, 'errorIfFieldNotFound'> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, 'errorIfFieldNotSet'> & { errorIfFieldNotSet: true })\n ): ValueAndError<PlTreeNodeAccessor>;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined {\n this.instanceData.guard();\n const step: GetFieldStep = typeof _step === 'string' ? { field: _step } : _step;\n\n const ve = this.resource.getField(this.instanceData.ctx.watcher, step, this.onUnstableLambda);\n\n if (ve === undefined) return undefined;\n\n return mapValueAndError(ve, (rid) => this.getResourceFromTree(rid, { ignoreError: true }));\n }\n\n public getInputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getInputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('inputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getOutputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getOutputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('outputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getIsReadyOrError(): boolean {\n this.instanceData.guard();\n const result = this.resource.getIsReadyOrError(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('not_ready:' + this.resourceType.name);\n return result;\n }\n\n public getIsFinal() {\n this.instanceData.guard();\n return this.resource.getIsFinal(this.instanceData.ctx.watcher);\n }\n\n public getError(): PlTreeNodeAccessor | undefined {\n this.instanceData.guard();\n const rid = this.resource.getError(this.instanceData.ctx.watcher);\n if (rid === undefined)\n // absence of error always considered as stable\n return undefined;\n return this.getResourceFromTree(rid, {});\n }\n\n public getData(): Uint8Array | undefined {\n return this.resource.data;\n }\n\n public getDataAsString(): string | undefined {\n return this.resource.getDataAsString();\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n return this.resource.getDataAsJson<T>();\n }\n\n public listInputFields(): string[] {\n this.instanceData.guard();\n this.getInputsLocked(); // will set unstable if not locked\n return this.resource.listInputFields(this.instanceData.ctx.watcher);\n }\n\n public listOutputFields(): string[] {\n this.instanceData.guard();\n this.getOutputsLocked(); // will set unstable if not locked\n return this.resource.listOutputFields(this.instanceData.ctx.watcher);\n }\n\n public listDynamicFields(): string[] {\n this.instanceData.guard();\n return this.resource.listDynamicFields(this.instanceData.ctx.watcher);\n }\n\n public getKeyValue(key: string, unstableIfNotFound: boolean = false): Uint8Array | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValue(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_b:' + key);\n return result;\n }\n\n /** @deprecated */\n public getKeyValueString(key: string): string | undefined {\n return this.getKeyValueAsString(key);\n }\n\n public getKeyValueAsString(key: string, unstableIfNotFound: boolean = false): string | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_s:' + key);\n return result;\n }\n\n public getKeyValueAsJson<T = unknown>(\n key: string,\n unstableIfNotFound: boolean = false,\n ): T | undefined {\n const result = this.resource.getKeyValueAsJson<T>(this.instanceData.ctx.watcher, key);\n if (result === undefined) {\n if (unstableIfNotFound) this.instanceData.ctx.markUnstable('key_not_found_j:' + key);\n return undefined;\n }\n return result;\n }\n\n /**\n * Can be used to pass a higher level accessor that will wrap the resource and throw its\n * errors on node resolution.\n * */\n public toEntryAccessor(): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.tree, this.id, this.instanceData);\n }\n\n /** Can be passed to nested computable. */\n public persist(): PlTreeEntry {\n return new PlTreeEntry(this.accessorData, this.resource.id);\n }\n}\n","import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalResourceId,\n ResourceData,\n ResourceId,\n ResourceKind,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n isNotNullResourceId,\n isNullResourceId,\n NullResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } 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: OptionalResourceId,\n public error: OptionalResourceId,\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 kvChanged? = new ChangeSource();\n\n readonly id: ResourceId;\n originalResourceId: OptionalResourceId;\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: OptionalResourceId;\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<ResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void\n ): ValueAndError<ResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<ResourceId> | 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<ResourceId>;\n if (isNotNullResourceId(field.value)) ret.value = field.value;\n if (isNotNullResourceId(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 !== NullResourceId\n || this.resourceReady\n || this.originalResourceId !== NullResourceId\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): ResourceId | undefined {\n if (isNullResourceId(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.kvChanged?.attachWatcher(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) as T;\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(`ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`);\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();\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 }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged());\n this.finalChanged?.markChanged();\n this.resourceStateChange?.markChanged();\n this.lockedChange?.markChanged();\n this.inputAndServiceFieldListChanged?.markChanged();\n this.outputFieldListChanged?.markChanged();\n this.dynamicFieldListChanged?.markChanged();\n this.kvChanged?.markChanged();\n this.resourceRemoved.markChanged();\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<ResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = 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 constructor(\n /** This will be the only resource not deleted during GC round */\n public readonly root: ResourceId,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\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 public get(watcher: Watcher, rid: ResourceId): 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: ResourceId[] = [];\n const decrementRefs: ResourceId[] = [];\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 !== NullResourceId)\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 changed = true;\n }\n\n // error\n if (resource.error !== rd.error) {\n if (isNotNullResourceId(resource.error))\n unexpectedTransitionError('resource can\\'t change attached error after it is set');\n resource.error = rd.error;\n incrementRefs.push(resource.error as ResourceId);\n notEmpty(resource.resourceStateChange).markChanged();\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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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 } 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 } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged();\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 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 }\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 }\n field.type = fd.type;\n field.change.markChanged();\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged();\n changed = true;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged();\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged();\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 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 fields.delete(fieldName);\n\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged();\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 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 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 changed = true;\n }\n\n // syncing kv\n let kvChanged = false;\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 kvChanged = true;\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n kvChanged = true;\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)) map.delete(key);\n });\n\n kvChanged = true;\n }\n\n if (kvChanged) notEmpty(resource.kvChanged).markChanged();\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 (isNotNullResourceId(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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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();\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 let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: ResourceId[] = [];\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 && res.id !== this.root) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged();\n });\n if (isNotNullResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged();\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\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 /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = 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.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","import type {\n FieldData,\n OptionalResourceId,\n PlTransaction,\n ResourceId,\n} from '@milaboratories/pl-client';\nimport {\n isNullResourceId,\n} from '@milaboratories/pl-client';\nimport Denque from 'denque';\nimport type { ExtendedResourceData, PlTreeState } from './state';\nimport { msToHumanReadable } from '@milaboratories/ts-helpers';\n\n/** Applied to list of fields in resource data. */\nexport type PruningFunction = (resource: ExtendedResourceData) => FieldData[];\n\nexport interface TreeLoadingRequest {\n /** Resource to prime the traversal algorithm. It is ok, if some of them\n * doesn't exist anymore. Should not contain elements from final resource\n * set. */\n readonly seedResources: ResourceId[];\n\n /** Resource ids for which state is already known and not expected to change.\n * Algorithm will not continue traversal over those ids, and states will not\n * be retrieved for them. */\n readonly finalResources: Set<ResourceId>;\n\n /** This function is applied to each resource data field list, before\n * using it continue traversal. This modification also is applied to\n * output data to make result self-consistent in terms that it will contain\n * all referenced resources, this is required to be able to pass it to tree\n * to update the state. */\n readonly pruningFunction?: PruningFunction;\n}\n\n/** Given the current tree state, build the request object to pass to\n * {@link loadTreeState} to load updated state. */\nexport function constructTreeLoadingRequest(\n tree: PlTreeState,\n pruningFunction?: PruningFunction,\n): TreeLoadingRequest {\n const seedResources: ResourceId[] = [];\n const finalResources = new Set<ResourceId>();\n tree.forEachResource((res) => {\n if (res.finalState) finalResources.add(res.id);\n else seedResources.push(res.id);\n });\n\n // if tree is empty, seeding tree reconstruction from the specified root\n if (seedResources.length === 0 && finalResources.size === 0) seedResources.push(tree.root);\n\n return { seedResources, finalResources, pruningFunction };\n}\n\nexport type TreeLoadingStat = {\n requests: number;\n roundTrips: number;\n retrievedResources: number;\n retrievedFields: number;\n retrievedKeyValues: number;\n retrievedResourceDataBytes: number;\n retrievedKeyValueBytes: number;\n prunedFields: number;\n finalResourcesSkipped: number;\n millisSpent: number;\n};\n\nexport function initialTreeLoadingStat(): TreeLoadingStat {\n return {\n requests: 0,\n roundTrips: 0,\n retrievedResources: 0,\n retrievedFields: 0,\n retrievedKeyValues: 0,\n retrievedResourceDataBytes: 0,\n retrievedKeyValueBytes: 0,\n prunedFields: 0,\n finalResourcesSkipped: 0,\n millisSpent: 0,\n };\n}\n\nexport function formatTreeLoadingStat(stat: TreeLoadingStat): string {\n let result = `Requests: ${stat.requests}\\n`;\n result += `Total time: ${msToHumanReadable(stat.millisSpent)}\\n`;\n result += `Round-trips: ${stat.roundTrips}\\n`;\n result += `Resources: ${stat.retrievedResources}\\n`;\n result += `Fields: ${stat.retrievedFields}\\n`;\n result += `KV: ${stat.retrievedKeyValues}\\n`;\n result += `Data Bytes: ${stat.retrievedResourceDataBytes}\\n`;\n result += `KV Bytes: ${stat.retrievedKeyValueBytes}\\n`;\n result += `Pruned fields: ${stat.prunedFields}\\n`;\n result += `Final resources skipped: ${stat.finalResourcesSkipped}`;\n return result;\n}\n\n/** Given the transaction (preferably read-only) and loading request, executes\n * the tree traversal algorithm, and collects fresh states of resources\n * to update the tree state. */\nexport async function loadTreeState(\n tx: PlTransaction,\n loadingRequest: TreeLoadingRequest,\n stats?: TreeLoadingStat,\n): Promise<ExtendedResourceData[]> {\n // saving start timestamp to add time spent in this function to the stats at the end of the method\n const startTimestamp = Date.now();\n\n // counting the request\n if (stats) stats.requests++;\n\n const { seedResources, finalResources, pruningFunction } = loadingRequest;\n\n // Main idea of using a queue here is that responses will arrive in the same order as they were\n // sent, so we can only wait for the earliest sent unprocessed response promise at any given moment.\n // In such a way logic become linear without recursion, and at the same time deal with data\n // as soon as it arrives.\n\n const pending = new Denque<Promise<ExtendedResourceData | undefined>>();\n\n // vars to calculate number of roundtrips for stats\n let roundTripToggle: boolean = true;\n let numberOfRoundTrips = 0;\n\n // tracking resources we already requested\n const requested = new Set<ResourceId>();\n const requestState = (rid: OptionalResourceId) => {\n if (isNullResourceId(rid) || requested.has(rid)) return;\n\n // separate check to collect stats\n if (finalResources.has(rid)) {\n if (stats) stats.finalResourcesSkipped++;\n return;\n }\n\n // adding the id, so we will not request it's state again if somebody else\n // references the same resource\n requested.add(rid);\n\n // requesting resource and all kv records\n const resourceData = tx.getResourceDataIfExists(rid, true);\n const kvData = tx.listKeyValuesIfResourceExists(rid);\n\n // counting round-trip (begin)\n const addRT = roundTripToggle;\n if (roundTripToggle) roundTripToggle = false;\n\n // pushing combined promise\n pending.push(\n (async () => {\n const [resource, kv] = await Promise.all([resourceData, kvData]);\n\n // counting round-trip, actually incrementing counter and returning toggle back, so the next request can acquire it\n if (addRT) {\n numberOfRoundTrips++;\n roundTripToggle = true;\n }\n\n if (resource === undefined) return undefined;\n\n if (kv === undefined) throw new Error('Inconsistent replies');\n\n return { ...resource, kv };\n })(),\n );\n };\n\n // sending seed requests\n seedResources.forEach((rid) => requestState(rid));\n\n const result: ExtendedResourceData[] = [];\n while (true) {\n // taking next pending request\n const nextResourcePromise = pending.shift();\n if (nextResourcePromise === undefined)\n // this means we have no pending requests and traversal is over\n break;\n\n // at this point we pause and wait for the nest requested resource state to arrive\n let nextResource = await nextResourcePromise;\n if (nextResource === undefined)\n // ignoring resources that were not found (this may happen for seed resource ids)\n continue;\n\n if (pruningFunction !== undefined) {\n // apply field pruning, if requested\n const fieldsAfterPruning = pruningFunction(nextResource);\n // collecting stats\n if (stats) stats.prunedFields += nextResource.fields.length - fieldsAfterPruning.length;\n nextResource = { ...nextResource, fields: fieldsAfterPruning };\n }\n\n // continue traversal over the referenced resource\n requestState(nextResource.error);\n for (const field of nextResource.fields) {\n requestState(field.value);\n requestState(field.error);\n }\n\n // collecting stats\n if (stats) {\n stats.retrievedResources++;\n stats.retrievedFields += nextResource.fields.length;\n stats.retrievedKeyValues += nextResource.kv.length;\n stats.retrievedResourceDataBytes += nextResource.data?.length ?? 0;\n for (const kv of nextResource.kv) stats.retrievedKeyValueBytes += kv.value.length;\n }\n\n // aggregating the state\n result.push(nextResource);\n }\n\n // adding the time we spent in this method to stats\n if (stats) {\n stats.millisSpent += Date.now() - startTimestamp;\n stats.roundTrips += numberOfRoundTrips;\n }\n\n return result;\n}\n","import type { ResourceId, ResourceType } from '@milaboratories/pl-client';\nimport type { Optional, Writable } from 'utility-types';\nimport type { ZodType, z } from 'zod';\nimport type { PlTreeNodeAccessor } from './accessors';\nimport { PlTreeEntry, PlTreeEntryAccessor } from './accessors';\nimport type { ComputableCtx } from '@milaboratories/computable';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n\n/**\n * A DTO that can be generated from a tree node to make a snapshot of specific parts of it's state.\n * Such snapshots can then be used in core that requires this information without the need of\n * retrieving state from the tree.\n */\nexport type ResourceSnapshot<\n Data = undefined,\n Fields extends Record<string, ResourceId | undefined> | undefined = undefined,\n KV extends Record<string, unknown> | undefined = undefined,\n> = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** The most generic type of ResourceSnapshot. */\ntype ResourceSnapshotGeneric = ResourceSnapshot<\n unknown,\n Record<string, ResourceId | undefined> | undefined,\n Record<string, unknown> | undefined\n>;\n\n/** Request that we'll pass to getResourceSnapshot function. We infer the type of ResourceSnapshot from this. */\nexport type ResourceSnapshotSchema<\n Data extends ZodType | 'raw' | undefined = undefined,\n Fields extends Record<string, boolean> | undefined = undefined,\n KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n> = {\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** Creates ResourceSnapshotSchema. It converts an optional schema type to schema type. */\nexport function rsSchema<\n const Data extends ZodType | 'raw' | undefined = undefined,\n const Fields extends Record<string, boolean> | undefined = undefined,\n const KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n>(\n schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>,\n): ResourceSnapshotSchema<Data, Fields, KV> {\n return schema as any;\n}\n\n/** The most generic type of ResourceSnapshotSchema. */\ntype ResourceSnapshotSchemaGeneric = ResourceSnapshotSchema<\n ZodType | 'raw' | undefined,\n Record<string, boolean> | undefined,\n Record<string, ZodType | 'raw'> | undefined\n>;\n\n/**\n * If Data is 'raw' in schema, we'll get bytes,\n * if it's Zod, we'll parse it via zod.\n * Or else we just got undefined in the field.\n */\ntype InferDataType<Data extends ZodType | 'raw' | undefined> = Data extends 'raw'\n ? Uint8Array\n : Data extends ZodType\n ? z.infer<Data>\n : undefined;\n\n/**\n * If Fields is a record of field names to booleans,\n * then if the value of the field is true, we'll require this field and throw a Error if it wasn't found.\n * If it's false and doesn't exist, we'll return undefined.\n * If Fields type is undefined, we won't set fields at all.\n */\ntype InferFieldsType<Fields extends Record<string, boolean> | undefined> = Fields extends undefined\n ? undefined\n : {\n [FieldName in keyof Fields]: Fields[FieldName] extends true\n ? ResourceId\n : ResourceId | undefined;\n };\n\n/**\n * If KV is undefined, won't set it.\n * If one of values is Zod, we'll get KV and converts it to Zod schema.\n * If the value is 'raw', just returns bytes.\n */\ntype InferKVType<KV extends Record<string, ZodType | 'raw'> | undefined> = KV extends undefined\n ? undefined\n : {\n [FieldName in keyof KV]: KV[FieldName] extends ZodType ? z.infer<KV[FieldName]> : Uint8Array;\n };\n\n/** Infer ResourceSnapshot from ResourceShapshotSchema, S can be any ResourceSnapshotSchema. */\nexport type InferSnapshot<S extends ResourceSnapshotSchemaGeneric> = ResourceSnapshot<\n InferDataType<S['data']>,\n InferFieldsType<S['fields']>,\n InferKVType<S['kv']>\n>;\n\n/** Gets a ResourceSnapshot from PlTreeEntry. */\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry,\n schema: Schema,\n ctx: ComputableCtx\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry | PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema,\n ctx?: ComputableCtx,\n): InferSnapshot<Schema> {\n const node\n = res instanceof PlTreeEntry\n ? notEmpty(ctx).accessor(res).node()\n : res instanceof PlTreeEntryAccessor\n ? res.node()\n : res;\n const info = node.resourceInfo;\n const result: Optional<Writable<ResourceSnapshotGeneric>, 'data' | 'fields' | 'kv'> = { ...info };\n\n if (schema.data !== undefined) {\n if (schema.data === 'raw') result.data = node.getData();\n else result.data = schema.data.parse(node.getDataAsJson());\n }\n\n if (schema.fields !== undefined) {\n const fields: Record<string, ResourceId | undefined> = {};\n // even if field is not defined, corresponding object field\n // with \"undefined\" value will still be added\n for (const [fieldName, required] of Object.entries(schema.fields))\n fields[fieldName] = node.traverse({\n field: fieldName,\n errorIfFieldNotSet: required,\n stableIfNotFound: !required,\n })?.id;\n result.fields = fields;\n }\n\n if (schema.kv !== undefined) {\n const kv: Record<string, unknown> = {};\n for (const [fieldName, type] of Object.entries(schema.kv)) {\n const value = node.getKeyValue(fieldName);\n\n if (value === undefined) {\n throw new Error(`Key not found ${fieldName}`);\n } else if (type === 'raw') {\n kv[fieldName] = value;\n } else {\n kv[fieldName] = type.parse(JSON.parse(Buffer.from(value).toString('utf-8')));\n }\n }\n result.kv = kv;\n }\n\n return result as any;\n}\n\n/** @deprecated */\nexport type ResourceWithData = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly fields: Map<string, ResourceId | undefined>;\n readonly data?: Uint8Array;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithData(\n res: PlTreeEntry | ResourceWithData,\n fields: string[],\n ctx: ComputableCtx,\n): ResourceWithData {\n if (res instanceof PlTreeEntry) {\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n\n const fValues: [string, ResourceId | undefined][] = fields.map((name) => [\n name,\n node.getField(name)?.value?.id,\n ]);\n\n return {\n ...info,\n fields: new Map(fValues),\n data: node.getData() ?? new Uint8Array(),\n };\n }\n\n return res;\n}\n\n/** @deprecated */\nexport type ResourceWithMetadata = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly metadata: Record<string, any>;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithMetadata(\n res: PlTreeEntry | ResourceWithMetadata,\n mdKeys: string[],\n ctx: ComputableCtx,\n): ResourceWithMetadata {\n if (!(res instanceof PlTreeEntry)) return res;\n\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n const mdEntries: [string, any][] = mdKeys.map((k) => [k, node.getKeyValue(k)]);\n\n return {\n ...info,\n metadata: Object.fromEntries(mdEntries),\n };\n}\n","import { PollingComputableHooks } from '@milaboratories/computable';\nimport { PlTreeEntry } from './accessors';\nimport type {\n FinalResourceDataPredicate,\n PlClient,\n ResourceId,\n TxOps,\n} from '@milaboratories/pl-client';\nimport {\n isTimeoutOrCancelError,\n} from '@milaboratories/pl-client';\nimport type { ExtendedResourceData } from './state';\nimport { PlTreeState, TreeStateUpdateError } from './state';\nimport type {\n PruningFunction,\n TreeLoadingStat,\n} from './sync';\nimport {\n constructTreeLoadingRequest,\n initialTreeLoadingStat,\n loadTreeState,\n} from './sync';\nimport * as tp from 'node:timers/promises';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\n\ntype StatLoggingMode = 'cumulative' | 'per-request';\n\nexport type SynchronizedTreeOps = {\n /** Override final predicate from the PlClient */\n finalPredicateOverride?: FinalResourceDataPredicate;\n\n /** Pruning function to limit set of fields through which tree will\n * traverse during state synchronization */\n pruning?: PruningFunction;\n\n /** Interval after last sync to sleep before the next one */\n pollingInterval: number;\n /** For how long to continue polling after the last derived value access */\n stopPollingDelay: number;\n\n /** If one of the values, tree will log stats of each polling request */\n logStat?: StatLoggingMode;\n\n /** Timeout for initial tree loading. If not specified, will use default for RO tx from pl-client. */\n initialTreeLoadingTimeout?: number;\n};\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nexport class SynchronizedTreeState {\n private readonly finalPredicate: FinalResourceDataPredicate;\n private state: PlTreeState;\n private readonly pollingInterval: number;\n private readonly pruning?: PruningFunction;\n private readonly logStat?: StatLoggingMode;\n private readonly hooks: PollingComputableHooks;\n private readonly abortController = new AbortController();\n\n private constructor(\n private readonly pl: PlClient,\n private readonly root: ResourceId,\n ops: SynchronizedTreeOps,\n private readonly logger?: MiLogger,\n ) {\n const { finalPredicateOverride, pruning, pollingInterval, stopPollingDelay, logStat } = ops;\n this.pruning = pruning;\n this.pollingInterval = pollingInterval;\n this.finalPredicate = finalPredicateOverride ?? pl.finalPredicate;\n this.logStat = logStat;\n this.state = new PlTreeState(root, this.finalPredicate);\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return new PlTreeEntry({ treeProvider: () => this.state, hooks: this.hooks }, rid);\n }\n\n /** Can be used to externally kick off the synchronization polling loop, and\n * await for the first synchronization to happen. */\n public async refreshState(): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n await this.hooks.refreshState();\n }\n\n private currentLoopDelayInterrupt: AbortController | undefined = undefined;\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n /** Called from computable hooks when external observer asks for state refresh */\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n if (this.terminated) reject(new Error('tree synchronization is terminated'));\n else {\n this.scheduledOnNextState.push({ resolve, reject });\n if (this.currentLoopDelayInterrupt) {\n this.currentLoopDelayInterrupt.abort();\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n /** Called from observer */\n private startUpdating(): void {\n if (this.terminated) return;\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n /** Executed from the main loop, and initialization procedure. */\n private async refresh(stats?: TreeLoadingStat, txOps?: TxOps): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n const request = constructTreeLoadingRequest(this.state, this.pruning);\n const data = await this.pl.withReadTx('ReadingTree', async (tx) => {\n return await loadTreeState(tx, request, stats);\n }, txOps);\n this.state.updateFromResourceData(data, true);\n }\n\n /** If true this tree state is permanently terminaed. */\n private terminated = false;\n\n private async mainLoop() {\n // will hold request stats\n let stat = this.logStat ? initialTreeLoadingStat() : undefined;\n\n let lastUpdate = Date.now();\n\n while (true) {\n if (!this.keepRunning || this.terminated) break;\n\n // saving those who want to be notified about new state here\n // because those who will be added during the tree retrieval\n // should be notified only on the next round\n let toNotify: ScheduledRefresh[] | undefined = undefined;\n if (this.scheduledOnNextState.length > 0) {\n toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n }\n\n try {\n // resetting stats if we were asked to collect non-cumulative stats\n if (this.logStat === 'per-request') stat = initialTreeLoadingStat();\n\n // actual tree synchronization\n await this.refresh(stat);\n\n // logging stats if we were asked to\n if (stat && this.logger) this.logger.info(`Tree stat (success, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we got new state\n if (toNotify !== undefined) for (const n of toNotify) n.resolve();\n } catch (e: any) {\n // logging stats if we were asked to (even if error occured)\n if (stat && this.logger) this.logger.info(`Tree stat (error, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we failed to refresh the state\n if (toNotify !== undefined) for (const n of toNotify) n.reject(e);\n\n // catching tree update errors, as they may leave our tree in inconsistent state\n if (e instanceof TreeStateUpdateError) {\n // important error logging, this should never happen\n this.logger?.error(e);\n\n // marking everybody who used previous state as changed\n this.state.invalidateTree('stat update error');\n // creating new tree\n this.state = new PlTreeState(this.root, this.finalPredicate);\n\n // scheduling state update without delay\n continue;\n\n // unfortunately external observer may still see tree in its default\n // empty state, though this is best we can do in this exceptional\n // situation, and hope on caching layers inside computables to present\n // some stale state until we reconstruct the tree again\n } else this.logger?.warn(e);\n }\n\n if (!this.keepRunning || this.terminated) break;\n\n if (this.scheduledOnNextState.length === 0) {\n try {\n this.currentLoopDelayInterrupt = new AbortController();\n await tp.setTimeout(this.pollingInterval,\n AbortSignal.any([this.abortController.signal, this.currentLoopDelayInterrupt.signal]));\n } catch (e: unknown) {\n if (!isTimeoutOrCancelError(e)) throw new Error('Unexpected error', { cause: e });\n break;\n } finally {\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n // reset only as a very last line\n this.currentLoop = undefined;\n }\n\n /**\n * Dumps the current state of the tree.\n * @returns An array of ExtendedResourceData objects representing the current state of the tree.\n */\n public dumpState(): ExtendedResourceData[] {\n return this.state.dumpState();\n }\n\n /**\n * Terminates the internal loop, and permanently destoys all internal state, so\n * all computables using this state will resolve to errors.\n * */\n public async terminate(): Promise<void> {\n this.keepRunning = false;\n this.terminated = true;\n this.abortController.abort();\n\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n\n this.state.invalidateTree('synchronization terminated for the tree');\n }\n\n /** @deprecated */\n public async awaitSyncLoopTermination(): Promise<void> {\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n }\n\n public static async init(\n pl: PlClient,\n root: ResourceId,\n ops: SynchronizedTreeOps,\n logger?: MiLogger,\n ) {\n const tree = new SynchronizedTreeState(pl, root, ops, logger);\n\n const stat = ops.logStat ? initialTreeLoadingStat() : undefined;\n\n let ok = false;\n\n try {\n await tree.refresh(stat, {\n timeout: ops.initialTreeLoadingTimeout,\n });\n ok = true;\n } finally {\n // logging stats if we were asked to (even if error occured)\n if (stat && logger)\n logger.info(\n `Tree stat (initial load, ${ok ? 'success' : 'failure'}): ${JSON.stringify(stat)}`,\n );\n }\n\n return tree;\n }\n}\n","import type { ExtendedResourceData } from './state';\n\nexport type ResourceStats = {\n /** Number of resources of this type */\n count: number;\n /** Total number of bytes in the field names of all resources of this type */\n fieldNameBytes: number;\n /** Total number of fields in all resources of this type */\n fieldsCount: number;\n /** Total number of bytes in the data of all resources of this type */\n dataBytes: number;\n /** Total number of key-value records in all resources of this type */\n kvCount: number;\n /** Total number of bytes in the key-value records of all resources of this type */\n kvBytes: number;\n};\n\n/**\n * A map of resource type statistics, keyed by the resource type name and version.\n *\n * @type {Record<string, ResourceStats>}\n */\nexport type TreeDumpStats = {\n total: ResourceStats;\n byResourceType: Record<`${string}/${string}`, ResourceStats>;\n};\n\n/**\n * Analyzes a collection of resources and generates statistics grouped by resource type.\n *\n * This function processes an array of ExtendedResourceData and calculates various metrics\n * for each unique resource type, including:\n * - Count of resources\n * - Total bytes in field names\n * - Total number of fields\n * - Total bytes in resource data\n * - Total number of key-value records\n * - Total bytes in key-value records\n *\n * The statistics are organized by resource type using a key in the format \"typeName/version\".\n *\n * @param dumpStats - Array of ExtendedResourceData objects to analyze\n * @returns A DumpStats object containing statistics for each resource type\n * @example\n * ```typescript\n * const resources = [...]; // Array of ExtendedResourceData\n * const stats = treeDumpStats(resources);\n * // stats = {\n * // \"MyResource/1\": {\n * // count: 5,\n * // fieldNameBytes: 150,\n * // fieldsCount: 10,\n * // dataBytes: 1024,\n * // kvCount: 3,\n * // kvBytes: 256\n * // },\n * // ...\n * // }\n * ```\n */\nexport function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {\n const stats: TreeDumpStats = {\n total: {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n },\n byResourceType: {},\n };\n\n for (const resource of dumpStats) {\n const typeKey = `${resource.type.name}/${resource.type.version}` as const;\n if (!stats.byResourceType[typeKey]) {\n stats.byResourceType[typeKey] = {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n };\n }\n\n const typeStats = stats.byResourceType[typeKey];\n typeStats.count++;\n stats.total.count++;\n\n for (const field of resource.fields) {\n typeStats.fieldNameBytes += field.name.length;\n typeStats.fieldsCount++;\n stats.total.fieldNameBytes += field.name.length;\n stats.total.fieldsCount++;\n }\n\n if (resource.data) {\n const dataLength = resource.data?.length ?? 0;\n typeStats.dataBytes += dataLength;\n stats.total.dataBytes += dataLength;\n }\n\n typeStats.kvCount += resource.kv.length;\n stats.total.kvCount += resource.kv.length;\n\n for (const kv of resource.kv) {\n const kvLength = kv.key.length + kv.value.length;\n typeStats.kvBytes += kvLength;\n stats.total.kvBytes += kvLength;\n }\n }\n\n return stats;\n}\n"],"names":["mapValueAndErrorIfDefined","input","mapping","mapValueAndError","ret","PlError","message","isPlTreeEntry","obj","isPlTreeEntryAccessor","isPlTreeNodeAccessor","PlTreeEntry","accessorData","rid","__publicField","ctx","guard","PlTreeEntryAccessor","resourceIdToString","getResourceFromTree","tree","instanceData","ops","acc","PlTreeNodeAccessor","err","parsePlError","notEmpty","rt","resourceTypesEqual","resourceTypeToString","treeEntryToResourceInfo","res","resource","marker","steps","commonOptions","result","current","_step","step","next","ve","key","unstableIfNotFound","TreeStateUpdateError","PlTreeField","name","type","value","error","status","valueIsFinal","resourceVersion","ChangeSource","InitialResourceVersion","PlTreeResource","initialState","logger","msg","watcher","onUnstable","field","_a","_b","_c","isNotNullResourceId","NullResourceId","isNullResourceId","bytes","cachedDecode","cachedDeserialize","stringifyWithResourceId","_d","_e","_f","_g","PlTreeState","root","isFinalPredicate","cb","v","resourceData","allowOrphanInputs","incrementRefs","decrementRefs","rd","statBeforeMutation","unexpectedTransitionError","reason","fields","rdWithoutFields","changed","fd","fieldName","readyStateBefore","kvChanged","kv","newStateKeys","_value","map","currentRefs","nextRefs","constructTreeLoadingRequest","pruningFunction","seedResources","finalResources","initialTreeLoadingStat","formatTreeLoadingStat","stat","msToHumanReadable","loadTreeState","tx","loadingRequest","stats","startTimestamp","pending","Denque","roundTripToggle","numberOfRoundTrips","requested","requestState","kvData","addRT","nextResourcePromise","nextResource","fieldsAfterPruning","rsSchema","schema","makeResourceSnapshot","node","required","treeEntryToResourceWithData","info","fValues","treeEntryToResourceWithMetadata","mdKeys","mdEntries","k","SynchronizedTreeState","pl","finalPredicateOverride","pruning","pollingInterval","stopPollingDelay","logStat","PollingComputableHooks","resolve","reject","txOps","request","data","lastUpdate","toNotify","n","e","tp","isTimeoutOrCancelError","ok","treeDumpStats","dumpStats","typeKey","typeStats","dataLength","kvLength"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/value_and_error.ts","../src/accessors.ts","../src/state.ts","../src/sync.ts","../src/snapshot.ts","../src/synchronized_tree.ts","../src/dump.ts"],"sourcesContent":["export interface ValueAndError<T> {\n value?: T;\n error?: T;\n}\n\nexport function mapValueAndErrorIfDefined<T1, T2>(\n input: ValueAndError<T1> | undefined,\n mapping: (v: T1) => T2,\n): ValueAndError<T2> | undefined {\n if (input === undefined) return undefined;\n else return mapValueAndError(input, mapping);\n}\n\nexport function mapValueAndError<T1, T2>(input: ValueAndError<T1>, mapping: (v: T1) => T2) {\n const ret = {} as ValueAndError<T2>;\n if (input.value !== undefined) ret.value = mapping(input.value);\n if (input.error !== undefined) ret.error = mapping(input.error);\n return ret;\n}\n","import type { PlTreeResource, PlTreeState } from './state';\nimport type {\n AccessorProvider,\n ComputableCtx,\n ComputableHooks,\n UsageGuard,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType,\n OptionalResourceId } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n resourceTypesEqual,\n resourceTypeToString,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n NullResourceId,\n} from '@milaboratories/pl-client';\nimport type { ValueAndError } from './value_and_error';\nimport { mapValueAndError } from './value_and_error';\nimport type {\n CommonFieldTraverseOps,\n FieldTraversalStep,\n GetFieldStep,\n ResourceTraversalOps,\n} from './traversal_ops';\nimport type { ValueOrError } from './value_or_error';\nimport { parsePlError } from '@milaboratories/pl-errors';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n/** Error encountered during traversal in field or resource. */\nexport class PlError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport type TreeAccessorData = {\n readonly treeProvider: () => PlTreeState;\n readonly hooks?: ComputableHooks;\n};\n\nexport type TreeAccessorInstanceData = {\n readonly guard: UsageGuard;\n readonly ctx: ComputableCtx;\n};\n\nexport function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'\n );\n}\n\nexport function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'\n );\n}\n\nexport function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {\n return (\n typeof obj === 'object'\n && obj !== null\n && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'\n );\n}\n\n/** Main entry point for using PlTree in reactive setting */\nexport class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntry';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n public readonly rid: ResourceId,\n ) {}\n\n public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {\n ctx,\n guard,\n });\n }\n\n public toJSON(): string {\n return this.toString();\n }\n\n public toString(): string {\n return `[ENTRY:${resourceIdToString(this.rid)}]`;\n }\n}\n\nfunction getResourceFromTree(\n accessorData: TreeAccessorData,\n tree: PlTreeState,\n instanceData: TreeAccessorInstanceData,\n rid: ResourceId,\n ops: ResourceTraversalOps,\n): PlTreeNodeAccessor {\n const acc = new PlTreeNodeAccessor(\n accessorData,\n tree,\n tree.get(instanceData.ctx.watcher, rid),\n instanceData,\n );\n\n if (!ops.ignoreError) {\n const err = acc.getError();\n if (err !== undefined)\n throw parsePlError(notEmpty(err.getDataAsString()), acc.id, acc.resourceType);\n }\n\n if (\n ops.assertResourceType !== undefined\n && (Array.isArray(ops.assertResourceType)\n ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1\n : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,\n );\n\n return acc;\n}\n\nexport class PlTreeEntryAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeEntryAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly rid: ResourceId,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {\n this.instanceData.guard();\n\n // this is the only entry point to acquire a PlTreeNodeAccessor,\n // so this is the only point where we should attach the hooks\n if (this.accessorData.hooks !== undefined)\n this.instanceData.ctx.attacheHooks(this.accessorData.hooks);\n\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, this.rid, ops);\n }\n}\n\n/**\n * Helper type to simplify implementation of APIs requiring type information.\n * */\nexport type ResourceInfo = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n};\n\n/**\n * Can be called only when a ctx is provided, because pl tree entry is a computable entity.\n * @deprecated\n * */\nexport function treeEntryToResourceInfo(res: PlTreeEntry | ResourceInfo, ctx: ComputableCtx) {\n if (res instanceof PlTreeEntry) return ctx.accessor(res).node().resourceInfo;\n\n return res;\n}\n\n/**\n * API contracts:\n * - API never return {@link NullResourceId}, absence of link is always modeled as `undefined`\n *\n * Important: never store instances of this class, always get fresh instance from {@link PlTreeState} accessor.\n * */\nexport class PlTreeNodeAccessor {\n private readonly __pl_tree_type_marker__ = 'PlTreeNodeAccessor';\n\n constructor(\n private readonly accessorData: TreeAccessorData,\n private readonly tree: PlTreeState,\n private readonly resource: PlTreeResource,\n private readonly instanceData: TreeAccessorInstanceData,\n ) {}\n\n public get id(): ResourceId {\n this.instanceData.guard();\n return this.resource.id;\n }\n\n public get originalId(): OptionalResourceId {\n this.instanceData.guard();\n return this.resource.originalResourceId;\n }\n\n public get resourceType(): ResourceType {\n this.instanceData.guard();\n return this.resource.type;\n }\n\n public get resourceInfo(): ResourceInfo {\n return { id: this.id, type: this.resourceType };\n }\n\n private getResourceFromTree(rid: ResourceId, ops: ResourceTraversalOps): PlTreeNodeAccessor {\n return getResourceFromTree(this.accessorData, this.tree, this.instanceData, rid, ops);\n }\n\n public traverse(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): PlTreeNodeAccessor;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;\n public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined {\n return this.traverseWithCommon({}, ...steps);\n }\n\n public traverseOrError(\n ...steps: [\n Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {\n errorIfFieldNotSet: true;\n },\n ]\n ): ValueOrError<PlTreeNodeAccessor, Error>;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined;\n public traverseOrError(\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n return this.traverseOrErrorWithCommon({}, ...steps);\n }\n\n public traverseWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): PlTreeNodeAccessor | undefined {\n const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);\n if (result === undefined) return undefined;\n\n if (!result.ok) throw result.error;\n return result.value;\n }\n\n public traverseOrErrorWithCommon(\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: PlTreeNodeAccessor = this;\n\n for (const _step of steps) {\n const step: FieldTraversalStep\n = typeof _step === 'string'\n ? {\n ...commonOptions,\n field: _step,\n }\n : { ...commonOptions, ..._step };\n\n const next = current.getField(_step);\n\n if (next === undefined) return undefined;\n\n if (step.pureFieldErrorToUndefined && next.value === undefined && next.error !== undefined)\n return undefined;\n\n if ((!step.ignoreError || next.value === undefined) && next.error !== undefined)\n return {\n ok: false,\n\n // FIXME: in next tickets we'll allow Errors to be thrown.\n error: parsePlError(\n notEmpty(next.error.getDataAsString()),\n current.id, current.resourceType, step.field,\n ),\n };\n\n if (next.value === undefined) {\n if (step.errorIfFieldNotSet)\n return {\n ok: false,\n error: new Error(`field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`),\n };\n // existing but unpopulated field is unstable because it must be resolved at some point\n this.onUnstableLambda('unpopulated_field:' + step.field);\n return undefined;\n }\n\n current = next.value;\n }\n return { ok: true, value: current };\n }\n\n private readonly onUnstableLambda = (marker: string) => {\n this.instanceData.ctx.markUnstable(marker);\n };\n\n public getField(\n _step:\n | (Omit<GetFieldStep, 'errorIfFieldNotFound'> & { errorIfFieldNotFound: true })\n | (Omit<GetFieldStep, 'errorIfFieldNotSet'> & { errorIfFieldNotSet: true })\n ): ValueAndError<PlTreeNodeAccessor>;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined;\n public getField(_step: GetFieldStep | string): ValueAndError<PlTreeNodeAccessor> | undefined {\n this.instanceData.guard();\n const step: GetFieldStep = typeof _step === 'string' ? { field: _step } : _step;\n\n const ve = this.resource.getField(this.instanceData.ctx.watcher, step, this.onUnstableLambda);\n\n if (ve === undefined) return undefined;\n\n return mapValueAndError(ve, (rid) => this.getResourceFromTree(rid, { ignoreError: true }));\n }\n\n public getInputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getInputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('inputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getOutputsLocked(): boolean {\n this.instanceData.guard();\n const result = this.resource.getOutputsLocked(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('outputs_unlocked:' + this.resourceType.name);\n return result;\n }\n\n public getIsReadyOrError(): boolean {\n this.instanceData.guard();\n const result = this.resource.getIsReadyOrError(this.instanceData.ctx.watcher);\n if (!result) this.instanceData.ctx.markUnstable('not_ready:' + this.resourceType.name);\n return result;\n }\n\n public getIsFinal() {\n this.instanceData.guard();\n return this.resource.getIsFinal(this.instanceData.ctx.watcher);\n }\n\n public getError(): PlTreeNodeAccessor | undefined {\n this.instanceData.guard();\n const rid = this.resource.getError(this.instanceData.ctx.watcher);\n if (rid === undefined)\n // absence of error always considered as stable\n return undefined;\n return this.getResourceFromTree(rid, {});\n }\n\n public getData(): Uint8Array | undefined {\n return this.resource.data;\n }\n\n public getDataAsString(): string | undefined {\n return this.resource.getDataAsString();\n }\n\n public getDataAsJson<T = unknown>(): T | undefined {\n return this.resource.getDataAsJson<T>();\n }\n\n public listInputFields(): string[] {\n this.instanceData.guard();\n this.getInputsLocked(); // will set unstable if not locked\n return this.resource.listInputFields(this.instanceData.ctx.watcher);\n }\n\n public listOutputFields(): string[] {\n this.instanceData.guard();\n this.getOutputsLocked(); // will set unstable if not locked\n return this.resource.listOutputFields(this.instanceData.ctx.watcher);\n }\n\n public listDynamicFields(): string[] {\n this.instanceData.guard();\n return this.resource.listDynamicFields(this.instanceData.ctx.watcher);\n }\n\n public getKeyValue(key: string, unstableIfNotFound: boolean = false): Uint8Array | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValue(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_b:' + key);\n return result;\n }\n\n /** @deprecated */\n public getKeyValueString(key: string): string | undefined {\n return this.getKeyValueAsString(key);\n }\n\n public getKeyValueAsString(key: string, unstableIfNotFound: boolean = false): string | undefined {\n this.instanceData.guard();\n const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);\n if (result === undefined && unstableIfNotFound)\n this.instanceData.ctx.markUnstable('key_not_found_s:' + key);\n return result;\n }\n\n public getKeyValueAsJson<T = unknown>(\n key: string,\n unstableIfNotFound: boolean = false,\n ): T | undefined {\n const result = this.resource.getKeyValueAsJson<T>(this.instanceData.ctx.watcher, key);\n if (result === undefined) {\n if (unstableIfNotFound) this.instanceData.ctx.markUnstable('key_not_found_j:' + key);\n return undefined;\n }\n return result;\n }\n\n /**\n * Can be used to pass a higher level accessor that will wrap the resource and throw its\n * errors on node resolution.\n * */\n public toEntryAccessor(): PlTreeEntryAccessor {\n return new PlTreeEntryAccessor(this.accessorData, this.tree, this.id, this.instanceData);\n }\n\n /** Can be passed to nested computable. */\n public persist(): PlTreeEntry {\n return new PlTreeEntry(this.accessorData, this.resource.id);\n }\n}\n","import type {\n BasicResourceData,\n FieldData,\n FieldStatus,\n FieldType,\n KeyValue,\n OptionalResourceId,\n ResourceData,\n ResourceId,\n ResourceKind,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n isNotNullResourceId,\n isNullResourceId,\n NullResourceId,\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } 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: OptionalResourceId,\n public error: OptionalResourceId,\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 kvChanged? = new ChangeSource();\n\n readonly id: ResourceId;\n originalResourceId: OptionalResourceId;\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: OptionalResourceId;\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<ResourceId>;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void\n ): ValueAndError<ResourceId> | undefined;\n public getField(\n watcher: Watcher,\n _step: string | GetFieldStep,\n onUnstable: (marker: string) => void = () => {},\n ): ValueAndError<ResourceId> | 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<ResourceId>;\n if (isNotNullResourceId(field.value)) ret.value = field.value;\n if (isNotNullResourceId(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 !== NullResourceId\n || this.resourceReady\n || this.originalResourceId !== NullResourceId\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): ResourceId | undefined {\n if (isNullResourceId(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.kvChanged?.attachWatcher(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(`ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`);\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();\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 }\n\n /** Used for invalidation */\n markAllChanged() {\n this.fieldsMap.forEach((field) => field.change.markChanged());\n this.finalChanged?.markChanged();\n this.resourceStateChange?.markChanged();\n this.lockedChange?.markChanged();\n this.inputAndServiceFieldListChanged?.markChanged();\n this.outputFieldListChanged?.markChanged();\n this.dynamicFieldListChanged?.markChanged();\n this.kvChanged?.markChanged();\n this.resourceRemoved.markChanged();\n }\n}\n\nexport class PlTreeState {\n /** resource heap */\n private resources: Map<ResourceId, PlTreeResource> = new Map();\n private readonly resourcesAdded = 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 constructor(\n /** This will be the only resource not deleted during GC round */\n public readonly root: ResourceId,\n public readonly isFinalPredicate: FinalResourceDataPredicate,\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 public get(watcher: Watcher, rid: ResourceId): 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: ResourceId[] = [];\n const decrementRefs: ResourceId[] = [];\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 !== NullResourceId)\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 changed = true;\n }\n\n // error\n if (resource.error !== rd.error) {\n if (isNotNullResourceId(resource.error))\n unexpectedTransitionError('resource can\\'t change attached error after it is set');\n resource.error = rd.error;\n incrementRefs.push(resource.error as ResourceId);\n notEmpty(resource.resourceStateChange).markChanged();\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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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 } 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 } else {\n notEmpty(resource.dynamicFieldListChanged).markChanged();\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 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 }\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 }\n field.type = fd.type;\n field.change.markChanged();\n changed = true;\n }\n\n // field value\n if (field.value !== fd.value) {\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n field.value = fd.value;\n if (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n field.change.markChanged();\n changed = true;\n }\n\n // field error\n if (field.error !== fd.error) {\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n field.error = fd.error;\n if (isNotNullResourceId(fd.error)) incrementRefs.push(fd.error);\n field.change.markChanged();\n changed = true;\n }\n\n // field status\n if (field.status !== fd.status) {\n field.status = fd.status;\n field.change.markChanged();\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 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 fields.delete(fieldName);\n\n if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);\n if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);\n\n notEmpty(resource!.dynamicFieldListChanged).markChanged();\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 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 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 changed = true;\n }\n\n // syncing kv\n let kvChanged = false;\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 kvChanged = true;\n } else if (Buffer.compare(current, kv.value) !== 0) {\n resource.kv.set(kv.key, kv.value);\n kvChanged = true;\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)) map.delete(key);\n });\n\n kvChanged = true;\n }\n\n if (kvChanged) notEmpty(resource.kvChanged).markChanged();\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 (isNotNullResourceId(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 (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);\n if (isNotNullResourceId(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();\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 let currentRefs = decrementRefs;\n while (currentRefs.length > 0) {\n const nextRefs: ResourceId[] = [];\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 && res.id !== this.root) {\n // removing fields\n res.fieldsMap.forEach((field) => {\n if (isNotNullResourceId(field.value)) nextRefs.push(field.value);\n if (isNotNullResourceId(field.error)) nextRefs.push(field.error);\n field.change.markChanged();\n });\n if (isNotNullResourceId(res.error)) nextRefs.push(res.error);\n res.resourceRemoved.markChanged();\n this.resources.delete(rid);\n }\n }\n currentRefs = nextRefs;\n }\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 /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n this.checkValid();\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = 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.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","import type {\n FieldData,\n OptionalResourceId,\n PlTransaction,\n ResourceId,\n} from '@milaboratories/pl-client';\nimport {\n isNullResourceId,\n} from '@milaboratories/pl-client';\nimport Denque from 'denque';\nimport type { ExtendedResourceData, PlTreeState } from './state';\nimport { msToHumanReadable } from '@milaboratories/ts-helpers';\n\n/** Applied to list of fields in resource data. */\nexport type PruningFunction = (resource: ExtendedResourceData) => FieldData[];\n\nexport interface TreeLoadingRequest {\n /** Resource to prime the traversal algorithm. It is ok, if some of them\n * doesn't exist anymore. Should not contain elements from final resource\n * set. */\n readonly seedResources: ResourceId[];\n\n /** Resource ids for which state is already known and not expected to change.\n * Algorithm will not continue traversal over those ids, and states will not\n * be retrieved for them. */\n readonly finalResources: Set<ResourceId>;\n\n /** This function is applied to each resource data field list, before\n * using it continue traversal. This modification also is applied to\n * output data to make result self-consistent in terms that it will contain\n * all referenced resources, this is required to be able to pass it to tree\n * to update the state. */\n readonly pruningFunction?: PruningFunction;\n}\n\n/** Given the current tree state, build the request object to pass to\n * {@link loadTreeState} to load updated state. */\nexport function constructTreeLoadingRequest(\n tree: PlTreeState,\n pruningFunction?: PruningFunction,\n): TreeLoadingRequest {\n const seedResources: ResourceId[] = [];\n const finalResources = new Set<ResourceId>();\n tree.forEachResource((res) => {\n if (res.finalState) finalResources.add(res.id);\n else seedResources.push(res.id);\n });\n\n // if tree is empty, seeding tree reconstruction from the specified root\n if (seedResources.length === 0 && finalResources.size === 0) seedResources.push(tree.root);\n\n return { seedResources, finalResources, pruningFunction };\n}\n\nexport type TreeLoadingStat = {\n requests: number;\n roundTrips: number;\n retrievedResources: number;\n retrievedFields: number;\n retrievedKeyValues: number;\n retrievedResourceDataBytes: number;\n retrievedKeyValueBytes: number;\n prunedFields: number;\n finalResourcesSkipped: number;\n millisSpent: number;\n};\n\nexport function initialTreeLoadingStat(): TreeLoadingStat {\n return {\n requests: 0,\n roundTrips: 0,\n retrievedResources: 0,\n retrievedFields: 0,\n retrievedKeyValues: 0,\n retrievedResourceDataBytes: 0,\n retrievedKeyValueBytes: 0,\n prunedFields: 0,\n finalResourcesSkipped: 0,\n millisSpent: 0,\n };\n}\n\nexport function formatTreeLoadingStat(stat: TreeLoadingStat): string {\n let result = `Requests: ${stat.requests}\\n`;\n result += `Total time: ${msToHumanReadable(stat.millisSpent)}\\n`;\n result += `Round-trips: ${stat.roundTrips}\\n`;\n result += `Resources: ${stat.retrievedResources}\\n`;\n result += `Fields: ${stat.retrievedFields}\\n`;\n result += `KV: ${stat.retrievedKeyValues}\\n`;\n result += `Data Bytes: ${stat.retrievedResourceDataBytes}\\n`;\n result += `KV Bytes: ${stat.retrievedKeyValueBytes}\\n`;\n result += `Pruned fields: ${stat.prunedFields}\\n`;\n result += `Final resources skipped: ${stat.finalResourcesSkipped}`;\n return result;\n}\n\n/** Given the transaction (preferably read-only) and loading request, executes\n * the tree traversal algorithm, and collects fresh states of resources\n * to update the tree state. */\nexport async function loadTreeState(\n tx: PlTransaction,\n loadingRequest: TreeLoadingRequest,\n stats?: TreeLoadingStat,\n): Promise<ExtendedResourceData[]> {\n // saving start timestamp to add time spent in this function to the stats at the end of the method\n const startTimestamp = Date.now();\n\n // counting the request\n if (stats) stats.requests++;\n\n const { seedResources, finalResources, pruningFunction } = loadingRequest;\n\n // Main idea of using a queue here is that responses will arrive in the same order as they were\n // sent, so we can only wait for the earliest sent unprocessed response promise at any given moment.\n // In such a way logic become linear without recursion, and at the same time deal with data\n // as soon as it arrives.\n\n const pending = new Denque<Promise<ExtendedResourceData | undefined>>();\n\n // vars to calculate number of roundtrips for stats\n let roundTripToggle: boolean = true;\n let numberOfRoundTrips = 0;\n\n // tracking resources we already requested\n const requested = new Set<ResourceId>();\n const requestState = (rid: OptionalResourceId) => {\n if (isNullResourceId(rid) || requested.has(rid)) return;\n\n // separate check to collect stats\n if (finalResources.has(rid)) {\n if (stats) stats.finalResourcesSkipped++;\n return;\n }\n\n // adding the id, so we will not request it's state again if somebody else\n // references the same resource\n requested.add(rid);\n\n // requesting resource and all kv records\n const resourceData = tx.getResourceDataIfExists(rid, true);\n const kvData = tx.listKeyValuesIfResourceExists(rid);\n\n // counting round-trip (begin)\n const addRT = roundTripToggle;\n if (roundTripToggle) roundTripToggle = false;\n\n // pushing combined promise\n pending.push(\n (async () => {\n const [resource, kv] = await Promise.all([resourceData, kvData]);\n\n // counting round-trip, actually incrementing counter and returning toggle back, so the next request can acquire it\n if (addRT) {\n numberOfRoundTrips++;\n roundTripToggle = true;\n }\n\n if (resource === undefined) return undefined;\n\n if (kv === undefined) throw new Error('Inconsistent replies');\n\n return { ...resource, kv };\n })(),\n );\n };\n\n // sending seed requests\n seedResources.forEach((rid) => requestState(rid));\n\n const result: ExtendedResourceData[] = [];\n while (true) {\n // taking next pending request\n const nextResourcePromise = pending.shift();\n if (nextResourcePromise === undefined)\n // this means we have no pending requests and traversal is over\n break;\n\n // at this point we pause and wait for the nest requested resource state to arrive\n let nextResource = await nextResourcePromise;\n if (nextResource === undefined)\n // ignoring resources that were not found (this may happen for seed resource ids)\n continue;\n\n if (pruningFunction !== undefined) {\n // apply field pruning, if requested\n const fieldsAfterPruning = pruningFunction(nextResource);\n // collecting stats\n if (stats) stats.prunedFields += nextResource.fields.length - fieldsAfterPruning.length;\n nextResource = { ...nextResource, fields: fieldsAfterPruning };\n }\n\n // continue traversal over the referenced resource\n requestState(nextResource.error);\n for (const field of nextResource.fields) {\n requestState(field.value);\n requestState(field.error);\n }\n\n // collecting stats\n if (stats) {\n stats.retrievedResources++;\n stats.retrievedFields += nextResource.fields.length;\n stats.retrievedKeyValues += nextResource.kv.length;\n stats.retrievedResourceDataBytes += nextResource.data?.length ?? 0;\n for (const kv of nextResource.kv) stats.retrievedKeyValueBytes += kv.value.length;\n }\n\n // aggregating the state\n result.push(nextResource);\n }\n\n // adding the time we spent in this method to stats\n if (stats) {\n stats.millisSpent += Date.now() - startTimestamp;\n stats.roundTrips += numberOfRoundTrips;\n }\n\n return result;\n}\n","import type { ResourceId, ResourceType } from '@milaboratories/pl-client';\nimport type { Optional, Writable } from 'utility-types';\nimport type { ZodType, z } from 'zod';\nimport type { PlTreeNodeAccessor } from './accessors';\nimport { PlTreeEntry, PlTreeEntryAccessor } from './accessors';\nimport type { ComputableCtx } from '@milaboratories/computable';\nimport { notEmpty } from '@milaboratories/ts-helpers';\n\n/**\n * A DTO that can be generated from a tree node to make a snapshot of specific parts of it's state.\n * Such snapshots can then be used in core that requires this information without the need of\n * retrieving state from the tree.\n */\nexport type ResourceSnapshot<\n Data = undefined,\n Fields extends Record<string, ResourceId | undefined> | undefined = undefined,\n KV extends Record<string, unknown> | undefined = undefined,\n> = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** The most generic type of ResourceSnapshot. */\ntype ResourceSnapshotGeneric = ResourceSnapshot<\n unknown,\n Record<string, ResourceId | undefined> | undefined,\n Record<string, unknown> | undefined\n>;\n\n/** Request that we'll pass to getResourceSnapshot function. We infer the type of ResourceSnapshot from this. */\nexport type ResourceSnapshotSchema<\n Data extends ZodType | 'raw' | undefined = undefined,\n Fields extends Record<string, boolean> | undefined = undefined,\n KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n> = {\n readonly data: Data;\n readonly fields: Fields;\n readonly kv: KV;\n};\n\n/** Creates ResourceSnapshotSchema. It converts an optional schema type to schema type. */\nexport function rsSchema<\n const Data extends ZodType | 'raw' | undefined = undefined,\n const Fields extends Record<string, boolean> | undefined = undefined,\n const KV extends Record<string, ZodType | 'raw'> | undefined = undefined,\n>(\n schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>,\n): ResourceSnapshotSchema<Data, Fields, KV> {\n return schema as any;\n}\n\n/** The most generic type of ResourceSnapshotSchema. */\ntype ResourceSnapshotSchemaGeneric = ResourceSnapshotSchema<\n ZodType | 'raw' | undefined,\n Record<string, boolean> | undefined,\n Record<string, ZodType | 'raw'> | undefined\n>;\n\n/**\n * If Data is 'raw' in schema, we'll get bytes,\n * if it's Zod, we'll parse it via zod.\n * Or else we just got undefined in the field.\n */\ntype InferDataType<Data extends ZodType | 'raw' | undefined> = Data extends 'raw'\n ? Uint8Array\n : Data extends ZodType\n ? z.infer<Data>\n : undefined;\n\n/**\n * If Fields is a record of field names to booleans,\n * then if the value of the field is true, we'll require this field and throw a Error if it wasn't found.\n * If it's false and doesn't exist, we'll return undefined.\n * If Fields type is undefined, we won't set fields at all.\n */\ntype InferFieldsType<Fields extends Record<string, boolean> | undefined> = Fields extends undefined\n ? undefined\n : {\n [FieldName in keyof Fields]: Fields[FieldName] extends true\n ? ResourceId\n : ResourceId | undefined;\n };\n\n/**\n * If KV is undefined, won't set it.\n * If one of values is Zod, we'll get KV and converts it to Zod schema.\n * If the value is 'raw', just returns bytes.\n */\ntype InferKVType<KV extends Record<string, ZodType | 'raw'> | undefined> = KV extends undefined\n ? undefined\n : {\n [FieldName in keyof KV]: KV[FieldName] extends ZodType ? z.infer<KV[FieldName]> : Uint8Array;\n };\n\n/** Infer ResourceSnapshot from ResourceShapshotSchema, S can be any ResourceSnapshotSchema. */\nexport type InferSnapshot<S extends ResourceSnapshotSchemaGeneric> = ResourceSnapshot<\n InferDataType<S['data']>,\n InferFieldsType<S['fields']>,\n InferKVType<S['kv']>\n>;\n\n/** Gets a ResourceSnapshot from PlTreeEntry. */\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry,\n schema: Schema,\n ctx: ComputableCtx\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema\n): InferSnapshot<Schema>;\nexport function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(\n res: PlTreeEntry | PlTreeEntryAccessor | PlTreeNodeAccessor,\n schema: Schema,\n ctx?: ComputableCtx,\n): InferSnapshot<Schema> {\n const node\n = res instanceof PlTreeEntry\n ? notEmpty(ctx).accessor(res).node()\n : res instanceof PlTreeEntryAccessor\n ? res.node()\n : res;\n const info = node.resourceInfo;\n const result: Optional<Writable<ResourceSnapshotGeneric>, 'data' | 'fields' | 'kv'> = { ...info };\n\n if (schema.data !== undefined) {\n if (schema.data === 'raw') result.data = node.getData();\n else result.data = schema.data.parse(node.getDataAsJson());\n }\n\n if (schema.fields !== undefined) {\n const fields: Record<string, ResourceId | undefined> = {};\n // even if field is not defined, corresponding object field\n // with \"undefined\" value will still be added\n for (const [fieldName, required] of Object.entries(schema.fields))\n fields[fieldName] = node.traverse({\n field: fieldName,\n errorIfFieldNotSet: required,\n stableIfNotFound: !required,\n })?.id;\n result.fields = fields;\n }\n\n if (schema.kv !== undefined) {\n const kv: Record<string, unknown> = {};\n for (const [fieldName, type] of Object.entries(schema.kv)) {\n const value = node.getKeyValue(fieldName);\n\n if (value === undefined) {\n throw new Error(`Key not found ${fieldName}`);\n } else if (type === 'raw') {\n kv[fieldName] = value;\n } else {\n kv[fieldName] = type.parse(JSON.parse(Buffer.from(value).toString('utf-8')));\n }\n }\n result.kv = kv;\n }\n\n return result as any;\n}\n\n/** @deprecated */\nexport type ResourceWithData = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly fields: Map<string, ResourceId | undefined>;\n readonly data?: Uint8Array;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithData(\n res: PlTreeEntry | ResourceWithData,\n fields: string[],\n ctx: ComputableCtx,\n): ResourceWithData {\n if (res instanceof PlTreeEntry) {\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n\n const fValues: [string, ResourceId | undefined][] = fields.map((name) => [\n name,\n node.getField(name)?.value?.id,\n ]);\n\n return {\n ...info,\n fields: new Map(fValues),\n data: node.getData() ?? new Uint8Array(),\n };\n }\n\n return res;\n}\n\n/** @deprecated */\nexport type ResourceWithMetadata = {\n readonly id: ResourceId;\n readonly type: ResourceType;\n readonly metadata: Record<string, any>;\n};\n\n/** @deprecated */\nexport function treeEntryToResourceWithMetadata(\n res: PlTreeEntry | ResourceWithMetadata,\n mdKeys: string[],\n ctx: ComputableCtx,\n): ResourceWithMetadata {\n if (!(res instanceof PlTreeEntry)) return res;\n\n const node = ctx.accessor(res).node();\n const info = node.resourceInfo;\n const mdEntries: [string, any][] = mdKeys.map((k) => [k, node.getKeyValue(k)]);\n\n return {\n ...info,\n metadata: Object.fromEntries(mdEntries),\n };\n}\n","import { PollingComputableHooks } from '@milaboratories/computable';\nimport { PlTreeEntry } from './accessors';\nimport type {\n FinalResourceDataPredicate,\n PlClient,\n ResourceId,\n TxOps,\n} from '@milaboratories/pl-client';\nimport {\n isTimeoutOrCancelError,\n} from '@milaboratories/pl-client';\nimport type { ExtendedResourceData } from './state';\nimport { PlTreeState, TreeStateUpdateError } from './state';\nimport type {\n PruningFunction,\n TreeLoadingStat,\n} from './sync';\nimport {\n constructTreeLoadingRequest,\n initialTreeLoadingStat,\n loadTreeState,\n} from './sync';\nimport * as tp from 'node:timers/promises';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\n\ntype StatLoggingMode = 'cumulative' | 'per-request';\n\nexport type SynchronizedTreeOps = {\n /** Override final predicate from the PlClient */\n finalPredicateOverride?: FinalResourceDataPredicate;\n\n /** Pruning function to limit set of fields through which tree will\n * traverse during state synchronization */\n pruning?: PruningFunction;\n\n /** Interval after last sync to sleep before the next one */\n pollingInterval: number;\n /** For how long to continue polling after the last derived value access */\n stopPollingDelay: number;\n\n /** If one of the values, tree will log stats of each polling request */\n logStat?: StatLoggingMode;\n\n /** Timeout for initial tree loading. If not specified, will use default for RO tx from pl-client. */\n initialTreeLoadingTimeout?: number;\n};\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nexport class SynchronizedTreeState {\n private readonly finalPredicate: FinalResourceDataPredicate;\n private state: PlTreeState;\n private readonly pollingInterval: number;\n private readonly pruning?: PruningFunction;\n private readonly logStat?: StatLoggingMode;\n private readonly hooks: PollingComputableHooks;\n private readonly abortController = new AbortController();\n\n private constructor(\n private readonly pl: PlClient,\n private readonly root: ResourceId,\n ops: SynchronizedTreeOps,\n private readonly logger?: MiLogger,\n ) {\n const { finalPredicateOverride, pruning, pollingInterval, stopPollingDelay, logStat } = ops;\n this.pruning = pruning;\n this.pollingInterval = pollingInterval;\n this.finalPredicate = finalPredicateOverride ?? pl.finalPredicate;\n this.logStat = logStat;\n this.state = new PlTreeState(root, this.finalPredicate);\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n /** @deprecated use \"entry\" instead */\n public accessor(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return this.entry(rid);\n }\n\n public entry(rid: ResourceId = this.root): PlTreeEntry {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n return new PlTreeEntry({ treeProvider: () => this.state, hooks: this.hooks }, rid);\n }\n\n /** Can be used to externally kick off the synchronization polling loop, and\n * await for the first synchronization to happen. */\n public async refreshState(): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n await this.hooks.refreshState();\n }\n\n private currentLoopDelayInterrupt: AbortController | undefined = undefined;\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n /** Called from computable hooks when external observer asks for state refresh */\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n if (this.terminated) reject(new Error('tree synchronization is terminated'));\n else {\n this.scheduledOnNextState.push({ resolve, reject });\n if (this.currentLoopDelayInterrupt) {\n this.currentLoopDelayInterrupt.abort();\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n /** Called from observer */\n private startUpdating(): void {\n if (this.terminated) return;\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n /** Executed from the main loop, and initialization procedure. */\n private async refresh(stats?: TreeLoadingStat, txOps?: TxOps): Promise<void> {\n if (this.terminated) throw new Error('tree synchronization is terminated');\n const request = constructTreeLoadingRequest(this.state, this.pruning);\n const data = await this.pl.withReadTx('ReadingTree', async (tx) => {\n return await loadTreeState(tx, request, stats);\n }, txOps);\n this.state.updateFromResourceData(data, true);\n }\n\n /** If true this tree state is permanently terminaed. */\n private terminated = false;\n\n private async mainLoop() {\n // will hold request stats\n let stat = this.logStat ? initialTreeLoadingStat() : undefined;\n\n let lastUpdate = Date.now();\n\n while (true) {\n if (!this.keepRunning || this.terminated) break;\n\n // saving those who want to be notified about new state here\n // because those who will be added during the tree retrieval\n // should be notified only on the next round\n let toNotify: ScheduledRefresh[] | undefined = undefined;\n if (this.scheduledOnNextState.length > 0) {\n toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n }\n\n try {\n // resetting stats if we were asked to collect non-cumulative stats\n if (this.logStat === 'per-request') stat = initialTreeLoadingStat();\n\n // actual tree synchronization\n await this.refresh(stat);\n\n // logging stats if we were asked to\n if (stat && this.logger) this.logger.info(`Tree stat (success, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we got new state\n if (toNotify !== undefined) for (const n of toNotify) n.resolve();\n } catch (e: any) {\n // logging stats if we were asked to (even if error occured)\n if (stat && this.logger) this.logger.info(`Tree stat (error, after ${Date.now() - lastUpdate}ms): ${JSON.stringify(stat)}`);\n lastUpdate = Date.now();\n\n // notifying that we failed to refresh the state\n if (toNotify !== undefined) for (const n of toNotify) n.reject(e);\n\n // catching tree update errors, as they may leave our tree in inconsistent state\n if (e instanceof TreeStateUpdateError) {\n // important error logging, this should never happen\n this.logger?.error(e);\n\n // marking everybody who used previous state as changed\n this.state.invalidateTree('stat update error');\n // creating new tree\n this.state = new PlTreeState(this.root, this.finalPredicate);\n\n // scheduling state update without delay\n continue;\n\n // unfortunately external observer may still see tree in its default\n // empty state, though this is best we can do in this exceptional\n // situation, and hope on caching layers inside computables to present\n // some stale state until we reconstruct the tree again\n } else this.logger?.warn(e);\n }\n\n if (!this.keepRunning || this.terminated) break;\n\n if (this.scheduledOnNextState.length === 0) {\n try {\n this.currentLoopDelayInterrupt = new AbortController();\n await tp.setTimeout(this.pollingInterval,\n AbortSignal.any([this.abortController.signal, this.currentLoopDelayInterrupt.signal]));\n } catch (e: unknown) {\n if (!isTimeoutOrCancelError(e)) throw new Error('Unexpected error', { cause: e });\n break;\n } finally {\n this.currentLoopDelayInterrupt = undefined;\n }\n }\n }\n\n // reset only as a very last line\n this.currentLoop = undefined;\n }\n\n /**\n * Dumps the current state of the tree.\n * @returns An array of ExtendedResourceData objects representing the current state of the tree.\n */\n public dumpState(): ExtendedResourceData[] {\n return this.state.dumpState();\n }\n\n /**\n * Terminates the internal loop, and permanently destoys all internal state, so\n * all computables using this state will resolve to errors.\n * */\n public async terminate(): Promise<void> {\n this.keepRunning = false;\n this.terminated = true;\n this.abortController.abort();\n\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n\n this.state.invalidateTree('synchronization terminated for the tree');\n }\n\n /** @deprecated */\n public async awaitSyncLoopTermination(): Promise<void> {\n if (this.currentLoop === undefined) return;\n await this.currentLoop;\n }\n\n public static async init(\n pl: PlClient,\n root: ResourceId,\n ops: SynchronizedTreeOps,\n logger?: MiLogger,\n ) {\n const tree = new SynchronizedTreeState(pl, root, ops, logger);\n\n const stat = ops.logStat ? initialTreeLoadingStat() : undefined;\n\n let ok = false;\n\n try {\n await tree.refresh(stat, {\n timeout: ops.initialTreeLoadingTimeout,\n });\n ok = true;\n } finally {\n // logging stats if we were asked to (even if error occured)\n if (stat && logger)\n logger.info(\n `Tree stat (initial load, ${ok ? 'success' : 'failure'}): ${JSON.stringify(stat)}`,\n );\n }\n\n return tree;\n }\n}\n","import type { ExtendedResourceData } from './state';\n\nexport type ResourceStats = {\n /** Number of resources of this type */\n count: number;\n /** Total number of bytes in the field names of all resources of this type */\n fieldNameBytes: number;\n /** Total number of fields in all resources of this type */\n fieldsCount: number;\n /** Total number of bytes in the data of all resources of this type */\n dataBytes: number;\n /** Total number of key-value records in all resources of this type */\n kvCount: number;\n /** Total number of bytes in the key-value records of all resources of this type */\n kvBytes: number;\n};\n\n/**\n * A map of resource type statistics, keyed by the resource type name and version.\n *\n * @type {Record<string, ResourceStats>}\n */\nexport type TreeDumpStats = {\n total: ResourceStats;\n byResourceType: Record<`${string}/${string}`, ResourceStats>;\n};\n\n/**\n * Analyzes a collection of resources and generates statistics grouped by resource type.\n *\n * This function processes an array of ExtendedResourceData and calculates various metrics\n * for each unique resource type, including:\n * - Count of resources\n * - Total bytes in field names\n * - Total number of fields\n * - Total bytes in resource data\n * - Total number of key-value records\n * - Total bytes in key-value records\n *\n * The statistics are organized by resource type using a key in the format \"typeName/version\".\n *\n * @param dumpStats - Array of ExtendedResourceData objects to analyze\n * @returns A DumpStats object containing statistics for each resource type\n * @example\n * ```typescript\n * const resources = [...]; // Array of ExtendedResourceData\n * const stats = treeDumpStats(resources);\n * // stats = {\n * // \"MyResource/1\": {\n * // count: 5,\n * // fieldNameBytes: 150,\n * // fieldsCount: 10,\n * // dataBytes: 1024,\n * // kvCount: 3,\n * // kvBytes: 256\n * // },\n * // ...\n * // }\n * ```\n */\nexport function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {\n const stats: TreeDumpStats = {\n total: {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n },\n byResourceType: {},\n };\n\n for (const resource of dumpStats) {\n const typeKey = `${resource.type.name}/${resource.type.version}` as const;\n if (!stats.byResourceType[typeKey]) {\n stats.byResourceType[typeKey] = {\n count: 0,\n fieldNameBytes: 0,\n fieldsCount: 0,\n dataBytes: 0,\n kvCount: 0,\n kvBytes: 0,\n };\n }\n\n const typeStats = stats.byResourceType[typeKey];\n typeStats.count++;\n stats.total.count++;\n\n for (const field of resource.fields) {\n typeStats.fieldNameBytes += field.name.length;\n typeStats.fieldsCount++;\n stats.total.fieldNameBytes += field.name.length;\n stats.total.fieldsCount++;\n }\n\n if (resource.data) {\n const dataLength = resource.data?.length ?? 0;\n typeStats.dataBytes += dataLength;\n stats.total.dataBytes += dataLength;\n }\n\n typeStats.kvCount += resource.kv.length;\n stats.total.kvCount += resource.kv.length;\n\n for (const kv of resource.kv) {\n const kvLength = kv.key.length + kv.value.length;\n typeStats.kvBytes += kvLength;\n stats.total.kvBytes += kvLength;\n }\n }\n\n return stats;\n}\n"],"names":["mapValueAndErrorIfDefined","input","mapping","mapValueAndError","ret","PlError","message","isPlTreeEntry","obj","isPlTreeEntryAccessor","isPlTreeNodeAccessor","PlTreeEntry","accessorData","rid","__publicField","ctx","guard","PlTreeEntryAccessor","resourceIdToString","getResourceFromTree","tree","instanceData","ops","acc","PlTreeNodeAccessor","err","parsePlError","notEmpty","rt","resourceTypesEqual","resourceTypeToString","treeEntryToResourceInfo","res","resource","marker","steps","commonOptions","result","current","_step","step","next","ve","key","unstableIfNotFound","TreeStateUpdateError","PlTreeField","name","type","value","error","status","valueIsFinal","resourceVersion","ChangeSource","InitialResourceVersion","PlTreeResource","initialState","logger","msg","watcher","onUnstable","field","_a","_b","_c","isNotNullResourceId","NullResourceId","isNullResourceId","bytes","cachedDecode","cachedDeserialize","stringifyWithResourceId","_d","_e","_f","_g","PlTreeState","root","isFinalPredicate","cb","v","resourceData","allowOrphanInputs","incrementRefs","decrementRefs","rd","statBeforeMutation","unexpectedTransitionError","reason","fields","rdWithoutFields","changed","fd","fieldName","readyStateBefore","kvChanged","kv","newStateKeys","_value","map","currentRefs","nextRefs","constructTreeLoadingRequest","pruningFunction","seedResources","finalResources","initialTreeLoadingStat","formatTreeLoadingStat","stat","msToHumanReadable","loadTreeState","tx","loadingRequest","stats","startTimestamp","pending","Denque","roundTripToggle","numberOfRoundTrips","requested","requestState","kvData","addRT","nextResourcePromise","nextResource","fieldsAfterPruning","rsSchema","schema","makeResourceSnapshot","node","required","treeEntryToResourceWithData","info","fValues","treeEntryToResourceWithMetadata","mdKeys","mdEntries","k","SynchronizedTreeState","pl","finalPredicateOverride","pruning","pollingInterval","stopPollingDelay","logStat","PollingComputableHooks","resolve","reject","txOps","request","data","lastUpdate","toNotify","n","e","tp","isTimeoutOrCancelError","ok","treeDumpStats","dumpStats","typeKey","typeStats","dataLength","kvLength"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-tree",
3
- "version": "1.6.11",
3
+ "version": "1.6.12",
4
4
  "description": "Reactive pl tree state",
5
5
  "engines": {
6
6
  "node": ">=20.16.0"
@@ -25,8 +25,8 @@
25
25
  "zod": "~3.23.8",
26
26
  "@milaboratories/computable": "^2.5.1",
27
27
  "@milaboratories/pl-errors": "^1.1.9",
28
- "@milaboratories/ts-helpers": "^1.4.1",
29
28
  "@milaboratories/pl-client": "^2.11.2",
29
+ "@milaboratories/ts-helpers": "^1.4.1",
30
30
  "@milaboratories/pl-error-like": "^1.12.2"
31
31
  },
32
32
  "devDependencies": {
package/src/state.ts CHANGED
@@ -307,7 +307,7 @@ export class PlTreeResource implements ResourceDataWithFinalState {
307
307
  public getKeyValueAsJson<T = unknown>(watcher: Watcher, key: string): T | undefined {
308
308
  const bytes = this.getKeyValue(watcher, key);
309
309
  if (bytes === undefined) return undefined;
310
- return cachedDeserialize(bytes) as T;
310
+ return cachedDeserialize(bytes);
311
311
  }
312
312
 
313
313
  public getDataAsString(): string | undefined {