@procedures/client 0.2.3 → 0.4.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/CHANGELOG.md +94 -0
- package/README.md +77 -44
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/client/transport.d.ts.map +1 -1
- package/dist/adapters/http/client/transport.js +35 -3
- package/dist/adapters/http/client/transport.js.map +1 -1
- package/dist/adapters/http/client/types.d.ts +3 -2
- package/dist/adapters/http/client/types.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.d.ts +2 -2
- package/dist/adapters/http/server/transport.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.js +54 -22
- package/dist/adapters/http/server/transport.js.map +1 -1
- package/dist/adapters/http/shared/headers.d.ts +1 -1
- package/dist/adapters/http/shared/headers.d.ts.map +1 -1
- package/dist/adapters/http/shared/headers.js +7 -6
- package/dist/adapters/http/shared/headers.js.map +1 -1
- package/dist/adapters/local/client/transport.d.ts +3 -0
- package/dist/adapters/local/client/transport.d.ts.map +1 -1
- package/dist/adapters/local/client/transport.js +67 -6
- package/dist/adapters/local/client/transport.js.map +1 -1
- package/dist/adapters/local/client/types.d.ts +15 -0
- package/dist/adapters/local/client/types.d.ts.map +1 -1
- package/dist/adapters/local/client/types.js.map +1 -1
- package/dist/adapters/mock/client/transport.d.ts +3 -2
- package/dist/adapters/mock/client/transport.d.ts.map +1 -1
- package/dist/adapters/mock/client/transport.js +8 -5
- package/dist/adapters/mock/client/transport.js.map +1 -1
- package/dist/adapters/mock/client/types.d.ts +7 -6
- package/dist/adapters/mock/client/types.d.ts.map +1 -1
- package/dist/adapters/port/transport.d.ts +62 -0
- package/dist/adapters/port/transport.d.ts.map +1 -0
- package/dist/adapters/port/transport.js +94 -0
- package/dist/adapters/port/transport.js.map +1 -0
- package/dist/adapters/websocket/client/index.d.ts +1 -1
- package/dist/adapters/websocket/client/index.d.ts.map +1 -1
- package/dist/adapters/websocket/client/index.js.map +1 -1
- package/dist/adapters/websocket/client/node.d.ts +30 -0
- package/dist/adapters/websocket/client/node.d.ts.map +1 -0
- package/dist/adapters/websocket/client/node.js +32 -0
- package/dist/adapters/websocket/client/node.js.map +1 -0
- package/dist/adapters/websocket/client/transport.d.ts +47 -7
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +229 -75
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/client/types.d.ts +71 -21
- package/dist/adapters/websocket/client/types.d.ts.map +1 -1
- package/dist/adapters/websocket/client/types.js.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts +65 -24
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +192 -263
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/server/types.d.ts +20 -1
- package/dist/adapters/websocket/server/types.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.d.ts +129 -0
- package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -0
- package/dist/adapters/websocket/shared/rpc.js +425 -0
- package/dist/adapters/websocket/shared/rpc.js.map +1 -0
- package/dist/browser.d.ts +29 -7
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +26 -3
- package/dist/browser.js.map +1 -1
- package/dist/client/call-types.d.ts +10 -10
- package/dist/client/call-types.d.ts.map +1 -1
- package/dist/client/call-types.js +1 -6
- package/dist/client/call-types.js.map +1 -1
- package/dist/client/client.d.ts +6 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +23 -9
- package/dist/client/client.js.map +1 -1
- package/dist/client/deadline.d.ts +38 -0
- package/dist/client/deadline.d.ts.map +1 -0
- package/dist/client/deadline.js +60 -0
- package/dist/client/deadline.js.map +1 -0
- package/dist/client/errors/factory.d.ts.map +1 -1
- package/dist/client/errors/factory.js +11 -7
- package/dist/client/errors/factory.js.map +1 -1
- package/dist/client/errors/http-errors.d.ts.map +1 -1
- package/dist/client/errors/http-errors.js +6 -0
- package/dist/client/errors/http-errors.js.map +1 -1
- package/dist/client/errors/index.d.ts +1 -1
- package/dist/client/errors/index.js +1 -1
- package/dist/client/errors/registry.d.ts +2 -1
- package/dist/client/errors/registry.d.ts.map +1 -1
- package/dist/client/errors/registry.js +72 -22
- package/dist/client/errors/registry.js.map +1 -1
- package/dist/client/index.d.ts +9 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +8 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/middleware/cache.d.ts +19 -5
- package/dist/client/middleware/cache.d.ts.map +1 -1
- package/dist/client/middleware/cache.js +106 -18
- package/dist/client/middleware/cache.js.map +1 -1
- package/dist/client/middleware/circuit-breaker.d.ts +28 -10
- package/dist/client/middleware/circuit-breaker.d.ts.map +1 -1
- package/dist/client/middleware/circuit-breaker.js +35 -24
- package/dist/client/middleware/circuit-breaker.js.map +1 -1
- package/dist/client/middleware/contexts.d.ts +16 -10
- package/dist/client/middleware/contexts.d.ts.map +1 -1
- package/dist/client/middleware/contexts.js.map +1 -1
- package/dist/client/middleware/items.d.ts +31 -2
- package/dist/client/middleware/items.d.ts.map +1 -1
- package/dist/client/middleware/items.js +86 -6
- package/dist/client/middleware/items.js.map +1 -1
- package/dist/client/middleware/lru.d.ts +2 -0
- package/dist/client/middleware/lru.d.ts.map +1 -1
- package/dist/client/middleware/lru.js +11 -0
- package/dist/client/middleware/lru.js.map +1 -1
- package/dist/client/middleware/rate-limit.d.ts +7 -6
- package/dist/client/middleware/rate-limit.d.ts.map +1 -1
- package/dist/client/middleware/rate-limit.js +9 -7
- package/dist/client/middleware/rate-limit.js.map +1 -1
- package/dist/client/middleware/resilience.d.ts +61 -0
- package/dist/client/middleware/resilience.d.ts.map +1 -0
- package/dist/client/middleware/resilience.js +59 -0
- package/dist/client/middleware/resilience.js.map +1 -0
- package/dist/client/middleware/retry.d.ts +45 -11
- package/dist/client/middleware/retry.d.ts.map +1 -1
- package/dist/client/middleware/retry.js +102 -22
- package/dist/client/middleware/retry.js.map +1 -1
- package/dist/client/middleware/timeout.d.ts +15 -12
- package/dist/client/middleware/timeout.d.ts.map +1 -1
- package/dist/client/middleware/timeout.js +48 -46
- package/dist/client/middleware/timeout.js.map +1 -1
- package/dist/client/middleware/tracing.d.ts.map +1 -1
- package/dist/client/middleware/tracing.js +11 -3
- package/dist/client/middleware/tracing.js.map +1 -1
- package/dist/client/types.d.ts +9 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/types.js.map +1 -1
- package/dist/clock.d.ts +19 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +18 -0
- package/dist/clock.js.map +1 -0
- package/dist/duration.d.ts +37 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +44 -0
- package/dist/duration.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/machines.d.ts +90 -0
- package/dist/machines.d.ts.map +1 -0
- package/dist/machines.js +127 -0
- package/dist/machines.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +10 -0
- package/dist/node.js.map +1 -0
- package/dist/procedures/capability.d.ts +3 -6
- package/dist/procedures/capability.d.ts.map +1 -1
- package/dist/procedures/capability.js +7 -8
- package/dist/procedures/capability.js.map +1 -1
- package/dist/procedures/collection/index.d.ts +3 -3
- package/dist/procedures/collection/index.d.ts.map +1 -1
- package/dist/procedures/collection/index.js +1 -1
- package/dist/procedures/collection/index.js.map +1 -1
- package/dist/procedures/collection/procedures.d.ts.map +1 -1
- package/dist/procedures/collection/procedures.js +49 -1
- package/dist/procedures/collection/procedures.js.map +1 -1
- package/dist/procedures/collection/schemas.d.ts +33 -0
- package/dist/procedures/collection/schemas.d.ts.map +1 -1
- package/dist/procedures/collection/schemas.js +68 -0
- package/dist/procedures/collection/schemas.js.map +1 -1
- package/dist/procedures/collection/storage.d.ts +37 -0
- package/dist/procedures/collection/storage.d.ts.map +1 -1
- package/dist/procedures/core/array.d.ts +1 -1
- package/dist/procedures/core/array.d.ts.map +1 -1
- package/dist/procedures/core/array.js +81 -29
- package/dist/procedures/core/array.js.map +1 -1
- package/dist/procedures/core/index.d.ts.map +1 -1
- package/dist/procedures/core/index.js +17 -2
- package/dist/procedures/core/index.js.map +1 -1
- package/dist/procedures/core/logic.js +1 -1
- package/dist/procedures/core/logic.js.map +1 -1
- package/dist/procedures/core/math.d.ts.map +1 -1
- package/dist/procedures/core/math.js +5 -1
- package/dist/procedures/core/math.js.map +1 -1
- package/dist/procedures/core/meta.d.ts.map +1 -1
- package/dist/procedures/core/meta.js +43 -8
- package/dist/procedures/core/meta.js.map +1 -1
- package/dist/procedures/core/object.d.ts.map +1 -1
- package/dist/procedures/core/object.js +42 -13
- package/dist/procedures/core/object.js.map +1 -1
- package/dist/procedures/core/operands.d.ts.map +1 -1
- package/dist/procedures/core/operands.js +6 -1
- package/dist/procedures/core/operands.js.map +1 -1
- package/dist/procedures/core/string.d.ts.map +1 -1
- package/dist/procedures/core/string.js +4 -2
- package/dist/procedures/core/string.js.map +1 -1
- package/dist/procedures/core/type.d.ts.map +1 -1
- package/dist/procedures/core/type.js +4 -2
- package/dist/procedures/core/type.js.map +1 -1
- package/dist/procedures/define-procedure.d.ts +19 -7
- package/dist/procedures/define-procedure.d.ts.map +1 -1
- package/dist/procedures/define-procedure.js +57 -17
- package/dist/procedures/define-procedure.js.map +1 -1
- package/dist/procedures/discovery.d.ts +4 -6
- package/dist/procedures/discovery.d.ts.map +1 -1
- package/dist/procedures/discovery.js +4 -6
- package/dist/procedures/discovery.js.map +1 -1
- package/dist/procedures/effects.d.ts +16 -0
- package/dist/procedures/effects.d.ts.map +1 -1
- package/dist/procedures/effects.js +33 -0
- package/dist/procedures/effects.js.map +1 -1
- package/dist/procedures/idempotency.d.ts +73 -0
- package/dist/procedures/idempotency.d.ts.map +1 -0
- package/dist/procedures/idempotency.js +131 -0
- package/dist/procedures/idempotency.js.map +1 -0
- package/dist/procedures/index.d.ts +7 -3
- package/dist/procedures/index.d.ts.map +1 -1
- package/dist/procedures/index.js +6 -2
- package/dist/procedures/index.js.map +1 -1
- package/dist/procedures/interceptors.d.ts +17 -4
- package/dist/procedures/interceptors.d.ts.map +1 -1
- package/dist/procedures/interceptors.js +18 -7
- package/dist/procedures/interceptors.js.map +1 -1
- package/dist/procedures/invoke.d.ts +15 -3
- package/dist/procedures/invoke.d.ts.map +1 -1
- package/dist/procedures/invoke.js +8 -3
- package/dist/procedures/invoke.js.map +1 -1
- package/dist/procedures/manifest.d.ts +83 -0
- package/dist/procedures/manifest.d.ts.map +1 -0
- package/dist/procedures/manifest.js +90 -0
- package/dist/procedures/manifest.js.map +1 -0
- package/dist/procedures/ref.d.ts +4 -2
- package/dist/procedures/ref.d.ts.map +1 -1
- package/dist/procedures/ref.js +2 -1
- package/dist/procedures/ref.js.map +1 -1
- package/dist/procedures/runtime-programs.d.ts +19 -0
- package/dist/procedures/runtime-programs.d.ts.map +1 -0
- package/dist/procedures/runtime-programs.js +24 -0
- package/dist/procedures/runtime-programs.js.map +1 -0
- package/dist/procedures/types.d.ts +16 -0
- package/dist/procedures/types.d.ts.map +1 -1
- package/dist/procedures/types.js.map +1 -1
- package/dist/protocol.d.ts +47 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +68 -0
- package/dist/protocol.js.map +1 -0
- package/dist/server/host-policy.d.ts +4 -3
- package/dist/server/host-policy.d.ts.map +1 -1
- package/dist/server/host-policy.js +6 -3
- package/dist/server/host-policy.js.map +1 -1
- package/dist/server/host-procedures.d.ts +31 -0
- package/dist/server/host-procedures.d.ts.map +1 -0
- package/dist/server/host-procedures.js +75 -0
- package/dist/server/host-procedures.js.map +1 -0
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/procedure-server.d.ts +112 -5
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +273 -19
- package/dist/server/procedure-server.js.map +1 -1
- package/dist/server/request-auth.d.ts +19 -0
- package/dist/server/request-auth.d.ts.map +1 -0
- package/dist/server/request-auth.js +32 -0
- package/dist/server/request-auth.js.map +1 -0
- package/dist/server/types.d.ts +32 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/timers.d.ts +60 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +33 -0
- package/dist/timers.js.map +1 -0
- package/dist/tracing/traceparent.d.ts +26 -0
- package/dist/tracing/traceparent.d.ts.map +1 -0
- package/dist/tracing/traceparent.js +53 -0
- package/dist/tracing/traceparent.js.map +1 -0
- package/package.json +11 -4
- package/src/adapters/http/client/transport.ts +31 -3
- package/src/adapters/http/client/types.ts +3 -2
- package/src/adapters/http/server/transport.ts +61 -26
- package/src/adapters/http/shared/headers.ts +7 -6
- package/src/adapters/local/client/transport.ts +74 -7
- package/src/adapters/local/client/types.ts +18 -0
- package/src/adapters/mock/client/transport.ts +9 -6
- package/src/adapters/mock/client/types.ts +7 -6
- package/src/adapters/port/transport.ts +124 -0
- package/src/adapters/websocket/client/index.ts +1 -0
- package/src/adapters/websocket/client/node.ts +34 -0
- package/src/adapters/websocket/client/transport.ts +251 -81
- package/src/adapters/websocket/client/types.ts +81 -21
- package/src/adapters/websocket/server/transport.ts +199 -301
- package/src/adapters/websocket/server/types.ts +20 -1
- package/src/adapters/websocket/shared/rpc.ts +453 -0
- package/src/browser.ts +51 -3
- package/src/client/call-types.ts +10 -14
- package/src/client/client.ts +28 -9
- package/src/client/deadline.ts +64 -0
- package/src/client/errors/README.md +2 -0
- package/src/client/errors/factory.ts +12 -8
- package/src/client/errors/http-errors.ts +5 -0
- package/src/client/errors/index.ts +1 -1
- package/src/client/errors/registry.ts +79 -22
- package/src/client/index.ts +21 -3
- package/src/client/middleware/cache.ts +120 -23
- package/src/client/middleware/circuit-breaker.ts +65 -35
- package/src/client/middleware/contexts.ts +17 -10
- package/src/client/middleware/items.ts +101 -6
- package/src/client/middleware/lru.ts +12 -0
- package/src/client/middleware/rate-limit.ts +9 -9
- package/src/client/middleware/resilience.ts +81 -0
- package/src/client/middleware/retry.ts +146 -34
- package/src/client/middleware/timeout.ts +57 -55
- package/src/client/middleware/tracing.ts +13 -4
- package/src/client/types.ts +9 -1
- package/src/clock.ts +21 -0
- package/src/duration.ts +56 -0
- package/src/index.ts +4 -0
- package/src/machines.ts +186 -0
- package/src/node.ts +11 -0
- package/src/procedures/capability.ts +7 -8
- package/src/procedures/collection/index.ts +9 -1
- package/src/procedures/collection/procedures.ts +57 -0
- package/src/procedures/collection/schemas.ts +110 -0
- package/src/procedures/collection/storage.ts +38 -0
- package/src/procedures/core/array.ts +79 -31
- package/src/procedures/core/index.ts +17 -2
- package/src/procedures/core/logic.ts +1 -1
- package/src/procedures/core/math.ts +5 -1
- package/src/procedures/core/meta.ts +45 -8
- package/src/procedures/core/object.ts +48 -14
- package/src/procedures/core/operands.ts +7 -0
- package/src/procedures/core/string.ts +4 -2
- package/src/procedures/core/type.ts +4 -2
- package/src/procedures/define-procedure.ts +73 -20
- package/src/procedures/discovery.ts +4 -6
- package/src/procedures/effects.ts +35 -0
- package/src/procedures/idempotency.ts +152 -0
- package/src/procedures/index.ts +18 -2
- package/src/procedures/interceptors.ts +28 -11
- package/src/procedures/invoke.ts +19 -5
- package/src/procedures/manifest.ts +158 -0
- package/src/procedures/ref.ts +4 -2
- package/src/procedures/runtime-programs.ts +27 -0
- package/src/procedures/types.ts +16 -0
- package/src/protocol.ts +108 -0
- package/src/server/host-policy.ts +8 -5
- package/src/server/host-procedures.ts +102 -0
- package/src/server/index.ts +5 -2
- package/src/server/procedure-server.ts +328 -12
- package/src/server/request-auth.ts +35 -0
- package/src/server/types.ts +37 -0
- package/src/timers.ts +82 -0
- package/src/tracing/traceparent.ts +61 -0
- package/dist/procedures/cli/announce.d.ts +0 -67
- package/dist/procedures/cli/announce.d.ts.map +0 -1
- package/dist/procedures/cli/announce.js +0 -392
- package/dist/procedures/cli/announce.js.map +0 -1
- package/dist/procedures/cli/discover.d.ts +0 -66
- package/dist/procedures/cli/discover.d.ts.map +0 -1
- package/dist/procedures/cli/discover.js +0 -310
- package/dist/procedures/cli/discover.js.map +0 -1
- package/dist/procedures/cli/index.d.ts +0 -13
- package/dist/procedures/cli/index.d.ts.map +0 -1
- package/dist/procedures/cli/index.js +0 -203
- package/dist/procedures/cli/index.js.map +0 -1
- package/dist/procedures/cli/init.d.ts +0 -17
- package/dist/procedures/cli/init.d.ts.map +0 -1
- package/dist/procedures/cli/init.js +0 -336
- package/dist/procedures/cli/init.js.map +0 -1
- package/src/procedures/cli/announce.ts +0 -470
- package/src/procedures/cli/discover.ts +0 -390
- package/src/procedures/cli/index.ts +0 -231
- package/src/procedures/cli/init.ts +0 -370
|
@@ -95,7 +95,7 @@ export interface HeaderConverter {
|
|
|
95
95
|
* Implements standard conventions for converting metadata to headers:
|
|
96
96
|
* - Auth: Bearer token, API key
|
|
97
97
|
* - Tracing: X-Trace-Id, X-Span-Id format
|
|
98
|
-
* -
|
|
98
|
+
* - The deadline: `procedure-timeout` in X-Metadata (no X-Timeout header)
|
|
99
99
|
* - Custom fields: Pass through as-is
|
|
100
100
|
*/
|
|
101
101
|
export class DefaultHeaderConverter implements HeaderConverter {
|
|
@@ -120,7 +120,10 @@ export class DefaultHeaderConverter implements HeaderConverter {
|
|
|
120
120
|
headers[HTTPHeaders.API_KEY] = metadata.auth.apiKey;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// Distributed Tracing
|
|
123
|
+
// Distributed Tracing: the W3C trace context, and the older headers (roadmap R16)
|
|
124
|
+
if (typeof metadata["traceparent"] === "string") {
|
|
125
|
+
headers["traceparent"] = metadata["traceparent"];
|
|
126
|
+
}
|
|
124
127
|
if (metadata.tracing?.traceId) {
|
|
125
128
|
headers[HTTPHeaders.TRACE_ID] = metadata.tracing.traceId;
|
|
126
129
|
}
|
|
@@ -131,10 +134,8 @@ export class DefaultHeaderConverter implements HeaderConverter {
|
|
|
131
134
|
headers[HTTPHeaders.PARENT_SPAN_ID] = metadata.tracing.parentSpanId;
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
headers[HTTPHeaders.TIMEOUT] = String(metadata.timeout.overall);
|
|
137
|
-
}
|
|
137
|
+
// No X-Timeout: the remaining time of the deadline goes as procedure-timeout in X-Metadata,
|
|
138
|
+
// which the server uses (roadmap R10). The server ignored X-Timeout.
|
|
138
139
|
|
|
139
140
|
const custom: Record<string, unknown> = {};
|
|
140
141
|
for (const [key, value] of Object.entries(metadata)) {
|
|
@@ -9,8 +9,41 @@ import type { Handler, LocalTransportOptions } from "./types.js";
|
|
|
9
9
|
import { methodKey } from "./types.js";
|
|
10
10
|
import type { ProcedureRegistry } from "../../../procedures/registry.js";
|
|
11
11
|
import type { AnyProcedure } from "../../../procedures/types.js";
|
|
12
|
-
import { InvocationError, invokeProcedure, isAsyncIterable } from "../../../procedures/invoke.js";
|
|
12
|
+
import { InvocationError, invokeProcedure, isAsyncIterable, type Interceptor } from "../../../procedures/invoke.js";
|
|
13
|
+
import { TIMEOUT_METADATA_KEY } from "../../../client/deadline.js";
|
|
14
|
+
import { narrowCapability } from "../../../procedures/capability.js";
|
|
15
|
+
import type { Capability, ClearanceOrder } from "../../../procedures/types.js";
|
|
13
16
|
import { methodToPath } from "../../../server/method.js";
|
|
17
|
+
import { errorCodeOf } from "../../../protocol.js";
|
|
18
|
+
|
|
19
|
+
/** The value of `untilAborted` when the signal aborts first. */
|
|
20
|
+
const ABORTED: unique symbol = Symbol("aborted");
|
|
21
|
+
|
|
22
|
+
/** The value of a promise, or ABORTED when the signal aborts first. The promise runs on. */
|
|
23
|
+
function untilAborted<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T | typeof ABORTED> {
|
|
24
|
+
if (!signal) return promise;
|
|
25
|
+
if (signal.aborted) {
|
|
26
|
+
promise.catch(() => undefined);
|
|
27
|
+
return Promise.resolve(ABORTED);
|
|
28
|
+
}
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const onAbort = (): void => {
|
|
31
|
+
promise.catch(() => undefined);
|
|
32
|
+
resolve(ABORTED);
|
|
33
|
+
};
|
|
34
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
35
|
+
promise.then(
|
|
36
|
+
(value) => {
|
|
37
|
+
signal.removeEventListener("abort", onAbort);
|
|
38
|
+
resolve(value);
|
|
39
|
+
},
|
|
40
|
+
(error: unknown) => {
|
|
41
|
+
signal.removeEventListener("abort", onAbort);
|
|
42
|
+
reject(error);
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
14
47
|
|
|
15
48
|
function successItem<TRes>(id: string, payload: unknown): ResponseItem<TRes> {
|
|
16
49
|
return { id, status: { type: "success", code: 200 }, payload: payload as TRes, metadata: {} };
|
|
@@ -53,10 +86,16 @@ export class LocalTransport implements Transport {
|
|
|
53
86
|
private readonly handlers = new Map<string, Handler>();
|
|
54
87
|
private readonly throwOnMissing: boolean;
|
|
55
88
|
private readonly registry: ProcedureRegistry | undefined;
|
|
89
|
+
private readonly interceptors: readonly Interceptor[] | undefined;
|
|
90
|
+
private readonly capability: Capability | undefined;
|
|
91
|
+
private readonly clearanceOrder: ClearanceOrder | undefined;
|
|
56
92
|
|
|
57
93
|
constructor(options: LocalTransportOptions = {}) {
|
|
58
94
|
this.throwOnMissing = options.throwOnMissing !== false;
|
|
59
95
|
this.registry = options.registry;
|
|
96
|
+
this.interceptors = options.interceptors;
|
|
97
|
+
this.capability = options.capability;
|
|
98
|
+
this.clearanceOrder = options.clearanceOrder;
|
|
60
99
|
|
|
61
100
|
// Register pre-configured handlers. A key without a version ("users.get") gets the
|
|
62
101
|
// empty version, as methodKey() makes it: before, such a key was never found.
|
|
@@ -136,21 +175,44 @@ export class LocalTransport implements Transport {
|
|
|
136
175
|
let values: AsyncIterable<unknown> | undefined;
|
|
137
176
|
let value: unknown;
|
|
138
177
|
if (procedure) {
|
|
139
|
-
|
|
178
|
+
// The interceptors, the capability and the deadline of the call, as on a server (R14)
|
|
179
|
+
const timeoutMs = message.metadata[TIMEOUT_METADATA_KEY];
|
|
180
|
+
const capability =
|
|
181
|
+
typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs >= 0
|
|
182
|
+
? narrowCapability(this.capability, { timeoutMs }, this.clearanceOrder)
|
|
183
|
+
: this.capability;
|
|
184
|
+
const output = await untilAborted(invokeProcedure(procedure, message.payload, {
|
|
140
185
|
registry: this.registry,
|
|
141
186
|
metadata: message.metadata,
|
|
142
187
|
signal: message.signal,
|
|
143
|
-
|
|
188
|
+
...(this.interceptors ? { interceptors: this.interceptors } : {}),
|
|
189
|
+
...(capability ? { capability } : {}),
|
|
190
|
+
...(this.clearanceOrder ? { clearanceOrder: this.clearanceOrder } : {}),
|
|
191
|
+
}), message.signal);
|
|
192
|
+
if (output === ABORTED) {
|
|
193
|
+
// The caller stops waiting at once, as over HTTP and WebSocket (the conformance suite
|
|
194
|
+
// of roadmap R18 found this: before, a local call waited for its handler)
|
|
195
|
+
yield errorItem<TRes>(message.id, "ABORTED", "Request was aborted");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
144
198
|
if (output.kind === "stream") values = output.items;
|
|
145
199
|
else value = output.value;
|
|
146
200
|
} else {
|
|
147
201
|
// Execute handler (may be sync, async or an async generator)
|
|
148
|
-
const result = await handler!(message.payload, message);
|
|
202
|
+
const result = await untilAborted(Promise.resolve(handler!(message.payload, message)), message.signal);
|
|
203
|
+
if (result === ABORTED) {
|
|
204
|
+
yield errorItem<TRes>(message.id, "ABORTED", "Request was aborted");
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
149
207
|
if (isAsyncIterable(result)) values = result;
|
|
150
208
|
else value = result;
|
|
151
209
|
}
|
|
152
210
|
|
|
153
211
|
if (values === undefined) {
|
|
212
|
+
if (message.signal?.aborted) {
|
|
213
|
+
yield errorItem<TRes>(message.id, "ABORTED", "Request was aborted");
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
154
216
|
yield successItem<TRes>(message.id, value);
|
|
155
217
|
return;
|
|
156
218
|
}
|
|
@@ -162,9 +224,13 @@ export class LocalTransport implements Transport {
|
|
|
162
224
|
yield successItem<TRes>(message.id, item);
|
|
163
225
|
}
|
|
164
226
|
} catch (error) {
|
|
165
|
-
// The handler threw, or the invocation failed (its code: VALIDATION_ERROR, ABORTED and so
|
|
166
|
-
|
|
167
|
-
|
|
227
|
+
// The handler threw, or the invocation failed (its code: VALIDATION_ERROR, ABORTED and so
|
|
228
|
+
// on). A handler error keeps its own code, as on the other faces (WIRE-PROTOCOL.md).
|
|
229
|
+
const code = errorCodeOf(error);
|
|
230
|
+
const item = errorItem<TRes>(message.id, code, error instanceof Error ? error.message : "Unknown error");
|
|
231
|
+
// The reason of a FORBIDDEN error travels on each face (roadmap R25)
|
|
232
|
+
if (error instanceof InvocationError && error.reason) item.metadata = { reason: error.reason };
|
|
233
|
+
yield item;
|
|
168
234
|
}
|
|
169
235
|
}
|
|
170
236
|
|
|
@@ -172,6 +238,7 @@ export class LocalTransport implements Transport {
|
|
|
172
238
|
// No resources to clean up
|
|
173
239
|
}
|
|
174
240
|
|
|
241
|
+
|
|
175
242
|
/**
|
|
176
243
|
* Clear all handlers.
|
|
177
244
|
*/
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import type { Message, Method } from "../../../client/types.js";
|
|
8
8
|
import type { ProcedureRegistry } from "../../../procedures/registry.js";
|
|
9
|
+
import type { Interceptor } from "../../../procedures/invoke.js";
|
|
10
|
+
import type { Capability, ClearanceOrder } from "../../../procedures/types.js";
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Handler function for a method.
|
|
@@ -47,4 +49,20 @@ export interface LocalTransportOptions {
|
|
|
47
49
|
* The procedure runs through `invokeProcedure()`, as on a server.
|
|
48
50
|
*/
|
|
49
51
|
registry?: ProcedureRegistry;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The interceptors of each procedure that the transport runs, as on a server: policy, tracing,
|
|
55
|
+
* timeouts, metrics (roadmap R14). Before, a local call had none.
|
|
56
|
+
*/
|
|
57
|
+
interceptors?: readonly Interceptor[] | undefined;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The capability of each call. The remaining time that a call sends (`procedure-timeout`)
|
|
61
|
+
* makes its deadline earlier, as on a server: a `Client` with a timeout gives a local call a
|
|
62
|
+
* deadline too (roadmap R14).
|
|
63
|
+
*/
|
|
64
|
+
capability?: Capability | undefined;
|
|
65
|
+
|
|
66
|
+
/** The order of the clearance values of the capability. */
|
|
67
|
+
clearanceOrder?: ClearanceOrder | undefined;
|
|
50
68
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
MockTransportOptions,
|
|
12
12
|
CallHistoryEntry,
|
|
13
13
|
} from "./types.js";
|
|
14
|
+
import { optionalMs } from "../../../duration.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Mock transport implementation for testing.
|
|
@@ -26,8 +27,8 @@ import type {
|
|
|
26
27
|
* ```typescript
|
|
27
28
|
* // Create mock transport with latency
|
|
28
29
|
* const mock = new MockTransport({
|
|
29
|
-
* minLatency: 10,
|
|
30
|
-
* maxLatency: 50,
|
|
30
|
+
* minLatency: ms(10),
|
|
31
|
+
* maxLatency: ms(50),
|
|
31
32
|
* });
|
|
32
33
|
*
|
|
33
34
|
* // Mock a specific response
|
|
@@ -57,14 +58,15 @@ import type {
|
|
|
57
58
|
export class MockTransport implements Transport {
|
|
58
59
|
readonly name = "mock";
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
/** The options, with the latencies in milliseconds */
|
|
62
|
+
private options: Required<Omit<MockTransportOptions, "minLatency" | "maxLatency">> & { minLatency: number; maxLatency: number };
|
|
61
63
|
private responses = new Map<ResponseMatcher, MockResponse>();
|
|
62
64
|
private history: CallHistoryEntry[] = [];
|
|
63
65
|
|
|
64
66
|
constructor(options: MockTransportOptions = {}) {
|
|
65
67
|
this.options = {
|
|
66
|
-
minLatency: options.minLatency ?? 0,
|
|
67
|
-
maxLatency: options.maxLatency ?? 0,
|
|
68
|
+
minLatency: optionalMs(options.minLatency, "minLatency") ?? 0,
|
|
69
|
+
maxLatency: optionalMs(options.maxLatency, "maxLatency") ?? 0,
|
|
68
70
|
failureRate: options.failureRate ?? 0,
|
|
69
71
|
defaultErrorMessage: options.defaultErrorMessage ?? "Mock transport error",
|
|
70
72
|
trackHistory: options.trackHistory ?? true,
|
|
@@ -247,7 +249,8 @@ export class MockTransport implements Transport {
|
|
|
247
249
|
|
|
248
250
|
// Apply custom delay if specified
|
|
249
251
|
if (mockResponse.delay !== undefined) {
|
|
250
|
-
|
|
252
|
+
const delay = optionalMs(mockResponse.delay, "delay");
|
|
253
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
251
254
|
}
|
|
252
255
|
|
|
253
256
|
// Handle error response
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { Message, ResponseItem } from "../../../client/types.js";
|
|
8
|
+
import type { Duration } from "../../../duration.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Mock response configuration.
|
|
@@ -26,10 +27,10 @@ export interface MockResponse<TRes = unknown> {
|
|
|
26
27
|
error?: Error;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
|
-
* Delay
|
|
30
|
+
* Delay before responding
|
|
30
31
|
* @default Uses transport's latency config
|
|
31
32
|
*/
|
|
32
|
-
delay?:
|
|
33
|
+
delay?: Duration;
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Number of times this response can be used
|
|
@@ -48,16 +49,16 @@ export type ResponseMatcher = (method: any, payload: unknown) => boolean;
|
|
|
48
49
|
*/
|
|
49
50
|
export interface MockTransportOptions {
|
|
50
51
|
/**
|
|
51
|
-
* Minimum latency
|
|
52
|
+
* Minimum latency
|
|
52
53
|
* @default 0
|
|
53
54
|
*/
|
|
54
|
-
minLatency?:
|
|
55
|
+
minLatency?: Duration;
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
* Maximum latency
|
|
58
|
+
* Maximum latency
|
|
58
59
|
* @default 0
|
|
59
60
|
*/
|
|
60
|
-
maxLatency?:
|
|
61
|
+
maxLatency?: Duration;
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
64
|
* Random failure rate (0-1)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transport over a message port (roadmap R27): a Web Worker, a `MessagePort` of a
|
|
3
|
+
* `MessageChannel`, an iframe, or a `worker_threads` port of Node.
|
|
4
|
+
*
|
|
5
|
+
* The two sides of a port send calls to each other with the frames of the WebSocket transport
|
|
6
|
+
* (`websocket/shared/rpc.ts`): a request, then a response, an error, or a stream with credit, and
|
|
7
|
+
* a cancel. A port sends objects, not text, so a frame needs no JSON. A side serves the calls of
|
|
8
|
+
* the other side with its `serve` handler, for example a `ProcedureServer`. Before, the site had
|
|
9
|
+
* two worker protocols of its own.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // In the worker: serve the procedures of a registry
|
|
14
|
+
* new PortTransport(self, { serve: new ProcedureServer({ registry, autoRegister: true }) });
|
|
15
|
+
*
|
|
16
|
+
* // On the page: call them
|
|
17
|
+
* const client = new Client(new PortTransport(new Worker(url, { type: "module" })));
|
|
18
|
+
* for await (const item of client.stream({ service: "site", operation: "run" }, input)) { ... }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { Message, ResponseItem, Transport } from "../../client/types.js";
|
|
23
|
+
import type { RequestHandler } from "../../server/types.js";
|
|
24
|
+
import type { WebSocketMessage } from "../websocket/server/types.js";
|
|
25
|
+
import { IncomingCalls, OutgoingCalls } from "../websocket/shared/rpc.js";
|
|
26
|
+
import { withoutInternalKeys } from "../metadata.js";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A message port: the object that a worker, a `MessagePort` or a `worker_threads` port gives. It
|
|
30
|
+
* has `postMessage`, and `addEventListener` (the browser form) or `on` (the Node form).
|
|
31
|
+
*
|
|
32
|
+
* The event of a listener has the type `any`: the DOM and Node give it different types, and a
|
|
33
|
+
* port of each must fit without a cast. The transport reads only its `data`.
|
|
34
|
+
*/
|
|
35
|
+
export interface PortLike {
|
|
36
|
+
postMessage(message: unknown): void;
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
addEventListener?(type: "message", listener: (event: any) => void): void;
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
removeEventListener?(type: "message", listener: (event: any) => void): void;
|
|
41
|
+
on?(type: "message", listener: (data: unknown) => void): unknown;
|
|
42
|
+
off?(type: "message", listener: (data: unknown) => void): unknown;
|
|
43
|
+
/** A `MessagePort` delivers its messages to `addEventListener` only after `start()`. */
|
|
44
|
+
start?(): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The options of a `PortTransport`. */
|
|
48
|
+
export interface PortTransportOptions {
|
|
49
|
+
/** The handler of the calls of the other side, for example a `ProcedureServer`. */
|
|
50
|
+
serve?: RequestHandler | undefined;
|
|
51
|
+
/** The number of stream items that the reader holds. The default is 64. */
|
|
52
|
+
streamWindow?: number | undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A frame of the protocol: an object with an id and a type. */
|
|
56
|
+
function isFrame(value: unknown): value is WebSocketMessage {
|
|
57
|
+
return value !== null && typeof value === "object" && typeof (value as { type?: unknown }).type === "string";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The transport over a message port, in the two directions. */
|
|
61
|
+
export class PortTransport implements Transport {
|
|
62
|
+
readonly name = "port";
|
|
63
|
+
private readonly outgoing: OutgoingCalls;
|
|
64
|
+
private readonly incoming: IncomingCalls | undefined;
|
|
65
|
+
private open = true;
|
|
66
|
+
private readonly onBrowserMessage = (event: { data: unknown }): void => this.receive(event.data);
|
|
67
|
+
private readonly onNodeMessage = (data: unknown): void => this.receive(data);
|
|
68
|
+
|
|
69
|
+
constructor(
|
|
70
|
+
private readonly port: PortLike,
|
|
71
|
+
options: PortTransportOptions = {},
|
|
72
|
+
) {
|
|
73
|
+
const send = (frame: WebSocketMessage): void => this.port.postMessage(frame);
|
|
74
|
+
const isOpen = (): boolean => this.open;
|
|
75
|
+
this.outgoing = new OutgoingCalls({
|
|
76
|
+
send,
|
|
77
|
+
isOpen,
|
|
78
|
+
// No time limit: a worker can run a long program. The `signal` of a call stops it. This file
|
|
79
|
+
// does not import the Durations (quantity, 6 kB of gzip), so the page of a worker stays small.
|
|
80
|
+
requestTimeoutMs: 0,
|
|
81
|
+
streamWindow: Math.max(2, options.streamWindow ?? 64),
|
|
82
|
+
idPrefix: "",
|
|
83
|
+
});
|
|
84
|
+
if (options.serve) {
|
|
85
|
+
this.incoming = new IncomingCalls({
|
|
86
|
+
handler: options.serve,
|
|
87
|
+
send,
|
|
88
|
+
isOpen,
|
|
89
|
+
// A call over a port comes from a part of this application: it has no credentials
|
|
90
|
+
requestOf: (frame, signal) => ({
|
|
91
|
+
id: frame.id,
|
|
92
|
+
method: frame.method!,
|
|
93
|
+
payload: frame.payload === undefined ? {} : frame.payload,
|
|
94
|
+
metadata: withoutInternalKeys(frame.metadata),
|
|
95
|
+
signal,
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (port.addEventListener) port.addEventListener("message", this.onBrowserMessage);
|
|
100
|
+
else port.on?.("message", this.onNodeMessage);
|
|
101
|
+
port.start?.();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private receive(data: unknown): void {
|
|
105
|
+
if (!this.open || !isFrame(data)) return;
|
|
106
|
+
if (this.outgoing.receive(data)) return;
|
|
107
|
+
this.incoming?.receive(data);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** This function sends a call to the other side, and gives its response items. */
|
|
111
|
+
send<TReq, TRes>(message: Message<TReq>): AsyncIterable<ResponseItem<TRes>> {
|
|
112
|
+
return this.outgoing.call<TReq, TRes>(message);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** This function stops the calls in the two directions, and stops to listen. It does not close the port. */
|
|
116
|
+
async close(): Promise<void> {
|
|
117
|
+
if (!this.open) return;
|
|
118
|
+
this.open = false;
|
|
119
|
+
this.outgoing.failAll("The port transport closed");
|
|
120
|
+
this.incoming?.abortAll();
|
|
121
|
+
if (this.port.removeEventListener) this.port.removeEventListener("message", this.onBrowserMessage);
|
|
122
|
+
else this.port.off?.("message", this.onNodeMessage);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WebSocket client transport for Node (finding of roadmap R36).
|
|
3
|
+
*
|
|
4
|
+
* This class is the `WebSocketTransport` of the browser entry with one other default: its sockets
|
|
5
|
+
* are of the `WebSocket` class of the `ws` package. A drop by the heartbeat or by the time limit
|
|
6
|
+
* of the handshake then ends the socket at once with `terminate()`. The global `WebSocket` of Node
|
|
7
|
+
* has only `close()`, which waits for the answer of the peer. With a dead peer, that socket stays
|
|
8
|
+
* open until the kernel stops it: 924.6 seconds in the harness cells of R36.
|
|
9
|
+
*
|
|
10
|
+
* Only the Node entry `@procedures/client/node` exports this class. The browser entry does not
|
|
11
|
+
* import `ws`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { WebSocket as NodeWebSocket } from "ws";
|
|
15
|
+
import { WebSocketTransport as PortableWebSocketTransport } from "./transport.js";
|
|
16
|
+
import type { WebSocketTransportOptions } from "./types.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The WebSocket client transport with the `WebSocket` class of the `ws` package as the default
|
|
20
|
+
* class of its sockets. The option `webSocket` gives another class.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { Client } from "@procedures/client";
|
|
25
|
+
* import { WebSocketTransport } from "@procedures/client/node";
|
|
26
|
+
*
|
|
27
|
+
* const client = new Client({ transport: new WebSocketTransport({ url: "ws://localhost:3000/ws" }) });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class WebSocketTransport extends PortableWebSocketTransport {
|
|
31
|
+
constructor(options: WebSocketTransportOptions) {
|
|
32
|
+
super({ ...options, webSocket: options.webSocket ?? NodeWebSocket });
|
|
33
|
+
}
|
|
34
|
+
}
|