@procedures/client 0.0.0-stage → 0.2.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 +42 -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 +562 -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 +51 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +89 -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 +525 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +1011 -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 +305 -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/capability.d.ts +111 -0
- package/dist/procedures/capability.d.ts.map +1 -0
- package/dist/procedures/capability.js +269 -0
- package/dist/procedures/capability.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 +203 -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 +210 -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 +639 -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 +158 -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 +588 -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 +275 -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 +244 -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 +272 -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 +270 -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 +210 -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 +357 -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/effects.d.ts +15 -0
- package/dist/procedures/effects.d.ts.map +1 -0
- package/dist/procedures/effects.js +18 -0
- package/dist/procedures/effects.js.map +1 -0
- package/dist/procedures/index.d.ts +27 -0
- package/dist/procedures/index.d.ts.map +1 -0
- package/dist/procedures/index.js +54 -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 +194 -0
- package/dist/procedures/interceptors.js.map +1 -0
- package/dist/procedures/invoke.d.ts +155 -0
- package/dist/procedures/invoke.d.ts.map +1 -0
- package/dist/procedures/invoke.js +343 -0
- package/dist/procedures/invoke.js.map +1 -0
- package/dist/procedures/module.d.ts +54 -0
- package/dist/procedures/module.d.ts.map +1 -0
- package/dist/procedures/module.js +103 -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 +468 -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/register.d.ts +8 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.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 +81 -0
- package/dist/server/host-policy.d.ts.map +1 -0
- package/dist/server/host-policy.js +104 -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 +226 -0
- package/dist/server/procedure-server.d.ts.map +1 -0
- package/dist/server/procedure-server.js +348 -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 +117 -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 +623 -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 +401 -0
- package/src/client/batch-executor.ts +514 -0
- package/src/client/call-types.ts +491 -0
- package/src/client/client.ts +1229 -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 +372 -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/capability.ts +333 -0
- package/src/procedures/cli/announce.ts +470 -0
- package/src/procedures/cli/discover.ts +390 -0
- package/src/procedures/cli/index.ts +231 -0
- package/src/procedures/cli/init.ts +370 -0
- package/src/procedures/collection/index.ts +51 -0
- package/src/procedures/collection/procedures.ts +257 -0
- package/src/procedures/collection/schemas.ts +550 -0
- package/src/procedures/collection/storage.ts +53 -0
- package/src/procedures/core/array.ts +1026 -0
- package/src/procedures/core/comparison.ts +265 -0
- package/src/procedures/core/index.ts +898 -0
- package/src/procedures/core/logic.ts +225 -0
- package/src/procedures/core/math.ts +471 -0
- package/src/procedures/core/meta.ts +389 -0
- package/src/procedures/core/object.ts +429 -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 +460 -0
- package/src/procedures/core/type.ts +346 -0
- package/src/procedures/define-procedure.ts +532 -0
- package/src/procedures/define.ts +387 -0
- package/src/procedures/discovery.ts +76 -0
- package/src/procedures/effects.ts +24 -0
- package/src/procedures/index.ts +239 -0
- package/src/procedures/interceptors.ts +273 -0
- package/src/procedures/invoke.ts +506 -0
- package/src/procedures/module.ts +117 -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 +596 -0
- package/src/register.ts +10 -0
- package/src/server/browser-guard.ts +147 -0
- package/src/server/host-policy.ts +163 -0
- package/src/server/index.ts +70 -0
- package/src/server/method.ts +33 -0
- package/src/server/procedure-server.ts +459 -0
- package/src/server/server.ts +364 -0
- package/src/server/types.ts +147 -0
|
@@ -0,0 +1,1305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedure Reference System
|
|
3
|
+
*
|
|
4
|
+
* Enables procedures-as-data: procedures can be passed as inputs to other procedures,
|
|
5
|
+
* composed declaratively via JSON, or imperatively via TypeScript.
|
|
6
|
+
*
|
|
7
|
+
* Key concepts:
|
|
8
|
+
* - PROCEDURE_SYMBOL: Symbol tag to identify procedure references in JSON/objects
|
|
9
|
+
* - ProcedureRef: A reference to a procedure with pre-bound input
|
|
10
|
+
* - $when: Controls when a procedure reference is executed during hydration
|
|
11
|
+
* - $name: Names the result of a chain step, for `$ref`
|
|
12
|
+
* - $ref: Reads a name of the scope (a chain step, `$last`, `item`, `acc`, `index`, `input`)
|
|
13
|
+
* - $literal: Gives a value without hydration
|
|
14
|
+
* - hydrateInput: Walks input tree and executes nested procedure references
|
|
15
|
+
* - executeRef: Helper for procedures to execute deferred refs
|
|
16
|
+
* - proc(): Factory function to create procedure references
|
|
17
|
+
*
|
|
18
|
+
* ## Execution Control with $when
|
|
19
|
+
*
|
|
20
|
+
* The `$when` field controls when a procedure reference is executed:
|
|
21
|
+
* - `"$immediate"` (or absent): Execute during hydration (default)
|
|
22
|
+
* - `"$never"`: Never execute during hydration, pass as pure data (with its whole subtree)
|
|
23
|
+
* - `"$parent"`: Defer to parent procedure (pass as data)
|
|
24
|
+
* - `"someName"`: Defer to the runner that gives this name in its `contextStack`
|
|
25
|
+
* (`dag.traverse` gives "dag.traverse", `core.catch` gives "catch")
|
|
26
|
+
*
|
|
27
|
+
* A deferred ref is data at every depth: hydration of the input that holds it does not run it.
|
|
28
|
+
* The procedure that receives it runs it later (deep dive CORE-11).
|
|
29
|
+
*
|
|
30
|
+
* ## Raw input
|
|
31
|
+
*
|
|
32
|
+
* A procedure that takes its input raw (control flow, the `runs-refs` and `raw-input` tags) gets
|
|
33
|
+
* the refs of its input unchanged: it runs them itself. Such an input carries the scope of the
|
|
34
|
+
* caller (`withScope`), so nested control flow can read the names of an outer chain.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Declarative (JSON) with execution control
|
|
39
|
+
* const pipelineJson = {
|
|
40
|
+
* $name: "traversal",
|
|
41
|
+
* $proc: ["dag", "traverse"],
|
|
42
|
+
* input: {
|
|
43
|
+
* visit: {
|
|
44
|
+
* $proc: ["git", "add"],
|
|
45
|
+
* input: { all: true },
|
|
46
|
+
* $when: "traversal", // Defer to traversal context
|
|
47
|
+
* },
|
|
48
|
+
* },
|
|
49
|
+
* };
|
|
50
|
+
*
|
|
51
|
+
* // The inner $proc is NOT executed during hydration.
|
|
52
|
+
* // dag.traverse receives it as data and executes per-node.
|
|
53
|
+
* await client.exec(pipelineJson);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
import type { ProcedurePath } from "./types.js";
|
|
58
|
+
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// Procedure Reference Constants
|
|
61
|
+
// =============================================================================
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Symbol used to tag objects as procedure references.
|
|
65
|
+
* This allows procedure references to be identified during input hydration.
|
|
66
|
+
*/
|
|
67
|
+
export const PROCEDURE_SYMBOL: symbol = Symbol.for("@mark/procedure");
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* JSON key used to identify procedure references in serialized form.
|
|
71
|
+
*/
|
|
72
|
+
export const PROCEDURE_JSON_KEY: string = "$proc";
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* JSON key used to control when a procedure reference is executed.
|
|
76
|
+
*/
|
|
77
|
+
export const PROCEDURE_WHEN_KEY: string = "$when";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* JSON key that names the result of a chain step: a later step reads it with `{ $ref: "<name>" }`.
|
|
81
|
+
*/
|
|
82
|
+
export const PROCEDURE_NAME_KEY: string = "$name";
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* JSON key used to reference outputs from named stages.
|
|
86
|
+
*/
|
|
87
|
+
export const OUTPUT_REF_KEY: string = "$ref";
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* JSON key of a literal. Hydration gives the value of `{ $literal: value }` and does not look
|
|
91
|
+
* inside it, so a `$proc` or a `$ref` in the value stays data (for example a JSON Schema `$ref`).
|
|
92
|
+
*/
|
|
93
|
+
export const LITERAL_KEY: string = "$literal";
|
|
94
|
+
|
|
95
|
+
// =============================================================================
|
|
96
|
+
// Execution Timing Constants
|
|
97
|
+
// =============================================================================
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Execute immediately during hydration (default behavior).
|
|
101
|
+
*/
|
|
102
|
+
export const WHEN_IMMEDIATE: string = "$immediate";
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Never execute during hydration - pass as pure data.
|
|
106
|
+
*/
|
|
107
|
+
export const WHEN_NEVER: string = "$never";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Defer to parent procedure - pass as data for parent to execute.
|
|
111
|
+
*/
|
|
112
|
+
export const WHEN_PARENT: string = "$parent";
|
|
113
|
+
|
|
114
|
+
// =============================================================================
|
|
115
|
+
// Step Result Info (for $continueIf handlers)
|
|
116
|
+
// =============================================================================
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Information passed to $continueIf handlers about the result of a procedure execution.
|
|
120
|
+
*/
|
|
121
|
+
export interface StepResultInfo {
|
|
122
|
+
/** Whether the procedure executed successfully */
|
|
123
|
+
success: boolean;
|
|
124
|
+
|
|
125
|
+
/** The procedure's output (if success) */
|
|
126
|
+
result?: unknown;
|
|
127
|
+
|
|
128
|
+
/** Error message (if failed) */
|
|
129
|
+
error?: string;
|
|
130
|
+
|
|
131
|
+
/** Whether the operation was a no-op (from result.skipped if present) */
|
|
132
|
+
skipped?: boolean;
|
|
133
|
+
|
|
134
|
+
/** The procedure path that was executed */
|
|
135
|
+
proc: ProcedurePath;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Decision returned by $continueIf handlers.
|
|
140
|
+
*/
|
|
141
|
+
export interface ContinueDecision {
|
|
142
|
+
/** Whether to continue execution (true) or propagate the error (false) */
|
|
143
|
+
continue: boolean;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// =============================================================================
|
|
147
|
+
// Output Reference Types (for $ref)
|
|
148
|
+
// =============================================================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* A reference to an output from a named stage.
|
|
152
|
+
*
|
|
153
|
+
* Reference syntax:
|
|
154
|
+
* - `"stageName"` - reference full output of named stage
|
|
155
|
+
* - `"stageName.field"` - reference field in output
|
|
156
|
+
* - `"stageName.nested.path"` - deep path traversal
|
|
157
|
+
* - `"$last"` - reference previous stage output
|
|
158
|
+
* - `"$last.value"` - reference field in previous output
|
|
159
|
+
*/
|
|
160
|
+
export interface OutputRef {
|
|
161
|
+
/** Path to a named output, optionally with property path */
|
|
162
|
+
readonly $ref: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Scope for tracking outputs during chain execution.
|
|
167
|
+
* Scopes form a tree structure for nested chains.
|
|
168
|
+
*/
|
|
169
|
+
export interface RefScope {
|
|
170
|
+
/** Named outputs in this scope */
|
|
171
|
+
outputs: Map<string, unknown>;
|
|
172
|
+
|
|
173
|
+
/** Previous step output ($last) */
|
|
174
|
+
last?: unknown | undefined;
|
|
175
|
+
|
|
176
|
+
/** Parent scope for nested chains */
|
|
177
|
+
parent?: RefScope | undefined;
|
|
178
|
+
|
|
179
|
+
/** This scope's name (if in a named chain) */
|
|
180
|
+
name?: string | undefined;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Create a new RefScope with optional parent.
|
|
185
|
+
*/
|
|
186
|
+
export function createRefScope(parent?: RefScope, name?: string): RefScope {
|
|
187
|
+
return {
|
|
188
|
+
outputs: new Map(),
|
|
189
|
+
parent,
|
|
190
|
+
name,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get a value by path from an object.
|
|
196
|
+
* Supports dot-separated paths like "foo.bar.baz".
|
|
197
|
+
* Only the own properties are read, so a path such as "a.constructor" gives undefined.
|
|
198
|
+
*/
|
|
199
|
+
export function getPath(obj: unknown, path: string[]): unknown {
|
|
200
|
+
let value = obj;
|
|
201
|
+
for (const key of path) {
|
|
202
|
+
if (value && typeof value === "object" && Object.hasOwn(value, key)) {
|
|
203
|
+
value = (value as Record<string, unknown>)[key];
|
|
204
|
+
} else {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Look up an output reference in a scope and its parents.
|
|
213
|
+
*
|
|
214
|
+
* The first segment is a name: the innermost scope with that name gives the value. `$last` is the
|
|
215
|
+
* last result of the innermost scope that has one. The other segments read fields of the value.
|
|
216
|
+
* `found` is false when no scope has the name. A missing field is `found` with the value undefined.
|
|
217
|
+
*/
|
|
218
|
+
export function lookupOutputRef(refPath: string, scope: RefScope | undefined): { found: boolean; value?: unknown } {
|
|
219
|
+
const [first, ...rest] = refPath.split(".");
|
|
220
|
+
for (let current = scope; current; current = current.parent) {
|
|
221
|
+
if (first === "$last") {
|
|
222
|
+
if (Object.hasOwn(current, "last")) return { found: true, value: getPath(current.last, rest) };
|
|
223
|
+
} else if (current.outputs.has(first!)) {
|
|
224
|
+
return { found: true, value: getPath(current.outputs.get(first!), rest) };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return { found: false };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Resolve an output reference within a scope.
|
|
232
|
+
*
|
|
233
|
+
* @param refPath - The reference path (e.g., "stageName.value" or "$last.value")
|
|
234
|
+
* @param scope - The current scope to resolve within
|
|
235
|
+
* @returns The resolved value, or undefined if not found
|
|
236
|
+
*/
|
|
237
|
+
export function resolveOutputRef(refPath: string, scope: RefScope): unknown {
|
|
238
|
+
return lookupOutputRef(refPath, scope).value;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// =============================================================================
|
|
242
|
+
// Scope of a raw input
|
|
243
|
+
// =============================================================================
|
|
244
|
+
|
|
245
|
+
const SCOPE_KEY = Symbol.for("@mark/ref-scope");
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* This function gives a copy of a raw input that carries a scope. A procedure that takes its input
|
|
249
|
+
* raw (control flow) reads the scope with `scopeOf()` and makes it the parent of its own scope.
|
|
250
|
+
* Thus the operands of a nested control-flow procedure can read the names of the outer chain.
|
|
251
|
+
* The scope is a property that is not enumerable: JSON and the transports do not see it.
|
|
252
|
+
*/
|
|
253
|
+
export function withScope<T>(input: T, scope: RefScope | undefined): T {
|
|
254
|
+
if (!scope || !isPlainObject(input)) return input;
|
|
255
|
+
const copy = { ...input };
|
|
256
|
+
Object.defineProperty(copy, SCOPE_KEY, { value: scope, enumerable: false });
|
|
257
|
+
return copy as T;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** The scope that a raw input carries (see `withScope()`), or undefined. */
|
|
261
|
+
export function scopeOf(input: unknown): RefScope | undefined {
|
|
262
|
+
if (typeof input !== "object" || input === null) return undefined;
|
|
263
|
+
return (input as { [SCOPE_KEY]?: RefScope })[SCOPE_KEY];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// =============================================================================
|
|
267
|
+
// Plain data
|
|
268
|
+
// =============================================================================
|
|
269
|
+
|
|
270
|
+
/** True for a plain object: an object literal, or an object with a null prototype. */
|
|
271
|
+
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
272
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
273
|
+
const prototype = Object.getPrototypeOf(value);
|
|
274
|
+
return prototype === Object.prototype || prototype === null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** True for `{ $literal: value }`: a plain object whose only key is `$literal`. */
|
|
278
|
+
export function isLiteral(value: unknown): value is { $literal: unknown } {
|
|
279
|
+
if (!isPlainObject(value)) return false;
|
|
280
|
+
const keys = Object.keys(value);
|
|
281
|
+
return keys.length === 1 && keys[0] === LITERAL_KEY;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// =============================================================================
|
|
285
|
+
// Procedure Reference Types
|
|
286
|
+
// =============================================================================
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Execution timing for procedure references.
|
|
290
|
+
* - `"$immediate"`: Execute during hydration (default)
|
|
291
|
+
* - `"$never"`: Never execute, pass as pure data
|
|
292
|
+
* - `"$parent"`: Defer to parent procedure
|
|
293
|
+
* - `string`: Defer to named ancestor context
|
|
294
|
+
*/
|
|
295
|
+
export type ProcedureWhen = "$immediate" | "$never" | "$parent" | string;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* A reference to a procedure with pre-bound input (runtime form).
|
|
299
|
+
* Can be passed as input to other procedures and will be executed during hydration.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const ref: ProcedureRef = {
|
|
304
|
+
* [PROCEDURE_SYMBOL]: true,
|
|
305
|
+
* path: ["git", "add"],
|
|
306
|
+
* input: { all: true },
|
|
307
|
+
* };
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
export interface ProcedureRef<TInput = unknown, TOutput = unknown> {
|
|
311
|
+
/** Symbol tag identifying this as a procedure reference */
|
|
312
|
+
readonly [PROCEDURE_SYMBOL]: true;
|
|
313
|
+
|
|
314
|
+
/** Path to the procedure */
|
|
315
|
+
readonly path: ProcedurePath;
|
|
316
|
+
|
|
317
|
+
/** Pre-bound input for the procedure */
|
|
318
|
+
readonly input: TInput;
|
|
319
|
+
|
|
320
|
+
/** Optional name for this execution context */
|
|
321
|
+
readonly $name?: string;
|
|
322
|
+
|
|
323
|
+
/** When to execute this reference */
|
|
324
|
+
readonly $when?: ProcedureWhen;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Phantom type for output inference.
|
|
328
|
+
* Not present at runtime, used for TypeScript type inference.
|
|
329
|
+
*/
|
|
330
|
+
readonly __output?: TOutput;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* JSON-serializable form of a procedure reference.
|
|
335
|
+
* Uses `$proc` key instead of Symbol for JSON compatibility.
|
|
336
|
+
*/
|
|
337
|
+
export interface ProcedureRefJson<TInput = unknown> {
|
|
338
|
+
/** JSON key identifying this as a procedure reference */
|
|
339
|
+
readonly $proc: ProcedurePath;
|
|
340
|
+
|
|
341
|
+
/** Pre-bound input for the procedure */
|
|
342
|
+
readonly input?: TInput;
|
|
343
|
+
|
|
344
|
+
/** Optional name for this execution context (for nested refs to target) */
|
|
345
|
+
readonly $name?: string;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* When to execute this reference:
|
|
349
|
+
* - "$immediate" (or absent): Execute during hydration
|
|
350
|
+
* - "$never": Never execute, pass as pure data
|
|
351
|
+
* - "$parent": Defer to parent procedure
|
|
352
|
+
* - "someName": Defer to named ancestor context
|
|
353
|
+
*/
|
|
354
|
+
readonly $when?: ProcedureWhen;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Either a runtime ProcedureRef or JSON-serialized form.
|
|
359
|
+
*/
|
|
360
|
+
export type AnyProcedureRef<TInput = unknown, TOutput = unknown> =
|
|
361
|
+
| ProcedureRef<TInput, TOutput>
|
|
362
|
+
| ProcedureRefJson<TInput>;
|
|
363
|
+
|
|
364
|
+
// =============================================================================
|
|
365
|
+
// Type Guards
|
|
366
|
+
// =============================================================================
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Check if a value is a procedure reference (runtime form with Symbol).
|
|
370
|
+
*/
|
|
371
|
+
export function isProcedureRef(value: unknown): value is ProcedureRef {
|
|
372
|
+
return (
|
|
373
|
+
typeof value === "object" &&
|
|
374
|
+
value !== null &&
|
|
375
|
+
PROCEDURE_SYMBOL in value &&
|
|
376
|
+
(value as Record<symbol, unknown>)[PROCEDURE_SYMBOL] === true
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Check if a value is a JSON procedure reference (serialized form with $proc key).
|
|
382
|
+
*/
|
|
383
|
+
export function isProcedureRefJson(value: unknown): value is ProcedureRefJson {
|
|
384
|
+
return (
|
|
385
|
+
typeof value === "object" &&
|
|
386
|
+
value !== null &&
|
|
387
|
+
PROCEDURE_JSON_KEY in value &&
|
|
388
|
+
Array.isArray((value as Record<string, unknown>)[PROCEDURE_JSON_KEY])
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Check if a value is any form of procedure reference.
|
|
394
|
+
*/
|
|
395
|
+
export function isAnyProcedureRef(value: unknown): value is AnyProcedureRef {
|
|
396
|
+
return isProcedureRef(value) || isProcedureRefJson(value);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Check if a value is an output reference ($ref).
|
|
401
|
+
*/
|
|
402
|
+
export function isOutputRef(value: unknown): value is OutputRef {
|
|
403
|
+
return (
|
|
404
|
+
typeof value === "object" &&
|
|
405
|
+
value !== null &&
|
|
406
|
+
OUTPUT_REF_KEY in value &&
|
|
407
|
+
typeof (value as Record<string, unknown>)[OUTPUT_REF_KEY] === "string"
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get the $when value from a procedure reference.
|
|
413
|
+
* Returns "$immediate" if not specified.
|
|
414
|
+
*/
|
|
415
|
+
export function getRefWhen(ref: AnyProcedureRef): ProcedureWhen {
|
|
416
|
+
if (isProcedureRef(ref)) {
|
|
417
|
+
return ref.$when ?? WHEN_IMMEDIATE;
|
|
418
|
+
}
|
|
419
|
+
return ref.$when ?? WHEN_IMMEDIATE;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get the $name value from a procedure reference, if any.
|
|
424
|
+
*/
|
|
425
|
+
export function getRefName(ref: AnyProcedureRef): string | undefined {
|
|
426
|
+
if (isProcedureRef(ref)) {
|
|
427
|
+
return ref.$name;
|
|
428
|
+
}
|
|
429
|
+
return ref.$name;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Check if a procedure reference should be executed in the given context.
|
|
434
|
+
*
|
|
435
|
+
* @param ref - The procedure reference to check
|
|
436
|
+
* @param contextStack - Stack of named contexts (innermost first)
|
|
437
|
+
* @param isParentContext - Whether we're checking from a parent procedure
|
|
438
|
+
* @returns true if the ref should be executed now
|
|
439
|
+
*/
|
|
440
|
+
export function shouldExecuteRef(
|
|
441
|
+
ref: AnyProcedureRef,
|
|
442
|
+
contextStack: string[],
|
|
443
|
+
isParentContext: boolean = false
|
|
444
|
+
): boolean {
|
|
445
|
+
const when = getRefWhen(ref);
|
|
446
|
+
|
|
447
|
+
// $immediate: always execute during hydration
|
|
448
|
+
if (when === WHEN_IMMEDIATE) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// $never: never execute during hydration
|
|
453
|
+
if (when === WHEN_NEVER) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// $parent: execute only when called from parent procedure
|
|
458
|
+
if (when === WHEN_PARENT) {
|
|
459
|
+
return isParentContext;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Named context: execute only when inside that named context
|
|
463
|
+
// The ref should execute when we're currently inside the named context
|
|
464
|
+
return contextStack.includes(when);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// =============================================================================
|
|
468
|
+
// Procedure Reference Builder
|
|
469
|
+
// =============================================================================
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Builder for creating procedure references with a fluent API.
|
|
473
|
+
*/
|
|
474
|
+
export class ProcedureRefBuilder<TInput = unknown, TOutput = unknown> {
|
|
475
|
+
private _path: ProcedurePath;
|
|
476
|
+
private _input: TInput = {} as TInput;
|
|
477
|
+
private _name?: string;
|
|
478
|
+
private _when?: ProcedureWhen;
|
|
479
|
+
|
|
480
|
+
constructor(path: ProcedurePath) {
|
|
481
|
+
this._path = path;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Set the input for this procedure reference.
|
|
486
|
+
*/
|
|
487
|
+
input<T>(input: T): ProcedureRefBuilder<T, TOutput> {
|
|
488
|
+
const builder = this as unknown as ProcedureRefBuilder<T, TOutput>;
|
|
489
|
+
builder._input = input;
|
|
490
|
+
return builder;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Name this execution context (for nested refs to target with $when).
|
|
495
|
+
*/
|
|
496
|
+
name(name: string): this {
|
|
497
|
+
this._name = name;
|
|
498
|
+
return this;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Set when this reference should be executed.
|
|
503
|
+
* @param when - "$immediate", "$never", "$parent", or a named context
|
|
504
|
+
*/
|
|
505
|
+
when(when: ProcedureWhen): this {
|
|
506
|
+
this._when = when;
|
|
507
|
+
return this;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Shorthand for .when("$never") - pass as pure data.
|
|
512
|
+
*/
|
|
513
|
+
defer(): this {
|
|
514
|
+
this._when = WHEN_NEVER;
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Shorthand for .when("$parent") - defer to parent procedure.
|
|
520
|
+
*/
|
|
521
|
+
deferToParent(): this {
|
|
522
|
+
this._when = WHEN_PARENT;
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Build the procedure reference object.
|
|
528
|
+
*/
|
|
529
|
+
build(): ProcedureRef<TInput, TOutput> {
|
|
530
|
+
const ref: ProcedureRef<TInput, TOutput> = {
|
|
531
|
+
[PROCEDURE_SYMBOL]: true,
|
|
532
|
+
path: this._path,
|
|
533
|
+
input: this._input,
|
|
534
|
+
} as ProcedureRef<TInput, TOutput>;
|
|
535
|
+
|
|
536
|
+
if (this._name) {
|
|
537
|
+
(ref as any).$name = this._name;
|
|
538
|
+
}
|
|
539
|
+
if (this._when) {
|
|
540
|
+
(ref as any).$when = this._when;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return ref;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Convert to JSON-serializable form.
|
|
548
|
+
*/
|
|
549
|
+
toJson(): ProcedureRefJson<TInput> {
|
|
550
|
+
const json: ProcedureRefJson<TInput> = {
|
|
551
|
+
$proc: this._path,
|
|
552
|
+
input: this._input,
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
if (this._name) {
|
|
556
|
+
(json as any).$name = this._name;
|
|
557
|
+
}
|
|
558
|
+
if (this._when) {
|
|
559
|
+
(json as any).$when = this._when;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return json;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Alias for build() - makes the builder callable in expression contexts.
|
|
567
|
+
*/
|
|
568
|
+
get ref(): ProcedureRef<TInput, TOutput> {
|
|
569
|
+
return this.build();
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Create a procedure reference.
|
|
575
|
+
*
|
|
576
|
+
* @param path - Path to the procedure
|
|
577
|
+
* @returns Builder for the procedure reference
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```typescript
|
|
581
|
+
* // Simple reference
|
|
582
|
+
* const addRef = proc(["git", "add"]).input({ all: true }).build();
|
|
583
|
+
*
|
|
584
|
+
* // Nested references (procedures as inputs)
|
|
585
|
+
* const pipeline = proc(["client", "chain"]).input({
|
|
586
|
+
* steps: [
|
|
587
|
+
* proc(["git", "add"]).input({ all: true }).ref,
|
|
588
|
+
* proc(["git", "commit"]).input({ message: "auto" }).ref,
|
|
589
|
+
* ],
|
|
590
|
+
* }).build();
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
593
|
+
export function proc<TOutput = unknown>(
|
|
594
|
+
path: ProcedurePath
|
|
595
|
+
): ProcedureRefBuilder<unknown, TOutput> {
|
|
596
|
+
return new ProcedureRefBuilder<unknown, TOutput>(path);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// =============================================================================
|
|
600
|
+
// JSON Conversion
|
|
601
|
+
// =============================================================================
|
|
602
|
+
|
|
603
|
+
/** The `$name` and `$when` fields of a reference, for a copy in the other form. */
|
|
604
|
+
function refFields(ref: { $name?: string | undefined; $when?: ProcedureWhen | undefined }): {
|
|
605
|
+
$name?: string;
|
|
606
|
+
$when?: ProcedureWhen;
|
|
607
|
+
} {
|
|
608
|
+
return {
|
|
609
|
+
...(ref.$name !== undefined ? { $name: ref.$name } : {}),
|
|
610
|
+
...(ref.$when !== undefined ? { $when: ref.$when } : {}),
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Convert a procedure reference from JSON form to runtime form.
|
|
616
|
+
* The `$name` and `$when` fields stay (deep dive CORE-11: before, they were dropped).
|
|
617
|
+
*/
|
|
618
|
+
export function fromJson<TInput, TOutput>(
|
|
619
|
+
json: ProcedureRefJson<TInput>
|
|
620
|
+
): ProcedureRef<TInput, TOutput> {
|
|
621
|
+
return {
|
|
622
|
+
[PROCEDURE_SYMBOL]: true,
|
|
623
|
+
path: json.$proc,
|
|
624
|
+
input: json.input,
|
|
625
|
+
...refFields(json),
|
|
626
|
+
} as ProcedureRef<TInput, TOutput>;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Convert a procedure reference from runtime form to JSON form.
|
|
631
|
+
* The `$name` and `$when` fields stay.
|
|
632
|
+
*/
|
|
633
|
+
export function toJson<TInput>(ref: ProcedureRef<TInput>): ProcedureRefJson<TInput> {
|
|
634
|
+
return {
|
|
635
|
+
$proc: ref.path,
|
|
636
|
+
input: ref.input,
|
|
637
|
+
...refFields(ref),
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Normalize any procedure reference to runtime form.
|
|
643
|
+
*/
|
|
644
|
+
export function normalizeRef<TInput, TOutput>(
|
|
645
|
+
ref: AnyProcedureRef<TInput, TOutput>
|
|
646
|
+
): ProcedureRef<TInput, TOutput> {
|
|
647
|
+
if (isProcedureRef(ref)) {
|
|
648
|
+
return ref;
|
|
649
|
+
}
|
|
650
|
+
return fromJson(ref);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// =============================================================================
|
|
654
|
+
// Input Hydration
|
|
655
|
+
// =============================================================================
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Executor function type for hydration.
|
|
659
|
+
* Called for each procedure reference found during hydration.
|
|
660
|
+
*/
|
|
661
|
+
export type RefExecutor = <TInput, TOutput>(
|
|
662
|
+
path: ProcedurePath,
|
|
663
|
+
input: TInput
|
|
664
|
+
) => Promise<TOutput>;
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Options for input hydration.
|
|
668
|
+
*/
|
|
669
|
+
export interface HydrateOptions {
|
|
670
|
+
/**
|
|
671
|
+
* Maximum nesting of procedure refs (default: 10). Plain data does not count: only the input
|
|
672
|
+
* of a ref inside the input of another ref adds one level.
|
|
673
|
+
*/
|
|
674
|
+
maxDepth?: number | undefined;
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Whether sibling refs run at the same time (default: false). With false, the refs run one
|
|
678
|
+
* after the other, from left to right and depth first, so the order of their effects is known.
|
|
679
|
+
*/
|
|
680
|
+
parallel?: boolean | undefined;
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* The context names of the runner. A ref with `$when: "<name>"` runs only when this list has
|
|
684
|
+
* the name. A runner such as `core.catch` gives its own name here when it hydrates its operand.
|
|
685
|
+
*/
|
|
686
|
+
contextStack?: string[] | undefined;
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Scope for resolving output references ($ref). Without a scope, a `$ref` object stays as it
|
|
690
|
+
* is (for example a JSON Schema reference). With a scope, a `$ref` name that no scope has is an error.
|
|
691
|
+
*/
|
|
692
|
+
scope?: RefScope | undefined;
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* This function tells whether the procedure at a path takes its input raw (control flow, the
|
|
696
|
+
* `runs-refs` and `raw-input` tags). Such a procedure gets the refs of its input unchanged and
|
|
697
|
+
* runs them itself. The default knows the core control-flow paths only. See `rawInputRule()`.
|
|
698
|
+
*/
|
|
699
|
+
rawInput?: ((path: ProcedurePath) => boolean) | undefined;
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* This function gets an event each time hydration runs a ref (see `HydrationEvent`). A trace
|
|
703
|
+
* uses it to show a nested call under the call that gets its result. An error of the function
|
|
704
|
+
* does not change the hydration.
|
|
705
|
+
*/
|
|
706
|
+
onRef?: ((event: HydrationEvent) => void) | undefined;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* An event of hydration: a procedure ref of the input runs now. Its input is hydrated already,
|
|
711
|
+
* so the events of the refs inside its input came first.
|
|
712
|
+
*/
|
|
713
|
+
export interface HydrationEvent {
|
|
714
|
+
/** The path of the procedure that runs. */
|
|
715
|
+
readonly path: ProcedurePath;
|
|
716
|
+
/**
|
|
717
|
+
* The ref that runs: the object of the program. For an array of refs that runs as an implicit
|
|
718
|
+
* chain, it is the `client.chain` ref that hydration made.
|
|
719
|
+
*/
|
|
720
|
+
readonly ref: AnyProcedureRef;
|
|
721
|
+
/**
|
|
722
|
+
* The ref whose input holds this ref: the call that gets the result. It is undefined when the
|
|
723
|
+
* ref is at the top of the hydrated value. Then the caller of the hydration gets the result:
|
|
724
|
+
* `exec()` gives it to the root call, and a control-flow procedure to its operand call.
|
|
725
|
+
*/
|
|
726
|
+
readonly consumer: AnyProcedureRef | undefined;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/** The observers of `observeHydration()`: they get the events of every hydration. */
|
|
730
|
+
const hydrationObservers = new Set<(event: HydrationEvent) => void>();
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* This function adds an observer of every hydration in this process (or worker), and gives the
|
|
734
|
+
* function that removes it. A host that does not call `hydrateInput` itself (the Composer of
|
|
735
|
+
* the site runs `client.exec()`) uses it for its trace. The observer gets the events of all
|
|
736
|
+
* concurrent hydrations: use it where one program runs at a time. For the events of one program,
|
|
737
|
+
* give `onRef` to that program: `client.exec(ref, input, { onRef })` (docs review DOC-10).
|
|
738
|
+
*/
|
|
739
|
+
export function observeHydration(observer: (event: HydrationEvent) => void): () => void {
|
|
740
|
+
hydrationObservers.add(observer);
|
|
741
|
+
return () => {
|
|
742
|
+
hydrationObservers.delete(observer);
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/** The maximum nesting of plain data in an input. A deeper input is an error, not a stack overflow. */
|
|
747
|
+
export const MAX_DATA_DEPTH = 1000;
|
|
748
|
+
|
|
749
|
+
/** The objects on the path from the root of the input to a value, to find a cycle. */
|
|
750
|
+
interface Ancestors {
|
|
751
|
+
readonly value: object;
|
|
752
|
+
readonly up: Ancestors | undefined;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Internal context for hydration.
|
|
757
|
+
*/
|
|
758
|
+
interface HydrateContext {
|
|
759
|
+
executor: RefExecutor;
|
|
760
|
+
maxDepth: number;
|
|
761
|
+
parallel: boolean;
|
|
762
|
+
contextStack: string[];
|
|
763
|
+
scope?: RefScope | undefined;
|
|
764
|
+
rawInput: (path: ProcedurePath) => boolean;
|
|
765
|
+
/** Prevent recursive implicit chain detection */
|
|
766
|
+
skipImplicitChain: boolean;
|
|
767
|
+
/** Inside a deferred ref, a `$ref` name that is not known yet stays for the runner. */
|
|
768
|
+
deferred: boolean;
|
|
769
|
+
/** The `onRef` function of the options */
|
|
770
|
+
onRef: ((event: HydrationEvent) => void) | undefined;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Hydrate an input tree by executing any nested procedure references.
|
|
775
|
+
*
|
|
776
|
+
* Walks the input object tree and replaces any ProcedureRef or ProcedureRefJson
|
|
777
|
+
* objects with the result of executing that procedure, respecting $when timing.
|
|
778
|
+
*
|
|
779
|
+
* The rules:
|
|
780
|
+
* - A ref with `$when: "$immediate"` (the default) runs. A ref whose procedure takes its input
|
|
781
|
+
* raw (see `HydrateOptions.rawInput`) gets its input unchanged, with the scope attached.
|
|
782
|
+
* - A ref with `$when: "$never"` stays as it is, with its whole subtree.
|
|
783
|
+
* - A ref with `$when: "$parent"` or `$when: "<name>"` stays data for its runner. Its procedure
|
|
784
|
+
* gets that ref later. The immediate refs of its input run now, unless the procedure takes its
|
|
785
|
+
* input raw. A named ref runs now only when `contextStack` has the name.
|
|
786
|
+
* - A `$ref` object gives a value from the scope. `{ $literal: value }` gives the value unchanged.
|
|
787
|
+
* - An array whose items are all refs that run now, outside the input of a ref, runs as one
|
|
788
|
+
* `client.chain`. An array with a deferred ref is a list.
|
|
789
|
+
* - Values that are not plain data (`Date`, `Map`, typed arrays, class instances) stay unchanged.
|
|
790
|
+
* A subtree without refs stays the same object.
|
|
791
|
+
*
|
|
792
|
+
* @param input - The input object potentially containing procedure references
|
|
793
|
+
* @param executor - Function to execute procedure references
|
|
794
|
+
* @param options - Hydration options
|
|
795
|
+
* @returns The hydrated input with executed procedure refs replaced by their results
|
|
796
|
+
*
|
|
797
|
+
* @example
|
|
798
|
+
* ```typescript
|
|
799
|
+
* const input = {
|
|
800
|
+
* visit: proc(["git", "add"]).input({ all: true }).build(),
|
|
801
|
+
* config: { nested: true },
|
|
802
|
+
* };
|
|
803
|
+
*
|
|
804
|
+
* const hydrated = await hydrateInput(input, async (path, input) => {
|
|
805
|
+
* return await client.call({ path, input });
|
|
806
|
+
* });
|
|
807
|
+
*
|
|
808
|
+
* // hydrated.visit is now the result of executing git.add
|
|
809
|
+
* ```
|
|
810
|
+
*/
|
|
811
|
+
export async function hydrateInput<T>(
|
|
812
|
+
input: T,
|
|
813
|
+
executor: RefExecutor,
|
|
814
|
+
options: HydrateOptions = {}
|
|
815
|
+
): Promise<T> {
|
|
816
|
+
const ctx: HydrateContext = {
|
|
817
|
+
executor,
|
|
818
|
+
maxDepth: options.maxDepth ?? 10,
|
|
819
|
+
parallel: options.parallel ?? false,
|
|
820
|
+
contextStack: options.contextStack ?? [],
|
|
821
|
+
scope: options.scope,
|
|
822
|
+
rawInput: options.rawInput ?? isControlFlowPath,
|
|
823
|
+
skipImplicitChain: false,
|
|
824
|
+
deferred: false,
|
|
825
|
+
onRef: options.onRef,
|
|
826
|
+
};
|
|
827
|
+
return hydrateValue(input, ctx, 0, undefined, 0);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* The path and the input of the root call of a program: the call that `client.exec()` starts.
|
|
832
|
+
* `exec()` and the body of a procedure that `procedure.define` made both use this function, so
|
|
833
|
+
* the same program gives the same result in both (docs review DOC-3: before, a defined body
|
|
834
|
+
* hydrated its root call as a nested ref).
|
|
835
|
+
*
|
|
836
|
+
* The rules of the root call:
|
|
837
|
+
* - A `$when` on the root call does not apply: the caller starts the root call now.
|
|
838
|
+
* - A procedure that takes its input raw (`rawInput`) gets its input unchanged, with the scope
|
|
839
|
+
* attached, and runs its operands itself.
|
|
840
|
+
* - Another procedure gets its input hydrated as a root: a list of calls that run now is an
|
|
841
|
+
* implicit chain, and the nested refs run.
|
|
842
|
+
*
|
|
843
|
+
* The caller then starts the call with the path and the input.
|
|
844
|
+
*/
|
|
845
|
+
export async function prepareRootCall(
|
|
846
|
+
ref: AnyProcedureRef,
|
|
847
|
+
executor: RefExecutor,
|
|
848
|
+
options: Pick<HydrateOptions, "rawInput" | "onRef" | "scope"> = {}
|
|
849
|
+
): Promise<{ path: ProcedurePath; input: unknown }> {
|
|
850
|
+
const root = normalizeRef(ref);
|
|
851
|
+
const rawInput = options.rawInput ?? isControlFlowPath;
|
|
852
|
+
if (rawInput(root.path)) {
|
|
853
|
+
return { path: root.path, input: withScope(root.input, options.scope) };
|
|
854
|
+
}
|
|
855
|
+
const input = await hydrateInput(root.input, executor, { rawInput, onRef: options.onRef, scope: options.scope });
|
|
856
|
+
return { path: root.path, input };
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* This function tells the observers that a ref runs now. The consumer is the nearest ref
|
|
861
|
+
* around the ref. An observer that throws does not change the hydration.
|
|
862
|
+
*/
|
|
863
|
+
function notifyRef(ctx: HydrateContext, ref: AnyProcedureRef, path: ProcedurePath, ancestors: Ancestors | undefined): void {
|
|
864
|
+
if (!ctx.onRef && hydrationObservers.size === 0) return;
|
|
865
|
+
let consumer: AnyProcedureRef | undefined;
|
|
866
|
+
for (let current = ancestors; current; current = current.up) {
|
|
867
|
+
if (isAnyProcedureRef(current.value)) {
|
|
868
|
+
consumer = current.value;
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const event: HydrationEvent = { path, ref, consumer };
|
|
873
|
+
for (const observer of ctx.onRef ? [ctx.onRef, ...hydrationObservers] : hydrationObservers) {
|
|
874
|
+
try {
|
|
875
|
+
observer(event);
|
|
876
|
+
} catch {
|
|
877
|
+
// A trace must not change the program
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/** The values of `fn` for each item: one after the other, or at the same time. */
|
|
883
|
+
async function eachValue<T>(items: readonly T[], fn: (item: T) => Promise<unknown>, parallel: boolean): Promise<unknown[]> {
|
|
884
|
+
if (parallel) return Promise.all(items.map(fn));
|
|
885
|
+
const results: unknown[] = [];
|
|
886
|
+
for (const item of items) results.push(await fn(item));
|
|
887
|
+
return results;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/** This function resolves a `$ref` in the scope of the hydration. */
|
|
891
|
+
function resolveRefValue(value: OutputRef, ctx: HydrateContext): unknown {
|
|
892
|
+
// No scope: the object is data (for example a JSON Schema reference), or a later scope binds it
|
|
893
|
+
if (!ctx.scope) return value;
|
|
894
|
+
const { found, value: resolved } = lookupOutputRef(value.$ref, ctx.scope);
|
|
895
|
+
if (found) return resolved;
|
|
896
|
+
// Inside a deferred ref, the runner can bind the name later
|
|
897
|
+
if (ctx.deferred) return value;
|
|
898
|
+
const name = value.$ref.split(".")[0];
|
|
899
|
+
throw new Error(
|
|
900
|
+
`Unknown $ref name "${name}" in "${value.$ref}": no step, item or input has this name here. ` +
|
|
901
|
+
`For a literal $ref object, write { "$literal": { "$ref": ... } }.`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Internal recursive hydration function.
|
|
907
|
+
*
|
|
908
|
+
* `refDepth` counts the refs around the value. `dataDepth` counts all levels.
|
|
909
|
+
*/
|
|
910
|
+
async function hydrateValue<T>(
|
|
911
|
+
value: T,
|
|
912
|
+
ctx: HydrateContext,
|
|
913
|
+
refDepth: number,
|
|
914
|
+
ancestors: Ancestors | undefined,
|
|
915
|
+
dataDepth: number
|
|
916
|
+
): Promise<T> {
|
|
917
|
+
// Handle null/undefined/primitives
|
|
918
|
+
if (value === null || typeof value !== "object") {
|
|
919
|
+
return value;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (dataDepth > MAX_DATA_DEPTH) {
|
|
923
|
+
throw new Error(`Hydration failed: the input has more than ${MAX_DATA_DEPTH} levels of nesting`);
|
|
924
|
+
}
|
|
925
|
+
for (let current = ancestors; current; current = current.up) {
|
|
926
|
+
if (current.value === value) {
|
|
927
|
+
throw new Error("Hydration failed: the input is cyclic (an object contains itself)");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// { $literal: value } gives the value without hydration
|
|
932
|
+
if (isLiteral(value)) {
|
|
933
|
+
return value.$literal as T;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// Check if this is an output reference ($ref)
|
|
937
|
+
if (isOutputRef(value)) {
|
|
938
|
+
return resolveRefValue(value, ctx) as T;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Check if this is a procedure reference ($proc)
|
|
942
|
+
if (isAnyProcedureRef(value)) {
|
|
943
|
+
return hydrateRef(value, ctx, refDepth, ancestors, dataDepth) as Promise<T>;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const inner: Ancestors = { value, up: ancestors };
|
|
947
|
+
|
|
948
|
+
// Handle arrays
|
|
949
|
+
if (Array.isArray(value)) {
|
|
950
|
+
// An array of procedure refs that all run now is an implicit chain. A deferred ref ($never,
|
|
951
|
+
// $parent, a context name that the runner did not give) is data, so a list with one is a list
|
|
952
|
+
// (docs review DOC-1: before, a list of only $never refs ran as a chain). Inside an implicit
|
|
953
|
+
// chain, the steps do not make another one.
|
|
954
|
+
if (
|
|
955
|
+
!ctx.skipImplicitChain &&
|
|
956
|
+
value.length > 0 &&
|
|
957
|
+
value.every((item) => isAnyProcedureRef(item) && shouldExecuteRef(item, ctx.contextStack, false))
|
|
958
|
+
) {
|
|
959
|
+
// client.chain runs the steps in order: they reach it raw. (Before, hydration ran the steps
|
|
960
|
+
// all at once, and client.chain got their results: deep dive, architecture review 3.4.)
|
|
961
|
+
const implicitChain: ProcedureRefJson = { $proc: ["client", "chain"], input: { steps: value } };
|
|
962
|
+
return hydrateRef(implicitChain, { ...ctx, skipImplicitChain: true }, refDepth, ancestors, dataDepth) as Promise<T>;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const items = await eachValue(value, (item) => hydrateValue(item, ctx, refDepth, inner, dataDepth + 1), ctx.parallel);
|
|
966
|
+
return (items.every((item, index) => item === value[index]) ? value : items) as T;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Values that are not plain data (Date, Map, typed arrays, class instances) stay unchanged
|
|
970
|
+
if (!isPlainObject(value)) {
|
|
971
|
+
return value;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Handle plain objects
|
|
975
|
+
const entries = Object.entries(value);
|
|
976
|
+
const values = await eachValue(entries, ([, val]) => hydrateValue(val, ctx, refDepth, inner, dataDepth + 1), ctx.parallel);
|
|
977
|
+
if (values.every((val, index) => val === entries[index]![1])) {
|
|
978
|
+
return value;
|
|
979
|
+
}
|
|
980
|
+
// Object.fromEntries makes own properties, also for a key such as "__proto__"
|
|
981
|
+
return Object.fromEntries(entries.map(([key], index) => [key, values[index]])) as T;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/** This function hydrates one procedure ref: it runs the ref, or it keeps the ref as data. */
|
|
985
|
+
async function hydrateRef(
|
|
986
|
+
value: AnyProcedureRef,
|
|
987
|
+
ctx: HydrateContext,
|
|
988
|
+
refDepth: number,
|
|
989
|
+
ancestors: Ancestors | undefined,
|
|
990
|
+
dataDepth: number
|
|
991
|
+
): Promise<unknown> {
|
|
992
|
+
const when = getRefWhen(value);
|
|
993
|
+
|
|
994
|
+
// $never: pure data, with its whole subtree (deep dive CORE-11: before, its input was hydrated)
|
|
995
|
+
if (when === WHEN_NEVER) {
|
|
996
|
+
return value;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (refDepth >= ctx.maxDepth) {
|
|
1000
|
+
throw new Error(`Hydration depth exceeded maximum of ${ctx.maxDepth}`);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const ref = normalizeRef(value);
|
|
1004
|
+
const raw = ctx.rawInput(ref.path);
|
|
1005
|
+
const inner: Ancestors = { value, up: ancestors };
|
|
1006
|
+
// The input of a ref is never an implicit chain
|
|
1007
|
+
const inputCtx = (deferred: boolean): HydrateContext => ({ ...ctx, skipImplicitChain: true, deferred });
|
|
1008
|
+
|
|
1009
|
+
// A ref that waits for its runner ($parent, or a name that the runner did not give) is data.
|
|
1010
|
+
// Its own $name is not a context here: hydration of its input does not run refs that wait for
|
|
1011
|
+
// it, at any depth (deep dive CORE-11: before, this depended on the depth of the ref).
|
|
1012
|
+
if (!shouldExecuteRef(value, ctx.contextStack, false)) {
|
|
1013
|
+
if (raw) return value;
|
|
1014
|
+
const input = await hydrateValue(ref.input, inputCtx(true), refDepth + 1, inner, dataDepth + 1);
|
|
1015
|
+
return input === ref.input ? value : { ...value, input };
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// A procedure that takes its input raw gets it unchanged, with the scope of the caller
|
|
1019
|
+
if (raw) {
|
|
1020
|
+
notifyRef(ctx, value, ref.path, ancestors);
|
|
1021
|
+
return ctx.executor(ref.path, withScope(ref.input, ctx.scope));
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const input = await hydrateValue(ref.input, inputCtx(false), refDepth + 1, inner, dataDepth + 1);
|
|
1025
|
+
notifyRef(ctx, value, ref.path, ancestors);
|
|
1026
|
+
return ctx.executor(ref.path, input);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// =============================================================================
|
|
1030
|
+
// Control-Flow Procedures
|
|
1031
|
+
// =============================================================================
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Last path segments of the core control-flow procedures (registered under `["client", ...]`).
|
|
1035
|
+
*
|
|
1036
|
+
* These procedures MUST receive their operand refs RAW so their handlers can execute
|
|
1037
|
+
* them with correct ordering, laziness, short-circuiting, and error scoping. If `exec()`
|
|
1038
|
+
* eagerly hydrated their inputs, the operands would run up-front (voiding conditional/
|
|
1039
|
+
* tryCatch short-circuiting) and an all-refs array would be hijacked into an implicit
|
|
1040
|
+
* chain that clobbers `steps` — the outer handler then throws `steps is not iterable`.
|
|
1041
|
+
* See documentation/BUGS-2026-07.md (C2, H2, H3, M35).
|
|
1042
|
+
*/
|
|
1043
|
+
export const CONTROL_FLOW_PROCEDURES: ReadonlySet<string> = new Set([
|
|
1044
|
+
"chain",
|
|
1045
|
+
"parallel",
|
|
1046
|
+
"conditional",
|
|
1047
|
+
"tryCatch",
|
|
1048
|
+
"and",
|
|
1049
|
+
"or",
|
|
1050
|
+
"map",
|
|
1051
|
+
"reduce",
|
|
1052
|
+
]);
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Whether a procedure path is one of the core control-flow procedures (`client.chain`,
|
|
1056
|
+
* `client.map` and the others). The whole path must match: a user procedure `foo.map` is not
|
|
1057
|
+
* control flow (deep dive CORE-5: before, only the last segment was compared).
|
|
1058
|
+
*/
|
|
1059
|
+
export function isControlFlowPath(path: ProcedurePath): boolean {
|
|
1060
|
+
return path.length === 2 && path[0] === "client" && CONTROL_FLOW_PROCEDURES.has(path[1]!);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* The tag of a procedure that runs procedure refs from its input (for example `dag.traverse`).
|
|
1065
|
+
* A server with an `expose` rule lets such a procedure call only the exposed procedures.
|
|
1066
|
+
* Hydration gives such a procedure its input raw.
|
|
1067
|
+
*/
|
|
1068
|
+
export const RUNS_REFS_TAG = "runs-refs";
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* The tag of a procedure that takes refs as data and does not run them (for example
|
|
1072
|
+
* `client.export`, which writes a ref as JSON). Hydration gives such a procedure its input raw.
|
|
1073
|
+
*/
|
|
1074
|
+
export const RAW_INPUT_TAG = "raw-input";
|
|
1075
|
+
|
|
1076
|
+
/** The fields of a procedure that the rules of this module read. */
|
|
1077
|
+
interface ProcedureShape {
|
|
1078
|
+
path: ProcedurePath;
|
|
1079
|
+
metadata?: { tags?: string[] | undefined } | undefined;
|
|
1080
|
+
handler?: unknown;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
const DATA_DRIVEN_HANDLERS = new WeakSet<object>();
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* This function marks a procedure whose behavior comes from data, for example a procedure
|
|
1087
|
+
* that `procedure.define` made from an aggregation. The mark is on the handler function: the
|
|
1088
|
+
* registry stores a copy of each procedure, but the copy has the same handler. The mark is not
|
|
1089
|
+
* in the metadata, because the caller of `procedure.define` gives the metadata.
|
|
1090
|
+
*/
|
|
1091
|
+
export function markDataDriven<T extends { handler?: unknown }>(procedure: T): T {
|
|
1092
|
+
if (typeof procedure.handler === "function") DATA_DRIVEN_HANDLERS.add(procedure.handler);
|
|
1093
|
+
return procedure;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* A data-driven procedure runs procedure refs that come from its input or from data: the
|
|
1098
|
+
* control-flow procedures, the procedures with the `runs-refs` tag and the procedures that
|
|
1099
|
+
* `procedure.define` made. The caller of such a procedure chooses what it calls.
|
|
1100
|
+
*/
|
|
1101
|
+
export function isDataDriven(procedure: ProcedureShape): boolean {
|
|
1102
|
+
return (
|
|
1103
|
+
isControlFlowPath(procedure.path) ||
|
|
1104
|
+
(procedure.metadata?.tags?.includes(RUNS_REFS_TAG) ?? false) ||
|
|
1105
|
+
(typeof procedure.handler === "function" && DATA_DRIVEN_HANDLERS.has(procedure.handler))
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* A procedure that takes its input raw: the control-flow procedures and the procedures with the
|
|
1111
|
+
* `runs-refs` or `raw-input` tag. `exec()` and hydration do not run the refs of such an input.
|
|
1112
|
+
* A procedure that `procedure.define` made takes ordinary input: its body is the data-driven part.
|
|
1113
|
+
*/
|
|
1114
|
+
export function takesRawInput(procedure: ProcedureShape): boolean {
|
|
1115
|
+
const tags = procedure.metadata?.tags;
|
|
1116
|
+
return (
|
|
1117
|
+
isControlFlowPath(procedure.path) ||
|
|
1118
|
+
(tags?.includes(RUNS_REFS_TAG) ?? false) ||
|
|
1119
|
+
(tags?.includes(RAW_INPUT_TAG) ?? false)
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* The raw-input rule of a registry, for `HydrateOptions.rawInput`. The procedure at the path
|
|
1125
|
+
* decides (deep dive CORE-5). A path that the registry does not have uses the control-flow paths.
|
|
1126
|
+
*/
|
|
1127
|
+
export function rawInputRule(
|
|
1128
|
+
registry: { get(path: ProcedurePath): ProcedureShape | undefined } | undefined
|
|
1129
|
+
): (path: ProcedurePath) => boolean {
|
|
1130
|
+
return (path) => {
|
|
1131
|
+
const procedure = registry?.get(path);
|
|
1132
|
+
return procedure ? takesRawInput(procedure) : isControlFlowPath(path);
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// =============================================================================
|
|
1137
|
+
// Deferred Ref Execution
|
|
1138
|
+
// =============================================================================
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Execute a deferred procedure reference.
|
|
1142
|
+
*
|
|
1143
|
+
* This is a helper for procedures that receive deferred refs (via $when)
|
|
1144
|
+
* and need to execute them with additional context.
|
|
1145
|
+
*
|
|
1146
|
+
* @param ref - The procedure reference to execute
|
|
1147
|
+
* @param executor - Function to execute the procedure
|
|
1148
|
+
* @param additionalInput - Additional input to merge (e.g., cwd for dag.traverse)
|
|
1149
|
+
* @param options - Hydration options for the input of the ref (for example the runner's `contextStack`)
|
|
1150
|
+
* @returns The result of executing the procedure
|
|
1151
|
+
*
|
|
1152
|
+
* @example
|
|
1153
|
+
* ```typescript
|
|
1154
|
+
* // In dag.traverse, execute a deferred ref with cwd
|
|
1155
|
+
* const result = await executeRef(
|
|
1156
|
+
* input.visit,
|
|
1157
|
+
* (path, input) => ctx.client.call(path, input),
|
|
1158
|
+
* { cwd: node.repoPath }
|
|
1159
|
+
* );
|
|
1160
|
+
* ```
|
|
1161
|
+
*/
|
|
1162
|
+
export async function executeRef<TOutput = unknown>(
|
|
1163
|
+
ref: AnyProcedureRef,
|
|
1164
|
+
executor: RefExecutor,
|
|
1165
|
+
additionalInput?: Record<string, unknown>,
|
|
1166
|
+
options: HydrateOptions = {}
|
|
1167
|
+
): Promise<TOutput> {
|
|
1168
|
+
const normalized = normalizeRef(ref);
|
|
1169
|
+
const baseInput = typeof normalized.input === "object" ? normalized.input : {};
|
|
1170
|
+
|
|
1171
|
+
// Merge additional input
|
|
1172
|
+
const mergedInput = {
|
|
1173
|
+
...(baseInput as Record<string, unknown>),
|
|
1174
|
+
...additionalInput,
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
const raw = (options.rawInput ?? isControlFlowPath)(normalized.path);
|
|
1178
|
+
if (raw) {
|
|
1179
|
+
return executor(normalized.path, withScope(mergedInput, options.scope));
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Hydrate the merged input (execute any nested $immediate refs)
|
|
1183
|
+
const hydratedInput = await hydrateInput(mergedInput, executor, options);
|
|
1184
|
+
|
|
1185
|
+
return executor(normalized.path, hydratedInput);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// =============================================================================
|
|
1189
|
+
// Template Extraction
|
|
1190
|
+
// =============================================================================
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Extract a JSON template from a procedure reference.
|
|
1194
|
+
* Useful for serializing imperative procedure compositions.
|
|
1195
|
+
* The `$name` and `$when` fields stay. A `$literal` stays as it is.
|
|
1196
|
+
*
|
|
1197
|
+
* @param ref - Procedure reference to extract template from
|
|
1198
|
+
* @returns JSON-serializable template
|
|
1199
|
+
*/
|
|
1200
|
+
export function extractTemplate<TInput>(
|
|
1201
|
+
ref: ProcedureRef<TInput>
|
|
1202
|
+
): ProcedureRefJson<unknown> {
|
|
1203
|
+
return extractTemplateValue(ref) as ProcedureRefJson<unknown>;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* Internal recursive template extraction.
|
|
1208
|
+
*/
|
|
1209
|
+
function extractTemplateValue(value: unknown): unknown {
|
|
1210
|
+
if (value === null || value === undefined) {
|
|
1211
|
+
return value;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
if (typeof value !== "object") {
|
|
1215
|
+
return value;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
if (isLiteral(value)) {
|
|
1219
|
+
return value;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// Convert procedure refs to JSON form (runtime form, or already JSON form)
|
|
1223
|
+
if (isAnyProcedureRef(value)) {
|
|
1224
|
+
const ref = normalizeRef(value);
|
|
1225
|
+
return {
|
|
1226
|
+
$proc: ref.path,
|
|
1227
|
+
input: extractTemplateValue(ref.input),
|
|
1228
|
+
...refFields(ref),
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Handle arrays
|
|
1233
|
+
if (Array.isArray(value)) {
|
|
1234
|
+
return value.map(extractTemplateValue);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// Handle plain objects
|
|
1238
|
+
const obj = value as Record<string, unknown>;
|
|
1239
|
+
return Object.fromEntries(Object.entries(obj).map(([key, val]) => [key, extractTemplateValue(val)]));
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// =============================================================================
|
|
1243
|
+
// Parse JSON with Procedure Refs
|
|
1244
|
+
// =============================================================================
|
|
1245
|
+
|
|
1246
|
+
/**
|
|
1247
|
+
* Parse JSON string and convert $proc objects to runtime ProcedureRef objects.
|
|
1248
|
+
* The `$name` and `$when` fields stay. A `$literal` stays as it is.
|
|
1249
|
+
*
|
|
1250
|
+
* @param json - JSON string potentially containing procedure references
|
|
1251
|
+
* @returns Parsed object with ProcedureRef objects
|
|
1252
|
+
*/
|
|
1253
|
+
export function parseProcedureJson<T>(json: string): T {
|
|
1254
|
+
const parsed = JSON.parse(json);
|
|
1255
|
+
return convertJsonToRefs(parsed) as T;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/**
|
|
1259
|
+
* Convert parsed JSON to runtime procedure refs.
|
|
1260
|
+
*/
|
|
1261
|
+
function convertJsonToRefs(value: unknown): unknown {
|
|
1262
|
+
if (value === null || value === undefined) {
|
|
1263
|
+
return value;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
if (typeof value !== "object") {
|
|
1267
|
+
return value;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
if (isLiteral(value)) {
|
|
1271
|
+
return value;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// Convert $proc objects to ProcedureRef
|
|
1275
|
+
if (isProcedureRefJson(value)) {
|
|
1276
|
+
return {
|
|
1277
|
+
[PROCEDURE_SYMBOL]: true,
|
|
1278
|
+
path: value.$proc,
|
|
1279
|
+
input: convertJsonToRefs(value.input),
|
|
1280
|
+
...refFields(value),
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// Handle arrays
|
|
1285
|
+
if (Array.isArray(value)) {
|
|
1286
|
+
return value.map(convertJsonToRefs);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Handle plain objects
|
|
1290
|
+
const obj = value as Record<string, unknown>;
|
|
1291
|
+
return Object.fromEntries(Object.entries(obj).map(([key, val]) => [key, convertJsonToRefs(val)]));
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/**
|
|
1295
|
+
* Stringify an object with procedure refs to JSON.
|
|
1296
|
+
* Converts ProcedureRef objects to $proc JSON form.
|
|
1297
|
+
*
|
|
1298
|
+
* @param value - Object potentially containing ProcedureRef objects
|
|
1299
|
+
* @param space - Indentation (passed to JSON.stringify)
|
|
1300
|
+
* @returns JSON string
|
|
1301
|
+
*/
|
|
1302
|
+
export function stringifyProcedureJson(value: unknown, space?: number): string {
|
|
1303
|
+
const converted = extractTemplateValue(value);
|
|
1304
|
+
return JSON.stringify(converted, null, space);
|
|
1305
|
+
}
|