@milaboratories/pl-client 2.18.5 → 3.1.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.
- package/dist/_virtual/_rolldown/runtime.cjs +12 -22
- package/dist/_virtual/_rolldown/runtime.js +6 -11
- package/dist/core/PromiseTracker.cjs +2 -3
- package/dist/core/PromiseTracker.cjs.map +1 -1
- package/dist/core/PromiseTracker.d.ts.map +1 -0
- package/dist/core/PromiseTracker.js +1 -2
- package/dist/core/PromiseTracker.js.map +1 -1
- package/dist/core/StatefulPromise.cjs +1 -2
- package/dist/core/StatefulPromise.cjs.map +1 -1
- package/dist/core/StatefulPromise.js +1 -1
- package/dist/core/StatefulPromise.js.map +1 -1
- package/dist/core/abstract_stream.d.ts.map +1 -0
- package/dist/core/advisory_locks.cjs +1 -2
- package/dist/core/advisory_locks.cjs.map +1 -1
- package/dist/core/advisory_locks.js +1 -1
- package/dist/core/advisory_locks.js.map +1 -1
- package/dist/core/auth.cjs +2 -3
- package/dist/core/auth.cjs.map +1 -1
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +1 -2
- package/dist/core/auth.js.map +1 -1
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/client.cjs +63 -36
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.d.ts +3 -1
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +54 -27
- package/dist/core/client.js.map +1 -1
- package/dist/core/config.cjs +16 -17
- package/dist/core/config.cjs.map +1 -1
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +16 -16
- package/dist/core/config.js.map +1 -1
- package/dist/core/default_client.cjs +6 -7
- package/dist/core/default_client.cjs.map +1 -1
- package/dist/core/default_client.d.ts.map +1 -0
- package/dist/core/default_client.js +1 -2
- package/dist/core/default_client.js.map +1 -1
- package/dist/core/driver.cjs +1 -2
- package/dist/core/driver.cjs.map +1 -1
- package/dist/core/driver.d.ts.map +1 -0
- package/dist/core/driver.js +1 -1
- package/dist/core/error_resource.cjs +1 -2
- package/dist/core/error_resource.cjs.map +1 -1
- package/dist/core/error_resource.js +1 -1
- package/dist/core/errors.cjs +11 -4
- package/dist/core/errors.cjs.map +1 -1
- package/dist/core/errors.d.ts +2 -1
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +9 -3
- package/dist/core/errors.js.map +1 -1
- package/dist/core/final.cjs +3 -4
- package/dist/core/final.cjs.map +1 -1
- package/dist/core/final.d.ts.map +1 -0
- package/dist/core/final.js +1 -2
- package/dist/core/final.js.map +1 -1
- package/dist/core/ll_client.cjs +35 -18
- package/dist/core/ll_client.cjs.map +1 -1
- package/dist/core/ll_client.d.ts +6 -1
- package/dist/core/ll_client.d.ts.map +1 -0
- package/dist/core/ll_client.js +25 -8
- package/dist/core/ll_client.js.map +1 -1
- package/dist/core/ll_transaction.cjs +4 -5
- package/dist/core/ll_transaction.cjs.map +1 -1
- package/dist/core/ll_transaction.d.ts.map +1 -0
- package/dist/core/ll_transaction.js +1 -2
- package/dist/core/ll_transaction.js.map +1 -1
- package/dist/core/stat.cjs +1 -2
- package/dist/core/stat.cjs.map +1 -1
- package/dist/core/stat.d.ts.map +1 -0
- package/dist/core/stat.js +1 -1
- package/dist/core/transaction.cjs +32 -21
- package/dist/core/transaction.cjs.map +1 -1
- package/dist/core/transaction.d.ts.map +1 -0
- package/dist/core/transaction.js +23 -12
- package/dist/core/transaction.js.map +1 -1
- package/dist/core/type_conversion.cjs +8 -9
- package/dist/core/type_conversion.cjs.map +1 -1
- package/dist/core/type_conversion.js +4 -5
- package/dist/core/type_conversion.js.map +1 -1
- package/dist/core/types.cjs +3 -4
- package/dist/core/types.cjs.map +1 -1
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/unauth_client.cjs +4 -5
- package/dist/core/unauth_client.cjs.map +1 -1
- package/dist/core/unauth_client.d.ts.map +1 -0
- package/dist/core/unauth_client.js +1 -2
- package/dist/core/unauth_client.js.map +1 -1
- package/dist/core/websocket_stream.cjs +4 -5
- package/dist/core/websocket_stream.cjs.map +1 -1
- package/dist/core/websocket_stream.js +1 -2
- package/dist/core/websocket_stream.js.map +1 -1
- package/dist/core/wire.d.ts.map +1 -0
- package/dist/helpers/pl.cjs +12 -14
- package/dist/helpers/pl.cjs.map +1 -1
- package/dist/helpers/pl.d.ts.map +1 -0
- package/dist/helpers/pl.js +5 -7
- package/dist/helpers/pl.js.map +1 -1
- package/dist/helpers/poll.cjs +3 -4
- package/dist/helpers/poll.cjs.map +1 -1
- package/dist/helpers/poll.d.ts.map +1 -0
- package/dist/helpers/poll.js +1 -2
- package/dist/helpers/poll.js.map +1 -1
- package/dist/helpers/retry_strategy.cjs +1 -2
- package/dist/helpers/retry_strategy.cjs.map +1 -1
- package/dist/helpers/retry_strategy.js +1 -1
- package/dist/helpers/retry_strategy.js.map +1 -1
- package/dist/helpers/tx_helpers.cjs +3 -4
- package/dist/helpers/tx_helpers.cjs.map +1 -1
- package/dist/helpers/tx_helpers.d.ts.map +1 -0
- package/dist/helpers/tx_helpers.js +1 -2
- package/dist/helpers/tx_helpers.js.map +1 -1
- package/dist/index.cjs +34 -34
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -3
- package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.cjs +3 -4
- package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.cjs.map +1 -1
- package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.js +1 -2
- package/dist/proto-grpc/github.com/googleapis/googleapis/google/rpc/status.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +2039 -644
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs +62 -13
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts +78 -8
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js +60 -11
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +658 -51
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +2033 -639
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs +251 -22
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts +104 -10
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js +248 -19
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs +28 -15
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.d.ts +4 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js +27 -14
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.cjs +17 -16
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.d.ts +4 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.d.ts.map +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.js +15 -14
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.js.map +1 -1
- package/dist/proto-grpc/google/protobuf/any.cjs +2 -3
- package/dist/proto-grpc/google/protobuf/any.cjs.map +1 -1
- package/dist/proto-grpc/google/protobuf/any.d.ts.map +1 -0
- package/dist/proto-grpc/google/protobuf/any.js +1 -2
- package/dist/proto-grpc/google/protobuf/any.js.map +1 -1
- package/dist/proto-grpc/google/protobuf/duration.cjs +2 -3
- package/dist/proto-grpc/google/protobuf/duration.cjs.map +1 -1
- package/dist/proto-grpc/google/protobuf/duration.d.ts.map +1 -0
- package/dist/proto-grpc/google/protobuf/duration.js +1 -2
- package/dist/proto-grpc/google/protobuf/duration.js.map +1 -1
- package/dist/proto-grpc/google/protobuf/timestamp.cjs +2 -3
- package/dist/proto-grpc/google/protobuf/timestamp.cjs.map +1 -1
- package/dist/proto-grpc/google/protobuf/timestamp.d.ts.map +1 -0
- package/dist/proto-grpc/google/protobuf/timestamp.js +1 -2
- package/dist/proto-grpc/google/protobuf/timestamp.js.map +1 -1
- package/dist/proto-grpc/google/rpc/code.cjs +1 -2
- package/dist/proto-grpc/google/rpc/code.cjs.map +1 -1
- package/dist/proto-grpc/google/rpc/code.d.ts.map +1 -0
- package/dist/proto-grpc/google/rpc/code.js +1 -1
- package/dist/proto-grpc/google/rpc/code.js.map +1 -1
- package/dist/proto-rest/index.cjs +8 -9
- package/dist/proto-rest/index.cjs.map +1 -1
- package/dist/proto-rest/index.d.ts.map +1 -0
- package/dist/proto-rest/index.js +1 -2
- package/dist/proto-rest/index.js.map +1 -1
- package/dist/proto-rest/plapi.d.ts +281 -28
- package/dist/proto-rest/plapi.d.ts.map +1 -0
- package/dist/test/tcp-proxy.cjs +2 -3
- package/dist/test/tcp-proxy.cjs.map +1 -1
- package/dist/test/tcp-proxy.d.ts.map +1 -0
- package/dist/test/tcp-proxy.js +1 -2
- package/dist/test/tcp-proxy.js.map +1 -1
- package/dist/test/test_config.cjs +16 -19
- package/dist/test/test_config.cjs.map +1 -1
- package/dist/test/test_config.d.ts.map +1 -0
- package/dist/test/test_config.js +3 -6
- package/dist/test/test_config.js.map +1 -1
- package/dist/util/pl.cjs +1 -2
- package/dist/util/pl.cjs.map +1 -1
- package/dist/util/pl.js +1 -1
- package/dist/util/util.cjs +1 -2
- package/dist/util/util.cjs.map +1 -1
- package/dist/util/util.js +1 -1
- package/package.json +8 -8
- package/src/core/client.ts +80 -30
- package/src/core/errors.ts +11 -0
- package/src/core/ll_client.test.ts +8 -0
- package/src/core/ll_client.ts +30 -2
- package/src/core/ll_transaction.test.ts +12 -2
- package/src/core/transaction.ts +41 -10
- package/src/core/type_conversion.ts +1 -1
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.client.ts +119 -15
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +2274 -322
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api_types.ts +276 -20
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/base_types.ts +11 -0
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/import.ts +2 -2
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/resource_types.ts +11 -0
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/ws-test.ts +3 -3
- package/src/proto-grpc/google/protobuf/descriptor.ts +2 -5
- package/src/proto-grpc/google/protobuf/struct.ts +1 -1
- package/src/proto-rest/plapi.ts +293 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unauth_client.js","names":[],"sources":["../../src/core/unauth_client.ts"],"sourcesContent":["import type { AuthInformation, PlClientConfig } from \"./config\";\nimport type {\n AuthAPI_ListMethods_Response,\n MaintenanceAPI_Ping_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { LLPlClient } from \"./ll_client\";\nimport { type MiLogger, notEmpty } from \"@milaboratories/ts-helpers\";\nimport { UnauthenticatedError } from \"./errors\";\n\n/** Primarily used for initial authentication (login) */\nexport class UnauthenticatedPlClient {\n public readonly ll: LLPlClient;\n\n private constructor(ll: LLPlClient) {\n this.ll = ll;\n }\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops?: { logger?: MiLogger },\n ): Promise<UnauthenticatedPlClient> {\n const ll = await LLPlClient.build(configOrAddress, ops);\n return new UnauthenticatedPlClient(ll);\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async authMethods(): Promise<AuthAPI_ListMethods_Response> {\n return await this.ll.authMethods();\n }\n\n public async requireAuth(): Promise<boolean> {\n return (await this.authMethods()).methods.length > 0;\n }\n\n public async login(user: string, password: string): Promise<AuthInformation> {\n try {\n const token = await this.ll.getJwtToken(BigInt(this.ll.conf.authTTLSeconds), {\n authorization: \"Basic \" + Buffer.from(user + \":\" + password).toString(\"base64\"),\n });\n const jwtToken = notEmpty(token);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"unauth_client.js","names":[],"sources":["../../src/core/unauth_client.ts"],"sourcesContent":["import type { AuthInformation, PlClientConfig } from \"./config\";\nimport type {\n AuthAPI_ListMethods_Response,\n MaintenanceAPI_Ping_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api\";\nimport { LLPlClient } from \"./ll_client\";\nimport { type MiLogger, notEmpty } from \"@milaboratories/ts-helpers\";\nimport { UnauthenticatedError } from \"./errors\";\n\n/** Primarily used for initial authentication (login) */\nexport class UnauthenticatedPlClient {\n public readonly ll: LLPlClient;\n\n private constructor(ll: LLPlClient) {\n this.ll = ll;\n }\n\n public static async build(\n configOrAddress: PlClientConfig | string,\n ops?: { logger?: MiLogger },\n ): Promise<UnauthenticatedPlClient> {\n const ll = await LLPlClient.build(configOrAddress, ops);\n return new UnauthenticatedPlClient(ll);\n }\n\n public async ping(): Promise<MaintenanceAPI_Ping_Response> {\n return await this.ll.ping();\n }\n\n public async authMethods(): Promise<AuthAPI_ListMethods_Response> {\n return await this.ll.authMethods();\n }\n\n public async requireAuth(): Promise<boolean> {\n return (await this.authMethods()).methods.length > 0;\n }\n\n public async login(user: string, password: string): Promise<AuthInformation> {\n try {\n const token = await this.ll.getJwtToken(BigInt(this.ll.conf.authTTLSeconds), {\n authorization: \"Basic \" + Buffer.from(user + \":\" + password).toString(\"base64\"),\n });\n const jwtToken = notEmpty(token);\n if (jwtToken === \"\") throw new Error(\"empty token\");\n return { jwtToken };\n } catch (e: any) {\n if (e.code === \"UNAUTHENTICATED\") throw new UnauthenticatedError(e.message);\n throw new Error(e);\n }\n }\n}\n"],"mappings":";;;;;AAUA,IAAa,0BAAb,MAAa,wBAAwB;CACnC;CAEA,YAAoB,IAAgB;AAClC,OAAK,KAAK;;CAGZ,aAAoB,MAClB,iBACA,KACkC;AAElC,SAAO,IAAI,wBADA,MAAM,WAAW,MAAM,iBAAiB,IAAI,CACjB;;CAGxC,MAAa,OAA8C;AACzD,SAAO,MAAM,KAAK,GAAG,MAAM;;CAG7B,MAAa,cAAqD;AAChE,SAAO,MAAM,KAAK,GAAG,aAAa;;CAGpC,MAAa,cAAgC;AAC3C,UAAQ,MAAM,KAAK,aAAa,EAAE,QAAQ,SAAS;;CAGrD,MAAa,MAAM,MAAc,UAA4C;AAC3E,MAAI;GAIF,MAAM,WAAW,SAHH,MAAM,KAAK,GAAG,YAAY,OAAO,KAAK,GAAG,KAAK,eAAe,EAAE,EAC3E,eAAe,WAAW,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC,SAAS,SAAS,EAChF,CAAC,CAC8B;AAChC,OAAI,aAAa,GAAI,OAAM,IAAI,MAAM,cAAc;AACnD,UAAO,EAAE,UAAU;WACZ,GAAQ;AACf,OAAI,EAAE,SAAS,kBAAmB,OAAM,IAAI,qBAAqB,EAAE,QAAQ;AAC3E,SAAM,IAAI,MAAM,EAAE"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
const require_runtime = require(
|
|
2
|
-
const require_errors = require(
|
|
3
|
-
const require_retry_strategy = require(
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_errors = require("./errors.cjs");
|
|
3
|
+
const require_retry_strategy = require("../helpers/retry_strategy.cjs");
|
|
4
4
|
let denque = require("denque");
|
|
5
5
|
denque = require_runtime.__toESM(denque);
|
|
6
6
|
let undici = require("undici");
|
|
7
|
-
|
|
8
7
|
//#region src/core/websocket_stream.ts
|
|
9
8
|
var ConnectionState = /* @__PURE__ */ function(ConnectionState) {
|
|
10
9
|
ConnectionState[ConnectionState["NEW"] = 0] = "NEW";
|
|
@@ -278,7 +277,7 @@ var WebSocketBiDiStream = class {
|
|
|
278
277
|
return true;
|
|
279
278
|
}
|
|
280
279
|
};
|
|
281
|
-
|
|
282
280
|
//#endregion
|
|
283
281
|
exports.WebSocketBiDiStream = WebSocketBiDiStream;
|
|
282
|
+
|
|
284
283
|
//# sourceMappingURL=websocket_stream.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket_stream.cjs","names":["Denque","RetryStrategy","WebSocket","ErrorEvent","DisconnectedError"],"sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from \"undici\";\nimport type { BiDiStream } from \"./abstract_stream\";\nimport Denque from \"denque\";\nimport type { RetryConfig } from \"../helpers/retry_strategy\";\nimport { RetryStrategy } from \"../helpers/retry_strategy\";\nimport { DisconnectedError } from \"./errors\";\n\ninterface QueuedMessage<InType extends object> {\n message: InType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver<OutType extends object> {\n resolve: (value: IteratorResult<OutType>) => void;\n reject: (error: Error) => void;\n}\n\nenum ConnectionState {\n NEW = 0,\n CONNECTING = 1,\n CONNECTED = 2,\n CLOSING = 3,\n CLOSED = 4,\n}\n\nexport type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {\n abortSignal?: AbortSignal;\n\n dispatcher?: Dispatcher;\n jwtToken?: string;\n retryConfig?: Partial<RetryConfig>;\n\n onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n};\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream<\n ClientMsg extends object,\n ServerMsg extends object,\n> implements BiDiStream<ClientMsg, ServerMsg> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = ConnectionState.NEW;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();\n private sendCompleted = false;\n private readonly onComplete: (\n stream: WebSocketBiDiStream<ClientMsg, ServerMsg>,\n ) => void | Promise<void>;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMsg>();\n private responseResolvers: ResponseResolver<ServerMsg>[] = [];\n\n // Error tracking\n private lastError?: Error;\n\n // Abort listener reference for cleanup\n private readonly abortHandler?: () => void;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMsg): Promise<void> => {\n return await this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream\n try {\n await this.onComplete(this); // custom onComplete may send additional messages\n } catch {\n // When 'complete' gets called concurrently with connection break or over a broken\n // transaction stream (server decided it should drop transaction), server would close\n // connection anyway on its end. We can safely ignore error here and just continue working.\n }\n this.sendCompleted = true;\n },\n };\n\n public readonly responses: AsyncIterable<ServerMsg> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n public close(): void {\n this.reconnection.cancel();\n\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Never reached CONNECTED state. ws.close() will never trigger 'close' event.\n this.ws?.close();\n this.onClose();\n return;\n }\n\n if (!this.progressConnectionState(ConnectionState.CLOSING)) return;\n this.ws!.close();\n }\n\n constructor(\n private readonly url: string,\n private readonly serializeClientMessage: (message: ClientMsg) => Uint8Array,\n private readonly parseServerMessage: (data: Uint8Array) => ServerMsg,\n private readonly options: WSStreamOptions<ClientMsg, ServerMsg> = {},\n ) {\n this.onComplete = this.options.onComplete ?? ((stream) => stream.close());\n\n const retryConfig = this.options.retryConfig ?? {};\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => {\n void this.connect();\n },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (this.options.abortSignal?.aborted) {\n this.progressConnectionState(ConnectionState.CLOSED);\n return;\n }\n\n this.abortHandler = () => this.close();\n this.options.abortSignal?.addEventListener(\"abort\", this.abortHandler, { once: true });\n this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.options.abortSignal?.aborted) return;\n\n // Prevent reconnecting after first successful connection.\n if (!this.progressConnectionState(ConnectionState.CONNECTING)) return;\n\n try {\n this.ws = this.createWebSocket();\n\n this.ws.addEventListener(\"open\", () => this.onOpen());\n this.ws.addEventListener(\"message\", (event) => this.onMessage(event.data));\n this.ws.addEventListener(\"error\", (error) => this.onError(error));\n this.ws.addEventListener(\"close\", () => this.onClose());\n } catch (error) {\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options: WebSocketInit = {};\n\n if (this.options.jwtToken)\n options.headers = { authorization: `Bearer ${this.options.jwtToken}` };\n if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;\n\n const ws = new WebSocket(this.url, options);\n ws.binaryType = \"arraybuffer\";\n return ws;\n }\n\n private onOpen(): void {\n this.progressConnectionState(ConnectionState.CONNECTED);\n this.processSendQueue();\n }\n\n private onMessage(data: unknown): void {\n if (!(data instanceof ArrayBuffer)) {\n this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));\n return;\n }\n\n try {\n const message = this.parseServerMessage(new Uint8Array(data));\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private onError(error: unknown): void {\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Try to connect several times until we succeed or run out of attempts.\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n return;\n }\n\n this.handleError(this.toError(error));\n }\n\n private onClose(): void {\n this.progressConnectionState(ConnectionState.CLOSED);\n\n // Clean up abort listener to prevent memory leaks\n if (this.abortHandler) {\n this.options.abortSignal?.removeEventListener(\"abort\", this.abortHandler);\n }\n\n // If abort signal was triggered, use that as the error source\n if (this.options.abortSignal?.aborted && !this.lastError) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n this.lastError = reason;\n } else if (reason !== undefined) {\n this.lastError = new Error(String(reason), { cause: reason });\n } else {\n this.lastError = this.createStreamClosedError();\n }\n }\n\n if (!this.lastError) {\n this.rejectAllSendOperations(this.createStreamClosedError());\n this.resolveAllPendingResponses(); // unblock active async iterator\n } else {\n this.rejectAllPendingOperations(this.lastError);\n }\n }\n\n // === Send Queue Management ===\n\n private enqueueSend(message: ClientMsg): Promise<void> {\n if (this.sendCompleted) {\n throw new Error(\"Cannot send: stream already completed\");\n }\n\n if (this.options.abortSignal?.aborted) {\n throw new Error(\"Cannot send: stream aborted\");\n }\n\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === ConnectionState.CONNECTED;\n }\n\n private sendQueuedMessage(queued: QueuedMessage<ClientMsg>): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error(\"WebSocket is not connected\");\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = this.serializeClientMessage(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 5;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);\n }\n }\n\n private waitForCondition(condition: () => boolean, intervalMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.options.abortSignal?.aborted) {\n return reject(this.toError(this.options.abortSignal.reason) ?? new Error(\"Stream aborted\"));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.options.abortSignal?.reason) ?? new Error(\"Stream aborted\"));\n };\n\n this.options.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.options.abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMsg): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMsg> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMsg>> {\n return new Promise<IteratorResult<ServerMsg>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.lastError) {\n reject(this.lastError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n // === Error Handling ===\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.close();\n }\n\n private rejectAllPendingOperations(error: Error): void {\n this.rejectAllSendOperations(error);\n this.rejectAllResponseResolvers(error);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.options.abortSignal?.aborted) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error(\"Stream aborted\", { cause: reason });\n }\n\n return new Error(\"Stream closed\");\n }\n\n // === Helpers ===\n\n private isStreamEnded(): boolean {\n return (\n this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false\n );\n }\n\n private toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (error instanceof ErrorEvent) {\n const err = error.error;\n // undici WebSocket throws TypeError with empty message on socket close\n // (e.g., when connection is lost or server disconnects)\n if (err instanceof TypeError && !err.message) {\n return new DisconnectedError(\"WebSocket connection closed unexpectedly\");\n }\n return err instanceof Error ? err : new Error(\"WebSocket error\", { cause: error });\n }\n return new Error(String(error));\n }\n\n /**\n * Connection state progresses linearly from NEW to CLOSED and never goes back.\n * This internal contract dramatically simplifies the internal stream state management.\n *\n * If you ever feel the need to make this contract less strict, think twice.\n */\n private progressConnectionState(newState: ConnectionState): boolean {\n if (newState < this.connectionState) {\n return false;\n }\n this.connectionState = newState;\n return true;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websocket_stream.cjs","names":["Denque","RetryStrategy","WebSocket","ErrorEvent","DisconnectedError"],"sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from \"undici\";\nimport type { BiDiStream } from \"./abstract_stream\";\nimport Denque from \"denque\";\nimport type { RetryConfig } from \"../helpers/retry_strategy\";\nimport { RetryStrategy } from \"../helpers/retry_strategy\";\nimport { DisconnectedError } from \"./errors\";\n\ninterface QueuedMessage<InType extends object> {\n message: InType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver<OutType extends object> {\n resolve: (value: IteratorResult<OutType>) => void;\n reject: (error: Error) => void;\n}\n\nenum ConnectionState {\n NEW = 0,\n CONNECTING = 1,\n CONNECTED = 2,\n CLOSING = 3,\n CLOSED = 4,\n}\n\nexport type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {\n abortSignal?: AbortSignal;\n\n dispatcher?: Dispatcher;\n jwtToken?: string;\n retryConfig?: Partial<RetryConfig>;\n\n onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n};\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream<\n ClientMsg extends object,\n ServerMsg extends object,\n> implements BiDiStream<ClientMsg, ServerMsg> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = ConnectionState.NEW;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();\n private sendCompleted = false;\n private readonly onComplete: (\n stream: WebSocketBiDiStream<ClientMsg, ServerMsg>,\n ) => void | Promise<void>;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMsg>();\n private responseResolvers: ResponseResolver<ServerMsg>[] = [];\n\n // Error tracking\n private lastError?: Error;\n\n // Abort listener reference for cleanup\n private readonly abortHandler?: () => void;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMsg): Promise<void> => {\n return await this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream\n try {\n await this.onComplete(this); // custom onComplete may send additional messages\n } catch {\n // When 'complete' gets called concurrently with connection break or over a broken\n // transaction stream (server decided it should drop transaction), server would close\n // connection anyway on its end. We can safely ignore error here and just continue working.\n }\n this.sendCompleted = true;\n },\n };\n\n public readonly responses: AsyncIterable<ServerMsg> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n public close(): void {\n this.reconnection.cancel();\n\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Never reached CONNECTED state. ws.close() will never trigger 'close' event.\n this.ws?.close();\n this.onClose();\n return;\n }\n\n if (!this.progressConnectionState(ConnectionState.CLOSING)) return;\n this.ws!.close();\n }\n\n constructor(\n private readonly url: string,\n private readonly serializeClientMessage: (message: ClientMsg) => Uint8Array,\n private readonly parseServerMessage: (data: Uint8Array) => ServerMsg,\n private readonly options: WSStreamOptions<ClientMsg, ServerMsg> = {},\n ) {\n this.onComplete = this.options.onComplete ?? ((stream) => stream.close());\n\n const retryConfig = this.options.retryConfig ?? {};\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => {\n void this.connect();\n },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (this.options.abortSignal?.aborted) {\n this.progressConnectionState(ConnectionState.CLOSED);\n return;\n }\n\n this.abortHandler = () => this.close();\n this.options.abortSignal?.addEventListener(\"abort\", this.abortHandler, { once: true });\n this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.options.abortSignal?.aborted) return;\n\n // Prevent reconnecting after first successful connection.\n if (!this.progressConnectionState(ConnectionState.CONNECTING)) return;\n\n try {\n this.ws = this.createWebSocket();\n\n this.ws.addEventListener(\"open\", () => this.onOpen());\n this.ws.addEventListener(\"message\", (event) => this.onMessage(event.data));\n this.ws.addEventListener(\"error\", (error) => this.onError(error));\n this.ws.addEventListener(\"close\", () => this.onClose());\n } catch (error) {\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options: WebSocketInit = {};\n\n if (this.options.jwtToken)\n options.headers = { authorization: `Bearer ${this.options.jwtToken}` };\n if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;\n\n const ws = new WebSocket(this.url, options);\n ws.binaryType = \"arraybuffer\";\n return ws;\n }\n\n private onOpen(): void {\n this.progressConnectionState(ConnectionState.CONNECTED);\n this.processSendQueue();\n }\n\n private onMessage(data: unknown): void {\n if (!(data instanceof ArrayBuffer)) {\n this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));\n return;\n }\n\n try {\n const message = this.parseServerMessage(new Uint8Array(data));\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private onError(error: unknown): void {\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Try to connect several times until we succeed or run out of attempts.\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n return;\n }\n\n this.handleError(this.toError(error));\n }\n\n private onClose(): void {\n this.progressConnectionState(ConnectionState.CLOSED);\n\n // Clean up abort listener to prevent memory leaks\n if (this.abortHandler) {\n this.options.abortSignal?.removeEventListener(\"abort\", this.abortHandler);\n }\n\n // If abort signal was triggered, use that as the error source\n if (this.options.abortSignal?.aborted && !this.lastError) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n this.lastError = reason;\n } else if (reason !== undefined) {\n this.lastError = new Error(String(reason), { cause: reason });\n } else {\n this.lastError = this.createStreamClosedError();\n }\n }\n\n if (!this.lastError) {\n this.rejectAllSendOperations(this.createStreamClosedError());\n this.resolveAllPendingResponses(); // unblock active async iterator\n } else {\n this.rejectAllPendingOperations(this.lastError);\n }\n }\n\n // === Send Queue Management ===\n\n private enqueueSend(message: ClientMsg): Promise<void> {\n if (this.sendCompleted) {\n throw new Error(\"Cannot send: stream already completed\");\n }\n\n if (this.options.abortSignal?.aborted) {\n throw new Error(\"Cannot send: stream aborted\");\n }\n\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === ConnectionState.CONNECTED;\n }\n\n private sendQueuedMessage(queued: QueuedMessage<ClientMsg>): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error(\"WebSocket is not connected\");\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = this.serializeClientMessage(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 5;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);\n }\n }\n\n private waitForCondition(condition: () => boolean, intervalMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.options.abortSignal?.aborted) {\n return reject(this.toError(this.options.abortSignal.reason) ?? new Error(\"Stream aborted\"));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.options.abortSignal?.reason) ?? new Error(\"Stream aborted\"));\n };\n\n this.options.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.options.abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMsg): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMsg> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMsg>> {\n return new Promise<IteratorResult<ServerMsg>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.lastError) {\n reject(this.lastError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n // === Error Handling ===\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.close();\n }\n\n private rejectAllPendingOperations(error: Error): void {\n this.rejectAllSendOperations(error);\n this.rejectAllResponseResolvers(error);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.options.abortSignal?.aborted) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error(\"Stream aborted\", { cause: reason });\n }\n\n return new Error(\"Stream closed\");\n }\n\n // === Helpers ===\n\n private isStreamEnded(): boolean {\n return (\n this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false\n );\n }\n\n private toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (error instanceof ErrorEvent) {\n const err = error.error;\n // undici WebSocket throws TypeError with empty message on socket close\n // (e.g., when connection is lost or server disconnects)\n if (err instanceof TypeError && !err.message) {\n return new DisconnectedError(\"WebSocket connection closed unexpectedly\");\n }\n return err instanceof Error ? err : new Error(\"WebSocket error\", { cause: error });\n }\n return new Error(String(error));\n }\n\n /**\n * Connection state progresses linearly from NEW to CLOSED and never goes back.\n * This internal contract dramatically simplifies the internal stream state management.\n *\n * If you ever feel the need to make this contract less strict, think twice.\n */\n private progressConnectionState(newState: ConnectionState): boolean {\n if (newState < this.connectionState) {\n return false;\n }\n this.connectionState = newState;\n return true;\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,6 @@ import { DisconnectedError } from "./errors.js";
|
|
|
2
2
|
import { RetryStrategy } from "../helpers/retry_strategy.js";
|
|
3
3
|
import Denque from "denque";
|
|
4
4
|
import { ErrorEvent, WebSocket } from "undici";
|
|
5
|
-
|
|
6
5
|
//#region src/core/websocket_stream.ts
|
|
7
6
|
var ConnectionState = /* @__PURE__ */ function(ConnectionState) {
|
|
8
7
|
ConnectionState[ConnectionState["NEW"] = 0] = "NEW";
|
|
@@ -276,7 +275,7 @@ var WebSocketBiDiStream = class {
|
|
|
276
275
|
return true;
|
|
277
276
|
}
|
|
278
277
|
};
|
|
279
|
-
|
|
280
278
|
//#endregion
|
|
281
279
|
export { WebSocketBiDiStream };
|
|
280
|
+
|
|
282
281
|
//# sourceMappingURL=websocket_stream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket_stream.js","names":[],"sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from \"undici\";\nimport type { BiDiStream } from \"./abstract_stream\";\nimport Denque from \"denque\";\nimport type { RetryConfig } from \"../helpers/retry_strategy\";\nimport { RetryStrategy } from \"../helpers/retry_strategy\";\nimport { DisconnectedError } from \"./errors\";\n\ninterface QueuedMessage<InType extends object> {\n message: InType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver<OutType extends object> {\n resolve: (value: IteratorResult<OutType>) => void;\n reject: (error: Error) => void;\n}\n\nenum ConnectionState {\n NEW = 0,\n CONNECTING = 1,\n CONNECTED = 2,\n CLOSING = 3,\n CLOSED = 4,\n}\n\nexport type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {\n abortSignal?: AbortSignal;\n\n dispatcher?: Dispatcher;\n jwtToken?: string;\n retryConfig?: Partial<RetryConfig>;\n\n onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n};\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream<\n ClientMsg extends object,\n ServerMsg extends object,\n> implements BiDiStream<ClientMsg, ServerMsg> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = ConnectionState.NEW;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();\n private sendCompleted = false;\n private readonly onComplete: (\n stream: WebSocketBiDiStream<ClientMsg, ServerMsg>,\n ) => void | Promise<void>;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMsg>();\n private responseResolvers: ResponseResolver<ServerMsg>[] = [];\n\n // Error tracking\n private lastError?: Error;\n\n // Abort listener reference for cleanup\n private readonly abortHandler?: () => void;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMsg): Promise<void> => {\n return await this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream\n try {\n await this.onComplete(this); // custom onComplete may send additional messages\n } catch {\n // When 'complete' gets called concurrently with connection break or over a broken\n // transaction stream (server decided it should drop transaction), server would close\n // connection anyway on its end. We can safely ignore error here and just continue working.\n }\n this.sendCompleted = true;\n },\n };\n\n public readonly responses: AsyncIterable<ServerMsg> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n public close(): void {\n this.reconnection.cancel();\n\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Never reached CONNECTED state. ws.close() will never trigger 'close' event.\n this.ws?.close();\n this.onClose();\n return;\n }\n\n if (!this.progressConnectionState(ConnectionState.CLOSING)) return;\n this.ws!.close();\n }\n\n constructor(\n private readonly url: string,\n private readonly serializeClientMessage: (message: ClientMsg) => Uint8Array,\n private readonly parseServerMessage: (data: Uint8Array) => ServerMsg,\n private readonly options: WSStreamOptions<ClientMsg, ServerMsg> = {},\n ) {\n this.onComplete = this.options.onComplete ?? ((stream) => stream.close());\n\n const retryConfig = this.options.retryConfig ?? {};\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => {\n void this.connect();\n },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (this.options.abortSignal?.aborted) {\n this.progressConnectionState(ConnectionState.CLOSED);\n return;\n }\n\n this.abortHandler = () => this.close();\n this.options.abortSignal?.addEventListener(\"abort\", this.abortHandler, { once: true });\n this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.options.abortSignal?.aborted) return;\n\n // Prevent reconnecting after first successful connection.\n if (!this.progressConnectionState(ConnectionState.CONNECTING)) return;\n\n try {\n this.ws = this.createWebSocket();\n\n this.ws.addEventListener(\"open\", () => this.onOpen());\n this.ws.addEventListener(\"message\", (event) => this.onMessage(event.data));\n this.ws.addEventListener(\"error\", (error) => this.onError(error));\n this.ws.addEventListener(\"close\", () => this.onClose());\n } catch (error) {\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options: WebSocketInit = {};\n\n if (this.options.jwtToken)\n options.headers = { authorization: `Bearer ${this.options.jwtToken}` };\n if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;\n\n const ws = new WebSocket(this.url, options);\n ws.binaryType = \"arraybuffer\";\n return ws;\n }\n\n private onOpen(): void {\n this.progressConnectionState(ConnectionState.CONNECTED);\n this.processSendQueue();\n }\n\n private onMessage(data: unknown): void {\n if (!(data instanceof ArrayBuffer)) {\n this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));\n return;\n }\n\n try {\n const message = this.parseServerMessage(new Uint8Array(data));\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private onError(error: unknown): void {\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Try to connect several times until we succeed or run out of attempts.\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n return;\n }\n\n this.handleError(this.toError(error));\n }\n\n private onClose(): void {\n this.progressConnectionState(ConnectionState.CLOSED);\n\n // Clean up abort listener to prevent memory leaks\n if (this.abortHandler) {\n this.options.abortSignal?.removeEventListener(\"abort\", this.abortHandler);\n }\n\n // If abort signal was triggered, use that as the error source\n if (this.options.abortSignal?.aborted && !this.lastError) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n this.lastError = reason;\n } else if (reason !== undefined) {\n this.lastError = new Error(String(reason), { cause: reason });\n } else {\n this.lastError = this.createStreamClosedError();\n }\n }\n\n if (!this.lastError) {\n this.rejectAllSendOperations(this.createStreamClosedError());\n this.resolveAllPendingResponses(); // unblock active async iterator\n } else {\n this.rejectAllPendingOperations(this.lastError);\n }\n }\n\n // === Send Queue Management ===\n\n private enqueueSend(message: ClientMsg): Promise<void> {\n if (this.sendCompleted) {\n throw new Error(\"Cannot send: stream already completed\");\n }\n\n if (this.options.abortSignal?.aborted) {\n throw new Error(\"Cannot send: stream aborted\");\n }\n\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === ConnectionState.CONNECTED;\n }\n\n private sendQueuedMessage(queued: QueuedMessage<ClientMsg>): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error(\"WebSocket is not connected\");\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = this.serializeClientMessage(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 5;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);\n }\n }\n\n private waitForCondition(condition: () => boolean, intervalMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.options.abortSignal?.aborted) {\n return reject(this.toError(this.options.abortSignal.reason) ?? new Error(\"Stream aborted\"));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.options.abortSignal?.reason) ?? new Error(\"Stream aborted\"));\n };\n\n this.options.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.options.abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMsg): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMsg> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMsg>> {\n return new Promise<IteratorResult<ServerMsg>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.lastError) {\n reject(this.lastError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n // === Error Handling ===\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.close();\n }\n\n private rejectAllPendingOperations(error: Error): void {\n this.rejectAllSendOperations(error);\n this.rejectAllResponseResolvers(error);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.options.abortSignal?.aborted) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error(\"Stream aborted\", { cause: reason });\n }\n\n return new Error(\"Stream closed\");\n }\n\n // === Helpers ===\n\n private isStreamEnded(): boolean {\n return (\n this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false\n );\n }\n\n private toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (error instanceof ErrorEvent) {\n const err = error.error;\n // undici WebSocket throws TypeError with empty message on socket close\n // (e.g., when connection is lost or server disconnects)\n if (err instanceof TypeError && !err.message) {\n return new DisconnectedError(\"WebSocket connection closed unexpectedly\");\n }\n return err instanceof Error ? err : new Error(\"WebSocket error\", { cause: error });\n }\n return new Error(String(error));\n }\n\n /**\n * Connection state progresses linearly from NEW to CLOSED and never goes back.\n * This internal contract dramatically simplifies the internal stream state management.\n *\n * If you ever feel the need to make this contract less strict, think twice.\n */\n private progressConnectionState(newState: ConnectionState): boolean {\n if (newState < this.connectionState) {\n return false;\n }\n this.connectionState = newState;\n return true;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websocket_stream.js","names":[],"sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from \"undici\";\nimport type { BiDiStream } from \"./abstract_stream\";\nimport Denque from \"denque\";\nimport type { RetryConfig } from \"../helpers/retry_strategy\";\nimport { RetryStrategy } from \"../helpers/retry_strategy\";\nimport { DisconnectedError } from \"./errors\";\n\ninterface QueuedMessage<InType extends object> {\n message: InType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver<OutType extends object> {\n resolve: (value: IteratorResult<OutType>) => void;\n reject: (error: Error) => void;\n}\n\nenum ConnectionState {\n NEW = 0,\n CONNECTING = 1,\n CONNECTED = 2,\n CLOSING = 3,\n CLOSED = 4,\n}\n\nexport type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {\n abortSignal?: AbortSignal;\n\n dispatcher?: Dispatcher;\n jwtToken?: string;\n retryConfig?: Partial<RetryConfig>;\n\n onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n};\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream<\n ClientMsg extends object,\n ServerMsg extends object,\n> implements BiDiStream<ClientMsg, ServerMsg> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = ConnectionState.NEW;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();\n private sendCompleted = false;\n private readonly onComplete: (\n stream: WebSocketBiDiStream<ClientMsg, ServerMsg>,\n ) => void | Promise<void>;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMsg>();\n private responseResolvers: ResponseResolver<ServerMsg>[] = [];\n\n // Error tracking\n private lastError?: Error;\n\n // Abort listener reference for cleanup\n private readonly abortHandler?: () => void;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMsg): Promise<void> => {\n return await this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream\n try {\n await this.onComplete(this); // custom onComplete may send additional messages\n } catch {\n // When 'complete' gets called concurrently with connection break or over a broken\n // transaction stream (server decided it should drop transaction), server would close\n // connection anyway on its end. We can safely ignore error here and just continue working.\n }\n this.sendCompleted = true;\n },\n };\n\n public readonly responses: AsyncIterable<ServerMsg> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n public close(): void {\n this.reconnection.cancel();\n\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Never reached CONNECTED state. ws.close() will never trigger 'close' event.\n this.ws?.close();\n this.onClose();\n return;\n }\n\n if (!this.progressConnectionState(ConnectionState.CLOSING)) return;\n this.ws!.close();\n }\n\n constructor(\n private readonly url: string,\n private readonly serializeClientMessage: (message: ClientMsg) => Uint8Array,\n private readonly parseServerMessage: (data: Uint8Array) => ServerMsg,\n private readonly options: WSStreamOptions<ClientMsg, ServerMsg> = {},\n ) {\n this.onComplete = this.options.onComplete ?? ((stream) => stream.close());\n\n const retryConfig = this.options.retryConfig ?? {};\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => {\n void this.connect();\n },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (this.options.abortSignal?.aborted) {\n this.progressConnectionState(ConnectionState.CLOSED);\n return;\n }\n\n this.abortHandler = () => this.close();\n this.options.abortSignal?.addEventListener(\"abort\", this.abortHandler, { once: true });\n this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.options.abortSignal?.aborted) return;\n\n // Prevent reconnecting after first successful connection.\n if (!this.progressConnectionState(ConnectionState.CONNECTING)) return;\n\n try {\n this.ws = this.createWebSocket();\n\n this.ws.addEventListener(\"open\", () => this.onOpen());\n this.ws.addEventListener(\"message\", (event) => this.onMessage(event.data));\n this.ws.addEventListener(\"error\", (error) => this.onError(error));\n this.ws.addEventListener(\"close\", () => this.onClose());\n } catch (error) {\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options: WebSocketInit = {};\n\n if (this.options.jwtToken)\n options.headers = { authorization: `Bearer ${this.options.jwtToken}` };\n if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;\n\n const ws = new WebSocket(this.url, options);\n ws.binaryType = \"arraybuffer\";\n return ws;\n }\n\n private onOpen(): void {\n this.progressConnectionState(ConnectionState.CONNECTED);\n this.processSendQueue();\n }\n\n private onMessage(data: unknown): void {\n if (!(data instanceof ArrayBuffer)) {\n this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));\n return;\n }\n\n try {\n const message = this.parseServerMessage(new Uint8Array(data));\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private onError(error: unknown): void {\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Try to connect several times until we succeed or run out of attempts.\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n return;\n }\n\n this.handleError(this.toError(error));\n }\n\n private onClose(): void {\n this.progressConnectionState(ConnectionState.CLOSED);\n\n // Clean up abort listener to prevent memory leaks\n if (this.abortHandler) {\n this.options.abortSignal?.removeEventListener(\"abort\", this.abortHandler);\n }\n\n // If abort signal was triggered, use that as the error source\n if (this.options.abortSignal?.aborted && !this.lastError) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n this.lastError = reason;\n } else if (reason !== undefined) {\n this.lastError = new Error(String(reason), { cause: reason });\n } else {\n this.lastError = this.createStreamClosedError();\n }\n }\n\n if (!this.lastError) {\n this.rejectAllSendOperations(this.createStreamClosedError());\n this.resolveAllPendingResponses(); // unblock active async iterator\n } else {\n this.rejectAllPendingOperations(this.lastError);\n }\n }\n\n // === Send Queue Management ===\n\n private enqueueSend(message: ClientMsg): Promise<void> {\n if (this.sendCompleted) {\n throw new Error(\"Cannot send: stream already completed\");\n }\n\n if (this.options.abortSignal?.aborted) {\n throw new Error(\"Cannot send: stream aborted\");\n }\n\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === ConnectionState.CONNECTED;\n }\n\n private sendQueuedMessage(queued: QueuedMessage<ClientMsg>): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error(\"WebSocket is not connected\");\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = this.serializeClientMessage(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 5;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);\n }\n }\n\n private waitForCondition(condition: () => boolean, intervalMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.options.abortSignal?.aborted) {\n return reject(this.toError(this.options.abortSignal.reason) ?? new Error(\"Stream aborted\"));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.options.abortSignal?.reason) ?? new Error(\"Stream aborted\"));\n };\n\n this.options.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.options.abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMsg): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMsg> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMsg>> {\n return new Promise<IteratorResult<ServerMsg>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.lastError) {\n reject(this.lastError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n // === Error Handling ===\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.close();\n }\n\n private rejectAllPendingOperations(error: Error): void {\n this.rejectAllSendOperations(error);\n this.rejectAllResponseResolvers(error);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.options.abortSignal?.aborted) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error(\"Stream aborted\", { cause: reason });\n }\n\n return new Error(\"Stream closed\");\n }\n\n // === Helpers ===\n\n private isStreamEnded(): boolean {\n return (\n this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false\n );\n }\n\n private toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (error instanceof ErrorEvent) {\n const err = error.error;\n // undici WebSocket throws TypeError with empty message on socket close\n // (e.g., when connection is lost or server disconnects)\n if (err instanceof TypeError && !err.message) {\n return new DisconnectedError(\"WebSocket connection closed unexpectedly\");\n }\n return err instanceof Error ? err : new Error(\"WebSocket error\", { cause: error });\n }\n return new Error(String(error));\n }\n\n /**\n * Connection state progresses linearly from NEW to CLOSED and never goes back.\n * This internal contract dramatically simplifies the internal stream state management.\n *\n * If you ever feel the need to make this contract less strict, think twice.\n */\n private progressConnectionState(newState: ConnectionState): boolean {\n if (newState < this.connectionState) {\n return false;\n }\n this.connectionState = newState;\n return true;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire.d.ts","names":[],"sources":["../../src/core/wire.ts"],"mappings":";;;;;;;;AASA;;KAAY,cAAA;EACV,IAAA;EACA,MAAA,EAAQ,cAAA;EACR,UAAA,EAAY,UAAA;EACZ,WAAA,EAAa,UAAA;AAAA;AAAA,KAGH,cAAA;EACV,IAAA;EACA,SAAA,EAAW,aAAA;AAAA;AAAA,KAGD,cAAA,GAAiB,cAAA,GAAiB,cAAA;;;;;AAL9C;UAciB,kBAAA;EACf,GAAA,IAAO,MAAA;AAAA;;;;UAMQ,yBAAA;EACf,wBAAA,SACE,iBAAA,GAAoB,SAAA,EAAW,cAAA,KAAmB,MAAA,GACjD,kBAAA,CAAmB,MAAA;AAAA"}
|
package/dist/helpers/pl.cjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
const require_runtime = require(
|
|
2
|
-
const require_transaction = require(
|
|
3
|
-
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_transaction = require("../core/transaction.cjs");
|
|
4
3
|
//#region src/helpers/pl.ts
|
|
5
4
|
var pl_exports = /* @__PURE__ */ require_runtime.__exportAll({
|
|
6
5
|
ClientRoot: () => ClientRoot,
|
|
7
6
|
EphHolder: () => EphHolder,
|
|
8
7
|
EphStdMap: () => EphStdMap,
|
|
9
8
|
Holder: () => Holder,
|
|
10
|
-
HolderRefField: () =>
|
|
9
|
+
HolderRefField: () => "ref",
|
|
11
10
|
JsonArray: () => JsonArray,
|
|
12
11
|
JsonBool: () => JsonBool,
|
|
13
12
|
JsonGzObject: () => JsonGzObject,
|
|
@@ -90,33 +89,32 @@ function futureRecord(tx, rId, keys, fieldType, prefix = "") {
|
|
|
90
89
|
/** Name of the field in block holder, that references the actual block-pack. */
|
|
91
90
|
const Holder = StdMap;
|
|
92
91
|
const EphHolder = EphStdMap;
|
|
93
|
-
const HolderRefField = "ref";
|
|
94
92
|
function wrapInHolder(tx, ref) {
|
|
95
93
|
const holder = tx.createStruct(Holder);
|
|
96
|
-
const mainHolderField = require_transaction.field(holder,
|
|
94
|
+
const mainHolderField = require_transaction.field(holder, "ref");
|
|
97
95
|
tx.createField(mainHolderField, "Input", ref);
|
|
98
96
|
tx.lock(holder);
|
|
99
97
|
return holder;
|
|
100
98
|
}
|
|
101
99
|
function wrapInEphHolder(tx, ref) {
|
|
102
100
|
const holder = tx.createEphemeral(EphHolder);
|
|
103
|
-
const mainHolderField = require_transaction.field(holder,
|
|
101
|
+
const mainHolderField = require_transaction.field(holder, "ref");
|
|
104
102
|
tx.createField(mainHolderField, "Input", ref);
|
|
105
103
|
tx.lock(holder);
|
|
106
104
|
return holder;
|
|
107
105
|
}
|
|
108
106
|
function unwrapHolder(tx, ref) {
|
|
109
|
-
return tx.getFutureFieldValue(ref,
|
|
107
|
+
return tx.getFutureFieldValue(ref, "ref", "Input");
|
|
110
108
|
}
|
|
111
|
-
|
|
112
109
|
//#endregion
|
|
113
110
|
exports.ClientRoot = ClientRoot;
|
|
114
111
|
exports.JsonGzObject = JsonGzObject;
|
|
115
112
|
exports.JsonObject = JsonObject;
|
|
116
|
-
Object.defineProperty(exports,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
Object.defineProperty(exports, "pl_exports", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
get: function() {
|
|
116
|
+
return pl_exports;
|
|
117
|
+
}
|
|
121
118
|
});
|
|
119
|
+
|
|
122
120
|
//# sourceMappingURL=pl.cjs.map
|
package/dist/helpers/pl.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pl.cjs","names":["field"],"sources":["../../src/helpers/pl.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * This file is exported under Pl \"namespace\" to the client users.\n *\n * It defines well known pl types, and methods to manipulate them.\n *\n */\n\nimport type { FutureFieldType, ResourceType } from \"../core/types\";\nimport type { AnyRef, FieldRef, PlTransaction, ResourceRef } from \"../core/transaction\";\nimport { field } from \"../core/transaction\";\n\nfunction rt(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport const ClientRoot = rt(\"ClientRoot\", \"1\");\n\nexport const StructTestResource = rt(\"StructTest\", \"1\");\nexport const ValueTestResource = rt(\"ValueTest\", \"1\");\n\nexport const JsonString = rt(\"json/string\", \"1\");\nexport const JsonBool = rt(\"json/bool\", \"1\");\nexport const JsonObject = rt(\"json/object\", \"1\");\nexport const JsonGzObject = rt(\"json-gz/object\", \"1\");\nexport const JsonArray = rt(\"json/array\", \"1\");\nexport const JsonNumber = rt(\"json/number\", \"1\");\nexport const JsonNull = rt(\"json/null\", \"1\");\n\nexport const RNull = rt(\"Null\", \"1\");\n\nexport const EphStdMap: ResourceType = rt(\"EphStdMap\", \"1\");\nexport const StdMap: ResourceType = rt(\"StdMap\", \"1\");\n\n//\n// Standard value resources\n//\n\nexport function createPlNull(tx: PlTransaction): ResourceRef {\n return tx.createValue(JsonNull, Buffer.from(JSON.stringify(null)));\n}\n\nexport function createPlBool(tx: PlTransaction, val: boolean): ResourceRef {\n return tx.createValue(JsonBool, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlNumber(tx: PlTransaction, val: number): ResourceRef {\n return tx.createValue(JsonNumber, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlString(tx: PlTransaction, val: string): ResourceRef {\n return tx.createValue(JsonString, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlArray(tx: PlTransaction, val: any[]): ResourceRef {\n return tx.createValue(JsonArray, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlObject(tx: PlTransaction, val: object): ResourceRef {\n return tx.createValue(JsonObject, Buffer.from(JSON.stringify(val)));\n}\n\n//\n// Pl Map\n//\n\nexport type PlRecordEntry<Key extends string = string, Ref extends AnyRef = AnyRef> = [Key, Ref];\n\nexport type PlRecord<Key extends string = string, Ref extends AnyRef = AnyRef> = Record<Key, Ref>;\n\nexport function plEntry<Key extends string = string, Ref extends AnyRef = AnyRef>(\n key: Key,\n ref: Ref,\n): PlRecordEntry<Key, Ref> {\n return [key, ref];\n}\n\nexport function plEntries<Key extends string = string, Ref extends AnyRef = AnyRef>(\n record: PlRecord<Key, Ref>,\n fields?: Key[],\n): PlRecordEntry<Key, Ref>[] {\n return fields === undefined\n ? (Object.entries(record) as PlRecordEntry<Key, Ref>[])\n : fields.map((key) => plEntry(key, record[key]));\n}\n\n/** Helper method to build standard pl map from a set of entries */\nexport function createPlMap(\n tx: PlTransaction,\n entries: PlRecordEntry[] | PlRecord,\n ephemeral: boolean,\n type?: ResourceType,\n): ResourceRef {\n const actualType = type ?? (ephemeral ? EphStdMap : StdMap);\n const rId = ephemeral ? tx.createEphemeral(actualType) : tx.createStruct(actualType);\n\n for (const [name, value] of Array.isArray(entries) ? entries : plEntries(entries))\n tx.createField(field(rId, name), \"Input\", value);\n\n tx.lock(rId);\n\n return rId;\n}\n\nexport function futureRecord<Key extends string>(\n tx: PlTransaction,\n rId: AnyRef,\n keys: Key[],\n fieldType: FutureFieldType,\n prefix: string = \"\",\n): PlRecord<Key, FieldRef> {\n return Object.fromEntries(\n keys.map((k) => plEntry(k, tx.getFutureFieldValue(rId, `${prefix}${k}`, fieldType))),\n ) as PlRecord<Key, FieldRef>;\n}\n\n//\n// Holder\n//\n\n/** Name of the field in block holder, that references the actual block-pack. */\nexport const Holder = StdMap;\nexport const EphHolder = EphStdMap;\nexport const HolderRefField = \"ref\";\n\nexport function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createStruct(Holder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function wrapInEphHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createEphemeral(EphHolder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function unwrapHolder(tx: PlTransaction, ref: AnyRef): FieldRef {\n return tx.getFutureFieldValue(ref, HolderRefField, \"Input\");\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pl.cjs","names":["field"],"sources":["../../src/helpers/pl.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * This file is exported under Pl \"namespace\" to the client users.\n *\n * It defines well known pl types, and methods to manipulate them.\n *\n */\n\nimport type { FutureFieldType, ResourceType } from \"../core/types\";\nimport type { AnyRef, FieldRef, PlTransaction, ResourceRef } from \"../core/transaction\";\nimport { field } from \"../core/transaction\";\n\nfunction rt(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport const ClientRoot = rt(\"ClientRoot\", \"1\");\n\nexport const StructTestResource = rt(\"StructTest\", \"1\");\nexport const ValueTestResource = rt(\"ValueTest\", \"1\");\n\nexport const JsonString = rt(\"json/string\", \"1\");\nexport const JsonBool = rt(\"json/bool\", \"1\");\nexport const JsonObject = rt(\"json/object\", \"1\");\nexport const JsonGzObject = rt(\"json-gz/object\", \"1\");\nexport const JsonArray = rt(\"json/array\", \"1\");\nexport const JsonNumber = rt(\"json/number\", \"1\");\nexport const JsonNull = rt(\"json/null\", \"1\");\n\nexport const RNull = rt(\"Null\", \"1\");\n\nexport const EphStdMap: ResourceType = rt(\"EphStdMap\", \"1\");\nexport const StdMap: ResourceType = rt(\"StdMap\", \"1\");\n\n//\n// Standard value resources\n//\n\nexport function createPlNull(tx: PlTransaction): ResourceRef {\n return tx.createValue(JsonNull, Buffer.from(JSON.stringify(null)));\n}\n\nexport function createPlBool(tx: PlTransaction, val: boolean): ResourceRef {\n return tx.createValue(JsonBool, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlNumber(tx: PlTransaction, val: number): ResourceRef {\n return tx.createValue(JsonNumber, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlString(tx: PlTransaction, val: string): ResourceRef {\n return tx.createValue(JsonString, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlArray(tx: PlTransaction, val: any[]): ResourceRef {\n return tx.createValue(JsonArray, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlObject(tx: PlTransaction, val: object): ResourceRef {\n return tx.createValue(JsonObject, Buffer.from(JSON.stringify(val)));\n}\n\n//\n// Pl Map\n//\n\nexport type PlRecordEntry<Key extends string = string, Ref extends AnyRef = AnyRef> = [Key, Ref];\n\nexport type PlRecord<Key extends string = string, Ref extends AnyRef = AnyRef> = Record<Key, Ref>;\n\nexport function plEntry<Key extends string = string, Ref extends AnyRef = AnyRef>(\n key: Key,\n ref: Ref,\n): PlRecordEntry<Key, Ref> {\n return [key, ref];\n}\n\nexport function plEntries<Key extends string = string, Ref extends AnyRef = AnyRef>(\n record: PlRecord<Key, Ref>,\n fields?: Key[],\n): PlRecordEntry<Key, Ref>[] {\n return fields === undefined\n ? (Object.entries(record) as PlRecordEntry<Key, Ref>[])\n : fields.map((key) => plEntry(key, record[key]));\n}\n\n/** Helper method to build standard pl map from a set of entries */\nexport function createPlMap(\n tx: PlTransaction,\n entries: PlRecordEntry[] | PlRecord,\n ephemeral: boolean,\n type?: ResourceType,\n): ResourceRef {\n const actualType = type ?? (ephemeral ? EphStdMap : StdMap);\n const rId = ephemeral ? tx.createEphemeral(actualType) : tx.createStruct(actualType);\n\n for (const [name, value] of Array.isArray(entries) ? entries : plEntries(entries))\n tx.createField(field(rId, name), \"Input\", value);\n\n tx.lock(rId);\n\n return rId;\n}\n\nexport function futureRecord<Key extends string>(\n tx: PlTransaction,\n rId: AnyRef,\n keys: Key[],\n fieldType: FutureFieldType,\n prefix: string = \"\",\n): PlRecord<Key, FieldRef> {\n return Object.fromEntries(\n keys.map((k) => plEntry(k, tx.getFutureFieldValue(rId, `${prefix}${k}`, fieldType))),\n ) as PlRecord<Key, FieldRef>;\n}\n\n//\n// Holder\n//\n\n/** Name of the field in block holder, that references the actual block-pack. */\nexport const Holder = StdMap;\nexport const EphHolder = EphStdMap;\nexport const HolderRefField = \"ref\";\n\nexport function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createStruct(Holder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function wrapInEphHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createEphemeral(EphHolder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function unwrapHolder(tx: PlTransaction, ref: AnyRef): FieldRef {\n return tx.getFutureFieldValue(ref, HolderRefField, \"Input\");\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pl.d.ts","names":[],"sources":["../../src/helpers/pl.ts"],"mappings":";;;;;;;cAiBa,UAAA,EAAU,YAAA;AAAA,cAEV,kBAAA,EAAkB,YAAA;AAAA,cAClB,iBAAA,EAAiB,YAAA;AAAA,cAEjB,UAAA,EAAU,YAAA;AAAA,cACV,QAAA,EAAQ,YAAA;AAAA,cACR,UAAA,EAAU,YAAA;AAAA,cACV,YAAA,EAAY,YAAA;AAAA,cACZ,SAAA,EAAS,YAAA;AAAA,cACT,UAAA,EAAU,YAAA;AAAA,cACV,QAAA,EAAQ,YAAA;AAAA,cAER,KAAA,EAAK,YAAA;AAAA,cAEL,SAAA,EAAW,YAAA;AAAA,cACX,MAAA,EAAQ,YAAA;AAAA,iBAML,YAAA,CAAa,EAAA,EAAI,aAAA,GAAgB,WAAA;AAAA,iBAIjC,YAAA,CAAa,EAAA,EAAI,aAAA,EAAe,GAAA,YAAe,WAAA;AAAA,iBAI/C,cAAA,CAAe,EAAA,EAAI,aAAA,EAAe,GAAA,WAAc,WAAA;AAAA,iBAIhD,cAAA,CAAe,EAAA,EAAI,aAAA,EAAe,GAAA,WAAc,WAAA;AAAA,iBAIhD,aAAA,CAAc,EAAA,EAAI,aAAA,EAAe,GAAA,UAAa,WAAA;AAAA,iBAI9C,cAAA,CAAe,EAAA,EAAI,aAAA,EAAe,GAAA,WAAc,WAAA;AAAA,KAQpD,aAAA,0CAAuD,MAAA,GAAS,MAAA,KAAW,GAAA,EAAK,GAAA;AAAA,KAEhF,QAAA,0CAAkD,MAAA,GAAS,MAAA,IAAU,MAAA,CAAO,GAAA,EAAK,GAAA;AAAA,iBAE7E,OAAA,0CAAiD,MAAA,GAAS,MAAA,CAAA,CACxE,GAAA,EAAK,GAAA,EACL,GAAA,EAAK,GAAA,GACJ,aAAA,CAAc,GAAA,EAAK,GAAA;AAAA,iBAIN,SAAA,0CAAmD,MAAA,GAAS,MAAA,CAAA,CAC1E,MAAA,EAAQ,QAAA,CAAS,GAAA,EAAK,GAAA,GACtB,MAAA,GAAS,GAAA,KACR,aAAA,CAAc,GAAA,EAAK,GAAA;;iBAON,WAAA,CACd,EAAA,EAAI,aAAA,EACJ,OAAA,EAAS,aAAA,KAAkB,QAAA,EAC3B,SAAA,WACA,IAAA,GAAO,YAAA,GACN,WAAA;AAAA,iBAYa,YAAA,oBAAA,CACd,EAAA,EAAI,aAAA,EACJ,GAAA,EAAK,MAAA,EACL,IAAA,EAAM,GAAA,IACN,SAAA,EAAW,eAAA,EACX,MAAA,YACC,QAAA,CAAS,GAAA,EAAK,QAAA;;cAWJ,MAAA,EAAM,YAAA;AAAA,cACN,SAAA,EAAS,YAAA;AAAA,cACT,cAAA;AAAA,iBAEG,YAAA,CAAa,EAAA,EAAI,aAAA,EAAe,GAAA,EAAK,MAAA,GAAS,WAAA;AAAA,iBAQ9C,eAAA,CAAgB,EAAA,EAAI,aAAA,EAAe,GAAA,EAAK,MAAA,GAAS,WAAA;AAAA,iBAQjD,YAAA,CAAa,EAAA,EAAI,aAAA,EAAe,GAAA,EAAK,MAAA,GAAS,QAAA"}
|
package/dist/helpers/pl.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { field } from "../core/transaction.js";
|
|
3
|
-
|
|
4
3
|
//#region src/helpers/pl.ts
|
|
5
4
|
var pl_exports = /* @__PURE__ */ __exportAll({
|
|
6
5
|
ClientRoot: () => ClientRoot,
|
|
7
6
|
EphHolder: () => EphHolder,
|
|
8
7
|
EphStdMap: () => EphStdMap,
|
|
9
8
|
Holder: () => Holder,
|
|
10
|
-
HolderRefField: () =>
|
|
9
|
+
HolderRefField: () => "ref",
|
|
11
10
|
JsonArray: () => JsonArray,
|
|
12
11
|
JsonBool: () => JsonBool,
|
|
13
12
|
JsonGzObject: () => JsonGzObject,
|
|
@@ -90,25 +89,24 @@ function futureRecord(tx, rId, keys, fieldType, prefix = "") {
|
|
|
90
89
|
/** Name of the field in block holder, that references the actual block-pack. */
|
|
91
90
|
const Holder = StdMap;
|
|
92
91
|
const EphHolder = EphStdMap;
|
|
93
|
-
const HolderRefField = "ref";
|
|
94
92
|
function wrapInHolder(tx, ref) {
|
|
95
93
|
const holder = tx.createStruct(Holder);
|
|
96
|
-
const mainHolderField = field(holder,
|
|
94
|
+
const mainHolderField = field(holder, "ref");
|
|
97
95
|
tx.createField(mainHolderField, "Input", ref);
|
|
98
96
|
tx.lock(holder);
|
|
99
97
|
return holder;
|
|
100
98
|
}
|
|
101
99
|
function wrapInEphHolder(tx, ref) {
|
|
102
100
|
const holder = tx.createEphemeral(EphHolder);
|
|
103
|
-
const mainHolderField = field(holder,
|
|
101
|
+
const mainHolderField = field(holder, "ref");
|
|
104
102
|
tx.createField(mainHolderField, "Input", ref);
|
|
105
103
|
tx.lock(holder);
|
|
106
104
|
return holder;
|
|
107
105
|
}
|
|
108
106
|
function unwrapHolder(tx, ref) {
|
|
109
|
-
return tx.getFutureFieldValue(ref,
|
|
107
|
+
return tx.getFutureFieldValue(ref, "ref", "Input");
|
|
110
108
|
}
|
|
111
|
-
|
|
112
109
|
//#endregion
|
|
113
110
|
export { ClientRoot, JsonGzObject, JsonObject, pl_exports };
|
|
111
|
+
|
|
114
112
|
//# sourceMappingURL=pl.js.map
|
package/dist/helpers/pl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pl.js","names":[],"sources":["../../src/helpers/pl.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * This file is exported under Pl \"namespace\" to the client users.\n *\n * It defines well known pl types, and methods to manipulate them.\n *\n */\n\nimport type { FutureFieldType, ResourceType } from \"../core/types\";\nimport type { AnyRef, FieldRef, PlTransaction, ResourceRef } from \"../core/transaction\";\nimport { field } from \"../core/transaction\";\n\nfunction rt(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport const ClientRoot = rt(\"ClientRoot\", \"1\");\n\nexport const StructTestResource = rt(\"StructTest\", \"1\");\nexport const ValueTestResource = rt(\"ValueTest\", \"1\");\n\nexport const JsonString = rt(\"json/string\", \"1\");\nexport const JsonBool = rt(\"json/bool\", \"1\");\nexport const JsonObject = rt(\"json/object\", \"1\");\nexport const JsonGzObject = rt(\"json-gz/object\", \"1\");\nexport const JsonArray = rt(\"json/array\", \"1\");\nexport const JsonNumber = rt(\"json/number\", \"1\");\nexport const JsonNull = rt(\"json/null\", \"1\");\n\nexport const RNull = rt(\"Null\", \"1\");\n\nexport const EphStdMap: ResourceType = rt(\"EphStdMap\", \"1\");\nexport const StdMap: ResourceType = rt(\"StdMap\", \"1\");\n\n//\n// Standard value resources\n//\n\nexport function createPlNull(tx: PlTransaction): ResourceRef {\n return tx.createValue(JsonNull, Buffer.from(JSON.stringify(null)));\n}\n\nexport function createPlBool(tx: PlTransaction, val: boolean): ResourceRef {\n return tx.createValue(JsonBool, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlNumber(tx: PlTransaction, val: number): ResourceRef {\n return tx.createValue(JsonNumber, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlString(tx: PlTransaction, val: string): ResourceRef {\n return tx.createValue(JsonString, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlArray(tx: PlTransaction, val: any[]): ResourceRef {\n return tx.createValue(JsonArray, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlObject(tx: PlTransaction, val: object): ResourceRef {\n return tx.createValue(JsonObject, Buffer.from(JSON.stringify(val)));\n}\n\n//\n// Pl Map\n//\n\nexport type PlRecordEntry<Key extends string = string, Ref extends AnyRef = AnyRef> = [Key, Ref];\n\nexport type PlRecord<Key extends string = string, Ref extends AnyRef = AnyRef> = Record<Key, Ref>;\n\nexport function plEntry<Key extends string = string, Ref extends AnyRef = AnyRef>(\n key: Key,\n ref: Ref,\n): PlRecordEntry<Key, Ref> {\n return [key, ref];\n}\n\nexport function plEntries<Key extends string = string, Ref extends AnyRef = AnyRef>(\n record: PlRecord<Key, Ref>,\n fields?: Key[],\n): PlRecordEntry<Key, Ref>[] {\n return fields === undefined\n ? (Object.entries(record) as PlRecordEntry<Key, Ref>[])\n : fields.map((key) => plEntry(key, record[key]));\n}\n\n/** Helper method to build standard pl map from a set of entries */\nexport function createPlMap(\n tx: PlTransaction,\n entries: PlRecordEntry[] | PlRecord,\n ephemeral: boolean,\n type?: ResourceType,\n): ResourceRef {\n const actualType = type ?? (ephemeral ? EphStdMap : StdMap);\n const rId = ephemeral ? tx.createEphemeral(actualType) : tx.createStruct(actualType);\n\n for (const [name, value] of Array.isArray(entries) ? entries : plEntries(entries))\n tx.createField(field(rId, name), \"Input\", value);\n\n tx.lock(rId);\n\n return rId;\n}\n\nexport function futureRecord<Key extends string>(\n tx: PlTransaction,\n rId: AnyRef,\n keys: Key[],\n fieldType: FutureFieldType,\n prefix: string = \"\",\n): PlRecord<Key, FieldRef> {\n return Object.fromEntries(\n keys.map((k) => plEntry(k, tx.getFutureFieldValue(rId, `${prefix}${k}`, fieldType))),\n ) as PlRecord<Key, FieldRef>;\n}\n\n//\n// Holder\n//\n\n/** Name of the field in block holder, that references the actual block-pack. */\nexport const Holder = StdMap;\nexport const EphHolder = EphStdMap;\nexport const HolderRefField = \"ref\";\n\nexport function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createStruct(Holder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function wrapInEphHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createEphemeral(EphHolder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function unwrapHolder(tx: PlTransaction, ref: AnyRef): FieldRef {\n return tx.getFutureFieldValue(ref, HolderRefField, \"Input\");\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pl.js","names":[],"sources":["../../src/helpers/pl.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * This file is exported under Pl \"namespace\" to the client users.\n *\n * It defines well known pl types, and methods to manipulate them.\n *\n */\n\nimport type { FutureFieldType, ResourceType } from \"../core/types\";\nimport type { AnyRef, FieldRef, PlTransaction, ResourceRef } from \"../core/transaction\";\nimport { field } from \"../core/transaction\";\n\nfunction rt(name: string, version: string): ResourceType {\n return { name, version };\n}\n\nexport const ClientRoot = rt(\"ClientRoot\", \"1\");\n\nexport const StructTestResource = rt(\"StructTest\", \"1\");\nexport const ValueTestResource = rt(\"ValueTest\", \"1\");\n\nexport const JsonString = rt(\"json/string\", \"1\");\nexport const JsonBool = rt(\"json/bool\", \"1\");\nexport const JsonObject = rt(\"json/object\", \"1\");\nexport const JsonGzObject = rt(\"json-gz/object\", \"1\");\nexport const JsonArray = rt(\"json/array\", \"1\");\nexport const JsonNumber = rt(\"json/number\", \"1\");\nexport const JsonNull = rt(\"json/null\", \"1\");\n\nexport const RNull = rt(\"Null\", \"1\");\n\nexport const EphStdMap: ResourceType = rt(\"EphStdMap\", \"1\");\nexport const StdMap: ResourceType = rt(\"StdMap\", \"1\");\n\n//\n// Standard value resources\n//\n\nexport function createPlNull(tx: PlTransaction): ResourceRef {\n return tx.createValue(JsonNull, Buffer.from(JSON.stringify(null)));\n}\n\nexport function createPlBool(tx: PlTransaction, val: boolean): ResourceRef {\n return tx.createValue(JsonBool, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlNumber(tx: PlTransaction, val: number): ResourceRef {\n return tx.createValue(JsonNumber, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlString(tx: PlTransaction, val: string): ResourceRef {\n return tx.createValue(JsonString, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlArray(tx: PlTransaction, val: any[]): ResourceRef {\n return tx.createValue(JsonArray, Buffer.from(JSON.stringify(val)));\n}\n\nexport function createPlObject(tx: PlTransaction, val: object): ResourceRef {\n return tx.createValue(JsonObject, Buffer.from(JSON.stringify(val)));\n}\n\n//\n// Pl Map\n//\n\nexport type PlRecordEntry<Key extends string = string, Ref extends AnyRef = AnyRef> = [Key, Ref];\n\nexport type PlRecord<Key extends string = string, Ref extends AnyRef = AnyRef> = Record<Key, Ref>;\n\nexport function plEntry<Key extends string = string, Ref extends AnyRef = AnyRef>(\n key: Key,\n ref: Ref,\n): PlRecordEntry<Key, Ref> {\n return [key, ref];\n}\n\nexport function plEntries<Key extends string = string, Ref extends AnyRef = AnyRef>(\n record: PlRecord<Key, Ref>,\n fields?: Key[],\n): PlRecordEntry<Key, Ref>[] {\n return fields === undefined\n ? (Object.entries(record) as PlRecordEntry<Key, Ref>[])\n : fields.map((key) => plEntry(key, record[key]));\n}\n\n/** Helper method to build standard pl map from a set of entries */\nexport function createPlMap(\n tx: PlTransaction,\n entries: PlRecordEntry[] | PlRecord,\n ephemeral: boolean,\n type?: ResourceType,\n): ResourceRef {\n const actualType = type ?? (ephemeral ? EphStdMap : StdMap);\n const rId = ephemeral ? tx.createEphemeral(actualType) : tx.createStruct(actualType);\n\n for (const [name, value] of Array.isArray(entries) ? entries : plEntries(entries))\n tx.createField(field(rId, name), \"Input\", value);\n\n tx.lock(rId);\n\n return rId;\n}\n\nexport function futureRecord<Key extends string>(\n tx: PlTransaction,\n rId: AnyRef,\n keys: Key[],\n fieldType: FutureFieldType,\n prefix: string = \"\",\n): PlRecord<Key, FieldRef> {\n return Object.fromEntries(\n keys.map((k) => plEntry(k, tx.getFutureFieldValue(rId, `${prefix}${k}`, fieldType))),\n ) as PlRecord<Key, FieldRef>;\n}\n\n//\n// Holder\n//\n\n/** Name of the field in block holder, that references the actual block-pack. */\nexport const Holder = StdMap;\nexport const EphHolder = EphStdMap;\nexport const HolderRefField = \"ref\";\n\nexport function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createStruct(Holder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function wrapInEphHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {\n const holder = tx.createEphemeral(EphHolder);\n const mainHolderField = field(holder, HolderRefField);\n tx.createField(mainHolderField, \"Input\", ref);\n tx.lock(holder);\n return holder;\n}\n\nexport function unwrapHolder(tx: PlTransaction, ref: AnyRef): FieldRef {\n return tx.getFutureFieldValue(ref, HolderRefField, \"Input\");\n}\n"],"mappings":"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"}
|
package/dist/helpers/poll.cjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
const require_runtime = require(
|
|
2
|
-
const require_types = require(
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_types = require("../core/types.cjs");
|
|
3
3
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
4
4
|
let node_timers_promises = require("node:timers/promises");
|
|
5
5
|
node_timers_promises = require_runtime.__toESM(node_timers_promises);
|
|
6
|
-
|
|
7
6
|
//#region src/helpers/poll.ts
|
|
8
7
|
/** This error tells state assertion mechanism that required state is not yet ready */
|
|
9
8
|
var ContinuePolling = class extends Error {
|
|
@@ -103,11 +102,11 @@ async function poll(cl, cb, retryOptions = DefaultPollingRetryOptions, txName =
|
|
|
103
102
|
retryState = (0, _milaboratories_ts_helpers.nextRetryStateOrError)(retryState);
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
|
-
|
|
107
105
|
//#endregion
|
|
108
106
|
exports.ContinuePolling = ContinuePolling;
|
|
109
107
|
exports.DefaultPollingRetryOptions = DefaultPollingRetryOptions;
|
|
110
108
|
exports.PollResourceAccessor = PollResourceAccessor;
|
|
111
109
|
exports.PollTxAccessor = PollTxAccessor;
|
|
112
110
|
exports.poll = poll;
|
|
111
|
+
|
|
113
112
|
//# sourceMappingURL=poll.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll.cjs","names":["isNullResourceId","isNotNullResourceId","resourceIdToString","tp"],"sources":["../../src/helpers/poll.ts"],"sourcesContent":["import type { PlClient } from \"../core/client\";\nimport type { RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { createRetryState, nextRetryStateOrError, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldData, FieldType, ResourceData, ResourceId } from \"../core/types\";\nimport { isNotNullResourceId, isNullResourceId, resourceIdToString } from \"../core/types\";\nimport type { PlTransaction } from \"../core/transaction\";\nimport * as tp from \"node:timers/promises\";\n\n/** This error tells state assertion mechanism that required state is not yet ready */\nexport class ContinuePolling extends Error {\n name = \"ContinuePolling\";\n}\n\nexport type PollFieldTraverseOps = {\n expectedType?: FieldType;\n /** Fail if error present along with the value, if value not present,\n * but error do, exception will be thrown anyway. */\n failOnError: boolean;\n /** Traverse only if field report its value as final. */\n onlyFinal: boolean;\n};\n\nconst DefaultPollFieldTraverseOps: PollFieldTraverseOps = {\n failOnError: true,\n onlyFinal: false,\n};\n\nexport class PollResourceAccessor {\n constructor(\n public readonly tx: PollTxAccessor,\n public readonly data: ResourceData,\n public readonly path: string[],\n ) {}\n\n public final(): PollResourceAccessor {\n if (!this.data.final) throw new ContinuePolling();\n return this;\n }\n\n public async requireNoError(): Promise<PollResourceAccessor> {\n if (isNullResourceId(this.data.error)) return this;\n await this.tx.throwError(this.data.error, this.path);\n // hmm... https://github.com/microsoft/TypeScript/issues/34955\n return this;\n }\n\n public getFieldData(name: string, expectedType?: FieldType): FieldData {\n const fieldData = this.data.fields.find((f) => f.name === name);\n\n if (fieldData !== undefined) {\n if (expectedType !== undefined && fieldData.type !== expectedType)\n throw new Error(`Unexpected field type. Expected ${expectedType}, found ${fieldData.type}`);\n return fieldData;\n }\n\n if (\n ((expectedType === \"Input\" || expectedType === \"Service\") && this.data.inputsLocked) ||\n (expectedType === \"Output\" && this.data.outputsLocked)\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions\n `Field \"${name}\" not found. Expected type: ${expectedType}, state: ${this.data}`,\n );\n\n throw new ContinuePolling();\n }\n\n public async get(\n name: string,\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<PollResourceAccessor> {\n const { expectedType, failOnError } = { ...DefaultPollFieldTraverseOps, ...ops };\n const path = [...this.path, name];\n\n const fieldData = this.getFieldData(name, expectedType);\n if (isNotNullResourceId(fieldData.error) && (failOnError || isNullResourceId(fieldData.value)))\n await this.tx.throwError(fieldData.error, path);\n\n if (isNullResourceId(fieldData.value)) throw new ContinuePolling();\n\n return await this.tx.get(fieldData.value, failOnError, path);\n }\n\n public async getMulti(\n ops: Partial<PollFieldTraverseOps>,\n ...names: string[]\n ): Promise<PollResourceAccessor[]> {\n return await Promise.all(names.map((name) => this.get(name, ops)));\n }\n\n public async getMultiObj<Key extends string>(\n ops: Partial<PollFieldTraverseOps>,\n ...names: Key[]\n ): Promise<Record<Key, PollResourceAccessor>> {\n return Object.fromEntries(\n await Promise.all(names.map(async (name) => [name, await this.get(name, ops)])),\n );\n }\n\n public async getAllFinal(\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<Record<string, PollResourceAccessor>> {\n return await this.getMultiObj(\n ops,\n ...this.data.fields\n .filter((f) => f.valueIsFinal || isNotNullResourceId(f.error))\n .map((f) => f.name),\n );\n }\n\n public async getKValue(key: string): Promise<string> {\n const value = await this.tx.tx.getKValueStringIfExists(this.data.id, key);\n if (value === undefined) throw new ContinuePolling();\n return value;\n }\n\n public async getKValueObj<T>(key: string): Promise<T> {\n return JSON.parse(await this.getKValue(key)) as T;\n }\n}\n\nexport class PollTxAccessor {\n constructor(public readonly tx: PlTransaction) {}\n\n public async get(\n rid: ResourceId,\n failOnError: boolean = true,\n path: string[] = [],\n ): Promise<PollResourceAccessor> {\n const data = await this.tx.getResourceData(rid, true);\n const accessor = new PollResourceAccessor(this, data, [...path, resourceIdToString(rid)]);\n if (failOnError) await accessor.requireNoError();\n return accessor;\n }\n\n async throwError(error: ResourceId, path: string[] = []): Promise<never> {\n const errorRes = await this.get(error);\n const errorText = Buffer.from(notEmpty(errorRes.data.data)).toString();\n throw new Error(`${path.join(\" -> \")} = ${errorText}`);\n }\n}\n\nexport const DefaultPollingRetryOptions: RetryOptions = {\n type: \"linearBackoff\",\n jitter: 0,\n maxAttempts: 100,\n backoffStep: 10,\n initialDelay: 10,\n};\n\nexport async function poll<T>(\n cl: PlClient,\n cb: (tx: PollTxAccessor) => Promise<T>,\n retryOptions: RetryOptions = DefaultPollingRetryOptions,\n txName: string = \"polling\",\n): Promise<T> {\n let retryState = createRetryState(retryOptions);\n while (true) {\n try {\n return await cl.withReadTx(txName, async (tx) => {\n return await cb(new PollTxAccessor(tx));\n });\n } catch (e: any) {\n // Rethrowing any error except the \"not ready yet\"\n if (!(e instanceof ContinuePolling)) throw e;\n }\n await tp.setTimeout(retryState.nextDelay);\n retryState = nextRetryStateOrError(retryState);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"poll.cjs","names":["isNullResourceId","isNotNullResourceId","resourceIdToString","tp"],"sources":["../../src/helpers/poll.ts"],"sourcesContent":["import type { PlClient } from \"../core/client\";\nimport type { RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { createRetryState, nextRetryStateOrError, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldData, FieldType, ResourceData, ResourceId } from \"../core/types\";\nimport { isNotNullResourceId, isNullResourceId, resourceIdToString } from \"../core/types\";\nimport type { PlTransaction } from \"../core/transaction\";\nimport * as tp from \"node:timers/promises\";\n\n/** This error tells state assertion mechanism that required state is not yet ready */\nexport class ContinuePolling extends Error {\n name = \"ContinuePolling\";\n}\n\nexport type PollFieldTraverseOps = {\n expectedType?: FieldType;\n /** Fail if error present along with the value, if value not present,\n * but error do, exception will be thrown anyway. */\n failOnError: boolean;\n /** Traverse only if field report its value as final. */\n onlyFinal: boolean;\n};\n\nconst DefaultPollFieldTraverseOps: PollFieldTraverseOps = {\n failOnError: true,\n onlyFinal: false,\n};\n\nexport class PollResourceAccessor {\n constructor(\n public readonly tx: PollTxAccessor,\n public readonly data: ResourceData,\n public readonly path: string[],\n ) {}\n\n public final(): PollResourceAccessor {\n if (!this.data.final) throw new ContinuePolling();\n return this;\n }\n\n public async requireNoError(): Promise<PollResourceAccessor> {\n if (isNullResourceId(this.data.error)) return this;\n await this.tx.throwError(this.data.error, this.path);\n // hmm... https://github.com/microsoft/TypeScript/issues/34955\n return this;\n }\n\n public getFieldData(name: string, expectedType?: FieldType): FieldData {\n const fieldData = this.data.fields.find((f) => f.name === name);\n\n if (fieldData !== undefined) {\n if (expectedType !== undefined && fieldData.type !== expectedType)\n throw new Error(`Unexpected field type. Expected ${expectedType}, found ${fieldData.type}`);\n return fieldData;\n }\n\n if (\n ((expectedType === \"Input\" || expectedType === \"Service\") && this.data.inputsLocked) ||\n (expectedType === \"Output\" && this.data.outputsLocked)\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions\n `Field \"${name}\" not found. Expected type: ${expectedType}, state: ${this.data}`,\n );\n\n throw new ContinuePolling();\n }\n\n public async get(\n name: string,\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<PollResourceAccessor> {\n const { expectedType, failOnError } = { ...DefaultPollFieldTraverseOps, ...ops };\n const path = [...this.path, name];\n\n const fieldData = this.getFieldData(name, expectedType);\n if (isNotNullResourceId(fieldData.error) && (failOnError || isNullResourceId(fieldData.value)))\n await this.tx.throwError(fieldData.error, path);\n\n if (isNullResourceId(fieldData.value)) throw new ContinuePolling();\n\n return await this.tx.get(fieldData.value, failOnError, path);\n }\n\n public async getMulti(\n ops: Partial<PollFieldTraverseOps>,\n ...names: string[]\n ): Promise<PollResourceAccessor[]> {\n return await Promise.all(names.map((name) => this.get(name, ops)));\n }\n\n public async getMultiObj<Key extends string>(\n ops: Partial<PollFieldTraverseOps>,\n ...names: Key[]\n ): Promise<Record<Key, PollResourceAccessor>> {\n return Object.fromEntries(\n await Promise.all(names.map(async (name) => [name, await this.get(name, ops)])),\n );\n }\n\n public async getAllFinal(\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<Record<string, PollResourceAccessor>> {\n return await this.getMultiObj(\n ops,\n ...this.data.fields\n .filter((f) => f.valueIsFinal || isNotNullResourceId(f.error))\n .map((f) => f.name),\n );\n }\n\n public async getKValue(key: string): Promise<string> {\n const value = await this.tx.tx.getKValueStringIfExists(this.data.id, key);\n if (value === undefined) throw new ContinuePolling();\n return value;\n }\n\n public async getKValueObj<T>(key: string): Promise<T> {\n return JSON.parse(await this.getKValue(key)) as T;\n }\n}\n\nexport class PollTxAccessor {\n constructor(public readonly tx: PlTransaction) {}\n\n public async get(\n rid: ResourceId,\n failOnError: boolean = true,\n path: string[] = [],\n ): Promise<PollResourceAccessor> {\n const data = await this.tx.getResourceData(rid, true);\n const accessor = new PollResourceAccessor(this, data, [...path, resourceIdToString(rid)]);\n if (failOnError) await accessor.requireNoError();\n return accessor;\n }\n\n async throwError(error: ResourceId, path: string[] = []): Promise<never> {\n const errorRes = await this.get(error);\n const errorText = Buffer.from(notEmpty(errorRes.data.data)).toString();\n throw new Error(`${path.join(\" -> \")} = ${errorText}`);\n }\n}\n\nexport const DefaultPollingRetryOptions: RetryOptions = {\n type: \"linearBackoff\",\n jitter: 0,\n maxAttempts: 100,\n backoffStep: 10,\n initialDelay: 10,\n};\n\nexport async function poll<T>(\n cl: PlClient,\n cb: (tx: PollTxAccessor) => Promise<T>,\n retryOptions: RetryOptions = DefaultPollingRetryOptions,\n txName: string = \"polling\",\n): Promise<T> {\n let retryState = createRetryState(retryOptions);\n while (true) {\n try {\n return await cl.withReadTx(txName, async (tx) => {\n return await cb(new PollTxAccessor(tx));\n });\n } catch (e: any) {\n // Rethrowing any error except the \"not ready yet\"\n if (!(e instanceof ContinuePolling)) throw e;\n }\n await tp.setTimeout(retryState.nextDelay);\n retryState = nextRetryStateOrError(retryState);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.d.ts","names":[],"sources":["../../src/helpers/poll.ts"],"mappings":";;;;;;;cASa,eAAA,SAAwB,KAAA;EACnC,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,YAAA,GAAe,SAAA;EAJX;AAGN;EAIE,WAAA;EAEA,SAAA;AAAA;AAAA,cAQW,oBAAA;EAAA,SAEO,EAAA,EAAI,cAAA;EAAA,SACJ,IAAA,EAAM,YAAA;EAAA,SACN,IAAA;cAFA,EAAA,EAAI,cAAA,EACJ,IAAA,EAAM,YAAA,EACN,IAAA;EAGX,KAAA,CAAA,GAAS,oBAAA;EAKH,cAAA,CAAA,GAAkB,OAAA,CAAQ,oBAAA;EAOhC,YAAA,CAAa,IAAA,UAAc,YAAA,GAAe,SAAA,GAAY,SAAA;EAqBhD,GAAA,CACX,IAAA,UACA,GAAA,GAAK,OAAA,CAAQ,oBAAA,IACZ,OAAA,CAAQ,oBAAA;EAaE,QAAA,CACX,GAAA,EAAK,OAAA,CAAQ,oBAAA,MACV,KAAA,aACF,OAAA,CAAQ,oBAAA;EAIE,WAAA,oBAAA,CACX,GAAA,EAAK,OAAA,CAAQ,oBAAA,MACV,KAAA,EAAO,GAAA,KACT,OAAA,CAAQ,MAAA,CAAO,GAAA,EAAK,oBAAA;EAMV,WAAA,CACX,GAAA,GAAK,OAAA,CAAQ,oBAAA,IACZ,OAAA,CAAQ,MAAA,SAAe,oBAAA;EASb,SAAA,CAAU,GAAA,WAAc,OAAA;EAMxB,YAAA,GAAA,CAAgB,GAAA,WAAc,OAAA,CAAQ,CAAA;AAAA;AAAA,cAKxC,cAAA;EAAA,SACiB,EAAA,EAAI,aAAA;cAAJ,EAAA,EAAI,aAAA;EAEnB,GAAA,CACX,GAAA,EAAK,UAAA,EACL,WAAA,YACA,IAAA,cACC,OAAA,CAAQ,oBAAA;EAOL,UAAA,CAAW,KAAA,EAAO,UAAA,EAAY,IAAA,cAAsB,OAAA;AAAA;AAAA,cAO/C,0BAAA,EAA4B,YAAA;AAAA,iBAQnB,IAAA,GAAA,CACpB,EAAA,EAAI,QAAA,EACJ,EAAA,GAAK,EAAA,EAAI,cAAA,KAAmB,OAAA,CAAQ,CAAA,GACpC,YAAA,GAAc,YAAA,EACd,MAAA,YACC,OAAA,CAAQ,CAAA"}
|
package/dist/helpers/poll.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isNotNullResourceId, isNullResourceId, resourceIdToString } from "../core/types.js";
|
|
2
2
|
import { createRetryState, nextRetryStateOrError, notEmpty } from "@milaboratories/ts-helpers";
|
|
3
3
|
import * as tp from "node:timers/promises";
|
|
4
|
-
|
|
5
4
|
//#region src/helpers/poll.ts
|
|
6
5
|
/** This error tells state assertion mechanism that required state is not yet ready */
|
|
7
6
|
var ContinuePolling = class extends Error {
|
|
@@ -101,7 +100,7 @@ async function poll(cl, cb, retryOptions = DefaultPollingRetryOptions, txName =
|
|
|
101
100
|
retryState = nextRetryStateOrError(retryState);
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
|
-
|
|
105
103
|
//#endregion
|
|
106
104
|
export { ContinuePolling, DefaultPollingRetryOptions, PollResourceAccessor, PollTxAccessor, poll };
|
|
105
|
+
|
|
107
106
|
//# sourceMappingURL=poll.js.map
|
package/dist/helpers/poll.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll.js","names":[],"sources":["../../src/helpers/poll.ts"],"sourcesContent":["import type { PlClient } from \"../core/client\";\nimport type { RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { createRetryState, nextRetryStateOrError, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldData, FieldType, ResourceData, ResourceId } from \"../core/types\";\nimport { isNotNullResourceId, isNullResourceId, resourceIdToString } from \"../core/types\";\nimport type { PlTransaction } from \"../core/transaction\";\nimport * as tp from \"node:timers/promises\";\n\n/** This error tells state assertion mechanism that required state is not yet ready */\nexport class ContinuePolling extends Error {\n name = \"ContinuePolling\";\n}\n\nexport type PollFieldTraverseOps = {\n expectedType?: FieldType;\n /** Fail if error present along with the value, if value not present,\n * but error do, exception will be thrown anyway. */\n failOnError: boolean;\n /** Traverse only if field report its value as final. */\n onlyFinal: boolean;\n};\n\nconst DefaultPollFieldTraverseOps: PollFieldTraverseOps = {\n failOnError: true,\n onlyFinal: false,\n};\n\nexport class PollResourceAccessor {\n constructor(\n public readonly tx: PollTxAccessor,\n public readonly data: ResourceData,\n public readonly path: string[],\n ) {}\n\n public final(): PollResourceAccessor {\n if (!this.data.final) throw new ContinuePolling();\n return this;\n }\n\n public async requireNoError(): Promise<PollResourceAccessor> {\n if (isNullResourceId(this.data.error)) return this;\n await this.tx.throwError(this.data.error, this.path);\n // hmm... https://github.com/microsoft/TypeScript/issues/34955\n return this;\n }\n\n public getFieldData(name: string, expectedType?: FieldType): FieldData {\n const fieldData = this.data.fields.find((f) => f.name === name);\n\n if (fieldData !== undefined) {\n if (expectedType !== undefined && fieldData.type !== expectedType)\n throw new Error(`Unexpected field type. Expected ${expectedType}, found ${fieldData.type}`);\n return fieldData;\n }\n\n if (\n ((expectedType === \"Input\" || expectedType === \"Service\") && this.data.inputsLocked) ||\n (expectedType === \"Output\" && this.data.outputsLocked)\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions\n `Field \"${name}\" not found. Expected type: ${expectedType}, state: ${this.data}`,\n );\n\n throw new ContinuePolling();\n }\n\n public async get(\n name: string,\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<PollResourceAccessor> {\n const { expectedType, failOnError } = { ...DefaultPollFieldTraverseOps, ...ops };\n const path = [...this.path, name];\n\n const fieldData = this.getFieldData(name, expectedType);\n if (isNotNullResourceId(fieldData.error) && (failOnError || isNullResourceId(fieldData.value)))\n await this.tx.throwError(fieldData.error, path);\n\n if (isNullResourceId(fieldData.value)) throw new ContinuePolling();\n\n return await this.tx.get(fieldData.value, failOnError, path);\n }\n\n public async getMulti(\n ops: Partial<PollFieldTraverseOps>,\n ...names: string[]\n ): Promise<PollResourceAccessor[]> {\n return await Promise.all(names.map((name) => this.get(name, ops)));\n }\n\n public async getMultiObj<Key extends string>(\n ops: Partial<PollFieldTraverseOps>,\n ...names: Key[]\n ): Promise<Record<Key, PollResourceAccessor>> {\n return Object.fromEntries(\n await Promise.all(names.map(async (name) => [name, await this.get(name, ops)])),\n );\n }\n\n public async getAllFinal(\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<Record<string, PollResourceAccessor>> {\n return await this.getMultiObj(\n ops,\n ...this.data.fields\n .filter((f) => f.valueIsFinal || isNotNullResourceId(f.error))\n .map((f) => f.name),\n );\n }\n\n public async getKValue(key: string): Promise<string> {\n const value = await this.tx.tx.getKValueStringIfExists(this.data.id, key);\n if (value === undefined) throw new ContinuePolling();\n return value;\n }\n\n public async getKValueObj<T>(key: string): Promise<T> {\n return JSON.parse(await this.getKValue(key)) as T;\n }\n}\n\nexport class PollTxAccessor {\n constructor(public readonly tx: PlTransaction) {}\n\n public async get(\n rid: ResourceId,\n failOnError: boolean = true,\n path: string[] = [],\n ): Promise<PollResourceAccessor> {\n const data = await this.tx.getResourceData(rid, true);\n const accessor = new PollResourceAccessor(this, data, [...path, resourceIdToString(rid)]);\n if (failOnError) await accessor.requireNoError();\n return accessor;\n }\n\n async throwError(error: ResourceId, path: string[] = []): Promise<never> {\n const errorRes = await this.get(error);\n const errorText = Buffer.from(notEmpty(errorRes.data.data)).toString();\n throw new Error(`${path.join(\" -> \")} = ${errorText}`);\n }\n}\n\nexport const DefaultPollingRetryOptions: RetryOptions = {\n type: \"linearBackoff\",\n jitter: 0,\n maxAttempts: 100,\n backoffStep: 10,\n initialDelay: 10,\n};\n\nexport async function poll<T>(\n cl: PlClient,\n cb: (tx: PollTxAccessor) => Promise<T>,\n retryOptions: RetryOptions = DefaultPollingRetryOptions,\n txName: string = \"polling\",\n): Promise<T> {\n let retryState = createRetryState(retryOptions);\n while (true) {\n try {\n return await cl.withReadTx(txName, async (tx) => {\n return await cb(new PollTxAccessor(tx));\n });\n } catch (e: any) {\n // Rethrowing any error except the \"not ready yet\"\n if (!(e instanceof ContinuePolling)) throw e;\n }\n await tp.setTimeout(retryState.nextDelay);\n retryState = nextRetryStateOrError(retryState);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"poll.js","names":[],"sources":["../../src/helpers/poll.ts"],"sourcesContent":["import type { PlClient } from \"../core/client\";\nimport type { RetryOptions } from \"@milaboratories/ts-helpers\";\nimport { createRetryState, nextRetryStateOrError, notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { FieldData, FieldType, ResourceData, ResourceId } from \"../core/types\";\nimport { isNotNullResourceId, isNullResourceId, resourceIdToString } from \"../core/types\";\nimport type { PlTransaction } from \"../core/transaction\";\nimport * as tp from \"node:timers/promises\";\n\n/** This error tells state assertion mechanism that required state is not yet ready */\nexport class ContinuePolling extends Error {\n name = \"ContinuePolling\";\n}\n\nexport type PollFieldTraverseOps = {\n expectedType?: FieldType;\n /** Fail if error present along with the value, if value not present,\n * but error do, exception will be thrown anyway. */\n failOnError: boolean;\n /** Traverse only if field report its value as final. */\n onlyFinal: boolean;\n};\n\nconst DefaultPollFieldTraverseOps: PollFieldTraverseOps = {\n failOnError: true,\n onlyFinal: false,\n};\n\nexport class PollResourceAccessor {\n constructor(\n public readonly tx: PollTxAccessor,\n public readonly data: ResourceData,\n public readonly path: string[],\n ) {}\n\n public final(): PollResourceAccessor {\n if (!this.data.final) throw new ContinuePolling();\n return this;\n }\n\n public async requireNoError(): Promise<PollResourceAccessor> {\n if (isNullResourceId(this.data.error)) return this;\n await this.tx.throwError(this.data.error, this.path);\n // hmm... https://github.com/microsoft/TypeScript/issues/34955\n return this;\n }\n\n public getFieldData(name: string, expectedType?: FieldType): FieldData {\n const fieldData = this.data.fields.find((f) => f.name === name);\n\n if (fieldData !== undefined) {\n if (expectedType !== undefined && fieldData.type !== expectedType)\n throw new Error(`Unexpected field type. Expected ${expectedType}, found ${fieldData.type}`);\n return fieldData;\n }\n\n if (\n ((expectedType === \"Input\" || expectedType === \"Service\") && this.data.inputsLocked) ||\n (expectedType === \"Output\" && this.data.outputsLocked)\n )\n throw new Error(\n // eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions\n `Field \"${name}\" not found. Expected type: ${expectedType}, state: ${this.data}`,\n );\n\n throw new ContinuePolling();\n }\n\n public async get(\n name: string,\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<PollResourceAccessor> {\n const { expectedType, failOnError } = { ...DefaultPollFieldTraverseOps, ...ops };\n const path = [...this.path, name];\n\n const fieldData = this.getFieldData(name, expectedType);\n if (isNotNullResourceId(fieldData.error) && (failOnError || isNullResourceId(fieldData.value)))\n await this.tx.throwError(fieldData.error, path);\n\n if (isNullResourceId(fieldData.value)) throw new ContinuePolling();\n\n return await this.tx.get(fieldData.value, failOnError, path);\n }\n\n public async getMulti(\n ops: Partial<PollFieldTraverseOps>,\n ...names: string[]\n ): Promise<PollResourceAccessor[]> {\n return await Promise.all(names.map((name) => this.get(name, ops)));\n }\n\n public async getMultiObj<Key extends string>(\n ops: Partial<PollFieldTraverseOps>,\n ...names: Key[]\n ): Promise<Record<Key, PollResourceAccessor>> {\n return Object.fromEntries(\n await Promise.all(names.map(async (name) => [name, await this.get(name, ops)])),\n );\n }\n\n public async getAllFinal(\n ops: Partial<PollFieldTraverseOps> = {},\n ): Promise<Record<string, PollResourceAccessor>> {\n return await this.getMultiObj(\n ops,\n ...this.data.fields\n .filter((f) => f.valueIsFinal || isNotNullResourceId(f.error))\n .map((f) => f.name),\n );\n }\n\n public async getKValue(key: string): Promise<string> {\n const value = await this.tx.tx.getKValueStringIfExists(this.data.id, key);\n if (value === undefined) throw new ContinuePolling();\n return value;\n }\n\n public async getKValueObj<T>(key: string): Promise<T> {\n return JSON.parse(await this.getKValue(key)) as T;\n }\n}\n\nexport class PollTxAccessor {\n constructor(public readonly tx: PlTransaction) {}\n\n public async get(\n rid: ResourceId,\n failOnError: boolean = true,\n path: string[] = [],\n ): Promise<PollResourceAccessor> {\n const data = await this.tx.getResourceData(rid, true);\n const accessor = new PollResourceAccessor(this, data, [...path, resourceIdToString(rid)]);\n if (failOnError) await accessor.requireNoError();\n return accessor;\n }\n\n async throwError(error: ResourceId, path: string[] = []): Promise<never> {\n const errorRes = await this.get(error);\n const errorText = Buffer.from(notEmpty(errorRes.data.data)).toString();\n throw new Error(`${path.join(\" -> \")} = ${errorText}`);\n }\n}\n\nexport const DefaultPollingRetryOptions: RetryOptions = {\n type: \"linearBackoff\",\n jitter: 0,\n maxAttempts: 100,\n backoffStep: 10,\n initialDelay: 10,\n};\n\nexport async function poll<T>(\n cl: PlClient,\n cb: (tx: PollTxAccessor) => Promise<T>,\n retryOptions: RetryOptions = DefaultPollingRetryOptions,\n txName: string = \"polling\",\n): Promise<T> {\n let retryState = createRetryState(retryOptions);\n while (true) {\n try {\n return await cl.withReadTx(txName, async (tx) => {\n return await cb(new PollTxAccessor(tx));\n });\n } catch (e: any) {\n // Rethrowing any error except the \"not ready yet\"\n if (!(e instanceof ContinuePolling)) throw e;\n }\n await tp.setTimeout(retryState.nextDelay);\n retryState = nextRetryStateOrError(retryState);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
//#region src/helpers/retry_strategy.ts
|
|
3
2
|
const DEFAULT_RETRY_CONFIG = {
|
|
4
3
|
maxAttempts: 10,
|
|
@@ -81,7 +80,7 @@ var ExponentialBackoff = class {
|
|
|
81
80
|
return delay * (1 - this.jitter / 2 + Math.random() * this.jitter);
|
|
82
81
|
}
|
|
83
82
|
};
|
|
84
|
-
|
|
85
83
|
//#endregion
|
|
86
84
|
exports.RetryStrategy = RetryStrategy;
|
|
85
|
+
|
|
87
86
|
//# sourceMappingURL=retry_strategy.cjs.map
|