@procedures/client 0.7.0 → 0.8.1
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 +107 -0
- package/README.md +115 -11
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/client/transport.d.ts +4 -0
- package/dist/adapters/http/client/transport.d.ts.map +1 -1
- package/dist/adapters/http/client/transport.js +11 -1
- package/dist/adapters/http/client/transport.js.map +1 -1
- package/dist/adapters/http/client/types.d.ts +19 -0
- package/dist/adapters/http/client/types.d.ts.map +1 -1
- package/dist/adapters/http/server/cors.d.ts +64 -0
- package/dist/adapters/http/server/cors.d.ts.map +1 -0
- package/dist/adapters/http/server/cors.js +113 -0
- package/dist/adapters/http/server/cors.js.map +1 -0
- package/dist/adapters/http/server/handler.d.ts +136 -0
- package/dist/adapters/http/server/handler.d.ts.map +1 -0
- package/dist/adapters/http/server/handler.js +495 -0
- package/dist/adapters/http/server/handler.js.map +1 -0
- package/dist/adapters/http/server/strategies.d.ts +14 -5
- package/dist/adapters/http/server/strategies.d.ts.map +1 -1
- package/dist/adapters/http/server/strategies.js.map +1 -1
- package/dist/adapters/http/server/transport.d.ts +36 -46
- package/dist/adapters/http/server/transport.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.js +58 -433
- package/dist/adapters/http/server/transport.js.map +1 -1
- package/dist/adapters/http/server/types.d.ts +13 -0
- package/dist/adapters/http/server/types.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.d.ts +7 -3
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +9 -3
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts +56 -1
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +174 -17
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/server/types.d.ts +10 -3
- package/dist/adapters/websocket/server/types.d.ts.map +1 -1
- package/dist/adapters/websocket/server/upgrade-router.d.ts +28 -0
- package/dist/adapters/websocket/server/upgrade-router.d.ts.map +1 -0
- package/dist/adapters/websocket/server/upgrade-router.js +62 -0
- package/dist/adapters/websocket/server/upgrade-router.js.map +1 -0
- package/dist/adapters/websocket/server/upgrade.d.ts +68 -0
- package/dist/adapters/websocket/server/upgrade.d.ts.map +1 -0
- package/dist/adapters/websocket/server/upgrade.js +49 -0
- package/dist/adapters/websocket/server/upgrade.js.map +1 -0
- package/dist/adapters/websocket/shared/rpc.d.ts +2 -0
- package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.js +8 -2
- package/dist/adapters/websocket/shared/rpc.js.map +1 -1
- package/dist/browser.d.ts +14 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +12 -3
- package/dist/browser.js.map +1 -1
- package/dist/client/client.d.ts +43 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +69 -1
- package/dist/client/client.js.map +1 -1
- package/dist/client/errors/registry.d.ts.map +1 -1
- package/dist/client/errors/registry.js +1 -0
- package/dist/client/errors/registry.js.map +1 -1
- package/dist/client/middleware/retry.d.ts +4 -0
- package/dist/client/middleware/retry.d.ts.map +1 -1
- package/dist/client/middleware/retry.js +86 -78
- package/dist/client/middleware/retry.js.map +1 -1
- package/dist/events/bus.d.ts +32 -14
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/bus.js +119 -65
- package/dist/events/bus.js.map +1 -1
- package/dist/events/index.d.ts +3 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js.map +1 -1
- package/dist/events/publisher.d.ts +14 -0
- package/dist/events/publisher.d.ts.map +1 -1
- package/dist/events/publisher.js +62 -10
- package/dist/events/publisher.js.map +1 -1
- package/dist/events/remote.d.ts +80 -18
- package/dist/events/remote.d.ts.map +1 -1
- package/dist/events/remote.js +448 -58
- package/dist/events/remote.js.map +1 -1
- package/dist/events/rows.d.ts +31 -0
- package/dist/events/rows.d.ts.map +1 -0
- package/dist/events/rows.js +39 -0
- package/dist/events/rows.js.map +1 -0
- package/dist/events/types.d.ts +13 -2
- package/dist/events/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +14 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +9 -0
- package/dist/node.js.map +1 -1
- package/dist/procedures/caller.d.ts +33 -0
- package/dist/procedures/caller.d.ts.map +1 -0
- package/dist/procedures/caller.js +27 -0
- package/dist/procedures/caller.js.map +1 -0
- package/dist/procedures/capability.d.ts +6 -0
- package/dist/procedures/capability.d.ts.map +1 -1
- package/dist/procedures/capability.js +25 -0
- package/dist/procedures/capability.js.map +1 -1
- package/dist/procedures/collection/changes.d.ts +94 -0
- package/dist/procedures/collection/changes.d.ts.map +1 -0
- package/dist/procedures/collection/changes.js +182 -0
- package/dist/procedures/collection/changes.js.map +1 -0
- package/dist/procedures/collection/index.d.ts +8 -3
- package/dist/procedures/collection/index.d.ts.map +1 -1
- package/dist/procedures/collection/index.js +6 -1
- package/dist/procedures/collection/index.js.map +1 -1
- package/dist/procedures/collection/procedures.d.ts +39 -2
- package/dist/procedures/collection/procedures.d.ts.map +1 -1
- package/dist/procedures/collection/procedures.js +131 -8
- package/dist/procedures/collection/procedures.js.map +1 -1
- package/dist/procedures/collection/query.d.ts +246 -0
- package/dist/procedures/collection/query.d.ts.map +1 -0
- package/dist/procedures/collection/query.js +854 -0
- package/dist/procedures/collection/query.js.map +1 -0
- package/dist/procedures/collection/schemas.d.ts +59 -0
- package/dist/procedures/collection/schemas.d.ts.map +1 -1
- package/dist/procedures/collection/schemas.js +172 -6
- package/dist/procedures/collection/schemas.js.map +1 -1
- package/dist/procedures/collection/storage.d.ts +64 -6
- package/dist/procedures/collection/storage.d.ts.map +1 -1
- package/dist/procedures/collection/storage.js +23 -0
- package/dist/procedures/collection/storage.js.map +1 -1
- package/dist/procedures/elicit.d.ts +190 -0
- package/dist/procedures/elicit.d.ts.map +1 -0
- package/dist/procedures/elicit.js +127 -0
- package/dist/procedures/elicit.js.map +1 -0
- package/dist/procedures/hints.d.ts +43 -0
- package/dist/procedures/hints.d.ts.map +1 -0
- package/dist/procedures/hints.js +74 -0
- package/dist/procedures/hints.js.map +1 -0
- package/dist/procedures/index.d.ts +12 -3
- package/dist/procedures/index.d.ts.map +1 -1
- package/dist/procedures/index.js +7 -1
- package/dist/procedures/index.js.map +1 -1
- package/dist/procedures/invoke.d.ts +20 -0
- package/dist/procedures/invoke.d.ts.map +1 -1
- package/dist/procedures/invoke.js +16 -0
- package/dist/procedures/invoke.js.map +1 -1
- package/dist/procedures/progress.d.ts +24 -0
- package/dist/procedures/progress.d.ts.map +1 -0
- package/dist/procedures/progress.js +11 -0
- package/dist/procedures/progress.js.map +1 -0
- package/dist/procedures/registry.d.ts.map +1 -1
- package/dist/procedures/registry.js +5 -0
- package/dist/procedures/registry.js.map +1 -1
- package/dist/procedures/types.d.ts +92 -0
- package/dist/procedures/types.d.ts.map +1 -1
- package/dist/procedures/types.js.map +1 -1
- package/dist/procedures/untrusted.d.ts +28 -0
- package/dist/procedures/untrusted.d.ts.map +1 -0
- package/dist/procedures/untrusted.js +32 -0
- package/dist/procedures/untrusted.js.map +1 -0
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +1 -0
- package/dist/protocol.js.map +1 -1
- package/dist/server/browser-guard.d.ts +12 -2
- package/dist/server/browser-guard.d.ts.map +1 -1
- package/dist/server/browser-guard.js +43 -6
- package/dist/server/browser-guard.js.map +1 -1
- package/dist/server/host-policy.d.ts +10 -1
- package/dist/server/host-policy.d.ts.map +1 -1
- package/dist/server/host-policy.js +5 -0
- package/dist/server/host-policy.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/procedure-server.d.ts +75 -9
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +151 -17
- package/dist/server/procedure-server.js.map +1 -1
- package/dist/server/request-auth.d.ts +51 -4
- package/dist/server/request-auth.d.ts.map +1 -1
- package/dist/server/request-auth.js +116 -5
- package/dist/server/request-auth.js.map +1 -1
- package/dist/server/types.d.ts +73 -5
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/timers.d.ts +5 -0
- package/dist/timers.d.ts.map +1 -1
- package/dist/timers.js +3 -1
- package/dist/timers.js.map +1 -1
- package/package.json +5 -1
- package/src/adapters/http/client/transport.ts +11 -1
- package/src/adapters/http/client/types.ts +22 -0
- package/src/adapters/http/server/cors.ts +144 -0
- package/src/adapters/http/server/handler.ts +624 -0
- package/src/adapters/http/server/strategies.ts +16 -6
- package/src/adapters/http/server/transport.ts +66 -479
- package/src/adapters/http/server/types.ts +15 -0
- package/src/adapters/websocket/client/transport.ts +9 -3
- package/src/adapters/websocket/server/transport.ts +189 -18
- package/src/adapters/websocket/server/types.ts +11 -3
- package/src/adapters/websocket/server/upgrade-router.ts +77 -0
- package/src/adapters/websocket/server/upgrade.ts +88 -0
- package/src/adapters/websocket/shared/rpc.ts +9 -2
- package/src/browser.ts +85 -2
- package/src/client/client.ts +83 -1
- package/src/client/errors/registry.ts +1 -0
- package/src/client/middleware/retry.ts +89 -78
- package/src/events/bus.ts +141 -73
- package/src/events/index.ts +3 -0
- package/src/events/publisher.ts +71 -10
- package/src/events/remote.ts +575 -73
- package/src/events/rows.ts +48 -0
- package/src/events/types.ts +15 -2
- package/src/index.ts +1 -1
- package/src/node.ts +21 -0
- package/src/procedures/caller.ts +45 -0
- package/src/procedures/capability.ts +21 -0
- package/src/procedures/collection/changes.ts +245 -0
- package/src/procedures/collection/index.ts +56 -1
- package/src/procedures/collection/procedures.ts +185 -7
- package/src/procedures/collection/query.ts +1009 -0
- package/src/procedures/collection/schemas.ts +233 -7
- package/src/procedures/collection/storage.ts +84 -6
- package/src/procedures/elicit.ts +320 -0
- package/src/procedures/hints.ts +91 -0
- package/src/procedures/index.ts +82 -2
- package/src/procedures/invoke.ts +31 -0
- package/src/procedures/progress.ts +25 -0
- package/src/procedures/registry.ts +4 -0
- package/src/procedures/types.ts +102 -0
- package/src/procedures/untrusted.ts +50 -0
- package/src/protocol.ts +3 -1
- package/src/server/browser-guard.ts +48 -6
- package/src/server/host-policy.ts +13 -1
- package/src/server/index.ts +3 -0
- package/src/server/procedure-server.ts +185 -20
- package/src/server/request-auth.ts +128 -6
- package/src/server/types.ts +82 -5
- package/src/timers.ts +8 -1
package/src/browser.ts
CHANGED
|
@@ -76,8 +76,9 @@ export {
|
|
|
76
76
|
export { Server } from "./server/server.js";
|
|
77
77
|
export type { ServerOptions } from "./server/server.js";
|
|
78
78
|
export { ProcedureServer, createProcedureServer, STREAM_METADATA_KEY, isUnboundedStream, tokenMatches } from "./server/procedure-server.js";
|
|
79
|
-
// The credentials of a network request (roadmap R18)
|
|
80
|
-
export { credentialsOf, bearerOf, withoutSecretHeaders } from "./server/request-auth.js";
|
|
79
|
+
// The credentials of a network request (roadmap R18), and the parts that a request hook reads (CLI-2a)
|
|
80
|
+
export { credentialsOf, bearerOf, withoutSecretHeaders, cookiesOf, requestCredentials } from "./server/request-auth.js";
|
|
81
|
+
export type { RequestCredentialsOptions } from "./server/request-auth.js";
|
|
81
82
|
// The procedures of a host: host.health, host.info, host.metrics (roadmap R19)
|
|
82
83
|
export { hostProcedures } from "./server/host-procedures.js";
|
|
83
84
|
export type { HostSource } from "./server/host-procedures.js";
|
|
@@ -93,6 +94,9 @@ export type {
|
|
|
93
94
|
RequestHandler,
|
|
94
95
|
Credentials,
|
|
95
96
|
Principal,
|
|
97
|
+
PrincipalOf,
|
|
98
|
+
RequestIdentity,
|
|
99
|
+
AmbientCredentials,
|
|
96
100
|
ServerHandler,
|
|
97
101
|
ServerMiddleware,
|
|
98
102
|
ServerContext,
|
|
@@ -117,6 +121,24 @@ export {
|
|
|
117
121
|
pathToKey,
|
|
118
122
|
keyToPath,
|
|
119
123
|
createCollectionProcedures,
|
|
124
|
+
// The change events of the collection writes (roadmap CLI-15)
|
|
125
|
+
collectionChangeTopic,
|
|
126
|
+
collectionTopicReads,
|
|
127
|
+
// The query language of the collection storages (roadmap CLI-14, CLI-34)
|
|
128
|
+
DEFAULT_FIND_LIMIT,
|
|
129
|
+
DEFAULT_QUERY_OPERATORS,
|
|
130
|
+
DEFAULT_QUERY_POLICY,
|
|
131
|
+
QUERY_OPERATORS,
|
|
132
|
+
applyPatch,
|
|
133
|
+
compareStorageValues,
|
|
134
|
+
compileSelector,
|
|
135
|
+
isPatchOperations,
|
|
136
|
+
matchesSelector,
|
|
137
|
+
mergePatch,
|
|
138
|
+
patchProblems,
|
|
139
|
+
queryEntries,
|
|
140
|
+
queryOptionsProblems,
|
|
141
|
+
selectorProblems,
|
|
120
142
|
// Manual registration helpers
|
|
121
143
|
registerModule,
|
|
122
144
|
registerProcedures,
|
|
@@ -128,6 +150,7 @@ export {
|
|
|
128
150
|
registerModules,
|
|
129
151
|
createRegistry,
|
|
130
152
|
registerClientProcedures,
|
|
153
|
+
callerOf,
|
|
131
154
|
// Procedure reference system (procedure-as-data)
|
|
132
155
|
PROCEDURE_SYMBOL,
|
|
133
156
|
PROCEDURE_JSON_KEY,
|
|
@@ -213,6 +236,7 @@ export {
|
|
|
213
236
|
|
|
214
237
|
export type {
|
|
215
238
|
Effects,
|
|
239
|
+
FsRootRules,
|
|
216
240
|
PermittedEffects,
|
|
217
241
|
Register,
|
|
218
242
|
ClearanceOf,
|
|
@@ -233,8 +257,29 @@ export type {
|
|
|
233
257
|
CollectionStorage,
|
|
234
258
|
StorageChanges,
|
|
235
259
|
StorageMetadata,
|
|
260
|
+
StorageWriteOptions,
|
|
261
|
+
StorageSetChange,
|
|
262
|
+
StorageDeleteChange,
|
|
263
|
+
StorageClearChange,
|
|
264
|
+
StorageChangeEvent,
|
|
265
|
+
StorageChangeBatch,
|
|
266
|
+
StorageObserver,
|
|
267
|
+
StorageFieldOperators,
|
|
268
|
+
StoragePatch,
|
|
269
|
+
StorageQueryOptions,
|
|
270
|
+
StorageSelector,
|
|
271
|
+
StorageSort,
|
|
272
|
+
StorageSortDirection,
|
|
273
|
+
StoragePatchOperations,
|
|
274
|
+
StorageQueryOperator,
|
|
275
|
+
StorageQueryPolicy,
|
|
276
|
+
CollectionProceduresOptions,
|
|
277
|
+
CollectionChangeEventsOptions,
|
|
278
|
+
CollectionChangeEvent,
|
|
236
279
|
ProcedureModule,
|
|
237
280
|
ModuleInput,
|
|
281
|
+
Caller,
|
|
282
|
+
CallerOptions,
|
|
238
283
|
RegistrationOptions,
|
|
239
284
|
ProcedureRegistryLike,
|
|
240
285
|
ProcedureDefinition,
|
|
@@ -331,6 +376,42 @@ export { TIMEOUT_METADATA_KEY, DEADLINE_METADATA_KEY } from "./client/deadline.j
|
|
|
331
376
|
// Typed durations: each public option that is a time takes a Duration (roadmap R11)
|
|
332
377
|
export { ms, seconds, minutes, hours, toMs, optionalMs, isDuration } from "./duration.js";
|
|
333
378
|
export type { Duration, TimeUnit } from "./duration.js";
|
|
379
|
+
// What the face of a call offers the procedure: the questions to the person at the caller, the
|
|
380
|
+
// progress, and the text from outside the host (CLI-10, CLI-12)
|
|
381
|
+
export {
|
|
382
|
+
createElicit,
|
|
383
|
+
elicitWithPolicy,
|
|
384
|
+
operatorAnswer,
|
|
385
|
+
elicitInput,
|
|
386
|
+
elicitConfirmation,
|
|
387
|
+
NO_ELICITATION_REASON,
|
|
388
|
+
} from "./procedures/elicit.js";
|
|
389
|
+
export type {
|
|
390
|
+
Elicit,
|
|
391
|
+
ElicitRequest,
|
|
392
|
+
ElicitFormRequest,
|
|
393
|
+
ElicitUrlRequest,
|
|
394
|
+
ElicitMode,
|
|
395
|
+
ElicitAction,
|
|
396
|
+
ElicitResult,
|
|
397
|
+
ElicitOptions,
|
|
398
|
+
ElicitField,
|
|
399
|
+
ElicitFieldBase,
|
|
400
|
+
ElicitTextField,
|
|
401
|
+
ElicitNumberField,
|
|
402
|
+
ElicitBooleanField,
|
|
403
|
+
ElicitChoiceField,
|
|
404
|
+
ElicitChoicesField,
|
|
405
|
+
ElicitValue,
|
|
406
|
+
ElicitationPolicy,
|
|
407
|
+
ConfirmationOptions,
|
|
408
|
+
ConfirmationResult,
|
|
409
|
+
} from "./procedures/elicit.js";
|
|
410
|
+
export type { ProgressUpdate, ReportProgress } from "./procedures/progress.js";
|
|
411
|
+
export { toolHintsOf, toolHintOverrideOf, toolHintOverrideRefusal } from "./procedures/hints.js";
|
|
412
|
+
export type { ToolHintOverride } from "./procedures/hints.js";
|
|
413
|
+
export { untrustedText, untrustedFieldsOf, untrustedTextsOf } from "./procedures/untrusted.js";
|
|
414
|
+
export type { UntrustedText, UntrustedSource, UntrustedValue } from "./procedures/untrusted.js";
|
|
334
415
|
// One manifest type (roadmap R17)
|
|
335
416
|
export { MANIFEST_FORMAT, describeProcedure as describeProcedureEntry, describeRegistry, exposedProcedures, hashOf } from "./procedures/manifest.js";
|
|
336
417
|
export type { ProcedureEntry, ProcedureManifest, CliDescription, DescribeOptions, DescribeRegistryOptions } from "./procedures/manifest.js";
|
|
@@ -411,6 +492,7 @@ export type {
|
|
|
411
492
|
TypedEventBus,
|
|
412
493
|
EventHandler,
|
|
413
494
|
EventBusOptions,
|
|
495
|
+
EventListenOptions,
|
|
414
496
|
EventWaitOptions,
|
|
415
497
|
ChannelMap,
|
|
416
498
|
} from "./events/index.js";
|
|
@@ -424,6 +506,7 @@ export type {
|
|
|
424
506
|
RemoteEvent,
|
|
425
507
|
RemoteEventHandler,
|
|
426
508
|
RemoteEventsOptions,
|
|
509
|
+
ResubscribeBackoff,
|
|
427
510
|
SubscribeOptions,
|
|
428
511
|
Subscription,
|
|
429
512
|
} from "./events/index.js";
|
package/src/client/client.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
Method,
|
|
31
31
|
Metadata,
|
|
32
32
|
Message,
|
|
33
|
+
ResponseItem,
|
|
33
34
|
ClientMiddleware,
|
|
34
35
|
ClientContext,
|
|
35
36
|
ClientRunner,
|
|
@@ -56,8 +57,19 @@ import { RouteResolver, type ResolvedRoute, type RouteResolutionResult } from ".
|
|
|
56
57
|
import { BatchExecutor, type ExecutionContext } from "./batch-executor.js";
|
|
57
58
|
import type { ProcedureRegistry } from "../procedures/registry.js";
|
|
58
59
|
import type { EventBus } from "../events/types.js";
|
|
60
|
+
import {
|
|
61
|
+
remoteEvents,
|
|
62
|
+
subscribeRemote,
|
|
63
|
+
type EventTransport,
|
|
64
|
+
type RemoteEvent,
|
|
65
|
+
type RemoteEventHandler,
|
|
66
|
+
type RemoteEventsOptions,
|
|
67
|
+
type SubscribeOptions,
|
|
68
|
+
type Subscription,
|
|
69
|
+
} from "../events/remote.js";
|
|
59
70
|
import { narrowCapability } from "../procedures/capability.js";
|
|
60
|
-
import { TIMEOUT_METADATA_KEY, absorbTimeout, writeRemainingTime } from "./deadline.js";
|
|
71
|
+
import { DEADLINE_METADATA_KEY, TIMEOUT_METADATA_KEY, absorbTimeout, writeRemainingTime } from "./deadline.js";
|
|
72
|
+
import { ms } from "../duration.js";
|
|
61
73
|
import type { Capability, ClearanceOrder, NestedCallOptions } from "../procedures/types.js";
|
|
62
74
|
import { PROCEDURE_REGISTRY } from "../procedures/registry.js";
|
|
63
75
|
import { validateSchema } from "../procedures/schema.js";
|
|
@@ -169,6 +181,12 @@ function callerOf(options: ExecOptions): CallerContext {
|
|
|
169
181
|
return caller;
|
|
170
182
|
}
|
|
171
183
|
|
|
184
|
+
/**
|
|
185
|
+
* The timeouts of a subscription: none. The timeout middleware takes 0 as "no timeout", so the
|
|
186
|
+
* timeouts of the client do not end a subscription, which has no end (roadmap CLI-15).
|
|
187
|
+
*/
|
|
188
|
+
const NO_SUBSCRIPTION_TIMEOUT = Object.freeze({ overall: ms(0), perAttempt: ms(0) });
|
|
189
|
+
|
|
172
190
|
/**
|
|
173
191
|
* Generate a unique message ID.
|
|
174
192
|
*/
|
|
@@ -221,6 +239,8 @@ export class Client<TContext = {}> {
|
|
|
221
239
|
private readonly throwOnError: boolean;
|
|
222
240
|
/** The bus of the local procedures. Undefined: the global bus. */
|
|
223
241
|
private bus: EventBus | undefined;
|
|
242
|
+
/** The transport of the subscriptions through the middleware, made at the first subscription */
|
|
243
|
+
private subscriptionTransport: EventTransport | undefined;
|
|
224
244
|
/** The interceptors of the local invocations (roadmap 1.2) */
|
|
225
245
|
private interceptors: readonly Interceptor[] = [];
|
|
226
246
|
/** The capability of the local invocations (CAPABILITIES-2026-10). Undefined: no limits. */
|
|
@@ -779,6 +799,68 @@ export class Client<TContext = {}> {
|
|
|
779
799
|
}
|
|
780
800
|
}
|
|
781
801
|
|
|
802
|
+
/**
|
|
803
|
+
* This method subscribes to topics of the event bus of the server (`documentation/EVENTS.md`).
|
|
804
|
+
* The call of `events.subscribe` goes through the middleware and the context of this client, as
|
|
805
|
+
* `stream()` does. Thus a token of the auth middleware goes with it. The subscriber resubscribes
|
|
806
|
+
* after a failure that a retry can repair, and the subscribers of the same topics share one call.
|
|
807
|
+
*
|
|
808
|
+
* A subscription has no deadline: the timeouts of the client (its timeout middleware, the
|
|
809
|
+
* `timeout` of its context and a `procedure-timeout` of its metadata) do not apply to it. For a
|
|
810
|
+
* deadline, give it in the metadata of the options, for example
|
|
811
|
+
* `{ metadata: { timeout: { overall: minutes(5) } } }`.
|
|
812
|
+
*
|
|
813
|
+
* @param topics - One topic, or a list of 1 to 64 topics
|
|
814
|
+
* @param handler - The handler of each event. A promise that it gives holds the next event.
|
|
815
|
+
* @param options - `onSubscribed`, `onError`, a signal, the metadata of the call, the resubscribe rules
|
|
816
|
+
* @returns The unsubscribe function, with the `ready` promise of the first confirmation
|
|
817
|
+
*
|
|
818
|
+
* @example
|
|
819
|
+
* ```typescript
|
|
820
|
+
* const unsubscribe = client.subscribe("collections.users", (event) => console.log(event));
|
|
821
|
+
* await unsubscribe.ready;
|
|
822
|
+
* unsubscribe();
|
|
823
|
+
* ```
|
|
824
|
+
*/
|
|
825
|
+
subscribe<T = unknown>(topics: string | readonly string[], handler: RemoteEventHandler<T>, options: SubscribeOptions = {}): Subscription {
|
|
826
|
+
return subscribeRemote<T>(this.eventTransport(), topics, handler, options);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* This method gives the events of topics of the event bus of the server as an async iterator,
|
|
831
|
+
* through the middleware of this client. A `break` or the signal ends the subscription. As for
|
|
832
|
+
* `subscribe()`, the timeouts of the client do not apply: the metadata of the options can give one.
|
|
833
|
+
*
|
|
834
|
+
* @param topics - One topic, or a list of 1 to 64 topics
|
|
835
|
+
* @param options - A signal, `onSubscribed`, the metadata of the call, the resubscribe rules
|
|
836
|
+
*/
|
|
837
|
+
events<T = unknown>(topics: string | readonly string[], options: RemoteEventsOptions = {}): AsyncIterable<RemoteEvent<T>> {
|
|
838
|
+
return remoteEvents<T>(this.eventTransport(), topics, options);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* The transport of the subscriptions of this client: each call goes through the middleware, with
|
|
843
|
+
* the context of the client in its metadata. The subscriptions of one client share it, so they
|
|
844
|
+
* share their calls. The timeouts and the deadline of the client stay out: only the metadata of
|
|
845
|
+
* the subscription can give them.
|
|
846
|
+
*/
|
|
847
|
+
private eventTransport(): EventTransport {
|
|
848
|
+
if (!this.subscriptionTransport) {
|
|
849
|
+
const send = <TReq, TRes>(message: Message<TReq>): AsyncIterable<ResponseItem<TRes>> => {
|
|
850
|
+
const metadata: Metadata = { ...this.defaultMetadata, ...(this.getEffectiveContext() as object) };
|
|
851
|
+
delete metadata["timeout"];
|
|
852
|
+
delete metadata[TIMEOUT_METADATA_KEY];
|
|
853
|
+
delete metadata[DEADLINE_METADATA_KEY];
|
|
854
|
+
metadata["timeout"] = NO_SUBSCRIPTION_TIMEOUT as unknown as NonNullable<Metadata["timeout"]>;
|
|
855
|
+
Object.assign(metadata, message.metadata);
|
|
856
|
+
absorbTimeout(metadata);
|
|
857
|
+
return this.composeMiddleware<TReq, TRes>()({ message: { ...message, metadata } });
|
|
858
|
+
};
|
|
859
|
+
this.subscriptionTransport = { send };
|
|
860
|
+
}
|
|
861
|
+
return this.subscriptionTransport;
|
|
862
|
+
}
|
|
863
|
+
|
|
782
864
|
/**
|
|
783
865
|
* Compose middleware chain using universal middleware composition.
|
|
784
866
|
*
|
|
@@ -84,6 +84,7 @@ const PROTOCOL_CATEGORIES: Readonly<Record<ProtocolErrorCode, ErrorCategory>> =
|
|
|
84
84
|
CONNECTION_CLOSED: ErrorCategory.NETWORK,
|
|
85
85
|
CONNECTION_NOT_FOUND: ErrorCategory.CLIENT,
|
|
86
86
|
TOPIC_NOT_FOUND: ErrorCategory.CLIENT,
|
|
87
|
+
TOPIC_CLEARED: ErrorCategory.CANCELLED,
|
|
87
88
|
};
|
|
88
89
|
|
|
89
90
|
/**
|
|
@@ -108,6 +108,10 @@ export interface RetryOptions {
|
|
|
108
108
|
/**
|
|
109
109
|
* Hook called after each retry completes (success or failure).
|
|
110
110
|
*
|
|
111
|
+
* The middleware calls it when the call ends: after the last item, or when the reader stops
|
|
112
|
+
* reading. A `Client` with `throwOnError` stops at the error item. Before, the hook then did
|
|
113
|
+
* not run, so it did not hear of a failure. A thrown error and an abort do not call it.
|
|
114
|
+
*
|
|
111
115
|
* @param success - Whether the retry succeeded
|
|
112
116
|
* @param attempt - Attempt number that just completed
|
|
113
117
|
*/
|
|
@@ -249,99 +253,106 @@ export function createRetryMiddleware(options: RetryOptions = {}): TypedClientMi
|
|
|
249
253
|
const idempotencyKey = idempotencyKeyOf(context.message.metadata) ?? newIdempotencyKey();
|
|
250
254
|
context.message.metadata[IDEMPOTENCY_KEY_METADATA] = idempotencyKey;
|
|
251
255
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
256
|
+
// The outcome of the call for onAfterRetry. The hook runs in `finally`: a reader that stops
|
|
257
|
+
// at an error item (a Client with throwOnError) closes this generator at its yield. Before,
|
|
258
|
+
// the hook came after the yield, so it did not hear of a failure.
|
|
259
|
+
let outcome: { success: boolean; attempt: number } | undefined;
|
|
260
|
+
try {
|
|
261
|
+
let attempt = 0;
|
|
262
|
+
for (;;) {
|
|
263
|
+
// Update retry metadata with current state
|
|
264
|
+
context.message.metadata.retry = {
|
|
265
|
+
...(typeof given === "object" && given !== null ? (given as object) : {}),
|
|
266
|
+
attempt,
|
|
267
|
+
maxAttempts: maxRetries + 1,
|
|
268
|
+
idempotent,
|
|
269
|
+
};
|
|
270
|
+
// Each attempt gets its own request id. The id correlates the frames of one attempt
|
|
271
|
+
// on the wire: a cancelled attempt can still answer under its id (deep dive TRN-8/9).
|
|
272
|
+
context.message.id = attempt === 0 ? baseId : `${baseId}.retry${attempt}`;
|
|
264
273
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
// Check if cancelled before attempt
|
|
275
|
+
if (signal?.aborted) {
|
|
276
|
+
yield abortedItem<TRes>(context.message.id);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
270
279
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
280
|
+
// The items pass through as they arrive (BUGS-2026-07 M2: before, the middleware
|
|
281
|
+
// collected the whole stream first). A retry is possible only while no item has
|
|
282
|
+
// reached the reader: the first item is a retryable error, or the attempt throws
|
|
283
|
+
// before its first item. After that, a retry would repeat items.
|
|
284
|
+
let started = false;
|
|
285
|
+
let lastItem: ResponseItem<TRes> | undefined;
|
|
286
|
+
let retryItem: ResponseItem<TRes> | undefined;
|
|
287
|
+
try {
|
|
288
|
+
for await (const item of next(context)) {
|
|
289
|
+
if (!started && attempt < maxRetries && shouldRetryItem(item, attempt)) {
|
|
290
|
+
retryItem = item;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
started = true;
|
|
294
|
+
lastItem = item;
|
|
295
|
+
outcome = { success: item.status.type === "success", attempt };
|
|
296
|
+
yield item;
|
|
283
297
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
298
|
+
} catch (error) {
|
|
299
|
+
// A thrown error does not call onAfterRetry
|
|
300
|
+
outcome = undefined;
|
|
301
|
+
const isAborted = signal?.aborted || (error instanceof Error && error.name === "AbortError");
|
|
302
|
+
if (started || isAborted || attempt >= maxRetries) {
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
// A thrown error is retried only when it is a network failure, or when shouldRetry
|
|
306
|
+
// says so. Before, every thrown error was retried: a validation error, an open
|
|
307
|
+
// circuit breaker, a rate limit (deep dive TRN-8).
|
|
308
|
+
const item = thrownItem<TRes>(context.message.id, error);
|
|
309
|
+
if (!shouldRetryItem(item, attempt)) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
retryItem = item;
|
|
292
313
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
throw error;
|
|
314
|
+
|
|
315
|
+
if (retryItem === undefined) {
|
|
316
|
+
// Success, a non-retryable error, or the last attempt
|
|
317
|
+
outcome = { success: lastItem?.status.type === "success", attempt };
|
|
318
|
+
return;
|
|
299
319
|
}
|
|
300
|
-
retryItem = item;
|
|
301
|
-
}
|
|
302
320
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
321
|
+
// The budget is empty: the error goes to the caller (R12)
|
|
322
|
+
if (!takeRetry()) {
|
|
323
|
+
outcome = { success: false, attempt };
|
|
324
|
+
yield retryItem;
|
|
325
|
+
return;
|
|
307
326
|
}
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
327
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
yield retryItem;
|
|
314
|
-
if (onAfterRetry) await onAfterRetry(false, attempt);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
328
|
+
// A server that asks for a wait (Retry-After) gets at least that wait (R12)
|
|
329
|
+
let delay = Math.max(retryDelayOf(attempt, overrides), retryAfterOf(retryItem) ?? 0);
|
|
317
330
|
|
|
318
|
-
|
|
319
|
-
|
|
331
|
+
// Before retry hook
|
|
332
|
+
if (onBeforeRetry) {
|
|
333
|
+
const hookResult = await onBeforeRetry(retryItem, attempt);
|
|
334
|
+
if (!hookResult.shouldRetry) {
|
|
335
|
+
// Hook decided not to retry - yield the error and return
|
|
336
|
+
outcome = { success: false, attempt };
|
|
337
|
+
yield retryItem;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
320
340
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (!hookResult.shouldRetry) {
|
|
325
|
-
// Hook decided not to retry - yield the error and return
|
|
326
|
-
yield retryItem;
|
|
327
|
-
if (onAfterRetry) {
|
|
328
|
-
await onAfterRetry(false, attempt);
|
|
341
|
+
// Use custom delay if provided by hook
|
|
342
|
+
if (hookResult.delayMs !== undefined) {
|
|
343
|
+
delay = hookResult.delayMs;
|
|
329
344
|
}
|
|
330
|
-
return;
|
|
331
345
|
}
|
|
332
346
|
|
|
333
|
-
//
|
|
334
|
-
if (
|
|
335
|
-
|
|
347
|
+
// The backoff stops at once when the caller aborts (deep dive TRN-8)
|
|
348
|
+
if (!(await sleep(delay, signal, clock))) {
|
|
349
|
+
yield abortedItem<TRes>(context.message.id);
|
|
350
|
+
return;
|
|
336
351
|
}
|
|
352
|
+
attempt++;
|
|
337
353
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (!(await sleep(delay, signal, clock))) {
|
|
341
|
-
yield abortedItem<TRes>(context.message.id);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
attempt++;
|
|
354
|
+
} finally {
|
|
355
|
+
if (outcome && onAfterRetry) await onAfterRetry(outcome.success, outcome.attempt);
|
|
345
356
|
}
|
|
346
357
|
};
|
|
347
358
|
};
|