@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":"ll_client.js","names":["GrpcPlApiClient","status","GrpcStatus"],"sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient as GrpcPlApiClient } from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client\";\nimport type { ClientOptions, Interceptor } from \"@grpc/grpc-js\";\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from \"@grpc/grpc-js\";\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from \"./config\";\nimport {\n plAddressToConfig,\n type wireProtocol,\n SUPPORTED_WIRE_PROTOCOLS,\n DEFAULT_LOGIN_TIMEOUT,\n deriveUnaryDeadline,\n smoothRtt,\n} from \"./config\";\nimport type { GrpcOptions } from \"@protobuf-ts/grpc-transport\";\nimport { GrpcTransport } from \"@protobuf-ts/grpc-transport\";\nimport { LLPlTransaction } from \"./ll_transaction\";\nimport { setResourceSignaturesRequired } from \"./types\";\nimport { parsePlJwt } from \"../util/pl\";\nimport { type Dispatcher, interceptors } from \"undici\";\nimport type { Middleware } from \"openapi-fetch\";\nimport { inferAuthRefreshTime } from \"./auth\";\nimport { hasCapability, type BackendCapability } from \"./capabilities\";\nimport { defaultHttpDispatcher } from \"@milaboratories/pl-http\";\nimport type { WireClientProvider, WireClientProviderFactory, WireConnection } from \"./wire\";\nimport { parseHttpAuth } from \"@milaboratories/pl-model-common\";\nimport type * as grpcTypes from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport {\n type PlApiPaths,\n type PlRestClientType,\n createClient,\n parseResponseError,\n} from \"../proto-rest\";\nimport { notEmpty, retry, withTimeout, type RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { Code } from \"../proto-grpc/google/rpc/code\";\nimport { WebSocketBiDiStream } from \"./websocket_stream\";\nimport {\n AuthAPI_Role,\n TxAPI_ClientMessage,\n TxAPI_ServerMessage,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { isAbortedError, isTransientCallFailure, isUnauthenticated } from \"./errors\";\nimport { Timestamp } from \"../proto-grpc/google/protobuf/timestamp\";\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\n/** Bounded retry for idempotent unary calls. Deliberately short: these calls sit on the\n * connect path and gate the UI, so a few quick attempts beat a long grind. */\nconst IDEMPOTENT_RETRY_OPTIONS: RetryOptions = {\n type: \"exponentialBackoff\",\n maxAttempts: 4,\n initialDelay: 200,\n backoffMultiplier: 2,\n jitter: 0.3,\n maxDelay: 2_000,\n};\n\n// Parses leading \"<major>.<minor>.<patch>\" from a version string like\n// \"3.1.1\" or \"3.1.1-rc1\" and returns true if the parsed version is >= target.\n// Returns false for unparseable versions (safer to assume an old backend).\nfunction isVersionAtLeast(version: string, target: [number, number, number]): boolean {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(version);\n if (!match) return false;\n const parsed: [number, number, number] = [Number(match[1]), Number(match[2]), Number(match[3])];\n for (let i = 0; i < 3; i++) {\n if (parsed[i] !== target[i]) return parsed[i] > target[i];\n }\n return true;\n}\n\n// Returns true iff `version` is strictly after the release tag `target`. Dev\n// builds (`git describe`-style, e.g. \"3.5.0-224-g0ca182\") are considered\n// AFTER the matching release tag — they include commits past the tag and so\n// have any change merged after it. Released versions with the same triplet\n// return false (we want the tag itself to be excluded).\n//\n// Examples for target [3,5,0]:\n// \"3.5.0\" → false (the tagged release)\n// \"3.5.0-224-g0ca182\" → true (dev build past the tag)\n// \"3.5.1\" → true\n// \"3.4.9\" → false\n// Returns false for unparseable versions.\nfunction isAfterVersion(version: string, target: [number, number, number]): boolean {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)(.*)$/.exec(version);\n if (!match) return false;\n const parsed: [number, number, number] = [Number(match[1]), Number(match[2]), Number(match[3])];\n const suffix = match[4];\n for (let i = 0; i < 3; i++) {\n if (parsed[i] !== target[i]) return parsed[i] > target[i];\n }\n return suffix !== \"\";\n}\n\nclass WireClientProviderImpl<Client> implements WireClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(\n private readonly wireOpts: () => WireConnection,\n private readonly clientConstructor: (wireOpts: WireConnection) => Client,\n ) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined) this.client = this.clientConstructor(this.wireOpts());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements WireClientProviderFactory {\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n /** Cached Ping response. Populated by build() before it returns; refreshed by every later ping(). */\n private _serverInfo?: grpcTypes.MaintenanceAPI_Ping_Response;\n private _authMethodsSync?: grpcTypes.AuthAPI_ListMethods_Response;\n\n private _status: PlConnectionStatus = \"OK\";\n private authProbeInFlight = false;\n private readonly statusListener?: PlConnectionStatusListener;\n\n private _wireProto: wireProtocol = \"grpc\";\n private _wireConn!: WireConnection;\n\n /** The live GrpcOptions object handed to GrpcTransport. The transport keeps it by\n * reference and re-reads it on every call, so mutating `timeout` here retunes\n * subsequent deadlines without tearing down the connection. */\n private _grpcOptions?: GrpcOptions;\n\n /** Smoothed round-trip estimate in ms, from ping timings. Undefined until the first\n * successful ping, in which case the configured deadline is used as-is. */\n private _rttMs?: number;\n\n private readonly _restInterceptors: Dispatcher.DispatcherComposeInterceptor[];\n private readonly _restMiddlewares: Middleware[];\n private readonly _grpcInterceptors: Interceptor[];\n private readonly providers: WeakRef<WireClientProviderImpl<any>>[] = [];\n\n public readonly clientProvider: WireClientProvider<PlRestClientType | GrpcPlApiClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n logger?: MiLogger;\n useAutoDetectWireProtocol?: boolean;\n } = {},\n ) {\n const conf =\n typeof configOrAddress === \"string\" ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n const pl = new LLPlClient(conf, ops);\n\n // FIXME(rfiskov)[MILAB-5275]: Investigate why autodetect randomly fails; temporary turn it off.\n if (ops.useAutoDetectWireProtocol) {\n await pl.detectOptimalWireProtocol();\n }\n\n // Guarantee a ping happened so capability-gated paths (login, refresh) can branch synchronously.\n // In the autodetect path the loop's last successful ping already populated _serverInfo via the\n // side-effect in ping(); this fallback covers the path where autodetect is disabled.\n // Retried, not bare: this ping is the first contact with the server, so DNS and LB\n // warm-up land here. A single transient failure must not fail the whole connect.\n // (Not inside ping() itself: the autodetect path already wraps it in its own retry.)\n if (!pl._serverInfo) await pl.withIdempotentRetry(\"ping\", () => pl.ping());\n\n // Install the process-global signature-strictness flag based on backend version.\n setResourceSignaturesRequired(pl.supportsResourceSignatures);\n\n // Guarantee authMethods happened so client can make weighted decision on which auth method to use.\n if (!pl._authMethodsSync) await pl.authMethods();\n\n return pl;\n }\n\n private constructor(\n public readonly conf: PlClientConfig,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n logger?: MiLogger;\n } = {},\n ) {\n const { auth, statusListener } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this._restInterceptors = [];\n this._restMiddlewares = [];\n this._grpcInterceptors = [];\n\n if (auth !== undefined) {\n this._restInterceptors.push(this.createRestAuthInterceptor());\n this._grpcInterceptors.push(this.createGrpcAuthInterceptor());\n }\n this._restInterceptors.push(interceptors.retry({ statusCodes: [] })); // Handle errors with openapi-fetch middleware.\n this._restMiddlewares.push(this.createRestErrorMiddleware());\n this._grpcInterceptors.push(this.createGrpcErrorInterceptor());\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n if (this.conf.wireProtocol) {\n this._wireProto = this.conf.wireProtocol;\n }\n\n this.initWireConnection(this._wireProto);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.clientProvider = this.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new GrpcPlApiClient(wireConn.Transport);\n } else {\n return createClient<PlApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n }\n\n private initWireConnection(protocol: wireProtocol) {\n switch (protocol) {\n case \"rest\":\n this.initRestConnection();\n return;\n case \"grpc\":\n this.initGrpcConnection(this.ops.shouldUseGzip ?? false);\n return;\n default:\n ((v: never) => {\n throw new Error(\n `Unsupported wire protocol '${v as string}'. Use one of: ${SUPPORTED_WIRE_PROTOCOLS.join(\", \")}`,\n );\n })(protocol);\n }\n }\n\n private initRestConnection(): void {\n const dispatcher = defaultHttpDispatcher(this.conf.grpcProxy, this._restInterceptors);\n this._replaceWireConnection({\n type: \"rest\",\n Config: this.conf,\n Dispatcher: dispatcher,\n Middlewares: this._restMiddlewares,\n });\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport\n * @param gzip - whether to enable gzip compression\n */\n private initGrpcConnection(gzip: boolean) {\n const clientOptions: ClientOptions = {\n \"grpc.keepalive_time_ms\": 30_000, // 30 seconds\n \"grpc.service_config_disable_resolution\": 1, // Disable DNS TXT lookups for service config\n // Raises the per-stream and connection-level HTTP/2 windows. Node's 64 KB default\n // caps a big single-stream read (project open) at window/RTT rather than link speed,\n // and a lost WINDOW_UPDATE can deadlock it under packet loss.\n \"grpc-node.flow_control_window\": 16 * 1024 * 1024, // 16 MiB\n interceptors: this._grpcInterceptors,\n };\n\n if (gzip) clientOptions[\"grpc.default_compression_algorithm\"] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.unaryDeadline(),\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n const grpcProxy =\n typeof this.conf.grpcProxy === \"string\" ? { url: this.conf.grpcProxy } : this.conf.grpcProxy;\n\n if (grpcProxy?.url) {\n const url = new URL(grpcProxy.url);\n if (grpcProxy.auth) {\n const parsed = parseHttpAuth(grpcProxy.auth);\n if (parsed.scheme !== \"Basic\") {\n throw new Error(`Unsupported auth scheme: ${parsed.scheme as string}.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n process.env.grpc_proxy = url.toString();\n } else {\n delete process.env.grpc_proxy;\n }\n\n this._grpcOptions = grpcOptions;\n this._replaceWireConnection({ type: \"grpc\", Transport: new GrpcTransport(grpcOptions) });\n }\n\n /** Unary deadline derived from the observed RTT, floored by the configured value so\n * a fast link behaves exactly as before, and capped by\n * {@link MAX_ADAPTIVE_REQUEST_TIMEOUT}. */\n private unaryDeadline(): number {\n return deriveUnaryDeadline(this.conf.defaultRequestTimeout, this._rttMs);\n }\n\n /** Folds a fresh round-trip sample into the estimate and retunes the live unary\n * deadline. Called after every successful ping. */\n private recordRtt(sampleMs: number): void {\n this._rttMs = smoothRtt(this._rttMs, sampleMs);\n\n if (this._grpcOptions) {\n const next = this.unaryDeadline();\n if (next !== this._grpcOptions.timeout) {\n this.ops.logger?.info(\n `Unary deadline retuned to ${next}ms (rtt estimate ${Math.round(this._rttMs)}ms)`,\n );\n this._grpcOptions.timeout = next;\n }\n }\n }\n\n /** Smoothed round-trip estimate in ms, or undefined before the first ping. */\n public get rttEstimateMs(): number | undefined {\n return this._rttMs;\n }\n\n /** Runs an idempotent unary call with a bounded retry on transient transport failures.\n * Safe only for calls with no side effects, since a retry may duplicate the request. */\n private async withIdempotentRetry<T>(name: string, cb: () => Promise<T>): Promise<T> {\n return await retry(cb, IDEMPOTENT_RETRY_OPTIONS, (e: unknown) => {\n if (!isTransientCallFailure(e)) return false;\n this.ops.logger?.info(`${name}: transient failure, retrying. err=${String(e)}`);\n return true;\n });\n }\n\n private _replaceWireConnection(newConn: WireConnection): void {\n const oldConn = this._wireConn;\n this._wireConn = newConn;\n this._wireProto = newConn.type;\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldConn !== undefined && oldConn.type === \"grpc\") oldConn.Transport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createWireClientProvider<Client>(\n clientConstructor: (transport: WireConnection) => Client,\n ): WireClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new WireClientProviderImpl<Client>(() => this._wireConn, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get wireConnection(): WireConnection {\n return this._wireConn;\n }\n\n public get wireProtocol(): wireProtocol | undefined {\n return this._wireProto;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error(\"Client is not authenticated\");\n if (this.authInformation?.jwtToken) {\n if (this.hasCapability(\"auth:v2\")) {\n return parsePlJwt(this.authInformation?.jwtToken).sub;\n }\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n } else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (newStatus === \"Unauthenticated\" && this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n /**\n * UNAUTHENTICATED covers both a dead session (must reset) and a per-request authorization failure\n * such as a revoked resource signature (must not). Disambiguate by probing getSessionInfo — an\n * authenticated call with no resource signature: success means the session is alive and the failure\n * was resource-level; a probe that is itself Unauthenticated means real auth loss. Coalesced via\n * authProbeInFlight so a burst of failures costs one probe.\n */\n private async verifyThenMaybeEscalateUnauthenticated(): Promise<void> {\n if (this._status !== \"OK\" || this.authProbeInFlight) return;\n this.authProbeInFlight = true;\n try {\n await this.getSessionInfo();\n } catch (e) {\n if (isUnauthenticated(e)) this.updateStatus(\"Unauthenticated\");\n } finally {\n this.authProbeInFlight = false;\n }\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined ||\n Date.now() < this.refreshTimestamp ||\n this.authRefreshInProgress ||\n this._status === \"Unauthenticated\"\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const ttl = BigInt(this.conf.authTTLSeconds);\n const token = this.hasCapability(\"auth:v2\")\n ? await this.refreshToken({ ttlSeconds: ttl })\n : await this.getJwtToken(ttl);\n this.authInformation = { jwtToken: token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /**\n * Creates middleware that parses error responses and handles them centrally.\n * This middleware runs before openapi-fetch parses the response, so we need to\n * manually parse the response body for error responses.\n */\n private createRestErrorMiddleware(): Middleware {\n return {\n onResponse: async ({ request: _request, response, options: _options }) => {\n const { body, ...resOptions } = response;\n\n if ([502, 503, 504].includes(response.status)) {\n // Service unavailable, bad gateway, gateway timeout\n this.updateStatus(\"Disconnected\");\n return new Response(body, { ...resOptions, status: response.status });\n }\n\n const respErr = await parseResponseError(response);\n if (!respErr.error) {\n // No error: nice!\n return new Response(respErr.origBody ?? body, { ...resOptions, status: response.status });\n }\n\n if (typeof respErr.error === \"string\") {\n // Non-standard error or normal response: let later middleware to deal wit it.\n return new Response(respErr.error, { ...resOptions, status: response.status });\n }\n\n if (respErr.error.code === Code.UNAUTHENTICATED) {\n void this.verifyThenMaybeEscalateUnauthenticated();\n }\n\n // Let later middleware to deal with standard gRPC error.\n return new Response(respErr.origBody, { ...resOptions, status: response.status });\n },\n };\n }\n\n /** Detects certain errors and update client status accordingly when using GRPC wire connection */\n private createGrpcErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n void this.verifyThenMaybeEscalateUnauthenticated();\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus(\"Disconnected\");\n next(status);\n },\n });\n },\n });\n };\n }\n\n private createRestAuthInterceptor(): Dispatcher.DispatcherComposeInterceptor {\n return (dispatch) => {\n return (options, handler) => {\n if (this.authInformation?.jwtToken !== undefined) {\n // TODO: check this magic really works and gets called\n options.headers = {\n ...options.headers,\n authorization: \"Bearer \" + this.authInformation.jwtToken,\n };\n this.refreshAuthInformationIfNeeded();\n }\n\n return dispatch(options, handler);\n };\n };\n }\n\n /** Injects authentication information if needed */\n private createGrpcAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set(\"authorization\", \"Bearer \" + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n public async getJwtToken(\n ttlSeconds: bigint,\n options?: { authorization?: string; role?: AuthAPI_Role },\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const role = options?.role ?? AuthAPI_Role.UNSPECIFIED;\n\n if (cl instanceof GrpcPlApiClient) {\n const meta: Record<string, string> = {};\n if (options?.authorization) meta.authorization = options.authorization;\n return (\n await cl.getJWTToken(\n {\n expiration: { seconds: ttlSeconds, nanos: 0 },\n requestedRole: role,\n },\n { meta, timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const headers: Record<string, string> = {};\n if (options?.authorization) headers.authorization = options.authorization;\n const resp = cl.POST(\"/v1/auth/jwt-token\", {\n body: { expiration: `${ttlSeconds}s`, requestedRole: role },\n headers,\n });\n return notEmpty((await resp).data, \"REST: empty response for JWT token request\").token;\n }\n }\n\n /** Login via username/password. Returns a fresh JWT. Backend creates a new session per call. */\n public async loginBasic(\n user: string,\n password: string,\n opts: { ttlSeconds?: bigint; role?: AuthAPI_Role } = {},\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const role = opts.role ?? AuthAPI_Role.UNSPECIFIED;\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"basic\",\n basic: { login: user, password },\n },\n expiration: { seconds: ttl, nanos: 0 },\n requestedRole: role,\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n // openapi-typescript generated all body fields as required, but Login.Request\n // has a credentials oneof — only one of `basic`/`token` is sent. Cast around it.\n body: {\n basic: { login: user, password },\n expiration: `${ttl}s`,\n requestedRole: role,\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for login request\").token;\n }\n }\n\n /** Login via opaque bearer token (controller pre-shared secret, OIDC id-token, etc.).\n * String input is UTF-8 encoded. Returns a fresh Platforma JWT. */\n public async loginWithToken(\n token: Uint8Array | string,\n opts: { ttlSeconds?: bigint; role?: AuthAPI_Role } = {},\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const role = opts.role ?? AuthAPI_Role.UNSPECIFIED;\n const bytes = typeof token === \"string\" ? Buffer.from(token, \"utf8\") : token;\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"token\",\n token: { token: bytes },\n },\n expiration: { seconds: ttl, nanos: 0 },\n requestedRole: role,\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n // openapi-typescript marks all body fields as required, but Login.Request has a oneof.\n // REST encodes `bytes` as a base64 string.\n body: {\n token: { token: Buffer.from(bytes).toString(\"base64\") },\n expiration: `${ttl}s`,\n requestedRole: role,\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for login request\").token;\n }\n }\n\n /** Login via SSO: forwards the raw IdP /token JSON body to the backend.\n * Backend validates signature + nonce + audience and mints a Platforma JWT. */\n public async loginSSO(tokenResponse: Uint8Array): Promise<string> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"sso\",\n sso: { tokenResponse },\n },\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n body: {\n sso: { tokenResponse: Buffer.from(tokenResponse).toString(\"base64\") },\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for SSO login request\").token;\n }\n }\n\n /** Request a one-time PKCE nonce + its expiry from the backend. The desktop is\n * expected to place the nonce verbatim into the OIDC auth-request before\n * redirecting to the IdP; the backend enforces the expiry on {@link loginSSO}. */\n public async beginSSOLogin(): Promise<{ nonce: string; expiresAt: Date; clientSecret?: string }> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n const resp = (await cl.beginSSOLogin({}).response).flow;\n if (resp.oneofKind !== \"publicPkce\") {\n throw new Error(`beginSSOLogin: unsupported flow ${resp.oneofKind}`);\n }\n const exp = notEmpty(resp.publicPkce.expiresAt, \"beginSSOLogin: missing expiresAt\");\n return {\n nonce: resp.publicPkce.nonce,\n expiresAt: Timestamp.toDate(exp),\n clientSecret: resp.publicPkce.clientSecret,\n };\n } else {\n const wsResponse = notEmpty(\n (await cl.POST(\"/v1/auth/sso/begin-login\", { body: {} })).data,\n \"REST: empty response for beginSSOLogin request\",\n );\n const pkce = notEmpty(wsResponse.publicPkce, \"REST: missing publicPkce in beginSSOLogin\");\n return {\n nonce: pkce.nonce,\n expiresAt: new Date(pkce.expiresAt),\n clientSecret: pkce.clientSecret,\n };\n }\n }\n\n /** Refresh the current JWT, preserving session id and role. */\n public async refreshToken(opts: { ttlSeconds?: bigint } = {}): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const currentToken = notEmpty(\n this.authInformation?.jwtToken,\n \"refreshToken called without a current JWT\",\n );\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.refreshToken(\n {\n token: currentToken,\n expiration: { seconds: ttl, nanos: 0 },\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/refresh\", {\n body: { token: currentToken, expiration: `${ttl}s` },\n });\n return notEmpty((await resp).data, \"REST: empty response for refresh request\").token;\n }\n }\n\n public async ping(): Promise<grpcTypes.MaintenanceAPI_Ping_Response> {\n const cl = this.clientProvider.get();\n let resp: grpcTypes.MaintenanceAPI_Ping_Response;\n // Ping is the cheapest call we make, so its duration is our best RTT proxy.\n const startedAt = performance.now();\n if (cl instanceof GrpcPlApiClient) {\n resp = (await cl.ping({})).response;\n } else {\n // The REST ping response predates the `capabilities` field (proto field 9).\n // Old servers omit it; treat absence as empty capability list.\n const pingData = notEmpty(\n (await cl.GET(\"/v1/ping\")).data,\n \"REST: empty response for ping request\",\n );\n resp = {\n ...(pingData as unknown as grpcTypes.MaintenanceAPI_Ping_Response),\n capabilities: (pingData as any).capabilities ?? [],\n };\n }\n this.recordRtt(performance.now() - startedAt);\n this._serverInfo = resp;\n return resp;\n }\n\n /** Cached Ping response. Always populated post-build(); throws if accessed earlier. */\n public get serverInfo(): grpcTypes.MaintenanceAPI_Ping_Response {\n if (!this._serverInfo) {\n throw new Error(\"LLPlClient.serverInfo accessed before build() completed\");\n }\n return this._serverInfo;\n }\n\n /** Synchronous capability check against the cached Ping response. */\n public hasCapability(capability: BackendCapability): boolean {\n return hasCapability(this.serverInfo.capabilities, capability);\n }\n\n /** True if the backend produces signed resource ids (and accepts the\n * setDefaultColor TX request). Tagged at 3.3.0 — backends older than this\n * return resources without signatures and reject color-proof requests. */\n public get supportsResourceSignatures(): boolean {\n return isVersionAtLeast(this.serverInfo.coreVersion, [3, 3, 0]);\n }\n\n /**\n * True if the backend honors per-file `permissions` on workdir fill rules, so\n * `exec.builder().writeFile/addFile({ writable: true })` takes effect. When false\n * the requested mode is ignored and files land at the canonical archive perm.\n *\n * [3, 5, 0] excludes the tagged 3.5.0 release but includes dev builds past the\n * tag (e.g. \"3.5.0-224-g0ca182\"), which is where the support lands.\n */\n public get supportsWritableWorkdirFiles(): boolean {\n return isAfterVersion(this.serverInfo.coreVersion, [3, 5, 0]);\n }\n\n /**\n * Detects the best available wire protocol.\n * If wireProtocol is explicitly configured, does nothing.\n * Otherwise probes the current protocol via ping; if it fails, switches to the alternative.\n */\n private async detectOptimalWireProtocol() {\n if (this.conf.wireProtocol) {\n return;\n }\n\n // Each retry is:\n // - ping request timeout (100 to 3_000ms)\n // - backoff delay (30 to 500ms)\n //\n // 30 attempts are ~43 seconds of overall waiting time.\n // Think twice on overall time this thing takes to complete when changing these parameters.\n // It may block UI when connecting to the server and loading projects list.\n const pingTimeoutFactor = 1.3;\n const maxPingTimeoutMs = 3_000;\n const retryOptions: RetryOptions = {\n type: \"exponentialBackoff\",\n maxAttempts: 30,\n initialDelay: 30,\n backoffMultiplier: 1.3,\n jitter: 0.2,\n maxDelay: 500,\n };\n\n let attempt = 1;\n let pingTimeoutMs = 100;\n await retry(\n () => withTimeout(this.ping(), pingTimeoutMs),\n retryOptions,\n (e: unknown) => {\n if (isAbortedError(e)) {\n this.ops.logger?.info(\n `Wire proto autodetect: ping timed out after ${pingTimeoutMs}ms: attempt=${attempt}, wire=${this._wireProto}`,\n );\n\n if (attempt % 2 === 0) {\n // We have 2 wire protocols to check. Increase timeout each 2 attempts.\n pingTimeoutMs = Math.min(\n Math.round(pingTimeoutMs * pingTimeoutFactor),\n maxPingTimeoutMs,\n );\n }\n } else {\n this.ops.logger?.info(\n `Wire proto autodetect: ping failed: attempt=${attempt}, wire=${this._wireProto}, err=${String(e)}`,\n );\n }\n\n attempt++;\n const protocol = this._wireProto === \"grpc\" ? \"rest\" : \"grpc\";\n this.ops.logger?.info(\n `Wire protocol autodetect next attempt: will try wire '${protocol}' with timeout ${pingTimeoutMs}ms`,\n );\n this.initWireConnection(protocol);\n return true;\n },\n );\n }\n\n public async license(): Promise<grpcTypes.MaintenanceAPI_License_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (await cl.license({})).response;\n } else {\n const resp = notEmpty(\n (await cl.GET(\"/v1/license\")).data,\n \"REST: empty response for license request\",\n );\n return {\n status: resp.status,\n isOk: resp.isOk,\n responseBody: Uint8Array.from(Buffer.from(resp.responseBody)),\n };\n }\n }\n\n public async authMethods(): Promise<grpcTypes.AuthAPI_ListMethods_Response> {\n const cl = this.clientProvider.get();\n let resp: grpcTypes.AuthAPI_ListMethods_Response;\n if (cl instanceof GrpcPlApiClient) {\n resp = (await cl.authMethods({})).response;\n } else {\n const wsResponse = notEmpty(\n (await cl.GET(\"/v1/auth/methods\")).data,\n \"REST: empty response for auth methods request\",\n );\n // OpenAPI schema flattens the protobuf oneof into `{ basic?, token? }`,\n // while protobuf-ts models it as a discriminated union. Reshape per item.\n resp = {\n methods: (wsResponse.methods ?? []).map((m): grpcTypes.AuthAPI_ListMethods_MethodInfo => {\n const base = { id: m.id, description: m.description };\n if (m.basic !== undefined) {\n return { ...base, method: { oneofKind: \"basic\", basic: m.basic } };\n }\n if (m.token !== undefined) {\n return { ...base, method: { oneofKind: \"token\", token: m.token } };\n }\n if (m.sso !== undefined) {\n return { ...base, method: { oneofKind: \"sso\", sso: m.sso } };\n }\n return { ...base, method: { oneofKind: undefined } };\n }),\n };\n }\n\n this._authMethodsSync = resp;\n return resp;\n }\n\n public get authMethodsSync(): grpcTypes.AuthAPI_ListMethods_Response {\n if (!this._authMethodsSync) {\n throw new Error(\"LLPlClient.authMethodsSync accessed before build() completed\");\n }\n return this._authMethodsSync;\n }\n\n public async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<grpcTypes.AuthAPI_GetUserRoot_Response> {\n // Retryable even with createIfNotExists: the call is get-or-create keyed on login, so a\n // second attempt returns the existing root rather than making another one.\n return await this.withIdempotentRetry(\"getUserRoot\", () => this.getUserRootOnce(opts));\n }\n\n private async getUserRootOnce(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<grpcTypes.AuthAPI_GetUserRoot_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.getUserRoot({\n login: opts.login ?? \"\",\n createIfNotExists: opts.createIfNotExists ?? false,\n })\n ).response;\n } else {\n const resp = notEmpty(\n (\n await cl.POST(\"/v1/auth/user-root\", {\n body: {\n login: opts.login ?? \"\",\n createIfNotExists: opts.createIfNotExists ?? false,\n },\n })\n ).data,\n \"REST: empty response for getUserRoot request\",\n );\n return {\n userRoot: resp.userRoot\n ? {\n resourceId: BigInt(resp.userRoot.resourceId),\n resourceSignature: Uint8Array.from(\n Buffer.from(resp.userRoot.resourceSignature, \"base64\"),\n ),\n }\n : undefined,\n };\n }\n }\n\n public async listUserResources(\n opts: { login?: string; startFrom?: bigint; limit?: number } = {},\n ): Promise<grpcTypes.AuthAPI_ListUserResources_Response[]> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"ListUserResources requires gRPC wire protocol; REST is not supported\");\n }\n\n const call = cl.listUserResources({\n login: opts.login ?? \"\",\n startFrom: opts.startFrom ?? 0n,\n limit: opts.limit ?? 0,\n });\n const responses: grpcTypes.AuthAPI_ListUserResources_Response[] = [];\n for await (const msg of call.responses) {\n responses.push(msg);\n }\n return responses;\n }\n\n /** Returns the authenticated caller's session id and effective role.\n * Models the {@link getUserRoot} wrapper: gRPC unary with a REST fallback. */\n public async getSessionInfo(): Promise<grpcTypes.AuthAPI_GetSessionInfo_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (await cl.getSessionInfo({})).response;\n } else {\n const resp = notEmpty(\n (await cl.POST(\"/v1/auth/session-info\", { body: {} })).data,\n \"REST: empty response for getSessionInfo request\",\n );\n return {\n sessionId: Uint8Array.from(Buffer.from(resp.sessionId, \"base64\")),\n role: resp.role as AuthAPI_Role,\n };\n }\n }\n\n /** Lists the users known to the server — the recipient picker's source. A user\n * becomes known on first login; provisioned users who have never logged in do not\n * appear. gRPC-only (unary, no REST binding). */\n public async listUsers(): Promise<grpcTypes.AuthAPI_User[]> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"ListUsers requires gRPC wire protocol; REST is not supported\");\n }\n\n return (await cl.listUsers({})).response.users;\n }\n\n /** Deletes a user account: the record, its identity-index entries (login, email and any\n * alternative of either), its grants, and its root resource with everything still attached\n * under it. Admin/controller credentials only, and irreversible — re-attach anything worth\n * keeping to another user's root first.\n * gRPC-only (unary, no REST binding), like {@link listUsers}. */\n public async deleteUser(login: string): Promise<grpcTypes.AuthAPI_DeleteUser_Response> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"DeleteUser requires gRPC wire protocol; REST is not supported\");\n }\n\n return (await cl.deleteUser({ login })).response;\n }\n\n public async txSync(txId: bigint): Promise<void> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n await cl.txSync({ txId: BigInt(txId) });\n } else {\n await cl.POST(\"/v1/tx-sync\", { body: { txId: txId.toString() } });\n }\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n\n const timeout =\n ops.timeout ??\n (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout);\n\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return cl.tx({\n abort: totalAbortSignal,\n timeout,\n });\n }\n\n const wireConn = this.wireConnection;\n if (wireConn.type === \"rest\") {\n // For REST/WebSocket protocol, timeout needs to be converted to AbortSignal\n if (timeout !== undefined) {\n totalAbortSignal = AbortSignal.any([totalAbortSignal, AbortSignal.timeout(timeout)]);\n }\n\n // The gRPC transport has the auth interceptor that already handles it, but here we need to refresh the auth information to be safe.\n this.refreshAuthInformationIfNeeded();\n\n const wsUrl = this.conf.ssl\n ? `wss://${this.conf.hostAndPort}/v1/ws/tx`\n : `ws://${this.conf.hostAndPort}/v1/ws/tx`;\n\n return new WebSocketBiDiStream(\n wsUrl,\n (msg) => TxAPI_ClientMessage.toBinary(msg),\n (data) => TxAPI_ServerMessage.fromBinary(new Uint8Array(data)),\n {\n abortSignal: totalAbortSignal,\n jwtToken: this.authInformation?.jwtToken,\n dispatcher: wireConn.Dispatcher,\n\n onComplete: async (stream) =>\n stream.requests.send({\n // Ask server to gracefully close the stream on its side, if not done yet.\n requestId: 0,\n request: { oneofKind: \"streamClose\", streamClose: {} },\n }),\n },\n );\n }\n\n throw new Error(`transactions are not supported for wire protocol ${this._wireProto}`);\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n if (this.wireConnection.type === \"grpc\") {\n this.wireConnection.Transport.close();\n } else {\n // TODO: close all WS connections\n }\n await this.httpDispatcher.destroy();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,2BAAyC;CAC7C,MAAM;CACN,aAAa;CACb,cAAc;CACd,mBAAmB;CACnB,QAAQ;CACR,UAAU;AACZ;AAKA,SAAS,iBAAiB,SAAiB,QAA2C;CACpF,MAAM,QAAQ,yBAAyB,KAAK,OAAO;CACnD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,SAAmC;EAAC,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;CAAC;CAC9F,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,OAAO;CAEzD,OAAO;AACT;AAcA,SAAS,eAAe,SAAiB,QAA2C;CAClF,MAAM,QAAQ,8BAA8B,KAAK,OAAO;CACxD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,SAAmC;EAAC,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;CAAC;CAC9F,MAAM,SAAS,MAAM;CACrB,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,OAAO;CAEzD,OAAO,WAAW;AACpB;AAEA,IAAM,yBAAN,MAA2E;CAItD;CACA;CAJnB,SAAqC,KAAA;CAErC,YACE,UACA,mBACA;EAFiB,KAAA,WAAA;EACA,KAAA,oBAAA;CAChB;CAEH,QAAqB;EACnB,KAAK,SAAS,KAAA;CAChB;CAEA,MAAqB;EACnB,IAAI,KAAK,WAAW,KAAA,GAAW,KAAK,SAAS,KAAK,kBAAkB,KAAK,SAAS,CAAC;EACnF,OAAO,KAAK;CACd;AACF;;AAGA,IAAa,aAAb,MAAa,WAAgD;CA+EzC;CACC;;CA9EnB;;CAEA;;CAEA;;CAEA;;CAEA;;CAGA;CACA;CAEA,UAAsC;CACtC,oBAA4B;CAC5B;CAEA,aAAmC;CACnC;;;;CAKA;;;CAIA;CAEA;CACA;CACA;CACA,YAAqE,CAAC;CAEtE;CAEA;CAEA,aAAoB,MAClB,iBACA,MAMI,CAAC,GACL;EAIA,MAAM,KAAK,IAAI,WAFb,OAAO,oBAAoB,WAAW,kBAAkB,eAAe,IAAI,iBAE7C,GAAG;EAGnC,IAAI,IAAI,2BACN,MAAM,GAAG,0BAA0B;EASrC,IAAI,CAAC,GAAG,aAAa,MAAM,GAAG,oBAAoB,cAAc,GAAG,KAAK,CAAC;EAGzE,8BAA8B,GAAG,0BAA0B;EAG3D,IAAI,CAAC,GAAG,kBAAkB,MAAM,GAAG,YAAY;EAE/C,OAAO;CACT;CAEA,YACE,MACA,MAKI,CAAC,GACL;EAPgB,KAAA,OAAA;EACC,KAAA,MAAA;EAOjB,MAAM,EAAE,MAAM,mBAAmB;EAEjC,IAAI,SAAS,KAAA,GAAW;GACtB,KAAK,mBAAmB,qBACtB,KAAK,iBACL,KAAK,KAAK,qBACZ;GACA,KAAK,kBAAkB,KAAK;GAC5B,KAAK,eAAe,KAAK;GACzB,KAAK,uBAAuB,KAAK;GACjC,KAAK,cAAc,KAAK;EAC1B;EAEA,KAAK,oBAAoB,CAAC;EAC1B,KAAK,mBAAmB,CAAC;EACzB,KAAK,oBAAoB,CAAC;EAE1B,IAAI,SAAS,KAAA,GAAW;GACtB,KAAK,kBAAkB,KAAK,KAAK,0BAA0B,CAAC;GAC5D,KAAK,kBAAkB,KAAK,KAAK,0BAA0B,CAAC;EAC9D;EACA,KAAK,kBAAkB,KAAK,aAAa,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;EACnE,KAAK,iBAAiB,KAAK,KAAK,0BAA0B,CAAC;EAC3D,KAAK,kBAAkB,KAAK,KAAK,2BAA2B,CAAC;EAE7D,KAAK,iBAAiB,sBAAsB,KAAK,KAAK,SAAS;EAC/D,IAAI,KAAK,KAAK,cACZ,KAAK,aAAa,KAAK,KAAK;EAG9B,KAAK,mBAAmB,KAAK,UAAU;EAEvC,IAAI,mBAAmB,KAAA,GAAW;GAChC,KAAK,iBAAiB;GACtB,eAAe,KAAK,OAAO;EAC7B;EAEA,KAAK,iBAAiB,KAAK,0BAA0B,aAAa;GAChE,IAAI,SAAS,SAAS,QACpB,OAAO,IAAIA,eAAgB,SAAS,SAAS;QAE7C,OAAO,aAAyB;IAC9B,aAAa,SAAS,OAAO;IAC7B,KAAK,SAAS,OAAO;IACrB,YAAY,SAAS;IACrB,aAAa,SAAS;GACxB,CAAC;EAEL,CAAC;CACH;CAEA,mBAA2B,UAAwB;EACjD,QAAQ,UAAR;GACE,KAAK;IACH,KAAK,mBAAmB;IACxB;GACF,KAAK;IACH,KAAK,mBAAmB,KAAK,IAAI,iBAAiB,KAAK;IACvD;GACF,SACE,EAAE,MAAa;IACb,MAAM,IAAI,MACR,8BAA8B,EAAY,iBAAiB,yBAAyB,KAAK,IAAI,GAC/F;GACF,EAAA,CAAG,QAAQ;EACf;CACF;CAEA,qBAAmC;EACjC,MAAM,aAAa,sBAAsB,KAAK,KAAK,WAAW,KAAK,iBAAiB;EACpF,KAAK,uBAAuB;GAC1B,MAAM;GACN,QAAQ,KAAK;GACb,YAAY;GACZ,aAAa,KAAK;EACpB,CAAC;CACH;;;;;CAMA,mBAA2B,MAAe;EACxC,MAAM,gBAA+B;GACnC,0BAA0B;GAC1B,0CAA0C;GAI1C,iCAAiC,KAAK,OAAO;GAC7C,cAAc,KAAK;EACrB;EAEA,IAAI,MAAM,cAAc,wCAAwC,sBAAsB;EAStF,MAAM,cAA2B;GAC/B,MAAM,KAAK,KAAK;GAChB,SAAS,KAAK,cAAc;GAC5B,oBAAoB,KAAK,KAAK,MAC1B,mBAAmB,UAAU,IAC7B,mBAAmB,eAAe;GACtC;EACF;EAEA,MAAM,YACJ,OAAO,KAAK,KAAK,cAAc,WAAW,EAAE,KAAK,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK;EAErF,IAAI,WAAW,KAAK;GAClB,MAAM,MAAM,IAAI,IAAI,UAAU,GAAG;GACjC,IAAI,UAAU,MAAM;IAClB,MAAM,SAAS,cAAc,UAAU,IAAI;IAC3C,IAAI,OAAO,WAAW,SACpB,MAAM,IAAI,MAAM,4BAA4B,OAAO,OAAiB,EAAE;IAExE,IAAI,WAAW,OAAO;IACtB,IAAI,WAAW,OAAO;GACxB;GACA,QAAQ,IAAI,aAAa,IAAI,SAAS;EACxC,OACE,OAAO,QAAQ,IAAI;EAGrB,KAAK,eAAe;EACpB,KAAK,uBAAuB;GAAE,MAAM;GAAQ,WAAW,IAAI,cAAc,WAAW;EAAE,CAAC;CACzF;;;;CAKA,gBAAgC;EAC9B,OAAO,oBAAoB,KAAK,KAAK,uBAAuB,KAAK,MAAM;CACzE;;;CAIA,UAAkB,UAAwB;EACxC,KAAK,SAAS,UAAU,KAAK,QAAQ,QAAQ;EAE7C,IAAI,KAAK,cAAc;GACrB,MAAM,OAAO,KAAK,cAAc;GAChC,IAAI,SAAS,KAAK,aAAa,SAAS;IACtC,KAAK,IAAI,QAAQ,KACf,6BAA6B,KAAK,mBAAmB,KAAK,MAAM,KAAK,MAAM,EAAE,IAC/E;IACA,KAAK,aAAa,UAAU;GAC9B;EACF;CACF;;CAGA,IAAW,gBAAoC;EAC7C,OAAO,KAAK;CACd;;;CAIA,MAAc,oBAAuB,MAAc,IAAkC;EACnF,OAAO,MAAM,MAAM,IAAI,2BAA2B,MAAe;GAC/D,IAAI,CAAC,uBAAuB,CAAC,GAAG,OAAO;GACvC,KAAK,IAAI,QAAQ,KAAK,GAAG,KAAK,qCAAqC,OAAO,CAAC,GAAG;GAC9E,OAAO;EACT,CAAC;CACH;CAEA,uBAA+B,SAA+B;EAC5D,MAAM,UAAU,KAAK;EACrB,KAAK,YAAY;EACjB,KAAK,aAAa,QAAQ;EAG1B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAAK;GAC9C,MAAM,WAAW,KAAK,UAAU,EAAE,CAAC,MAAM;GACzC,IAAI,aAAa,KAAA,GAAW;IAE1B,KAAK,UAAU,OAAO,GAAG,CAAC;IAC1B;GACF,OACE,SAAS,MAAM;EAEnB;EAEA,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,QAAQ,QAAQ,UAAU,MAAM;CAChF;CAEA,yBAAiC;;;;;;CAOjC,yBACE,mBAC4B;EAI5B,KAAK;EACL,IAAI,KAAK,0BAA0B,IAAI;GACrC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAEzC,IADiB,KAAK,UAAU,EAAE,CAAC,MACxB,MAAM,KAAA,GAAW;IAC1B,KAAK,UAAU,OAAO,GAAG,CAAC;IAC1B;GACF;GAEF,KAAK,yBAAyB;EAChC;EAEA,MAAM,WAAW,IAAI,6BAAqC,KAAK,WAAW,iBAAiB;EAC3F,KAAK,UAAU,KAAK,IAAI,QAAQ,QAAQ,CAAC;EACzC,OAAO;CACT;CAEA,IAAW,iBAAiC;EAC1C,OAAO,KAAK;CACd;CAEA,IAAW,eAAyC;EAClD,OAAO,KAAK;CACd;;;;CAKA,IAAW,gBAAyB;EAClC,OAAO,KAAK,oBAAoB,KAAA;CAClC;;CAGA,IAAW,WAA0B;EACnC,IAAI,CAAC,KAAK,eAAe,MAAM,IAAI,MAAM,6BAA6B;EACtE,IAAI,KAAK,iBAAiB,UAAU;GAClC,IAAI,KAAK,cAAc,SAAS,GAC9B,OAAO,WAAW,KAAK,iBAAiB,QAAQ,CAAC,CAAC;GAEpD,OAAO,WAAW,KAAK,iBAAiB,QAAQ,CAAC,CAAC,KAAK;EACzD,OAAO,OAAO;CAChB;CAEA,aAAqB,WAA+B;EAClD,QAAQ,eAAe;GACrB,IAAI,KAAK,YAAY,WAAW;IAC9B,KAAK,UAAU;IACf,IAAI,KAAK,mBAAmB,KAAA,GAAW,KAAK,eAAe,KAAK,OAAO;IACvE,IAAI,cAAc,qBAAqB,KAAK,gBAAgB,KAAA,GAAW,KAAK,YAAY;GAC1F;EACF,CAAC;CACH;;;;;;;;CASA,MAAc,yCAAwD;EACpE,IAAI,KAAK,YAAY,QAAQ,KAAK,mBAAmB;EACrD,KAAK,oBAAoB;EACzB,IAAI;GACF,MAAM,KAAK,eAAe;EAC5B,SAAS,GAAG;GACV,IAAI,kBAAkB,CAAC,GAAG,KAAK,aAAa,iBAAiB;EAC/D,UAAU;GACR,KAAK,oBAAoB;EAC3B;CACF;CAEA,IAAW,SAA6B;EACtC,OAAO,KAAK;CACd;CAEA,wBAAyC;CAEzC,iCAA+C;EAC7C,IACE,KAAK,qBAAqB,KAAA,KAC1B,KAAK,IAAI,IAAI,KAAK,oBAClB,KAAK,yBACL,KAAK,YAAY,mBAEjB;EAGF,KAAK,wBAAwB;EAC7B,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,MAAM,OAAO,KAAK,KAAK,cAAc;IAC3C,MAAM,QAAQ,KAAK,cAAc,SAAS,IACtC,MAAM,KAAK,aAAa,EAAE,YAAY,IAAI,CAAC,IAC3C,MAAM,KAAK,YAAY,GAAG;IAC9B,KAAK,kBAAkB,EAAE,UAAU,MAAM;IACzC,KAAK,mBAAmB,qBACtB,KAAK,iBACL,KAAK,KAAK,qBACZ;IACA,IAAI,KAAK,cAAc,KAAK,aAAa,KAAK,eAAe;GAC/D,SAAS,GAAY;IACnB,IAAI,KAAK,sBAAsB,KAAK,qBAAqB,CAAC;GAC5D,UAAU;IACR,KAAK,wBAAwB;GAC/B;EACF,EAAA,CAAG;CACL;;;;;;CAOA,4BAAgD;EAC9C,OAAO,EACL,YAAY,OAAO,EAAE,SAAS,UAAU,UAAU,SAAS,eAAe;GACxE,MAAM,EAAE,MAAM,GAAG,eAAe;GAEhC,IAAI;IAAC;IAAK;IAAK;GAAG,CAAC,CAAC,SAAS,SAAS,MAAM,GAAG;IAE7C,KAAK,aAAa,cAAc;IAChC,OAAO,IAAI,SAAS,MAAM;KAAE,GAAG;KAAY,QAAQ,SAAS;IAAO,CAAC;GACtE;GAEA,MAAM,UAAU,MAAM,mBAAmB,QAAQ;GACjD,IAAI,CAAC,QAAQ,OAEX,OAAO,IAAI,SAAS,QAAQ,YAAY,MAAM;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;GAG1F,IAAI,OAAO,QAAQ,UAAU,UAE3B,OAAO,IAAI,SAAS,QAAQ,OAAO;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;GAG/E,IAAI,QAAQ,MAAM,SAAA,IAChB,KAAU,uCAAuC;GAInD,OAAO,IAAI,SAAS,QAAQ,UAAU;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;EAClF,EACF;CACF;;CAGA,6BAAkD;EAChD,QAAQ,SAAS,aAAa;GAC5B,OAAO,IAAI,iBAAiB,SAAS,OAAO,GAAG,EAC7C,QAAQ,UAAU,UAAU,SAAS;IACnC,KAAK,UAAU,EACb,kBAAkB,UAAQ,SAAS;KACjC,IAAIC,SAAO,QAAQC,OAAW,iBAE5B,KAAU,uCAAuC;KACnD,IAAID,SAAO,QAAQC,OAAW,aAE5B,KAAK,aAAa,cAAc;KAClC,KAAKD,QAAM;IACb,EACF,CAAC;GACH,EACF,CAAC;EACH;CACF;CAEA,4BAA6E;EAC3E,QAAQ,aAAa;GACnB,QAAQ,SAAS,YAAY;IAC3B,IAAI,KAAK,iBAAiB,aAAa,KAAA,GAAW;KAEhD,QAAQ,UAAU;MAChB,GAAG,QAAQ;MACX,eAAe,YAAY,KAAK,gBAAgB;KAClD;KACA,KAAK,+BAA+B;IACtC;IAEA,OAAO,SAAS,SAAS,OAAO;GAClC;EACF;CACF;;CAGA,4BAAiD;EAC/C,QAAQ,SAAS,aAAa;GAC5B,OAAO,IAAI,iBAAiB,SAAS,OAAO,GAAG,EAC7C,QAAQ,UAAU,UAAU,SAAS;IACnC,IAAI,KAAK,iBAAiB,aAAa,KAAA,GAAW;KAChD,SAAS,IAAI,iBAAiB,YAAY,KAAK,gBAAgB,QAAQ;KACvE,KAAK,+BAA+B;KACpC,KAAK,UAAU,QAAQ;IACzB,OACE,KAAK,UAAU,QAAQ;GAE3B,EACF,CAAC;EACH;CACF;CAEA,MAAa,YACX,YACA,SACiB;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,OAAO,SAAS,QAAA;EAEtB,IAAI,cAAcD,gBAAiB;GACjC,MAAM,OAA+B,CAAC;GACtC,IAAI,SAAS,eAAe,KAAK,gBAAgB,QAAQ;GACzD,QACE,MAAM,GAAG,YACP;IACE,YAAY;KAAE,SAAS;KAAY,OAAO;IAAE;IAC5C,eAAe;GACjB,GACA;IAAE;IAAM,SAAS;GAAsB,CACzC,CAAC,CAAC,SAAA,CACF;EACJ,OAAO;GACL,MAAM,UAAkC,CAAC;GACzC,IAAI,SAAS,eAAe,QAAQ,gBAAgB,QAAQ;GAK5D,OAAO,UAAU,MAJJ,GAAG,KAAK,sBAAsB;IACzC,MAAM;KAAE,YAAY,GAAG,WAAW;KAAI,eAAe;IAAK;IAC1D;GACF,CAC0B,EAAA,CAAG,MAAM,4CAA4C,CAAC,CAAC;EACnF;CACF;;CAGA,MAAa,WACX,MACA,UACA,OAAqD,CAAC,GACrC;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,OAAO,KAAK,QAAA;EAElB,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP;GACE,aAAa;IACX,WAAW;IACX,OAAO;KAAE,OAAO;KAAM;IAAS;GACjC;GACA,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;GACrC,eAAe;EACjB,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAWF,OAAO,UAAU,MATJ,GAAG,KAAK,kBAAkB,EAGrC,MAAM;GACJ,OAAO;IAAE,OAAO;IAAM;GAAS;GAC/B,YAAY,GAAG,IAAI;GACnB,eAAe;EACjB,EACF,CAC0B,EAAA,CAAG,MAAM,wCAAwC,CAAC,CAAC;CAEjF;;;CAIA,MAAa,eACX,OACA,OAAqD,CAAC,GACrC;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,OAAO,KAAK,QAAA;EAClB,MAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,OAAO,MAAM,IAAI;EAEvE,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP;GACE,aAAa;IACX,WAAW;IACX,OAAO,EAAE,OAAO,MAAM;GACxB;GACA,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;GACrC,eAAe;EACjB,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAWF,OAAO,UAAU,MATJ,GAAG,KAAK,kBAAkB,EAGrC,MAAM;GACJ,OAAO,EAAE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE;GACtD,YAAY,GAAG,IAAI;GACnB,eAAe;EACjB,EACF,CAC0B,EAAA,CAAG,MAAM,wCAAwC,CAAC,CAAC;CAEjF;;;CAIA,MAAa,SAAS,eAA4C;EAChE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP,EACE,aAAa;GACX,WAAW;GACX,KAAK,EAAE,cAAc;EACvB,EACF,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAOF,OAAO,UAAU,MALJ,GAAG,KAAK,kBAAkB,EACrC,MAAM,EACJ,KAAK,EAAE,eAAe,OAAO,KAAK,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,EACtE,EACF,CAC0B,EAAA,CAAG,MAAM,4CAA4C,CAAC,CAAC;CAErF;;;;CAKA,MAAa,gBAAoF;EAC/F,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAAiB;GACjC,MAAM,QAAQ,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,SAAA,CAAU;GACnD,IAAI,KAAK,cAAc,cACrB,MAAM,IAAI,MAAM,mCAAmC,KAAK,WAAW;GAErE,MAAM,MAAM,SAAS,KAAK,WAAW,WAAW,kCAAkC;GAClF,OAAO;IACL,OAAO,KAAK,WAAW;IACvB,WAAW,UAAU,OAAO,GAAG;IAC/B,cAAc,KAAK,WAAW;GAChC;EACF,OAAO;GAKL,MAAM,OAAO,SAJM,UAChB,MAAM,GAAG,KAAK,4BAA4B,EAAE,MAAM,CAAC,EAAE,CAAC,EAAA,CAAG,MAC1D,gDAE6B,CAAC,CAAC,YAAY,2CAA2C;GACxF,OAAO;IACL,OAAO,KAAK;IACZ,WAAW,IAAI,KAAK,KAAK,SAAS;IAClC,cAAc,KAAK;GACrB;EACF;CACF;;CAGA,MAAa,aAAa,OAAgC,CAAC,GAAoB;EAC7E,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,eAAe,SACnB,KAAK,iBAAiB,UACtB,2CACF;EAEA,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,aACP;GACE,OAAO;GACP,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;EACvC,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAKF,OAAO,UAAU,MAHJ,GAAG,KAAK,oBAAoB,EACvC,MAAM;GAAE,OAAO;GAAc,YAAY,GAAG,IAAI;EAAG,EACrD,CAC0B,EAAA,CAAG,MAAM,0CAA0C,CAAC,CAAC;CAEnF;CAEA,MAAa,OAAwD;EACnE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI;EAEJ,MAAM,YAAY,YAAY,IAAI;EAClC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,KAAK,CAAC,CAAC,EAAA,CAAG;OACtB;GAGL,MAAM,WAAW,UACd,MAAM,GAAG,IAAI,UAAU,EAAA,CAAG,MAC3B,uCACF;GACA,OAAO;IACL,GAAI;IACJ,cAAe,SAAiB,gBAAgB,CAAC;GACnD;EACF;EACA,KAAK,UAAU,YAAY,IAAI,IAAI,SAAS;EAC5C,KAAK,cAAc;EACnB,OAAO;CACT;;CAGA,IAAW,aAAqD;EAC9D,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,yDAAyD;EAE3E,OAAO,KAAK;CACd;;CAGA,cAAqB,YAAwC;EAC3D,OAAO,cAAc,KAAK,WAAW,cAAc,UAAU;CAC/D;;;;CAKA,IAAW,6BAAsC;EAC/C,OAAO,iBAAiB,KAAK,WAAW,aAAa;GAAC;GAAG;GAAG;EAAC,CAAC;CAChE;;;;;;;;;CAUA,IAAW,+BAAwC;EACjD,OAAO,eAAe,KAAK,WAAW,aAAa;GAAC;GAAG;GAAG;EAAC,CAAC;CAC9D;;;;;;CAOA,MAAc,4BAA4B;EACxC,IAAI,KAAK,KAAK,cACZ;EAUF,MAAM,oBAAoB;EAC1B,MAAM,mBAAmB;EACzB,MAAM,eAA6B;GACjC,MAAM;GACN,aAAa;GACb,cAAc;GACd,mBAAmB;GACnB,QAAQ;GACR,UAAU;EACZ;EAEA,IAAI,UAAU;EACd,IAAI,gBAAgB;EACpB,MAAM,YACE,YAAY,KAAK,KAAK,GAAG,aAAa,GAC5C,eACC,MAAe;GACd,IAAI,eAAe,CAAC,GAAG;IACrB,KAAK,IAAI,QAAQ,KACf,+CAA+C,cAAc,cAAc,QAAQ,SAAS,KAAK,YACnG;IAEA,IAAI,UAAU,MAAM,GAElB,gBAAgB,KAAK,IACnB,KAAK,MAAM,gBAAgB,iBAAiB,GAC5C,gBACF;GAEJ,OACE,KAAK,IAAI,QAAQ,KACf,+CAA+C,QAAQ,SAAS,KAAK,WAAW,QAAQ,OAAO,CAAC,GAClG;GAGF;GACA,MAAM,WAAW,KAAK,eAAe,SAAS,SAAS;GACvD,KAAK,IAAI,QAAQ,KACf,yDAAyD,SAAS,iBAAiB,cAAc,GACnG;GACA,KAAK,mBAAmB,QAAQ;GAChC,OAAO;EACT,CACF;CACF;CAEA,MAAa,UAA8D;EACzE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAA,CAAG;OACzB;GACL,MAAM,OAAO,UACV,MAAM,GAAG,IAAI,aAAa,EAAA,CAAG,MAC9B,0CACF;GACA,OAAO;IACL,QAAQ,KAAK;IACb,MAAM,KAAK;IACX,cAAc,WAAW,KAAK,OAAO,KAAK,KAAK,YAAY,CAAC;GAC9D;EACF;CACF;CAEA,MAAa,cAA+D;EAC1E,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI;EACJ,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,YAAY,CAAC,CAAC,EAAA,CAAG;OAQlC,OAAO,EACL,UAPiB,UAChB,MAAM,GAAG,IAAI,kBAAkB,EAAA,CAAG,MACnC,+CAKmB,CAAC,CAAC,WAAW,CAAC,EAAA,CAAG,KAAK,MAAgD;GACvF,MAAM,OAAO;IAAE,IAAI,EAAE;IAAI,aAAa,EAAE;GAAY;GACpD,IAAI,EAAE,UAAU,KAAA,GACd,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAS,OAAO,EAAE;IAAM;GAAE;GAEnE,IAAI,EAAE,UAAU,KAAA,GACd,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAS,OAAO,EAAE;IAAM;GAAE;GAEnE,IAAI,EAAE,QAAQ,KAAA,GACZ,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAO,KAAK,EAAE;IAAI;GAAE;GAE7D,OAAO;IAAE,GAAG;IAAM,QAAQ,EAAE,WAAW,KAAA,EAAU;GAAE;EACrD,CAAC,EACH;EAGF,KAAK,mBAAmB;EACxB,OAAO;CACT;CAEA,IAAW,kBAA0D;EACnE,IAAI,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,8DAA8D;EAEhF,OAAO,KAAK;CACd;CAEA,MAAa,YACX,OAAwD,CAAC,GACR;EAGjD,OAAO,MAAM,KAAK,oBAAoB,qBAAqB,KAAK,gBAAgB,IAAI,CAAC;CACvF;CAEA,MAAc,gBACZ,OAAwD,CAAC,GACR;EACjD,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,YAAY;GACnB,OAAO,KAAK,SAAS;GACrB,mBAAmB,KAAK,qBAAqB;EAC/C,CAAC,EAAA,CACD;OACG;GACL,MAAM,OAAO,UAET,MAAM,GAAG,KAAK,sBAAsB,EAClC,MAAM;IACJ,OAAO,KAAK,SAAS;IACrB,mBAAmB,KAAK,qBAAqB;GAC/C,EACF,CAAC,EAAA,CACD,MACF,8CACF;GACA,OAAO,EACL,UAAU,KAAK,WACX;IACE,YAAY,OAAO,KAAK,SAAS,UAAU;IAC3C,mBAAmB,WAAW,KAC5B,OAAO,KAAK,KAAK,SAAS,mBAAmB,QAAQ,CACvD;GACF,IACA,KAAA,EACN;EACF;CACF;CAEA,MAAa,kBACX,OAA+D,CAAC,GACP;EACzD,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,sEAAsE;EAGxF,MAAM,OAAO,GAAG,kBAAkB;GAChC,OAAO,KAAK,SAAS;GACrB,WAAW,KAAK,aAAa;GAC7B,OAAO,KAAK,SAAS;EACvB,CAAC;EACD,MAAM,YAA4D,CAAC;EACnE,WAAW,MAAM,OAAO,KAAK,WAC3B,UAAU,KAAK,GAAG;EAEpB,OAAO;CACT;;;CAIA,MAAa,iBAAqE;EAChF,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,eAAe,CAAC,CAAC,EAAA,CAAG;OAChC;GACL,MAAM,OAAO,UACV,MAAM,GAAG,KAAK,yBAAyB,EAAE,MAAM,CAAC,EAAE,CAAC,EAAA,CAAG,MACvD,iDACF;GACA,OAAO;IACL,WAAW,WAAW,KAAK,OAAO,KAAK,KAAK,WAAW,QAAQ,CAAC;IAChE,MAAM,KAAK;GACb;EACF;CACF;;;;CAKA,MAAa,YAA+C;EAC1D,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,8DAA8D;EAGhF,QAAQ,MAAM,GAAG,UAAU,CAAC,CAAC,EAAA,CAAG,SAAS;CAC3C;;;;;;CAOA,MAAa,WAAW,OAA+D;EACrF,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,+DAA+D;EAGjF,QAAQ,MAAM,GAAG,WAAW,EAAE,MAAM,CAAC,EAAA,CAAG;CAC1C;CAEA,MAAa,OAAO,MAA6B;EAC/C,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,MAAM,GAAG,OAAO,EAAE,MAAM,OAAO,IAAI,EAAE,CAAC;OAEtC,MAAM,GAAG,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,EAAE,EAAE,CAAC;CAEpE;CAEA,SAAS,IAAa,MAAiB,CAAC,GAAoB;EAC1D,OAAO,IAAI,iBAAiB,gBAAgB;GAC1C,IAAI,mBAAmB;GACvB,IAAI,IAAI,aAAa,mBAAmB,YAAY,IAAI,CAAC,kBAAkB,IAAI,WAAW,CAAC;GAE3F,MAAM,UACJ,IAAI,YACH,KAAK,KAAK,KAAK,8BAA8B,KAAK,KAAK;GAE1D,MAAM,KAAK,KAAK,eAAe,IAAI;GACnC,IAAI,cAAcA,gBAChB,OAAO,GAAG,GAAG;IACX,OAAO;IACP;GACF,CAAC;GAGH,MAAM,WAAW,KAAK;GACtB,IAAI,SAAS,SAAS,QAAQ;IAE5B,IAAI,YAAY,KAAA,GACd,mBAAmB,YAAY,IAAI,CAAC,kBAAkB,YAAY,QAAQ,OAAO,CAAC,CAAC;IAIrF,KAAK,+BAA+B;IAMpC,OAAO,IAAI,oBAJG,KAAK,KAAK,MACpB,SAAS,KAAK,KAAK,YAAY,aAC/B,QAAQ,KAAK,KAAK,YAAY,aAI/B,QAAQ,oBAAoB,SAAS,GAAG,IACxC,SAAS,oBAAoB,WAAW,IAAI,WAAW,IAAI,CAAC,GAC7D;KACE,aAAa;KACb,UAAU,KAAK,iBAAiB;KAChC,YAAY,SAAS;KAErB,YAAY,OAAO,WACjB,OAAO,SAAS,KAAK;MAEnB,WAAW;MACX,SAAS;OAAE,WAAW;OAAe,aAAa,CAAC;MAAE;KACvD,CAAC;IACL,CACF;GACF;GAEA,MAAM,IAAI,MAAM,oDAAoD,KAAK,YAAY;EACvF,CAAC;CACH;;CAGA,MAAa,QAAQ;EACnB,IAAI,KAAK,eAAe,SAAS,QAC/B,KAAK,eAAe,UAAU,MAAM;EAItC,MAAM,KAAK,eAAe,QAAQ;CACpC;AACF"}
1
+ {"version":3,"file":"ll_client.js","names":["GrpcPlApiClient","status","GrpcStatus"],"sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient as GrpcPlApiClient } from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client\";\nimport type { ClientOptions, Interceptor } from \"@grpc/grpc-js\";\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from \"@grpc/grpc-js\";\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from \"./config\";\nimport {\n plAddressToConfig,\n type wireProtocol,\n SUPPORTED_WIRE_PROTOCOLS,\n DEFAULT_LOGIN_TIMEOUT,\n deriveUnaryDeadline,\n smoothRtt,\n} from \"./config\";\nimport type { GrpcOptions } from \"@protobuf-ts/grpc-transport\";\nimport { GrpcTransport } from \"@protobuf-ts/grpc-transport\";\nimport { LLPlTransaction } from \"./ll_transaction\";\nimport { setResourceSignaturesRequired } from \"./types\";\nimport { parsePlJwt } from \"../util/pl\";\nimport { type Dispatcher, interceptors } from \"undici\";\nimport type { Middleware } from \"openapi-fetch\";\nimport { inferAuthRefreshTime } from \"./auth\";\nimport { hasCapability, type BackendCapability } from \"./capabilities\";\nimport { defaultHttpDispatcher } from \"@milaboratories/pl-http\";\nimport type { WireClientProvider, WireClientProviderFactory, WireConnection } from \"./wire\";\nimport { parseHttpAuth } from \"@milaboratories/pl-model-common\";\nimport type * as grpcTypes from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport {\n type PlApiPaths,\n type PlRestClientType,\n createClient,\n parseResponseError,\n} from \"../proto-rest\";\nimport { notEmpty, retry, withTimeout, type RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { Code } from \"../proto-grpc/google/rpc/code\";\nimport { WebSocketBiDiStream } from \"./websocket_stream\";\nimport {\n AuthAPI_Role,\n TxAPI_ClientMessage,\n TxAPI_ServerMessage,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { isAbortedError, isTransientCallFailure, isUnauthenticated } from \"./errors\";\nimport { Timestamp } from \"../proto-grpc/google/protobuf/timestamp\";\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\n/** Bounded retry for idempotent unary calls. Deliberately short: these calls sit on the\n * connect path and gate the UI, so a few quick attempts beat a long grind. */\nconst IDEMPOTENT_RETRY_OPTIONS: RetryOptions = {\n type: \"exponentialBackoff\",\n maxAttempts: 4,\n initialDelay: 200,\n backoffMultiplier: 2,\n jitter: 0.3,\n maxDelay: 2_000,\n};\n\n// Parses leading \"<major>.<minor>.<patch>\" from a version string like\n// \"3.1.1\" or \"3.1.1-rc1\" and returns true if the parsed version is >= target.\n// Returns false for unparseable versions (safer to assume an old backend).\nfunction isVersionAtLeast(version: string, target: [number, number, number]): boolean {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(version);\n if (!match) return false;\n const parsed: [number, number, number] = [Number(match[1]), Number(match[2]), Number(match[3])];\n for (let i = 0; i < 3; i++) {\n if (parsed[i] !== target[i]) return parsed[i] > target[i];\n }\n return true;\n}\n\n// Returns true iff `version` is strictly after the release tag `target`. Dev\n// builds (`git describe`-style, e.g. \"3.5.0-224-g0ca182\") are considered\n// AFTER the matching release tag — they include commits past the tag and so\n// have any change merged after it. Released versions with the same triplet\n// return false (we want the tag itself to be excluded).\n//\n// Examples for target [3,5,0]:\n// \"3.5.0\" → false (the tagged release)\n// \"3.5.0-224-g0ca182\" → true (dev build past the tag)\n// \"3.5.1\" → true\n// \"3.4.9\" → false\n// Returns false for unparseable versions.\nfunction isAfterVersion(version: string, target: [number, number, number]): boolean {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)(.*)$/.exec(version);\n if (!match) return false;\n const parsed: [number, number, number] = [Number(match[1]), Number(match[2]), Number(match[3])];\n const suffix = match[4];\n for (let i = 0; i < 3; i++) {\n if (parsed[i] !== target[i]) return parsed[i] > target[i];\n }\n return suffix !== \"\";\n}\n\nclass WireClientProviderImpl<Client> implements WireClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(\n private readonly wireOpts: () => WireConnection,\n private readonly clientConstructor: (wireOpts: WireConnection) => Client,\n ) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined) this.client = this.clientConstructor(this.wireOpts());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements WireClientProviderFactory {\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n /** Cached Ping response. Populated by build() before it returns; refreshed by every later ping(). */\n private _serverInfo?: grpcTypes.MaintenanceAPI_Ping_Response;\n private _authMethodsSync?: grpcTypes.AuthAPI_ListMethods_Response;\n\n private _status: PlConnectionStatus = \"OK\";\n private authProbeInFlight = false;\n private readonly statusListener?: PlConnectionStatusListener;\n\n private _wireProto: wireProtocol = \"grpc\";\n private _wireConn!: WireConnection;\n\n /** The live GrpcOptions object handed to GrpcTransport. The transport keeps it by\n * reference and re-reads it on every call, so mutating `timeout` here retunes\n * subsequent deadlines without tearing down the connection. */\n private _grpcOptions?: GrpcOptions;\n\n /** Smoothed round-trip estimate in ms, from ping timings. Undefined until the first\n * successful ping, in which case the configured deadline is used as-is. */\n private _rttMs?: number;\n\n private readonly _restInterceptors: Dispatcher.DispatcherComposeInterceptor[];\n private readonly _restMiddlewares: Middleware[];\n private readonly _grpcInterceptors: Interceptor[];\n private readonly providers: WeakRef<WireClientProviderImpl<any>>[] = [];\n\n public readonly clientProvider: WireClientProvider<PlRestClientType | GrpcPlApiClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n logger?: MiLogger;\n useAutoDetectWireProtocol?: boolean;\n } = {},\n ) {\n const conf =\n typeof configOrAddress === \"string\" ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n const pl = new LLPlClient(conf, ops);\n\n // FIXME(rfiskov)[MILAB-5275]: Investigate why autodetect randomly fails; temporary turn it off.\n if (ops.useAutoDetectWireProtocol) {\n await pl.detectOptimalWireProtocol();\n }\n\n // Guarantee a ping happened so capability-gated paths (login, refresh) can branch synchronously.\n // In the autodetect path the loop's last successful ping already populated _serverInfo via the\n // side-effect in ping(); this fallback covers the path where autodetect is disabled.\n // Retried, not bare: this ping is the first contact with the server, so DNS and LB\n // warm-up land here. A single transient failure must not fail the whole connect.\n // (Not inside ping() itself: the autodetect path already wraps it in its own retry.)\n if (!pl._serverInfo) await pl.withIdempotentRetry(\"ping\", () => pl.ping());\n\n // Install the process-global signature-strictness flag based on backend version.\n setResourceSignaturesRequired(pl.supportsResourceSignatures);\n\n // Guarantee authMethods happened so client can make weighted decision on which auth method to use.\n if (!pl._authMethodsSync) await pl.authMethods();\n\n return pl;\n }\n\n private constructor(\n public readonly conf: PlClientConfig,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n logger?: MiLogger;\n } = {},\n ) {\n const { auth, statusListener } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this._restInterceptors = [];\n this._restMiddlewares = [];\n this._grpcInterceptors = [];\n\n if (auth !== undefined) {\n this._restInterceptors.push(this.createRestAuthInterceptor());\n this._grpcInterceptors.push(this.createGrpcAuthInterceptor());\n }\n this._restInterceptors.push(interceptors.retry({ statusCodes: [] })); // Handle errors with openapi-fetch middleware.\n this._restMiddlewares.push(this.createRestErrorMiddleware());\n this._grpcInterceptors.push(this.createGrpcErrorInterceptor());\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n if (this.conf.wireProtocol) {\n this._wireProto = this.conf.wireProtocol;\n }\n\n this.initWireConnection(this._wireProto);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.clientProvider = this.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new GrpcPlApiClient(wireConn.Transport);\n } else {\n return createClient<PlApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n }\n\n private initWireConnection(protocol: wireProtocol) {\n switch (protocol) {\n case \"rest\":\n this.initRestConnection();\n return;\n case \"grpc\":\n this.initGrpcConnection(this.ops.shouldUseGzip ?? false);\n return;\n default:\n ((v: never) => {\n throw new Error(\n `Unsupported wire protocol '${v as string}'. Use one of: ${SUPPORTED_WIRE_PROTOCOLS.join(\", \")}`,\n );\n })(protocol);\n }\n }\n\n private initRestConnection(): void {\n const dispatcher = defaultHttpDispatcher(this.conf.grpcProxy, this._restInterceptors);\n this._replaceWireConnection({\n type: \"rest\",\n Config: this.conf,\n Dispatcher: dispatcher,\n Middlewares: this._restMiddlewares,\n });\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport\n * @param gzip - whether to enable gzip compression\n */\n private initGrpcConnection(gzip: boolean) {\n const clientOptions: ClientOptions = {\n \"grpc.keepalive_time_ms\": 30_000, // 30 seconds\n \"grpc.service_config_disable_resolution\": 1, // Disable DNS TXT lookups for service config\n // Raises the per-stream and connection-level HTTP/2 windows. Node's 64 KB default\n // caps a big single-stream read (project open) at window/RTT rather than link speed,\n // and a lost WINDOW_UPDATE can deadlock it under packet loss.\n \"grpc-node.flow_control_window\": 16 * 1024 * 1024, // 16 MiB\n interceptors: this._grpcInterceptors,\n };\n\n if (gzip) clientOptions[\"grpc.default_compression_algorithm\"] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.unaryDeadline(),\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n const grpcProxy =\n typeof this.conf.grpcProxy === \"string\" ? { url: this.conf.grpcProxy } : this.conf.grpcProxy;\n\n if (grpcProxy?.url) {\n const url = new URL(grpcProxy.url);\n if (grpcProxy.auth) {\n const parsed = parseHttpAuth(grpcProxy.auth);\n if (parsed.scheme !== \"Basic\") {\n throw new Error(`Unsupported auth scheme: ${parsed.scheme as string}.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n process.env.grpc_proxy = url.toString();\n } else {\n delete process.env.grpc_proxy;\n }\n\n this._grpcOptions = grpcOptions;\n this._replaceWireConnection({ type: \"grpc\", Transport: new GrpcTransport(grpcOptions) });\n }\n\n /** Unary deadline derived from the observed RTT, floored by the configured value so\n * a fast link behaves exactly as before, and capped by\n * {@link MAX_ADAPTIVE_REQUEST_TIMEOUT}. */\n private unaryDeadline(): number {\n return deriveUnaryDeadline(this.conf.defaultRequestTimeout, this._rttMs);\n }\n\n /** Folds a fresh round-trip sample into the estimate and retunes the live unary\n * deadline. Called after every successful ping. */\n private recordRtt(sampleMs: number): void {\n this._rttMs = smoothRtt(this._rttMs, sampleMs);\n\n if (this._grpcOptions) {\n const next = this.unaryDeadline();\n if (next !== this._grpcOptions.timeout) {\n this.ops.logger?.info(\n `Unary deadline retuned to ${next}ms (rtt estimate ${Math.round(this._rttMs)}ms)`,\n );\n this._grpcOptions.timeout = next;\n }\n }\n }\n\n /** Smoothed round-trip estimate in ms, or undefined before the first ping. */\n public get rttEstimateMs(): number | undefined {\n return this._rttMs;\n }\n\n /** Runs an idempotent unary call with a bounded retry on transient transport failures.\n * Safe only for calls with no side effects, since a retry may duplicate the request. */\n private async withIdempotentRetry<T>(name: string, cb: () => Promise<T>): Promise<T> {\n return await retry(cb, IDEMPOTENT_RETRY_OPTIONS, (e: unknown) => {\n if (!isTransientCallFailure(e)) return false;\n this.ops.logger?.info(`${name}: transient failure, retrying. err=${String(e)}`);\n return true;\n });\n }\n\n private _replaceWireConnection(newConn: WireConnection): void {\n const oldConn = this._wireConn;\n this._wireConn = newConn;\n this._wireProto = newConn.type;\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldConn !== undefined && oldConn.type === \"grpc\") oldConn.Transport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createWireClientProvider<Client>(\n clientConstructor: (transport: WireConnection) => Client,\n ): WireClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new WireClientProviderImpl<Client>(() => this._wireConn, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get wireConnection(): WireConnection {\n return this._wireConn;\n }\n\n public get wireProtocol(): wireProtocol | undefined {\n return this._wireProto;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error(\"Client is not authenticated\");\n if (this.authInformation?.jwtToken) {\n if (this.hasCapability(\"auth:v2\")) {\n return parsePlJwt(this.authInformation?.jwtToken).sub;\n }\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n } else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (newStatus === \"Unauthenticated\" && this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n /**\n * UNAUTHENTICATED covers both a dead session (must reset) and a per-request authorization failure\n * such as a revoked resource signature (must not). Disambiguate by probing getSessionInfo — an\n * authenticated call with no resource signature: success means the session is alive and the failure\n * was resource-level; a probe that is itself Unauthenticated means real auth loss. Coalesced via\n * authProbeInFlight so a burst of failures costs one probe.\n */\n private async verifyThenMaybeEscalateUnauthenticated(): Promise<void> {\n if (this._status !== \"OK\" || this.authProbeInFlight) return;\n this.authProbeInFlight = true;\n try {\n await this.getSessionInfo();\n } catch (e) {\n if (isUnauthenticated(e)) this.updateStatus(\"Unauthenticated\");\n } finally {\n this.authProbeInFlight = false;\n }\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined ||\n Date.now() < this.refreshTimestamp ||\n this.authRefreshInProgress ||\n this._status === \"Unauthenticated\"\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const ttl = BigInt(this.conf.authTTLSeconds);\n const token = this.hasCapability(\"auth:v2\")\n ? await this.refreshToken({ ttlSeconds: ttl })\n : await this.getJwtToken(ttl);\n this.authInformation = { jwtToken: token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /**\n * Creates middleware that parses error responses and handles them centrally.\n * This middleware runs before openapi-fetch parses the response, so we need to\n * manually parse the response body for error responses.\n */\n private createRestErrorMiddleware(): Middleware {\n return {\n onResponse: async ({ request: _request, response, options: _options }) => {\n const { body, ...resOptions } = response;\n\n if ([502, 503, 504].includes(response.status)) {\n // Service unavailable, bad gateway, gateway timeout\n this.updateStatus(\"Disconnected\");\n return new Response(body, { ...resOptions, status: response.status });\n }\n\n const respErr = await parseResponseError(response);\n if (!respErr.error) {\n // No error: nice!\n return new Response(respErr.origBody ?? body, { ...resOptions, status: response.status });\n }\n\n if (typeof respErr.error === \"string\") {\n // Non-standard error or normal response: let later middleware to deal wit it.\n return new Response(respErr.error, { ...resOptions, status: response.status });\n }\n\n if (respErr.error.code === Code.UNAUTHENTICATED) {\n void this.verifyThenMaybeEscalateUnauthenticated();\n }\n\n // Let later middleware to deal with standard gRPC error.\n return new Response(respErr.origBody, { ...resOptions, status: response.status });\n },\n };\n }\n\n /** Detects certain errors and update client status accordingly when using GRPC wire connection */\n private createGrpcErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n void this.verifyThenMaybeEscalateUnauthenticated();\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus(\"Disconnected\");\n next(status);\n },\n });\n },\n });\n };\n }\n\n private createRestAuthInterceptor(): Dispatcher.DispatcherComposeInterceptor {\n return (dispatch) => {\n return (options, handler) => {\n if (this.authInformation?.jwtToken !== undefined) {\n // TODO: check this magic really works and gets called\n options.headers = {\n ...options.headers,\n authorization: \"Bearer \" + this.authInformation.jwtToken,\n };\n this.refreshAuthInformationIfNeeded();\n }\n\n return dispatch(options, handler);\n };\n };\n }\n\n /** Injects authentication information if needed */\n private createGrpcAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set(\"authorization\", \"Bearer \" + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n public async getJwtToken(\n ttlSeconds: bigint,\n options?: { authorization?: string; role?: AuthAPI_Role },\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const role = options?.role ?? AuthAPI_Role.UNSPECIFIED;\n\n if (cl instanceof GrpcPlApiClient) {\n const meta: Record<string, string> = {};\n if (options?.authorization) meta.authorization = options.authorization;\n return (\n await cl.getJWTToken(\n {\n expiration: { seconds: ttlSeconds, nanos: 0 },\n requestedRole: role,\n },\n { meta, timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const headers: Record<string, string> = {};\n if (options?.authorization) headers.authorization = options.authorization;\n const resp = cl.POST(\"/v1/auth/jwt-token\", {\n body: { expiration: `${ttlSeconds}s`, requestedRole: role },\n headers,\n });\n return notEmpty((await resp).data, \"REST: empty response for JWT token request\").token;\n }\n }\n\n /** Login via username/password. Returns a fresh JWT. Backend creates a new session per call.\n * `opts.idP` names the advertised login method to route to; omitted, the backend keeps its\n * current first-match behaviour. */\n public async loginBasic(\n user: string,\n password: string,\n opts: { ttlSeconds?: bigint; role?: AuthAPI_Role; idP?: string } = {},\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const role = opts.role ?? AuthAPI_Role.UNSPECIFIED;\n const basic =\n opts.idP === undefined ? { login: user, password } : { login: user, password, idp: opts.idP };\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"basic\",\n basic,\n },\n expiration: { seconds: ttl, nanos: 0 },\n requestedRole: role,\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n // openapi-typescript generated all body fields as required, but Login.Request\n // has a credentials oneof — only one of `basic`/`token` is sent. Cast around it.\n body: {\n basic,\n expiration: `${ttl}s`,\n requestedRole: role,\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for login request\").token;\n }\n }\n\n /** Login via opaque bearer token (controller pre-shared secret, OIDC id-token, etc.).\n * String input is UTF-8 encoded. Returns a fresh Platforma JWT. */\n public async loginWithToken(\n token: Uint8Array | string,\n opts: { ttlSeconds?: bigint; role?: AuthAPI_Role } = {},\n ): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const role = opts.role ?? AuthAPI_Role.UNSPECIFIED;\n const bytes = typeof token === \"string\" ? Buffer.from(token, \"utf8\") : token;\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"token\",\n token: { token: bytes },\n },\n expiration: { seconds: ttl, nanos: 0 },\n requestedRole: role,\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n // openapi-typescript marks all body fields as required, but Login.Request has a oneof.\n // REST encodes `bytes` as a base64 string.\n body: {\n token: { token: Buffer.from(bytes).toString(\"base64\") },\n expiration: `${ttl}s`,\n requestedRole: role,\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for login request\").token;\n }\n }\n\n /** Login via SSO: forwards the raw IdP /token JSON body to the backend.\n * Backend validates signature + nonce + audience and mints a Platforma JWT. `idP` names the\n * advertised login method to route to; omitted, the backend keeps its current first-match\n * behaviour. */\n public async loginSSO(tokenResponse: Uint8Array, idP?: string): Promise<string> {\n const cl = this.clientProvider.get();\n const sso = idP === undefined ? { tokenResponse } : { tokenResponse, idp: idP };\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.login(\n {\n credentials: {\n oneofKind: \"sso\",\n sso,\n },\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/login\", {\n body: {\n sso: { ...sso, tokenResponse: Buffer.from(tokenResponse).toString(\"base64\") },\n } as any,\n });\n return notEmpty((await resp).data, \"REST: empty response for SSO login request\").token;\n }\n }\n\n /** Request a one-time PKCE nonce + its expiry from the backend. The desktop is\n * expected to place the nonce verbatim into the OIDC auth-request before\n * redirecting to the IdP; the backend enforces the expiry on {@link loginSSO}. `idP` names the\n * advertised login method to route to; omitted, the backend keeps its current first-match\n * behaviour. */\n public async beginSSOLogin(\n idP?: string,\n ): Promise<{ nonce: string; expiresAt: Date; clientSecret?: string }> {\n const cl = this.clientProvider.get();\n const request = idP === undefined ? {} : { idp: idP };\n if (cl instanceof GrpcPlApiClient) {\n const resp = (await cl.beginSSOLogin(request).response).flow;\n if (resp.oneofKind !== \"publicPkce\") {\n throw new Error(`beginSSOLogin: unsupported flow ${resp.oneofKind}`);\n }\n const exp = notEmpty(resp.publicPkce.expiresAt, \"beginSSOLogin: missing expiresAt\");\n return {\n nonce: resp.publicPkce.nonce,\n expiresAt: Timestamp.toDate(exp),\n clientSecret: resp.publicPkce.clientSecret,\n };\n } else {\n const wsResponse = notEmpty(\n (await cl.POST(\"/v1/auth/sso/begin-login\", { body: request as any })).data,\n \"REST: empty response for beginSSOLogin request\",\n );\n const pkce = notEmpty(wsResponse.publicPkce, \"REST: missing publicPkce in beginSSOLogin\");\n return {\n nonce: pkce.nonce,\n expiresAt: new Date(pkce.expiresAt),\n clientSecret: pkce.clientSecret,\n };\n }\n }\n\n /** Refresh the current JWT, preserving session id and role. */\n public async refreshToken(opts: { ttlSeconds?: bigint } = {}): Promise<string> {\n const cl = this.clientProvider.get();\n const ttl = opts.ttlSeconds ?? BigInt(this.conf.authTTLSeconds);\n const currentToken = notEmpty(\n this.authInformation?.jwtToken,\n \"refreshToken called without a current JWT\",\n );\n\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.refreshToken(\n {\n token: currentToken,\n expiration: { seconds: ttl, nanos: 0 },\n },\n { timeout: DEFAULT_LOGIN_TIMEOUT },\n ).response\n ).token;\n } else {\n const resp = cl.POST(\"/v1/auth/refresh\", {\n body: { token: currentToken, expiration: `${ttl}s` },\n });\n return notEmpty((await resp).data, \"REST: empty response for refresh request\").token;\n }\n }\n\n public async ping(): Promise<grpcTypes.MaintenanceAPI_Ping_Response> {\n const cl = this.clientProvider.get();\n let resp: grpcTypes.MaintenanceAPI_Ping_Response;\n // Ping is the cheapest call we make, so its duration is our best RTT proxy.\n const startedAt = performance.now();\n if (cl instanceof GrpcPlApiClient) {\n resp = (await cl.ping({})).response;\n } else {\n // The REST ping response predates the `capabilities` field (proto field 9).\n // Old servers omit it; treat absence as empty capability list.\n const pingData = notEmpty(\n (await cl.GET(\"/v1/ping\")).data,\n \"REST: empty response for ping request\",\n );\n resp = {\n ...(pingData as unknown as grpcTypes.MaintenanceAPI_Ping_Response),\n capabilities: (pingData as any).capabilities ?? [],\n };\n }\n this.recordRtt(performance.now() - startedAt);\n this._serverInfo = resp;\n return resp;\n }\n\n /** Cached Ping response. Always populated post-build(); throws if accessed earlier. */\n public get serverInfo(): grpcTypes.MaintenanceAPI_Ping_Response {\n if (!this._serverInfo) {\n throw new Error(\"LLPlClient.serverInfo accessed before build() completed\");\n }\n return this._serverInfo;\n }\n\n /** Synchronous capability check against the cached Ping response. */\n public hasCapability(capability: BackendCapability): boolean {\n return hasCapability(this.serverInfo.capabilities, capability);\n }\n\n /** True if the backend produces signed resource ids (and accepts the\n * setDefaultColor TX request). Tagged at 3.3.0 — backends older than this\n * return resources without signatures and reject color-proof requests. */\n public get supportsResourceSignatures(): boolean {\n return isVersionAtLeast(this.serverInfo.coreVersion, [3, 3, 0]);\n }\n\n /**\n * True if the backend honors per-file `permissions` on workdir fill rules, so\n * `exec.builder().writeFile/addFile({ writable: true })` takes effect. When false\n * the requested mode is ignored and files land at the canonical archive perm.\n *\n * [3, 5, 0] excludes the tagged 3.5.0 release but includes dev builds past the\n * tag (e.g. \"3.5.0-224-g0ca182\"), which is where the support lands.\n */\n public get supportsWritableWorkdirFiles(): boolean {\n return isAfterVersion(this.serverInfo.coreVersion, [3, 5, 0]);\n }\n\n /**\n * Detects the best available wire protocol.\n * If wireProtocol is explicitly configured, does nothing.\n * Otherwise probes the current protocol via ping; if it fails, switches to the alternative.\n */\n private async detectOptimalWireProtocol() {\n if (this.conf.wireProtocol) {\n return;\n }\n\n // Each retry is:\n // - ping request timeout (100 to 3_000ms)\n // - backoff delay (30 to 500ms)\n //\n // 30 attempts are ~43 seconds of overall waiting time.\n // Think twice on overall time this thing takes to complete when changing these parameters.\n // It may block UI when connecting to the server and loading projects list.\n const pingTimeoutFactor = 1.3;\n const maxPingTimeoutMs = 3_000;\n const retryOptions: RetryOptions = {\n type: \"exponentialBackoff\",\n maxAttempts: 30,\n initialDelay: 30,\n backoffMultiplier: 1.3,\n jitter: 0.2,\n maxDelay: 500,\n };\n\n let attempt = 1;\n let pingTimeoutMs = 100;\n await retry(\n () => withTimeout(this.ping(), pingTimeoutMs),\n retryOptions,\n (e: unknown) => {\n if (isAbortedError(e)) {\n this.ops.logger?.info(\n `Wire proto autodetect: ping timed out after ${pingTimeoutMs}ms: attempt=${attempt}, wire=${this._wireProto}`,\n );\n\n if (attempt % 2 === 0) {\n // We have 2 wire protocols to check. Increase timeout each 2 attempts.\n pingTimeoutMs = Math.min(\n Math.round(pingTimeoutMs * pingTimeoutFactor),\n maxPingTimeoutMs,\n );\n }\n } else {\n this.ops.logger?.info(\n `Wire proto autodetect: ping failed: attempt=${attempt}, wire=${this._wireProto}, err=${String(e)}`,\n );\n }\n\n attempt++;\n const protocol = this._wireProto === \"grpc\" ? \"rest\" : \"grpc\";\n this.ops.logger?.info(\n `Wire protocol autodetect next attempt: will try wire '${protocol}' with timeout ${pingTimeoutMs}ms`,\n );\n this.initWireConnection(protocol);\n return true;\n },\n );\n }\n\n public async license(): Promise<grpcTypes.MaintenanceAPI_License_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (await cl.license({})).response;\n } else {\n const resp = notEmpty(\n (await cl.GET(\"/v1/license\")).data,\n \"REST: empty response for license request\",\n );\n return {\n status: resp.status,\n isOk: resp.isOk,\n responseBody: Uint8Array.from(Buffer.from(resp.responseBody)),\n };\n }\n }\n\n public async authMethods(): Promise<grpcTypes.AuthAPI_ListMethods_Response> {\n const cl = this.clientProvider.get();\n let resp: grpcTypes.AuthAPI_ListMethods_Response;\n if (cl instanceof GrpcPlApiClient) {\n resp = (await cl.authMethods({})).response;\n } else {\n const wsResponse = notEmpty(\n (await cl.GET(\"/v1/auth/methods\")).data,\n \"REST: empty response for auth methods request\",\n );\n // OpenAPI schema flattens the protobuf oneof into `{ basic?, token? }`,\n // while protobuf-ts models it as a discriminated union. Reshape per item.\n resp = {\n methods: (wsResponse.methods ?? []).map((m): grpcTypes.AuthAPI_ListMethods_MethodInfo => {\n const base = { id: m.id, description: m.description, title: m.title };\n if (m.basic !== undefined) {\n return { ...base, method: { oneofKind: \"basic\", basic: m.basic } };\n }\n if (m.token !== undefined) {\n return { ...base, method: { oneofKind: \"token\", token: m.token } };\n }\n if (m.sso !== undefined) {\n return { ...base, method: { oneofKind: \"sso\", sso: m.sso } };\n }\n return { ...base, method: { oneofKind: undefined } };\n }),\n };\n }\n\n this._authMethodsSync = resp;\n return resp;\n }\n\n public get authMethodsSync(): grpcTypes.AuthAPI_ListMethods_Response {\n if (!this._authMethodsSync) {\n throw new Error(\"LLPlClient.authMethodsSync accessed before build() completed\");\n }\n return this._authMethodsSync;\n }\n\n public async getUserRoot(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<grpcTypes.AuthAPI_GetUserRoot_Response> {\n // Retryable even with createIfNotExists: the call is get-or-create keyed on login, so a\n // second attempt returns the existing root rather than making another one.\n return await this.withIdempotentRetry(\"getUserRoot\", () => this.getUserRootOnce(opts));\n }\n\n private async getUserRootOnce(\n opts: { login?: string; createIfNotExists?: boolean } = {},\n ): Promise<grpcTypes.AuthAPI_GetUserRoot_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (\n await cl.getUserRoot({\n login: opts.login ?? \"\",\n createIfNotExists: opts.createIfNotExists ?? false,\n })\n ).response;\n } else {\n const resp = notEmpty(\n (\n await cl.POST(\"/v1/auth/user-root\", {\n body: {\n login: opts.login ?? \"\",\n createIfNotExists: opts.createIfNotExists ?? false,\n },\n })\n ).data,\n \"REST: empty response for getUserRoot request\",\n );\n return {\n userRoot: resp.userRoot\n ? {\n resourceId: BigInt(resp.userRoot.resourceId),\n resourceSignature: Uint8Array.from(\n Buffer.from(resp.userRoot.resourceSignature, \"base64\"),\n ),\n }\n : undefined,\n };\n }\n }\n\n public async listUserResources(\n opts: { login?: string; startFrom?: bigint; limit?: number } = {},\n ): Promise<grpcTypes.AuthAPI_ListUserResources_Response[]> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"ListUserResources requires gRPC wire protocol; REST is not supported\");\n }\n\n const call = cl.listUserResources({\n login: opts.login ?? \"\",\n startFrom: opts.startFrom ?? 0n,\n limit: opts.limit ?? 0,\n });\n const responses: grpcTypes.AuthAPI_ListUserResources_Response[] = [];\n for await (const msg of call.responses) {\n responses.push(msg);\n }\n return responses;\n }\n\n /** Returns the authenticated caller's session id and effective role.\n * Models the {@link getUserRoot} wrapper: gRPC unary with a REST fallback. */\n public async getSessionInfo(): Promise<grpcTypes.AuthAPI_GetSessionInfo_Response> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return (await cl.getSessionInfo({})).response;\n } else {\n const resp = notEmpty(\n (await cl.POST(\"/v1/auth/session-info\", { body: {} })).data,\n \"REST: empty response for getSessionInfo request\",\n );\n return {\n sessionId: Uint8Array.from(Buffer.from(resp.sessionId, \"base64\")),\n role: resp.role as AuthAPI_Role,\n };\n }\n }\n\n /** Lists the users known to the server — the recipient picker's source. A user\n * becomes known on first login; provisioned users who have never logged in do not\n * appear. gRPC-only (unary, no REST binding). */\n public async listUsers(): Promise<grpcTypes.AuthAPI_User[]> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"ListUsers requires gRPC wire protocol; REST is not supported\");\n }\n\n return (await cl.listUsers({})).response.users;\n }\n\n /** Deletes a user account: the record, its identity-index entries (login, email and any\n * alternative of either), its grants, and its root resource with everything still attached\n * under it. Admin/controller credentials only, and irreversible — re-attach anything worth\n * keeping to another user's root first.\n * gRPC-only (unary, no REST binding), like {@link listUsers}. */\n public async deleteUser(login: string): Promise<grpcTypes.AuthAPI_DeleteUser_Response> {\n const cl = this.clientProvider.get();\n\n if (!(cl instanceof GrpcPlApiClient)) {\n throw new Error(\"DeleteUser requires gRPC wire protocol; REST is not supported\");\n }\n\n return (await cl.deleteUser({ login })).response;\n }\n\n public async txSync(txId: bigint): Promise<void> {\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n await cl.txSync({ txId: BigInt(txId) });\n } else {\n await cl.POST(\"/v1/tx-sync\", { body: { txId: txId.toString() } });\n }\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n\n const timeout =\n ops.timeout ??\n (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout);\n\n const cl = this.clientProvider.get();\n if (cl instanceof GrpcPlApiClient) {\n return cl.tx({\n abort: totalAbortSignal,\n timeout,\n });\n }\n\n const wireConn = this.wireConnection;\n if (wireConn.type === \"rest\") {\n // For REST/WebSocket protocol, timeout needs to be converted to AbortSignal\n if (timeout !== undefined) {\n totalAbortSignal = AbortSignal.any([totalAbortSignal, AbortSignal.timeout(timeout)]);\n }\n\n // The gRPC transport has the auth interceptor that already handles it, but here we need to refresh the auth information to be safe.\n this.refreshAuthInformationIfNeeded();\n\n const wsUrl = this.conf.ssl\n ? `wss://${this.conf.hostAndPort}/v1/ws/tx`\n : `ws://${this.conf.hostAndPort}/v1/ws/tx`;\n\n return new WebSocketBiDiStream(\n wsUrl,\n (msg) => TxAPI_ClientMessage.toBinary(msg),\n (data) => TxAPI_ServerMessage.fromBinary(new Uint8Array(data)),\n {\n abortSignal: totalAbortSignal,\n jwtToken: this.authInformation?.jwtToken,\n dispatcher: wireConn.Dispatcher,\n\n onComplete: async (stream) =>\n stream.requests.send({\n // Ask server to gracefully close the stream on its side, if not done yet.\n requestId: 0,\n request: { oneofKind: \"streamClose\", streamClose: {} },\n }),\n },\n );\n }\n\n throw new Error(`transactions are not supported for wire protocol ${this._wireProto}`);\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n if (this.wireConnection.type === \"grpc\") {\n this.wireConnection.Transport.close();\n } else {\n // TODO: close all WS connections\n }\n await this.httpDispatcher.destroy();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,2BAAyC;CAC7C,MAAM;CACN,aAAa;CACb,cAAc;CACd,mBAAmB;CACnB,QAAQ;CACR,UAAU;AACZ;AAKA,SAAS,iBAAiB,SAAiB,QAA2C;CACpF,MAAM,QAAQ,yBAAyB,KAAK,OAAO;CACnD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,SAAmC;EAAC,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;CAAC;CAC9F,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,OAAO;CAEzD,OAAO;AACT;AAcA,SAAS,eAAe,SAAiB,QAA2C;CAClF,MAAM,QAAQ,8BAA8B,KAAK,OAAO;CACxD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,SAAmC;EAAC,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;EAAG,OAAO,MAAM,EAAE;CAAC;CAC9F,MAAM,SAAS,MAAM;CACrB,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,OAAO;CAEzD,OAAO,WAAW;AACpB;AAEA,IAAM,yBAAN,MAA2E;CAItD;CACA;CAJnB,SAAqC,KAAA;CAErC,YACE,UACA,mBACA;EAFiB,KAAA,WAAA;EACA,KAAA,oBAAA;CAChB;CAEH,QAAqB;EACnB,KAAK,SAAS,KAAA;CAChB;CAEA,MAAqB;EACnB,IAAI,KAAK,WAAW,KAAA,GAAW,KAAK,SAAS,KAAK,kBAAkB,KAAK,SAAS,CAAC;EACnF,OAAO,KAAK;CACd;AACF;;AAGA,IAAa,aAAb,MAAa,WAAgD;CA+EzC;CACC;;CA9EnB;;CAEA;;CAEA;;CAEA;;CAEA;;CAGA;CACA;CAEA,UAAsC;CACtC,oBAA4B;CAC5B;CAEA,aAAmC;CACnC;;;;CAKA;;;CAIA;CAEA;CACA;CACA;CACA,YAAqE,CAAC;CAEtE;CAEA;CAEA,aAAoB,MAClB,iBACA,MAMI,CAAC,GACL;EAIA,MAAM,KAAK,IAAI,WAFb,OAAO,oBAAoB,WAAW,kBAAkB,eAAe,IAAI,iBAE7C,GAAG;EAGnC,IAAI,IAAI,2BACN,MAAM,GAAG,0BAA0B;EASrC,IAAI,CAAC,GAAG,aAAa,MAAM,GAAG,oBAAoB,cAAc,GAAG,KAAK,CAAC;EAGzE,8BAA8B,GAAG,0BAA0B;EAG3D,IAAI,CAAC,GAAG,kBAAkB,MAAM,GAAG,YAAY;EAE/C,OAAO;CACT;CAEA,YACE,MACA,MAKI,CAAC,GACL;EAPgB,KAAA,OAAA;EACC,KAAA,MAAA;EAOjB,MAAM,EAAE,MAAM,mBAAmB;EAEjC,IAAI,SAAS,KAAA,GAAW;GACtB,KAAK,mBAAmB,qBACtB,KAAK,iBACL,KAAK,KAAK,qBACZ;GACA,KAAK,kBAAkB,KAAK;GAC5B,KAAK,eAAe,KAAK;GACzB,KAAK,uBAAuB,KAAK;GACjC,KAAK,cAAc,KAAK;EAC1B;EAEA,KAAK,oBAAoB,CAAC;EAC1B,KAAK,mBAAmB,CAAC;EACzB,KAAK,oBAAoB,CAAC;EAE1B,IAAI,SAAS,KAAA,GAAW;GACtB,KAAK,kBAAkB,KAAK,KAAK,0BAA0B,CAAC;GAC5D,KAAK,kBAAkB,KAAK,KAAK,0BAA0B,CAAC;EAC9D;EACA,KAAK,kBAAkB,KAAK,aAAa,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;EACnE,KAAK,iBAAiB,KAAK,KAAK,0BAA0B,CAAC;EAC3D,KAAK,kBAAkB,KAAK,KAAK,2BAA2B,CAAC;EAE7D,KAAK,iBAAiB,sBAAsB,KAAK,KAAK,SAAS;EAC/D,IAAI,KAAK,KAAK,cACZ,KAAK,aAAa,KAAK,KAAK;EAG9B,KAAK,mBAAmB,KAAK,UAAU;EAEvC,IAAI,mBAAmB,KAAA,GAAW;GAChC,KAAK,iBAAiB;GACtB,eAAe,KAAK,OAAO;EAC7B;EAEA,KAAK,iBAAiB,KAAK,0BAA0B,aAAa;GAChE,IAAI,SAAS,SAAS,QACpB,OAAO,IAAIA,eAAgB,SAAS,SAAS;QAE7C,OAAO,aAAyB;IAC9B,aAAa,SAAS,OAAO;IAC7B,KAAK,SAAS,OAAO;IACrB,YAAY,SAAS;IACrB,aAAa,SAAS;GACxB,CAAC;EAEL,CAAC;CACH;CAEA,mBAA2B,UAAwB;EACjD,QAAQ,UAAR;GACE,KAAK;IACH,KAAK,mBAAmB;IACxB;GACF,KAAK;IACH,KAAK,mBAAmB,KAAK,IAAI,iBAAiB,KAAK;IACvD;GACF,SACE,EAAE,MAAa;IACb,MAAM,IAAI,MACR,8BAA8B,EAAY,iBAAiB,yBAAyB,KAAK,IAAI,GAC/F;GACF,EAAA,CAAG,QAAQ;EACf;CACF;CAEA,qBAAmC;EACjC,MAAM,aAAa,sBAAsB,KAAK,KAAK,WAAW,KAAK,iBAAiB;EACpF,KAAK,uBAAuB;GAC1B,MAAM;GACN,QAAQ,KAAK;GACb,YAAY;GACZ,aAAa,KAAK;EACpB,CAAC;CACH;;;;;CAMA,mBAA2B,MAAe;EACxC,MAAM,gBAA+B;GACnC,0BAA0B;GAC1B,0CAA0C;GAI1C,iCAAiC,KAAK,OAAO;GAC7C,cAAc,KAAK;EACrB;EAEA,IAAI,MAAM,cAAc,wCAAwC,sBAAsB;EAStF,MAAM,cAA2B;GAC/B,MAAM,KAAK,KAAK;GAChB,SAAS,KAAK,cAAc;GAC5B,oBAAoB,KAAK,KAAK,MAC1B,mBAAmB,UAAU,IAC7B,mBAAmB,eAAe;GACtC;EACF;EAEA,MAAM,YACJ,OAAO,KAAK,KAAK,cAAc,WAAW,EAAE,KAAK,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK;EAErF,IAAI,WAAW,KAAK;GAClB,MAAM,MAAM,IAAI,IAAI,UAAU,GAAG;GACjC,IAAI,UAAU,MAAM;IAClB,MAAM,SAAS,cAAc,UAAU,IAAI;IAC3C,IAAI,OAAO,WAAW,SACpB,MAAM,IAAI,MAAM,4BAA4B,OAAO,OAAiB,EAAE;IAExE,IAAI,WAAW,OAAO;IACtB,IAAI,WAAW,OAAO;GACxB;GACA,QAAQ,IAAI,aAAa,IAAI,SAAS;EACxC,OACE,OAAO,QAAQ,IAAI;EAGrB,KAAK,eAAe;EACpB,KAAK,uBAAuB;GAAE,MAAM;GAAQ,WAAW,IAAI,cAAc,WAAW;EAAE,CAAC;CACzF;;;;CAKA,gBAAgC;EAC9B,OAAO,oBAAoB,KAAK,KAAK,uBAAuB,KAAK,MAAM;CACzE;;;CAIA,UAAkB,UAAwB;EACxC,KAAK,SAAS,UAAU,KAAK,QAAQ,QAAQ;EAE7C,IAAI,KAAK,cAAc;GACrB,MAAM,OAAO,KAAK,cAAc;GAChC,IAAI,SAAS,KAAK,aAAa,SAAS;IACtC,KAAK,IAAI,QAAQ,KACf,6BAA6B,KAAK,mBAAmB,KAAK,MAAM,KAAK,MAAM,EAAE,IAC/E;IACA,KAAK,aAAa,UAAU;GAC9B;EACF;CACF;;CAGA,IAAW,gBAAoC;EAC7C,OAAO,KAAK;CACd;;;CAIA,MAAc,oBAAuB,MAAc,IAAkC;EACnF,OAAO,MAAM,MAAM,IAAI,2BAA2B,MAAe;GAC/D,IAAI,CAAC,uBAAuB,CAAC,GAAG,OAAO;GACvC,KAAK,IAAI,QAAQ,KAAK,GAAG,KAAK,qCAAqC,OAAO,CAAC,GAAG;GAC9E,OAAO;EACT,CAAC;CACH;CAEA,uBAA+B,SAA+B;EAC5D,MAAM,UAAU,KAAK;EACrB,KAAK,YAAY;EACjB,KAAK,aAAa,QAAQ;EAG1B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAAK;GAC9C,MAAM,WAAW,KAAK,UAAU,EAAE,CAAC,MAAM;GACzC,IAAI,aAAa,KAAA,GAAW;IAE1B,KAAK,UAAU,OAAO,GAAG,CAAC;IAC1B;GACF,OACE,SAAS,MAAM;EAEnB;EAEA,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,QAAQ,QAAQ,UAAU,MAAM;CAChF;CAEA,yBAAiC;;;;;;CAOjC,yBACE,mBAC4B;EAI5B,KAAK;EACL,IAAI,KAAK,0BAA0B,IAAI;GACrC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAEzC,IADiB,KAAK,UAAU,EAAE,CAAC,MACxB,MAAM,KAAA,GAAW;IAC1B,KAAK,UAAU,OAAO,GAAG,CAAC;IAC1B;GACF;GAEF,KAAK,yBAAyB;EAChC;EAEA,MAAM,WAAW,IAAI,6BAAqC,KAAK,WAAW,iBAAiB;EAC3F,KAAK,UAAU,KAAK,IAAI,QAAQ,QAAQ,CAAC;EACzC,OAAO;CACT;CAEA,IAAW,iBAAiC;EAC1C,OAAO,KAAK;CACd;CAEA,IAAW,eAAyC;EAClD,OAAO,KAAK;CACd;;;;CAKA,IAAW,gBAAyB;EAClC,OAAO,KAAK,oBAAoB,KAAA;CAClC;;CAGA,IAAW,WAA0B;EACnC,IAAI,CAAC,KAAK,eAAe,MAAM,IAAI,MAAM,6BAA6B;EACtE,IAAI,KAAK,iBAAiB,UAAU;GAClC,IAAI,KAAK,cAAc,SAAS,GAC9B,OAAO,WAAW,KAAK,iBAAiB,QAAQ,CAAC,CAAC;GAEpD,OAAO,WAAW,KAAK,iBAAiB,QAAQ,CAAC,CAAC,KAAK;EACzD,OAAO,OAAO;CAChB;CAEA,aAAqB,WAA+B;EAClD,QAAQ,eAAe;GACrB,IAAI,KAAK,YAAY,WAAW;IAC9B,KAAK,UAAU;IACf,IAAI,KAAK,mBAAmB,KAAA,GAAW,KAAK,eAAe,KAAK,OAAO;IACvE,IAAI,cAAc,qBAAqB,KAAK,gBAAgB,KAAA,GAAW,KAAK,YAAY;GAC1F;EACF,CAAC;CACH;;;;;;;;CASA,MAAc,yCAAwD;EACpE,IAAI,KAAK,YAAY,QAAQ,KAAK,mBAAmB;EACrD,KAAK,oBAAoB;EACzB,IAAI;GACF,MAAM,KAAK,eAAe;EAC5B,SAAS,GAAG;GACV,IAAI,kBAAkB,CAAC,GAAG,KAAK,aAAa,iBAAiB;EAC/D,UAAU;GACR,KAAK,oBAAoB;EAC3B;CACF;CAEA,IAAW,SAA6B;EACtC,OAAO,KAAK;CACd;CAEA,wBAAyC;CAEzC,iCAA+C;EAC7C,IACE,KAAK,qBAAqB,KAAA,KAC1B,KAAK,IAAI,IAAI,KAAK,oBAClB,KAAK,yBACL,KAAK,YAAY,mBAEjB;EAGF,KAAK,wBAAwB;EAC7B,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,MAAM,OAAO,KAAK,KAAK,cAAc;IAC3C,MAAM,QAAQ,KAAK,cAAc,SAAS,IACtC,MAAM,KAAK,aAAa,EAAE,YAAY,IAAI,CAAC,IAC3C,MAAM,KAAK,YAAY,GAAG;IAC9B,KAAK,kBAAkB,EAAE,UAAU,MAAM;IACzC,KAAK,mBAAmB,qBACtB,KAAK,iBACL,KAAK,KAAK,qBACZ;IACA,IAAI,KAAK,cAAc,KAAK,aAAa,KAAK,eAAe;GAC/D,SAAS,GAAY;IACnB,IAAI,KAAK,sBAAsB,KAAK,qBAAqB,CAAC;GAC5D,UAAU;IACR,KAAK,wBAAwB;GAC/B;EACF,EAAA,CAAG;CACL;;;;;;CAOA,4BAAgD;EAC9C,OAAO,EACL,YAAY,OAAO,EAAE,SAAS,UAAU,UAAU,SAAS,eAAe;GACxE,MAAM,EAAE,MAAM,GAAG,eAAe;GAEhC,IAAI;IAAC;IAAK;IAAK;GAAG,CAAC,CAAC,SAAS,SAAS,MAAM,GAAG;IAE7C,KAAK,aAAa,cAAc;IAChC,OAAO,IAAI,SAAS,MAAM;KAAE,GAAG;KAAY,QAAQ,SAAS;IAAO,CAAC;GACtE;GAEA,MAAM,UAAU,MAAM,mBAAmB,QAAQ;GACjD,IAAI,CAAC,QAAQ,OAEX,OAAO,IAAI,SAAS,QAAQ,YAAY,MAAM;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;GAG1F,IAAI,OAAO,QAAQ,UAAU,UAE3B,OAAO,IAAI,SAAS,QAAQ,OAAO;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;GAG/E,IAAI,QAAQ,MAAM,SAAA,IAChB,KAAU,uCAAuC;GAInD,OAAO,IAAI,SAAS,QAAQ,UAAU;IAAE,GAAG;IAAY,QAAQ,SAAS;GAAO,CAAC;EAClF,EACF;CACF;;CAGA,6BAAkD;EAChD,QAAQ,SAAS,aAAa;GAC5B,OAAO,IAAI,iBAAiB,SAAS,OAAO,GAAG,EAC7C,QAAQ,UAAU,UAAU,SAAS;IACnC,KAAK,UAAU,EACb,kBAAkB,UAAQ,SAAS;KACjC,IAAIC,SAAO,QAAQC,OAAW,iBAE5B,KAAU,uCAAuC;KACnD,IAAID,SAAO,QAAQC,OAAW,aAE5B,KAAK,aAAa,cAAc;KAClC,KAAKD,QAAM;IACb,EACF,CAAC;GACH,EACF,CAAC;EACH;CACF;CAEA,4BAA6E;EAC3E,QAAQ,aAAa;GACnB,QAAQ,SAAS,YAAY;IAC3B,IAAI,KAAK,iBAAiB,aAAa,KAAA,GAAW;KAEhD,QAAQ,UAAU;MAChB,GAAG,QAAQ;MACX,eAAe,YAAY,KAAK,gBAAgB;KAClD;KACA,KAAK,+BAA+B;IACtC;IAEA,OAAO,SAAS,SAAS,OAAO;GAClC;EACF;CACF;;CAGA,4BAAiD;EAC/C,QAAQ,SAAS,aAAa;GAC5B,OAAO,IAAI,iBAAiB,SAAS,OAAO,GAAG,EAC7C,QAAQ,UAAU,UAAU,SAAS;IACnC,IAAI,KAAK,iBAAiB,aAAa,KAAA,GAAW;KAChD,SAAS,IAAI,iBAAiB,YAAY,KAAK,gBAAgB,QAAQ;KACvE,KAAK,+BAA+B;KACpC,KAAK,UAAU,QAAQ;IACzB,OACE,KAAK,UAAU,QAAQ;GAE3B,EACF,CAAC;EACH;CACF;CAEA,MAAa,YACX,YACA,SACiB;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,OAAO,SAAS,QAAA;EAEtB,IAAI,cAAcD,gBAAiB;GACjC,MAAM,OAA+B,CAAC;GACtC,IAAI,SAAS,eAAe,KAAK,gBAAgB,QAAQ;GACzD,QACE,MAAM,GAAG,YACP;IACE,YAAY;KAAE,SAAS;KAAY,OAAO;IAAE;IAC5C,eAAe;GACjB,GACA;IAAE;IAAM,SAAS;GAAsB,CACzC,CAAC,CAAC,SAAA,CACF;EACJ,OAAO;GACL,MAAM,UAAkC,CAAC;GACzC,IAAI,SAAS,eAAe,QAAQ,gBAAgB,QAAQ;GAK5D,OAAO,UAAU,MAJJ,GAAG,KAAK,sBAAsB;IACzC,MAAM;KAAE,YAAY,GAAG,WAAW;KAAI,eAAe;IAAK;IAC1D;GACF,CAC0B,EAAA,CAAG,MAAM,4CAA4C,CAAC,CAAC;EACnF;CACF;;;;CAKA,MAAa,WACX,MACA,UACA,OAAmE,CAAC,GACnD;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,OAAO,KAAK,QAAA;EAClB,MAAM,QACJ,KAAK,QAAQ,KAAA,IAAY;GAAE,OAAO;GAAM;EAAS,IAAI;GAAE,OAAO;GAAM;GAAU,KAAK,KAAK;EAAI;EAE9F,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP;GACE,aAAa;IACX,WAAW;IACX;GACF;GACA,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;GACrC,eAAe;EACjB,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAWF,OAAO,UAAU,MATJ,GAAG,KAAK,kBAAkB,EAGrC,MAAM;GACJ;GACA,YAAY,GAAG,IAAI;GACnB,eAAe;EACjB,EACF,CAC0B,EAAA,CAAG,MAAM,wCAAwC,CAAC,CAAC;CAEjF;;;CAIA,MAAa,eACX,OACA,OAAqD,CAAC,GACrC;EACjB,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,OAAO,KAAK,QAAA;EAClB,MAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,OAAO,MAAM,IAAI;EAEvE,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP;GACE,aAAa;IACX,WAAW;IACX,OAAO,EAAE,OAAO,MAAM;GACxB;GACA,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;GACrC,eAAe;EACjB,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAWF,OAAO,UAAU,MATJ,GAAG,KAAK,kBAAkB,EAGrC,MAAM;GACJ,OAAO,EAAE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE;GACtD,YAAY,GAAG,IAAI;GACnB,eAAe;EACjB,EACF,CAC0B,EAAA,CAAG,MAAM,wCAAwC,CAAC,CAAC;CAEjF;;;;;CAMA,MAAa,SAAS,eAA2B,KAA+B;EAC9E,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,QAAQ,KAAA,IAAY,EAAE,cAAc,IAAI;GAAE;GAAe,KAAK;EAAI;EAC9E,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,MACP,EACE,aAAa;GACX,WAAW;GACX;EACF,EACF,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAOF,OAAO,UAAU,MALJ,GAAG,KAAK,kBAAkB,EACrC,MAAM,EACJ,KAAK;GAAE,GAAG;GAAK,eAAe,OAAO,KAAK,aAAa,CAAC,CAAC,SAAS,QAAQ;EAAE,EAC9E,EACF,CAC0B,EAAA,CAAG,MAAM,4CAA4C,CAAC,CAAC;CAErF;;;;;;CAOA,MAAa,cACX,KACoE;EACpE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,UAAU,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK,IAAI;EACpD,IAAI,cAAcA,gBAAiB;GACjC,MAAM,QAAQ,MAAM,GAAG,cAAc,OAAO,CAAC,CAAC,SAAA,CAAU;GACxD,IAAI,KAAK,cAAc,cACrB,MAAM,IAAI,MAAM,mCAAmC,KAAK,WAAW;GAErE,MAAM,MAAM,SAAS,KAAK,WAAW,WAAW,kCAAkC;GAClF,OAAO;IACL,OAAO,KAAK,WAAW;IACvB,WAAW,UAAU,OAAO,GAAG;IAC/B,cAAc,KAAK,WAAW;GAChC;EACF,OAAO;GAKL,MAAM,OAAO,SAJM,UAChB,MAAM,GAAG,KAAK,4BAA4B,EAAE,MAAM,QAAe,CAAC,EAAA,CAAG,MACtE,gDAE6B,CAAC,CAAC,YAAY,2CAA2C;GACxF,OAAO;IACL,OAAO,KAAK;IACZ,WAAW,IAAI,KAAK,KAAK,SAAS;IAClC,cAAc,KAAK;GACrB;EACF;CACF;;CAGA,MAAa,aAAa,OAAgC,CAAC,GAAoB;EAC7E,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,MAAM,MAAM,KAAK,cAAc,OAAO,KAAK,KAAK,cAAc;EAC9D,MAAM,eAAe,SACnB,KAAK,iBAAiB,UACtB,2CACF;EAEA,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,aACP;GACE,OAAO;GACP,YAAY;IAAE,SAAS;IAAK,OAAO;GAAE;EACvC,GACA,EAAE,SAAS,sBAAsB,CACnC,CAAC,CAAC,SAAA,CACF;OAKF,OAAO,UAAU,MAHJ,GAAG,KAAK,oBAAoB,EACvC,MAAM;GAAE,OAAO;GAAc,YAAY,GAAG,IAAI;EAAG,EACrD,CAC0B,EAAA,CAAG,MAAM,0CAA0C,CAAC,CAAC;CAEnF;CAEA,MAAa,OAAwD;EACnE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI;EAEJ,MAAM,YAAY,YAAY,IAAI;EAClC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,KAAK,CAAC,CAAC,EAAA,CAAG;OACtB;GAGL,MAAM,WAAW,UACd,MAAM,GAAG,IAAI,UAAU,EAAA,CAAG,MAC3B,uCACF;GACA,OAAO;IACL,GAAI;IACJ,cAAe,SAAiB,gBAAgB,CAAC;GACnD;EACF;EACA,KAAK,UAAU,YAAY,IAAI,IAAI,SAAS;EAC5C,KAAK,cAAc;EACnB,OAAO;CACT;;CAGA,IAAW,aAAqD;EAC9D,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,yDAAyD;EAE3E,OAAO,KAAK;CACd;;CAGA,cAAqB,YAAwC;EAC3D,OAAO,cAAc,KAAK,WAAW,cAAc,UAAU;CAC/D;;;;CAKA,IAAW,6BAAsC;EAC/C,OAAO,iBAAiB,KAAK,WAAW,aAAa;GAAC;GAAG;GAAG;EAAC,CAAC;CAChE;;;;;;;;;CAUA,IAAW,+BAAwC;EACjD,OAAO,eAAe,KAAK,WAAW,aAAa;GAAC;GAAG;GAAG;EAAC,CAAC;CAC9D;;;;;;CAOA,MAAc,4BAA4B;EACxC,IAAI,KAAK,KAAK,cACZ;EAUF,MAAM,oBAAoB;EAC1B,MAAM,mBAAmB;EACzB,MAAM,eAA6B;GACjC,MAAM;GACN,aAAa;GACb,cAAc;GACd,mBAAmB;GACnB,QAAQ;GACR,UAAU;EACZ;EAEA,IAAI,UAAU;EACd,IAAI,gBAAgB;EACpB,MAAM,YACE,YAAY,KAAK,KAAK,GAAG,aAAa,GAC5C,eACC,MAAe;GACd,IAAI,eAAe,CAAC,GAAG;IACrB,KAAK,IAAI,QAAQ,KACf,+CAA+C,cAAc,cAAc,QAAQ,SAAS,KAAK,YACnG;IAEA,IAAI,UAAU,MAAM,GAElB,gBAAgB,KAAK,IACnB,KAAK,MAAM,gBAAgB,iBAAiB,GAC5C,gBACF;GAEJ,OACE,KAAK,IAAI,QAAQ,KACf,+CAA+C,QAAQ,SAAS,KAAK,WAAW,QAAQ,OAAO,CAAC,GAClG;GAGF;GACA,MAAM,WAAW,KAAK,eAAe,SAAS,SAAS;GACvD,KAAK,IAAI,QAAQ,KACf,yDAAyD,SAAS,iBAAiB,cAAc,GACnG;GACA,KAAK,mBAAmB,QAAQ;GAChC,OAAO;EACT,CACF;CACF;CAEA,MAAa,UAA8D;EACzE,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAA,CAAG;OACzB;GACL,MAAM,OAAO,UACV,MAAM,GAAG,IAAI,aAAa,EAAA,CAAG,MAC9B,0CACF;GACA,OAAO;IACL,QAAQ,KAAK;IACb,MAAM,KAAK;IACX,cAAc,WAAW,KAAK,OAAO,KAAK,KAAK,YAAY,CAAC;GAC9D;EACF;CACF;CAEA,MAAa,cAA+D;EAC1E,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI;EACJ,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,YAAY,CAAC,CAAC,EAAA,CAAG;OAQlC,OAAO,EACL,UAPiB,UAChB,MAAM,GAAG,IAAI,kBAAkB,EAAA,CAAG,MACnC,+CAKmB,CAAC,CAAC,WAAW,CAAC,EAAA,CAAG,KAAK,MAAgD;GACvF,MAAM,OAAO;IAAE,IAAI,EAAE;IAAI,aAAa,EAAE;IAAa,OAAO,EAAE;GAAM;GACpE,IAAI,EAAE,UAAU,KAAA,GACd,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAS,OAAO,EAAE;IAAM;GAAE;GAEnE,IAAI,EAAE,UAAU,KAAA,GACd,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAS,OAAO,EAAE;IAAM;GAAE;GAEnE,IAAI,EAAE,QAAQ,KAAA,GACZ,OAAO;IAAE,GAAG;IAAM,QAAQ;KAAE,WAAW;KAAO,KAAK,EAAE;IAAI;GAAE;GAE7D,OAAO;IAAE,GAAG;IAAM,QAAQ,EAAE,WAAW,KAAA,EAAU;GAAE;EACrD,CAAC,EACH;EAGF,KAAK,mBAAmB;EACxB,OAAO;CACT;CAEA,IAAW,kBAA0D;EACnE,IAAI,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,8DAA8D;EAEhF,OAAO,KAAK;CACd;CAEA,MAAa,YACX,OAAwD,CAAC,GACR;EAGjD,OAAO,MAAM,KAAK,oBAAoB,qBAAqB,KAAK,gBAAgB,IAAI,CAAC;CACvF;CAEA,MAAc,gBACZ,OAAwD,CAAC,GACR;EACjD,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QACE,MAAM,GAAG,YAAY;GACnB,OAAO,KAAK,SAAS;GACrB,mBAAmB,KAAK,qBAAqB;EAC/C,CAAC,EAAA,CACD;OACG;GACL,MAAM,OAAO,UAET,MAAM,GAAG,KAAK,sBAAsB,EAClC,MAAM;IACJ,OAAO,KAAK,SAAS;IACrB,mBAAmB,KAAK,qBAAqB;GAC/C,EACF,CAAC,EAAA,CACD,MACF,8CACF;GACA,OAAO,EACL,UAAU,KAAK,WACX;IACE,YAAY,OAAO,KAAK,SAAS,UAAU;IAC3C,mBAAmB,WAAW,KAC5B,OAAO,KAAK,KAAK,SAAS,mBAAmB,QAAQ,CACvD;GACF,IACA,KAAA,EACN;EACF;CACF;CAEA,MAAa,kBACX,OAA+D,CAAC,GACP;EACzD,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,sEAAsE;EAGxF,MAAM,OAAO,GAAG,kBAAkB;GAChC,OAAO,KAAK,SAAS;GACrB,WAAW,KAAK,aAAa;GAC7B,OAAO,KAAK,SAAS;EACvB,CAAC;EACD,MAAM,YAA4D,CAAC;EACnE,WAAW,MAAM,OAAO,KAAK,WAC3B,UAAU,KAAK,GAAG;EAEpB,OAAO;CACT;;;CAIA,MAAa,iBAAqE;EAChF,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,QAAQ,MAAM,GAAG,eAAe,CAAC,CAAC,EAAA,CAAG;OAChC;GACL,MAAM,OAAO,UACV,MAAM,GAAG,KAAK,yBAAyB,EAAE,MAAM,CAAC,EAAE,CAAC,EAAA,CAAG,MACvD,iDACF;GACA,OAAO;IACL,WAAW,WAAW,KAAK,OAAO,KAAK,KAAK,WAAW,QAAQ,CAAC;IAChE,MAAM,KAAK;GACb;EACF;CACF;;;;CAKA,MAAa,YAA+C;EAC1D,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,8DAA8D;EAGhF,QAAQ,MAAM,GAAG,UAAU,CAAC,CAAC,EAAA,CAAG,SAAS;CAC3C;;;;;;CAOA,MAAa,WAAW,OAA+D;EACrF,MAAM,KAAK,KAAK,eAAe,IAAI;EAEnC,IAAI,EAAE,cAAcA,iBAClB,MAAM,IAAI,MAAM,+DAA+D;EAGjF,QAAQ,MAAM,GAAG,WAAW,EAAE,MAAM,CAAC,EAAA,CAAG;CAC1C;CAEA,MAAa,OAAO,MAA6B;EAC/C,MAAM,KAAK,KAAK,eAAe,IAAI;EACnC,IAAI,cAAcA,gBAChB,MAAM,GAAG,OAAO,EAAE,MAAM,OAAO,IAAI,EAAE,CAAC;OAEtC,MAAM,GAAG,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,EAAE,EAAE,CAAC;CAEpE;CAEA,SAAS,IAAa,MAAiB,CAAC,GAAoB;EAC1D,OAAO,IAAI,iBAAiB,gBAAgB;GAC1C,IAAI,mBAAmB;GACvB,IAAI,IAAI,aAAa,mBAAmB,YAAY,IAAI,CAAC,kBAAkB,IAAI,WAAW,CAAC;GAE3F,MAAM,UACJ,IAAI,YACH,KAAK,KAAK,KAAK,8BAA8B,KAAK,KAAK;GAE1D,MAAM,KAAK,KAAK,eAAe,IAAI;GACnC,IAAI,cAAcA,gBAChB,OAAO,GAAG,GAAG;IACX,OAAO;IACP;GACF,CAAC;GAGH,MAAM,WAAW,KAAK;GACtB,IAAI,SAAS,SAAS,QAAQ;IAE5B,IAAI,YAAY,KAAA,GACd,mBAAmB,YAAY,IAAI,CAAC,kBAAkB,YAAY,QAAQ,OAAO,CAAC,CAAC;IAIrF,KAAK,+BAA+B;IAMpC,OAAO,IAAI,oBAJG,KAAK,KAAK,MACpB,SAAS,KAAK,KAAK,YAAY,aAC/B,QAAQ,KAAK,KAAK,YAAY,aAI/B,QAAQ,oBAAoB,SAAS,GAAG,IACxC,SAAS,oBAAoB,WAAW,IAAI,WAAW,IAAI,CAAC,GAC7D;KACE,aAAa;KACb,UAAU,KAAK,iBAAiB;KAChC,YAAY,SAAS;KAErB,YAAY,OAAO,WACjB,OAAO,SAAS,KAAK;MAEnB,WAAW;MACX,SAAS;OAAE,WAAW;OAAe,aAAa,CAAC;MAAE;KACvD,CAAC;IACL,CACF;GACF;GAEA,MAAM,IAAI,MAAM,oDAAoD,KAAK,YAAY;EACvF,CAAC;CACH;;CAGA,MAAa,QAAQ;EACnB,IAAI,KAAK,eAAe,SAAS,QAC/B,KAAK,eAAe,UAAU,MAAM;EAItC,MAAM,KAAK,eAAe,QAAQ;CACpC;AACF"}
@@ -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.cjs","names":["isSignedResourceId","AuthAPI_GrantAccess_GrantType","AuthAPI_Role","toResourceSignature","parseSignedResourceId","isLocalResourceId","createSignedResourceId","isNotFoundError","PromiseTracker","initialTxStatWithoutTime","ensureSignedResourceIdNotNull","protoToResource","JsonObject","JsonGzObject","ErrorResourceType","extractBasicResourceData","fieldTypeToProto","protoToField","toBytes","resourceIsDeleted","createLocalResourceId"],"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.cjs","names":["isSignedResourceId","AuthAPI_GrantAccess_GrantType","AuthAPI_Role","toResourceSignature","parseSignedResourceId","isLocalResourceId","createSignedResourceId","isNotFoundError","PromiseTracker","initialTxStatWithoutTime","ensureSignedResourceIdNotNull","protoToResource","JsonObject","JsonGzObject","ErrorResourceType","extractBasicResourceData","fieldTypeToProto","protoToField","toBytes","resourceIsDeleted","createLocalResourceId"],"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":"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"}