@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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credentials of a network request (roadmap R18). A server transport reads them into
|
|
3
|
+
* `ServerRequest.credentials`, and leaves the secret headers out of the metadata, so a handler
|
|
4
|
+
* and a nested call do not see them. `ProcedureServer` examines them.
|
|
5
|
+
*/
|
|
6
|
+
/** The headers that carry a secret. They do not go into the metadata of a request. */
|
|
7
|
+
const SECRET_HEADERS = new Set(["authorization", "proxy-authorization", "cookie", "x-api-key"]);
|
|
8
|
+
/** The headers without the secret ones, and without the headers that are not text. */
|
|
9
|
+
export function withoutSecretHeaders(headers) {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
12
|
+
if (!SECRET_HEADERS.has(key.toLowerCase()) && typeof value === "string")
|
|
13
|
+
out[key] = value;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
/** The token of an `Authorization: Bearer <token>` header, or undefined. */
|
|
18
|
+
export function bearerOf(header) {
|
|
19
|
+
return typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length) : undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The credentials of a request or of a WebSocket upgrade: the bearer token of its
|
|
23
|
+
* `Authorization` header, or else of its `token` query (a browser WebSocket cannot set headers).
|
|
24
|
+
*/
|
|
25
|
+
export function credentialsOf(request) {
|
|
26
|
+
const bearer = bearerOf(request.headers["authorization"]);
|
|
27
|
+
if (bearer !== undefined)
|
|
28
|
+
return { bearer };
|
|
29
|
+
const query = new URL(request.url ?? "/", "http://localhost").searchParams.get("token");
|
|
30
|
+
return query === null ? {} : { bearer: query };
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=request-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-auth.js","sourceRoot":"","sources":["../../src/server/request-auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,sFAAsF;AACtF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,qBAAqB,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAEhG,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,OAAgC;IACnE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,QAAQ,CAAC,MAAe;IACtC,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAuE;IACnG,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxF,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjD,CAAC"}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -21,6 +21,38 @@ export interface ServerRequest<TReq = unknown> {
|
|
|
21
21
|
metadata: Metadata;
|
|
22
22
|
/** Abort signal for cancellation */
|
|
23
23
|
signal?: AbortSignal;
|
|
24
|
+
/**
|
|
25
|
+
* The credentials that a network transport read from the request: the bearer token of an
|
|
26
|
+
* `Authorization` header, or of the `token` query of a WebSocket connection (roadmap R18). They
|
|
27
|
+
* are not in the metadata, so a handler and a nested call do not see them. A request without
|
|
28
|
+
* credentials comes from this process (a direct `handle()`, MCP over stdio).
|
|
29
|
+
*/
|
|
30
|
+
credentials?: Credentials | undefined;
|
|
31
|
+
/** The principal of the request: who sends it. `ProcedureServer` sets it when it authenticates the request. */
|
|
32
|
+
principal?: Principal | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** The credentials of a request. */
|
|
35
|
+
export interface Credentials {
|
|
36
|
+
/** The bearer token that the request presents. */
|
|
37
|
+
readonly bearer?: string | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Who sends a request (roadmap R18). */
|
|
40
|
+
export interface Principal {
|
|
41
|
+
/** The id of the principal. With the token of a host: "token". */
|
|
42
|
+
readonly id: string;
|
|
43
|
+
/** How the server authenticated it: "token", or the name of an authenticate function. */
|
|
44
|
+
readonly via: string;
|
|
45
|
+
/** More facts about the principal, from an authenticate function. */
|
|
46
|
+
readonly claims?: Readonly<Record<string, unknown>> | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The contract of a server transport (roadmap R18): a transport turns each protocol request
|
|
50
|
+
* into a `ServerRequest` (with its signal and its credentials), gives it to `handle()`, and turns
|
|
51
|
+
* the `ServerResponse` back (a value, a stream or an error). `Server` and `ProcedureServer`
|
|
52
|
+
* satisfy it, and a test can give a function.
|
|
53
|
+
*/
|
|
54
|
+
export interface RequestHandler {
|
|
55
|
+
handle(request: ServerRequest): Promise<ServerResponse>;
|
|
24
56
|
}
|
|
25
57
|
/**
|
|
26
58
|
* Server response in unified RPC format.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGnE,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,OAAO,EAAE,IAAI,CAAC;IAEd,qDAAqD;IACrD,QAAQ,EAAE,QAAQ,CAAC;IAEnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGnE,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,OAAO,EAAE,IAAI,CAAC;IAEd,qDAAqD;IACrD,QAAQ,EAAE,QAAQ,CAAC;IAEnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAEtC,+GAA+G;IAC/G,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACnC;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACzD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,OAAO;IAC5C,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IAEX,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,wBAAwB;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC1D,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,2BAA2B;IAC3B,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CACzD,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC7D,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAC3B,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAE9B;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAM,EAAE,MAAM,EAOzB;CACF;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;IAHpC,YACE,OAAO,EAAE,MAAM,EACC,IAAI,GAAE,MAAc,EACpB,SAAS,GAAE,OAAe,EAI3C;CACF"}
|
package/dist/server/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwJH;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAc;QACxB,KAAK,CACH,wBAAwB,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,SAAS,GACxD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAC7C,EAAE,CACH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAGlB,IAAI;IACJ,SAAS;IAH3B,YACE,OAAe,EACC,IAAI,GAAW,KAAK,EACpB,SAAS,GAAY,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;oBAHC,IAAI;yBACJ,SAAS;QAGzB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
|
package/dist/timers.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The timer settings of the core, as data (roadmap R34).
|
|
3
|
+
*
|
|
4
|
+
* Each default time of the middleware, the transports and the server comes from this object, so
|
|
5
|
+
* a tool can read the settings without a call. `@procedures/systems` binds them to the symbols of
|
|
6
|
+
* the timer law of `systems`, and examines rules such as "the time of one try is less than the
|
|
7
|
+
* request time of the WebSocket". The values are milliseconds. The options of an application
|
|
8
|
+
* are Durations (roadmap R11), and they replace these values.
|
|
9
|
+
*/
|
|
10
|
+
/** The default times of the core, in milliseconds. */
|
|
11
|
+
export interface TimerDefaults {
|
|
12
|
+
readonly retry: {
|
|
13
|
+
/** The tries after the first one. */
|
|
14
|
+
readonly maxRetries: number;
|
|
15
|
+
readonly retryDelayMs: number;
|
|
16
|
+
readonly backoffMultiplier: number;
|
|
17
|
+
/** The longest backoff. Infinity: no limit. */
|
|
18
|
+
readonly maxDelayMs: number;
|
|
19
|
+
};
|
|
20
|
+
readonly circuitBreaker: {
|
|
21
|
+
readonly failureWindowMs: number;
|
|
22
|
+
readonly resetTimeoutMs: number;
|
|
23
|
+
};
|
|
24
|
+
readonly cache: {
|
|
25
|
+
readonly ttlMs: number;
|
|
26
|
+
readonly statsIntervalMs: number;
|
|
27
|
+
};
|
|
28
|
+
readonly rateLimit: {
|
|
29
|
+
readonly windowMs: number;
|
|
30
|
+
};
|
|
31
|
+
readonly webSocketClient: {
|
|
32
|
+
/** The time of the handshake. */
|
|
33
|
+
readonly connectionTimeoutMs: number;
|
|
34
|
+
/** The time until the first frame of a call. */
|
|
35
|
+
readonly requestTimeoutMs: number;
|
|
36
|
+
readonly heartbeatIntervalMs: number;
|
|
37
|
+
readonly heartbeatTimeoutMs: number;
|
|
38
|
+
/** The pongs that can go missing, one after the other, before the connection closes. */
|
|
39
|
+
readonly heartbeatMisses: number;
|
|
40
|
+
readonly reconnectInitialDelayMs: number;
|
|
41
|
+
readonly reconnectMaxDelayMs: number;
|
|
42
|
+
};
|
|
43
|
+
readonly webSocketServer: {
|
|
44
|
+
readonly heartbeatIntervalMs: number;
|
|
45
|
+
readonly heartbeatMisses: number;
|
|
46
|
+
/** The time until the first frame of a call of the server to a client. */
|
|
47
|
+
readonly reverseRequestTimeoutMs: number;
|
|
48
|
+
};
|
|
49
|
+
readonly idempotency: {
|
|
50
|
+
/** The time that the server keeps the result of a keyed write. */
|
|
51
|
+
readonly ttlMs: number;
|
|
52
|
+
};
|
|
53
|
+
readonly server: {
|
|
54
|
+
/** The time that `ProcedureServer.stop()` waits for the calls that run. */
|
|
55
|
+
readonly stopGraceMs: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** The default times of the core. The middleware, the transports and the server read them. */
|
|
59
|
+
export declare const TIMER_DEFAULTS: TimerDefaults;
|
|
60
|
+
//# sourceMappingURL=timers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE;QACd,qCAAqC;QACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;QACnC,+CAA+C;QAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,QAAQ,CAAC,cAAc,EAAE;QACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,eAAe,EAAE;QACxB,iCAAiC;QACjC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,gDAAgD;QAChD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,wFAAwF;QACxF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;QACzC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;KACtC,CAAC;IACF,QAAQ,CAAC,eAAe,EAAE;QACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,0EAA0E;QAC1E,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;KAC1C,CAAC;IACF,QAAQ,CAAC,WAAW,EAAE;QACpB,kEAAkE;QAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE;QACf,2EAA2E;QAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH;AAED,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,aAqB3B,CAAC"}
|
package/dist/timers.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The timer settings of the core, as data (roadmap R34).
|
|
3
|
+
*
|
|
4
|
+
* Each default time of the middleware, the transports and the server comes from this object, so
|
|
5
|
+
* a tool can read the settings without a call. `@procedures/systems` binds them to the symbols of
|
|
6
|
+
* the timer law of `systems`, and examines rules such as "the time of one try is less than the
|
|
7
|
+
* request time of the WebSocket". The values are milliseconds. The options of an application
|
|
8
|
+
* are Durations (roadmap R11), and they replace these values.
|
|
9
|
+
*/
|
|
10
|
+
/** The default times of the core. The middleware, the transports and the server read them. */
|
|
11
|
+
export const TIMER_DEFAULTS = Object.freeze({
|
|
12
|
+
retry: Object.freeze({ maxRetries: 3, retryDelayMs: 1000, backoffMultiplier: 2, maxDelayMs: Number.POSITIVE_INFINITY }),
|
|
13
|
+
circuitBreaker: Object.freeze({ failureWindowMs: 10_000, resetTimeoutMs: 30_000 }),
|
|
14
|
+
cache: Object.freeze({ ttlMs: 60_000, statsIntervalMs: 60_000 }),
|
|
15
|
+
rateLimit: Object.freeze({ windowMs: 60_000 }),
|
|
16
|
+
webSocketClient: Object.freeze({
|
|
17
|
+
connectionTimeoutMs: 10_000,
|
|
18
|
+
requestTimeoutMs: 30_000,
|
|
19
|
+
// 20 s: with the pong timeout of 5 s, the client finds a dead connection after 25 s, before a
|
|
20
|
+
// call on it reaches the request time of 30 s. Before, 30 s gave 35 s (the timer law, R34).
|
|
21
|
+
heartbeatIntervalMs: 20_000,
|
|
22
|
+
heartbeatTimeoutMs: 5_000,
|
|
23
|
+
heartbeatMisses: 1,
|
|
24
|
+
reconnectInitialDelayMs: 1_000,
|
|
25
|
+
reconnectMaxDelayMs: 30_000,
|
|
26
|
+
}),
|
|
27
|
+
// 15 s: with 2 misses, the server finds a dead client after 30 s, not later than a call of the
|
|
28
|
+
// server to it reaches its request time of 30 s. Before, 30 s gave 60 s (the timer law, R34).
|
|
29
|
+
webSocketServer: Object.freeze({ heartbeatIntervalMs: 15_000, heartbeatMisses: 2, reverseRequestTimeoutMs: 30_000 }),
|
|
30
|
+
idempotency: Object.freeze({ ttlMs: 10 * 60_000 }),
|
|
31
|
+
server: Object.freeze({ stopGraceMs: 0 }),
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=timers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timers.js","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmDH,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAkB,MAAM,CAAC,MAAM,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC;IACvH,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;IAChE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC9C,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC;QAC7B,mBAAmB,EAAE,MAAM;QAC3B,gBAAgB,EAAE,MAAM;QACxB,8FAA8F;QAC9F,4FAA4F;QAC5F,mBAAmB,EAAE,MAAM;QAC3B,kBAAkB,EAAE,KAAK;QACzB,eAAe,EAAE,CAAC;QAClB,uBAAuB,EAAE,KAAK;QAC9B,mBAAmB,EAAE,MAAM;KAC5B,CAAC;IACF,+FAA+F;IAC/F,8FAA8F;IAC9F,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,mBAAmB,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC;IACpH,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;CAC1C,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The W3C trace context (roadmap R16): `traceparent` is `00-<trace id>-<span id>-<flags>`, with a
|
|
3
|
+
* trace id of 32 hex digits and a span id of 16. The tracing middleware of a client sends it in
|
|
4
|
+
* the metadata of a call (and HTTP as the `traceparent` header). The tracing interceptor of a
|
|
5
|
+
* server continues that trace, and gives it to the nested calls, so one trace goes from the
|
|
6
|
+
* client to the last handler. Before, the client and the server made two traces.
|
|
7
|
+
*/
|
|
8
|
+
/** The metadata key of the W3C trace context of a call. */
|
|
9
|
+
export declare const TRACEPARENT_METADATA_KEY = "traceparent";
|
|
10
|
+
/** A trace context: the trace, the span of the caller, and the sampled flag. */
|
|
11
|
+
export interface TraceContext {
|
|
12
|
+
readonly traceId: string;
|
|
13
|
+
readonly spanId: string;
|
|
14
|
+
readonly sampled: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** This function makes a new trace id: 32 random hex digits. */
|
|
17
|
+
export declare function newTraceId(): string;
|
|
18
|
+
/** This function makes a new span id: 16 random hex digits. */
|
|
19
|
+
export declare function newSpanId(): string;
|
|
20
|
+
/** True when the ids have the W3C form. */
|
|
21
|
+
export declare function isW3cIds(traceId: string, spanId: string): boolean;
|
|
22
|
+
/** The `traceparent` of a trace and a span. */
|
|
23
|
+
export declare function formatTraceparent(traceId: string, spanId: string, sampled?: boolean): string;
|
|
24
|
+
/** The trace context of a `traceparent` value, or undefined when it is not valid. */
|
|
25
|
+
export declare function parseTraceparent(value: unknown): TraceContext | undefined;
|
|
26
|
+
//# sourceMappingURL=traceparent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceparent.d.ts","sourceRoot":"","sources":["../../src/tracing/traceparent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAMtD,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAUD,gEAAgE;AAChE,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAED,2CAA2C;AAC3C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,MAAM,CAEzF;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAOzE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The W3C trace context (roadmap R16): `traceparent` is `00-<trace id>-<span id>-<flags>`, with a
|
|
3
|
+
* trace id of 32 hex digits and a span id of 16. The tracing middleware of a client sends it in
|
|
4
|
+
* the metadata of a call (and HTTP as the `traceparent` header). The tracing interceptor of a
|
|
5
|
+
* server continues that trace, and gives it to the nested calls, so one trace goes from the
|
|
6
|
+
* client to the last handler. Before, the client and the server made two traces.
|
|
7
|
+
*/
|
|
8
|
+
/** The metadata key of the W3C trace context of a call. */
|
|
9
|
+
export const TRACEPARENT_METADATA_KEY = "traceparent";
|
|
10
|
+
const TRACEPARENT = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
|
|
11
|
+
const ZERO_TRACE = "0".repeat(32);
|
|
12
|
+
const ZERO_SPAN = "0".repeat(16);
|
|
13
|
+
function randomHex(bytes) {
|
|
14
|
+
const values = new Uint8Array(bytes);
|
|
15
|
+
const crypto = globalThis.crypto;
|
|
16
|
+
if (crypto?.getRandomValues)
|
|
17
|
+
crypto.getRandomValues(values);
|
|
18
|
+
else
|
|
19
|
+
for (let index = 0; index < bytes; index++)
|
|
20
|
+
values[index] = Math.floor(Math.random() * 256);
|
|
21
|
+
return Array.from(values, (value) => value.toString(16).padStart(2, "0")).join("");
|
|
22
|
+
}
|
|
23
|
+
/** This function makes a new trace id: 32 random hex digits. */
|
|
24
|
+
export function newTraceId() {
|
|
25
|
+
const id = randomHex(16);
|
|
26
|
+
return id === ZERO_TRACE ? newTraceId() : id;
|
|
27
|
+
}
|
|
28
|
+
/** This function makes a new span id: 16 random hex digits. */
|
|
29
|
+
export function newSpanId() {
|
|
30
|
+
const id = randomHex(8);
|
|
31
|
+
return id === ZERO_SPAN ? newSpanId() : id;
|
|
32
|
+
}
|
|
33
|
+
/** True when the ids have the W3C form. */
|
|
34
|
+
export function isW3cIds(traceId, spanId) {
|
|
35
|
+
return /^[0-9a-f]{32}$/.test(traceId) && /^[0-9a-f]{16}$/.test(spanId) && traceId !== ZERO_TRACE && spanId !== ZERO_SPAN;
|
|
36
|
+
}
|
|
37
|
+
/** The `traceparent` of a trace and a span. */
|
|
38
|
+
export function formatTraceparent(traceId, spanId, sampled = true) {
|
|
39
|
+
return `00-${traceId}-${spanId}-${sampled ? "01" : "00"}`;
|
|
40
|
+
}
|
|
41
|
+
/** The trace context of a `traceparent` value, or undefined when it is not valid. */
|
|
42
|
+
export function parseTraceparent(value) {
|
|
43
|
+
if (typeof value !== "string")
|
|
44
|
+
return undefined;
|
|
45
|
+
const match = TRACEPARENT.exec(value.trim().toLowerCase());
|
|
46
|
+
if (!match)
|
|
47
|
+
return undefined;
|
|
48
|
+
const [, traceId, spanId, flags] = match;
|
|
49
|
+
if (traceId === ZERO_TRACE || spanId === ZERO_SPAN)
|
|
50
|
+
return undefined;
|
|
51
|
+
return { traceId: traceId, spanId: spanId, sampled: (parseInt(flags, 16) & 1) === 1 };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=traceparent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceparent.js","sourceRoot":"","sources":["../../src/tracing/traceparent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,wBAAwB,GAAG,aAAa,CAAC;AAEtD,MAAM,WAAW,GAAG,kDAAkD,CAAC;AACvE,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAClC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AASjC,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAI,UAAmF,CAAC,MAAM,CAAC;IAC3G,IAAI,MAAM,EAAE,eAAe;QAAE,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;;QACvD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IACjG,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IACzB,OAAO,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS;IACvB,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7C,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,MAAc;IACtD,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,OAAO,KAAK,UAAU,IAAI,MAAM,KAAK,SAAS,CAAC;AAC3H,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,MAAc,EAAE,OAAO,GAAG,IAAI;IAC/E,OAAO,MAAM,OAAO,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;IACzC,IAAI,OAAO,KAAK,UAAU,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACrE,OAAO,EAAE,OAAO,EAAE,OAAQ,EAAE,MAAM,EAAE,MAAO,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;AAC3F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/client",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"description": "Procedures as data for TypeScript: define typed procedures once and call them in process, over HTTP, WebSocket, the CLI or MCP. Streaming, middleware, retries, caching and a JSON program format.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"rpc",
|
|
@@ -43,6 +43,10 @@
|
|
|
43
43
|
"types": "./dist/browser.d.ts",
|
|
44
44
|
"import": "./dist/browser.js"
|
|
45
45
|
},
|
|
46
|
+
"./node": {
|
|
47
|
+
"types": "./dist/node.d.ts",
|
|
48
|
+
"import": "./dist/node.js"
|
|
49
|
+
},
|
|
46
50
|
"./register": {
|
|
47
51
|
"types": "./dist/register.d.ts",
|
|
48
52
|
"import": "./dist/register.js"
|
|
@@ -68,9 +72,6 @@
|
|
|
68
72
|
"import": "./dist/server/index.js"
|
|
69
73
|
}
|
|
70
74
|
},
|
|
71
|
-
"bin": {
|
|
72
|
-
"client-registry": "./dist/procedures/cli/index.js"
|
|
73
|
-
},
|
|
74
75
|
"files": [
|
|
75
76
|
"dist",
|
|
76
77
|
"src",
|
|
@@ -90,14 +91,20 @@
|
|
|
90
91
|
"provenance": true
|
|
91
92
|
},
|
|
92
93
|
"dependencies": {
|
|
94
|
+
"@mark1russell7/algebra": "^0.5.0",
|
|
95
|
+
"@mark1russell7/quantity": "^0.2.0",
|
|
96
|
+
"@mark1russell7/service": "^0.4.0",
|
|
93
97
|
"ws": "^8.18.3",
|
|
94
98
|
"zod": "^4.6.5"
|
|
95
99
|
},
|
|
96
100
|
"devDependencies": {
|
|
97
101
|
"@mark1russell7/cue": "^1.0.0",
|
|
102
|
+
"@stryker-mutator/core": "10.0.0",
|
|
103
|
+
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
98
104
|
"@types/express": "^5.0.0",
|
|
99
105
|
"@types/node": "^22.0.0",
|
|
100
106
|
"@types/ws": "^8.18.1",
|
|
107
|
+
"fast-check": "^4.10.2",
|
|
101
108
|
"typescript": "^7.0.2",
|
|
102
109
|
"vitest": "^5.0.3"
|
|
103
110
|
},
|
|
@@ -12,6 +12,21 @@ import type {
|
|
|
12
12
|
} from "../../../client/types.js";
|
|
13
13
|
|
|
14
14
|
import type { HttpTransportOptions } from "./types.js";
|
|
15
|
+
import { DELIVERY_METADATA_KEY, RETRY_AFTER_METADATA_KEY, isNotSentError } from "../../../client/middleware/items.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The wait that an error response asks for, in milliseconds: `retryAfterMs` of the body of the
|
|
19
|
+
* server transport, or else the Retry-After header (seconds, or an HTTP date).
|
|
20
|
+
*/
|
|
21
|
+
function retryAfterMsOf(header: string | null, body: unknown): number | undefined {
|
|
22
|
+
const fromBody = (body as { retryAfterMs?: unknown } | null | undefined)?.retryAfterMs;
|
|
23
|
+
if (typeof fromBody === "number" && Number.isFinite(fromBody) && fromBody >= 0) return fromBody;
|
|
24
|
+
if (header === null || header.trim() === "") return undefined;
|
|
25
|
+
const seconds = Number(header);
|
|
26
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;
|
|
27
|
+
const date = Date.parse(header);
|
|
28
|
+
return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());
|
|
29
|
+
}
|
|
15
30
|
|
|
16
31
|
/** The media type of a stream response: one JSON value on each line. */
|
|
17
32
|
const NDJSON = "application/x-ndjson";
|
|
@@ -32,6 +47,8 @@ import {
|
|
|
32
47
|
createAbortError,
|
|
33
48
|
createErrorFromException,
|
|
34
49
|
} from "../shared/index.js";
|
|
50
|
+
import { optionalMs } from "../../../duration.js";
|
|
51
|
+
import { PROTOCOL_HEADER, PROTOCOL_VERSION } from "../../../protocol.js";
|
|
35
52
|
|
|
36
53
|
/**
|
|
37
54
|
* HTTP Client Transport
|
|
@@ -74,7 +91,7 @@ export class HttpTransport implements Transport {
|
|
|
74
91
|
this.headerConverter =
|
|
75
92
|
options.headerConverter || createDefaultHeaderConverter();
|
|
76
93
|
this.defaultHeaders = options.defaultHeaders || {};
|
|
77
|
-
this.timeout = options.timeout;
|
|
94
|
+
this.timeout = optionalMs(options.timeout, "timeout");
|
|
78
95
|
}
|
|
79
96
|
|
|
80
97
|
/**
|
|
@@ -123,6 +140,8 @@ export class HttpTransport implements Transport {
|
|
|
123
140
|
[HTTPHeaders.CONTENT_TYPE]: "application/json",
|
|
124
141
|
// A streaming procedure answers with NDJSON; other procedures with JSON
|
|
125
142
|
Accept: `${NDJSON}, application/json`,
|
|
143
|
+
// The protocol version of this client (roadmap R25)
|
|
144
|
+
[PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
|
|
126
145
|
...this.defaultHeaders,
|
|
127
146
|
...metadataHeaders,
|
|
128
147
|
},
|
|
@@ -153,6 +172,13 @@ export class HttpTransport implements Transport {
|
|
|
153
172
|
// the client kept only the HTTP status ("HTTP 500").
|
|
154
173
|
const status = this.httpStatusToUniversal(response.status as HTTPStatus, responseBody);
|
|
155
174
|
finished = true;
|
|
175
|
+
if (status.type === "error") {
|
|
176
|
+
const retryAfter = retryAfterMsOf(response.headers.get("Retry-After"), responseBody);
|
|
177
|
+
if (retryAfter !== undefined) metadata[RETRY_AFTER_METADATA_KEY] = retryAfter;
|
|
178
|
+
// The reason of a FORBIDDEN error (roadmap R25)
|
|
179
|
+
const reason = (responseBody as { reason?: unknown } | null | undefined)?.reason;
|
|
180
|
+
if (typeof reason === "string") metadata["reason"] = reason;
|
|
181
|
+
}
|
|
156
182
|
|
|
157
183
|
// Yield single response item
|
|
158
184
|
yield {
|
|
@@ -183,7 +209,9 @@ export class HttpTransport implements Transport {
|
|
|
183
209
|
retryable: errorDetails.retryable,
|
|
184
210
|
},
|
|
185
211
|
payload: null as TRes,
|
|
186
|
-
|
|
212
|
+
// A refused connection sent nothing. After a reset or a timeout, the server can have
|
|
213
|
+
// the request, so only an idempotent call can go again (R1).
|
|
214
|
+
metadata: { [DELIVERY_METADATA_KEY]: isNotSentError(error) ? "not-sent" : "indeterminate" },
|
|
187
215
|
};
|
|
188
216
|
} finally {
|
|
189
217
|
if (timeoutId) clearTimeout(timeoutId);
|
|
@@ -251,7 +279,7 @@ export class HttpTransport implements Transport {
|
|
|
251
279
|
id,
|
|
252
280
|
status: { type: "error", code: "STREAM_ENDED", message: "The stream ended without its end line", retryable: true },
|
|
253
281
|
payload: null as TRes,
|
|
254
|
-
metadata,
|
|
282
|
+
metadata: { ...metadata, [DELIVERY_METADATA_KEY]: "indeterminate" },
|
|
255
283
|
};
|
|
256
284
|
} finally {
|
|
257
285
|
reader.releaseLock();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { UrlStrategy, HttpMethodStrategy, HeaderConverter } from "../shared/index.js";
|
|
9
|
+
import type { Duration } from "../../../duration.js";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* HTTP Client Transport Configuration
|
|
@@ -28,6 +29,6 @@ export interface HttpTransportOptions {
|
|
|
28
29
|
/** Default headers applied to all requests */
|
|
29
30
|
defaultHeaders?: Record<string, string>;
|
|
30
31
|
|
|
31
|
-
/**
|
|
32
|
-
timeout?:
|
|
32
|
+
/** The time to the first item of a response, for example `seconds(30)` */
|
|
33
|
+
timeout?: Duration;
|
|
33
34
|
}
|
|
@@ -10,16 +10,23 @@ import { createServer } from "http";
|
|
|
10
10
|
import type { Server as HttpServer } from "http";
|
|
11
11
|
import type { ServerTransport, ServerRequest, ServerResponse } from "../../../server/types.js";
|
|
12
12
|
import type { Metadata } from "../../../client/types.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { RequestHandler } from "../../../server/types.js";
|
|
14
14
|
import { HTTPMethod, HTTPHeaders, decodeMetadataHeader, METADATA_HEADER_LIMIT } from "../shared/index.js";
|
|
15
15
|
import { ERROR_REGISTRY } from "../../../client/errors/index.js";
|
|
16
16
|
import type { HttpServerTransportOptions } from "./types.js";
|
|
17
17
|
import { createPatternServerUrlStrategy } from "./strategies.js";
|
|
18
18
|
import { checkBrowserRequest, type BrowserGuardOptions } from "../../../server/browser-guard.js";
|
|
19
|
+
import { bearerOf, withoutSecretHeaders } from "../../../server/request-auth.js";
|
|
20
|
+
import { PROTOCOL_HEADER, PROTOCOL_VERSION, errorCodeOf, httpStatusOf, protocolVersionOf } from "../../../protocol.js";
|
|
19
21
|
|
|
20
22
|
/** The media type of a stream response: one JSON value on each line. */
|
|
21
23
|
const NDJSON = "application/x-ndjson";
|
|
22
24
|
|
|
25
|
+
/** True when a stream response can run without an end (`STREAM_METADATA_KEY` of procedure-server.ts). */
|
|
26
|
+
function isUnboundedStream(response: { metadata?: Record<string, unknown> | undefined }): boolean {
|
|
27
|
+
return response.metadata?.["stream"] === "unbounded";
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
/** The metadata keys that the transport sets: a query parameter or a header cannot replace them. */
|
|
24
31
|
const RESERVED_METADATA = new Set(["headers", "query", "params"]);
|
|
25
32
|
|
|
@@ -35,10 +42,9 @@ class BodyError extends Error {
|
|
|
35
42
|
|
|
36
43
|
/** The code and message of a thrown error, with its retryable flag (deep dive TRN-7). */
|
|
37
44
|
function errorOf(error: unknown): { code: string; message: string; retryable: boolean } {
|
|
38
|
-
const code = (error as { code?: unknown } | undefined)?.code;
|
|
39
45
|
const retryable = (error as { retryable?: unknown } | undefined)?.retryable;
|
|
40
46
|
return {
|
|
41
|
-
code:
|
|
47
|
+
code: errorCodeOf(error),
|
|
42
48
|
message: error instanceof Error ? error.message : String(error),
|
|
43
49
|
retryable: typeof retryable === "boolean" ? retryable : false,
|
|
44
50
|
};
|
|
@@ -64,24 +70,6 @@ function write(res: Response, chunk: string, signal: AbortSignal): Promise<void>
|
|
|
64
70
|
});
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
/**
|
|
68
|
-
* The HTTP status of the error codes of a procedure invocation (they are not in the error
|
|
69
|
-
* registry, so before, a validation error was a 500).
|
|
70
|
-
*/
|
|
71
|
-
const INVOCATION_HTTP_STATUS: Record<string, number> = {
|
|
72
|
-
VALIDATION_ERROR: 400,
|
|
73
|
-
NOT_EXPOSED: 403,
|
|
74
|
-
NOT_DECLARED: 403,
|
|
75
|
-
FORBIDDEN: 403,
|
|
76
|
-
NOT_FOUND: 404,
|
|
77
|
-
NO_HANDLER: 404,
|
|
78
|
-
ABORTED: 499,
|
|
79
|
-
TIMEOUT: 504,
|
|
80
|
-
OUTPUT_VALIDATION_ERROR: 500,
|
|
81
|
-
NO_OUTPUT: 500,
|
|
82
|
-
HANDLER_ERROR: 500,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
73
|
/**
|
|
86
74
|
* HTTP server transport adapter for Express.
|
|
87
75
|
*
|
|
@@ -126,7 +114,7 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
126
114
|
corsOptions: HttpServerTransportOptions["corsOptions"] | undefined;
|
|
127
115
|
httpServer: HttpServer | undefined;
|
|
128
116
|
};
|
|
129
|
-
private server:
|
|
117
|
+
private server: RequestHandler;
|
|
130
118
|
/** The controllers of the requests in progress: stop() aborts them (deep dive TRN-15) */
|
|
131
119
|
private openRequests = new Set<AbortController>();
|
|
132
120
|
private stopped = false;
|
|
@@ -134,7 +122,7 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
134
122
|
/** The browser checks of each procedure call (see `server/browser-guard.ts`) */
|
|
135
123
|
private readonly guard: BrowserGuardOptions;
|
|
136
124
|
|
|
137
|
-
constructor(server:
|
|
125
|
+
constructor(server: RequestHandler, options: HttpServerTransportOptions = {}) {
|
|
138
126
|
this.server = server;
|
|
139
127
|
const basePath = options.basePath ?? "/api";
|
|
140
128
|
this.options = {
|
|
@@ -198,7 +186,8 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
198
186
|
HTTPHeaders.TRACE_ID,
|
|
199
187
|
HTTPHeaders.SPAN_ID,
|
|
200
188
|
HTTPHeaders.PARENT_SPAN_ID,
|
|
201
|
-
|
|
189
|
+
"traceparent",
|
|
190
|
+
PROTOCOL_HEADER,
|
|
202
191
|
HTTPHeaders.METADATA,
|
|
203
192
|
"collection",
|
|
204
193
|
"collectionName",
|
|
@@ -256,6 +245,18 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
256
245
|
* Converts to unified RPC format, processes, and sends response.
|
|
257
246
|
*/
|
|
258
247
|
private async handleHttpRequest(req: Request, res: Response): Promise<void> {
|
|
248
|
+
// The protocol version of this server, on each response (roadmap R25)
|
|
249
|
+
res.setHeader(PROTOCOL_HEADER, String(PROTOCOL_VERSION));
|
|
250
|
+
const version = protocolVersionOf(req.headers[PROTOCOL_HEADER.toLowerCase()]);
|
|
251
|
+
if (version !== undefined && version > PROTOCOL_VERSION) {
|
|
252
|
+
res.status(400).json({
|
|
253
|
+
error: `This server speaks the protocol ${PROTOCOL_VERSION}, and the request uses ${version}`,
|
|
254
|
+
code: "PROTOCOL_VERSION",
|
|
255
|
+
retryable: false,
|
|
256
|
+
protocol: PROTOCOL_VERSION,
|
|
257
|
+
});
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
259
260
|
if (this.stopped) {
|
|
260
261
|
res.status(503).json({ error: "Server stopped", code: "SERVER_STOPPED", retryable: true });
|
|
261
262
|
return;
|
|
@@ -360,6 +361,26 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
360
361
|
): Promise<void> {
|
|
361
362
|
const ndjson = String(req.headers.accept ?? "").includes(NDJSON);
|
|
362
363
|
|
|
364
|
+
if (!ndjson && isUnboundedStream(response)) {
|
|
365
|
+
// The last item of a stream without an end never comes: refuse the call, and end the stream
|
|
366
|
+
// (roadmap R15: before, the request waited until a timeout)
|
|
367
|
+
void Promise.resolve(stream[Symbol.asyncIterator]().return?.()).catch(() => undefined);
|
|
368
|
+
this.serverResponseToHttp(
|
|
369
|
+
{
|
|
370
|
+
id: response.id,
|
|
371
|
+
status: {
|
|
372
|
+
type: "error",
|
|
373
|
+
code: "NOT_ACCEPTABLE",
|
|
374
|
+
message: `This procedure gives a stream that can run without an end. Send "Accept: ${NDJSON}" to read its items.`,
|
|
375
|
+
retryable: false,
|
|
376
|
+
},
|
|
377
|
+
metadata: {},
|
|
378
|
+
},
|
|
379
|
+
res
|
|
380
|
+
);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
363
384
|
if (!ndjson) {
|
|
364
385
|
let last: { value: unknown } | undefined;
|
|
365
386
|
try {
|
|
@@ -424,11 +445,14 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
424
445
|
const id =
|
|
425
446
|
(req.headers["x-request-id"] as string) ??
|
|
426
447
|
`req-${Date.now()}-${Math.random()}`;
|
|
448
|
+
const bearer = bearerOf(req.headers["authorization"]);
|
|
427
449
|
|
|
428
450
|
// Build metadata from headers and query params. The flattened query parameters cannot
|
|
429
451
|
// replace headers, query or params (before, "?headers=x" replaced metadata.headers).
|
|
452
|
+
// The headers without the secrets: the credentials go in request.credentials, not in the
|
|
453
|
+
// metadata, so a handler and a nested call do not see them (roadmap R18)
|
|
430
454
|
const metadata: Metadata = {
|
|
431
|
-
headers: req.headers as Record<string, string
|
|
455
|
+
headers: withoutSecretHeaders(req.headers as Record<string, string>),
|
|
432
456
|
query: req.query,
|
|
433
457
|
params: req.params,
|
|
434
458
|
};
|
|
@@ -505,6 +529,8 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
505
529
|
method,
|
|
506
530
|
payload,
|
|
507
531
|
metadata,
|
|
532
|
+
// A network request: ProcedureServer examines the token (roadmap R18)
|
|
533
|
+
credentials: bearer === undefined ? {} : { bearer },
|
|
508
534
|
};
|
|
509
535
|
}
|
|
510
536
|
|
|
@@ -524,7 +550,7 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
524
550
|
// HTTP status via the error registry rather than parseInt (which yields NaN -> 500, so every
|
|
525
551
|
// error became a 500). See documentation/BUGS-2026-07.md (M7).
|
|
526
552
|
const mapped =
|
|
527
|
-
|
|
553
|
+
httpStatusOf(status.code) ??
|
|
528
554
|
(ERROR_REGISTRY as Record<string, { httpStatus?: number }>)[status.code]?.httpStatus;
|
|
529
555
|
httpStatusCode = mapped ?? (status.type === "success" ? 200 : 500);
|
|
530
556
|
} else if (typeof status.code === "number") {
|
|
@@ -551,10 +577,19 @@ export class HttpServerTransport implements ServerTransport {
|
|
|
551
577
|
}
|
|
552
578
|
res.json(payload);
|
|
553
579
|
} else {
|
|
580
|
+
// The wait that the error asks for: a Retry-After header in seconds, and the exact
|
|
581
|
+
// milliseconds in the body (R12)
|
|
582
|
+
const retryAfterMs = metadata["retry-after"];
|
|
583
|
+
const hasRetryAfter = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs >= 0;
|
|
584
|
+
if (hasRetryAfter) res.setHeader("Retry-After", String(Math.ceil(retryAfterMs / 1000)));
|
|
585
|
+
// The reason of a FORBIDDEN error travels on each face (roadmap R25)
|
|
586
|
+
const reason = typeof metadata["reason"] === "string" ? metadata["reason"] : undefined;
|
|
554
587
|
res.json({
|
|
555
588
|
error: status.message,
|
|
556
589
|
code: status.code,
|
|
557
590
|
retryable: status.retryable,
|
|
591
|
+
...(hasRetryAfter ? { retryAfterMs } : {}),
|
|
592
|
+
...(reason !== undefined ? { reason } : {}),
|
|
558
593
|
});
|
|
559
594
|
}
|
|
560
595
|
}
|