@milaboratories/pl-client 3.15.0 → 3.16.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 (34) hide show
  1. package/dist/core/ll_client.cjs +35 -18
  2. package/dist/core/ll_client.cjs.map +1 -1
  3. package/dist/core/ll_client.d.ts +12 -5
  4. package/dist/core/ll_client.d.ts.map +1 -1
  5. package/dist/core/ll_client.js +35 -18
  6. package/dist/core/ll_client.js.map +1 -1
  7. package/dist/core/transaction.cjs +2 -1
  8. package/dist/core/transaction.cjs.map +1 -1
  9. package/dist/core/transaction.d.ts.map +1 -1
  10. package/dist/core/transaction.js +2 -1
  11. package/dist/core/transaction.js.map +1 -1
  12. package/dist/core/unauth_client.cjs +79 -32
  13. package/dist/core/unauth_client.cjs.map +1 -1
  14. package/dist/core/unauth_client.d.ts +49 -14
  15. package/dist/core/unauth_client.d.ts.map +1 -1
  16. package/dist/core/unauth_client.js +79 -32
  17. package/dist/core/unauth_client.js.map +1 -1
  18. package/dist/index.d.ts +2 -2
  19. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +150 -18
  20. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
  21. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +127 -9
  22. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -1
  23. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +150 -18
  24. package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
  25. package/dist/proto-rest/plapi.d.ts +8 -2
  26. package/dist/proto-rest/plapi.d.ts.map +1 -1
  27. package/package.json +2 -2
  28. package/src/core/ll_client.ts +25 -13
  29. package/src/core/transaction.ts +2 -0
  30. package/src/core/unauth_client.test.ts +69 -1
  31. package/src/core/unauth_client.ts +108 -34
  32. package/src/core/unauth_client_branch.test.ts +416 -5
  33. package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +225 -15
  34. package/src/proto-rest/plapi.ts +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","names":[],"sources":["../../src/core/transaction.ts"],"mappings":";;;;;;;;;;iBAkEiB;;;WAGN,UAAU,QAAQ;;;WAIlB,SAAS;;;iBAIH;EACf;EACA,OAAO;;;iBAIQ;EACf;EACA;;YAGU,mBAAmB;EAAiB,IAAI;EAAY;;;;;;;;;YASpD,qBACP;EAAqB;;EACpB;EAAyB,IAAI;EAAkB;;UAE3C,SAAS;;EAEjB,YAAY;;EAEZ;;YAGU,UAAU,SAAS;YACnB,WAAW,SAAS;YACpB,eAAe,SAAS;YACxB,aAAa,UAAU;YAEvB,iBAAiB,cAAc,kBAAkB;YACjD,cAAc,SAAS;YACvB,SAAS,iBAAiB;wBAEtB,QAAQ,KAAK,SAAS,OAAO;wBAI7B,WAAW,KAAK,SAAS,OAAO;wBAMhC,aAAa,KAAK,SAAS,OAAO;wBAIlC,WAAW,KAAK,cAAc,OAAO;wBAIrC,cAAc,KAAK,SAAS,OAAO;wBASnC,UAAU,KAAK,cAAc;wBAKvB,gBAAgB,KAAK,WAAW,UAAU,QAAQ;iBAMvD;EACf;EACA,mBAAmB;;;iBAIJ;;EAEf;;;;;;qBAOW,kBAAS;YACV,YAAY;;;;;;;qBAQX,aAAI;YACL,OAAO;wBAYH,oBAAoB;wBAoBd,mBAAmB,KAAK,iBAAiB,QAAQ;wBAMvD,MAAM,YAAY,gBAAgB,oBAAoB;;qBAKzD,yBAAyB;EACpC;;;;;;;;;;qBAoBW;mBA4BQ;WACD;WACA;mBACC;mBACA;mBACA;mBACA;mBAjCF;mBACA;;mBAGA;UAET;;;;UAKA;UAEA;WAEQ,SAAO;mBAEN;mBACA;MACN,QAAQ;EAOnB,YACmB,IAAI,iBACL,cACA,mBACC,aAAa,0BACb,gBAAgB,4BAChB,yBAAyB,SAAS,kBAAkB,0BACpD;;;;EAiCZ,MAAM,GAAG,mBAAmB,QAAQ,YAAY,QAAQ,MAAM,QAAQ;UAI/D;UAKN;UAgBA;UAgBM;;UAON;;EAOD,gBAAgB,YAAY;UAO3B;UAIA;UAcA;UAQA;MAIG;;;EAME,UAAM;EAiCN,WAAO;MAwBT,cAAc;EAQlB,gBACL,cACA,MAAM,cACN,yBACA,QAAQ,aACP;EAkBI,aAAa,cAAc,mBAAmB,QAAQ;EACtD,aAAa,cAAc,oBAAoB,QAAQ;UAiBtD;EAmBD,WAAW,MAAM,eAAe;EAUhC,aACL,MAAM,cACN,OAAO,qBACP,QAAQ,aACP;EAoBI,gBACL,MAAM,cACN,OAAO,qBACP,QAAQ,aACP;EAoBI,YACL,MAAM,cACN,MAAM,qBACN,yBACA,QAAQ,aACP;EAoBI,gBAAgB,eAAe,QAAQ,aAAa;EAKpD,kBACL,eACA,oCACA,QAAQ,aACP;EAKI,YAAY,iBAAiB,QAAQ,aAAa;EASlD,gBAAgB,cAAc,KAAK;EAOnC,mBAAmB;EAInB,kBAAkB,eAAe,QAAQ;EAYzC,wBAAwB,eAAe;EAOvC,eAAe,KAAK;EAOpB,eAAe,KAAK,mBAAmB;;EAWjC,gBAAgB,KAAK,gBAAgB,mBAAmB,QAAQ;;EAEhE,gBAAgB,KAAK,gBAAgB,oBAAoB,QAAQ;;EAEjE,gBACX,KAAK,gBACL,sBACC,QAAQ,oBAAoB;;EAElB,gBACX,KAAK,gBACL,kBACA,uBACC,QAAQ;;EAEE,gBACX,KAAK,gBACL,mBACA,uBACC,QAAQ;;EAEE,gBACX,KAAK,gBACL,qBACA,uBACC,QAAQ,oBAAoB;EAyElB,wBACX,KAAK,gBACL,mBACC,QAAQ;EACE,wBACX,KAAK,gBACL,oBACC,QAAQ;EACE,wBACX,KAAK,gBACL,sBACC,QAAQ,oBAAoB;;;;;;;;EA0BxB,WAAW,KAAK;;;;;EAYhB,YAAY,KAAK;EAQjB,KAAK,KAAK;EAKV,iBAAiB,KAAK,gBAAgB,KAAK;;;;;;;;;;;EAoB3C,YACL,KAAK,gBACL,gBACA,aAAa,kBACb,YAAW;;;;;;;EAmBN,aAAa,KAAK,gBAAgB;;;;;;;;;;;;EAqBlC,WAAW,KAAK,iBAAiB,QAAQ;EAWzC,YAAY,KAAK,aAAa,WAAW,WAAW,QAAQ;EAS5D,YAAY,KAAK,cAAc;EAU/B,SAAS,KAAK,aAAa,KAAK;EAwBhC,cAAc,KAAK,aAAa,KAAK;EAWrC,SAAS,KAAK,cAAc,QAAQ;EAQ9B,iBAAiB,KAAK,cAAc,QAAQ;EAIlD,WAAW,KAAK;EAOhB,YAAY,KAAK;EAWX,cAAc,KAAK,iBAAiB,QAAQ;EAsB5C,oBAAoB,KAAK,iBAAiB,QAAQ;EASlD,8BAA8B,KAAK,iBAAiB,QAAQ;EAI5D,oCACX,KAAK,iBACJ,QAAQ;EAIJ,UAAU,KAAK,gBAAgB,aAAa,OAAO;EAanD,aAAa,KAAK,gBAAgB;EAU5B,UAAU,KAAK,gBAAgB,cAAc,QAAQ;EAoBrD,gBAAgB,KAAK,gBAAgB,cAAc;EAInD,cAAc,GAAG,KAAK,gBAAgB,cAAc,QAAQ;EAI5D,kBACX,KAAK,gBACL,cACC,QAAQ;EAqBE,wBACX,KAAK,gBACL,cACC;EAOU,sBAAsB,GAAG,KAAK,gBAAgB,cAAc,QAAQ;;EAkB1E,oBAAoB,KAAK,QAAQ,mBAAmB,WAAW,kBAAkB;EAW3E,iBAAa;;EAMb,YAAQ;;;EAUR,SAAK;;;;;;;;;;;;;;;;;;;;;;EA6BX,aACL,QAAQ,eAAe,qBACvB;IACE,cAAc;IACd,oBAAoB;IACpB;IACA;MAED,cAAc;UAqFT;iBAIO;iBAEA"}
1
+ {"version":3,"file":"transaction.d.ts","names":[],"sources":["../../src/core/transaction.ts"],"mappings":"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"}
@@ -796,7 +796,8 @@ var PlTransaction = class PlTransaction {
796
796
  traverseStopRules: opts?.traverseStopRules,
797
797
  includeKv: opts?.includeKv ?? false,
798
798
  maxDepth: opts?.maxDepth,
799
- showSoftDeletes: false
799
+ showSoftDeletes: false,
800
+ changedSinceToken: /* @__PURE__ */ new Uint8Array(0)
800
801
  }
801
802
  });
802
803
  return { [Symbol.asyncIterator]() {
@@ -1 +1 @@
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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"}
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 // Empty token requests the full tree — this call has no continuation to resume.\n changedSinceToken: new Uint8Array(0),\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":";;;;;;;;;;;AAqHA,SAAgB,QAAQ,KAAiC;CACvD,OAAO,IAAI,eAAe,YAAY,KAAK,IAAI,eAAe,WAAW;AAC3E;AAEA,SAAgB,WAAW,KAAoC;CAC7D,IAAI,OAAO,QAAQ,UAAU,OAAO;CACpC,IAAI,OAAO,QAAQ,UAAU,OAAO;CACpC,OAAO,cAAc,GAAG;AAC1B;AAEA,SAAgB,aAAa,KAAsC;CACjE,OAAO,OAAO,QAAQ,YAAY,mBAAmB,GAAG;AAC1D;AAEA,SAAgB,WAAW,KAAmC;CAC5D,OAAO,cAAc,IAAI,UAAU;AACrC;AAEA,SAAgB,cAAc,KAAiC;CAC7D,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,IAAI,eAAe,UAAU,KAC7B,IAAI,eAAe,SAAS;AAEhC;AAEA,SAAgB,UAAU,KAA8B;CACtD,IAAI,WAAW,GAAG,GAAG,OAAO;EAAE,YAAY,IAAI,WAAW;EAAS,WAAW,IAAI;CAAU;MACtF,OAAO;AACd;AAEA,eAAsB,gBAAgB,KAA2C;CAC/E,IAAI,WAAW,GAAG,GAChB,OAAO;EAAE,YAAY,MAAM,IAAI,WAAW;EAAU,WAAW,IAAI;CAAU;CAC/E,OAAO;AACT;;;;;AAiBA,MAAa,YAAY;;;;;;;AASzB,MAAa,OAAO;;;;;;;;;;AAYpB,MAAM,eAAe;AACrB,SAAgB,oBAAoB,OAAwB;CAC1D,OAAO,UAAU;AACnB;AAEA,MAAM,iBAAiB,oCAAoB,IAAI,WAAW,CAAC,CAAC;AAE5D,SAAS,yBAAyB,KAA8C;CAC9E,IAAI,cAAc,GAAG,GAEnB,OAAO;EAAE,YAAY,IAAI;EAAS,mBAAmB;CAAe;CAEtE,IAAI,aAAa,GAAG,GAAG;EAErB,MAAM,EAAE,UAAU,cAAc,sBAAsB,GAAG;EACzD,OAAO;GAAE,YAAY;GAAoB,mBAAmB;EAAU;CACxE;CAEA,OAAO;EAAE,YAAY;EAAe,mBAAmB;CAAe;AACxE;AAEA,eAAsB,mBAAmB,KAAgD;CACvF,IAAI,cAAc,GAAG,GAAG,OAAO,MAAM,IAAI;CACzC,IAAI,kBAAkB,GAAG,GAAG,OAAO,uBAAuB,GAAG;CAC7D,OAAO;AACT;AAEA,SAAgB,MAAM,YAA4B,WAAgC;CAChF,OAAO;EAAE;EAAY;CAAU;AACjC;;AAGA,IAAa,mBAAb,cAAsC,MAAM;CAC1C,OAAO;AACT;AAEA,eAAe,oBAAuB,IAA8C;CAClF,IAAI;EACF,OAAO,MAAM,GAAG;CAClB,SAAS,GAAG;EACV,IAAI,gBAAgB,CAAC,GAAG,OAAO,KAAA;EAC/B,MAAM;CACR;AACF;;;;;;;;;AAUA,IAAa,gBAAb,MAAa,cAAc;CA4BN;CACD;CACA;CACC;CACA;CACA;CACA;CAjCnB;CACA,YAAqC,cAAc,cAAc;;CAGjE,kBAAmC,KAAK,IAAI;CAE5C,yBAAiC;;;;CAKjC,aAAqB;CAErB,uBAAwC;CAExC,UAA0B,IAAI,eAAe;CAE7C,aAA8B,KAAK,IAAI;CACvC,QAAyB,yBAAyB;CAClD,IAAW,OAAe;EACxB,OAAO;GACL,GAAG,KAAK;GACR,QAAQ,KAAK,IAAI,IAAI,KAAK;EAC5B;CACF;CAEA,YACE,IACA,MACA,UACA,aACA,gBACA,yBACA,wBAAkD,OAClD;EAPiB,KAAA,KAAA;EACD,KAAA,OAAA;EACA,KAAA,WAAA;EACC,KAAA,cAAA;EACA,KAAA,iBAAA;EACA,KAAA,0BAAA;EACA,KAAA,wBAAA;EAGjB,KAAK,aAAa,KAAK,mBACrB;GACE,WAAW;GACX,QAAQ;IACN;IACA;IACA,UAAU,WAAA,IAAA;GAGZ;EACF,IACC,MAAM,SAAS,EAAE,OAAO,IAAI,EAAE,CACjC;EAEA,KAAU,MAAM,KAAK,UAAU;EAG/B,KAAK,WAAW,OAAO,QAAQ;GAC7B,IAAI,CAAC,KAAK,sBACR,QAAQ,KAAK,GAAG;EAEpB,CAAC;EAGD,KAAK,MAAM;CACb;;;;CAKA,MAAgB,mBAAgE;EAC9E,OAAO,KAAK,QAAQ,MAAM,iBAAiB;CAC7C;CAEA,MAAc,0BAAyC;EAErD,MAAM,KAAK,QAAQ,SAAS;CAC9B;CAEA,mBACE,GACA,QACY;EACZ,OAAO,KAAK,QAAQ,MAAM,YAAY;GACpC,MAAM,qBAAqB,KAAK,GAAG,KAAK,GAAG,KAAK;GAEhD,KAAU,QAAQ,MAAM,kBAAkB;GAE1C,MAAM,KAAK,wBAAwB;GAGnC,OAAO,OAAO,MAAM,kBAAkB;EACxC,CAAC;CACH;CAEA,kBACE,GACA,QACY;EACZ,OAAO,KAAK,QAAQ,MAAM,YAAY;GACpC,MAAM,qBAAqB,KAAK,GAAG,KAAK,GAAG,IAAI;GAE/C,KAAU,QAAQ,MAAM,kBAAkB;GAE1C,MAAM,KAAK,wBAAwB;GAGnC,OAAO,OAAO,MAAM,kBAAkB;EACxC,CAAC;CACH;CAEA,MAAc,aACZ,GACe;EACf,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK;CAC7B;;CAGA,cACE,GACM;EACN,KAAU,MAAM,KAAK,aAAa,CAAC,CAAC;CACtC;;CAGA,gBAAuB,YAA8B;EACnD,KAAK,cAAc;GACjB,WAAW;GACX,iBAAiB,EAAE,WAAW;EAChC,CAAC;CACH;CAEA,mBAA2B,KAA8C;EACvE,OAAO,yBAAyB,GAAG;CACrC;CAEA,gBAAwB,KAItB;EACA,MAAM,OAAO,UAAU,GAAG;EAC1B,MAAM,SAAS,yBAAyB,KAAK,UAAU;EACvD,OAAO;GACL,YAAY,OAAO;GACnB,WAAW,KAAK;GAChB,mBAAmB,OAAO;EAC5B;CACF;CAEA,iBAAyB,KAGvB;EACA,MAAM,EAAE,YAAY,sBAAsB,KAAK,mBAAmB,GAAG;EACrE,OAAO;GAAE,iBAAiB;GAAY,wBAAwB;EAAkB;CAClF;CAEA,cAAsB;EACpB,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,4BAA4B;CACnE;CAEA,IAAW,YAAY;EACrB,OAAO,KAAK;CACd;;;CAIA,MAAa,SAAS;EACpB,KAAK,YAAY;EAGjB,KAAK,aAAa;EAElB,IAAI,CAAC,KAAK,UAAU;GAElB,MAAM,iBAAiB,KAAK,MAAM,KAAK,GAAG,SAAS,CAAC;GACpD,MAAM,KAAK,wBAAwB;GACnC,MAAM;GACN,MAAM,KAAK,GAAG,MAAM;EACtB,OAAO;GACL,MAAM,iBAAiB,KAAK,MAC1B,KAAK,mBAAmB;IAAE,WAAW;IAAY,UAAU,CAAC;GAAE,IAAI,MAAM,EAAE,SAAS,OAAO,CAC5F;GAGA,MAAM,iBAAiB,KAAK,MAAM,KAAK,GAAG,SAAS,CAAC;GAIpD,MAAM,KAAK,wBAAwB;GAEnC,IAAI,CAAE,MAAM,gBAAiB,MAAM,IAAI,iBAAiB;GAExD,MAAM;GAGN,MAAM,KAAK,GAAG,MAAM;EACtB;CACF;CAEA,MAAa,UAAU;EACrB,KAAK,YAAY;EAGjB,KAAK,aAAa;EAElB,MAAM,kBAAkB,KAAK,aAAa;GAAE,WAAW;GAAa,WAAW,CAAC;EAAE,CAAC;EACnF,KAAU,MAAM,eAAe;EAE/B,MAAM,iBAAiB,KAAK,MAAM,KAAK,GAAG,SAAS,CAAC;EAIpD,MAAM,KAAK,wBAAwB;EAEnC,MAAM;EACN,MAAM;EACN,MAAM,KAAK,GAAG,MAAM;CACtB;CAMA,IAAW,aAA+B;EACxC,OAAO,8BAA8B,KAAK,WAAW;CACvD;CAMA,gBACE,MACA,MACA,gBAAyB,OACzB,OACa;EACb,OAAO,KAAK,eACV,QACC,aAAa;GACZ,WAAW;GACX,yBAAyB;IACvB;IACA,IAAI;IACJ,MAAM,OAAO,KAAK,IAAI;IACtB;IACA,YAAY,SAAS;GACvB;EACF,KACC,MAAM,EAAE,wBAAwB,aAChC,MAAM,EAAE,wBAAwB,iBACnC;CACF;CAIA,aACE,MACA,aAAsB,MACqB;EAC3C,OAAO,KAAK,mBACV;GACE,WAAW;GACX,sBAAsB;IACpB,MAAM,OAAO,KAAK,IAAI;IACtB;GACF;EACF,IACC,MAAM,gBAAgB,SAAS,EAAE,qBAAqB,QAAQ,CAAC,CAClE;CACF;CAEA,eACE,MACA,KACA,QACA,cACa;EACb,MAAM,UAAU,KAAK,oBAAoB,IAAI;EAE7C,MAAM,WAAW,KAAK,mBAAmB,IAAI,OAAO,IAAI,MAAM;GAG5D,OAAO,uBAFO,OAAO,CAEa,GADtB,eAAe,oBAAoB,aAAa,CAAC,CAAC,IAAI,KAAA,CAC1B;EAC1C,CAAC;EAED,KAAU,MAAM,QAAQ;EAExB,OAAO;GAAE;GAAU;EAAQ;CAC7B;CAEA,WAAkB,MAAiC;EACjD,KAAK,MAAM;EACX,OAAO,KAAK,eACV,OACC,aAAa;GAAE,WAAW;GAAsB,oBAAoB;IAAE;IAAM,IAAI;GAAQ;EAAE,KAC1F,MAAM,EAAE,mBAAmB,aAC3B,MAAM,EAAE,mBAAmB,iBAC9B;CACF;CAEA,aACE,MACA,MACA,OACa;EACb,KAAK,MAAM;EACX,KAAK,MAAM,2BAA2B,MAAM,UAAU;EACtD,OAAO,KAAK,eACV,QACC,aAAa;GACZ,WAAW;GACX,sBAAsB;IACpB;IACA,IAAI;IACJ,MACE,SAAS,KAAA,IAAY,KAAA,IAAY,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,IAAI;IAClF,YAAY,SAAS;GACvB;EACF,KACC,MAAM,EAAE,qBAAqB,aAC7B,MAAM,EAAE,qBAAqB,iBAChC;CACF;CAEA,gBACE,MACA,MACA,OACa;EACb,KAAK,MAAM;EACX,KAAK,MAAM,8BAA8B,MAAM,UAAU;EACzD,OAAO,KAAK,eACV,QACC,aAAa;GACZ,WAAW;GACX,yBAAyB;IACvB;IACA,IAAI;IACJ,MACE,SAAS,KAAA,IAAY,KAAA,IAAY,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,IAAI;IAClF,YAAY,SAAS;GACvB;EACF,KACC,MAAM,EAAE,wBAAwB,aAChC,MAAM,EAAE,wBAAwB,iBACnC;CACF;CAEA,YACE,MACA,MACA,gBAAyB,OACzB,OACa;EACb,KAAK,MAAM;EACX,KAAK,MAAM,0BAA0B,MAAM,UAAU;EACrD,OAAO,KAAK,eACV,QACC,aAAa;GACZ,WAAW;GACX,qBAAqB;IACnB;IACA,IAAI;IACJ,MAAM,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,IAAI;IACrD;IACA,YAAY,SAAS;GACvB;EACF,KACC,MAAM,EAAE,oBAAoB,aAC5B,MAAM,EAAE,oBAAoB,iBAC/B;CACF;CAEA,gBAAuB,MAAe,OAAiC;EACrE,MAAM,WAAW,mBAAmB,IAAI;EACxC,OAAO,KAAK,YAAY,YAAY,UAAU,OAAO,KAAK;CAC5D;CAEA,kBACE,MACA,gBAAoC,OACpC,OACa;EACb,MAAM,EAAE,MAAM,UAAU,cAAc,qBAAqB,MAAM,aAAa;EAC9E,OAAO,KAAK,YAAY,YAAY,eAAe,YAAY,UAAU,OAAO,KAAK;CACvF;CAEA,YAAmB,SAAiB,OAAiC;EACnE,OAAO,KAAK,YACV,mBACA,KAAK,UAAU,EAAE,QAAQ,CAA6B,GACtD,OACA,KACF;CACF;CAEA,gBAAuB,MAAc,KAA2B;EAC9D,KAAK,cAAc;GACjB,WAAW;GACX,iBAAiB;IAAE,GAAG,KAAK,mBAAmB,GAAG;IAAG;GAAK;EAC3D,CAAC;CACH;CAEA,mBAA0B,MAAoB;EAC5C,KAAK,cAAc;GAAE,WAAW;GAAsB,oBAAoB,EAAE,KAAK;EAAE,CAAC;CACtF;CAEA,kBAAyB,MAAyC;EAChE,OAAO,KAAK,mBACV;GAAE,WAAW;GAAmB,iBAAiB,EAAE,KAAK;EAAE,IACzD,MAAM;GACL,MAAM,QAAQ,EAAE,gBAAgB;GAChC,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,yCAAyC;GAE3E,OAAO,uBAAuB,OADlB,oBAAoB,EAAE,gBAAgB,iBACX,CAAC;EAC1C,CACF;CACF;CAEA,wBAA+B,MAAgC;EAC7D,OAAO,KAAK,mBACV;GAAE,WAAW;GAAsB,oBAAoB,EAAE,KAAK;EAAE,IAC/D,MAAM,EAAE,mBAAmB,MAC9B;CACF;CAEA,eAAsB,KAA6B;EACjD,KAAK,cAAc;GACjB,WAAW;GACX,gBAAgB,KAAK,mBAAmB,GAAG;EAC7C,CAAC;CACH;CAEA,eAAsB,KAAyC;EAC7D,OAAO,KAAK,mBACV;GACE,WAAW;GACX,gBAAgB,KAAK,mBAAmB,GAAG;EAC7C,IACC,MAAM,EAAE,eAAe,MAC1B;CACF;CA6BA,MAAa,gBACX,KACA,aAAsB,MACtB,cAAuB,OACoB;EAC3C,OAAO,KAAK,MAAM,YAAY;GAC5B,IAAI,CAAC,eAAe,aAAa,GAAG,GAAG;IAErC,MAAM,YAAY,KAAK,wBAAwB,IAAI,GAAG;IACtD,IAAI,aAAa,UAAU,uBAAuB,KAAK;SACjD,CAAC,YAAY;MACf,KAAK,MAAM;MACX,KAAK,MAAM,sBAAsB,UAAU,UAAU,MAAM,UAAU;MACrE,OAAO,UAAU;KACnB,OAAO,IAAI,UAAU,MAAM;MACzB,KAAK,MAAM;MACX,KAAK,MAAM,sBAAsB,UAAU,UAAU,MAAM,UAAU;MACrE,KAAK,MAAM,uBAAuB,UAAU,KAAK,OAAO;MACxD,OAAO,UAAU;KACnB;;GAEJ;GAEA,MAAM,SAAS,MAAM,KAAK,mBACxB;IACE,WAAW;IACX,aAAa;KACX,GAAG,KAAK,mBAAmB,GAAG;KAClB;KACZ,iBAAiB;IACnB;GACF,IACC,MAAM,gBAAgB,SAAS,EAAE,YAAY,QAAQ,CAAC,CACzD;GAEA,KAAK,MAAM;GACX,KAAK,MAAM,oBAAoB,OAAO,MAAM,UAAU;GACtD,KAAK,MAAM,qBAAqB,OAAO,OAAO;GAI9C,IAAI,aAAa,GAAG,KAAK,KAAK,eAAe,MAAM,GAAG;IACpD,WAAW,MAAM;IACjB,MAAM,YAAY,KAAK,wBAAwB,IAAI,GAAG;IACtD,IAAI;SACE,cAAc,CAAC,UAAU,MAAM;MACjC,UAAU,OAAO;MAEjB,UAAU,uBAAuB,KAAK;KACxC;WACK;KACL,MAAM,YAAY,yBAAyB,MAAM;KACjD,WAAW,SAAS;KACpB,IAAI,YACF,KAAK,wBAAwB,IAAI,KAAK;MACpC;MACA,MAAM;MACN,sBAAsB,KAAK;KAC7B,CAAC;UAED,KAAK,wBAAwB,IAAI,KAAK;MACpC;MACA,MAAM,KAAA;MACN,sBAAsB,KAAK;KAC7B,CAAC;IACL;GACF;GAEA,OAAO;EACT,CAAC;CACH;CAcA,MAAa,wBACX,KACA,aAAsB,MACiC;EACvD,OAAO,KAAK,MAAM,YAAY;GAG5B,MAAM,SAAS,MAAM,oBACnB,YAAY,MAAM,KAAK,gBAAgB,KAAK,YAAY,IAAI,CAC9D;GAGA,IAAI,WAAW,KAAA,KAAa,aAAa,GAAG,GAAG,KAAK,wBAAwB,OAAO,GAAG;GAEtF,OAAO;EACT,CAAC;CACH;;;;;;;;CASA,WAAkB,KAA2B;EAC3C,KAAK,MAAM;EACX,KAAK,cAAc;GACjB,WAAW;GACX,oBAAoB,KAAK,mBAAmB,GAAG;EACjD,CAAC;CACH;;;;;CAMA,YAAmB,KAA2B;EAC5C,KAAK,MAAM;EACX,KAAK,cAAc;GACjB,WAAW;GACX,qBAAqB,KAAK,mBAAmB,GAAG;EAClD,CAAC;CACH;CAEA,KAAY,KAA2B;EACrC,KAAK,WAAW,GAAG;EACnB,KAAK,YAAY,GAAG;CACtB;CAEA,iBAAwB,KAAqB,KAA2B;EACtE,KAAK,cAAc;GACjB,WAAW;GACX,kBAAkB;IAChB,GAAG,KAAK,mBAAmB,GAAG;IAC9B,GAAG,KAAK,iBAAiB,GAAG;GAC9B;EACF,CAAC;CACH;;;;;;;;;;;CAYA,YACE,KACA,QACA,aACA,YAAA,GACM;EACN,KAAK,cAAc;GACjB,WAAW;GACX,aAAa;IACX,GAAG,KAAK,mBAAmB,GAAG;IAC9B,YAAY;IACZ;IACA;GACF;EACF,CAAC;CACH;;;;;;;CAQA,aAAoB,KAAqB,QAAsB;EAC7D,KAAK,cAAc;GACjB,WAAW;GACX,cAAc;IACZ,GAAG,KAAK,mBAAmB,GAAG;IAC9B,YAAY;GACd;EACF,CAAC;CACH;;;;;;;;;;;;CAaA,WAAkB,KAA+C;EAC/D,OAAO,KAAK,mBACV;GAAE,WAAW;GAAc,YAAY,KAAK,mBAAmB,GAAG;EAAE,IACnE,MAAM,EAAE,WAAW,MACtB;CACF;CAMA,YAAmB,KAAkB,WAAsB,OAAsB;EAC/E,KAAK,MAAM;EACX,KAAK,cAAc;GACjB,WAAW;GACX,aAAa;IAAE,MAAM,iBAAiB,SAAS;IAAG,IAAI,KAAK,gBAAgB,GAAG;GAAE;EAClF,CAAC;EACD,IAAI,UAAU,KAAA,GAAW,KAAK,SAAS,KAAK,KAAK;CACnD;CAEA,YAAmB,KAAoC;EACrD,OAAO,KAAK,mBACV;GACE,WAAW;GACX,aAAa,EAAE,OAAO,KAAK,gBAAgB,GAAG,EAAE;EAClD,IACC,MAAM,EAAE,YAAY,MACvB;CACF;CAEA,SAAgB,KAAkB,KAAmB;EACnD,KAAK,MAAM;EACX,IAAI,WAAW,GAAG,GAChB,KAAK,cAAc;GACjB,WAAW;GACX,UAAU;IACR,OAAO,KAAK,gBAAgB,GAAG;IAC/B,OAAO;KACL,GAAG,KAAK,mBAAmB,GAAG;KAC9B,WAAW;IACb;GACF;EACF,CAAC;OAED,KAAK,cAAc;GACjB,WAAW;GACX,UAAU;IACR,OAAO,KAAK,gBAAgB,GAAG;IAC/B,OAAO,KAAK,gBAAgB,GAAG;GACjC;EACF,CAAC;CAEL;CAEA,cAAqB,KAAkB,KAA2B;EAChE,KAAK,MAAM;EACX,KAAK,cAAc;GACjB,WAAW;GACX,eAAe;IACb,OAAO,KAAK,gBAAgB,GAAG;IAC/B,GAAG,KAAK,iBAAiB,GAAG;GAC9B;EACF,CAAC;CACH;CAEA,SAAgB,KAAsC;EACpD,KAAK,MAAM;EACX,OAAO,KAAK,mBACV;GAAE,WAAW;GAAY,UAAU,EAAE,OAAO,KAAK,gBAAgB,GAAG,EAAE;EAAE,IACvE,MAAM,aAAa,SAAS,EAAE,SAAS,KAAK,CAAC,CAChD;CACF;CAEA,MAAa,iBAAiB,KAAkD;EAC9E,OAAO,KAAK,MAAM,oBAAoB,YAAY,MAAM,KAAK,SAAS,GAAG,CAAC,CAAC;CAC7E;CAEA,WAAkB,KAAwB;EACxC,KAAK,cAAc;GACjB,WAAW;GACX,YAAY,EAAE,OAAO,KAAK,gBAAgB,GAAG,EAAE;EACjD,CAAC;CACH;CAEA,YAAmB,KAAwB;EACzC,KAAK,cAAc;GACjB,WAAW;GACX,aAAa,EAAE,OAAO,KAAK,gBAAgB,GAAG,EAAE;EAClD,CAAC;CACH;CAMA,MAAa,cAAc,KAA0C;EACnE,OAAO,KAAK,MAAM,YAAY;GAC5B,MAAM,SAAS,MAAM,KAAK,kBACxB;IACE,WAAW;IACX,sBAAsB;KACpB,GAAG,KAAK,mBAAmB,GAAG;KAC9B,WAAW;KACX,OAAO;IACT;GACF,IACC,MAAM,EAAE,KAAK,MAAM,EAAE,qBAAqB,MAAO,CACpD;GAEA,KAAK,MAAM;GACX,KAAK,MAAM,iBAAiB,OAAO;GACnC,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,eAAe,GAAG,IAAI,SAAS,GAAG,MAAM;GAE5E,OAAO;EACT,CAAC;CACH;CAEA,MAAa,oBAAoB,KAAgD;EAC/E,OAAO,KAAK,MAAM,aACf,MAAM,KAAK,cAAc,GAAG,EAAA,CAAG,KAAK,EAAE,KAAK,aAAa;GACvD;GACA,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS;EACrC,EAAE,CACJ;CACF;CAEA,MAAa,8BAA8B,KAAsD;EAC/F,OAAO,KAAK,MAAM,oBAAoB,YAAY,MAAM,KAAK,cAAc,GAAG,CAAC,CAAC;CAClF;CAEA,MAAa,oCACX,KACuC;EACvC,OAAO,KAAK,MAAM,oBAAoB,YAAY,MAAM,KAAK,oBAAoB,GAAG,CAAC,CAAC;CACxF;CAEA,UAAiB,KAAqB,KAAa,OAAkC;EACnF,KAAK,MAAM;EACX,KAAK,MAAM;EACX,KAAK,cAAc;GACjB,WAAW;GACX,qBAAqB;IACnB,GAAG,KAAK,mBAAmB,GAAG;IAC9B;IACA,OAAO,QAAQ,KAAK;GACtB;EACF,CAAC;CACH;CAEA,aAAoB,KAAqB,KAAmB;EAC1D,KAAK,cAAc;GACjB,WAAW;GACX,wBAAwB;IACtB,GAAG,KAAK,mBAAmB,GAAG;IAC9B;GACF;EACF,CAAC;CACH;CAEA,MAAa,UAAU,KAAqB,KAAkC;EAC5E,OAAO,KAAK,MAAM,YAAY;GAC5B,MAAM,SAAS,MAAM,KAAK,mBACxB;IACE,WAAW;IACX,qBAAqB;KACnB,GAAG,KAAK,mBAAmB,GAAG;KAC9B;IACF;GACF,IACC,MAAM,EAAE,oBAAoB,KAC/B;GAEA,KAAK,MAAM;GACX,KAAK,MAAM,cAAc,OAAO;GAEhC,OAAO;EACT,CAAC;CACH;CAEA,MAAa,gBAAgB,KAAqB,KAA8B;EAC9E,OAAO,KAAK,MAAM,YAAY,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;CACtF;CAEA,MAAa,cAAiB,KAAqB,KAAyB;EAC1E,OAAO,KAAK,MAAM,YAAY,KAAK,MAAM,MAAM,KAAK,gBAAgB,KAAK,GAAG,CAAC,CAAM;CACrF;CAEA,MAAa,kBACX,KACA,KACiC;EACjC,OAAO,KAAK,MAAM,YAAY;GAC5B,MAAM,SAAS,MAAM,KAAK,mBACxB;IACE,WAAW;IACX,6BAA6B;KAC3B,GAAG,KAAK,mBAAmB,GAAG;KAC9B;IACF;GACF,IACC,MACC,EAAE,4BAA4B,SAAS,EAAE,4BAA4B,QAAQ,KAAA,CACjF;GAEA,KAAK,MAAM;GACX,KAAK,MAAM,cAAc,QAAQ,UAAU;GAE3C,OAAO;EACT,CAAC;CACH;CAEA,MAAa,wBACX,KACA,KAC6B;EAC7B,OAAO,KAAK,MAAM,YAAY;GAC5B,MAAM,OAAO,MAAM,KAAK,kBAAkB,KAAK,GAAG;GAClD,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS;EACrE,CAAC;CACH;CAEA,MAAa,sBAAyB,KAAqB,KAAqC;EAC9F,OAAO,KAAK,MAAM,YAAY;GAC5B,MAAM,MAAM,MAAM,KAAK,wBAAwB,KAAK,GAAG;GACvD,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;GAC9B,OAAO,KAAK,MAAM,GAAG;EACvB,CAAC;CACH;;CAYA,oBAA2B,KAAa,WAAmB,WAAsC;EAC/F,MAAM,OAAO,OAAO,KAAK,KAAK,UAAU;GAAE;GAAW;EAAU,CAAC,CAAC;EACjE,MAAM,mBAAmB,KAAK,gBAAgB;GAAE,MAAM;GAAiB,SAAS;EAAI,GAAG,IAAI;EAC3F,KAAK,SAAS;GAAE,YAAY;GAAkB,WAAW;EAAW,GAAG,GAAG;EAC1E,OAAO;GAAE,YAAY;GAAkB,WAAW;EAAS;CAC7D;CAMA,MAAa,gBAAgB;EAC3B,KAAK,uBAAuB;EAC5B,OAAO,MAAM,KAAK;CACpB;;CAGA,MAAa,WAAW;EACtB,IAAI,KAAK,YAAY;EACrB,KAAK,aAAa;EAClB,MAAM,iBAAiB,KAAK,MAAM,KAAK,GAAG,SAAS,CAAC;EACpD,MAAM,KAAK,wBAAwB;EACnC,MAAM;CACR;;;CAIA,MAAa,QAAQ;EACnB,MAAM,KAAK,GAAG,MAAM;CACtB;;;;;;;;;;;;;;;;;;;;;;CA2BA,aACE,OACA,MAMkC;EAClC,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,MAAM,kDAAkD;EAGpE,MAAM,aAAa,MAAM,KAAK,SAAwC;GAEpE,MAAM,EAAE,UAAU,cAAc,sBADf,OAAO,SAAS,WAAW,OAAO,KAAK,EACM;GAC9D,OAAO;IAAE,YAAY;IAAU,mBAAmB;GAAU;EAC9D,CAAC;EAED,MAAM,YAAY,WAAW;EAE7B,MAAM,iBAAiB,KAAK,GAAG,WAAW;GACxC,WAAW;GACX,cAAc;IAEZ,YAAY,WAAW,cAAc;IACrC,mBAAmB,WAAW,qCAAqB,IAAI,WAAW,CAAC;IACnE,OAAO;IACP,aAAa,MAAM;IACnB,mBAAmB,MAAM;IACzB,WAAW,MAAM,aAAa;IAC9B,UAAU,MAAM;IAChB,iBAAiB;IAEjB,mCAAmB,IAAI,WAAW,CAAC;GACrC;EACF,CAAC;EAED,OAAO,EACL,CAAC,OAAO,iBAAmD;GACzD,MAAM,WAAW,eAAe,OAAO,cAAc,CAAC;GAEtD,OAAO;IACL,MAAM,OAAmD;KACvD,OAAO,MAAM;MACX,MAAM,OAAO,MAAM,SAAS,KAAK;MACjC,IAAI,KAAK,MAAM,OAAO;OAAE,OAAO,KAAA;OAAW,MAAM;MAAK;MAErD,MAAM,QAAQ,KAAK,MAAM;MACzB,IAAI,UAAU,KAAA,GAAW;MAEzB,IAAI,MAAM,YAAY,kBAAkB,MAAM,QAAQ,GACpD;MAGF,IAAI,CAAC,MAAM,UAMT,OAAO;OACL,OAAO;QAAE,WAAW;QAAc,IALzB,uBACT,MAAM,YACN,oBAAoB,MAAM,iBAAiB,CAGR;QAAG,oBAAoB;OAAK;OAC/D,MAAM;MACR;MAGF,OAAO;OACL,OAAO;QACL,WAAW;QACX,GAAG,gBAAgB,MAAM,QAAQ;QACjC,IAAI,MAAM;QACV,oBAAoB,MAAM;OAC5B;OACA,MAAM;MACR;KACF;IACF;IACA,MAAM,SAAqD;KACzD,IAAI,SAAS,QAAQ,MAAM,SAAS,OAAO;KAC3C,OAAO;MAAE,OAAO,KAAA;MAAW,MAAM;KAAK;IACxC;IACA,MAAM,MAAM,OAA6D;KACvE,IAAI,SAAS,OAAO,MAAM,SAAS,MAAM,KAAK;KAC9C,MAAM;IACR;GACF;EACF,EACF;CACF;CAMA,oBAA4B,MAAgC;EAC1D,OAAO,sBAAsB,MAAM,EAAE,KAAK,wBAAwB,KAAK,SAAS;CAClF;CAEA,OAAe,mBAAmB;CAElC,OAAe,gBAAgB;EAC7B,cAAc;EACd,IAAI,cAAc,qBAAA,YAA8B,cAAc,mBAAmB;EACjF,OAAO,cAAc;CACvB;AACF"}
@@ -26,7 +26,9 @@ var UnauthenticatedPlClient = class UnauthenticatedPlClient {
26
26
  }
27
27
  /** Classifies the advertised authentication methods by credential scheme.
28
28
  * On legacy backends (no auth:v2) the typed oneof is empty; callers fall through to {@link login}
29
- * which uses the legacy GetJWTToken path. SSO is surfaced via {@link ssoConfig}, not here. */
29
+ * which uses the legacy GetJWTToken path.
30
+ * @deprecated collapses every basic-kind method into one boolean; use {@link loginMethods} to
31
+ * see each advertised method's own id. `login()` still reads this to choose the credential path. */
30
32
  get supportedAuthSchemes() {
31
33
  const result = {
32
34
  basic: false,
@@ -36,46 +38,87 @@ var UnauthenticatedPlClient = class UnauthenticatedPlClient {
36
38
  else if (m.method.oneofKind === "token") result.token = true;
37
39
  return result;
38
40
  }
41
+ /** Builds the {@link SSOAuthMethod} projection an advertised SSO entry carries, or `undefined`
42
+ * for a flow no client here can drive. Shared by {@link ssoConfig} and {@link loginMethods},
43
+ * which each apply their own rule for an unsupported flow. */
44
+ toSSOAuthMethod(method) {
45
+ if (method.method.oneofKind !== "sso") return void 0;
46
+ const sso = method.method.sso;
47
+ if (sso.flowType !== 0) return void 0;
48
+ return {
49
+ id: method.id,
50
+ title: method.title || method.description || method.id,
51
+ description: method.description,
52
+ issuer: sso.issuer,
53
+ clientId: sso.clientId,
54
+ scopes: sso.scopes,
55
+ resource: sso.resource,
56
+ prompt: sso.prompt,
57
+ redirectPorts: sso.redirectPorts,
58
+ subjectTokenSource: sso.subjectTokenSource,
59
+ userIdClaim: sso.userIdClaim,
60
+ groupsClaim: sso.groupsClaim,
61
+ accessType: sso.accessType || void 0,
62
+ flowType: "public_pkce"
63
+ };
64
+ }
39
65
  /** Projection of the first advertised SSO method, derived from {@link authMethodsSync}.
40
- * v1: at most one SSO method per deployment, so callers do not need to discriminate. */
66
+ * v1: at most one SSO method per deployment, so callers do not need to discriminate.
67
+ * @deprecated surfaces only the first advertised SSO method; use {@link loginMethods} to see
68
+ * every advertised method, of every kind. */
41
69
  ssoConfig() {
42
70
  for (const method of this.ll.authMethodsSync.methods) {
43
71
  if (method.method.oneofKind !== "sso") continue;
44
72
  const sso = method.method.sso;
45
73
  if (sso.flowType !== 0) throw new Error(`ssoConfig: unsupported SSO flow type ${sso.flowType}`);
46
- return {
47
- id: method.id,
48
- description: method.description,
49
- issuer: sso.issuer,
50
- clientId: sso.clientId,
51
- scopes: sso.scopes,
52
- resource: sso.resource,
53
- prompt: sso.prompt,
54
- redirectPorts: sso.redirectPorts,
55
- subjectTokenSource: sso.subjectTokenSource,
56
- userIdClaim: sso.userIdClaim,
57
- groupsClaim: sso.groupsClaim,
58
- accessType: sso.accessType || void 0,
59
- flowType: "public_pkce"
60
- };
74
+ return this.toSSOAuthMethod(method);
75
+ }
76
+ }
77
+ /** Every login method the backend advertises, of every kind, in advertised order, each
78
+ * keeping its own `id`, `title`, `description` and kind. An entry with no usable method arm, or an
79
+ * SSO entry whose flow no client here can drive, is dropped rather than failing the whole
80
+ * list, which is why this accessor skips where {@link ssoConfig} throws. */
81
+ loginMethods() {
82
+ const picked = [];
83
+ for (const method of this.ll.authMethodsSync.methods) switch (method.method.oneofKind) {
84
+ case "basic":
85
+ case "token":
86
+ picked.push({
87
+ kind: method.method.oneofKind,
88
+ id: method.id,
89
+ title: method.title || method.description || method.id,
90
+ description: method.description
91
+ });
92
+ break;
93
+ case "sso": {
94
+ const sso = this.toSSOAuthMethod(method);
95
+ if (sso !== void 0) picked.push({
96
+ kind: "sso",
97
+ ...sso
98
+ });
99
+ break;
100
+ }
101
+ default: break;
61
102
  }
103
+ return picked;
62
104
  }
63
- /** Login with username+password.
105
+ /** Login with username and password.
64
106
  *
65
- * On auth:v2 backends the client inspects the advertised AuthMethods:
66
- * - if basic auth is offered, sends {@link LLPlClient.loginBasic};
67
- * - if only token auth is offered, treats `password` as an opaque bearer token and
68
- * sends {@link LLPlClient.loginWithToken} (so deployments configured for static-token
69
- * auth still log in without the caller switching methods).
107
+ * Routes to {@link LLPlClient.loginBasic} or {@link LLPlClient.loginWithToken} based on the
108
+ * advertised method `idP` names. On legacy backends, uses GetJWTToken with Basic header.
70
109
  *
71
- * On legacy backends (no auth:v2) it falls through to GetJWTToken with the Basic header,
72
- * preserving original behavior. */
73
- async login(user, password) {
110
+ * `idP` names the advertised method. A named basic-kind method routes to the basic branch;
111
+ * a named token-kind method routes to the token branch even when the backend also advertises
112
+ * a basic method — the token wire carries no selector, so the id itself is dropped there and
113
+ * only the branch choice is kept. Omitted, or naming no advertised method, falls back to
114
+ * today's first-match behavior: basic wins over token when both are advertised. */
115
+ async login(user, password, idP) {
74
116
  try {
75
117
  let token;
76
118
  if (this.ll.hasCapability("auth:v2")) {
77
119
  const schemes = this.supportedAuthSchemes;
78
- if (schemes.basic) token = await this.ll.loginBasic(user, password);
120
+ if ((idP === void 0 ? void 0 : this.loginMethods().find((m) => m.id === idP)?.kind) === "token") token = await this.ll.loginWithToken(password);
121
+ else if (schemes.basic) token = idP === void 0 ? await this.ll.loginBasic(user, password) : await this.ll.loginBasic(user, password, { idP });
79
122
  else if (schemes.token) token = await this.ll.loginWithToken(password);
80
123
  else throw new Error("backend advertises no supported authentication methods");
81
124
  } else token = await this.ll.getJwtToken(BigInt(this.ll.conf.authTTLSeconds), { authorization: "Basic " + Buffer.from(user + ":" + password).toString("base64") });
@@ -88,9 +131,11 @@ var UnauthenticatedPlClient = class UnauthenticatedPlClient {
88
131
  }
89
132
  }
90
133
  /** Request fresh server-issued login material. v1 only emits the public-PKCE flow;
91
- * desktop MUST place the returned `nonce` verbatim into the OIDC auth-request. */
92
- async beginSSOLogin() {
93
- const attempt = await this.ll.beginSSOLogin();
134
+ * desktop MUST place the returned `nonce` verbatim into the OIDC auth-request. `idP` names
135
+ * the advertised SSO method to route to; omitted, the backend keeps its current first-match
136
+ * behaviour. */
137
+ async beginSSOLogin(idP) {
138
+ const attempt = idP === void 0 ? await this.ll.beginSSOLogin() : await this.ll.beginSSOLogin(idP);
94
139
  return {
95
140
  flow: "public_pkce",
96
141
  nonce: attempt.nonce,
@@ -98,10 +143,12 @@ var UnauthenticatedPlClient = class UnauthenticatedPlClient {
98
143
  clientSecret: attempt.clientSecret
99
144
  };
100
145
  }
101
- /** Forward the verbatim IdP `/token` response body and receive a Platforma JWT. */
146
+ /** Forward the verbatim IdP `/token` response body and receive a Platforma JWT. `idP` names
147
+ * the advertised SSO method to route to; omitted, the backend keeps its current first-match
148
+ * behaviour. */
102
149
  async loginSSO(payload) {
103
150
  try {
104
- const jwtToken = await this.ll.loginSSO(payload.tokenResponse);
151
+ const jwtToken = payload.idP === void 0 ? await this.ll.loginSSO(payload.tokenResponse) : await this.ll.loginSSO(payload.tokenResponse, payload.idP);
105
152
  if (jwtToken === "") throw new Error("empty token");
106
153
  return { jwtToken };
107
154
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"unauth_client.cjs","names":["LLPlClient","UnauthenticatedError"],"sources":["../../src/core/unauth_client.ts"],"sourcesContent":["import type { AuthInformation, PlClientConfig } from \"./config\";\nimport {\n type AuthAPI_ListMethods_Response,\n type MaintenanceAPI_Ping_Response,\n AuthAPI_ListMethods_SSOAuthMethod_FlowType,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { LLPlClient } from \"./ll_client\";\nimport { type MiLogger, notEmpty } from \"@milaboratories/ts-helpers\";\nimport { UnauthenticatedError } from \"./errors\";\nimport type { BackendCapability } from \"./capabilities\";\n\n/** Login-flow shape advertised by the backend for a given SSO method. Extension\n * point: future flow variants (e.g. backend-driven) sit alongside `public_pkce`. */\nexport type SSOFlowType = \"public_pkce\";\n\n/** Typed projection of `AuthAPI.ListMethods.SSOAuthMethod` for desktop consumption.\n * Carries everything needed to drive the PKCE flow + diagnostics fields the renderer\n * may surface (`userIdClaim`, `groupsClaim`). */\nexport type SSOAuthMethod = {\n id: string;\n description: string;\n issuer: string;\n clientId: string;\n scopes: string;\n resource: string;\n prompt: string;\n redirectPorts: number[];\n subjectTokenSource: string;\n userIdClaim: string;\n groupsClaim: string;\n flowType: SSOFlowType;\n /** OIDC `access_type` auth-request param (\"online\" | \"offline\"). Google-specific:\n * \"offline\" makes Google issue a refresh token; other IdPs ignore it. Absent when\n * the server does not set it — never send an empty string to the IdP. */\n accessType?: string;\n};\n\n/** Server-issued material returned by {@link UnauthenticatedPlClient.beginSSOLogin}.\n * Discriminated on `flow`; future flow variants extend the union. */\nexport type SSOLoginAttempt = {\n flow: \"public_pkce\";\n nonce: string;\n expiresAt: Date;\n /** Confidential-client secret for the IdP token exchange; absent for public clients.\n * Google's OIDC has no public-client mode — it requires a client_secret at the token\n * endpoint even with PKCE — so for Google the backend forwards its secret here and the\n * desktop exchanges the code as a confidential client. */\n clientSecret?: string;\n};\n\n/** Primarily used for initial authentication (login) */\nexport class UnauthenticatedPlClient {\n public readonly ll: LLPlClient;\n\n private constructor(ll: LLPlClient) {\n this.ll = ll;\n }\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops?: { logger?: MiLogger },\n ): Promise<UnauthenticatedPlClient> {\n const ll = await LLPlClient.build(configOrAddress, ops);\n return new UnauthenticatedPlClient(ll);\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async authMethods(): Promise<AuthAPI_ListMethods_Response> {\n return await this.ll.authMethods();\n }\n\n public async requireAuth(): Promise<boolean> {\n return (await this.authMethods()).methods.length > 0;\n }\n\n public hasCapability(capability: BackendCapability): boolean {\n return this.ll.hasCapability(capability);\n }\n\n /** Classifies the advertised authentication methods by credential scheme.\n * On legacy backends (no auth:v2) the typed oneof is empty; callers fall through to {@link login}\n * which uses the legacy GetJWTToken path. SSO is surfaced via {@link ssoConfig}, not here. */\n public get supportedAuthSchemes(): { basic: boolean; token: boolean } {\n const result = { basic: false, token: false };\n for (const m of this.ll.authMethodsSync.methods) {\n if (m.method.oneofKind === \"basic\") result.basic = true;\n else if (m.method.oneofKind === \"token\") result.token = true;\n }\n return result;\n }\n\n /** Projection of the first advertised SSO method, derived from {@link authMethodsSync}.\n * v1: at most one SSO method per deployment, so callers do not need to discriminate. */\n public ssoConfig(): SSOAuthMethod | undefined {\n for (const method of this.ll.authMethodsSync.methods) {\n if (method.method.oneofKind !== \"sso\") continue;\n const sso = method.method.sso;\n if (sso.flowType !== AuthAPI_ListMethods_SSOAuthMethod_FlowType.PUBLIC_PKCE) {\n throw new Error(`ssoConfig: unsupported SSO flow type ${sso.flowType}`);\n }\n return {\n id: method.id,\n description: method.description,\n issuer: sso.issuer,\n clientId: sso.clientId,\n scopes: sso.scopes,\n resource: sso.resource,\n prompt: sso.prompt,\n redirectPorts: sso.redirectPorts,\n subjectTokenSource: sso.subjectTokenSource,\n userIdClaim: sso.userIdClaim,\n groupsClaim: sso.groupsClaim,\n accessType: sso.accessType || undefined,\n flowType: \"public_pkce\",\n };\n }\n return undefined;\n }\n\n /** Login with username+password.\n *\n * On auth:v2 backends the client inspects the advertised AuthMethods:\n * - if basic auth is offered, sends {@link LLPlClient.loginBasic};\n * - if only token auth is offered, treats `password` as an opaque bearer token and\n * sends {@link LLPlClient.loginWithToken} (so deployments configured for static-token\n * auth still log in without the caller switching methods).\n *\n * On legacy backends (no auth:v2) it falls through to GetJWTToken with the Basic header,\n * preserving original behavior. */\n public async login(user: string, password: string): Promise<AuthInformation> {\n try {\n let token: string;\n if (this.ll.hasCapability(\"auth:v2\")) {\n const schemes = this.supportedAuthSchemes;\n if (schemes.basic) {\n token = await this.ll.loginBasic(user, password);\n } else if (schemes.token) {\n token = await this.ll.loginWithToken(password);\n } else {\n throw new Error(\"backend advertises no supported authentication methods\");\n }\n } else {\n token = await this.ll.getJwtToken(BigInt(this.ll.conf.authTTLSeconds), {\n authorization: \"Basic \" + Buffer.from(user + \":\" + password).toString(\"base64\"),\n });\n }\n const jwtToken = notEmpty(token);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n\n /** Request fresh server-issued login material. v1 only emits the public-PKCE flow;\n * desktop MUST place the returned `nonce` verbatim into the OIDC auth-request. */\n public async beginSSOLogin(): Promise<SSOLoginAttempt> {\n const attempt = await this.ll.beginSSOLogin();\n return {\n flow: \"public_pkce\",\n nonce: attempt.nonce,\n expiresAt: attempt.expiresAt,\n clientSecret: attempt.clientSecret,\n };\n }\n\n /** Forward the verbatim IdP `/token` response body and receive a Platforma JWT. */\n public async loginSSO(payload: { tokenResponse: Uint8Array }): Promise<AuthInformation> {\n try {\n const jwtToken = await this.ll.loginSSO(payload.tokenResponse);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"unauth_client.cjs","names":["LLPlClient","UnauthenticatedError"],"sources":["../../src/core/unauth_client.ts"],"sourcesContent":["import type { AuthInformation, PlClientConfig } from \"./config\";\nimport {\n type AuthAPI_ListMethods_Response,\n type MaintenanceAPI_Ping_Response,\n AuthAPI_ListMethods_SSOAuthMethod_FlowType,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { LLPlClient } from \"./ll_client\";\nimport { type MiLogger, notEmpty } from \"@milaboratories/ts-helpers\";\nimport { UnauthenticatedError } from \"./errors\";\nimport type { BackendCapability } from \"./capabilities\";\n\n/** Login-flow shape advertised by the backend for a given SSO method. Extension\n * point: future flow variants (e.g. backend-driven) sit alongside `public_pkce`. */\nexport type SSOFlowType = \"public_pkce\";\n\n/** Typed projection of `AuthAPI.ListMethods.SSOAuthMethod` for desktop consumption.\n * Carries everything needed to drive the PKCE flow + diagnostics fields the renderer\n * may surface (`userIdClaim`, `groupsClaim`). */\nexport type SSOAuthMethod = {\n id: string;\n title: string;\n description: string;\n issuer: string;\n clientId: string;\n scopes: string;\n resource: string;\n prompt: string;\n redirectPorts: number[];\n subjectTokenSource: string;\n userIdClaim: string;\n groupsClaim: string;\n flowType: SSOFlowType;\n /** OIDC `access_type` auth-request param (\"online\" | \"offline\"). Google-specific:\n * \"offline\" makes Google issue a refresh token; other IdPs ignore it. Absent when\n * the server does not set it — never send an empty string to the IdP. */\n accessType?: string;\n};\n\n/** Server-issued material returned by {@link UnauthenticatedPlClient.beginSSOLogin}.\n * Discriminated on `flow`; future flow variants extend the union. */\nexport type SSOLoginAttempt = {\n flow: \"public_pkce\";\n nonce: string;\n expiresAt: Date;\n /** Confidential-client secret for the IdP token exchange; absent for public clients.\n * Google's OIDC has no public-client mode — it requires a client_secret at the token\n * endpoint even with PKCE — so for Google the backend forwards its secret here and the\n * desktop exchanges the code as a confidential client. */\n clientSecret?: string;\n};\n\n/** One login method the backend advertises, of any kind. Every advertised method keeps its own\n * `id`, `title`, `description` and kind. Two same-kind methods, such as two LDAP directories, are\n * two entries a caller can name apart and never collapsed into one. See {@link UnauthenticatedPlClient.loginMethods}. */\nexport type LoginMethod =\n | { kind: \"basic\"; id: string; title: string; description: string }\n | { kind: \"token\"; id: string; title: string; description: string }\n | ({ kind: \"sso\" } & SSOAuthMethod);\n\n/** Primarily used for initial authentication (login) */\nexport class UnauthenticatedPlClient {\n public readonly ll: LLPlClient;\n\n private constructor(ll: LLPlClient) {\n this.ll = ll;\n }\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops?: { logger?: MiLogger },\n ): Promise<UnauthenticatedPlClient> {\n const ll = await LLPlClient.build(configOrAddress, ops);\n return new UnauthenticatedPlClient(ll);\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async authMethods(): Promise<AuthAPI_ListMethods_Response> {\n return await this.ll.authMethods();\n }\n\n public async requireAuth(): Promise<boolean> {\n return (await this.authMethods()).methods.length > 0;\n }\n\n public hasCapability(capability: BackendCapability): boolean {\n return this.ll.hasCapability(capability);\n }\n\n /** Classifies the advertised authentication methods by credential scheme.\n * On legacy backends (no auth:v2) the typed oneof is empty; callers fall through to {@link login}\n * which uses the legacy GetJWTToken path.\n * @deprecated collapses every basic-kind method into one boolean; use {@link loginMethods} to\n * see each advertised method's own id. `login()` still reads this to choose the credential path. */\n public get supportedAuthSchemes(): { basic: boolean; token: boolean } {\n const result = { basic: false, token: false };\n for (const m of this.ll.authMethodsSync.methods) {\n if (m.method.oneofKind === \"basic\") result.basic = true;\n else if (m.method.oneofKind === \"token\") result.token = true;\n }\n return result;\n }\n\n /** Builds the {@link SSOAuthMethod} projection an advertised SSO entry carries, or `undefined`\n * for a flow no client here can drive. Shared by {@link ssoConfig} and {@link loginMethods},\n * which each apply their own rule for an unsupported flow. */\n private toSSOAuthMethod(\n method: AuthAPI_ListMethods_Response[\"methods\"][number],\n ): SSOAuthMethod | undefined {\n if (method.method.oneofKind !== \"sso\") return undefined;\n const sso = method.method.sso;\n if (sso.flowType !== AuthAPI_ListMethods_SSOAuthMethod_FlowType.PUBLIC_PKCE) return undefined;\n return {\n id: method.id,\n title: method.title || method.description || method.id,\n description: method.description,\n issuer: sso.issuer,\n clientId: sso.clientId,\n scopes: sso.scopes,\n resource: sso.resource,\n prompt: sso.prompt,\n redirectPorts: sso.redirectPorts,\n subjectTokenSource: sso.subjectTokenSource,\n userIdClaim: sso.userIdClaim,\n groupsClaim: sso.groupsClaim,\n accessType: sso.accessType || undefined,\n flowType: \"public_pkce\",\n };\n }\n\n /** Projection of the first advertised SSO method, derived from {@link authMethodsSync}.\n * v1: at most one SSO method per deployment, so callers do not need to discriminate.\n * @deprecated surfaces only the first advertised SSO method; use {@link loginMethods} to see\n * every advertised method, of every kind. */\n public ssoConfig(): SSOAuthMethod | undefined {\n for (const method of this.ll.authMethodsSync.methods) {\n if (method.method.oneofKind !== \"sso\") continue;\n const sso = method.method.sso;\n if (sso.flowType !== AuthAPI_ListMethods_SSOAuthMethod_FlowType.PUBLIC_PKCE) {\n throw new Error(`ssoConfig: unsupported SSO flow type ${sso.flowType}`);\n }\n return this.toSSOAuthMethod(method);\n }\n return undefined;\n }\n\n /** Every login method the backend advertises, of every kind, in advertised order, each\n * keeping its own `id`, `title`, `description` and kind. An entry with no usable method arm, or an\n * SSO entry whose flow no client here can drive, is dropped rather than failing the whole\n * list, which is why this accessor skips where {@link ssoConfig} throws. */\n public loginMethods(): LoginMethod[] {\n const picked: LoginMethod[] = [];\n for (const method of this.ll.authMethodsSync.methods) {\n switch (method.method.oneofKind) {\n case \"basic\":\n case \"token\":\n picked.push({\n kind: method.method.oneofKind,\n id: method.id,\n title: method.title || method.description || method.id,\n description: method.description,\n });\n break;\n case \"sso\": {\n const sso = this.toSSOAuthMethod(method);\n if (sso !== undefined) picked.push({ kind: \"sso\", ...sso });\n break;\n }\n default:\n // No arm at all — a legacy backend advertising nothing pickable.\n break;\n }\n }\n return picked;\n }\n\n /** Login with username and password.\n *\n * Routes to {@link LLPlClient.loginBasic} or {@link LLPlClient.loginWithToken} based on the\n * advertised method `idP` names. On legacy backends, uses GetJWTToken with Basic header.\n *\n * `idP` names the advertised method. A named basic-kind method routes to the basic branch;\n * a named token-kind method routes to the token branch even when the backend also advertises\n * a basic method — the token wire carries no selector, so the id itself is dropped there and\n * only the branch choice is kept. Omitted, or naming no advertised method, falls back to\n * today's first-match behavior: basic wins over token when both are advertised. */\n public async login(user: string, password: string, idP?: string): Promise<AuthInformation> {\n try {\n let token: string;\n if (this.ll.hasCapability(\"auth:v2\")) {\n const schemes = this.supportedAuthSchemes;\n const namedKind =\n idP === undefined ? undefined : this.loginMethods().find((m) => m.id === idP)?.kind;\n if (namedKind === \"token\") {\n token = await this.ll.loginWithToken(password);\n } else if (schemes.basic) {\n token =\n idP === undefined\n ? await this.ll.loginBasic(user, password)\n : await this.ll.loginBasic(user, password, { idP });\n } else if (schemes.token) {\n token = await this.ll.loginWithToken(password);\n } else {\n throw new Error(\"backend advertises no supported authentication methods\");\n }\n } else {\n token = await this.ll.getJwtToken(BigInt(this.ll.conf.authTTLSeconds), {\n authorization: \"Basic \" + Buffer.from(user + \":\" + password).toString(\"base64\"),\n });\n }\n const jwtToken = notEmpty(token);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n\n /** Request fresh server-issued login material. v1 only emits the public-PKCE flow;\n * desktop MUST place the returned `nonce` verbatim into the OIDC auth-request. `idP` names\n * the advertised SSO method to route to; omitted, the backend keeps its current first-match\n * behaviour. */\n public async beginSSOLogin(idP?: string): Promise<SSOLoginAttempt> {\n const attempt =\n idP === undefined ? await this.ll.beginSSOLogin() : await this.ll.beginSSOLogin(idP);\n return {\n flow: \"public_pkce\",\n nonce: attempt.nonce,\n expiresAt: attempt.expiresAt,\n clientSecret: attempt.clientSecret,\n };\n }\n\n /** Forward the verbatim IdP `/token` response body and receive a Platforma JWT. `idP` names\n * the advertised SSO method to route to; omitted, the backend keeps its current first-match\n * behaviour. */\n public async loginSSO(payload: {\n tokenResponse: Uint8Array;\n idP?: string;\n }): Promise<AuthInformation> {\n try {\n const jwtToken =\n payload.idP === undefined\n ? await this.ll.loginSSO(payload.tokenResponse)\n : await this.ll.loginSSO(payload.tokenResponse, payload.idP);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n}\n"],"mappings":"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"}