@milaboratories/pl-client 3.12.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/core/capabilities.cjs.map +1 -1
  2. package/dist/core/capabilities.d.ts +2 -3
  3. package/dist/core/capabilities.d.ts.map +1 -1
  4. package/dist/core/capabilities.js.map +1 -1
  5. package/dist/core/client.cjs +42 -4
  6. package/dist/core/client.cjs.map +1 -1
  7. package/dist/core/client.d.ts +21 -4
  8. package/dist/core/client.d.ts.map +1 -1
  9. package/dist/core/client.js +42 -4
  10. package/dist/core/client.js.map +1 -1
  11. package/dist/core/config.cjs +1 -0
  12. package/dist/core/config.cjs.map +1 -1
  13. package/dist/core/config.d.ts +4 -0
  14. package/dist/core/config.d.ts.map +1 -1
  15. package/dist/core/config.js +1 -0
  16. package/dist/core/config.js.map +1 -1
  17. package/dist/core/errors.cjs +1 -0
  18. package/dist/core/errors.cjs.map +1 -1
  19. package/dist/core/errors.d.ts.map +1 -1
  20. package/dist/core/errors.js +1 -0
  21. package/dist/core/errors.js.map +1 -1
  22. package/dist/core/final.cjs +4 -1
  23. package/dist/core/final.cjs.map +1 -1
  24. package/dist/core/final.d.ts.map +1 -1
  25. package/dist/core/final.js +4 -1
  26. package/dist/core/final.js.map +1 -1
  27. package/dist/core/ll_client.cjs +47 -8
  28. package/dist/core/ll_client.cjs.map +1 -1
  29. package/dist/core/ll_client.d.ts +22 -7
  30. package/dist/core/ll_client.d.ts.map +1 -1
  31. package/dist/core/ll_client.js +48 -9
  32. package/dist/core/ll_client.js.map +1 -1
  33. package/dist/core/transaction.cjs +82 -1
  34. package/dist/core/transaction.cjs.map +1 -1
  35. package/dist/core/transaction.d.ts +52 -2
  36. package/dist/core/transaction.d.ts.map +1 -1
  37. package/dist/core/transaction.js +80 -2
  38. package/dist/core/transaction.js.map +1 -1
  39. package/dist/core/user_resources.cjs +54 -0
  40. package/dist/core/user_resources.cjs.map +1 -1
  41. package/dist/core/user_resources.d.ts +55 -1
  42. package/dist/core/user_resources.d.ts.map +1 -1
  43. package/dist/core/user_resources.js +54 -0
  44. package/dist/core/user_resources.js.map +1 -1
  45. package/dist/index.cjs +3 -0
  46. package/dist/index.d.ts +3 -3
  47. package/dist/index.js +2 -2
  48. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +6 -6
  49. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
  50. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +6 -6
  51. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -1
  52. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +6 -6
  53. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
  54. package/package.json +4 -4
  55. package/src/core/capabilities.ts +10 -3
  56. package/src/core/client.ts +69 -4
  57. package/src/core/config.test.ts +15 -0
  58. package/src/core/config.ts +6 -0
  59. package/src/core/errors.ts +2 -0
  60. package/src/core/final.ts +4 -0
  61. package/src/core/ll_client.test.ts +15 -2
  62. package/src/core/ll_client.ts +59 -9
  63. package/src/core/transaction.ts +103 -3
  64. package/src/core/user_resources.ts +85 -0
  65. package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.js","names":[],"sources":["../../src/core/transaction.ts"],"sourcesContent":["// TODO: fix this\n/* eslint-disable no-prototype-builtins */\nimport type {\n ColorProof,\n LocalResourceId,\n OptionalSignedResourceId,\n BasicResourceData,\n FieldData,\n FieldType,\n ResourceData,\n SignedResourceId,\n ResourceSignature,\n ResourceType,\n FutureFieldType,\n} from \"./types\";\nimport {\n createSignedResourceId,\n createLocalResourceId,\n isLocalResourceId,\n ensureSignedResourceIdNotNull,\n MaxTxId,\n extractBasicResourceData,\n parseSignedResourceId,\n toResourceSignature,\n isSignedResourceId,\n} from \"./types\";\nimport type {\n ClientMessageRequest,\n LLPlTransaction,\n OneOfKind,\n ServerMessageResponse,\n} from \"./ll_transaction\";\nimport type {\n ResourceAPI_Tree_Filter,\n ResourceAPI_Tree_SeedResource,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { TxAPI_Open_Request_WritableTx } from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport type { NonUndefined } from \"utility-types\";\nimport { toBytes } from \"../util/util\";\nimport {\n fieldTypeToProto,\n protoToField,\n protoToResource,\n resourceIsDeleted,\n} from \"./type_conversion\";\nimport {\n canonicalJsonBytes,\n canonicalJsonGzBytes,\n deepFreeze,\n notEmpty,\n} from \"@milaboratories/ts-helpers\";\nimport { isNotFoundError } from \"./errors\";\nimport type { FinalResourceDataPredicate } from \"./final\";\nimport type { LRUCache } from \"lru-cache\";\nimport type { ResourceDataCacheRecord } from \"./cache\";\nimport type { TxStat } from \"./stat\";\nimport { initialTxStatWithoutTime } from \"./stat\";\nimport type { ErrorResourceData } from \"./error_resource\";\nimport { ErrorResourceType } from \"./error_resource\";\nimport { JsonGzObject, JsonObject } from \"../helpers/pl\";\nimport { PromiseTracker } from \"./PromiseTracker\";\n\n/** Reference to resource, used only within transaction */\nexport interface ResourceRef {\n /** Global resource id of newly created resources, become available only\n * after response for the corresponding creation request is received. */\n readonly globalId: Promise<SignedResourceId>;\n\n /** Transaction-local resource id is assigned right after resource creation\n * request is sent, and can be used right away */\n readonly localId: LocalResourceId;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValue {\n key: string;\n value: Uint8Array;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValueString {\n key: string;\n value: string;\n}\n\nexport type ResourceTreeItem = ResourceData & { kv: KeyValue[]; traverseWasStopped: boolean };\n\n/** A single frame from the resourceTree() stream.\n *\n * When the server advertises `treeStopMarker:v1`, a stop-matched node is emitted\n * as a lightweight marker instead of a full resource payload. Callers must\n * narrow on `frameKind` before accessing type-specific fields.\n * Note: `frameKind` is distinct from `ResourceData.kind` (which is the resource kind).\n */\nexport type ResourceTreeFrame =\n | (ResourceTreeItem & { frameKind: \"resource\" })\n | { frameKind: \"stopMarker\"; id: SignedResourceId; traverseWasStopped: true };\n\ninterface _FieldId<RId> {\n /** Parent resource id */\n resourceId: RId;\n /** Field name */\n fieldName: string;\n}\n\nexport type FieldId = _FieldId<SignedResourceId>;\nexport type FieldRef = _FieldId<ResourceRef>;\nexport type LocalFieldId = _FieldId<LocalResourceId>;\nexport type AnyFieldId = FieldId | LocalFieldId;\n\nexport type AnyResourceRef = ResourceRef | LocalResourceId | SignedResourceId;\nexport type AnyFieldRef = _FieldId<AnyResourceRef>; // FieldRef | FieldId\nexport type AnyRef = AnyResourceRef | AnyFieldRef;\n\nexport function isField(ref: AnyRef): ref is AnyFieldRef {\n return ref.hasOwnProperty(\"resourceId\") && ref.hasOwnProperty(\"fieldName\");\n}\n\nexport function isResource(ref: AnyRef): ref is AnyResourceRef {\n if (typeof ref === \"bigint\") return true; // LocalResourceId\n if (typeof ref === \"string\") return true; // SignedResourceId\n return isResourceRef(ref);\n}\n\nexport function isResourceId(ref: AnyRef): ref is SignedResourceId {\n return typeof ref === \"string\" && isSignedResourceId(ref);\n}\n\nexport function isFieldRef(ref: AnyFieldRef): ref is FieldRef {\n return isResourceRef(ref.resourceId);\n}\n\nexport function isResourceRef(ref: AnyRef): ref is ResourceRef {\n return (\n typeof ref === \"object\" &&\n ref !== null &&\n ref.hasOwnProperty(\"globalId\") &&\n ref.hasOwnProperty(\"localId\")\n );\n}\n\nexport function toFieldId(ref: AnyFieldRef): AnyFieldId {\n if (isFieldRef(ref)) return { resourceId: ref.resourceId.localId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport async function toGlobalFieldId(ref: FieldRef | FieldId): Promise<FieldId> {\n if (isFieldRef(ref))\n return { resourceId: await ref.resourceId.globalId, fieldName: ref.fieldName };\n return ref;\n}\n\nexport interface ResourceIdWithSignature {\n resourceId: bigint;\n resourceSignature: ResourceSignature;\n}\n\nconst emptySignature = toResourceSignature(new Uint8Array(0));\n\nfunction toResourceIdAndSignature(ref: AnyResourceRef): ResourceIdWithSignature {\n if (isResourceRef(ref)) {\n // Local ID — no signature yet\n return { resourceId: ref.localId, resourceSignature: emptySignature };\n }\n if (isResourceId(ref)) {\n // SignedResourceId — decompose\n const { globalId, signature } = parseSignedResourceId(ref);\n return { resourceId: globalId as bigint, resourceSignature: signature };\n }\n // Raw bigint (LocalResourceId)\n return { resourceId: ref as bigint, resourceSignature: emptySignature };\n}\n\nexport async function toGlobalResourceId(ref: AnyResourceRef): Promise<SignedResourceId> {\n if (isResourceRef(ref)) return await ref.globalId;\n if (isLocalResourceId(ref)) return createSignedResourceId(ref); // legacy path: loose security mode in backend\n return ref;\n}\n\nexport function field(resourceId: AnyResourceRef, fieldName: string): AnyFieldRef {\n return { resourceId, fieldName };\n}\n\n/** If transaction commit failed due to write conflicts */\nexport class TxCommitConflict extends Error {\n name = \"TxCommitConflict\";\n}\n\nasync function notFoundToUndefined<T>(cb: () => Promise<T>): Promise<T | undefined> {\n try {\n return await cb();\n } catch (e) {\n if (isNotFoundError(e)) return undefined;\n throw e;\n }\n}\n\n/**\n * Each platform transaction has 3 stages:\n * - initialization (txOpen message -> txInfo response)\n * - communication (create resources, fields, references and so on)\n * - finalization (txCommit or txDiscard message)\n *\n * This class encapsulates finalization stage and provides ready-to-communication transaction object.\n * */\nexport class PlTransaction {\n private readonly globalTxId: Promise<bigint>;\n private readonly localTxId: number = PlTransaction.nextLocalTxId();\n\n /** Used in caching */\n private readonly txOpenTimestamp = Date.now();\n\n private localResourceIdCounter = 0;\n\n /** Store logical tx open / closed state to prevent invalid sequence of requests.\n * True means output stream was completed.\n * Contract: there must be no async operations between setting this field to true and sending complete signal to stream. */\n private _completed = false;\n\n private globalTxIdWasAwaited: boolean = false;\n\n public readonly pending = new PromiseTracker();\n\n private readonly _startTime = Date.now();\n private readonly _stat = initialTxStatWithoutTime();\n public get stat(): TxStat {\n return {\n ...this._stat,\n timeMs: Date.now() - this._startTime,\n };\n }\n\n constructor(\n private readonly ll: LLPlTransaction,\n public readonly name: string,\n public readonly writable: boolean,\n private readonly _clientRoot: OptionalSignedResourceId,\n private readonly finalPredicate: FinalResourceDataPredicate,\n private readonly sharedResourceDataCache: LRUCache<SignedResourceId, ResourceDataCacheRecord>,\n private readonly enableFormattedErrors: boolean = false,\n ) {\n // initiating transaction\n this.globalTxId = this.sendSingleAndParse(\n {\n oneofKind: \"txOpen\",\n txOpen: {\n name,\n enableFormattedErrors,\n writable: writable\n ? TxAPI_Open_Request_WritableTx.WRITABLE\n : TxAPI_Open_Request_WritableTx.NOT_WRITABLE,\n },\n },\n (r) => notEmpty(r.txOpen.tx?.id),\n );\n\n void this.track(this.globalTxId);\n\n // To avoid floating promise\n this.globalTxId.catch((err) => {\n if (!this.globalTxIdWasAwaited) {\n console.warn(err);\n }\n });\n\n // Adding stats\n this._stat.txCount++;\n }\n\n /**\n * Collect all pending promises for the transaction finalization.\n */\n public track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n return this.pending.track(promiseOrCallback);\n }\n\n private async drainAndAwaitPendingOps(): Promise<void> {\n // awaiting these pending operations first, to catch any errors\n await this.pending.awaitAll();\n }\n\n private sendSingleAndParse<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, false);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private sendMultiAndParse<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>[]) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, true);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private async sendVoidSync<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): Promise<void> {\n await this.ll.send(r, false);\n }\n\n /** Requests sent with this method should never produce recoverable errors */\n private sendVoidAsync<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): void {\n void this.track(this.sendVoidSync(r));\n }\n\n /** Set default color proof for subsequent resource creation requests */\n public setDefaultColor(colorProof: ColorProof): void {\n this.sendVoidAsync({\n oneofKind: \"setDefaultColor\",\n setDefaultColor: { colorProof },\n });\n }\n\n private toSignedResourceId(rId: AnyResourceRef): ResourceIdWithSignature {\n return toResourceIdAndSignature(rId);\n }\n\n private toSignedFieldId(fId: AnyFieldRef): {\n resourceId: bigint;\n resourceSignature: ResourceSignature;\n fieldName: string;\n } {\n const base = toFieldId(fId);\n const signed = toResourceIdAndSignature(base.resourceId);\n return {\n resourceId: signed.resourceId,\n fieldName: base.fieldName,\n resourceSignature: signed.resourceSignature,\n };\n }\n\n private toSignedErrorRef(rId: AnyResourceRef): {\n errorResourceId: bigint;\n errorResourceSignature: ResourceSignature;\n } {\n const { resourceId, resourceSignature } = this.toSignedResourceId(rId);\n return { errorResourceId: resourceId, errorResourceSignature: resourceSignature };\n }\n\n private checkTxOpen() {\n if (this._completed) throw new Error(\"Transaction already closed\");\n }\n\n public get completed() {\n return this._completed;\n }\n\n /** Commit & closes transaction. {@link TxCommitConflict} is thrown on\n * commit conflicts. */\n public async commit() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n if (!this.writable) {\n // no need to explicitly commit or reject read-only tx\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n await this.ll.await();\n } else {\n const commitResponse = this.track(\n this.sendSingleAndParse({ oneofKind: \"txCommit\", txCommit: {} }, (r) => r.txCommit.success),\n );\n\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n if (!(await commitResponse)) throw new TxCommitConflict();\n\n await completeResult;\n\n // await event-loop completion\n await this.ll.await();\n }\n }\n\n public async discard() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n const discardResponse = this.sendVoidSync({ oneofKind: \"txDiscard\", txDiscard: {} });\n void this.track(discardResponse);\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n await discardResponse;\n await completeResult;\n await this.ll.await();\n }\n\n //\n // Main tx methods\n //\n\n public get clientRoot(): SignedResourceId {\n return ensureSignedResourceIdNotNull(this._clientRoot);\n }\n\n //\n // Resources\n //\n\n public createSingleton(\n name: string,\n type: ResourceType,\n errorIfExists: boolean = false,\n color?: ColorProof,\n ): ResourceRef {\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateSingleton\",\n resourceCreateSingleton: {\n type,\n id: localId,\n data: Buffer.from(name),\n errorIfExists,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateSingleton.resourceId,\n (r) => r.resourceCreateSingleton.resourceSignature,\n );\n }\n\n public getSingleton(name: string, loadFields: true): Promise<ResourceData>;\n public getSingleton(name: string, loadFields: false): Promise<BasicResourceData>;\n public getSingleton(\n name: string,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"resourceGetSingleton\",\n resourceGetSingleton: {\n data: Buffer.from(name),\n loadFields,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGetSingleton.resource)),\n );\n }\n\n private createResource<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n root: boolean,\n req: (localId: LocalResourceId) => OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => bigint,\n sigExtractor: (resp: OneOfKind<ServerMessageResponse, Kind>) => Uint8Array | undefined,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(root);\n\n const globalId = this.sendSingleAndParse(req(localId), (r) => {\n const rawId = parser(r);\n const sig = sigExtractor ? toResourceSignature(sigExtractor(r)) : undefined;\n return createSignedResourceId(rawId, sig);\n });\n\n void this.track(globalId);\n\n return { globalId, localId };\n }\n\n public createRoot(type: ResourceType): ResourceRef {\n this._stat.rootsCreated++;\n return this.createResource(\n true,\n (localId) => ({ oneofKind: \"resourceCreateRoot\", resourceCreateRoot: { type, id: localId } }),\n (r) => r.resourceCreateRoot.resourceId,\n (r) => r.resourceCreateRoot.resourceSignature,\n );\n }\n\n public createStruct(\n type: ResourceType,\n data?: Uint8Array | string,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.structsCreated++;\n this._stat.structsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateStruct\",\n resourceCreateStruct: {\n type,\n id: localId,\n data:\n data === undefined ? undefined : typeof data === \"string\" ? Buffer.from(data) : data,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateStruct.resourceId,\n (r) => r.resourceCreateStruct.resourceSignature,\n );\n }\n\n public createEphemeral(\n type: ResourceType,\n data?: Uint8Array | string,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.ephemeralsCreated++;\n this._stat.ephemeralsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateEphemeral\",\n resourceCreateEphemeral: {\n type,\n id: localId,\n data:\n data === undefined ? undefined : typeof data === \"string\" ? Buffer.from(data) : data,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateEphemeral.resourceId,\n (r) => r.resourceCreateEphemeral.resourceSignature,\n );\n }\n\n public createValue(\n type: ResourceType,\n data: Uint8Array | string,\n errorIfExists: boolean = false,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.valuesCreated++;\n this._stat.valuesCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateValue\",\n resourceCreateValue: {\n type,\n id: localId,\n data: typeof data === \"string\" ? Buffer.from(data) : data,\n errorIfExists,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateValue.resourceId,\n (r) => r.resourceCreateValue.resourceSignature,\n );\n }\n\n public createJsonValue(data: unknown, color?: ColorProof): ResourceRef {\n const jsonData = canonicalJsonBytes(data);\n return this.createValue(JsonObject, jsonData, false, color);\n }\n\n public createJsonGzValue(\n data: unknown,\n minSizeToGzip: number | undefined = 16_384,\n color?: ColorProof,\n ): ResourceRef {\n const { data: jsonData, isGzipped } = canonicalJsonGzBytes(data, minSizeToGzip);\n return this.createValue(isGzipped ? JsonGzObject : JsonObject, jsonData, false, color);\n }\n\n public createError(message: string, color?: ColorProof): ResourceRef {\n return this.createValue(\n ErrorResourceType,\n JSON.stringify({ message } satisfies ErrorResourceData),\n false,\n color,\n );\n }\n\n public setResourceName(name: string, rId: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: \"resourceNameSet\",\n resourceNameSet: { ...this.toSignedResourceId(rId), name },\n });\n }\n\n public deleteResourceName(name: string): void {\n this.sendVoidAsync({ oneofKind: \"resourceNameDelete\", resourceNameDelete: { name } });\n }\n\n public getResourceByName(name: string): Promise<SignedResourceId> {\n return this.sendSingleAndParse(\n { oneofKind: \"resourceNameGet\", resourceNameGet: { name } },\n (r) => {\n const rawId = r.resourceNameGet.resourceId;\n if (rawId === 0n) throw new Error(\"null resource id from getResourceByName\");\n const sig = toResourceSignature(r.resourceNameGet.resourceSignature);\n return createSignedResourceId(rawId, sig);\n },\n );\n }\n\n public checkResourceNameExists(name: string): Promise<boolean> {\n return this.sendSingleAndParse(\n { oneofKind: \"resourceNameExists\", resourceNameExists: { name } },\n (r) => r.resourceNameExists.exists,\n );\n }\n\n public removeResource(rId: SignedResourceId): void {\n this.sendVoidAsync({\n oneofKind: \"resourceRemove\",\n resourceRemove: this.toSignedResourceId(rId),\n });\n }\n\n public resourceExists(rId: SignedResourceId): Promise<boolean> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"resourceExists\",\n resourceExists: this.toSignedResourceId(rId),\n },\n (r) => r.resourceExists.exists,\n );\n }\n\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: true): Promise<ResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: false): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ): Promise<BasicResourceData | ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: true,\n ignoreCache: boolean,\n ): Promise<ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: false,\n ignoreCache: boolean,\n ): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ignoreCache: boolean,\n ): Promise<BasicResourceData | ResourceData>;\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ignoreCache: boolean = false,\n ): Promise<BasicResourceData | ResourceData> {\n return this.track(async () => {\n if (!ignoreCache && isResourceId(rId)) {\n // checking if we can return result from cache\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache && fromCache.cacheTxOpenTimestamp < this.txOpenTimestamp) {\n if (!loadFields) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n return fromCache.basicData;\n } else if (fromCache.data) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n this._stat.rGetDataCacheFields += fromCache.data.fields.length;\n return fromCache.data;\n }\n }\n }\n\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceGet\",\n resourceGet: {\n ...this.toSignedResourceId(rId),\n loadFields: loadFields,\n showSoftDeletes: false,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGet.resource)),\n );\n\n this._stat.rGetDataNetRequests++;\n this._stat.rGetDataNetBytes += result.data?.length ?? 0;\n this._stat.rGetDataNetFields += result.fields.length;\n\n // we will cache only final resource data states\n // caching result even if we were ignore the cache\n if (isResourceId(rId) && this.finalPredicate(result)) {\n deepFreeze(result);\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache) {\n if (loadFields && !fromCache.data) {\n fromCache.data = result;\n // updating timestamp because we updated the record\n fromCache.cacheTxOpenTimestamp = this.txOpenTimestamp;\n }\n } else {\n const basicData = extractBasicResourceData(result);\n deepFreeze(basicData);\n if (loadFields)\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: result,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n else\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: undefined,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n }\n }\n\n return result;\n });\n }\n\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: true,\n ): Promise<ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: false,\n ): Promise<BasicResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean,\n ): Promise<BasicResourceData | ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData | undefined> {\n return this.track(async () => {\n // calling this method will ignore cache, because user intention is to detect resource absence\n // which cache will prevent\n const result = await notFoundToUndefined(\n async () => await this.getResourceData(rId, loadFields, true),\n );\n\n // cleaning cache record if resource was removed from the db\n if (result === undefined && isResourceId(rId)) this.sharedResourceDataCache.delete(rId);\n\n return result;\n });\n }\n\n /**\n * Inform platform that resource will not get any new input fields.\n * This is required, when client creates resource without schema and wants\n * controller to start calculations.\n * Most controllers will not start calculations even when all inputs\n * have their values, if inputs list is not locked.\n */\n public lockInputs(rId: AnyResourceRef): void {\n this._stat.inputsLocked++;\n this.sendVoidAsync({\n oneofKind: \"resourceLockInputs\",\n resourceLockInputs: this.toSignedResourceId(rId),\n });\n }\n\n /**\n * Inform platform that resource will not get any new output fields.\n * This is required for resource to pass deduplication.\n */\n public lockOutputs(rId: AnyResourceRef): void {\n this._stat.outputsLocked++;\n this.sendVoidAsync({\n oneofKind: \"resourceLockOutputs\",\n resourceLockOutputs: this.toSignedResourceId(rId),\n });\n }\n\n public lock(rID: AnyResourceRef): void {\n this.lockInputs(rID);\n this.lockOutputs(rID);\n }\n\n public setResourceError(rId: AnyResourceRef, ref: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: \"resourceSetError\",\n resourceSetError: {\n ...this.toSignedResourceId(rId),\n ...this.toSignedErrorRef(ref),\n },\n });\n }\n\n //\n // Fields\n //\n\n public createField(fId: AnyFieldRef, fieldType: FieldType, value?: AnyRef): void {\n this._stat.fieldsCreated++;\n this.sendVoidAsync({\n oneofKind: \"fieldCreate\",\n fieldCreate: { type: fieldTypeToProto(fieldType), id: this.toSignedFieldId(fId) },\n });\n if (value !== undefined) this.setField(fId, value);\n }\n\n public fieldExists(fId: AnyFieldRef): Promise<boolean> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"fieldExists\",\n fieldExists: { field: this.toSignedFieldId(fId) },\n },\n (r) => r.fieldExists.exists,\n );\n }\n\n public setField(fId: AnyFieldRef, ref: AnyRef): void {\n this._stat.fieldsSet++;\n if (isResource(ref)) {\n this.sendVoidAsync({\n oneofKind: \"fieldSet\",\n fieldSet: {\n field: this.toSignedFieldId(fId),\n value: {\n ...this.toSignedResourceId(ref),\n fieldName: \"\", // default value, read as undefined\n },\n },\n });\n } else {\n this.sendVoidAsync({\n oneofKind: \"fieldSet\",\n fieldSet: {\n field: this.toSignedFieldId(fId),\n value: this.toSignedFieldId(ref),\n },\n });\n }\n }\n\n public setFieldError(fId: AnyFieldRef, ref: AnyResourceRef): void {\n this._stat.fieldsSet++;\n this.sendVoidAsync({\n oneofKind: \"fieldSetError\",\n fieldSetError: {\n field: this.toSignedFieldId(fId),\n ...this.toSignedErrorRef(ref),\n },\n });\n }\n\n public getField(fId: AnyFieldRef): Promise<FieldData> {\n this._stat.fieldsGet++;\n return this.sendSingleAndParse(\n { oneofKind: \"fieldGet\", fieldGet: { field: this.toSignedFieldId(fId) } },\n (r) => protoToField(notEmpty(r.fieldGet.field)),\n );\n }\n\n public async getFieldIfExists(fId: AnyFieldRef): Promise<FieldData | undefined> {\n return this.track(notFoundToUndefined(async () => await this.getField(fId)));\n }\n\n public resetField(fId: AnyFieldRef): void {\n this.sendVoidAsync({\n oneofKind: \"fieldReset\",\n fieldReset: { field: this.toSignedFieldId(fId) },\n });\n }\n\n public removeField(fId: AnyFieldRef): void {\n this.sendVoidAsync({\n oneofKind: \"fieldRemove\",\n fieldRemove: { field: this.toSignedFieldId(fId) },\n });\n }\n\n //\n // KV\n //\n\n public async listKeyValues(rId: AnyResourceRef): Promise<KeyValue[]> {\n return this.track(async () => {\n const result = await this.sendMultiAndParse(\n {\n oneofKind: \"resourceKeyValueList\",\n resourceKeyValueList: {\n ...this.toSignedResourceId(rId),\n startFrom: \"\",\n limit: 0,\n },\n },\n (r) => r.map((e) => e.resourceKeyValueList.record!),\n );\n\n this._stat.kvListRequests++;\n this._stat.kvListEntries += result.length;\n for (const kv of result) this._stat.kvListBytes += kv.key.length + kv.value.length;\n\n return result;\n });\n }\n\n public async listKeyValuesString(rId: AnyResourceRef): Promise<KeyValueString[]> {\n return this.track(async () =>\n (await this.listKeyValues(rId)).map(({ key, value }) => ({\n key,\n value: Buffer.from(value).toString(),\n })),\n );\n }\n\n public async listKeyValuesIfResourceExists(rId: AnyResourceRef): Promise<KeyValue[] | undefined> {\n return this.track(notFoundToUndefined(async () => await this.listKeyValues(rId)));\n }\n\n public async listKeyValuesStringIfResourceExists(\n rId: AnyResourceRef,\n ): Promise<KeyValueString[] | undefined> {\n return this.track(notFoundToUndefined(async () => await this.listKeyValuesString(rId)));\n }\n\n public setKValue(rId: AnyResourceRef, key: string, value: Uint8Array | string): void {\n this._stat.kvSetRequests++;\n this._stat.kvSetBytes++;\n this.sendVoidAsync({\n oneofKind: \"resourceKeyValueSet\",\n resourceKeyValueSet: {\n ...this.toSignedResourceId(rId),\n key,\n value: toBytes(value),\n },\n });\n }\n\n public deleteKValue(rId: AnyResourceRef, key: string): void {\n this.sendVoidAsync({\n oneofKind: \"resourceKeyValueDelete\",\n resourceKeyValueDelete: {\n ...this.toSignedResourceId(rId),\n key,\n },\n });\n }\n\n public async getKValue(rId: AnyResourceRef, key: string): Promise<Uint8Array> {\n return this.track(async () => {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceKeyValueGet\",\n resourceKeyValueGet: {\n ...this.toSignedResourceId(rId),\n key,\n },\n },\n (r) => r.resourceKeyValueGet.value,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result.length;\n\n return result;\n });\n }\n\n public async getKValueString(rId: AnyResourceRef, key: string): Promise<string> {\n return this.track(async () => Buffer.from(await this.getKValue(rId, key)).toString());\n }\n\n public async getKValueJson<T>(rId: AnyResourceRef, key: string): Promise<T> {\n return this.track(async () => JSON.parse(await this.getKValueString(rId, key)) as T);\n }\n\n public async getKValueIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<Uint8Array | undefined> {\n return this.track(async () => {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceKeyValueGetIfExists\",\n resourceKeyValueGetIfExists: {\n ...this.toSignedResourceId(rId),\n key,\n },\n },\n (r) =>\n r.resourceKeyValueGetIfExists.exists ? r.resourceKeyValueGetIfExists.value : undefined,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result?.length ?? 0;\n\n return result;\n });\n }\n\n public async getKValueStringIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<string | undefined> {\n return this.track(async () => {\n const data = await this.getKValueIfExists(rId, key);\n return data === undefined ? undefined : Buffer.from(data).toString();\n });\n }\n\n public async getKValueJsonIfExists<T>(rId: AnyResourceRef, key: string): Promise<T | undefined> {\n return this.track(async () => {\n const str = await this.getKValueStringIfExists(rId, key);\n if (str === undefined) return undefined;\n return JSON.parse(str) as T;\n });\n }\n\n //\n // Cache\n //\n // TODO\n\n //\n // High level ops\n //\n\n /** Resolves existing or create first level resource from */\n public getFutureFieldValue(rId: AnyRef, fieldName: string, fieldType: FutureFieldType): FieldRef {\n const data = Buffer.from(JSON.stringify({ fieldName, fieldType }));\n const getFieldResource = this.createEphemeral({ name: \"json/getField\", version: \"1\" }, data);\n this.setField({ resourceId: getFieldResource, fieldName: \"resource\" }, rId);\n return { resourceId: getFieldResource, fieldName: \"result\" };\n }\n\n //\n // Technical\n //\n\n public async getGlobalTxId() {\n this.globalTxIdWasAwaited = true;\n return await this.globalTxId;\n }\n\n /** Closes output event stream */\n public async complete() {\n if (this._completed) return;\n this._completed = true;\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n }\n\n /** Await incoming message loop termination and throw\n * any leftover errors if it was unsuccessful */\n public async await() {\n await this.ll.await();\n }\n\n //\n // Tree streaming\n //\n\n /**\n * Perform a single `ResourceTree` walk and yield each visited resource.\n *\n * Items are yielded incrementally as stream frames arrive from server.\n *\n * The low-level transaction stream is still ordered, so each active request\n * must be consumed to completion (or closed via iterator `return()`/`throw()`)\n * before later responses can be dispatched.\n *\n * @param seeds - Roots for the traversal. May include both {@link ResourceData}\n * and {@link SignedResourceId} values in the same array.\n * @param opts.fieldFilter - Per-field predicate; matching field edges are not descended.\n * This wire field accepts only one filter. Compose multiple rules via\n * `treeFilter.and(...)` / `treeFilter.or(...)`.\n * @param opts.traverseStopRules - Per-resource predicate; matching resources are returned\n * with `traverseWasStopped = true` and their children are not visited.\n * This wire field accepts only one filter. Compose multiple rules via\n * `treeFilter.and(...)` / `treeFilter.or(...)`.\n * @param opts.includeKv - When true, each yielded item includes KV entries.\n * @param opts.maxDepth - Optional depth cap.\n */\n public resourceTree(\n seeds: (ResourceData | SignedResourceId)[],\n opts?: {\n fieldFilter?: ResourceAPI_Tree_Filter;\n traverseStopRules?: ResourceAPI_Tree_Filter;\n includeKv?: boolean;\n maxDepth?: number;\n },\n ): AsyncIterable<ResourceTreeFrame> {\n if (seeds.length === 0) {\n throw new Error(\"resourceTree: at least one seed must be provided\");\n }\n\n const seedProtos = seeds.map((seed): ResourceAPI_Tree_SeedResource => {\n const signedId = typeof seed === \"string\" ? seed : seed.id;\n const { globalId, signature } = parseSignedResourceId(signedId);\n return { resourceId: globalId, resourceSignature: signature };\n });\n\n const firstSeed = seedProtos[0];\n\n const responseStream = this.ll.sendStream({\n oneofKind: \"resourceTree\",\n resourceTree: {\n // Keep compatibility with request shape that requires non-optional fields.\n resourceId: firstSeed?.resourceId ?? 0n,\n resourceSignature: firstSeed?.resourceSignature ?? new Uint8Array(0),\n seeds: seedProtos,\n fieldFilter: opts?.fieldFilter,\n traverseStopRules: opts?.traverseStopRules,\n includeKv: opts?.includeKv ?? false,\n maxDepth: opts?.maxDepth,\n showSoftDeletes: false,\n },\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ResourceTreeFrame> {\n const iterator = responseStream[Symbol.asyncIterator]();\n\n return {\n async next(): Promise<IteratorResult<ResourceTreeFrame>> {\n while (true) {\n const item = await iterator.next();\n if (item.done) return { value: undefined, done: true };\n\n const frame = item.value.resourceTree;\n if (frame === undefined) continue;\n\n if (frame.resource && resourceIsDeleted(frame.resource)) {\n continue;\n }\n\n if (!frame.resource) {\n // Stop-marker frame: no resource body; server advertised treeStopMarker:v1.\n const id = createSignedResourceId(\n frame.resourceId,\n toResourceSignature(frame.resourceSignature),\n );\n return {\n value: { frameKind: \"stopMarker\", id, traverseWasStopped: true },\n done: false,\n };\n }\n\n return {\n value: {\n frameKind: \"resource\",\n ...protoToResource(frame.resource),\n kv: frame.kv,\n traverseWasStopped: frame.traverseWasStopped,\n },\n done: false,\n };\n }\n },\n async return(): Promise<IteratorResult<ResourceTreeFrame>> {\n if (iterator.return) await iterator.return();\n return { value: undefined, done: true };\n },\n async throw(error?: unknown): Promise<IteratorResult<ResourceTreeFrame>> {\n if (iterator.throw) await iterator.throw(error);\n throw error;\n },\n };\n },\n };\n }\n\n //\n // Helpers\n //\n\n private nextLocalResourceId(root: boolean): LocalResourceId {\n return createLocalResourceId(root, ++this.localResourceIdCounter, this.localTxId);\n }\n\n private static localTxIdCounter = 0;\n\n private static nextLocalTxId() {\n PlTransaction.localTxIdCounter++;\n if (PlTransaction.localTxIdCounter === MaxTxId) PlTransaction.localTxIdCounter = 1;\n return PlTransaction.localTxIdCounter;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transaction.js","names":[],"sources":["../../src/core/transaction.ts"],"sourcesContent":["import type {\n ColorProof,\n LocalResourceId,\n OptionalSignedResourceId,\n BasicResourceData,\n FieldData,\n FieldType,\n ResourceData,\n SignedResourceId,\n ResourceSignature,\n ResourceType,\n FutureFieldType,\n} from \"./types\";\nimport {\n createSignedResourceId,\n createLocalResourceId,\n isLocalResourceId,\n ensureSignedResourceIdNotNull,\n MaxTxId,\n extractBasicResourceData,\n parseSignedResourceId,\n toResourceSignature,\n isSignedResourceId,\n} from \"./types\";\nimport type {\n ClientMessageRequest,\n LLPlTransaction,\n OneOfKind,\n ServerMessageResponse,\n} from \"./ll_transaction\";\nimport type {\n AuthAPI_Grant,\n ResourceAPI_Tree_Filter,\n ResourceAPI_Tree_SeedResource,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport {\n TxAPI_Open_Request_WritableTx,\n AuthAPI_GrantAccess_GrantType,\n AuthAPI_Role,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport type { NonUndefined } from \"utility-types\";\nimport { toBytes } from \"../util/util\";\nimport {\n fieldTypeToProto,\n protoToField,\n protoToResource,\n resourceIsDeleted,\n} from \"./type_conversion\";\nimport {\n canonicalJsonBytes,\n canonicalJsonGzBytes,\n deepFreeze,\n notEmpty,\n} from \"@milaboratories/ts-helpers\";\nimport { isNotFoundError } from \"./errors\";\nimport type { FinalResourceDataPredicate } from \"./final\";\nimport type { LRUCache } from \"lru-cache\";\nimport type { ResourceDataCacheRecord } from \"./cache\";\nimport type { TxStat } from \"./stat\";\nimport { initialTxStatWithoutTime } from \"./stat\";\nimport type { ErrorResourceData } from \"./error_resource\";\nimport { ErrorResourceType } from \"./error_resource\";\nimport { JsonGzObject, JsonObject } from \"../helpers/pl\";\nimport { PromiseTracker } from \"./PromiseTracker\";\n\n/** Reference to resource, used only within transaction */\nexport interface ResourceRef {\n /** Global resource id of newly created resources, become available only\n * after response for the corresponding creation request is received. */\n readonly globalId: Promise<SignedResourceId>;\n\n /** Transaction-local resource id is assigned right after resource creation\n * request is sent, and can be used right away */\n readonly localId: LocalResourceId;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValue {\n key: string;\n value: Uint8Array;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValueString {\n key: string;\n value: string;\n}\n\nexport type ResourceTreeItem = ResourceData & { kv: KeyValue[]; traverseWasStopped: boolean };\n\n/** A single frame from the resourceTree() stream.\n *\n * When the server advertises `treeStopMarker:v1`, a stop-matched node is emitted\n * as a lightweight marker instead of a full resource payload. Callers must\n * narrow on `frameKind` before accessing type-specific fields.\n * Note: `frameKind` is distinct from `ResourceData.kind` (which is the resource kind).\n */\nexport type ResourceTreeFrame =\n | (ResourceTreeItem & { frameKind: \"resource\" })\n | { frameKind: \"stopMarker\"; id: SignedResourceId; traverseWasStopped: true };\n\ninterface _FieldId<RId> {\n /** Parent resource id */\n resourceId: RId;\n /** Field name */\n fieldName: string;\n}\n\nexport type FieldId = _FieldId<SignedResourceId>;\nexport type FieldRef = _FieldId<ResourceRef>;\nexport type LocalFieldId = _FieldId<LocalResourceId>;\nexport type AnyFieldId = FieldId | LocalFieldId;\n\nexport type AnyResourceRef = ResourceRef | LocalResourceId | SignedResourceId;\nexport type AnyFieldRef = _FieldId<AnyResourceRef>; // FieldRef | FieldId\nexport type AnyRef = AnyResourceRef | AnyFieldRef;\n\nexport function isField(ref: AnyRef): ref is AnyFieldRef {\n return ref.hasOwnProperty(\"resourceId\") && ref.hasOwnProperty(\"fieldName\");\n}\n\nexport function isResource(ref: AnyRef): ref is AnyResourceRef {\n if (typeof ref === \"bigint\") return true; // LocalResourceId\n if (typeof ref === \"string\") return true; // SignedResourceId\n return isResourceRef(ref);\n}\n\nexport function isResourceId(ref: AnyRef): ref is SignedResourceId {\n return typeof ref === \"string\" && isSignedResourceId(ref);\n}\n\nexport function isFieldRef(ref: AnyFieldRef): ref is FieldRef {\n return isResourceRef(ref.resourceId);\n}\n\nexport function isResourceRef(ref: AnyRef): ref is ResourceRef {\n return (\n typeof ref === \"object\" &&\n ref !== null &&\n ref.hasOwnProperty(\"globalId\") &&\n ref.hasOwnProperty(\"localId\")\n );\n}\n\nexport function toFieldId(ref: AnyFieldRef): AnyFieldId {\n if (isFieldRef(ref)) return { resourceId: ref.resourceId.localId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport async function toGlobalFieldId(ref: FieldRef | FieldId): Promise<FieldId> {\n if (isFieldRef(ref))\n return { resourceId: await ref.resourceId.globalId, fieldName: ref.fieldName };\n return ref;\n}\n\nexport interface ResourceIdWithSignature {\n resourceId: bigint;\n resourceSignature: ResourceSignature;\n}\n\n/** Access level handed to a grant recipient (see {@link PlTransaction.grantAccess}). */\nexport interface GrantPermissions {\n /** Write access = ability to modify the resource subtree + re-share it. */\n writable: boolean;\n}\n\n/**\n * Distinguishes a regular user-to-user grant from a system-level public grant.\n * Re-export of the wire enum so callers need not reach into the generated proto.\n */\nexport const GrantType = AuthAPI_GrantAccess_GrantType;\nexport type GrantType = AuthAPI_GrantAccess_GrantType;\n\n/**\n * Effective role of an authenticated session (controller / workflow / user / admin).\n * Re-export of the wire enum so callers need not reach into the generated proto.\n * Returned by {@link LLPlClient.getSessionInfo} and surfaced as\n * {@link PlClient.currentUserRole}.\n */\nexport const Role = AuthAPI_Role;\nexport type Role = AuthAPI_Role;\n\n/**\n * Recognises the \"all users on the server\" sentinel login. A public\n * ({@link GrantType.ANY_AUTHORISED}) grant is recorded against a reserved login, and\n * recipients of an everyone-grant surface in `ListGrants` with that value — callers\n * detect it here and map it to \"*\".\n *\n * Matched by exact token equality. The long random token guarantees no real user login\n * collides with it.\n */\nconst EveryoneUser = \"everyone-Po9ahwahxai7Aejingaiyiequuecu3ei4moaNge4xahTh0Co7XeeLeiph6ahy3As\";\nexport function isEveryoneUserLogin(login: string): boolean {\n return login === EveryoneUser;\n}\n\nconst emptySignature = toResourceSignature(new Uint8Array(0));\n\nfunction toResourceIdAndSignature(ref: AnyResourceRef): ResourceIdWithSignature {\n if (isResourceRef(ref)) {\n // Local ID — no signature yet\n return { resourceId: ref.localId, resourceSignature: emptySignature };\n }\n if (isResourceId(ref)) {\n // SignedResourceId — decompose\n const { globalId, signature } = parseSignedResourceId(ref);\n return { resourceId: globalId as bigint, resourceSignature: signature };\n }\n // Raw bigint (LocalResourceId)\n return { resourceId: ref as bigint, resourceSignature: emptySignature };\n}\n\nexport async function toGlobalResourceId(ref: AnyResourceRef): Promise<SignedResourceId> {\n if (isResourceRef(ref)) return await ref.globalId;\n if (isLocalResourceId(ref)) return createSignedResourceId(ref); // legacy path: loose security mode in backend\n return ref;\n}\n\nexport function field(resourceId: AnyResourceRef, fieldName: string): AnyFieldRef {\n return { resourceId, fieldName };\n}\n\n/** If transaction commit failed due to write conflicts */\nexport class TxCommitConflict extends Error {\n name = \"TxCommitConflict\";\n}\n\nasync function notFoundToUndefined<T>(cb: () => Promise<T>): Promise<T | undefined> {\n try {\n return await cb();\n } catch (e) {\n if (isNotFoundError(e)) return undefined;\n throw e;\n }\n}\n\n/**\n * Each platform transaction has 3 stages:\n * - initialization (txOpen message -> txInfo response)\n * - communication (create resources, fields, references and so on)\n * - finalization (txCommit or txDiscard message)\n *\n * This class encapsulates finalization stage and provides ready-to-communication transaction object.\n * */\nexport class PlTransaction {\n private readonly globalTxId: Promise<bigint>;\n private readonly localTxId: number = PlTransaction.nextLocalTxId();\n\n /** Used in caching */\n private readonly txOpenTimestamp = Date.now();\n\n private localResourceIdCounter = 0;\n\n /** Store logical tx open / closed state to prevent invalid sequence of requests.\n * True means output stream was completed.\n * Contract: there must be no async operations between setting this field to true and sending complete signal to stream. */\n private _completed = false;\n\n private globalTxIdWasAwaited: boolean = false;\n\n public readonly pending = new PromiseTracker();\n\n private readonly _startTime = Date.now();\n private readonly _stat = initialTxStatWithoutTime();\n public get stat(): TxStat {\n return {\n ...this._stat,\n timeMs: Date.now() - this._startTime,\n };\n }\n\n constructor(\n private readonly ll: LLPlTransaction,\n public readonly name: string,\n public readonly writable: boolean,\n private readonly _clientRoot: OptionalSignedResourceId,\n private readonly finalPredicate: FinalResourceDataPredicate,\n private readonly sharedResourceDataCache: LRUCache<SignedResourceId, ResourceDataCacheRecord>,\n private readonly enableFormattedErrors: boolean = false,\n ) {\n // initiating transaction\n this.globalTxId = this.sendSingleAndParse(\n {\n oneofKind: \"txOpen\",\n txOpen: {\n name,\n enableFormattedErrors,\n writable: writable\n ? TxAPI_Open_Request_WritableTx.WRITABLE\n : TxAPI_Open_Request_WritableTx.NOT_WRITABLE,\n },\n },\n (r) => notEmpty(r.txOpen.tx?.id),\n );\n\n void this.track(this.globalTxId);\n\n // To avoid floating promise\n this.globalTxId.catch((err) => {\n if (!this.globalTxIdWasAwaited) {\n console.warn(err);\n }\n });\n\n // Adding stats\n this._stat.txCount++;\n }\n\n /**\n * Collect all pending promises for the transaction finalization.\n */\n public track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n return this.pending.track(promiseOrCallback);\n }\n\n private async drainAndAwaitPendingOps(): Promise<void> {\n // awaiting these pending operations first, to catch any errors\n await this.pending.awaitAll();\n }\n\n private sendSingleAndParse<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, false);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private sendMultiAndParse<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>[]) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, true);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private async sendVoidSync<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): Promise<void> {\n await this.ll.send(r, false);\n }\n\n /** Requests sent with this method should never produce recoverable errors */\n private sendVoidAsync<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): void {\n void this.track(this.sendVoidSync(r));\n }\n\n /** Set default color proof for subsequent resource creation requests */\n public setDefaultColor(colorProof: ColorProof): void {\n this.sendVoidAsync({\n oneofKind: \"setDefaultColor\",\n setDefaultColor: { colorProof },\n });\n }\n\n private toSignedResourceId(rId: AnyResourceRef): ResourceIdWithSignature {\n return toResourceIdAndSignature(rId);\n }\n\n private toSignedFieldId(fId: AnyFieldRef): {\n resourceId: bigint;\n resourceSignature: ResourceSignature;\n fieldName: string;\n } {\n const base = toFieldId(fId);\n const signed = toResourceIdAndSignature(base.resourceId);\n return {\n resourceId: signed.resourceId,\n fieldName: base.fieldName,\n resourceSignature: signed.resourceSignature,\n };\n }\n\n private toSignedErrorRef(rId: AnyResourceRef): {\n errorResourceId: bigint;\n errorResourceSignature: ResourceSignature;\n } {\n const { resourceId, resourceSignature } = this.toSignedResourceId(rId);\n return { errorResourceId: resourceId, errorResourceSignature: resourceSignature };\n }\n\n private checkTxOpen() {\n if (this._completed) throw new Error(\"Transaction already closed\");\n }\n\n public get completed() {\n return this._completed;\n }\n\n /** Commit & closes transaction. {@link TxCommitConflict} is thrown on\n * commit conflicts. */\n public async commit() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n if (!this.writable) {\n // no need to explicitly commit or reject read-only tx\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n await this.ll.await();\n } else {\n const commitResponse = this.track(\n this.sendSingleAndParse({ oneofKind: \"txCommit\", txCommit: {} }, (r) => r.txCommit.success),\n );\n\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n if (!(await commitResponse)) throw new TxCommitConflict();\n\n await completeResult;\n\n // await event-loop completion\n await this.ll.await();\n }\n }\n\n public async discard() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n const discardResponse = this.sendVoidSync({ oneofKind: \"txDiscard\", txDiscard: {} });\n void this.track(discardResponse);\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n await discardResponse;\n await completeResult;\n await this.ll.await();\n }\n\n //\n // Main tx methods\n //\n\n public get clientRoot(): SignedResourceId {\n return ensureSignedResourceIdNotNull(this._clientRoot);\n }\n\n //\n // Resources\n //\n\n public createSingleton(\n name: string,\n type: ResourceType,\n errorIfExists: boolean = false,\n color?: ColorProof,\n ): ResourceRef {\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateSingleton\",\n resourceCreateSingleton: {\n type,\n id: localId,\n data: Buffer.from(name),\n errorIfExists,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateSingleton.resourceId,\n (r) => r.resourceCreateSingleton.resourceSignature,\n );\n }\n\n public getSingleton(name: string, loadFields: true): Promise<ResourceData>;\n public getSingleton(name: string, loadFields: false): Promise<BasicResourceData>;\n public getSingleton(\n name: string,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"resourceGetSingleton\",\n resourceGetSingleton: {\n data: Buffer.from(name),\n loadFields,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGetSingleton.resource)),\n );\n }\n\n private createResource<Kind extends NonUndefined<ClientMessageRequest[\"oneofKind\"]>>(\n root: boolean,\n req: (localId: LocalResourceId) => OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => bigint,\n sigExtractor: (resp: OneOfKind<ServerMessageResponse, Kind>) => Uint8Array | undefined,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(root);\n\n const globalId = this.sendSingleAndParse(req(localId), (r) => {\n const rawId = parser(r);\n const sig = sigExtractor ? toResourceSignature(sigExtractor(r)) : undefined;\n return createSignedResourceId(rawId, sig);\n });\n\n void this.track(globalId);\n\n return { globalId, localId };\n }\n\n public createRoot(type: ResourceType): ResourceRef {\n this._stat.rootsCreated++;\n return this.createResource(\n true,\n (localId) => ({ oneofKind: \"resourceCreateRoot\", resourceCreateRoot: { type, id: localId } }),\n (r) => r.resourceCreateRoot.resourceId,\n (r) => r.resourceCreateRoot.resourceSignature,\n );\n }\n\n public createStruct(\n type: ResourceType,\n data?: Uint8Array | string,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.structsCreated++;\n this._stat.structsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateStruct\",\n resourceCreateStruct: {\n type,\n id: localId,\n data:\n data === undefined ? undefined : typeof data === \"string\" ? Buffer.from(data) : data,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateStruct.resourceId,\n (r) => r.resourceCreateStruct.resourceSignature,\n );\n }\n\n public createEphemeral(\n type: ResourceType,\n data?: Uint8Array | string,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.ephemeralsCreated++;\n this._stat.ephemeralsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateEphemeral\",\n resourceCreateEphemeral: {\n type,\n id: localId,\n data:\n data === undefined ? undefined : typeof data === \"string\" ? Buffer.from(data) : data,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateEphemeral.resourceId,\n (r) => r.resourceCreateEphemeral.resourceSignature,\n );\n }\n\n public createValue(\n type: ResourceType,\n data: Uint8Array | string,\n errorIfExists: boolean = false,\n color?: ColorProof,\n ): ResourceRef {\n this._stat.valuesCreated++;\n this._stat.valuesCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: \"resourceCreateValue\",\n resourceCreateValue: {\n type,\n id: localId,\n data: typeof data === \"string\" ? Buffer.from(data) : data,\n errorIfExists,\n colorProof: color ?? emptySignature,\n },\n }),\n (r) => r.resourceCreateValue.resourceId,\n (r) => r.resourceCreateValue.resourceSignature,\n );\n }\n\n public createJsonValue(data: unknown, color?: ColorProof): ResourceRef {\n const jsonData = canonicalJsonBytes(data);\n return this.createValue(JsonObject, jsonData, false, color);\n }\n\n public createJsonGzValue(\n data: unknown,\n minSizeToGzip: number | undefined = 16_384,\n color?: ColorProof,\n ): ResourceRef {\n const { data: jsonData, isGzipped } = canonicalJsonGzBytes(data, minSizeToGzip);\n return this.createValue(isGzipped ? JsonGzObject : JsonObject, jsonData, false, color);\n }\n\n public createError(message: string, color?: ColorProof): ResourceRef {\n return this.createValue(\n ErrorResourceType,\n JSON.stringify({ message } satisfies ErrorResourceData),\n false,\n color,\n );\n }\n\n public setResourceName(name: string, rId: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: \"resourceNameSet\",\n resourceNameSet: { ...this.toSignedResourceId(rId), name },\n });\n }\n\n public deleteResourceName(name: string): void {\n this.sendVoidAsync({ oneofKind: \"resourceNameDelete\", resourceNameDelete: { name } });\n }\n\n public getResourceByName(name: string): Promise<SignedResourceId> {\n return this.sendSingleAndParse(\n { oneofKind: \"resourceNameGet\", resourceNameGet: { name } },\n (r) => {\n const rawId = r.resourceNameGet.resourceId;\n if (rawId === 0n) throw new Error(\"null resource id from getResourceByName\");\n const sig = toResourceSignature(r.resourceNameGet.resourceSignature);\n return createSignedResourceId(rawId, sig);\n },\n );\n }\n\n public checkResourceNameExists(name: string): Promise<boolean> {\n return this.sendSingleAndParse(\n { oneofKind: \"resourceNameExists\", resourceNameExists: { name } },\n (r) => r.resourceNameExists.exists,\n );\n }\n\n public removeResource(rId: SignedResourceId): void {\n this.sendVoidAsync({\n oneofKind: \"resourceRemove\",\n resourceRemove: this.toSignedResourceId(rId),\n });\n }\n\n public resourceExists(rId: SignedResourceId): Promise<boolean> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"resourceExists\",\n resourceExists: this.toSignedResourceId(rId),\n },\n (r) => r.resourceExists.exists,\n );\n }\n\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: true): Promise<ResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: false): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ): Promise<BasicResourceData | ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: true,\n ignoreCache: boolean,\n ): Promise<ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: false,\n ignoreCache: boolean,\n ): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ignoreCache: boolean,\n ): Promise<BasicResourceData | ResourceData>;\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ignoreCache: boolean = false,\n ): Promise<BasicResourceData | ResourceData> {\n return this.track(async () => {\n if (!ignoreCache && isResourceId(rId)) {\n // checking if we can return result from cache\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache && fromCache.cacheTxOpenTimestamp < this.txOpenTimestamp) {\n if (!loadFields) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n return fromCache.basicData;\n } else if (fromCache.data) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n this._stat.rGetDataCacheFields += fromCache.data.fields.length;\n return fromCache.data;\n }\n }\n }\n\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceGet\",\n resourceGet: {\n ...this.toSignedResourceId(rId),\n loadFields: loadFields,\n showSoftDeletes: false,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGet.resource)),\n );\n\n this._stat.rGetDataNetRequests++;\n this._stat.rGetDataNetBytes += result.data?.length ?? 0;\n this._stat.rGetDataNetFields += result.fields.length;\n\n // we will cache only final resource data states\n // caching result even if we were ignore the cache\n if (isResourceId(rId) && this.finalPredicate(result)) {\n deepFreeze(result);\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache) {\n if (loadFields && !fromCache.data) {\n fromCache.data = result;\n // updating timestamp because we updated the record\n fromCache.cacheTxOpenTimestamp = this.txOpenTimestamp;\n }\n } else {\n const basicData = extractBasicResourceData(result);\n deepFreeze(basicData);\n if (loadFields)\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: result,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n else\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: undefined,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n }\n }\n\n return result;\n });\n }\n\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: true,\n ): Promise<ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: false,\n ): Promise<BasicResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean,\n ): Promise<BasicResourceData | ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData | undefined> {\n return this.track(async () => {\n // calling this method will ignore cache, because user intention is to detect resource absence\n // which cache will prevent\n const result = await notFoundToUndefined(\n async () => await this.getResourceData(rId, loadFields, true),\n );\n\n // cleaning cache record if resource was removed from the db\n if (result === undefined && isResourceId(rId)) this.sharedResourceDataCache.delete(rId);\n\n return result;\n });\n }\n\n /**\n * Inform platform that resource will not get any new input fields.\n * This is required, when client creates resource without schema and wants\n * controller to start calculations.\n * Most controllers will not start calculations even when all inputs\n * have their values, if inputs list is not locked.\n */\n public lockInputs(rId: AnyResourceRef): void {\n this._stat.inputsLocked++;\n this.sendVoidAsync({\n oneofKind: \"resourceLockInputs\",\n resourceLockInputs: this.toSignedResourceId(rId),\n });\n }\n\n /**\n * Inform platform that resource will not get any new output fields.\n * This is required for resource to pass deduplication.\n */\n public lockOutputs(rId: AnyResourceRef): void {\n this._stat.outputsLocked++;\n this.sendVoidAsync({\n oneofKind: \"resourceLockOutputs\",\n resourceLockOutputs: this.toSignedResourceId(rId),\n });\n }\n\n public lock(rID: AnyResourceRef): void {\n this.lockInputs(rID);\n this.lockOutputs(rID);\n }\n\n public setResourceError(rId: AnyResourceRef, ref: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: \"resourceSetError\",\n resourceSetError: {\n ...this.toSignedResourceId(rId),\n ...this.toSignedErrorRef(ref),\n },\n });\n }\n\n /**\n * Grant another user access to a resource (and its subtree). Used by the\n * project-sharing donor flow to hand a recipient the shared envelope.\n *\n * `grantType` defaults to a regular user-to-user grant\n * ({@link GrantType.SINGLE_USER}); pass {@link GrantType.ANY_AUTHORISED}\n * to make the resource public to everyone (requires backend `publicGrants:v1`\n * and a role allowed to grant to everyone — `target` is ignored / rewritten\n * to the everyone-user by the backend).\n */\n public grantAccess(\n rId: AnyResourceRef,\n target: string,\n permissions: GrantPermissions,\n grantType: GrantType = AuthAPI_GrantAccess_GrantType.SINGLE_USER,\n ): void {\n this.sendVoidAsync({\n oneofKind: \"grantAccess\",\n grantAccess: {\n ...this.toSignedResourceId(rId),\n targetUser: target,\n permissions,\n grantType,\n },\n });\n }\n\n /**\n * Revoke a single user's grant on a resource — the inverse of {@link grantAccess}.\n * Used by the sharing donor flow to pull one recipient out of a multi-recipient\n * envelope without tearing the whole share down. A no-op on the backend if the user\n * has no grant.\n */\n public revokeAccess(rId: AnyResourceRef, target: string): void {\n this.sendVoidAsync({\n oneofKind: \"revokeAccess\",\n revokeAccess: {\n ...this.toSignedResourceId(rId),\n targetUser: target,\n },\n });\n }\n\n /**\n * Enumerate the grants of a resource — the donor-side \"who did I share with\" view.\n * The backend gates this on the signed, writable resource handle, so only the\n * resource's owner can read its grants. Recipients of a public\n * ({@link GrantType.ANY_AUTHORISED}) grant surface with `user` matching the\n * everyone-sentinel — test with {@link isEveryoneUserLogin}.\n *\n * Transactional unary op (single response with all grants), so it rides the tx\n * channel and works on every wire protocol — unlike the standalone server-streaming\n * `ListGrants` RPC, which has no REST binding.\n */\n public listGrants(rId: AnyResourceRef): Promise<AuthAPI_Grant[]> {\n return this.sendSingleAndParse(\n { oneofKind: \"listGrants\", listGrants: this.toSignedResourceId(rId) },\n (r) => r.listGrants.grants,\n );\n }\n\n //\n // Fields\n //\n\n public createField(fId: AnyFieldRef, fieldType: FieldType, value?: AnyRef): void {\n this._stat.fieldsCreated++;\n this.sendVoidAsync({\n oneofKind: \"fieldCreate\",\n fieldCreate: { type: fieldTypeToProto(fieldType), id: this.toSignedFieldId(fId) },\n });\n if (value !== undefined) this.setField(fId, value);\n }\n\n public fieldExists(fId: AnyFieldRef): Promise<boolean> {\n return this.sendSingleAndParse(\n {\n oneofKind: \"fieldExists\",\n fieldExists: { field: this.toSignedFieldId(fId) },\n },\n (r) => r.fieldExists.exists,\n );\n }\n\n public setField(fId: AnyFieldRef, ref: AnyRef): void {\n this._stat.fieldsSet++;\n if (isResource(ref)) {\n this.sendVoidAsync({\n oneofKind: \"fieldSet\",\n fieldSet: {\n field: this.toSignedFieldId(fId),\n value: {\n ...this.toSignedResourceId(ref),\n fieldName: \"\", // default value, read as undefined\n },\n },\n });\n } else {\n this.sendVoidAsync({\n oneofKind: \"fieldSet\",\n fieldSet: {\n field: this.toSignedFieldId(fId),\n value: this.toSignedFieldId(ref),\n },\n });\n }\n }\n\n public setFieldError(fId: AnyFieldRef, ref: AnyResourceRef): void {\n this._stat.fieldsSet++;\n this.sendVoidAsync({\n oneofKind: \"fieldSetError\",\n fieldSetError: {\n field: this.toSignedFieldId(fId),\n ...this.toSignedErrorRef(ref),\n },\n });\n }\n\n public getField(fId: AnyFieldRef): Promise<FieldData> {\n this._stat.fieldsGet++;\n return this.sendSingleAndParse(\n { oneofKind: \"fieldGet\", fieldGet: { field: this.toSignedFieldId(fId) } },\n (r) => protoToField(notEmpty(r.fieldGet.field)),\n );\n }\n\n public async getFieldIfExists(fId: AnyFieldRef): Promise<FieldData | undefined> {\n return this.track(notFoundToUndefined(async () => await this.getField(fId)));\n }\n\n public resetField(fId: AnyFieldRef): void {\n this.sendVoidAsync({\n oneofKind: \"fieldReset\",\n fieldReset: { field: this.toSignedFieldId(fId) },\n });\n }\n\n public removeField(fId: AnyFieldRef): void {\n this.sendVoidAsync({\n oneofKind: \"fieldRemove\",\n fieldRemove: { field: this.toSignedFieldId(fId) },\n });\n }\n\n //\n // KV\n //\n\n public async listKeyValues(rId: AnyResourceRef): Promise<KeyValue[]> {\n return this.track(async () => {\n const result = await this.sendMultiAndParse(\n {\n oneofKind: \"resourceKeyValueList\",\n resourceKeyValueList: {\n ...this.toSignedResourceId(rId),\n startFrom: \"\",\n limit: 0,\n },\n },\n (r) => r.map((e) => e.resourceKeyValueList.record!),\n );\n\n this._stat.kvListRequests++;\n this._stat.kvListEntries += result.length;\n for (const kv of result) this._stat.kvListBytes += kv.key.length + kv.value.length;\n\n return result;\n });\n }\n\n public async listKeyValuesString(rId: AnyResourceRef): Promise<KeyValueString[]> {\n return this.track(async () =>\n (await this.listKeyValues(rId)).map(({ key, value }) => ({\n key,\n value: Buffer.from(value).toString(),\n })),\n );\n }\n\n public async listKeyValuesIfResourceExists(rId: AnyResourceRef): Promise<KeyValue[] | undefined> {\n return this.track(notFoundToUndefined(async () => await this.listKeyValues(rId)));\n }\n\n public async listKeyValuesStringIfResourceExists(\n rId: AnyResourceRef,\n ): Promise<KeyValueString[] | undefined> {\n return this.track(notFoundToUndefined(async () => await this.listKeyValuesString(rId)));\n }\n\n public setKValue(rId: AnyResourceRef, key: string, value: Uint8Array | string): void {\n this._stat.kvSetRequests++;\n this._stat.kvSetBytes++;\n this.sendVoidAsync({\n oneofKind: \"resourceKeyValueSet\",\n resourceKeyValueSet: {\n ...this.toSignedResourceId(rId),\n key,\n value: toBytes(value),\n },\n });\n }\n\n public deleteKValue(rId: AnyResourceRef, key: string): void {\n this.sendVoidAsync({\n oneofKind: \"resourceKeyValueDelete\",\n resourceKeyValueDelete: {\n ...this.toSignedResourceId(rId),\n key,\n },\n });\n }\n\n public async getKValue(rId: AnyResourceRef, key: string): Promise<Uint8Array> {\n return this.track(async () => {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceKeyValueGet\",\n resourceKeyValueGet: {\n ...this.toSignedResourceId(rId),\n key,\n },\n },\n (r) => r.resourceKeyValueGet.value,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result.length;\n\n return result;\n });\n }\n\n public async getKValueString(rId: AnyResourceRef, key: string): Promise<string> {\n return this.track(async () => Buffer.from(await this.getKValue(rId, key)).toString());\n }\n\n public async getKValueJson<T>(rId: AnyResourceRef, key: string): Promise<T> {\n return this.track(async () => JSON.parse(await this.getKValueString(rId, key)) as T);\n }\n\n public async getKValueIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<Uint8Array | undefined> {\n return this.track(async () => {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: \"resourceKeyValueGetIfExists\",\n resourceKeyValueGetIfExists: {\n ...this.toSignedResourceId(rId),\n key,\n },\n },\n (r) =>\n r.resourceKeyValueGetIfExists.exists ? r.resourceKeyValueGetIfExists.value : undefined,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result?.length ?? 0;\n\n return result;\n });\n }\n\n public async getKValueStringIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<string | undefined> {\n return this.track(async () => {\n const data = await this.getKValueIfExists(rId, key);\n return data === undefined ? undefined : Buffer.from(data).toString();\n });\n }\n\n public async getKValueJsonIfExists<T>(rId: AnyResourceRef, key: string): Promise<T | undefined> {\n return this.track(async () => {\n const str = await this.getKValueStringIfExists(rId, key);\n if (str === undefined) return undefined;\n return JSON.parse(str) as T;\n });\n }\n\n //\n // Cache\n //\n // TODO\n\n //\n // High level ops\n //\n\n /** Resolves existing or create first level resource from */\n public getFutureFieldValue(rId: AnyRef, fieldName: string, fieldType: FutureFieldType): FieldRef {\n const data = Buffer.from(JSON.stringify({ fieldName, fieldType }));\n const getFieldResource = this.createEphemeral({ name: \"json/getField\", version: \"1\" }, data);\n this.setField({ resourceId: getFieldResource, fieldName: \"resource\" }, rId);\n return { resourceId: getFieldResource, fieldName: \"result\" };\n }\n\n //\n // Technical\n //\n\n public async getGlobalTxId() {\n this.globalTxIdWasAwaited = true;\n return await this.globalTxId;\n }\n\n /** Closes output event stream */\n public async complete() {\n if (this._completed) return;\n this._completed = true;\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n }\n\n /** Await incoming message loop termination and throw\n * any leftover errors if it was unsuccessful */\n public async await() {\n await this.ll.await();\n }\n\n //\n // Tree streaming\n //\n\n /**\n * Perform a single `ResourceTree` walk and yield each visited resource.\n *\n * Items are yielded incrementally as stream frames arrive from server.\n *\n * The low-level transaction stream is still ordered, so each active request\n * must be consumed to completion (or closed via iterator `return()`/`throw()`)\n * before later responses can be dispatched.\n *\n * @param seeds - Roots for the traversal. May include both {@link ResourceData}\n * and {@link SignedResourceId} values in the same array.\n * @param opts.fieldFilter - Per-field predicate; matching field edges are not descended.\n * This wire field accepts only one filter. Compose multiple rules via\n * `treeFilter.and(...)` / `treeFilter.or(...)`.\n * @param opts.traverseStopRules - Per-resource predicate; matching resources are returned\n * with `traverseWasStopped = true` and their children are not visited.\n * This wire field accepts only one filter. Compose multiple rules via\n * `treeFilter.and(...)` / `treeFilter.or(...)`.\n * @param opts.includeKv - When true, each yielded item includes KV entries.\n * @param opts.maxDepth - Optional depth cap.\n */\n public resourceTree(\n seeds: (ResourceData | SignedResourceId)[],\n opts?: {\n fieldFilter?: ResourceAPI_Tree_Filter;\n traverseStopRules?: ResourceAPI_Tree_Filter;\n includeKv?: boolean;\n maxDepth?: number;\n },\n ): AsyncIterable<ResourceTreeFrame> {\n if (seeds.length === 0) {\n throw new Error(\"resourceTree: at least one seed must be provided\");\n }\n\n const seedProtos = seeds.map((seed): ResourceAPI_Tree_SeedResource => {\n const signedId = typeof seed === \"string\" ? seed : seed.id;\n const { globalId, signature } = parseSignedResourceId(signedId);\n return { resourceId: globalId, resourceSignature: signature };\n });\n\n const firstSeed = seedProtos[0];\n\n const responseStream = this.ll.sendStream({\n oneofKind: \"resourceTree\",\n resourceTree: {\n // Keep compatibility with request shape that requires non-optional fields.\n resourceId: firstSeed?.resourceId ?? 0n,\n resourceSignature: firstSeed?.resourceSignature ?? new Uint8Array(0),\n seeds: seedProtos,\n fieldFilter: opts?.fieldFilter,\n traverseStopRules: opts?.traverseStopRules,\n includeKv: opts?.includeKv ?? false,\n maxDepth: opts?.maxDepth,\n showSoftDeletes: false,\n },\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ResourceTreeFrame> {\n const iterator = responseStream[Symbol.asyncIterator]();\n\n return {\n async next(): Promise<IteratorResult<ResourceTreeFrame>> {\n while (true) {\n const item = await iterator.next();\n if (item.done) return { value: undefined, done: true };\n\n const frame = item.value.resourceTree;\n if (frame === undefined) continue;\n\n if (frame.resource && resourceIsDeleted(frame.resource)) {\n continue;\n }\n\n if (!frame.resource) {\n // Stop-marker frame: no resource body; server advertised treeStopMarker:v1.\n const id = createSignedResourceId(\n frame.resourceId,\n toResourceSignature(frame.resourceSignature),\n );\n return {\n value: { frameKind: \"stopMarker\", id, traverseWasStopped: true },\n done: false,\n };\n }\n\n return {\n value: {\n frameKind: \"resource\",\n ...protoToResource(frame.resource),\n kv: frame.kv,\n traverseWasStopped: frame.traverseWasStopped,\n },\n done: false,\n };\n }\n },\n async return(): Promise<IteratorResult<ResourceTreeFrame>> {\n if (iterator.return) await iterator.return();\n return { value: undefined, done: true };\n },\n async throw(error?: unknown): Promise<IteratorResult<ResourceTreeFrame>> {\n if (iterator.throw) await iterator.throw(error);\n throw error;\n },\n };\n },\n };\n }\n\n //\n // Helpers\n //\n\n private nextLocalResourceId(root: boolean): LocalResourceId {\n return createLocalResourceId(root, ++this.localResourceIdCounter, this.localTxId);\n }\n\n private static localTxIdCounter = 0;\n\n private static nextLocalTxId() {\n PlTransaction.localTxIdCounter++;\n if (PlTransaction.localTxIdCounter === MaxTxId) PlTransaction.localTxIdCounter = 1;\n return PlTransaction.localTxIdCounter;\n }\n}\n"],"mappings":"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"}
@@ -72,6 +72,60 @@ var UserResources = class {
72
72
  if (this.backendCapability !== "legacy") return await this.getDataLibrariesViaList(opts);
73
73
  return await this.getDataLibrariesViaLegacy();
74
74
  }
75
+ /**
76
+ * Discovers shared resources of a given type granted to the user, as signed resource ids.
77
+ *
78
+ * The public, type-filtered form of {@link getDataLibrariesViaList}: it polls the
79
+ * `ListUserResources` gRPC stream and returns every `sharedResource` entry whose
80
+ * `resourceType.name` matches `resourceTypeName`. Matching is by name only — the
81
+ * version is ignored (permissive, survives schema bumps).
82
+ *
83
+ * gRPC-only: `ListUserResources` throws on a REST-connected client
84
+ * ({@link LLPlClient.listUserResources}), so callers on REST get a thrown error.
85
+ */
86
+ async listSharedResourcesByType(resourceTypeName, opts = {}) {
87
+ const responses = await this.ll.listUserResources({ login: opts.login });
88
+ const result = [];
89
+ for (const msg of responses) {
90
+ if (msg.entry.oneofKind !== "sharedResource") continue;
91
+ const sr = msg.entry.sharedResource;
92
+ if (!sr.resourceType) continue;
93
+ if (sr.resourceType.name !== resourceTypeName) continue;
94
+ result.push(require_types.createSignedResourceId(sr.resourceId, require_types.toResourceSignature(sr.resourceSignature)));
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * Enumerates the recipients of a single resource — the donor-side "who did I
100
+ * share with" view.
101
+ *
102
+ * Takes a signed, writable resource handle: the backend gates grant listing on a
103
+ * signed resource id with writable permission, so only the resource's owner can
104
+ * call it. An everyone-grant surfaces with `user` matching the backend's
105
+ * everyone-sentinel — test with {@link isEveryoneUserLogin} (from "./transaction");
106
+ * the caller maps that to "*".
107
+ *
108
+ * Runs over a read transaction ({@link PlTransaction.listGrants}), so it works on
109
+ * every wire protocol — including REST, where the standalone server-streaming
110
+ * `ListGrants` RPC has no binding.
111
+ */
112
+ async listGrants(resourceId) {
113
+ return (await this.runTx("ListGrants", false, "", (tx) => tx.listGrants(resourceId))).map((grant) => ({
114
+ user: grant.user,
115
+ writable: grant.permissions?.writable ?? false,
116
+ grantedBy: grant.grantedBy,
117
+ grantedAt: Number(grant.grantedAt)
118
+ }));
119
+ }
120
+ /**
121
+ * Lists the logins of users known to the server, for the recipient picker. A user becomes
122
+ * known on first login; provisioned users who have never logged in do not appear. gRPC-only
123
+ * (the underlying {@link LLPlClient.listUsers} has no REST binding) — throws on a
124
+ * REST-connected client, so callers gate on the `userListing:v1` capability.
125
+ */
126
+ async listUsers() {
127
+ return (await this.ll.listUsers()).map((user) => ({ login: user.login }));
128
+ }
75
129
  async getUserRootViaRpc(opts = {}) {
76
130
  const resp = await this.ll.getUserRoot({
77
131
  login: opts.login,
@@ -1 +1 @@
1
- {"version":3,"file":"user_resources.cjs","names":["isUnimplementedError","createSignedResourceId","toResourceSignature","ClientRoot","toGlobalResourceId","isNotNullSignedResourceId"],"sources":["../../src/core/user_resources.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { LLPlClient } from \"./ll_client\";\nimport type { PlTransaction } from \"./transaction\";\nimport { toGlobalResourceId } from \"./transaction\";\nimport type { OptionalSignedResourceId, SignedResourceId, ResourceType } from \"./types\";\nimport {\n createSignedResourceId,\n isNotNullSignedResourceId,\n NullSignedResourceId,\n toResourceSignature,\n} from \"./types\";\nimport { isUnimplementedError } from \"./errors\";\nimport { ClientRoot } from \"../helpers/pl\";\n\nconst AnonymousClientRoot = \"AnonymousRoot\";\nconst LsStorageTypePrefix = \"LS/\"; // implements ls API in particular storage\nconst LsProviderFieldPrefix = \"storage/\"; // provides access to storages list\n\n/** Information about a single data library (LS storage). */\nexport interface StorageInfo {\n /** Machine-stable identifier, e.g. \"library\". Used for filtering and map keys. */\n readonly storageId: string;\n /** Human-readable display name. For V1/legacy equals storageId; for V2 from resource JSON data. */\n readonly storageName: string;\n /** Signed resource ID for this storage resource. */\n readonly resourceId: SignedResourceId;\n /** Full resource type including correct version (\"1\" or \"2\"). */\n readonly resourceType: ResourceType;\n}\n\n/** V2 LsStorage resource JSON data shape (contract with backend). */\ninterface LsStorageV2Data {\n storageName: string;\n storageID: string;\n}\n\n/**\n * Callback type for running transactions. Matches PlClient._withTx signature\n * so the index can run transactions before PlClient is fully initialized.\n */\nexport type TxRunner = <T>(\n name: string,\n writable: boolean,\n clientRoot: OptionalSignedResourceId,\n body: (tx: PlTransaction) => Promise<T>,\n) => Promise<T>;\n\ntype BackendCapability = \"getUserRoot\" | \"listUserResources\" | \"legacy\";\n\n/**\n * Abstracts user resource discovery with backward compatibility.\n *\n * Detects backend capability on the first getUserRoot() call and remembers\n * the result. Three-tier fallback:\n * 1. getUserRoot RPC (newest, supports createIfNotExists)\n * 2. listUserResources RPC (streams all resources, picks userRoot)\n * 3. Named resource lookup/creation via transaction (legacy)\n */\nexport class UserResources {\n private backendCapability: BackendCapability | undefined;\n\n constructor(\n private readonly ll: LLPlClient,\n private readonly runTx: TxRunner,\n public readonly authUser: string | null,\n ) {}\n\n /**\n * Returns the user's root resource ID.\n *\n * On first call, detects backend capability by trying methods in order:\n * 1. getUserRoot RPC (newest)\n * 2. listUserResources RPC\n * 3. Named resource lookup/creation via transaction (legacy)\n */\n async getUserRoot(opts: { login?: string; createIfNotExists: true }): Promise<SignedResourceId>;\n async getUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n if (this.backendCapability === undefined) {\n return await this.detectAndGetUserRoot(opts);\n }\n return await this.getUserRootWith(this.backendCapability, opts);\n }\n\n private async detectAndGetUserRoot(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async detectAndGetUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async detectAndGetUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n // 1. Try getUserRoot RPC\n try {\n const root = await this.getUserRootViaRpc(opts);\n this.backendCapability = \"getUserRoot\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 2. Try listUserResources\n try {\n const root = await this.getUserRootViaList(opts);\n this.backendCapability = \"listUserResources\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 3. Legacy fallback\n this.backendCapability = \"legacy\";\n return await this.getUserRootViaLegacy(opts);\n }\n\n private async getUserRootWith(\n capability: BackendCapability,\n opts: { login?: string; createIfNotExists: true },\n ): Promise<SignedResourceId>;\n private async getUserRootWith(\n capability: BackendCapability,\n opts?: { login?: string; createIfNotExists?: boolean },\n ): Promise<SignedResourceId | undefined>;\n private async getUserRootWith(\n capability: BackendCapability,\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n switch (capability) {\n case \"getUserRoot\":\n return await this.getUserRootViaRpc(opts);\n case \"listUserResources\":\n return await this.getUserRootViaList(opts);\n case \"legacy\":\n return await this.getUserRootViaLegacy(opts);\n }\n }\n\n /**\n * Returns all data libraries the user has access to.\n * Always fetches fresh from the server (no caching).\n */\n async getDataLibraries(\n opts: { login?: string; createUserRootIfNotExists?: boolean } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n if (this.backendCapability === undefined) {\n // First call — detect backend capability\n try {\n const libs = await this.getDataLibrariesViaList(opts);\n // getUserRoot RPC doesn't return libraries, but listUserResources does;\n // record at least \"listUserResources\" so future getUserRoot calls don't re-detect.\n this.backendCapability = \"listUserResources\";\n return libs;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n this.backendCapability = \"legacy\";\n return await this.getDataLibrariesViaLegacy();\n }\n }\n\n // A server that supports getUserRoot definitely supports listUserResources.\n if (this.backendCapability !== \"legacy\") {\n return await this.getDataLibrariesViaList(opts);\n }\n return await this.getDataLibrariesViaLegacy();\n }\n\n private async getUserRootViaRpc(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaRpc(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaRpc(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const resp = await this.ll.getUserRoot({\n login: opts.login,\n createIfNotExists: opts.createIfNotExists,\n });\n if (resp.userRoot === undefined) {\n if (!opts.createIfNotExists) return undefined;\n throw new Error(\"getUserRoot returned no userRoot entry\");\n }\n return createSignedResourceId(\n resp.userRoot.resourceId,\n toResourceSignature(resp.userRoot.resourceSignature),\n );\n }\n\n private async getUserRootViaList(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaList(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaList(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const responses = await this.ll.listUserResources({ login: opts.login, limit: 1 });\n for (const msg of responses) {\n if (msg.entry.oneofKind === \"userRoot\") {\n return createSignedResourceId(\n msg.entry.userRoot.resourceId,\n toResourceSignature(msg.entry.userRoot.resourceSignature),\n );\n }\n }\n\n if (opts.createIfNotExists) {\n throw new Error(\"listUserResources returned no userRoot entry\");\n }\n\n return undefined;\n }\n\n private async getDataLibrariesViaList(\n opts: { login?: string } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n const responses = await this.ll.listUserResources({ login: opts.login });\n\n // Collect all LS/* shared resources, separating V1 and V2\n const v1Entries: StorageInfo[] = [];\n const v2ResourceIds: { resourceId: SignedResourceId; resourceType: ResourceType }[] = [];\n\n for (const msg of responses) {\n if (msg.entry.oneofKind !== \"sharedResource\") continue;\n const sr = msg.entry.sharedResource;\n\n if (!sr.resourceType) continue;\n const typeName = sr.resourceType.name;\n const typeVersion = sr.resourceType.version;\n if (!typeName.startsWith(LsStorageTypePrefix)) continue;\n\n const rId = createSignedResourceId(sr.resourceId, toResourceSignature(sr.resourceSignature));\n const rType: ResourceType = { name: typeName, version: typeVersion };\n\n if (typeVersion === \"2\") {\n v2ResourceIds.push({ resourceId: rId, resourceType: rType });\n } else {\n // V1 or unknown version: derive storageId from type name\n const storageId = typeName.substring(LsStorageTypePrefix.length);\n v1Entries.push({\n storageId,\n storageName: storageId,\n resourceId: rId,\n resourceType: rType,\n });\n }\n }\n\n // Read V2 resource data in a single transaction\n let v2Entries: StorageInfo[] = [];\n if (v2ResourceIds.length > 0) {\n v2Entries = await this.runTx(\n \"ReadLsStorageV2Data\",\n false,\n NullSignedResourceId,\n async (tx) => {\n const entries: StorageInfo[] = [];\n for (const { resourceId, resourceType } of v2ResourceIds) {\n const rd = await tx.getResourceData(resourceId, false);\n if (rd.data) {\n const v2Data = JSON.parse(Buffer.from(rd.data).toString(\"utf-8\")) as LsStorageV2Data;\n entries.push({\n storageId: v2Data.storageID,\n storageName: v2Data.storageName,\n resourceId,\n resourceType,\n });\n }\n }\n return entries;\n },\n );\n }\n\n const result = new Map<string, StorageInfo>();\n for (const entry of [...v1Entries, ...v2Entries]) {\n result.set(entry.storageId, entry);\n }\n return result;\n }\n\n private async getUserRootViaLegacy(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaLegacy(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaLegacy(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const login = opts.login ?? this.authUser;\n const mainRootName =\n login === null ? AnonymousClientRoot : createHash(\"sha256\").update(login).digest(\"hex\");\n\n return await this.runTx(\"initialization\", true, NullSignedResourceId, async (tx) => {\n if (await tx.checkResourceNameExists(mainRootName)) {\n return await tx.getResourceByName(mainRootName);\n }\n\n if (!opts.createIfNotExists) {\n return undefined;\n }\n\n const mainRoot = tx.createRoot(ClientRoot);\n tx.setResourceName(mainRootName, mainRoot);\n await tx.commit();\n return await toGlobalResourceId(mainRoot);\n });\n }\n\n private async getDataLibrariesViaLegacy(): Promise<ReadonlyMap<string, StorageInfo>> {\n return await this.runTx(\"GetAvailableStorageIds\", false, NullSignedResourceId, async (tx) => {\n const lsProviderId = await tx.getResourceByName(\"LSProvider\");\n const provider = await tx.getResourceData(lsProviderId, true);\n\n const result = new Map<string, StorageInfo>();\n for (const field of provider.fields) {\n if (field.type !== \"Dynamic\" || !isNotNullSignedResourceId(field.value)) continue;\n if (!field.name.startsWith(LsProviderFieldPrefix)) continue;\n\n const storageId = field.name.substring(LsProviderFieldPrefix.length);\n result.set(storageId, {\n storageId,\n storageName: storageId,\n resourceId: field.value,\n resourceType: { name: `${LsStorageTypePrefix}${storageId}`, version: \"1\" },\n });\n }\n return result;\n });\n }\n}\n"],"mappings":";;;;;;AAcA,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;;;;;;;;;;AA0C9B,IAAa,gBAAb,MAA2B;CAIN;CACA;CACD;CALlB;CAEA,YACE,IACA,OACA,UACA;EAHiB,KAAA,KAAA;EACA,KAAA,QAAA;EACD,KAAA,WAAA;CACf;CAeH,MAAM,YACJ,OAAwD,CAAC,GAClB;EACvC,IAAI,KAAK,sBAAsB,KAAA,GAC7B,OAAO,MAAM,KAAK,qBAAqB,IAAI;EAE7C,OAAO,MAAM,KAAK,gBAAgB,KAAK,mBAAmB,IAAI;CAChE;CAUA,MAAc,qBACZ,OAAwD,CAAC,GAClB;EAEvC,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,kBAAkB,IAAI;GAC9C,KAAK,oBAAoB;GACzB,OAAO;EACT,SAAS,KAAK;GACZ,IAAI,CAACA,eAAAA,qBAAqB,GAAG,GAAG,MAAM;EACxC;EAGA,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,mBAAmB,IAAI;GAC/C,KAAK,oBAAoB;GACzB,OAAO;EACT,SAAS,KAAK;GACZ,IAAI,CAACA,eAAAA,qBAAqB,GAAG,GAAG,MAAM;EACxC;EAGA,KAAK,oBAAoB;EACzB,OAAO,MAAM,KAAK,qBAAqB,IAAI;CAC7C;CAUA,MAAc,gBACZ,YACA,OAAwD,CAAC,GAClB;EACvC,QAAQ,YAAR;GACE,KAAK,eACH,OAAO,MAAM,KAAK,kBAAkB,IAAI;GAC1C,KAAK,qBACH,OAAO,MAAM,KAAK,mBAAmB,IAAI;GAC3C,KAAK,UACH,OAAO,MAAM,KAAK,qBAAqB,IAAI;EAC/C;CACF;;;;;CAMA,MAAM,iBACJ,OAAgE,CAAC,GACtB;EAC3C,IAAI,KAAK,sBAAsB,KAAA,GAE7B,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,wBAAwB,IAAI;GAGpD,KAAK,oBAAoB;GACzB,OAAO;EACT,SAAS,KAAK;GACZ,IAAI,CAACA,eAAAA,qBAAqB,GAAG,GAAG,MAAM;GACtC,KAAK,oBAAoB;GACzB,OAAO,MAAM,KAAK,0BAA0B;EAC9C;EAIF,IAAI,KAAK,sBAAsB,UAC7B,OAAO,MAAM,KAAK,wBAAwB,IAAI;EAEhD,OAAO,MAAM,KAAK,0BAA0B;CAC9C;CAUA,MAAc,kBACZ,OAAwD,CAAC,GAClB;EACvC,MAAM,OAAO,MAAM,KAAK,GAAG,YAAY;GACrC,OAAO,KAAK;GACZ,mBAAmB,KAAK;EAC1B,CAAC;EACD,IAAI,KAAK,aAAa,KAAA,GAAW;GAC/B,IAAI,CAAC,KAAK,mBAAmB,OAAO,KAAA;GACpC,MAAM,IAAI,MAAM,wCAAwC;EAC1D;EACA,OAAOC,cAAAA,uBACL,KAAK,SAAS,YACdC,cAAAA,oBAAoB,KAAK,SAAS,iBAAiB,CACrD;CACF;CAUA,MAAc,mBACZ,OAAwD,CAAC,GAClB;EACvC,MAAM,YAAY,MAAM,KAAK,GAAG,kBAAkB;GAAE,OAAO,KAAK;GAAO,OAAO;EAAE,CAAC;EACjF,KAAK,MAAM,OAAO,WAChB,IAAI,IAAI,MAAM,cAAc,YAC1B,OAAOD,cAAAA,uBACL,IAAI,MAAM,SAAS,YACnBC,cAAAA,oBAAoB,IAAI,MAAM,SAAS,iBAAiB,CAC1D;EAIJ,IAAI,KAAK,mBACP,MAAM,IAAI,MAAM,8CAA8C;CAIlE;CAEA,MAAc,wBACZ,OAA2B,CAAC,GACe;EAC3C,MAAM,YAAY,MAAM,KAAK,GAAG,kBAAkB,EAAE,OAAO,KAAK,MAAM,CAAC;EAGvE,MAAM,YAA2B,CAAC;EAClC,MAAM,gBAAgF,CAAC;EAEvF,KAAK,MAAM,OAAO,WAAW;GAC3B,IAAI,IAAI,MAAM,cAAc,kBAAkB;GAC9C,MAAM,KAAK,IAAI,MAAM;GAErB,IAAI,CAAC,GAAG,cAAc;GACtB,MAAM,WAAW,GAAG,aAAa;GACjC,MAAM,cAAc,GAAG,aAAa;GACpC,IAAI,CAAC,SAAS,WAAW,mBAAmB,GAAG;GAE/C,MAAM,MAAMD,cAAAA,uBAAuB,GAAG,YAAYC,cAAAA,oBAAoB,GAAG,iBAAiB,CAAC;GAC3F,MAAM,QAAsB;IAAE,MAAM;IAAU,SAAS;GAAY;GAEnE,IAAI,gBAAgB,KAClB,cAAc,KAAK;IAAE,YAAY;IAAK,cAAc;GAAM,CAAC;QACtD;IAEL,MAAM,YAAY,SAAS,UAAU,CAA0B;IAC/D,UAAU,KAAK;KACb;KACA,aAAa;KACb,YAAY;KACZ,cAAc;IAChB,CAAC;GACH;EACF;EAGA,IAAI,YAA2B,CAAC;EAChC,IAAI,cAAc,SAAS,GACzB,YAAY,MAAM,KAAK,MACrB,uBACA,OAAA,IAEA,OAAO,OAAO;GACZ,MAAM,UAAyB,CAAC;GAChC,KAAK,MAAM,EAAE,YAAY,kBAAkB,eAAe;IACxD,MAAM,KAAK,MAAM,GAAG,gBAAgB,YAAY,KAAK;IACrD,IAAI,GAAG,MAAM;KACX,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC,SAAS,OAAO,CAAC;KAChE,QAAQ,KAAK;MACX,WAAW,OAAO;MAClB,aAAa,OAAO;MACpB;MACA;KACF,CAAC;IACH;GACF;GACA,OAAO;EACT,CACF;EAGF,MAAM,yBAAS,IAAI,IAAyB;EAC5C,KAAK,MAAM,SAAS,CAAC,GAAG,WAAW,GAAG,SAAS,GAC7C,OAAO,IAAI,MAAM,WAAW,KAAK;EAEnC,OAAO;CACT;CAUA,MAAc,qBACZ,OAAwD,CAAC,GAClB;EACvC,MAAM,QAAQ,KAAK,SAAS,KAAK;EACjC,MAAM,eACJ,UAAU,OAAO,uBAAA,GAAA,YAAA,WAAA,CAAiC,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;EAExF,OAAO,MAAM,KAAK,MAAM,kBAAkB,MAAA,IAA4B,OAAO,OAAO;GAClF,IAAI,MAAM,GAAG,wBAAwB,YAAY,GAC/C,OAAO,MAAM,GAAG,kBAAkB,YAAY;GAGhD,IAAI,CAAC,KAAK,mBACR;GAGF,MAAM,WAAW,GAAG,WAAWC,WAAAA,UAAU;GACzC,GAAG,gBAAgB,cAAc,QAAQ;GACzC,MAAM,GAAG,OAAO;GAChB,OAAO,MAAMC,oBAAAA,mBAAmB,QAAQ;EAC1C,CAAC;CACH;CAEA,MAAc,4BAAuE;EACnF,OAAO,MAAM,KAAK,MAAM,0BAA0B,OAAA,IAA6B,OAAO,OAAO;GAC3F,MAAM,eAAe,MAAM,GAAG,kBAAkB,YAAY;GAC5D,MAAM,WAAW,MAAM,GAAG,gBAAgB,cAAc,IAAI;GAE5D,MAAM,yBAAS,IAAI,IAAyB;GAC5C,KAAK,MAAM,SAAS,SAAS,QAAQ;IACnC,IAAI,MAAM,SAAS,aAAa,CAACC,cAAAA,0BAA0B,MAAM,KAAK,GAAG;IACzE,IAAI,CAAC,MAAM,KAAK,WAAW,qBAAqB,GAAG;IAEnD,MAAM,YAAY,MAAM,KAAK,UAAU,CAA4B;IACnE,OAAO,IAAI,WAAW;KACpB;KACA,aAAa;KACb,YAAY,MAAM;KAClB,cAAc;MAAE,MAAM,GAAG,sBAAsB;MAAa,SAAS;KAAI;IAC3E,CAAC;GACH;GACA,OAAO;EACT,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"user_resources.cjs","names":["isUnimplementedError","createSignedResourceId","toResourceSignature","ClientRoot","toGlobalResourceId","isNotNullSignedResourceId"],"sources":["../../src/core/user_resources.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { LLPlClient } from \"./ll_client\";\nimport type { PlTransaction } from \"./transaction\";\nimport { toGlobalResourceId } from \"./transaction\";\nimport type { OptionalSignedResourceId, SignedResourceId, ResourceType } from \"./types\";\nimport {\n createSignedResourceId,\n isNotNullSignedResourceId,\n NullSignedResourceId,\n toResourceSignature,\n} from \"./types\";\nimport { isUnimplementedError } from \"./errors\";\nimport { ClientRoot } from \"../helpers/pl\";\n\nconst AnonymousClientRoot = \"AnonymousRoot\";\nconst LsStorageTypePrefix = \"LS/\"; // implements ls API in particular storage\nconst LsProviderFieldPrefix = \"storage/\"; // provides access to storages list\n\n/** One recipient of a resource, as returned by {@link UserResources.listGrants}. */\nexport interface GrantEntry {\n /** Login the grant targets. An everyone-grant surfaces here as the backend's\n * everyone-sentinel — test with {@link isEveryoneUserLogin} (from \"./transaction\"); callers\n * map it to \"*\". */\n readonly user: string;\n /** True for a writable grant (copy / collaboration), false for read-only. */\n readonly writable: boolean;\n /** Login of the user who created the grant. */\n readonly grantedBy: string;\n /** When the grant was created (ms epoch). */\n readonly grantedAt: number;\n}\n\n/** One user known to the server, as returned by {@link UserResources.listUsers}. */\nexport interface UserEntry {\n /** Stable identifier of the user; the grant target and `GetUserRoot` key. */\n readonly login: string;\n}\n\n/** Information about a single data library (LS storage). */\nexport interface StorageInfo {\n /** Machine-stable identifier, e.g. \"library\". Used for filtering and map keys. */\n readonly storageId: string;\n /** Human-readable display name. For V1/legacy equals storageId; for V2 from resource JSON data. */\n readonly storageName: string;\n /** Signed resource ID for this storage resource. */\n readonly resourceId: SignedResourceId;\n /** Full resource type including correct version (\"1\" or \"2\"). */\n readonly resourceType: ResourceType;\n}\n\n/** V2 LsStorage resource JSON data shape (contract with backend). */\ninterface LsStorageV2Data {\n storageName: string;\n storageID: string;\n}\n\n/**\n * Callback type for running transactions. Matches PlClient._withTx signature\n * so the index can run transactions before PlClient is fully initialized.\n */\nexport type TxRunner = <T>(\n name: string,\n writable: boolean,\n clientRoot: OptionalSignedResourceId,\n body: (tx: PlTransaction) => Promise<T>,\n) => Promise<T>;\n\ntype BackendCapability = \"getUserRoot\" | \"listUserResources\" | \"legacy\";\n\n/**\n * Abstracts user resource discovery with backward compatibility.\n *\n * Detects backend capability on the first getUserRoot() call and remembers\n * the result. Three-tier fallback:\n * 1. getUserRoot RPC (newest, supports createIfNotExists)\n * 2. listUserResources RPC (streams all resources, picks userRoot)\n * 3. Named resource lookup/creation via transaction (legacy)\n */\nexport class UserResources {\n private backendCapability: BackendCapability | undefined;\n\n constructor(\n private readonly ll: LLPlClient,\n private readonly runTx: TxRunner,\n public readonly authUser: string | null,\n ) {}\n\n /**\n * Returns the user's root resource ID.\n *\n * On first call, detects backend capability by trying methods in order:\n * 1. getUserRoot RPC (newest)\n * 2. listUserResources RPC\n * 3. Named resource lookup/creation via transaction (legacy)\n */\n async getUserRoot(opts: { login?: string; createIfNotExists: true }): Promise<SignedResourceId>;\n async getUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n if (this.backendCapability === undefined) {\n return await this.detectAndGetUserRoot(opts);\n }\n return await this.getUserRootWith(this.backendCapability, opts);\n }\n\n private async detectAndGetUserRoot(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async detectAndGetUserRoot(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async detectAndGetUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n // 1. Try getUserRoot RPC\n try {\n const root = await this.getUserRootViaRpc(opts);\n this.backendCapability = \"getUserRoot\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 2. Try listUserResources\n try {\n const root = await this.getUserRootViaList(opts);\n this.backendCapability = \"listUserResources\";\n return root;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n }\n\n // 3. Legacy fallback\n this.backendCapability = \"legacy\";\n return await this.getUserRootViaLegacy(opts);\n }\n\n private async getUserRootWith(\n capability: BackendCapability,\n opts: { login?: string; createIfNotExists: true },\n ): Promise<SignedResourceId>;\n private async getUserRootWith(\n capability: BackendCapability,\n opts?: { login?: string; createIfNotExists?: boolean },\n ): Promise<SignedResourceId | undefined>;\n private async getUserRootWith(\n capability: BackendCapability,\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n switch (capability) {\n case \"getUserRoot\":\n return await this.getUserRootViaRpc(opts);\n case \"listUserResources\":\n return await this.getUserRootViaList(opts);\n case \"legacy\":\n return await this.getUserRootViaLegacy(opts);\n }\n }\n\n /**\n * Returns all data libraries the user has access to.\n * Always fetches fresh from the server (no caching).\n */\n async getDataLibraries(\n opts: { login?: string; createUserRootIfNotExists?: boolean } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n if (this.backendCapability === undefined) {\n // First call — detect backend capability\n try {\n const libs = await this.getDataLibrariesViaList(opts);\n // getUserRoot RPC doesn't return libraries, but listUserResources does;\n // record at least \"listUserResources\" so future getUserRoot calls don't re-detect.\n this.backendCapability = \"listUserResources\";\n return libs;\n } catch (err) {\n if (!isUnimplementedError(err)) throw err;\n this.backendCapability = \"legacy\";\n return await this.getDataLibrariesViaLegacy();\n }\n }\n\n // A server that supports getUserRoot definitely supports listUserResources.\n if (this.backendCapability !== \"legacy\") {\n return await this.getDataLibrariesViaList(opts);\n }\n return await this.getDataLibrariesViaLegacy();\n }\n\n /**\n * Discovers shared resources of a given type granted to the user, as signed resource ids.\n *\n * The public, type-filtered form of {@link getDataLibrariesViaList}: it polls the\n * `ListUserResources` gRPC stream and returns every `sharedResource` entry whose\n * `resourceType.name` matches `resourceTypeName`. Matching is by name only — the\n * version is ignored (permissive, survives schema bumps).\n *\n * gRPC-only: `ListUserResources` throws on a REST-connected client\n * ({@link LLPlClient.listUserResources}), so callers on REST get a thrown error.\n */\n async listSharedResourcesByType(\n resourceTypeName: string,\n opts: { login?: string } = {},\n ): Promise<SignedResourceId[]> {\n const responses = await this.ll.listUserResources({ login: opts.login });\n\n const result: SignedResourceId[] = [];\n for (const msg of responses) {\n if (msg.entry.oneofKind !== \"sharedResource\") continue;\n const sr = msg.entry.sharedResource;\n if (!sr.resourceType) continue;\n if (sr.resourceType.name !== resourceTypeName) continue;\n result.push(createSignedResourceId(sr.resourceId, toResourceSignature(sr.resourceSignature)));\n }\n return result;\n }\n\n /**\n * Enumerates the recipients of a single resource — the donor-side \"who did I\n * share with\" view.\n *\n * Takes a signed, writable resource handle: the backend gates grant listing on a\n * signed resource id with writable permission, so only the resource's owner can\n * call it. An everyone-grant surfaces with `user` matching the backend's\n * everyone-sentinel — test with {@link isEveryoneUserLogin} (from \"./transaction\");\n * the caller maps that to \"*\".\n *\n * Runs over a read transaction ({@link PlTransaction.listGrants}), so it works on\n * every wire protocol — including REST, where the standalone server-streaming\n * `ListGrants` RPC has no binding.\n */\n async listGrants(resourceId: SignedResourceId): Promise<GrantEntry[]> {\n const grants = await this.runTx(\"ListGrants\", false, NullSignedResourceId, (tx) =>\n tx.listGrants(resourceId),\n );\n return grants.map((grant) => ({\n user: grant.user,\n writable: grant.permissions?.writable ?? false,\n grantedBy: grant.grantedBy,\n grantedAt: Number(grant.grantedAt),\n }));\n }\n\n /**\n * Lists the logins of users known to the server, for the recipient picker. A user becomes\n * known on first login; provisioned users who have never logged in do not appear. gRPC-only\n * (the underlying {@link LLPlClient.listUsers} has no REST binding) — throws on a\n * REST-connected client, so callers gate on the `userListing:v1` capability.\n */\n async listUsers(): Promise<UserEntry[]> {\n const users = await this.ll.listUsers();\n return users.map((user) => ({ login: user.login }));\n }\n\n private async getUserRootViaRpc(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaRpc(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaRpc(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const resp = await this.ll.getUserRoot({\n login: opts.login,\n createIfNotExists: opts.createIfNotExists,\n });\n if (resp.userRoot === undefined) {\n if (!opts.createIfNotExists) return undefined;\n throw new Error(\"getUserRoot returned no userRoot entry\");\n }\n return createSignedResourceId(\n resp.userRoot.resourceId,\n toResourceSignature(resp.userRoot.resourceSignature),\n );\n }\n\n private async getUserRootViaList(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaList(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaList(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const responses = await this.ll.listUserResources({ login: opts.login, limit: 1 });\n for (const msg of responses) {\n if (msg.entry.oneofKind === \"userRoot\") {\n return createSignedResourceId(\n msg.entry.userRoot.resourceId,\n toResourceSignature(msg.entry.userRoot.resourceSignature),\n );\n }\n }\n\n if (opts.createIfNotExists) {\n throw new Error(\"listUserResources returned no userRoot entry\");\n }\n\n return undefined;\n }\n\n private async getDataLibrariesViaList(\n opts: { login?: string } = {},\n ): Promise<ReadonlyMap<string, StorageInfo>> {\n const responses = await this.ll.listUserResources({ login: opts.login });\n\n // Collect all LS/* shared resources, separating V1 and V2\n const v1Entries: StorageInfo[] = [];\n const v2ResourceIds: { resourceId: SignedResourceId; resourceType: ResourceType }[] = [];\n\n for (const msg of responses) {\n if (msg.entry.oneofKind !== \"sharedResource\") continue;\n const sr = msg.entry.sharedResource;\n\n if (!sr.resourceType) continue;\n const typeName = sr.resourceType.name;\n const typeVersion = sr.resourceType.version;\n if (!typeName.startsWith(LsStorageTypePrefix)) continue;\n\n const rId = createSignedResourceId(sr.resourceId, toResourceSignature(sr.resourceSignature));\n const rType: ResourceType = { name: typeName, version: typeVersion };\n\n if (typeVersion === \"2\") {\n v2ResourceIds.push({ resourceId: rId, resourceType: rType });\n } else {\n // V1 or unknown version: derive storageId from type name\n const storageId = typeName.substring(LsStorageTypePrefix.length);\n v1Entries.push({\n storageId,\n storageName: storageId,\n resourceId: rId,\n resourceType: rType,\n });\n }\n }\n\n // Read V2 resource data in a single transaction\n let v2Entries: StorageInfo[] = [];\n if (v2ResourceIds.length > 0) {\n v2Entries = await this.runTx(\n \"ReadLsStorageV2Data\",\n false,\n NullSignedResourceId,\n async (tx) => {\n const entries: StorageInfo[] = [];\n for (const { resourceId, resourceType } of v2ResourceIds) {\n const rd = await tx.getResourceData(resourceId, false);\n if (rd.data) {\n const v2Data = JSON.parse(Buffer.from(rd.data).toString(\"utf-8\")) as LsStorageV2Data;\n entries.push({\n storageId: v2Data.storageID,\n storageName: v2Data.storageName,\n resourceId,\n resourceType,\n });\n }\n }\n return entries;\n },\n );\n }\n\n const result = new Map<string, StorageInfo>();\n for (const entry of [...v1Entries, ...v2Entries]) {\n result.set(entry.storageId, entry);\n }\n return result;\n }\n\n private async getUserRootViaLegacy(opts: {\n login?: string;\n createIfNotExists: true;\n }): Promise<SignedResourceId>;\n private async getUserRootViaLegacy(opts?: {\n login?: string;\n createIfNotExists?: boolean;\n }): Promise<SignedResourceId | undefined>;\n private async getUserRootViaLegacy(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<SignedResourceId | undefined> {\n const login = opts.login ?? this.authUser;\n const mainRootName =\n login === null ? AnonymousClientRoot : createHash(\"sha256\").update(login).digest(\"hex\");\n\n return await this.runTx(\"initialization\", true, NullSignedResourceId, async (tx) => {\n if (await tx.checkResourceNameExists(mainRootName)) {\n return await tx.getResourceByName(mainRootName);\n }\n\n if (!opts.createIfNotExists) {\n return undefined;\n }\n\n const mainRoot = tx.createRoot(ClientRoot);\n tx.setResourceName(mainRootName, mainRoot);\n await tx.commit();\n return await toGlobalResourceId(mainRoot);\n });\n }\n\n private async getDataLibrariesViaLegacy(): Promise<ReadonlyMap<string, StorageInfo>> {\n return await this.runTx(\"GetAvailableStorageIds\", false, NullSignedResourceId, async (tx) => {\n const lsProviderId = await tx.getResourceByName(\"LSProvider\");\n const provider = await tx.getResourceData(lsProviderId, true);\n\n const result = new Map<string, StorageInfo>();\n for (const field of provider.fields) {\n if (field.type !== \"Dynamic\" || !isNotNullSignedResourceId(field.value)) continue;\n if (!field.name.startsWith(LsProviderFieldPrefix)) continue;\n\n const storageId = field.name.substring(LsProviderFieldPrefix.length);\n result.set(storageId, {\n storageId,\n storageName: storageId,\n resourceId: field.value,\n resourceType: { name: `${LsStorageTypePrefix}${storageId}`, version: \"1\" },\n });\n }\n return result;\n });\n }\n}\n"],"mappings":"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"}
@@ -3,6 +3,24 @@ import { PlTransaction } from "./transaction.js";
3
3
  import { LLPlClient } from "./ll_client.js";
4
4
 
5
5
  //#region src/core/user_resources.d.ts
6
+ /** One recipient of a resource, as returned by {@link UserResources.listGrants}. */
7
+ interface GrantEntry {
8
+ /** Login the grant targets. An everyone-grant surfaces here as the backend's
9
+ * everyone-sentinel — test with {@link isEveryoneUserLogin} (from "./transaction"); callers
10
+ * map it to "*". */
11
+ readonly user: string;
12
+ /** True for a writable grant (copy / collaboration), false for read-only. */
13
+ readonly writable: boolean;
14
+ /** Login of the user who created the grant. */
15
+ readonly grantedBy: string;
16
+ /** When the grant was created (ms epoch). */
17
+ readonly grantedAt: number;
18
+ }
19
+ /** One user known to the server, as returned by {@link UserResources.listUsers}. */
20
+ interface UserEntry {
21
+ /** Stable identifier of the user; the grant target and `GetUserRoot` key. */
22
+ readonly login: string;
23
+ }
6
24
  /** Information about a single data library (LS storage). */
7
25
  interface StorageInfo {
8
26
  /** Machine-stable identifier, e.g. "library". Used for filtering and map keys. */
@@ -60,6 +78,42 @@ declare class UserResources {
60
78
  login?: string;
61
79
  createUserRootIfNotExists?: boolean;
62
80
  }): Promise<ReadonlyMap<string, StorageInfo>>;
81
+ /**
82
+ * Discovers shared resources of a given type granted to the user, as signed resource ids.
83
+ *
84
+ * The public, type-filtered form of {@link getDataLibrariesViaList}: it polls the
85
+ * `ListUserResources` gRPC stream and returns every `sharedResource` entry whose
86
+ * `resourceType.name` matches `resourceTypeName`. Matching is by name only — the
87
+ * version is ignored (permissive, survives schema bumps).
88
+ *
89
+ * gRPC-only: `ListUserResources` throws on a REST-connected client
90
+ * ({@link LLPlClient.listUserResources}), so callers on REST get a thrown error.
91
+ */
92
+ listSharedResourcesByType(resourceTypeName: string, opts?: {
93
+ login?: string;
94
+ }): Promise<SignedResourceId[]>;
95
+ /**
96
+ * Enumerates the recipients of a single resource — the donor-side "who did I
97
+ * share with" view.
98
+ *
99
+ * Takes a signed, writable resource handle: the backend gates grant listing on a
100
+ * signed resource id with writable permission, so only the resource's owner can
101
+ * call it. An everyone-grant surfaces with `user` matching the backend's
102
+ * everyone-sentinel — test with {@link isEveryoneUserLogin} (from "./transaction");
103
+ * the caller maps that to "*".
104
+ *
105
+ * Runs over a read transaction ({@link PlTransaction.listGrants}), so it works on
106
+ * every wire protocol — including REST, where the standalone server-streaming
107
+ * `ListGrants` RPC has no binding.
108
+ */
109
+ listGrants(resourceId: SignedResourceId): Promise<GrantEntry[]>;
110
+ /**
111
+ * Lists the logins of users known to the server, for the recipient picker. A user becomes
112
+ * known on first login; provisioned users who have never logged in do not appear. gRPC-only
113
+ * (the underlying {@link LLPlClient.listUsers} has no REST binding) — throws on a
114
+ * REST-connected client, so callers gate on the `userListing:v1` capability.
115
+ */
116
+ listUsers(): Promise<UserEntry[]>;
63
117
  private getUserRootViaRpc;
64
118
  private getUserRootViaList;
65
119
  private getDataLibrariesViaList;
@@ -67,5 +121,5 @@ declare class UserResources {
67
121
  private getDataLibrariesViaLegacy;
68
122
  }
69
123
  //#endregion
70
- export { StorageInfo, TxRunner, UserResources };
124
+ export { GrantEntry, StorageInfo, TxRunner, UserEntry, UserResources };
71
125
  //# sourceMappingURL=user_resources.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user_resources.d.ts","names":[],"sources":["../../src/core/user_resources.ts"],"mappings":";;;;;;UAmBiB,WAAA;EAAA;EAAA,SAEN,SAAA;;WAEA,WAAA;EAFA;EAAA,SAIA,UAAA,EAAY,gBAAA;EAAZ;EAAA,SAEA,YAAA,EAAc,YAAY;AAAA;;;AAAA;AAarC;KAAY,QAAA,OACV,IAAA,UACA,QAAA,WACA,UAAA,EAAY,wBAAA,EACZ,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,MAClC,OAAA,CAAQ,CAAA;;;;;;;;;;cAaA,aAAA;EAAA,iBAIQ,EAAA;EAAA,iBACA,KAAA;EAAA,SACD,QAAA;EAAA,QALV,iBAAA;cAGW,EAAA,EAAI,UAAA,EACJ,KAAA,EAAO,QAAA,EACR,QAAA;EApBX;;;;;;;AACK;EA8BN,WAAA,CAAY,IAAA;IAAQ,KAAA;IAAgB,iBAAA;EAAA,IAA4B,OAAA,CAAQ,gBAAA;EACxE,WAAA,CAAY,IAAA;IAChB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EAAA,QAUE,oBAAA;EAAA,QAkCA,eAAA;EA4BH;;;;EAFL,gBAAA,CACJ,IAAA;IAAQ,KAAA;IAAgB,yBAAA;EAAA,IACvB,OAAA,CAAQ,WAAA,SAAoB,WAAA;EAAA,QAuBjB,iBAAA;EAAA,QAyBA,kBAAA;EAAA,QA4BA,uBAAA;EAAA,QAoEA,oBAAA;EAAA,QA+BA,yBAAA;AAAA"}
1
+ {"version":3,"file":"user_resources.d.ts","names":[],"sources":["../../src/core/user_resources.ts"],"mappings":";;;;;;UAmBiB,UAAA;EAAA;;;EAAA,SAIN,IAAA;EAAA;EAAA,SAEA,QAAA;EAEA;EAAA,SAAA,SAAA;EAES;EAAA,SAAT,SAAA;AAAA;;UAIM,SAAA;EAED;EAAA,SAAL,KAAK;AAAA;;UAIC,WAAA;EAQoB;EAAA,SAN1B,SAAA;EAEA;EAAA,SAAA,WAAA;EAEY;EAAA,SAAZ,UAAA,EAAY,gBAAA;EAEE;EAAA,SAAd,YAAA,EAAc,YAAY;AAAA;AAarC;;;;AAAA,KAAY,QAAA,OACV,IAAA,UACA,QAAA,WACA,UAAA,EAAY,wBAAA,EACZ,IAAA,GAAO,EAAA,EAAI,aAAA,KAAkB,OAAA,CAAQ,CAAA,MAClC,OAAA,CAAQ,CAAA;;;;;;;;;;cAaA,aAAA;EAAA,iBAIQ,EAAA;EAAA,iBACA,KAAA;EAAA,SACD,QAAA;EAAA,QALV,iBAAA;cAGW,EAAA,EAAI,UAAA,EACJ,KAAA,EAAO,QAAA,EACR,QAAA;EApBlB;;;;AACY;AAad;;;EAiBQ,WAAA,CAAY,IAAA;IAAQ,KAAA;IAAgB,iBAAA;EAAA,IAA4B,OAAA,CAAQ,gBAAA;EACxE,WAAA,CAAY,IAAA;IAChB,KAAA;IACA,iBAAA;EAAA,IACE,OAAA,CAAQ,gBAAA;EAAA,QAUE,oBAAA;EAAA,QAkCA,eAAA;EAiEX;;;;EAvCG,gBAAA,CACJ,IAAA;IAAQ,KAAA;IAAgB,yBAAA;EAAA,IACvB,OAAA,CAAQ,WAAA,SAAoB,WAAA;EAzFZ;;;;;;;;;;;EA2Hb,yBAAA,CACJ,gBAAA,UACA,IAAA;IAAQ,KAAA;EAAA,IACP,OAAA,CAAQ,gBAAA;EAjH2D;;;;;;;;;;;;;;EA6IhE,UAAA,CAAW,UAAA,EAAY,gBAAA,GAAmB,OAAA,CAAQ,UAAA;EAjE7C;;;;;;EAmFL,SAAA,IAAa,OAAA,CAAQ,SAAA;EAAA,QAKb,iBAAA;EAAA,QAyBA,kBAAA;EAAA,QA4BA,uBAAA;EAAA,QAoEA,oBAAA;EAAA,QA+BA,yBAAA;AAAA"}
@@ -72,6 +72,60 @@ var UserResources = class {
72
72
  if (this.backendCapability !== "legacy") return await this.getDataLibrariesViaList(opts);
73
73
  return await this.getDataLibrariesViaLegacy();
74
74
  }
75
+ /**
76
+ * Discovers shared resources of a given type granted to the user, as signed resource ids.
77
+ *
78
+ * The public, type-filtered form of {@link getDataLibrariesViaList}: it polls the
79
+ * `ListUserResources` gRPC stream and returns every `sharedResource` entry whose
80
+ * `resourceType.name` matches `resourceTypeName`. Matching is by name only — the
81
+ * version is ignored (permissive, survives schema bumps).
82
+ *
83
+ * gRPC-only: `ListUserResources` throws on a REST-connected client
84
+ * ({@link LLPlClient.listUserResources}), so callers on REST get a thrown error.
85
+ */
86
+ async listSharedResourcesByType(resourceTypeName, opts = {}) {
87
+ const responses = await this.ll.listUserResources({ login: opts.login });
88
+ const result = [];
89
+ for (const msg of responses) {
90
+ if (msg.entry.oneofKind !== "sharedResource") continue;
91
+ const sr = msg.entry.sharedResource;
92
+ if (!sr.resourceType) continue;
93
+ if (sr.resourceType.name !== resourceTypeName) continue;
94
+ result.push(createSignedResourceId(sr.resourceId, toResourceSignature(sr.resourceSignature)));
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * Enumerates the recipients of a single resource — the donor-side "who did I
100
+ * share with" view.
101
+ *
102
+ * Takes a signed, writable resource handle: the backend gates grant listing on a
103
+ * signed resource id with writable permission, so only the resource's owner can
104
+ * call it. An everyone-grant surfaces with `user` matching the backend's
105
+ * everyone-sentinel — test with {@link isEveryoneUserLogin} (from "./transaction");
106
+ * the caller maps that to "*".
107
+ *
108
+ * Runs over a read transaction ({@link PlTransaction.listGrants}), so it works on
109
+ * every wire protocol — including REST, where the standalone server-streaming
110
+ * `ListGrants` RPC has no binding.
111
+ */
112
+ async listGrants(resourceId) {
113
+ return (await this.runTx("ListGrants", false, "", (tx) => tx.listGrants(resourceId))).map((grant) => ({
114
+ user: grant.user,
115
+ writable: grant.permissions?.writable ?? false,
116
+ grantedBy: grant.grantedBy,
117
+ grantedAt: Number(grant.grantedAt)
118
+ }));
119
+ }
120
+ /**
121
+ * Lists the logins of users known to the server, for the recipient picker. A user becomes
122
+ * known on first login; provisioned users who have never logged in do not appear. gRPC-only
123
+ * (the underlying {@link LLPlClient.listUsers} has no REST binding) — throws on a
124
+ * REST-connected client, so callers gate on the `userListing:v1` capability.
125
+ */
126
+ async listUsers() {
127
+ return (await this.ll.listUsers()).map((user) => ({ login: user.login }));
128
+ }
75
129
  async getUserRootViaRpc(opts = {}) {
76
130
  const resp = await this.ll.getUserRoot({
77
131
  login: opts.login,