@procedures/client 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +832 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/adapters/http/client/index.d.ts +11 -0
- package/dist/adapters/http/client/index.d.ts.map +1 -0
- package/dist/adapters/http/client/index.js +18 -0
- package/dist/adapters/http/client/index.js.map +1 -0
- package/dist/adapters/http/client/transport.d.ts +72 -0
- package/dist/adapters/http/client/transport.d.ts.map +1 -0
- package/dist/adapters/http/client/transport.js +282 -0
- package/dist/adapters/http/client/transport.js.map +1 -0
- package/dist/adapters/http/client/types.d.ts +27 -0
- package/dist/adapters/http/client/types.d.ts.map +1 -0
- package/dist/adapters/http/client/types.js +8 -0
- package/dist/adapters/http/client/types.js.map +1 -0
- package/dist/adapters/http/index.d.ts +7 -0
- package/dist/adapters/http/index.d.ts.map +1 -0
- package/dist/adapters/http/index.js +7 -0
- package/dist/adapters/http/index.js.map +1 -0
- package/dist/adapters/http/server/index.d.ts +9 -0
- package/dist/adapters/http/server/index.d.ts.map +1 -0
- package/dist/adapters/http/server/index.js +10 -0
- package/dist/adapters/http/server/index.js.map +1 -0
- package/dist/adapters/http/server/strategies.d.ts +39 -0
- package/dist/adapters/http/server/strategies.d.ts.map +1 -0
- package/dist/adapters/http/server/strategies.js +90 -0
- package/dist/adapters/http/server/strategies.js.map +1 -0
- package/dist/adapters/http/server/transport.d.ts +66 -0
- package/dist/adapters/http/server/transport.d.ts.map +1 -0
- package/dist/adapters/http/server/transport.js +561 -0
- package/dist/adapters/http/server/transport.js.map +1 -0
- package/dist/adapters/http/server/types.d.ts +71 -0
- package/dist/adapters/http/server/types.d.ts.map +1 -0
- package/dist/adapters/http/server/types.js +7 -0
- package/dist/adapters/http/server/types.js.map +1 -0
- package/dist/adapters/http/shared/constants.d.ts +95 -0
- package/dist/adapters/http/shared/constants.d.ts.map +1 -0
- package/dist/adapters/http/shared/constants.js +102 -0
- package/dist/adapters/http/shared/constants.js.map +1 -0
- package/dist/adapters/http/shared/errors.d.ts +78 -0
- package/dist/adapters/http/shared/errors.d.ts.map +1 -0
- package/dist/adapters/http/shared/errors.js +151 -0
- package/dist/adapters/http/shared/errors.js.map +1 -0
- package/dist/adapters/http/shared/headers.d.ts +122 -0
- package/dist/adapters/http/shared/headers.d.ts.map +1 -0
- package/dist/adapters/http/shared/headers.js +216 -0
- package/dist/adapters/http/shared/headers.js.map +1 -0
- package/dist/adapters/http/shared/index.d.ts +12 -0
- package/dist/adapters/http/shared/index.d.ts.map +1 -0
- package/dist/adapters/http/shared/index.js +17 -0
- package/dist/adapters/http/shared/index.js.map +1 -0
- package/dist/adapters/http/shared/status-codes.d.ts +92 -0
- package/dist/adapters/http/shared/status-codes.d.ts.map +1 -0
- package/dist/adapters/http/shared/status-codes.js +189 -0
- package/dist/adapters/http/shared/status-codes.js.map +1 -0
- package/dist/adapters/http/shared/strategies.d.ts +90 -0
- package/dist/adapters/http/shared/strategies.d.ts.map +1 -0
- package/dist/adapters/http/shared/strategies.js +180 -0
- package/dist/adapters/http/shared/strategies.js.map +1 -0
- package/dist/adapters/local/client/index.d.ts +8 -0
- package/dist/adapters/local/client/index.d.ts.map +1 -0
- package/dist/adapters/local/client/index.js +8 -0
- package/dist/adapters/local/client/index.js.map +1 -0
- package/dist/adapters/local/client/transport.d.ts +81 -0
- package/dist/adapters/local/client/transport.d.ts.map +1 -0
- package/dist/adapters/local/client/transport.js +172 -0
- package/dist/adapters/local/client/transport.js.map +1 -0
- package/dist/adapters/local/client/types.d.ts +39 -0
- package/dist/adapters/local/client/types.d.ts.map +1 -0
- package/dist/adapters/local/client/types.js +13 -0
- package/dist/adapters/local/client/types.js.map +1 -0
- package/dist/adapters/metadata.d.ts +10 -0
- package/dist/adapters/metadata.d.ts.map +1 -0
- package/dist/adapters/metadata.js +19 -0
- package/dist/adapters/metadata.js.map +1 -0
- package/dist/adapters/mock/client/builder.d.ts +35 -0
- package/dist/adapters/mock/client/builder.d.ts.map +1 -0
- package/dist/adapters/mock/client/builder.js +58 -0
- package/dist/adapters/mock/client/builder.js.map +1 -0
- package/dist/adapters/mock/client/index.d.ts +9 -0
- package/dist/adapters/mock/client/index.d.ts.map +1 -0
- package/dist/adapters/mock/client/index.js +10 -0
- package/dist/adapters/mock/client/index.js.map +1 -0
- package/dist/adapters/mock/client/transport.d.ts +149 -0
- package/dist/adapters/mock/client/transport.d.ts.map +1 -0
- package/dist/adapters/mock/client/transport.js +289 -0
- package/dist/adapters/mock/client/transport.js.map +1 -0
- package/dist/adapters/mock/client/types.d.ts +86 -0
- package/dist/adapters/mock/client/types.d.ts.map +1 -0
- package/dist/adapters/mock/client/types.js +7 -0
- package/dist/adapters/mock/client/types.js.map +1 -0
- package/dist/adapters/websocket/client/index.d.ts +9 -0
- package/dist/adapters/websocket/client/index.d.ts.map +1 -0
- package/dist/adapters/websocket/client/index.js +9 -0
- package/dist/adapters/websocket/client/index.js.map +1 -0
- package/dist/adapters/websocket/client/transport.d.ts +106 -0
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -0
- package/dist/adapters/websocket/client/transport.js +647 -0
- package/dist/adapters/websocket/client/transport.js.map +1 -0
- package/dist/adapters/websocket/client/types.d.ts +192 -0
- package/dist/adapters/websocket/client/types.d.ts.map +1 -0
- package/dist/adapters/websocket/client/types.js +17 -0
- package/dist/adapters/websocket/client/types.js.map +1 -0
- package/dist/adapters/websocket/index.d.ts +8 -0
- package/dist/adapters/websocket/index.d.ts.map +1 -0
- package/dist/adapters/websocket/index.js +8 -0
- package/dist/adapters/websocket/index.js.map +1 -0
- package/dist/adapters/websocket/server/index.d.ts +8 -0
- package/dist/adapters/websocket/server/index.d.ts.map +1 -0
- package/dist/adapters/websocket/server/index.js +8 -0
- package/dist/adapters/websocket/server/index.js.map +1 -0
- package/dist/adapters/websocket/server/transport.d.ts +112 -0
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -0
- package/dist/adapters/websocket/server/transport.js +619 -0
- package/dist/adapters/websocket/server/transport.js.map +1 -0
- package/dist/adapters/websocket/server/types.d.ts +140 -0
- package/dist/adapters/websocket/server/types.d.ts.map +1 -0
- package/dist/adapters/websocket/server/types.js +7 -0
- package/dist/adapters/websocket/server/types.js.map +1 -0
- package/dist/browser.d.ts +48 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +86 -0
- package/dist/browser.js.map +1 -0
- package/dist/client/batch-executor.d.ts +160 -0
- package/dist/client/batch-executor.d.ts.map +1 -0
- package/dist/client/batch-executor.js +397 -0
- package/dist/client/batch-executor.js.map +1 -0
- package/dist/client/call-types.d.ts +271 -0
- package/dist/client/call-types.d.ts.map +1 -0
- package/dist/client/call-types.js +208 -0
- package/dist/client/call-types.js.map +1 -0
- package/dist/client/client.d.ts +517 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +990 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/consumption.d.ts +191 -0
- package/dist/client/consumption.d.ts.map +1 -0
- package/dist/client/consumption.js +98 -0
- package/dist/client/consumption.js.map +1 -0
- package/dist/client/context.d.ts +116 -0
- package/dist/client/context.d.ts.map +1 -0
- package/dist/client/context.js +111 -0
- package/dist/client/context.js.map +1 -0
- package/dist/client/errors/codes.d.ts +71 -0
- package/dist/client/errors/codes.d.ts.map +1 -0
- package/dist/client/errors/codes.js +81 -0
- package/dist/client/errors/codes.js.map +1 -0
- package/dist/client/errors/factory.d.ts +102 -0
- package/dist/client/errors/factory.d.ts.map +1 -0
- package/dist/client/errors/factory.js +210 -0
- package/dist/client/errors/factory.js.map +1 -0
- package/dist/client/errors/http-errors.d.ts +47 -0
- package/dist/client/errors/http-errors.d.ts.map +1 -0
- package/dist/client/errors/http-errors.js +548 -0
- package/dist/client/errors/http-errors.js.map +1 -0
- package/dist/client/errors/http-status.d.ts +73 -0
- package/dist/client/errors/http-status.d.ts.map +1 -0
- package/dist/client/errors/http-status.js +79 -0
- package/dist/client/errors/http-status.js.map +1 -0
- package/dist/client/errors/index.d.ts +36 -0
- package/dist/client/errors/index.d.ts.map +1 -0
- package/dist/client/errors/index.js +40 -0
- package/dist/client/errors/index.js.map +1 -0
- package/dist/client/errors/registry.d.ts +38 -0
- package/dist/client/errors/registry.d.ts.map +1 -0
- package/dist/client/errors/registry.js +535 -0
- package/dist/client/errors/registry.js.map +1 -0
- package/dist/client/errors/types.d.ts +112 -0
- package/dist/client/errors/types.d.ts.map +1 -0
- package/dist/client/errors/types.js +45 -0
- package/dist/client/errors/types.js.map +1 -0
- package/dist/client/index.d.ts +44 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +36 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/middleware/auth.d.ts +90 -0
- package/dist/client/middleware/auth.d.ts.map +1 -0
- package/dist/client/middleware/auth.js +98 -0
- package/dist/client/middleware/auth.js.map +1 -0
- package/dist/client/middleware/batching.d.ts +102 -0
- package/dist/client/middleware/batching.d.ts.map +1 -0
- package/dist/client/middleware/batching.js +245 -0
- package/dist/client/middleware/batching.js.map +1 -0
- package/dist/client/middleware/cache.d.ts +124 -0
- package/dist/client/middleware/cache.d.ts.map +1 -0
- package/dist/client/middleware/cache.js +208 -0
- package/dist/client/middleware/cache.js.map +1 -0
- package/dist/client/middleware/circuit-breaker.d.ts +113 -0
- package/dist/client/middleware/circuit-breaker.d.ts.map +1 -0
- package/dist/client/middleware/circuit-breaker.js +236 -0
- package/dist/client/middleware/circuit-breaker.js.map +1 -0
- package/dist/client/middleware/contexts.d.ts +199 -0
- package/dist/client/middleware/contexts.d.ts.map +1 -0
- package/dist/client/middleware/contexts.js +74 -0
- package/dist/client/middleware/contexts.js.map +1 -0
- package/dist/client/middleware/items.d.ts +37 -0
- package/dist/client/middleware/items.d.ts.map +1 -0
- package/dist/client/middleware/items.js +100 -0
- package/dist/client/middleware/items.js.map +1 -0
- package/dist/client/middleware/lru.d.ts +32 -0
- package/dist/client/middleware/lru.d.ts.map +1 -0
- package/dist/client/middleware/lru.js +62 -0
- package/dist/client/middleware/lru.js.map +1 -0
- package/dist/client/middleware/pagination.d.ts +114 -0
- package/dist/client/middleware/pagination.d.ts.map +1 -0
- package/dist/client/middleware/pagination.js +148 -0
- package/dist/client/middleware/pagination.js.map +1 -0
- package/dist/client/middleware/rate-limit.d.ts +105 -0
- package/dist/client/middleware/rate-limit.d.ts.map +1 -0
- package/dist/client/middleware/rate-limit.js +222 -0
- package/dist/client/middleware/rate-limit.js.map +1 -0
- package/dist/client/middleware/retry.d.ts +100 -0
- package/dist/client/middleware/retry.d.ts.map +1 -0
- package/dist/client/middleware/retry.js +150 -0
- package/dist/client/middleware/retry.js.map +1 -0
- package/dist/client/middleware/timeout.d.ts +91 -0
- package/dist/client/middleware/timeout.d.ts.map +1 -0
- package/dist/client/middleware/timeout.js +253 -0
- package/dist/client/middleware/timeout.js.map +1 -0
- package/dist/client/middleware/tracing.d.ts +118 -0
- package/dist/client/middleware/tracing.d.ts.map +1 -0
- package/dist/client/middleware/tracing.js +152 -0
- package/dist/client/middleware/tracing.js.map +1 -0
- package/dist/client/route-resolver.d.ts +181 -0
- package/dist/client/route-resolver.d.ts.map +1 -0
- package/dist/client/route-resolver.js +300 -0
- package/dist/client/route-resolver.js.map +1 -0
- package/dist/client/typed-method.d.ts +29 -0
- package/dist/client/typed-method.d.ts.map +1 -0
- package/dist/client/typed-method.js +36 -0
- package/dist/client/typed-method.js.map +1 -0
- package/dist/client/typed.d.ts +102 -0
- package/dist/client/typed.d.ts.map +1 -0
- package/dist/client/typed.js +52 -0
- package/dist/client/typed.js.map +1 -0
- package/dist/client/types.d.ts +296 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +26 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/validation/index.d.ts +34 -0
- package/dist/client/validation/index.d.ts.map +1 -0
- package/dist/client/validation/index.js +36 -0
- package/dist/client/validation/index.js.map +1 -0
- package/dist/client/validation/middleware.d.ts +82 -0
- package/dist/client/validation/middleware.d.ts.map +1 -0
- package/dist/client/validation/middleware.js +138 -0
- package/dist/client/validation/middleware.js.map +1 -0
- package/dist/client/validation/types.d.ts +118 -0
- package/dist/client/validation/types.d.ts.map +1 -0
- package/dist/client/validation/types.js +59 -0
- package/dist/client/validation/types.js.map +1 -0
- package/dist/collections/async/async-queue.d.ts +144 -0
- package/dist/collections/async/async-queue.d.ts.map +1 -0
- package/dist/collections/async/async-queue.js +347 -0
- package/dist/collections/async/async-queue.js.map +1 -0
- package/dist/collections/async/channels.d.ts +188 -0
- package/dist/collections/async/channels.d.ts.map +1 -0
- package/dist/collections/async/channels.js +312 -0
- package/dist/collections/async/channels.js.map +1 -0
- package/dist/collections/behaviors/bounded.d.ts +79 -0
- package/dist/collections/behaviors/bounded.d.ts.map +1 -0
- package/dist/collections/behaviors/bounded.js +384 -0
- package/dist/collections/behaviors/bounded.js.map +1 -0
- package/dist/collections/behaviors/evented.d.ts +154 -0
- package/dist/collections/behaviors/evented.d.ts.map +1 -0
- package/dist/collections/behaviors/evented.js +299 -0
- package/dist/collections/behaviors/evented.js.map +1 -0
- package/dist/collections/behaviors/lru.d.ts +84 -0
- package/dist/collections/behaviors/lru.d.ts.map +1 -0
- package/dist/collections/behaviors/lru.js +330 -0
- package/dist/collections/behaviors/lru.js.map +1 -0
- package/dist/collections/behaviors/readonly.d.ts +73 -0
- package/dist/collections/behaviors/readonly.d.ts.map +1 -0
- package/dist/collections/behaviors/readonly.js +158 -0
- package/dist/collections/behaviors/readonly.js.map +1 -0
- package/dist/collections/behaviors/safe.d.ts +163 -0
- package/dist/collections/behaviors/safe.d.ts.map +1 -0
- package/dist/collections/behaviors/safe.js +172 -0
- package/dist/collections/behaviors/safe.js.map +1 -0
- package/dist/collections/behaviors/synchronized.d.ts +88 -0
- package/dist/collections/behaviors/synchronized.d.ts.map +1 -0
- package/dist/collections/behaviors/synchronized.js +294 -0
- package/dist/collections/behaviors/synchronized.js.map +1 -0
- package/dist/collections/behaviors/ttl.d.ts +118 -0
- package/dist/collections/behaviors/ttl.d.ts.map +1 -0
- package/dist/collections/behaviors/ttl.js +338 -0
- package/dist/collections/behaviors/ttl.js.map +1 -0
- package/dist/collections/core/effects.d.ts +176 -0
- package/dist/collections/core/effects.d.ts.map +1 -0
- package/dist/collections/core/effects.js +180 -0
- package/dist/collections/core/effects.js.map +1 -0
- package/dist/collections/core/events.d.ts +192 -0
- package/dist/collections/core/events.d.ts.map +1 -0
- package/dist/collections/core/events.js +291 -0
- package/dist/collections/core/events.js.map +1 -0
- package/dist/collections/core/middleware.d.ts +231 -0
- package/dist/collections/core/middleware.d.ts.map +1 -0
- package/dist/collections/core/middleware.js +161 -0
- package/dist/collections/core/middleware.js.map +1 -0
- package/dist/collections/core/policies.d.ts +220 -0
- package/dist/collections/core/policies.d.ts.map +1 -0
- package/dist/collections/core/policies.js +48 -0
- package/dist/collections/core/policies.js.map +1 -0
- package/dist/collections/core/traits.d.ts +142 -0
- package/dist/collections/core/traits.d.ts.map +1 -0
- package/dist/collections/core/traits.js +8 -0
- package/dist/collections/core/traits.js.map +1 -0
- package/dist/collections/examples.d.ts +13 -0
- package/dist/collections/examples.d.ts.map +1 -0
- package/dist/collections/examples.js +302 -0
- package/dist/collections/examples.js.map +1 -0
- package/dist/collections/fx/collectors.d.ts +190 -0
- package/dist/collections/fx/collectors.d.ts.map +1 -0
- package/dist/collections/fx/collectors.js +369 -0
- package/dist/collections/fx/collectors.js.map +1 -0
- package/dist/collections/fx/iter.d.ts +166 -0
- package/dist/collections/fx/iter.d.ts.map +1 -0
- package/dist/collections/fx/iter.js +421 -0
- package/dist/collections/fx/iter.js.map +1 -0
- package/dist/collections/impl/array-deque.d.ts +107 -0
- package/dist/collections/impl/array-deque.d.ts.map +1 -0
- package/dist/collections/impl/array-deque.js +381 -0
- package/dist/collections/impl/array-deque.js.map +1 -0
- package/dist/collections/impl/array-list.d.ts +101 -0
- package/dist/collections/impl/array-list.d.ts.map +1 -0
- package/dist/collections/impl/array-list.js +387 -0
- package/dist/collections/impl/array-list.js.map +1 -0
- package/dist/collections/impl/hash-map.d.ts +141 -0
- package/dist/collections/impl/hash-map.d.ts.map +1 -0
- package/dist/collections/impl/hash-map.js +450 -0
- package/dist/collections/impl/hash-map.js.map +1 -0
- package/dist/collections/impl/hash-set.d.ts +125 -0
- package/dist/collections/impl/hash-set.d.ts.map +1 -0
- package/dist/collections/impl/hash-set.js +264 -0
- package/dist/collections/impl/hash-set.js.map +1 -0
- package/dist/collections/impl/linked-hash-map.d.ts +141 -0
- package/dist/collections/impl/linked-hash-map.d.ts.map +1 -0
- package/dist/collections/impl/linked-hash-map.js +472 -0
- package/dist/collections/impl/linked-hash-map.js.map +1 -0
- package/dist/collections/impl/linked-list.d.ts +109 -0
- package/dist/collections/impl/linked-list.d.ts.map +1 -0
- package/dist/collections/impl/linked-list.js +491 -0
- package/dist/collections/impl/linked-list.js.map +1 -0
- package/dist/collections/impl/priority-queue.d.ts +134 -0
- package/dist/collections/impl/priority-queue.d.ts.map +1 -0
- package/dist/collections/impl/priority-queue.js +336 -0
- package/dist/collections/impl/priority-queue.js.map +1 -0
- package/dist/collections/impl/tree-map.d.ts +146 -0
- package/dist/collections/impl/tree-map.d.ts.map +1 -0
- package/dist/collections/impl/tree-map.js +781 -0
- package/dist/collections/impl/tree-map.js.map +1 -0
- package/dist/collections/impl/tree-set.d.ts +112 -0
- package/dist/collections/impl/tree-set.d.ts.map +1 -0
- package/dist/collections/impl/tree-set.js +374 -0
- package/dist/collections/impl/tree-set.js.map +1 -0
- package/dist/collections/index.d.ts +105 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +135 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/interfaces/collection.d.ts +119 -0
- package/dist/collections/interfaces/collection.d.ts.map +1 -0
- package/dist/collections/interfaces/collection.js +8 -0
- package/dist/collections/interfaces/collection.js.map +1 -0
- package/dist/collections/interfaces/list.d.ts +247 -0
- package/dist/collections/interfaces/list.d.ts.map +1 -0
- package/dist/collections/interfaces/list.js +8 -0
- package/dist/collections/interfaces/list.js.map +1 -0
- package/dist/collections/interfaces/map.d.ts +344 -0
- package/dist/collections/interfaces/map.d.ts.map +1 -0
- package/dist/collections/interfaces/map.js +8 -0
- package/dist/collections/interfaces/map.js.map +1 -0
- package/dist/collections/interfaces/queue.d.ts +304 -0
- package/dist/collections/interfaces/queue.d.ts.map +1 -0
- package/dist/collections/interfaces/queue.js +8 -0
- package/dist/collections/interfaces/queue.js.map +1 -0
- package/dist/collections/interfaces/set.d.ts +137 -0
- package/dist/collections/interfaces/set.d.ts.map +1 -0
- package/dist/collections/interfaces/set.js +8 -0
- package/dist/collections/interfaces/set.js.map +1 -0
- package/dist/collections/storage/api.d.ts +109 -0
- package/dist/collections/storage/api.d.ts.map +1 -0
- package/dist/collections/storage/api.js +182 -0
- package/dist/collections/storage/api.js.map +1 -0
- package/dist/collections/storage/hybrid.d.ts +164 -0
- package/dist/collections/storage/hybrid.d.ts.map +1 -0
- package/dist/collections/storage/hybrid.js +416 -0
- package/dist/collections/storage/hybrid.js.map +1 -0
- package/dist/collections/storage/index.d.ts +16 -0
- package/dist/collections/storage/index.d.ts.map +1 -0
- package/dist/collections/storage/index.js +13 -0
- package/dist/collections/storage/index.js.map +1 -0
- package/dist/collections/storage/interface.d.ts +141 -0
- package/dist/collections/storage/interface.d.ts.map +1 -0
- package/dist/collections/storage/interface.js +23 -0
- package/dist/collections/storage/interface.js.map +1 -0
- package/dist/collections/storage/memory.d.ts +68 -0
- package/dist/collections/storage/memory.d.ts.map +1 -0
- package/dist/collections/storage/memory.js +154 -0
- package/dist/collections/storage/memory.js.map +1 -0
- package/dist/collections/utils/defaults.d.ts +135 -0
- package/dist/collections/utils/defaults.d.ts.map +1 -0
- package/dist/collections/utils/defaults.js +322 -0
- package/dist/collections/utils/defaults.js.map +1 -0
- package/dist/collections/utils/factories.d.ts +144 -0
- package/dist/collections/utils/factories.d.ts.map +1 -0
- package/dist/collections/utils/factories.js +293 -0
- package/dist/collections/utils/factories.js.map +1 -0
- package/dist/collections/utils/helpers.d.ts +137 -0
- package/dist/collections/utils/helpers.d.ts.map +1 -0
- package/dist/collections/utils/helpers.js +221 -0
- package/dist/collections/utils/helpers.js.map +1 -0
- package/dist/collections.d.ts +12 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +10 -0
- package/dist/collections.js.map +1 -0
- package/dist/components/define.d.ts +134 -0
- package/dist/components/define.d.ts.map +1 -0
- package/dist/components/define.js +486 -0
- package/dist/components/define.js.map +1 -0
- package/dist/components/index.d.ts +39 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +38 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/types.d.ts +264 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +46 -0
- package/dist/components/types.js.map +1 -0
- package/dist/events/bus.d.ts +193 -0
- package/dist/events/bus.d.ts.map +1 -0
- package/dist/events/bus.js +511 -0
- package/dist/events/bus.js.map +1 -0
- package/dist/events/index.d.ts +34 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +36 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/types.d.ts +242 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +8 -0
- package/dist/events/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/compose.d.ts +88 -0
- package/dist/middleware/compose.d.ts.map +1 -0
- package/dist/middleware/compose.js +108 -0
- package/dist/middleware/compose.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/types.d.ts +112 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +14 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/procedures/cli/announce.d.ts +67 -0
- package/dist/procedures/cli/announce.d.ts.map +1 -0
- package/dist/procedures/cli/announce.js +392 -0
- package/dist/procedures/cli/announce.js.map +1 -0
- package/dist/procedures/cli/discover.d.ts +66 -0
- package/dist/procedures/cli/discover.d.ts.map +1 -0
- package/dist/procedures/cli/discover.js +310 -0
- package/dist/procedures/cli/discover.js.map +1 -0
- package/dist/procedures/cli/index.d.ts +13 -0
- package/dist/procedures/cli/index.d.ts.map +1 -0
- package/dist/procedures/cli/index.js +201 -0
- package/dist/procedures/cli/index.js.map +1 -0
- package/dist/procedures/cli/init.d.ts +17 -0
- package/dist/procedures/cli/init.d.ts.map +1 -0
- package/dist/procedures/cli/init.js +336 -0
- package/dist/procedures/cli/init.js.map +1 -0
- package/dist/procedures/collection/index.d.ts +10 -0
- package/dist/procedures/collection/index.d.ts.map +1 -0
- package/dist/procedures/collection/index.js +10 -0
- package/dist/procedures/collection/index.js.map +1 -0
- package/dist/procedures/collection/procedures.d.ts +21 -0
- package/dist/procedures/collection/procedures.d.ts.map +1 -0
- package/dist/procedures/collection/procedures.js +198 -0
- package/dist/procedures/collection/procedures.js.map +1 -0
- package/dist/procedures/collection/schemas.d.ts +131 -0
- package/dist/procedures/collection/schemas.d.ts.map +1 -0
- package/dist/procedures/collection/schemas.js +422 -0
- package/dist/procedures/collection/schemas.js.map +1 -0
- package/dist/procedures/collection/storage.d.ts +53 -0
- package/dist/procedures/collection/storage.d.ts.map +1 -0
- package/dist/procedures/collection/storage.js +2 -0
- package/dist/procedures/collection/storage.js.map +1 -0
- package/dist/procedures/core/array.d.ts +276 -0
- package/dist/procedures/core/array.d.ts.map +1 -0
- package/dist/procedures/core/array.js +637 -0
- package/dist/procedures/core/array.js.map +1 -0
- package/dist/procedures/core/comparison.d.ts +85 -0
- package/dist/procedures/core/comparison.d.ts.map +1 -0
- package/dist/procedures/core/comparison.js +156 -0
- package/dist/procedures/core/comparison.js.map +1 -0
- package/dist/procedures/core/index.d.ts +261 -0
- package/dist/procedures/core/index.d.ts.map +1 -0
- package/dist/procedures/core/index.js +585 -0
- package/dist/procedures/core/index.js.map +1 -0
- package/dist/procedures/core/logic.d.ts +144 -0
- package/dist/procedures/core/logic.d.ts.map +1 -0
- package/dist/procedures/core/logic.js +169 -0
- package/dist/procedures/core/logic.js.map +1 -0
- package/dist/procedures/core/math.d.ts +139 -0
- package/dist/procedures/core/math.d.ts.map +1 -0
- package/dist/procedures/core/math.js +273 -0
- package/dist/procedures/core/math.js.map +1 -0
- package/dist/procedures/core/meta.d.ts +111 -0
- package/dist/procedures/core/meta.d.ts.map +1 -0
- package/dist/procedures/core/meta.js +239 -0
- package/dist/procedures/core/meta.js.map +1 -0
- package/dist/procedures/core/object.d.ts +109 -0
- package/dist/procedures/core/object.d.ts.map +1 -0
- package/dist/procedures/core/object.js +270 -0
- package/dist/procedures/core/object.js.map +1 -0
- package/dist/procedures/core/operands.d.ts +51 -0
- package/dist/procedures/core/operands.d.ts.map +1 -0
- package/dist/procedures/core/operands.js +90 -0
- package/dist/procedures/core/operands.js.map +1 -0
- package/dist/procedures/core/outputs.d.ts +28 -0
- package/dist/procedures/core/outputs.d.ts.map +1 -0
- package/dist/procedures/core/outputs.js +42 -0
- package/dist/procedures/core/outputs.js.map +1 -0
- package/dist/procedures/core/results.d.ts +202 -0
- package/dist/procedures/core/results.d.ts.map +1 -0
- package/dist/procedures/core/results.js +106 -0
- package/dist/procedures/core/results.js.map +1 -0
- package/dist/procedures/core/schemas.d.ts +48 -0
- package/dist/procedures/core/schemas.d.ts.map +1 -0
- package/dist/procedures/core/schemas.js +102 -0
- package/dist/procedures/core/schemas.js.map +1 -0
- package/dist/procedures/core/string.d.ts +138 -0
- package/dist/procedures/core/string.d.ts.map +1 -0
- package/dist/procedures/core/string.js +268 -0
- package/dist/procedures/core/string.js.map +1 -0
- package/dist/procedures/core/type.d.ts +101 -0
- package/dist/procedures/core/type.d.ts.map +1 -0
- package/dist/procedures/core/type.js +208 -0
- package/dist/procedures/core/type.js.map +1 -0
- package/dist/procedures/define-procedure.d.ts +187 -0
- package/dist/procedures/define-procedure.d.ts.map +1 -0
- package/dist/procedures/define-procedure.js +356 -0
- package/dist/procedures/define-procedure.js.map +1 -0
- package/dist/procedures/define.d.ts +228 -0
- package/dist/procedures/define.d.ts.map +1 -0
- package/dist/procedures/define.js +300 -0
- package/dist/procedures/define.js.map +1 -0
- package/dist/procedures/discovery.d.ts +57 -0
- package/dist/procedures/discovery.d.ts.map +1 -0
- package/dist/procedures/discovery.js +68 -0
- package/dist/procedures/discovery.js.map +1 -0
- package/dist/procedures/index.d.ts +24 -0
- package/dist/procedures/index.d.ts.map +1 -0
- package/dist/procedures/index.js +69 -0
- package/dist/procedures/index.js.map +1 -0
- package/dist/procedures/interceptors.d.ts +82 -0
- package/dist/procedures/interceptors.d.ts.map +1 -0
- package/dist/procedures/interceptors.js +193 -0
- package/dist/procedures/interceptors.js.map +1 -0
- package/dist/procedures/invoke.d.ts +127 -0
- package/dist/procedures/invoke.d.ts.map +1 -0
- package/dist/procedures/invoke.js +277 -0
- package/dist/procedures/invoke.js.map +1 -0
- package/dist/procedures/module.d.ts +49 -0
- package/dist/procedures/module.d.ts.map +1 -0
- package/dist/procedures/module.js +93 -0
- package/dist/procedures/module.js.map +1 -0
- package/dist/procedures/policy.d.ts +70 -0
- package/dist/procedures/policy.d.ts.map +1 -0
- package/dist/procedures/policy.js +138 -0
- package/dist/procedures/policy.js.map +1 -0
- package/dist/procedures/ref.d.ts +606 -0
- package/dist/procedures/ref.d.ts.map +1 -0
- package/dist/procedures/ref.js +895 -0
- package/dist/procedures/ref.js.map +1 -0
- package/dist/procedures/registry.d.ts +208 -0
- package/dist/procedures/registry.d.ts.map +1 -0
- package/dist/procedures/registry.js +402 -0
- package/dist/procedures/registry.js.map +1 -0
- package/dist/procedures/schema.d.ts +126 -0
- package/dist/procedures/schema.d.ts.map +1 -0
- package/dist/procedures/schema.js +108 -0
- package/dist/procedures/schema.js.map +1 -0
- package/dist/procedures/storage/adapter.d.ts +148 -0
- package/dist/procedures/storage/adapter.d.ts.map +1 -0
- package/dist/procedures/storage/adapter.js +214 -0
- package/dist/procedures/storage/adapter.js.map +1 -0
- package/dist/procedures/storage/api.d.ts +125 -0
- package/dist/procedures/storage/api.d.ts.map +1 -0
- package/dist/procedures/storage/api.js +220 -0
- package/dist/procedures/storage/api.js.map +1 -0
- package/dist/procedures/storage/factory.d.ts +134 -0
- package/dist/procedures/storage/factory.d.ts.map +1 -0
- package/dist/procedures/storage/factory.js +166 -0
- package/dist/procedures/storage/factory.js.map +1 -0
- package/dist/procedures/storage/hybrid.d.ts +193 -0
- package/dist/procedures/storage/hybrid.d.ts.map +1 -0
- package/dist/procedures/storage/hybrid.js +519 -0
- package/dist/procedures/storage/hybrid.js.map +1 -0
- package/dist/procedures/storage/index.d.ts +17 -0
- package/dist/procedures/storage/index.d.ts.map +1 -0
- package/dist/procedures/storage/index.js +17 -0
- package/dist/procedures/storage/index.js.map +1 -0
- package/dist/procedures/storage/procedures.d.ts +39 -0
- package/dist/procedures/storage/procedures.d.ts.map +1 -0
- package/dist/procedures/storage/procedures.js +261 -0
- package/dist/procedures/storage/procedures.js.map +1 -0
- package/dist/procedures/storage/serialization.d.ts +123 -0
- package/dist/procedures/storage/serialization.d.ts.map +1 -0
- package/dist/procedures/storage/serialization.js +216 -0
- package/dist/procedures/storage/serialization.js.map +1 -0
- package/dist/procedures/storage/synced-registry.d.ts +246 -0
- package/dist/procedures/storage/synced-registry.d.ts.map +1 -0
- package/dist/procedures/storage/synced-registry.js +575 -0
- package/dist/procedures/storage/synced-registry.js.map +1 -0
- package/dist/procedures/storage/types.d.ts +130 -0
- package/dist/procedures/storage/types.d.ts.map +1 -0
- package/dist/procedures/storage/types.js +8 -0
- package/dist/procedures/storage/types.js.map +1 -0
- package/dist/procedures/types.d.ts +370 -0
- package/dist/procedures/types.d.ts.map +1 -0
- package/dist/procedures/types.js +23 -0
- package/dist/procedures/types.js.map +1 -0
- package/dist/server/browser-guard.d.ts +69 -0
- package/dist/server/browser-guard.d.ts.map +1 -0
- package/dist/server/browser-guard.js +103 -0
- package/dist/server/browser-guard.js.map +1 -0
- package/dist/server/host-policy.d.ts +59 -0
- package/dist/server/host-policy.d.ts.map +1 -0
- package/dist/server/host-policy.js +82 -0
- package/dist/server/host-policy.js.map +1 -0
- package/dist/server/index.d.ts +46 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +42 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/method.d.ts +24 -0
- package/dist/server/method.d.ts.map +1 -0
- package/dist/server/method.js +29 -0
- package/dist/server/method.js.map +1 -0
- package/dist/server/procedure-server.d.ts +212 -0
- package/dist/server/procedure-server.d.ts.map +1 -0
- package/dist/server/procedure-server.js +323 -0
- package/dist/server/procedure-server.js.map +1 -0
- package/dist/server/server.d.ts +161 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +279 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/types.d.ts +106 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +29 -0
- package/dist/server/types.js.map +1 -0
- package/package.json +115 -3
- package/src/adapters/http/client/index.ts +51 -0
- package/src/adapters/http/client/transport.ts +338 -0
- package/src/adapters/http/client/types.ts +33 -0
- package/src/adapters/http/index.ts +7 -0
- package/src/adapters/http/server/index.ts +14 -0
- package/src/adapters/http/server/strategies.ts +105 -0
- package/src/adapters/http/server/transport.ts +622 -0
- package/src/adapters/http/server/types.ts +81 -0
- package/src/adapters/http/shared/constants.ts +108 -0
- package/src/adapters/http/shared/errors.ts +199 -0
- package/src/adapters/http/shared/headers.ts +291 -0
- package/src/adapters/http/shared/index.ts +21 -0
- package/src/adapters/http/shared/status-codes.ts +212 -0
- package/src/adapters/http/shared/strategies.ts +255 -0
- package/src/adapters/local/client/index.ts +11 -0
- package/src/adapters/local/client/transport.ts +188 -0
- package/src/adapters/local/client/types.ts +50 -0
- package/src/adapters/metadata.ts +17 -0
- package/src/adapters/mock/client/builder.ts +64 -0
- package/src/adapters/mock/client/index.ts +19 -0
- package/src/adapters/mock/client/transport.ts +352 -0
- package/src/adapters/mock/client/types.ts +99 -0
- package/src/adapters/websocket/client/index.ts +18 -0
- package/src/adapters/websocket/client/transport.ts +733 -0
- package/src/adapters/websocket/client/types.ts +235 -0
- package/src/adapters/websocket/index.ts +24 -0
- package/src/adapters/websocket/server/index.ts +18 -0
- package/src/adapters/websocket/server/transport.ts +705 -0
- package/src/adapters/websocket/server/types.ts +169 -0
- package/src/browser.ts +373 -0
- package/src/client/batch-executor.ts +514 -0
- package/src/client/call-types.ts +491 -0
- package/src/client/client.ts +1202 -0
- package/src/client/consumption.ts +288 -0
- package/src/client/context.ts +228 -0
- package/src/client/errors/README.md +279 -0
- package/src/client/errors/codes.ts +88 -0
- package/src/client/errors/factory.ts +263 -0
- package/src/client/errors/http-errors.ts +601 -0
- package/src/client/errors/http-status.ts +82 -0
- package/src/client/errors/index.ts +72 -0
- package/src/client/errors/registry.ts +595 -0
- package/src/client/errors/types.ts +139 -0
- package/src/client/index.ts +124 -0
- package/src/client/middleware/auth.ts +132 -0
- package/src/client/middleware/cache.ts +316 -0
- package/src/client/middleware/circuit-breaker.ts +339 -0
- package/src/client/middleware/contexts.ts +319 -0
- package/src/client/middleware/items.ts +114 -0
- package/src/client/middleware/lru.ts +66 -0
- package/src/client/middleware/pagination.ts +213 -0
- package/src/client/middleware/rate-limit.ts +315 -0
- package/src/client/middleware/retry.ts +236 -0
- package/src/client/middleware/timeout.ts +308 -0
- package/src/client/middleware/tracing.ts +191 -0
- package/src/client/route-resolver.ts +407 -0
- package/src/client/typed-method.ts +65 -0
- package/src/client/typed.ts +140 -0
- package/src/client/types.ts +361 -0
- package/src/client/validation/index.ts +56 -0
- package/src/client/validation/middleware.ts +254 -0
- package/src/client/validation/types.ts +162 -0
- package/src/events/bus.ts +594 -0
- package/src/events/index.ts +67 -0
- package/src/events/types.ts +263 -0
- package/src/index.ts +33 -0
- package/src/middleware/compose.ts +159 -0
- package/src/middleware/index.ts +28 -0
- package/src/middleware/types.ts +166 -0
- package/src/procedures/cli/announce.ts +470 -0
- package/src/procedures/cli/discover.ts +390 -0
- package/src/procedures/cli/index.ts +229 -0
- package/src/procedures/cli/init.ts +370 -0
- package/src/procedures/collection/index.ts +51 -0
- package/src/procedures/collection/procedures.ts +245 -0
- package/src/procedures/collection/schemas.ts +550 -0
- package/src/procedures/collection/storage.ts +53 -0
- package/src/procedures/core/array.ts +1024 -0
- package/src/procedures/core/comparison.ts +263 -0
- package/src/procedures/core/index.ts +895 -0
- package/src/procedures/core/logic.ts +225 -0
- package/src/procedures/core/math.ts +469 -0
- package/src/procedures/core/meta.ts +384 -0
- package/src/procedures/core/object.ts +427 -0
- package/src/procedures/core/operands.ts +119 -0
- package/src/procedures/core/outputs.ts +48 -0
- package/src/procedures/core/results.ts +296 -0
- package/src/procedures/core/schemas.ts +123 -0
- package/src/procedures/core/string.ts +458 -0
- package/src/procedures/core/type.ts +344 -0
- package/src/procedures/define-procedure.ts +531 -0
- package/src/procedures/define.ts +387 -0
- package/src/procedures/discovery.ts +76 -0
- package/src/procedures/index.ts +228 -0
- package/src/procedures/interceptors.ts +272 -0
- package/src/procedures/invoke.ts +413 -0
- package/src/procedures/module.ts +107 -0
- package/src/procedures/policy.ts +171 -0
- package/src/procedures/ref.ts +1305 -0
- package/src/procedures/registry.ts +473 -0
- package/src/procedures/schema.ts +225 -0
- package/src/procedures/types.ts +485 -0
- package/src/server/browser-guard.ts +147 -0
- package/src/server/host-policy.ts +121 -0
- package/src/server/index.ts +70 -0
- package/src/server/method.ts +33 -0
- package/src/server/procedure-server.ts +417 -0
- package/src/server/server.ts +364 -0
- package/src/server/types.ts +147 -0
|
@@ -0,0 +1,1202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal Client
|
|
3
|
+
*
|
|
4
|
+
* Protocol-agnostic RPC client with middleware composition.
|
|
5
|
+
* Works with any transport: HTTP, gRPC, WebSocket, or local.
|
|
6
|
+
*
|
|
7
|
+
* The Client class is generic over its accumulated context type, enabling
|
|
8
|
+
* compile-time validation of middleware chains. Each call to `use()` returns
|
|
9
|
+
* a new type that includes the middleware's provided context.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Type accumulates as middleware is added
|
|
14
|
+
* const client = new Client(transport)
|
|
15
|
+
* .use(createRetryMiddleware()) // Client<BaseContext & RetryContext>
|
|
16
|
+
* .use(createCacheMiddleware({ methods: ["users.get"] })) // Client<... & CacheContext>
|
|
17
|
+
* .use(createAuthMiddleware(...)) // Client<... & AuthContext>
|
|
18
|
+
*
|
|
19
|
+
* // Middleware requiring context validates at compile time
|
|
20
|
+
* client.use(middlewareThatRequiresAuth); // OK if AuthContext is in chain
|
|
21
|
+
*
|
|
22
|
+
* // Context passing via withContext() and per-call options
|
|
23
|
+
* const authedClient = client.withContext({ auth: { token: "user-token" } });
|
|
24
|
+
* await authedClient.call(method, payload, { context: { retry: { maxAttempts: 5 } } });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
Transport,
|
|
30
|
+
Method,
|
|
31
|
+
Metadata,
|
|
32
|
+
Message,
|
|
33
|
+
ClientMiddleware,
|
|
34
|
+
ClientContext,
|
|
35
|
+
ClientRunner,
|
|
36
|
+
ClientOptions,
|
|
37
|
+
TypedClientMiddleware,
|
|
38
|
+
} from "./types.js";
|
|
39
|
+
import { ClientError } from "./types.js";
|
|
40
|
+
import { compose } from "../middleware/compose.js";
|
|
41
|
+
import { pathToMethod } from "../server/method.js";
|
|
42
|
+
import type { CallOptions, ClientContextInput } from "./context.js";
|
|
43
|
+
import { mergeContext, normalizeCallOptions } from "./context.js";
|
|
44
|
+
import type { SchemaDefinition, ZodLike } from "./validation/types.js";
|
|
45
|
+
import { methodToKey } from "./validation/types.js";
|
|
46
|
+
import { SCHEMA_REGISTRY, type ZodMiddleware } from "./validation/middleware.js";
|
|
47
|
+
import type {
|
|
48
|
+
Route,
|
|
49
|
+
CallRequest,
|
|
50
|
+
CallResponse,
|
|
51
|
+
StreamingCallResponse,
|
|
52
|
+
ProcedureCallResult,
|
|
53
|
+
} from "./call-types.js";
|
|
54
|
+
import { buildResponse, toMiddlewareContext } from "./call-types.js";
|
|
55
|
+
import { RouteResolver, type ResolvedRoute, type RouteResolutionResult } from "./route-resolver.js";
|
|
56
|
+
import { BatchExecutor, type ExecutionContext } from "./batch-executor.js";
|
|
57
|
+
import type { ProcedureRegistry } from "../procedures/registry.js";
|
|
58
|
+
import type { EventBus } from "../events/types.js";
|
|
59
|
+
import { PROCEDURE_REGISTRY } from "../procedures/registry.js";
|
|
60
|
+
import { validateSchema } from "../procedures/schema.js";
|
|
61
|
+
import type { AnyProcedure, ProcedureClient, ProcedurePath } from "../procedures/types.js";
|
|
62
|
+
import {
|
|
63
|
+
InvocationError,
|
|
64
|
+
invokeProcedure,
|
|
65
|
+
outputItems,
|
|
66
|
+
outputValue,
|
|
67
|
+
type InvokeOptions,
|
|
68
|
+
type Invocation,
|
|
69
|
+
type Interceptor,
|
|
70
|
+
} from "../procedures/invoke.js";
|
|
71
|
+
import { isHandlerConfig, isStreamConfig, type HandlerCallback, type OutputConfig } from "./consumption.js";
|
|
72
|
+
import {
|
|
73
|
+
isAnyProcedureRef,
|
|
74
|
+
isPlainObject,
|
|
75
|
+
normalizeRef,
|
|
76
|
+
prepareRootCall,
|
|
77
|
+
rawInputRule,
|
|
78
|
+
type ProcedureRef,
|
|
79
|
+
type AnyProcedureRef,
|
|
80
|
+
type HydrationEvent,
|
|
81
|
+
} from "../procedures/ref.js";
|
|
82
|
+
|
|
83
|
+
/** Each element of each array item: the stream form of an `outputMode: "batch"` procedure. */
|
|
84
|
+
async function* batchElements(items: AsyncIterable<unknown>): AsyncGenerator<unknown, void, undefined> {
|
|
85
|
+
for await (const item of items) {
|
|
86
|
+
if (Array.isArray(item)) {
|
|
87
|
+
yield* item;
|
|
88
|
+
} else {
|
|
89
|
+
yield item;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The items of a source, with up to `size` items read ahead of the reader. With size 0, the
|
|
96
|
+
* source runs only when the reader reads (the source itself is returned).
|
|
97
|
+
*/
|
|
98
|
+
function readAhead<T>(source: AsyncIterable<T>, size: number): AsyncIterable<T> {
|
|
99
|
+
if (size <= 0) return source;
|
|
100
|
+
return (async function* () {
|
|
101
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
102
|
+
const buffer: Array<Promise<IteratorResult<T>>> = [];
|
|
103
|
+
let ended = false;
|
|
104
|
+
const pull = (): void => {
|
|
105
|
+
while (!ended && buffer.length < size + 1) {
|
|
106
|
+
const next = iterator.next();
|
|
107
|
+
buffer.push(next);
|
|
108
|
+
// The handler marks the end, and keeps a failure from being unhandled until it is read
|
|
109
|
+
next.then(
|
|
110
|
+
(result) => {
|
|
111
|
+
if (result.done) ended = true;
|
|
112
|
+
},
|
|
113
|
+
() => {
|
|
114
|
+
ended = true;
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
let finished = false;
|
|
120
|
+
try {
|
|
121
|
+
// Before each read: the item for the reader, and `size` items ahead
|
|
122
|
+
for (pull(); buffer.length > 0; pull()) {
|
|
123
|
+
const result = await buffer.shift()!;
|
|
124
|
+
if (result.done) break;
|
|
125
|
+
yield result.value;
|
|
126
|
+
}
|
|
127
|
+
finished = true;
|
|
128
|
+
} finally {
|
|
129
|
+
if (!finished) await iterator.return?.();
|
|
130
|
+
}
|
|
131
|
+
})();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The metadata and the signal of a procedure, for the nested calls that it makes. */
|
|
135
|
+
interface CallerContext {
|
|
136
|
+
metadata?: Record<string, unknown> | undefined;
|
|
137
|
+
signal?: AbortSignal | undefined;
|
|
138
|
+
/** The invocation whose handler makes the call: the interceptors link a nested call to it. */
|
|
139
|
+
parent?: Invocation | undefined;
|
|
140
|
+
/** The hydration observer of the program (`exec(ref, input, { onRef })`). */
|
|
141
|
+
onRef?: ((event: HydrationEvent) => void) | undefined;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The options of `exec()` and `execStream()`. */
|
|
145
|
+
export interface ExecOptions {
|
|
146
|
+
/**
|
|
147
|
+
* This function gets the hydration events of this program only: the refs that hydration runs,
|
|
148
|
+
* also inside control flow and runners, with the call that gets each result. A trace uses it.
|
|
149
|
+
* (`observeHydration()` gets the events of every program in the process.)
|
|
150
|
+
*/
|
|
151
|
+
onRef?: ((event: HydrationEvent) => void) | undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate a unique message ID.
|
|
156
|
+
*/
|
|
157
|
+
function generateId(): string {
|
|
158
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Universal Client for protocol-agnostic RPC.
|
|
163
|
+
*
|
|
164
|
+
* Features:
|
|
165
|
+
* - Works with any transport (HTTP, gRPC, WebSocket, local)
|
|
166
|
+
* - Middleware composition (retry, cache, timeout, custom)
|
|
167
|
+
* - Stream-first API (single response = stream with 1 item)
|
|
168
|
+
* - Type-safe request/response handling
|
|
169
|
+
* - **Type-accumulating middleware**: Context types build through `use()` calls
|
|
170
|
+
*
|
|
171
|
+
* @typeParam TContext - Accumulated context type from applied middleware.
|
|
172
|
+
* Starts as `{}` and grows as middleware is added via `use()`.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // HTTP client with type-accumulating middleware
|
|
177
|
+
* const client = new Client({ transport: new HttpTransport({ baseUrl: "/api" }) })
|
|
178
|
+
* .use(createRetryMiddleware()) // Client<{} & RetryContext>
|
|
179
|
+
* .use(createCacheMiddleware({ methods: ["users.get"] })) // Client<{} & RetryContext & CacheContext>
|
|
180
|
+
* .use(createAuthMiddleware({ // Client<... & AuthContext>
|
|
181
|
+
* token: "abc123"
|
|
182
|
+
* }));
|
|
183
|
+
*
|
|
184
|
+
* // The client type now carries all middleware context
|
|
185
|
+
* const user = await client.call(
|
|
186
|
+
* { service: "users", operation: "get" },
|
|
187
|
+
* { id: 123 }
|
|
188
|
+
* );
|
|
189
|
+
*
|
|
190
|
+
* // Streaming
|
|
191
|
+
* for await (const event of client.stream(
|
|
192
|
+
* { service: "events", operation: "watch" },
|
|
193
|
+
* { topic: "orders" }
|
|
194
|
+
* )) {
|
|
195
|
+
* console.log(event);
|
|
196
|
+
* }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export class Client<TContext = {}> {
|
|
200
|
+
private readonly transport: Transport;
|
|
201
|
+
private readonly middleware: ClientMiddleware[] = [];
|
|
202
|
+
private readonly defaultMetadata: Metadata;
|
|
203
|
+
private readonly throwOnError: boolean;
|
|
204
|
+
/** The bus of the local procedures. Undefined: the global bus. */
|
|
205
|
+
private bus: EventBus | undefined;
|
|
206
|
+
/** The interceptors of the local invocations (roadmap 1.2) */
|
|
207
|
+
private interceptors: readonly Interceptor[] = [];
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Context values set via withContext().
|
|
211
|
+
* Merged with parent context when creating child clients.
|
|
212
|
+
*/
|
|
213
|
+
private readonly clientContext: Partial<TContext>;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Parent client reference (for context inheritance).
|
|
217
|
+
* When set, middleware and transport are shared, only context differs.
|
|
218
|
+
*/
|
|
219
|
+
private readonly parent?: Client<any>;
|
|
220
|
+
|
|
221
|
+
constructor(options: ClientOptions | Transport) {
|
|
222
|
+
// Support both new Client(transport) and new Client({ transport, ... })
|
|
223
|
+
if ("send" in options && typeof options.send === "function") {
|
|
224
|
+
// Direct transport passed - narrow to Transport type
|
|
225
|
+
const transport = options as Transport;
|
|
226
|
+
this.transport = transport;
|
|
227
|
+
this.defaultMetadata = {};
|
|
228
|
+
this.throwOnError = true;
|
|
229
|
+
} else {
|
|
230
|
+
// Options object - narrow to ClientOptions type
|
|
231
|
+
const opts = options as ClientOptions;
|
|
232
|
+
this.transport = opts.transport;
|
|
233
|
+
this.defaultMetadata = opts.defaultMetadata || {};
|
|
234
|
+
this.throwOnError = opts.throwOnError !== false;
|
|
235
|
+
this.bus = opts.bus;
|
|
236
|
+
this.interceptors = opts.interceptors ?? [];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Initialize empty context (child clients override this)
|
|
240
|
+
this.clientContext = {};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Create a child client from this client (private, for withContext).
|
|
245
|
+
*/
|
|
246
|
+
private static createChild<TParentContext, TChildContext extends TParentContext>(
|
|
247
|
+
parent: Client<TParentContext>,
|
|
248
|
+
additionalContext: Partial<TChildContext>,
|
|
249
|
+
): Client<TChildContext> {
|
|
250
|
+
// Create a child with shared middleware chain
|
|
251
|
+
const child = Object.create(Client.prototype) as Client<TChildContext>;
|
|
252
|
+
|
|
253
|
+
// Share immutable references (no copying)
|
|
254
|
+
(child as any).transport = parent.transport;
|
|
255
|
+
(child as any).middleware = parent.middleware;
|
|
256
|
+
(child as any).defaultMetadata = parent.defaultMetadata;
|
|
257
|
+
(child as any).throwOnError = parent.throwOnError;
|
|
258
|
+
(child as any).bus = parent.bus;
|
|
259
|
+
(child as any).interceptors = parent.interceptors;
|
|
260
|
+
|
|
261
|
+
// Object.create() bypasses class-field initializers, so procedureRegistry (which normally
|
|
262
|
+
// defaults to PROCEDURE_REGISTRY via a field initializer) would be undefined on the child
|
|
263
|
+
// and exec()/route() would throw "Cannot read properties of undefined (reading 'get')".
|
|
264
|
+
// Inherit the parent's registry; leave the lazy resolver/executor undefined so the child
|
|
265
|
+
// builds its own (batchExecutor binds this.executeProcedure, which must be the child's).
|
|
266
|
+
// See documentation/BUGS-2026-07.md (H1).
|
|
267
|
+
(child as any).procedureRegistry = parent.procedureRegistry;
|
|
268
|
+
(child as any).routeResolver = undefined;
|
|
269
|
+
(child as any).batchExecutor = undefined;
|
|
270
|
+
|
|
271
|
+
// Set parent and additional context
|
|
272
|
+
(child as any).parent = parent;
|
|
273
|
+
(child as any).clientContext = additionalContext;
|
|
274
|
+
|
|
275
|
+
return child;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Create a child client with additional context.
|
|
280
|
+
*
|
|
281
|
+
* Child clients:
|
|
282
|
+
* - Share the middleware chain (cheap to create)
|
|
283
|
+
* - Inherit parent context (merged recursively)
|
|
284
|
+
* - Can override specific context fields
|
|
285
|
+
*
|
|
286
|
+
* Context priority (lowest to highest):
|
|
287
|
+
* 1. Middleware defaults (e.g., maxRetries: 3 from createRetryMiddleware)
|
|
288
|
+
* 2. Parent client context (full inheritance chain)
|
|
289
|
+
* 3. This client's context
|
|
290
|
+
* 4. Per-call context override
|
|
291
|
+
*
|
|
292
|
+
* @param context - Context to set/override on the child client
|
|
293
|
+
* @returns New client with accumulated context
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* // Create authenticated child client
|
|
298
|
+
* const authedClient = client.withContext({
|
|
299
|
+
* auth: { token: "user-token" },
|
|
300
|
+
* timeout: { overall: 5000 }
|
|
301
|
+
* });
|
|
302
|
+
*
|
|
303
|
+
* // Nested children inherit and can override
|
|
304
|
+
* const adminClient = authedClient.withContext({
|
|
305
|
+
* auth: { token: "admin-token" }, // Overrides parent token
|
|
306
|
+
* // timeout inherited from parent
|
|
307
|
+
* });
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
withContext<TAdditional extends object = {}>(
|
|
311
|
+
context: TAdditional & ClientContextInput<TContext>,
|
|
312
|
+
): Client<TContext & TAdditional> {
|
|
313
|
+
return Client.createChild(this, context) as Client<TContext & TAdditional>;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Get effective context by merging entire parent chain.
|
|
318
|
+
*
|
|
319
|
+
* @returns Merged context from all ancestors plus this client
|
|
320
|
+
*/
|
|
321
|
+
private getEffectiveContext(): Partial<TContext> {
|
|
322
|
+
if (this.parent) {
|
|
323
|
+
return mergeContext(this.parent.getEffectiveContext(), this.clientContext);
|
|
324
|
+
}
|
|
325
|
+
return this.clientContext;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Add middleware to the client.
|
|
330
|
+
*
|
|
331
|
+
* Middleware is composed in the order added (onion model):
|
|
332
|
+
* - First added = outermost layer
|
|
333
|
+
* - Last added = innermost layer (closest to transport)
|
|
334
|
+
*
|
|
335
|
+
* **Type Accumulation**: When using `TypedClientMiddleware`, the return type
|
|
336
|
+
* accumulates the middleware's provided context. This enables compile-time
|
|
337
|
+
* validation of middleware chains.
|
|
338
|
+
*
|
|
339
|
+
* @typeParam TProvides - Context type this middleware provides
|
|
340
|
+
* @typeParam TRequires - Context type this middleware requires (must be subset of TContext)
|
|
341
|
+
* @param middleware - Middleware function (typed or untyped)
|
|
342
|
+
* @returns Client with accumulated context type
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```typescript
|
|
346
|
+
* // Type accumulation example
|
|
347
|
+
* const client = new Client(transport)
|
|
348
|
+
* .use(createTimeoutMiddleware({ overall: 5000 })) // Client<TimeoutContext>
|
|
349
|
+
* .use(createRetryMiddleware()) // Client<TimeoutContext & RetryContext>
|
|
350
|
+
* .use(createCacheMiddleware({ methods: ["users.get"] })); // Client<... & CacheContext>
|
|
351
|
+
*
|
|
352
|
+
* // Middleware ordering (onion model)
|
|
353
|
+
* client
|
|
354
|
+
* .use(timeoutMiddleware()) // Outer: handles timeouts
|
|
355
|
+
* .use(retryMiddleware()) // Middle: handles retries
|
|
356
|
+
* .use(cacheMiddleware()); // Inner: handles caching
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
use<TProvides = {}, TRequires extends TContext = TContext>(
|
|
360
|
+
middleware: TypedClientMiddleware<TProvides, TRequires> | ClientMiddleware,
|
|
361
|
+
): Client<TContext & TProvides> {
|
|
362
|
+
this.middleware.push(middleware as ClientMiddleware);
|
|
363
|
+
// Cast is safe because we're just adding type information
|
|
364
|
+
// Runtime behavior is unchanged
|
|
365
|
+
return this as unknown as Client<TContext & TProvides>;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Make a single RPC call (request/response).
|
|
370
|
+
*
|
|
371
|
+
* The result is the last item of the response stream: the one item of a request/response
|
|
372
|
+
* call, or the final item of a streaming procedure. To read each item, use `stream()`.
|
|
373
|
+
*
|
|
374
|
+
* @param method - Method to invoke
|
|
375
|
+
* @param payload - Request payload
|
|
376
|
+
* @param options - Call options (context override, metadata, signal, schema)
|
|
377
|
+
* OR legacy Metadata object for backward compatibility
|
|
378
|
+
* @returns Response payload
|
|
379
|
+
* @throws {ClientError} if response has error status (when throwOnError=true)
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* // Simple call
|
|
384
|
+
* const user = await client.call(
|
|
385
|
+
* { service: "users", operation: "get" },
|
|
386
|
+
* { id: 123 }
|
|
387
|
+
* );
|
|
388
|
+
*
|
|
389
|
+
* // With context override
|
|
390
|
+
* const user = await client.call(
|
|
391
|
+
* { service: "users", operation: "get" },
|
|
392
|
+
* { id: 123 },
|
|
393
|
+
* { context: { timeout: { overall: 10000 } } }
|
|
394
|
+
* );
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
async call<TReq, TRes>(
|
|
398
|
+
method: Method,
|
|
399
|
+
payload: TReq,
|
|
400
|
+
options?: CallOptions<TContext> | Metadata,
|
|
401
|
+
): Promise<TRes> {
|
|
402
|
+
// The result of a stream is its last item (the "sponge" mode of procedures/types.ts). Every
|
|
403
|
+
// request/response transport yields one item, so its result does not change. (Before, the
|
|
404
|
+
// result was the first item, and a falsy first item - 0, false, "" - threw "No response".)
|
|
405
|
+
let last: { value: TRes } | undefined;
|
|
406
|
+
for await (const item of this.stream<TReq, TRes>(method, payload, options)) {
|
|
407
|
+
last = { value: item };
|
|
408
|
+
}
|
|
409
|
+
if (!last) {
|
|
410
|
+
throw new Error("No response received from stream");
|
|
411
|
+
}
|
|
412
|
+
return last.value;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ===========================================================================
|
|
416
|
+
// Procedure Reference Execution (Procedure-as-Data)
|
|
417
|
+
// ===========================================================================
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Execute a procedure reference with automatic input hydration.
|
|
421
|
+
*
|
|
422
|
+
* This method supports procedure-as-data: procedures can be passed as inputs
|
|
423
|
+
* to other procedures, composed declaratively via JSON, or imperatively via TypeScript.
|
|
424
|
+
*
|
|
425
|
+
* **Input Hydration**: Any ProcedureRef or `$proc` objects in the input tree
|
|
426
|
+
* are automatically executed and replaced with their results before the
|
|
427
|
+
* main procedure runs.
|
|
428
|
+
*
|
|
429
|
+
* @param refOrPath - Procedure reference, JSON procedure ref, or procedure path
|
|
430
|
+
* @param input - Input for the procedure. With a reference, its fields go over the fields of the reference's input.
|
|
431
|
+
* @returns Output of the procedure
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```typescript
|
|
435
|
+
* import { proc } from "@procedures/client";
|
|
436
|
+
*
|
|
437
|
+
* // Using proc() builder
|
|
438
|
+
* const result = await client.exec(
|
|
439
|
+
* proc(["git", "add"]).input({ all: true }).build()
|
|
440
|
+
* );
|
|
441
|
+
*
|
|
442
|
+
* // Using JSON format
|
|
443
|
+
* const result = await client.exec({
|
|
444
|
+
* $proc: ["git", "add"],
|
|
445
|
+
* input: { all: true },
|
|
446
|
+
* });
|
|
447
|
+
*
|
|
448
|
+
* // Using path + input (simple form)
|
|
449
|
+
* const result = await client.exec(["git", "add"], { all: true });
|
|
450
|
+
*
|
|
451
|
+
* // Nested procedure refs (hydrated automatically)
|
|
452
|
+
* const result = await client.exec(
|
|
453
|
+
* proc(["dag", "traverse"]).input({
|
|
454
|
+
* visit: proc(["client", "chain"]).input({
|
|
455
|
+
* steps: [
|
|
456
|
+
* proc(["git", "add"]).input({ all: true }).ref,
|
|
457
|
+
* proc(["git", "commit"]).input({ message: "auto" }).ref,
|
|
458
|
+
* ],
|
|
459
|
+
* }).ref,
|
|
460
|
+
* }).build()
|
|
461
|
+
* );
|
|
462
|
+
* ```
|
|
463
|
+
*/
|
|
464
|
+
async exec<TOutput = unknown>(
|
|
465
|
+
refOrPath: AnyProcedureRef | ProcedurePath,
|
|
466
|
+
input?: unknown,
|
|
467
|
+
options: ExecOptions = {}
|
|
468
|
+
): Promise<TOutput> {
|
|
469
|
+
const caller: CallerContext = options.onRef ? { onRef: options.onRef } : {};
|
|
470
|
+
const { path, input: hydratedInput } = await this.prepareRef(refOrPath, input, caller);
|
|
471
|
+
return this.execInternal<TOutput>(path, hydratedInput, caller);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Execute a procedure reference and read each output: each item of a streaming procedure, or
|
|
476
|
+
* the one value of another procedure. The input refs run as in `exec()`. Nothing runs until
|
|
477
|
+
* the caller reads the first item.
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```typescript
|
|
481
|
+
* for await (const line of client.execStream(["logs", "tail"], { file: "app.log" })) {
|
|
482
|
+
* console.log(line);
|
|
483
|
+
* }
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
execStream<TOutput = unknown>(
|
|
487
|
+
refOrPath: AnyProcedureRef | ProcedurePath,
|
|
488
|
+
input?: unknown,
|
|
489
|
+
options: ExecOptions = {}
|
|
490
|
+
): AsyncIterable<TOutput> {
|
|
491
|
+
const self = this;
|
|
492
|
+
const caller: CallerContext = options.onRef ? { onRef: options.onRef } : {};
|
|
493
|
+
return (async function* () {
|
|
494
|
+
const { path, input: hydratedInput } = await self.prepareRef(refOrPath, input, caller);
|
|
495
|
+
yield* self.execStreamInternal<TOutput>(path, hydratedInput, caller);
|
|
496
|
+
})();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* The path and the input of a reference, with the refs of the input run (hydrated).
|
|
501
|
+
*/
|
|
502
|
+
private async prepareRef(
|
|
503
|
+
refOrPath: AnyProcedureRef | ProcedurePath,
|
|
504
|
+
input: unknown,
|
|
505
|
+
caller: CallerContext = {}
|
|
506
|
+
): Promise<{ path: ProcedurePath; input: unknown }> {
|
|
507
|
+
// Normalize to ProcedureRef
|
|
508
|
+
let ref: ProcedureRef;
|
|
509
|
+
|
|
510
|
+
if (isAnyProcedureRef(refOrPath)) {
|
|
511
|
+
ref = normalizeRef(refOrPath);
|
|
512
|
+
// The fields of `input` go over the fields of the ref's input (before, `input` was ignored)
|
|
513
|
+
if (input !== undefined) {
|
|
514
|
+
ref = {
|
|
515
|
+
...ref,
|
|
516
|
+
input: isPlainObject(ref.input) && isPlainObject(input) ? { ...ref.input, ...input } : input,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
} else if (Array.isArray(refOrPath) && refOrPath.every((s) => typeof s === "string")) {
|
|
520
|
+
// Path array provided, use second argument as input
|
|
521
|
+
ref = {
|
|
522
|
+
[Symbol.for("@mark/procedure") as typeof import("../procedures/ref.js").PROCEDURE_SYMBOL]: true,
|
|
523
|
+
path: refOrPath as ProcedurePath,
|
|
524
|
+
input: input ?? {},
|
|
525
|
+
} as ProcedureRef;
|
|
526
|
+
} else {
|
|
527
|
+
throw new Error("exec() requires a ProcedureRef, $proc JSON, or procedure path array");
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Create executor function for hydration
|
|
531
|
+
const executor = async <TIn, TOut>(path: ProcedurePath, inp: TIn): Promise<TOut> => {
|
|
532
|
+
return this.execInternal<TOut>(path, inp, caller);
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// A procedure that takes its input raw (control flow, the `runs-refs` and `raw-input` tags,
|
|
536
|
+
// `procedure.define`) gets its operand refs RAW: it runs them itself, with correct
|
|
537
|
+
// ordering/laziness/error-scoping. Eagerly hydrating here would run the operands up-front
|
|
538
|
+
// and can hijack an all-refs array into an implicit chain that clobbers `steps`. See
|
|
539
|
+
// documentation/BUGS-2026-07.md (C2, H2, H3, M35). The procedure in the registry decides,
|
|
540
|
+
// also for the refs nested in the input (deep dive CORE-5: before, the last path segment did).
|
|
541
|
+
// The body of a defined procedure starts its root call the same way (prepareRootCall, DOC-3)
|
|
542
|
+
return prepareRootCall(ref, executor, { rawInput: rawInputRule(this.procedureRegistry), onRef: caller.onRef });
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* The options of a local invocation. The nested calls of the procedure go through this
|
|
547
|
+
* client, so a path without a local handler goes to the transport. The nested calls get the
|
|
548
|
+
* metadata and the signal of the caller: when the caller aborts, its nested work stops. (Before,
|
|
549
|
+
* each nested call started again with no metadata and no signal: deep dive CORE-10.)
|
|
550
|
+
*/
|
|
551
|
+
private invokeOptions(caller: CallerContext = {}): InvokeOptions {
|
|
552
|
+
const self = this;
|
|
553
|
+
// The nested calls get the metadata and the signal of the invocation (an interceptor can
|
|
554
|
+
// change them), and name it as their parent
|
|
555
|
+
const client = (invocation: Invocation): ProcedureClient => {
|
|
556
|
+
const nested: CallerContext = {
|
|
557
|
+
metadata: invocation.metadata,
|
|
558
|
+
signal: invocation.signal,
|
|
559
|
+
parent: invocation,
|
|
560
|
+
onRef: caller.onRef,
|
|
561
|
+
};
|
|
562
|
+
return {
|
|
563
|
+
call: <TInput, TOutput>(path: ProcedurePath, input: TInput) => self.execInternal<TOutput>(path, input, nested),
|
|
564
|
+
stream: <TInput, TOutput>(path: ProcedurePath, input: TInput) => self.execStreamInternal<TOutput>(path, input, nested),
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
return {
|
|
568
|
+
registry: this.procedureRegistry,
|
|
569
|
+
metadata: caller.metadata ?? {},
|
|
570
|
+
signal: caller.signal,
|
|
571
|
+
client,
|
|
572
|
+
bus: this.bus,
|
|
573
|
+
interceptors: this.interceptors,
|
|
574
|
+
parent: caller.parent,
|
|
575
|
+
onRef: caller.onRef,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** The call options of a remote call for a caller: its metadata as context, and its signal. */
|
|
580
|
+
private remoteCallOptions(caller: CallerContext): CallOptions<TContext> {
|
|
581
|
+
const options: CallOptions<TContext> = { context: (caller.metadata ?? {}) as ClientContextInput<TContext> };
|
|
582
|
+
if (caller.signal) {
|
|
583
|
+
options.signal = caller.signal;
|
|
584
|
+
}
|
|
585
|
+
return options;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* The input for a procedure without a local handler: validated with the local schema when
|
|
590
|
+
* the registry has the procedure, then sent to the transport.
|
|
591
|
+
*/
|
|
592
|
+
private async remoteInput(procedure: AnyProcedure | undefined, path: ProcedurePath, input: unknown): Promise<unknown> {
|
|
593
|
+
if (!procedure) return input;
|
|
594
|
+
const result = await validateSchema(procedure.input, input);
|
|
595
|
+
if (!result.ok) {
|
|
596
|
+
throw new InvocationError(
|
|
597
|
+
"VALIDATION_ERROR",
|
|
598
|
+
`Input validation failed for ${path.join(".")}: ${result.message}`,
|
|
599
|
+
path
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
return result.value;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Internal procedure execution (no hydration of the top-level input).
|
|
607
|
+
*/
|
|
608
|
+
private async execInternal<TOutput>(
|
|
609
|
+
path: ProcedurePath,
|
|
610
|
+
input: unknown,
|
|
611
|
+
caller: CallerContext = {}
|
|
612
|
+
): Promise<TOutput> {
|
|
613
|
+
const procedure = this.procedureRegistry.get(path);
|
|
614
|
+
if (procedure?.handler) {
|
|
615
|
+
const options = this.invokeOptions(caller);
|
|
616
|
+
return outputValue(await invokeProcedure<TOutput>(procedure, input, options), path);
|
|
617
|
+
}
|
|
618
|
+
// No local handler: the transport runs it (a remote procedure)
|
|
619
|
+
return this.call(
|
|
620
|
+
this.pathToMethod(path),
|
|
621
|
+
await this.remoteInput(procedure, path, input),
|
|
622
|
+
this.remoteCallOptions(caller)
|
|
623
|
+
) as Promise<TOutput>;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Internal streaming execution (no hydration of the top-level input).
|
|
628
|
+
*/
|
|
629
|
+
private execStreamInternal<TOutput>(
|
|
630
|
+
path: ProcedurePath,
|
|
631
|
+
input: unknown,
|
|
632
|
+
caller: CallerContext = {}
|
|
633
|
+
): AsyncIterable<TOutput> {
|
|
634
|
+
const self = this;
|
|
635
|
+
return (async function* () {
|
|
636
|
+
const procedure = self.procedureRegistry.get(path);
|
|
637
|
+
if (procedure?.handler) {
|
|
638
|
+
const options = self.invokeOptions(caller);
|
|
639
|
+
yield* outputItems(await invokeProcedure<TOutput>(procedure, input, options));
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
yield* self.stream<unknown, TOutput>(
|
|
643
|
+
self.pathToMethod(path),
|
|
644
|
+
await self.remoteInput(procedure, path, input),
|
|
645
|
+
self.remoteCallOptions(caller)
|
|
646
|
+
);
|
|
647
|
+
})();
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Make a streaming RPC call.
|
|
652
|
+
*
|
|
653
|
+
* Returns an async iterable that yields response payloads.
|
|
654
|
+
* For single request/response, yields exactly one item.
|
|
655
|
+
*
|
|
656
|
+
* @param method - Method to invoke
|
|
657
|
+
* @param payload - Request payload
|
|
658
|
+
* @param options - Call options (context override, metadata, signal, schema)
|
|
659
|
+
* OR legacy Metadata object for backward compatibility
|
|
660
|
+
* @returns Async iterable of response payloads
|
|
661
|
+
* @throws {ClientError} if any response item has error status (when throwOnError=true)
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```typescript
|
|
665
|
+
* // Streaming response
|
|
666
|
+
* for await (const event of client.stream(
|
|
667
|
+
* { service: "events", operation: "watch" },
|
|
668
|
+
* { topic: "orders" }
|
|
669
|
+
* )) {
|
|
670
|
+
* console.log(event);
|
|
671
|
+
* }
|
|
672
|
+
*
|
|
673
|
+
* // With context and signal
|
|
674
|
+
* const controller = new AbortController();
|
|
675
|
+
* for await (const event of client.stream(
|
|
676
|
+
* { service: "events", operation: "watch" },
|
|
677
|
+
* { topic: "orders" },
|
|
678
|
+
* { context: { timeout: { overall: 30000 } }, signal: controller.signal }
|
|
679
|
+
* )) {
|
|
680
|
+
* console.log(event);
|
|
681
|
+
* }
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
async *stream<TReq, TRes>(
|
|
685
|
+
method: Method,
|
|
686
|
+
payload: TReq,
|
|
687
|
+
options?: CallOptions<TContext> | Metadata,
|
|
688
|
+
): AsyncIterable<TRes> {
|
|
689
|
+
// Normalize options (backward compatible with legacy Metadata parameter)
|
|
690
|
+
const opts = normalizeCallOptions(options);
|
|
691
|
+
|
|
692
|
+
// Merge context: parent chain -> client context -> per-call context
|
|
693
|
+
const effectiveContext = mergeContext(
|
|
694
|
+
this.getEffectiveContext() as object,
|
|
695
|
+
(opts.context ?? {}) as object,
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
// Create message with merged context in metadata
|
|
699
|
+
const message: Message<TReq> = {
|
|
700
|
+
id: generateId(),
|
|
701
|
+
method,
|
|
702
|
+
payload,
|
|
703
|
+
metadata: {
|
|
704
|
+
...this.defaultMetadata,
|
|
705
|
+
...effectiveContext, // Context flows into metadata
|
|
706
|
+
...opts.metadata, // Raw metadata last (highest priority)
|
|
707
|
+
},
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// Set signal if provided
|
|
711
|
+
if (opts.signal) {
|
|
712
|
+
message.signal = opts.signal;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Store schema override in metadata for Zod middleware
|
|
716
|
+
if (opts.schema) {
|
|
717
|
+
(message.metadata as any).__schema = opts.schema;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Compose middleware chain
|
|
721
|
+
const runner = this.composeMiddleware<TReq, TRes>();
|
|
722
|
+
|
|
723
|
+
// Execute through middleware chain
|
|
724
|
+
const context: ClientContext<TReq> = { message };
|
|
725
|
+
const responseStream = runner(context);
|
|
726
|
+
|
|
727
|
+
// Yield payloads, handling errors
|
|
728
|
+
for await (const item of responseStream) {
|
|
729
|
+
if (item.status.type === "error" && this.throwOnError) {
|
|
730
|
+
throw new ClientError(item.status, item.id);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
yield item.payload;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Compose middleware chain using universal middleware composition.
|
|
739
|
+
*
|
|
740
|
+
* @returns Composed runner function
|
|
741
|
+
* @private
|
|
742
|
+
*/
|
|
743
|
+
private composeMiddleware<TReq, TRes>(): ClientRunner<TReq, TRes> {
|
|
744
|
+
// Innermost function: call transport
|
|
745
|
+
const self = this;
|
|
746
|
+
const transportRunner: ClientRunner<TReq, TRes> = async function* (context: ClientContext<TReq>) {
|
|
747
|
+
yield* self.transport.send<TReq, TRes>(context.message);
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
// Use universal middleware composition
|
|
751
|
+
// compose(...middleware, finalRunner) applies middleware in order (onion model)
|
|
752
|
+
return compose<false>(...(this.middleware as any[]), transportRunner) as ClientRunner<TReq, TRes>;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Get transport name.
|
|
757
|
+
*/
|
|
758
|
+
get transportName(): string {
|
|
759
|
+
return this.transport.name;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Close client and cleanup transport resources.
|
|
764
|
+
*/
|
|
765
|
+
async close(): Promise<void> {
|
|
766
|
+
await this.transport.close();
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// ===========================================================================
|
|
770
|
+
// Schema Registration (Zod Validation)
|
|
771
|
+
// ===========================================================================
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Cached reference to Zod middleware for schema registration.
|
|
775
|
+
*/
|
|
776
|
+
private zodMiddleware: ZodMiddleware | undefined;
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Register a validation schema for a specific method.
|
|
780
|
+
*
|
|
781
|
+
* Requires `createZodMiddleware()` to be added via `.use()` first.
|
|
782
|
+
* Schemas are used to validate request payloads before sending and
|
|
783
|
+
* response payloads after receiving.
|
|
784
|
+
*
|
|
785
|
+
* @param method - Method to register schema for
|
|
786
|
+
* @param schemas - Input and/or output Zod schemas
|
|
787
|
+
* @returns this (for chaining)
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```typescript
|
|
791
|
+
* import { z } from "zod";
|
|
792
|
+
*
|
|
793
|
+
* const client = new Client({ transport })
|
|
794
|
+
* .use(createZodMiddleware())
|
|
795
|
+
* .schema({ service: "users", operation: "get" }, {
|
|
796
|
+
* input: z.object({ id: z.string() }),
|
|
797
|
+
* output: z.object({ id: z.string(), name: z.string() }),
|
|
798
|
+
* })
|
|
799
|
+
* .schema({ service: "users", operation: "create" }, {
|
|
800
|
+
* input: UserCreateSchema,
|
|
801
|
+
* output: UserSchema,
|
|
802
|
+
* });
|
|
803
|
+
*
|
|
804
|
+
* // Validation happens automatically on call
|
|
805
|
+
* const user = await client.call(
|
|
806
|
+
* { service: "users", operation: "get" },
|
|
807
|
+
* { id: "123" } // Validated against input schema
|
|
808
|
+
* );
|
|
809
|
+
* // Response validated against output schema
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
schema<TInput extends ZodLike = ZodLike, TOutput extends ZodLike = ZodLike>(
|
|
813
|
+
method: Method,
|
|
814
|
+
schemas: {
|
|
815
|
+
input?: TInput;
|
|
816
|
+
output?: TOutput;
|
|
817
|
+
},
|
|
818
|
+
): this {
|
|
819
|
+
// Find Zod middleware (lazy lookup, cached)
|
|
820
|
+
if (!this.zodMiddleware) {
|
|
821
|
+
this.zodMiddleware = this.findZodMiddleware();
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (!this.zodMiddleware) {
|
|
825
|
+
throw new Error(
|
|
826
|
+
"Cannot register schema: createZodMiddleware() must be added via .use() first",
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const key = methodToKey(method);
|
|
831
|
+
this.zodMiddleware[SCHEMA_REGISTRY].set(key, schemas as SchemaDefinition);
|
|
832
|
+
|
|
833
|
+
return this;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Find Zod middleware in the middleware chain.
|
|
838
|
+
*/
|
|
839
|
+
private findZodMiddleware(): ZodMiddleware | undefined {
|
|
840
|
+
// Check parent chain first (child clients share middleware)
|
|
841
|
+
if (this.parent) {
|
|
842
|
+
return this.parent.findZodMiddleware();
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
return this.middleware.find(
|
|
846
|
+
(m): m is ZodMiddleware => SCHEMA_REGISTRY in m,
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// ===========================================================================
|
|
851
|
+
// Nested Route API
|
|
852
|
+
// ===========================================================================
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Procedure registry for route resolution.
|
|
856
|
+
* Uses global registry by default.
|
|
857
|
+
*/
|
|
858
|
+
private procedureRegistry: ProcedureRegistry = PROCEDURE_REGISTRY;
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Route resolver instance (lazy initialized).
|
|
862
|
+
*/
|
|
863
|
+
private routeResolver: RouteResolver | undefined;
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Batch executor instance (lazy initialized).
|
|
867
|
+
*/
|
|
868
|
+
private batchExecutor: BatchExecutor | undefined;
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Set a custom procedure registry for this client.
|
|
872
|
+
*
|
|
873
|
+
* @param registry - Procedure registry to use
|
|
874
|
+
* @returns this (for chaining)
|
|
875
|
+
*/
|
|
876
|
+
useRegistry(registry: ProcedureRegistry): this {
|
|
877
|
+
this.procedureRegistry = registry;
|
|
878
|
+
this.routeResolver = undefined; // Reset resolver
|
|
879
|
+
return this;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Set the event bus of the local procedures of this client (`ctx.bus`).
|
|
884
|
+
*
|
|
885
|
+
* @param bus - Event bus for the procedures
|
|
886
|
+
* @returns this (for chaining)
|
|
887
|
+
*/
|
|
888
|
+
useBus(bus: EventBus): this {
|
|
889
|
+
this.bus = bus;
|
|
890
|
+
return this;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Make a call using the nested route API.
|
|
895
|
+
*
|
|
896
|
+
* This method supports:
|
|
897
|
+
* - Per-call middleware overrides
|
|
898
|
+
* - Batch execution with configurable strategies
|
|
899
|
+
* - Type-safe nested route structures
|
|
900
|
+
*
|
|
901
|
+
* @param request - Call request with route and options
|
|
902
|
+
* @returns Response mirroring the route structure
|
|
903
|
+
*
|
|
904
|
+
* @example
|
|
905
|
+
* ```typescript
|
|
906
|
+
* // Single route call
|
|
907
|
+
* const result = await client.route({
|
|
908
|
+
* route: {
|
|
909
|
+
* collections: {
|
|
910
|
+
* users: {
|
|
911
|
+
* get: { id: "123" }
|
|
912
|
+
* }
|
|
913
|
+
* }
|
|
914
|
+
* }
|
|
915
|
+
* });
|
|
916
|
+
* // result.collections.users.get.data = { id: "123", name: "John" }
|
|
917
|
+
*
|
|
918
|
+
* // Batched call with middleware overrides
|
|
919
|
+
* const results = await client.route({
|
|
920
|
+
* middlewares: {
|
|
921
|
+
* retry: { attempts: 3 },
|
|
922
|
+
* timeout: { ms: 5000 }
|
|
923
|
+
* },
|
|
924
|
+
* batch: { strategy: 'all' },
|
|
925
|
+
* route: {
|
|
926
|
+
* collections: {
|
|
927
|
+
* users: { get: { id: "123" } },
|
|
928
|
+
* orders: { list: { userId: "123" } }
|
|
929
|
+
* },
|
|
930
|
+
* weather: {
|
|
931
|
+
* forecast: { city: "NYC", days: 5 }
|
|
932
|
+
* }
|
|
933
|
+
* }
|
|
934
|
+
* });
|
|
935
|
+
* ```
|
|
936
|
+
*/
|
|
937
|
+
async route<TRoute extends Route>(
|
|
938
|
+
request: CallRequest<TRoute>
|
|
939
|
+
): Promise<CallResponse<TRoute>> {
|
|
940
|
+
const resolver = this.getRouteResolver();
|
|
941
|
+
const executor = this.getBatchExecutor();
|
|
942
|
+
|
|
943
|
+
// Resolve routes to procedures
|
|
944
|
+
const resolution = resolver.resolve(request.route);
|
|
945
|
+
|
|
946
|
+
if (!resolution.success) {
|
|
947
|
+
return buildResponse<TRoute>(this.resolutionFailure(resolution));
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Create execution context
|
|
951
|
+
const context = this.createExecutionContext(request);
|
|
952
|
+
|
|
953
|
+
// Execute routes
|
|
954
|
+
const batchConfig = request.batch ?? { strategy: "all" };
|
|
955
|
+
const result = await executor.executeBatch<TRoute>(
|
|
956
|
+
resolution.resolved,
|
|
957
|
+
context,
|
|
958
|
+
batchConfig
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
return result.response;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Make a streaming call using the nested route API.
|
|
966
|
+
*
|
|
967
|
+
* Returns an async iterator that yields results as they complete,
|
|
968
|
+
* plus a promise for the final complete response.
|
|
969
|
+
*
|
|
970
|
+
* @param request - Call request (batch.strategy should be 'stream')
|
|
971
|
+
* @returns Streaming response with iterator and completion promise
|
|
972
|
+
*/
|
|
973
|
+
routeStream<TRoute extends Route>(
|
|
974
|
+
request: CallRequest<TRoute>
|
|
975
|
+
): StreamingCallResponse<TRoute> {
|
|
976
|
+
const resolver = this.getRouteResolver();
|
|
977
|
+
const executor = this.getBatchExecutor();
|
|
978
|
+
|
|
979
|
+
const resolution = resolver.resolve(request.route);
|
|
980
|
+
|
|
981
|
+
if (!resolution.success) {
|
|
982
|
+
// Return error response immediately
|
|
983
|
+
const errorResults = this.resolutionFailure(resolution);
|
|
984
|
+
|
|
985
|
+
return {
|
|
986
|
+
results: (async function* () {
|
|
987
|
+
for (const [path, result] of errorResults) {
|
|
988
|
+
yield { path, result };
|
|
989
|
+
}
|
|
990
|
+
})(),
|
|
991
|
+
complete: Promise.resolve(buildResponse<TRoute>(errorResults)),
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
const context = this.createExecutionContext(request);
|
|
996
|
+
const streamConfig = request.batch ?? { strategy: "stream" };
|
|
997
|
+
|
|
998
|
+
return executor.getStreamingResponse<TRoute>(
|
|
999
|
+
resolution.resolved,
|
|
1000
|
+
context,
|
|
1001
|
+
streamConfig
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* The results of a route that did not resolve: an error for each leaf that failed, and
|
|
1007
|
+
* `SKIPPED` for every other leaf, also the leaves after a validation error. (Before, the leaves
|
|
1008
|
+
* after a validation error were missing: deep dive CORE-14.)
|
|
1009
|
+
*/
|
|
1010
|
+
private resolutionFailure(resolution: RouteResolutionResult): Array<[ProcedurePath, ProcedureCallResult]> {
|
|
1011
|
+
const skipped = (path: ProcedurePath): ProcedureCallResult => ({
|
|
1012
|
+
success: false,
|
|
1013
|
+
error: { code: "SKIPPED", message: "Skipped due to other route errors", retryable: false, path },
|
|
1014
|
+
});
|
|
1015
|
+
const results: Array<[ProcedurePath, ProcedureCallResult]> = resolution.errors.map((error) => [
|
|
1016
|
+
error.path,
|
|
1017
|
+
{
|
|
1018
|
+
success: false,
|
|
1019
|
+
error: {
|
|
1020
|
+
code: error.type === "not_found" ? "NOT_FOUND" : "VALIDATION_ERROR",
|
|
1021
|
+
message: error.message,
|
|
1022
|
+
retryable: false,
|
|
1023
|
+
path: error.path,
|
|
1024
|
+
},
|
|
1025
|
+
},
|
|
1026
|
+
]);
|
|
1027
|
+
for (const resolved of resolution.resolved) results.push([resolved.path, skipped(resolved.path)]);
|
|
1028
|
+
for (const path of resolution.skipped) results.push([path, skipped(path)]);
|
|
1029
|
+
return results;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Get the route resolver (lazy initialization).
|
|
1034
|
+
*/
|
|
1035
|
+
private getRouteResolver(): RouteResolver {
|
|
1036
|
+
if (!this.routeResolver) {
|
|
1037
|
+
this.routeResolver = new RouteResolver(this.procedureRegistry);
|
|
1038
|
+
}
|
|
1039
|
+
return this.routeResolver;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Get the batch executor (lazy initialization).
|
|
1044
|
+
*/
|
|
1045
|
+
private getBatchExecutor(): BatchExecutor {
|
|
1046
|
+
if (!this.batchExecutor) {
|
|
1047
|
+
this.batchExecutor = new BatchExecutor(this.executeProcedure.bind(this));
|
|
1048
|
+
}
|
|
1049
|
+
return this.batchExecutor;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Create execution context from call request.
|
|
1054
|
+
*/
|
|
1055
|
+
private createExecutionContext<TRoute extends Route>(
|
|
1056
|
+
request: CallRequest<TRoute>
|
|
1057
|
+
): ExecutionContext {
|
|
1058
|
+
// Merge context: parent chain -> client context -> middleware overrides. The override keys
|
|
1059
|
+
// become the keys that the middleware reads (deep dive CORE-14). No internal key goes into
|
|
1060
|
+
// the metadata: a handler sees it as ctx.metadata (deep dive CORE-10).
|
|
1061
|
+
const effectiveContext = mergeContext(
|
|
1062
|
+
this.getEffectiveContext() as object,
|
|
1063
|
+
toMiddlewareContext(request.middlewares)
|
|
1064
|
+
);
|
|
1065
|
+
|
|
1066
|
+
const context: ExecutionContext = {
|
|
1067
|
+
metadata: {
|
|
1068
|
+
...this.defaultMetadata,
|
|
1069
|
+
...effectiveContext,
|
|
1070
|
+
},
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// Only set signal if provided (exactOptionalPropertyTypes)
|
|
1074
|
+
if (request.signal) {
|
|
1075
|
+
context.signal = request.signal;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return context;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Execute a single procedure call.
|
|
1083
|
+
* Used by BatchExecutor.
|
|
1084
|
+
*
|
|
1085
|
+
* The `out` config of the route leaf chooses the result (BUGS-2026-07 H8):
|
|
1086
|
+
* - sponge (the default): the value, or the last item of a stream (or `accumulate` of all items);
|
|
1087
|
+
* - stream: `data` is an AsyncIterable of the items. The procedure starts when the reader reads.
|
|
1088
|
+
* With `bufferSize`, that many items are read ahead of the reader;
|
|
1089
|
+
* - handlers: `progress` gets each item but the last, `complete` gets the last, `error` gets the error.
|
|
1090
|
+
*
|
|
1091
|
+
* A procedure with `outputMode: "batch"` returns an array: sponge gives the array, and stream
|
|
1092
|
+
* gives each element.
|
|
1093
|
+
*/
|
|
1094
|
+
private async executeProcedure(
|
|
1095
|
+
resolved: ResolvedRoute,
|
|
1096
|
+
context: ExecutionContext
|
|
1097
|
+
): Promise<ProcedureCallResult> {
|
|
1098
|
+
const { path, outputConfig } = resolved;
|
|
1099
|
+
|
|
1100
|
+
try {
|
|
1101
|
+
const items = this.routeItems(resolved, context);
|
|
1102
|
+
if (isStreamConfig(outputConfig)) {
|
|
1103
|
+
const elements = resolved.procedure.outputMode === "batch" ? batchElements(items) : items;
|
|
1104
|
+
return { success: true, data: readAhead(elements, outputConfig.bufferSize ?? 0) };
|
|
1105
|
+
}
|
|
1106
|
+
if (isHandlerConfig(outputConfig)) {
|
|
1107
|
+
return { success: true, data: await this.consumeWithHandlers(items, outputConfig, path) };
|
|
1108
|
+
}
|
|
1109
|
+
return { success: true, data: await this.sponge(items, outputConfig, path) };
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
return {
|
|
1112
|
+
success: false,
|
|
1113
|
+
error: {
|
|
1114
|
+
code: error instanceof ClientError || error instanceof InvocationError ? error.code : "EXECUTION_ERROR",
|
|
1115
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1116
|
+
retryable: error instanceof ClientError ? error.retryable : false,
|
|
1117
|
+
path,
|
|
1118
|
+
},
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* The output items of a resolved route: from the local handler, or from the transport.
|
|
1125
|
+
*/
|
|
1126
|
+
private routeItems(resolved: ResolvedRoute, context: ExecutionContext): AsyncGenerator<unknown, void, undefined> {
|
|
1127
|
+
const self = this;
|
|
1128
|
+
const { path, procedure, input } = resolved;
|
|
1129
|
+
return (async function* () {
|
|
1130
|
+
if (procedure.handler) {
|
|
1131
|
+
// The resolver validated the input already (not an asynchronous schema: see ResolvedRoute)
|
|
1132
|
+
const options = {
|
|
1133
|
+
...self.invokeOptions({ metadata: context.metadata, signal: context.signal }),
|
|
1134
|
+
inputValidated: resolved.inputValidated !== false,
|
|
1135
|
+
};
|
|
1136
|
+
yield* outputItems(await invokeProcedure(procedure, input, options));
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const callOptions: CallOptions<TContext> = { context: context.metadata as ClientContextInput<TContext> };
|
|
1140
|
+
if (context.signal) {
|
|
1141
|
+
callOptions.signal = context.signal;
|
|
1142
|
+
}
|
|
1143
|
+
yield* self.stream(self.pathToMethod(path), input, callOptions);
|
|
1144
|
+
})();
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/** The sponge mode: the last item, or `accumulate` of all items. */
|
|
1148
|
+
private async sponge(items: AsyncIterable<unknown>, config: OutputConfig, path: ProcedurePath): Promise<unknown> {
|
|
1149
|
+
const accumulate = "type" in config && config.type === "sponge" ? config.accumulate : undefined;
|
|
1150
|
+
const all: unknown[] = [];
|
|
1151
|
+
let last: { value: unknown } | undefined;
|
|
1152
|
+
for await (const item of items) {
|
|
1153
|
+
last = { value: item };
|
|
1154
|
+
if (accumulate) all.push(item);
|
|
1155
|
+
}
|
|
1156
|
+
if (!last) {
|
|
1157
|
+
throw new InvocationError("NO_OUTPUT", `Procedure gave no output: ${path.join(".")}`, path);
|
|
1158
|
+
}
|
|
1159
|
+
return accumulate ? accumulate(all.slice(0, -1), last.value) : last.value;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/** The handlers mode: `progress` for each item but the last, then `complete`, or `error`. */
|
|
1163
|
+
private async consumeWithHandlers(
|
|
1164
|
+
items: AsyncIterable<unknown>,
|
|
1165
|
+
config: { progress?: HandlerCallback; complete?: HandlerCallback; error?: HandlerCallback<Error> },
|
|
1166
|
+
path: ProcedurePath
|
|
1167
|
+
): Promise<unknown> {
|
|
1168
|
+
let previous: { value: unknown } | undefined;
|
|
1169
|
+
try {
|
|
1170
|
+
for await (const item of items) {
|
|
1171
|
+
if (previous) await this.deliver(config.progress, previous.value);
|
|
1172
|
+
previous = { value: item };
|
|
1173
|
+
}
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
await this.deliver(config.error, error instanceof Error ? error : new Error(String(error)));
|
|
1176
|
+
throw error;
|
|
1177
|
+
}
|
|
1178
|
+
if (!previous) {
|
|
1179
|
+
throw new InvocationError("NO_OUTPUT", `Procedure gave no output: ${path.join(".")}`, path);
|
|
1180
|
+
}
|
|
1181
|
+
await this.deliver(config.complete, previous.value);
|
|
1182
|
+
return previous.value;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
/** A handler callback gets the data: a function, or a procedure path (the data is its input). */
|
|
1186
|
+
private async deliver<T>(callback: HandlerCallback<T> | undefined, data: T): Promise<void> {
|
|
1187
|
+
if (callback === undefined) return;
|
|
1188
|
+
if (Array.isArray(callback)) {
|
|
1189
|
+
await this.execInternal(callback, data);
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
await callback(data);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Convert procedure path to Method object.
|
|
1197
|
+
*/
|
|
1198
|
+
private pathToMethod(path: ProcedurePath): Method {
|
|
1199
|
+
// The one mapping of every host (deep dive architecture review 3.3)
|
|
1200
|
+
return pathToMethod(path);
|
|
1201
|
+
}
|
|
1202
|
+
}
|