@rikalabs/akter 0.1.0-alpha.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 +15 -0
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +116 -0
- package/dist/actor/codecs.d.ts +77 -0
- package/dist/actor/codecs.js +87 -0
- package/dist/actor/connections.d.ts +34 -0
- package/dist/actor/connections.js +145 -0
- package/dist/actor/definition.d.ts +893 -0
- package/dist/actor/definition.js +147 -0
- package/dist/actor/descriptor.d.ts +172 -0
- package/dist/actor/descriptor.js +367 -0
- package/dist/actor/handles.d.ts +77 -0
- package/dist/actor/handles.js +265 -0
- package/dist/actor/jobs.d.ts +10 -0
- package/dist/actor/jobs.js +137 -0
- package/dist/actor/layers.d.ts +41 -0
- package/dist/actor/layers.js +177 -0
- package/dist/actor/reads.d.ts +47 -0
- package/dist/actor/reads.js +224 -0
- package/dist/actor/served.d.ts +120 -0
- package/dist/actor/served.js +72 -0
- package/dist/actor/turns.d.ts +13 -0
- package/dist/actor/turns.js +332 -0
- package/dist/actor/workflows.d.ts +16 -0
- package/dist/actor/workflows.js +37 -0
- package/dist/client/calls.d.ts +47 -0
- package/dist/client/calls.js +425 -0
- package/dist/client/clock.d.ts +56 -0
- package/dist/client/clock.js +119 -0
- package/dist/client/fleet-page.d.ts +15 -0
- package/dist/client/fleet-page.js +13 -0
- package/dist/client/fleet.d.ts +29 -0
- package/dist/client/fleet.js +51 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.js +6 -0
- package/dist/client/make.d.ts +157 -0
- package/dist/client/make.js +221 -0
- package/dist/client/offline/queue.d.ts +118 -0
- package/dist/client/offline/queue.js +292 -0
- package/dist/client/offline/store.d.ts +74 -0
- package/dist/client/offline/store.js +78 -0
- package/dist/client/optimistic.d.ts +57 -0
- package/dist/client/optimistic.js +136 -0
- package/dist/client/report.d.ts +2 -0
- package/dist/client/report.js +8 -0
- package/dist/client/sessions/connection.d.ts +118 -0
- package/dist/client/sessions/connection.js +162 -0
- package/dist/client/sessions/feed.d.ts +42 -0
- package/dist/client/sessions/feed.js +43 -0
- package/dist/client/sessions/sse.d.ts +47 -0
- package/dist/client/sessions/sse.js +112 -0
- package/dist/client/sessions/stream.d.ts +28 -0
- package/dist/client/sessions/stream.js +35 -0
- package/dist/client/sessions/watch.d.ts +34 -0
- package/dist/client/sessions/watch.js +40 -0
- package/dist/client/transport.d.ts +37 -0
- package/dist/client/transport.js +66 -0
- package/dist/contexts/command.d.ts +132 -0
- package/dist/contexts/command.js +20 -0
- package/dist/contexts/connection.d.ts +68 -0
- package/dist/contexts/connection.js +0 -0
- package/dist/contexts/job.d.ts +49 -0
- package/dist/contexts/job.js +0 -0
- package/dist/contexts/workflow.d.ts +147 -0
- package/dist/contexts/workflow.js +22 -0
- package/dist/errors/actor.d.ts +200 -0
- package/dist/errors/actor.js +271 -0
- package/dist/errors/content.d.ts +19 -0
- package/dist/errors/content.js +14 -0
- package/dist/errors/database.d.ts +22 -0
- package/dist/errors/database.js +23 -0
- package/dist/errors/events.d.ts +17 -0
- package/dist/errors/events.js +14 -0
- package/dist/errors/subscription.d.ts +12 -0
- package/dist/errors/subscription.js +8 -0
- package/dist/errors/workflow.d.ts +28 -0
- package/dist/errors/workflow.js +17 -0
- package/dist/handles/actors.d.ts +17 -0
- package/dist/handles/actors.js +7 -0
- package/dist/handles/content.d.ts +59 -0
- package/dist/handles/content.js +36 -0
- package/dist/handles/intents.d.ts +164 -0
- package/dist/handles/intents.js +214 -0
- package/dist/handles/run.d.ts +31 -0
- package/dist/handles/run.js +21 -0
- package/dist/handles/workflow.d.ts +27 -0
- package/dist/handles/workflow.js +23 -0
- package/dist/identity/caller.d.ts +105 -0
- package/dist/identity/caller.js +68 -0
- package/dist/identity/child.d.ts +18 -0
- package/dist/identity/child.js +39 -0
- package/dist/identity/command.d.ts +19 -0
- package/dist/identity/command.js +21 -0
- package/dist/identity/connection.d.ts +24 -0
- package/dist/identity/connection.js +29 -0
- package/dist/identity/content.d.ts +18 -0
- package/dist/identity/content.js +12 -0
- package/dist/identity/digest.d.ts +4 -0
- package/dist/identity/digest.js +5 -0
- package/dist/identity/execution.d.ts +32 -0
- package/dist/identity/execution.js +63 -0
- package/dist/identity/mint.d.ts +51 -0
- package/dist/identity/mint.js +76 -0
- package/dist/identity/version.d.ts +2 -0
- package/dist/identity/version.js +3 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +97 -0
- package/dist/members/blob.d.ts +43 -0
- package/dist/members/blob.js +29 -0
- package/dist/members/command.d.ts +109 -0
- package/dist/members/command.js +61 -0
- package/dist/members/connection.d.ts +55 -0
- package/dist/members/connection.js +49 -0
- package/dist/members/event.d.ts +36 -0
- package/dist/members/event.js +24 -0
- package/dist/members/job.d.ts +157 -0
- package/dist/members/job.js +67 -0
- package/dist/members/payload.d.ts +93 -0
- package/dist/members/payload.js +145 -0
- package/dist/members/reducer.d.ts +64 -0
- package/dist/members/reducer.js +27 -0
- package/dist/members/stream.d.ts +36 -0
- package/dist/members/stream.js +14 -0
- package/dist/members/subscription.d.ts +182 -0
- package/dist/members/subscription.js +91 -0
- package/dist/members/workflow.d.ts +99 -0
- package/dist/members/workflow.js +2 -0
- package/dist/policies/access.d.ts +35 -0
- package/dist/policies/access.js +6 -0
- package/dist/policies/command.d.ts +127 -0
- package/dist/policies/command.js +45 -0
- package/dist/policies/job.d.ts +28 -0
- package/dist/policies/job.js +60 -0
- package/dist/policies/schedules.d.ts +33 -0
- package/dist/policies/schedules.js +131 -0
- package/dist/protocol/frames.d.ts +66 -0
- package/dist/protocol/frames.js +55 -0
- package/dist/protocol/inspection.d.ts +807 -0
- package/dist/protocol/inspection.js +243 -0
- package/dist/protocol/wire.d.ts +184 -0
- package/dist/protocol/wire.js +150 -0
- package/dist/runtime/actors.d.ts +155 -0
- package/dist/runtime/actors.js +4 -0
- package/dist/runtime/admission.d.ts +34 -0
- package/dist/runtime/admission.js +72 -0
- package/dist/runtime/adoption/backfill.d.ts +27 -0
- package/dist/runtime/adoption/backfill.js +144 -0
- package/dist/runtime/adoption/enforce.d.ts +55 -0
- package/dist/runtime/adoption/enforce.js +241 -0
- package/dist/runtime/adoption/observe.d.ts +43 -0
- package/dist/runtime/adoption/observe.js +139 -0
- package/dist/runtime/adoption/plan.d.ts +45 -0
- package/dist/runtime/adoption/plan.js +192 -0
- package/dist/runtime/adoption/startup.d.ts +32 -0
- package/dist/runtime/adoption/startup.js +76 -0
- package/dist/runtime/adoption/status.d.ts +23 -0
- package/dist/runtime/adoption/status.js +47 -0
- package/dist/runtime/adoption/target.d.ts +33 -0
- package/dist/runtime/adoption/target.js +49 -0
- package/dist/runtime/connections/holder.d.ts +221 -0
- package/dist/runtime/connections/holder.js +816 -0
- package/dist/runtime/connections/owner.d.ts +263 -0
- package/dist/runtime/connections/owner.js +896 -0
- package/dist/runtime/connections/protocol.d.ts +441 -0
- package/dist/runtime/connections/protocol.js +222 -0
- package/dist/runtime/connections/reads.d.ts +24 -0
- package/dist/runtime/connections/reads.js +19 -0
- package/dist/runtime/connections/streams.d.ts +62 -0
- package/dist/runtime/connections/streams.js +128 -0
- package/dist/runtime/connections/transport.d.ts +40 -0
- package/dist/runtime/connections/transport.js +68 -0
- package/dist/runtime/connections/watch.d.ts +52 -0
- package/dist/runtime/connections/watch.js +159 -0
- package/dist/runtime/content/grant.d.ts +34 -0
- package/dist/runtime/content/grant.js +58 -0
- package/dist/runtime/content/store.d.ts +63 -0
- package/dist/runtime/content/store.js +294 -0
- package/dist/runtime/cron/key.d.ts +2 -0
- package/dist/runtime/cron/key.js +2 -0
- package/dist/runtime/cron/schedule.d.ts +69 -0
- package/dist/runtime/cron/schedule.js +144 -0
- package/dist/runtime/database/bounded.d.ts +43 -0
- package/dist/runtime/database/bounded.js +108 -0
- package/dist/runtime/database/connection.d.ts +8 -0
- package/dist/runtime/database/connection.js +18 -0
- package/dist/runtime/database/coordination.d.ts +19 -0
- package/dist/runtime/database/coordination.js +72 -0
- package/dist/runtime/database/flock.d.ts +10 -0
- package/dist/runtime/database/flock.js +60 -0
- package/dist/runtime/database/gate.d.ts +26 -0
- package/dist/runtime/database/gate.js +54 -0
- package/dist/runtime/database/keepalive.d.ts +11 -0
- package/dist/runtime/database/keepalive.js +22 -0
- package/dist/runtime/database/migrations.d.ts +177 -0
- package/dist/runtime/database/migrations.js +1018 -0
- package/dist/runtime/database/neki/migrations.d.ts +31 -0
- package/dist/runtime/database/neki/migrations.js +276 -0
- package/dist/runtime/database/neki/session.d.ts +23 -0
- package/dist/runtime/database/neki/session.js +31 -0
- package/dist/runtime/database/pglite.d.ts +21 -0
- package/dist/runtime/database/pglite.js +74 -0
- package/dist/runtime/database/replica.d.ts +41 -0
- package/dist/runtime/database/replica.js +51 -0
- package/dist/runtime/database/shards.d.ts +21 -0
- package/dist/runtime/database/shards.js +37 -0
- package/dist/runtime/database/snapshot.d.ts +7 -0
- package/dist/runtime/database/snapshot.js +7 -0
- package/dist/runtime/database/tenancy.d.ts +69 -0
- package/dist/runtime/database/tenancy.js +145 -0
- package/dist/runtime/database/transient.d.ts +10 -0
- package/dist/runtime/database/transient.js +25 -0
- package/dist/runtime/drain.d.ts +132 -0
- package/dist/runtime/drain.js +109 -0
- package/dist/runtime/entity/mailbox.d.ts +86 -0
- package/dist/runtime/entity/mailbox.js +121 -0
- package/dist/runtime/entity/register.d.ts +424 -0
- package/dist/runtime/entity/register.js +669 -0
- package/dist/runtime/events/append.d.ts +192 -0
- package/dist/runtime/events/append.js +128 -0
- package/dist/runtime/events/cursor.d.ts +2 -0
- package/dist/runtime/events/cursor.js +5 -0
- package/dist/runtime/events/replay.d.ts +20 -0
- package/dist/runtime/events/replay.js +45 -0
- package/dist/runtime/feeds.d.ts +26 -0
- package/dist/runtime/feeds.js +100 -0
- package/dist/runtime/fleet/checks.d.ts +17 -0
- package/dist/runtime/fleet/checks.js +106 -0
- package/dist/runtime/fleet/maintainer.d.ts +38 -0
- package/dist/runtime/fleet/maintainer.js +383 -0
- package/dist/runtime/fleet/pgoutput.d.ts +41 -0
- package/dist/runtime/fleet/pgoutput.js +102 -0
- package/dist/runtime/fleet/setup.d.ts +36 -0
- package/dist/runtime/fleet/setup.js +58 -0
- package/dist/runtime/fleet/subscribe.d.ts +42 -0
- package/dist/runtime/fleet/subscribe.js +147 -0
- package/dist/runtime/index.d.ts +66 -0
- package/dist/runtime/index.js +37 -0
- package/dist/runtime/inspector/http.d.ts +19 -0
- package/dist/runtime/inspector/http.js +36 -0
- package/dist/runtime/inspector/layer.d.ts +46 -0
- package/dist/runtime/inspector/layer.js +180 -0
- package/dist/runtime/inspector/queries.d.ts +711 -0
- package/dist/runtime/inspector/queries.js +494 -0
- package/dist/runtime/jobs/attempt.d.ts +254 -0
- package/dist/runtime/jobs/attempt.js +413 -0
- package/dist/runtime/jobs/isolation.d.ts +20 -0
- package/dist/runtime/jobs/isolation.js +10 -0
- package/dist/runtime/jobs/progress.d.ts +95 -0
- package/dist/runtime/jobs/progress.js +144 -0
- package/dist/runtime/layer.d.ts +260 -0
- package/dist/runtime/layer.js +876 -0
- package/dist/runtime/members.d.ts +381 -0
- package/dist/runtime/members.js +8 -0
- package/dist/runtime/operators/audit.d.ts +64 -0
- package/dist/runtime/operators/audit.js +56 -0
- package/dist/runtime/operators/auth.d.ts +29 -0
- package/dist/runtime/operators/auth.js +42 -0
- package/dist/runtime/operators/export.d.ts +68 -0
- package/dist/runtime/operators/export.js +137 -0
- package/dist/runtime/operators/grants.d.ts +45 -0
- package/dist/runtime/operators/grants.js +40 -0
- package/dist/runtime/operators/repair.d.ts +206 -0
- package/dist/runtime/operators/repair.js +226 -0
- package/dist/runtime/operators/routes.d.ts +35 -0
- package/dist/runtime/operators/routes.js +190 -0
- package/dist/runtime/operators/seed.d.ts +123 -0
- package/dist/runtime/operators/seed.js +123 -0
- package/dist/runtime/payloads/versions.d.ts +65 -0
- package/dist/runtime/payloads/versions.js +240 -0
- package/dist/runtime/peering/authority.d.ts +42 -0
- package/dist/runtime/peering/authority.js +132 -0
- package/dist/runtime/peering/credentials.d.ts +21 -0
- package/dist/runtime/peering/credentials.js +13 -0
- package/dist/runtime/peering/transport.d.ts +51 -0
- package/dist/runtime/peering/transport.js +175 -0
- package/dist/runtime/queries.d.ts +18 -0
- package/dist/runtime/queries.js +169 -0
- package/dist/runtime/readiness.d.ts +36 -0
- package/dist/runtime/readiness.js +44 -0
- package/dist/runtime/registration.d.ts +58 -0
- package/dist/runtime/registration.js +186 -0
- package/dist/runtime/request.d.ts +158 -0
- package/dist/runtime/request.js +102 -0
- package/dist/runtime/retry.d.ts +8 -0
- package/dist/runtime/retry.js +11 -0
- package/dist/runtime/runner.d.ts +93 -0
- package/dist/runtime/runner.js +122 -0
- package/dist/runtime/storage/codec.d.ts +39 -0
- package/dist/runtime/storage/codec.js +41 -0
- package/dist/runtime/storage/generation.d.ts +69 -0
- package/dist/runtime/storage/generation.js +49 -0
- package/dist/runtime/storage/placements.d.ts +15 -0
- package/dist/runtime/storage/placements.js +38 -0
- package/dist/runtime/storage/platform.d.ts +6 -0
- package/dist/runtime/storage/platform.js +9 -0
- package/dist/runtime/storage/retention.d.ts +73 -0
- package/dist/runtime/storage/retention.js +158 -0
- package/dist/runtime/subscriptions/identity.d.ts +31 -0
- package/dist/runtime/subscriptions/identity.js +45 -0
- package/dist/runtime/subscriptions/relay.d.ts +175 -0
- package/dist/runtime/subscriptions/relay.js +763 -0
- package/dist/runtime/subscriptions/storage.d.ts +40 -0
- package/dist/runtime/subscriptions/storage.js +98 -0
- package/dist/runtime/sweeps.d.ts +39 -0
- package/dist/runtime/sweeps.js +54 -0
- package/dist/runtime/telemetry/defects.d.ts +57 -0
- package/dist/runtime/telemetry/defects.js +43 -0
- package/dist/runtime/telemetry/metrics.d.ts +52 -0
- package/dist/runtime/telemetry/metrics.js +138 -0
- package/dist/runtime/telemetry/routes.d.ts +19 -0
- package/dist/runtime/telemetry/routes.js +18 -0
- package/dist/runtime/telemetry/sampler.d.ts +26 -0
- package/dist/runtime/telemetry/sampler.js +101 -0
- package/dist/runtime/telemetry/spans.d.ts +38 -0
- package/dist/runtime/telemetry/spans.js +44 -0
- package/dist/runtime/telemetry/usage.d.ts +52 -0
- package/dist/runtime/telemetry/usage.js +30 -0
- package/dist/runtime/topology/admission.d.ts +13 -0
- package/dist/runtime/topology/admission.js +36 -0
- package/dist/runtime/topology/locks.d.ts +56 -0
- package/dist/runtime/topology/locks.js +81 -0
- package/dist/runtime/topology/messages.d.ts +15 -0
- package/dist/runtime/topology/messages.js +32 -0
- package/dist/runtime/turn/admission.d.ts +22 -0
- package/dist/runtime/turn/admission.js +41 -0
- package/dist/runtime/turn/blobs.d.ts +38 -0
- package/dist/runtime/turn/blobs.js +215 -0
- package/dist/runtime/turn/execute.d.ts +208 -0
- package/dist/runtime/turn/execute.js +972 -0
- package/dist/runtime/turn/group.d.ts +165 -0
- package/dist/runtime/turn/group.js +326 -0
- package/dist/runtime/turn/hooks.d.ts +44 -0
- package/dist/runtime/turn/hooks.js +28 -0
- package/dist/runtime/turn/outbox.d.ts +159 -0
- package/dist/runtime/turn/outbox.js +269 -0
- package/dist/runtime/turn/pipeline.d.ts +68 -0
- package/dist/runtime/turn/pipeline.js +83 -0
- package/dist/runtime/turn/receipt.d.ts +81 -0
- package/dist/runtime/turn/receipt.js +32 -0
- package/dist/runtime/turn/relay.d.ts +179 -0
- package/dist/runtime/turn/relay.js +685 -0
- package/dist/runtime/turn/rows.d.ts +43 -0
- package/dist/runtime/turn/rows.js +592 -0
- package/dist/runtime/workflows/compatibility.d.ts +125 -0
- package/dist/runtime/workflows/compatibility.js +285 -0
- package/dist/runtime/workflows/engine.d.ts +107 -0
- package/dist/runtime/workflows/engine.js +826 -0
- package/dist/runtime/workflows/manifest.d.ts +34 -0
- package/dist/runtime/workflows/manifest.js +39 -0
- package/dist/runtime/workflows/steps.d.ts +33 -0
- package/dist/runtime/workflows/steps.js +152 -0
- package/dist/serve/api.d.ts +99 -0
- package/dist/serve/api.js +403 -0
- package/dist/serve/assertion/binding.d.ts +41 -0
- package/dist/serve/assertion/binding.js +92 -0
- package/dist/serve/assertion/verify.d.ts +93 -0
- package/dist/serve/assertion/verify.js +189 -0
- package/dist/serve/auth.d.ts +200 -0
- package/dist/serve/auth.js +92 -0
- package/dist/serve/clock.d.ts +10 -0
- package/dist/serve/clock.js +25 -0
- package/dist/serve/jwt.d.ts +65 -0
- package/dist/serve/jwt.js +202 -0
- package/dist/serve/layer.d.ts +98 -0
- package/dist/serve/layer.js +809 -0
- package/dist/serve/mcp/endpoint.d.ts +39 -0
- package/dist/serve/mcp/endpoint.js +187 -0
- package/dist/serve/mcp/tools.d.ts +37 -0
- package/dist/serve/mcp/tools.js +125 -0
- package/dist/serve/origin.d.ts +6 -0
- package/dist/serve/origin.js +21 -0
- package/dist/serve/sessions/feed.d.ts +79 -0
- package/dist/serve/sessions/feed.js +115 -0
- package/dist/serve/sessions/socket.d.ts +56 -0
- package/dist/serve/sessions/socket.js +212 -0
- package/dist/serve/sessions/sse.d.ts +27 -0
- package/dist/serve/sessions/sse.js +26 -0
- package/dist/serve/sessions/stream.d.ts +9 -0
- package/dist/serve/sessions/stream.js +9 -0
- package/dist/serve/sessions/watch.d.ts +12 -0
- package/dist/serve/sessions/watch.js +11 -0
- package/dist/serve/wire.d.ts +16 -0
- package/dist/serve/wire.js +50 -0
- package/dist/state/blob.d.ts +71 -0
- package/dist/state/blob.js +0 -0
- package/dist/state/migration.d.ts +53 -0
- package/dist/state/migration.js +29 -0
- package/dist/tables/fleet.d.ts +170 -0
- package/dist/tables/fleet.js +214 -0
- package/dist/tables/owned.d.ts +250 -0
- package/dist/tables/owned.js +233 -0
- package/dist/testing/actor-test.d.ts +360 -0
- package/dist/testing/actor-test.js +337 -0
- package/dist/testing/cluster.d.ts +93 -0
- package/dist/testing/cluster.js +296 -0
- package/dist/testing/conformance/access.d.ts +5 -0
- package/dist/testing/conformance/access.js +531 -0
- package/dist/testing/conformance/admission.d.ts +11 -0
- package/dist/testing/conformance/admission.js +182 -0
- package/dist/testing/conformance/adoption.d.ts +2 -0
- package/dist/testing/conformance/adoption.js +1019 -0
- package/dist/testing/conformance/assertions.d.ts +202 -0
- package/dist/testing/conformance/assertions.js +849 -0
- package/dist/testing/conformance/batches.d.ts +41 -0
- package/dist/testing/conformance/batches.js +388 -0
- package/dist/testing/conformance/blobs.d.ts +14 -0
- package/dist/testing/conformance/blobs.js +405 -0
- package/dist/testing/conformance/capacity.d.ts +8 -0
- package/dist/testing/conformance/capacity.js +433 -0
- package/dist/testing/conformance/client.d.ts +5 -0
- package/dist/testing/conformance/client.js +719 -0
- package/dist/testing/conformance/cold-serve.d.ts +16 -0
- package/dist/testing/conformance/cold-serve.js +254 -0
- package/dist/testing/conformance/connections/actors.d.ts +1143 -0
- package/dist/testing/conformance/connections/actors.js +180 -0
- package/dist/testing/conformance/connections/harness.d.ts +1754 -0
- package/dist/testing/conformance/connections/harness.js +142 -0
- package/dist/testing/conformance/connections/holders.d.ts +4 -0
- package/dist/testing/conformance/connections/holders.js +165 -0
- package/dist/testing/conformance/connections/lifecycle.d.ts +4 -0
- package/dist/testing/conformance/connections/lifecycle.js +113 -0
- package/dist/testing/conformance/connections/limits.d.ts +4 -0
- package/dist/testing/conformance/connections/limits.js +127 -0
- package/dist/testing/conformance/connections/reauthorization.d.ts +4 -0
- package/dist/testing/conformance/connections/reauthorization.js +170 -0
- package/dist/testing/conformance/connections/resync.d.ts +4 -0
- package/dist/testing/conformance/connections/resync.js +360 -0
- package/dist/testing/conformance/connections/takeover.d.ts +4 -0
- package/dist/testing/conformance/connections/takeover.js +287 -0
- package/dist/testing/conformance/connections.d.ts +4 -0
- package/dist/testing/conformance/connections.js +15 -0
- package/dist/testing/conformance/content-blobs.d.ts +16 -0
- package/dist/testing/conformance/content-blobs.js +534 -0
- package/dist/testing/conformance/counter.d.ts +16 -0
- package/dist/testing/conformance/counter.js +813 -0
- package/dist/testing/conformance/cron.d.ts +5 -0
- package/dist/testing/conformance/cron.js +665 -0
- package/dist/testing/conformance/drain.d.ts +26 -0
- package/dist/testing/conformance/drain.js +540 -0
- package/dist/testing/conformance/effect-control.d.ts +38 -0
- package/dist/testing/conformance/effect-control.js +1059 -0
- package/dist/testing/conformance/effects.d.ts +23 -0
- package/dist/testing/conformance/effects.js +432 -0
- package/dist/testing/conformance/events.d.ts +28 -0
- package/dist/testing/conformance/events.js +335 -0
- package/dist/testing/conformance/export.d.ts +2 -0
- package/dist/testing/conformance/export.js +368 -0
- package/dist/testing/conformance/fleet.d.ts +444 -0
- package/dist/testing/conformance/fleet.js +1009 -0
- package/dist/testing/conformance/groups.d.ts +7 -0
- package/dist/testing/conformance/groups.js +353 -0
- package/dist/testing/conformance/heap.d.ts +3 -0
- package/dist/testing/conformance/heap.js +149 -0
- package/dist/testing/conformance/http.d.ts +2809 -0
- package/dist/testing/conformance/http.js +1234 -0
- package/dist/testing/conformance/inspection-views.d.ts +8 -0
- package/dist/testing/conformance/inspection-views.js +272 -0
- package/dist/testing/conformance/inspector.d.ts +7 -0
- package/dist/testing/conformance/inspector.js +650 -0
- package/dist/testing/conformance/mint.d.ts +58 -0
- package/dist/testing/conformance/mint.js +692 -0
- package/dist/testing/conformance/multi-runner.d.ts +8 -0
- package/dist/testing/conformance/multi-runner.js +403 -0
- package/dist/testing/conformance/neki/plan.d.ts +19 -0
- package/dist/testing/conformance/neki/plan.js +30 -0
- package/dist/testing/conformance/observability.d.ts +3 -0
- package/dist/testing/conformance/observability.js +343 -0
- package/dist/testing/conformance/offline.d.ts +4 -0
- package/dist/testing/conformance/offline.js +474 -0
- package/dist/testing/conformance/operator-harness.d.ts +57 -0
- package/dist/testing/conformance/operator-harness.js +78 -0
- package/dist/testing/conformance/operator.d.ts +3 -0
- package/dist/testing/conformance/operator.js +379 -0
- package/dist/testing/conformance/outbox-cross-shard.d.ts +14 -0
- package/dist/testing/conformance/outbox-cross-shard.js +160 -0
- package/dist/testing/conformance/outbox.d.ts +36 -0
- package/dist/testing/conformance/outbox.js +437 -0
- package/dist/testing/conformance/payload-migrations.d.ts +3 -0
- package/dist/testing/conformance/payload-migrations.js +612 -0
- package/dist/testing/conformance/pipeline.d.ts +3 -0
- package/dist/testing/conformance/pipeline.js +1040 -0
- package/dist/testing/conformance/placement.d.ts +22 -0
- package/dist/testing/conformance/placement.js +539 -0
- package/dist/testing/conformance/platform.d.ts +40 -0
- package/dist/testing/conformance/platform.js +101 -0
- package/dist/testing/conformance/progress.d.ts +39 -0
- package/dist/testing/conformance/progress.js +666 -0
- package/dist/testing/conformance/properties.d.ts +6 -0
- package/dist/testing/conformance/properties.js +295 -0
- package/dist/testing/conformance/protocols.d.ts +4 -0
- package/dist/testing/conformance/protocols.js +618 -0
- package/dist/testing/conformance/provider/advertise.d.ts +21 -0
- package/dist/testing/conformance/provider/advertise.js +44 -0
- package/dist/testing/conformance/read-your-writes.d.ts +20 -0
- package/dist/testing/conformance/read-your-writes.js +192 -0
- package/dist/testing/conformance/reducers.d.ts +8 -0
- package/dist/testing/conformance/reducers.js +258 -0
- package/dist/testing/conformance/relay.d.ts +42 -0
- package/dist/testing/conformance/relay.js +1115 -0
- package/dist/testing/conformance/restore.d.ts +43 -0
- package/dist/testing/conformance/restore.js +341 -0
- package/dist/testing/conformance/retention.d.ts +14 -0
- package/dist/testing/conformance/retention.js +463 -0
- package/dist/testing/conformance/rls.d.ts +24 -0
- package/dist/testing/conformance/rls.js +576 -0
- package/dist/testing/conformance/simulation.d.ts +31 -0
- package/dist/testing/conformance/simulation.js +167 -0
- package/dist/testing/conformance/single-shard.d.ts +2 -0
- package/dist/testing/conformance/single-shard.js +125 -0
- package/dist/testing/conformance/singleton.d.ts +3 -0
- package/dist/testing/conformance/singleton.js +293 -0
- package/dist/testing/conformance/statements.d.ts +60 -0
- package/dist/testing/conformance/statements.js +108 -0
- package/dist/testing/conformance/streams.d.ts +7 -0
- package/dist/testing/conformance/streams.js +280 -0
- package/dist/testing/conformance/subscriptions/access.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/access.js +98 -0
- package/dist/testing/conformance/subscriptions/actors.d.ts +4910 -0
- package/dist/testing/conformance/subscriptions/actors.js +372 -0
- package/dist/testing/conformance/subscriptions/cluster.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/cluster.js +89 -0
- package/dist/testing/conformance/subscriptions/delivery.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/delivery.js +253 -0
- package/dist/testing/conformance/subscriptions/deploys.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/deploys.js +162 -0
- package/dist/testing/conformance/subscriptions/epochs.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/epochs.js +169 -0
- package/dist/testing/conformance/subscriptions/failures.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/failures.js +108 -0
- package/dist/testing/conformance/subscriptions/feeds.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/feeds.js +218 -0
- package/dist/testing/conformance/subscriptions/harness.d.ts +124 -0
- package/dist/testing/conformance/subscriptions/harness.js +143 -0
- package/dist/testing/conformance/subscriptions/operator.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/operator.js +128 -0
- package/dist/testing/conformance/subscriptions/retention.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/retention.js +288 -0
- package/dist/testing/conformance/subscriptions/routing.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/routing.js +179 -0
- package/dist/testing/conformance/subscriptions.d.ts +4 -0
- package/dist/testing/conformance/subscriptions.js +19 -0
- package/dist/testing/conformance/tables.d.ts +125 -0
- package/dist/testing/conformance/tables.js +664 -0
- package/dist/testing/conformance/transports/actors.d.ts +1907 -0
- package/dist/testing/conformance/transports/actors.js +163 -0
- package/dist/testing/conformance/transports/client.d.ts +3 -0
- package/dist/testing/conformance/transports/client.js +237 -0
- package/dist/testing/conformance/transports/feeds.d.ts +3 -0
- package/dist/testing/conformance/transports/feeds.js +232 -0
- package/dist/testing/conformance/transports/harness.d.ts +93 -0
- package/dist/testing/conformance/transports/harness.js +84 -0
- package/dist/testing/conformance/transports/streams.d.ts +3 -0
- package/dist/testing/conformance/transports/streams.js +96 -0
- package/dist/testing/conformance/transports/websocket.d.ts +3 -0
- package/dist/testing/conformance/transports/websocket.js +384 -0
- package/dist/testing/conformance/transports/wire.d.ts +141 -0
- package/dist/testing/conformance/transports/wire.js +204 -0
- package/dist/testing/conformance/transports.d.ts +3 -0
- package/dist/testing/conformance/transports.js +11 -0
- package/dist/testing/conformance/watch.d.ts +59 -0
- package/dist/testing/conformance/watch.js +879 -0
- package/dist/testing/conformance/workflow-engine.d.ts +97 -0
- package/dist/testing/conformance/workflow-engine.js +253 -0
- package/dist/testing/conformance/workflow-versions.d.ts +3 -0
- package/dist/testing/conformance/workflow-versions.js +545 -0
- package/dist/testing/conformance/workflows/access.d.ts +4 -0
- package/dist/testing/conformance/workflows/access.js +147 -0
- package/dist/testing/conformance/workflows/actors.d.ts +2317 -0
- package/dist/testing/conformance/workflows/actors.js +305 -0
- package/dist/testing/conformance/workflows/basics.d.ts +4 -0
- package/dist/testing/conformance/workflows/basics.js +144 -0
- package/dist/testing/conformance/workflows/engine.d.ts +4 -0
- package/dist/testing/conformance/workflows/engine.js +80 -0
- package/dist/testing/conformance/workflows/guards.d.ts +4 -0
- package/dist/testing/conformance/workflows/guards.js +172 -0
- package/dist/testing/conformance/workflows/harness.d.ts +14 -0
- package/dist/testing/conformance/workflows/harness.js +44 -0
- package/dist/testing/conformance/workflows/recovery.d.ts +4 -0
- package/dist/testing/conformance/workflows/recovery.js +181 -0
- package/dist/testing/conformance/workflows/starts.d.ts +4 -0
- package/dist/testing/conformance/workflows/starts.js +57 -0
- package/dist/testing/conformance/workflows/suspension.d.ts +4 -0
- package/dist/testing/conformance/workflows/suspension.js +106 -0
- package/dist/testing/conformance/workflows/waits.d.ts +4 -0
- package/dist/testing/conformance/workflows/waits.js +284 -0
- package/dist/testing/conformance/workflows.d.ts +4 -0
- package/dist/testing/conformance/workflows.js +19 -0
- package/dist/testing/conformance.d.ts +330 -0
- package/dist/testing/conformance.js +364 -0
- package/dist/testing/database.d.ts +31 -0
- package/dist/testing/database.js +70 -0
- package/dist/testing/foundation.d.ts +41 -0
- package/dist/testing/foundation.js +517 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/property.d.ts +40 -0
- package/dist/testing/property.js +95 -0
- package/dist/testing/simulate-cluster.d.ts +112 -0
- package/dist/testing/simulate-cluster.js +257 -0
- package/dist/testing/simulate.d.ts +90 -0
- package/dist/testing/simulate.js +127 -0
- package/package.json +1 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Data, Effect } from "effect";
|
|
2
|
+
import type { ServedConnection } from "../../actor/served.ts";
|
|
3
|
+
import type { ValueSchema } from "../../members/command.ts";
|
|
4
|
+
import type { AnyConnection } from "../../members/connection.ts";
|
|
5
|
+
import type { ProgressJob } from "../../members/job.ts";
|
|
6
|
+
/**
|
|
7
|
+
* One job's progress as its client receives it: the job's tag and a frame
|
|
8
|
+
* decoded by that job's `progress` schema. Unions over the jobs a connection
|
|
9
|
+
* member lists, so narrowing on `job` types `frame`.
|
|
10
|
+
*/
|
|
11
|
+
export type ProgressUpdate<J extends ProgressJob = ProgressJob> = J extends ProgressJob ? {
|
|
12
|
+
readonly job: J["tag"];
|
|
13
|
+
readonly frame: J["progress"]["Type"];
|
|
14
|
+
} : never;
|
|
15
|
+
/** The progress a connection member's client receives: one update per job the member lists. */
|
|
16
|
+
export type ProgressOfConnection<M extends AnyConnection> = ProgressUpdate<NonNullable<M["progress"]>["jobs"][number]>;
|
|
17
|
+
type Messages<Frame> = Data.TaggedEnum<{
|
|
18
|
+
Frame: {
|
|
19
|
+
readonly frame: Frame;
|
|
20
|
+
/** The flushed-through event cursor the frame was sent above; absent under `stampCursor: false`. */
|
|
21
|
+
readonly cursor: string | undefined;
|
|
22
|
+
/** The cursor of the event the frame was sent from, to deduplicate on after a resync. */
|
|
23
|
+
readonly event: string | undefined;
|
|
24
|
+
};
|
|
25
|
+
/** The actor's owner died; frames since `after` may be lost. Replay events after it, or reload state. */
|
|
26
|
+
Resync: {
|
|
27
|
+
readonly after: string | undefined;
|
|
28
|
+
readonly reason: "OwnerLost";
|
|
29
|
+
/** Milliseconds the client has to resynchronize before the connection closes. */
|
|
30
|
+
readonly deadline: number;
|
|
31
|
+
};
|
|
32
|
+
ResyncReplayed: {};
|
|
33
|
+
Progress: ProgressUpdate & {
|
|
34
|
+
readonly jobId: string;
|
|
35
|
+
readonly attempt: number;
|
|
36
|
+
readonly seq: number;
|
|
37
|
+
};
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* An executor's progress on a job the member lists: display-only, lossy, and
|
|
41
|
+
* never replayed after a resync. `frame` is decoded by that job's `progress`
|
|
42
|
+
* schema; `seq` counts the attempt's reports, so a gap is a dropped one.
|
|
43
|
+
*/
|
|
44
|
+
export type ProgressMessage<Progress extends ProgressUpdate = ProgressUpdate> = Extract<Messages<never>, {
|
|
45
|
+
readonly _tag: "Progress";
|
|
46
|
+
}> & Progress;
|
|
47
|
+
/**
|
|
48
|
+
* What a connection's client receives, in order: member frames, the holder's
|
|
49
|
+
* resync notices, and executor progress for a member that lists jobs.
|
|
50
|
+
* `Progress` is the member's `ProgressUpdate`, so its messages narrow by `job`.
|
|
51
|
+
*/
|
|
52
|
+
export type ConnectionMessage<Frame, Progress extends ProgressUpdate = ProgressUpdate> = Exclude<Messages<Frame>, {
|
|
53
|
+
readonly _tag: "Progress";
|
|
54
|
+
}> | ProgressMessage<Progress>;
|
|
55
|
+
/** Options of one `connect` call. */
|
|
56
|
+
export interface ConnectOptions {
|
|
57
|
+
/** Stops waiting for the connection to open. */
|
|
58
|
+
readonly signal?: AbortSignal;
|
|
59
|
+
/**
|
|
60
|
+
* Resynchronizes after an owner loss: replay events after `after`, or reload
|
|
61
|
+
* state. The connection acknowledges the resync once this settles; without
|
|
62
|
+
* it, the resync is acknowledged at once and only seen in `messages`. A
|
|
63
|
+
* callback that throws, at once or later, still settles the acknowledgment.
|
|
64
|
+
*/
|
|
65
|
+
readonly onResync?: (resync: {
|
|
66
|
+
readonly after: string | undefined;
|
|
67
|
+
}) => void | Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
/** An open connection: typed frames both ways. */
|
|
70
|
+
export interface ClientConnection<Server, Client, Progress extends ProgressUpdate = ProgressUpdate> {
|
|
71
|
+
/** The server's id for this connection. */
|
|
72
|
+
readonly connectionId: string;
|
|
73
|
+
/** The flushed-through event cursor when it opened: replay events after it to catch up. */
|
|
74
|
+
readonly cursor: string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Every message in order. The iteration ends when this client closes the
|
|
77
|
+
* connection and throws its `ActorError` otherwise: `SessionEnded`
|
|
78
|
+
* `ServerClosed` when the actor closed it, and `HolderLost` with
|
|
79
|
+
* `resync: true` for a dropped socket. Consume either this or `frames`, not both.
|
|
80
|
+
*/
|
|
81
|
+
readonly messages: AsyncIterable<ConnectionMessage<Server, Progress>>;
|
|
82
|
+
/** The member frames of `messages`, without the resync notices or progress. */
|
|
83
|
+
readonly frames: AsyncIterable<Server>;
|
|
84
|
+
/** Sends one frame; rejects with `SessionEnded` `HolderLost` once the session ended or its socket stopped being open. */
|
|
85
|
+
readonly send: (frame: Client) => Promise<void>;
|
|
86
|
+
/** Closes the connection. The `messages` iteration then ends without an error. */
|
|
87
|
+
readonly close: () => Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
interface SocketSource {
|
|
90
|
+
readonly member: ServedConnection;
|
|
91
|
+
readonly url: string;
|
|
92
|
+
/** The `authorization` credential to send in `hello` and `reauthenticate`, read afresh each time. */
|
|
93
|
+
readonly authorization: Effect.Effect<string | undefined>;
|
|
94
|
+
readonly params: ValueSchema["Type"];
|
|
95
|
+
readonly options: ConnectOptions;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Opens one connection over WebSocket: `hello` with the credential and
|
|
99
|
+
* params, then member frames both ways. It resolves once the server sent
|
|
100
|
+
* `open`, and rejects with the declared `open` failure or the `ActorError`
|
|
101
|
+
* that refused it.
|
|
102
|
+
*
|
|
103
|
+
* The credential is read before the socket opens, so a provider that throws
|
|
104
|
+
* or rejects fails `connect` with its own error; it is read again for each
|
|
105
|
+
* renewal, and a provider that fails then leaves the old credential to expire,
|
|
106
|
+
* which the server ends the session at. Incoming messages are handled one at
|
|
107
|
+
* a time, in arrival order, with the socket's close after them. A message
|
|
108
|
+
* with a `t` this client doesn't know is ignored, as the protocol says; one
|
|
109
|
+
* that is broken ends the session, as does a frame cursor that isn't a
|
|
110
|
+
* position. Nothing reads the socket once the session ends, so a failure this
|
|
111
|
+
* client detected closes it too. After a resync, a frame whose event the
|
|
112
|
+
* client already had is a duplicate and is dropped. Progress is lossy by
|
|
113
|
+
* design: one this client can't read is dropped and the session goes on. The
|
|
114
|
+
* holder ignores a resync acknowledgment before the member's own replay; a
|
|
115
|
+
* second one after it is harmless.
|
|
116
|
+
*/
|
|
117
|
+
export declare const connect: <Server, Client>({ member, url, authorization, params, options, }: SocketSource) => Promise<ClientConnection<Server, Client>>;
|
|
118
|
+
export {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Data, Deferred, Effect, Match, Option, Predicate, Queue, Schema, Stream } from "effect";
|
|
2
|
+
import { ActorError, SessionEnded } from "../../errors/actor.js";
|
|
3
|
+
import { ClientWireMessage, ServerWireMessage, SUBPROTOCOL } from "../../protocol/frames.js";
|
|
4
|
+
import { aborted, decodeFailure, undecodableFailure } from "../transport.js";
|
|
5
|
+
const ConnectionMessage = Data.taggedEnum();
|
|
6
|
+
const encodeClient = Schema.encodeEffect(Schema.fromJsonString(ClientWireMessage));
|
|
7
|
+
const decodeServer = Schema.decodeUnknownOption(Schema.fromJsonString(ServerWireMessage));
|
|
8
|
+
const decodeTagged = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Struct({ t: Schema.String })));
|
|
9
|
+
const KNOWN = new Set(ServerWireMessage.members.map((member) => member.fields.t.literal));
|
|
10
|
+
const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Json));
|
|
11
|
+
/** A frame's event cursor as a position, or `undefined` for text that isn't one. */
|
|
12
|
+
const eventPosition = (cursor) => Option.getOrUndefined(Schema.decodeOption(Schema.BigIntFromString)(cursor));
|
|
13
|
+
const ended = (cause, resync) => ActorError.make({ reason: SessionEnded.make({ cause, resync }) });
|
|
14
|
+
const holderLost = ended("HolderLost", true);
|
|
15
|
+
const isClientClosed = (failure) => Schema.is(ActorError)(failure) &&
|
|
16
|
+
Schema.is(SessionEnded)(failure.reason) &&
|
|
17
|
+
failure.reason.cause === "ClientClosed";
|
|
18
|
+
/** Ends the message stream without an error. */
|
|
19
|
+
const DONE = "done";
|
|
20
|
+
/**
|
|
21
|
+
* Opens one connection over WebSocket: `hello` with the credential and
|
|
22
|
+
* params, then member frames both ways. It resolves once the server sent
|
|
23
|
+
* `open`, and rejects with the declared `open` failure or the `ActorError`
|
|
24
|
+
* that refused it.
|
|
25
|
+
*
|
|
26
|
+
* The credential is read before the socket opens, so a provider that throws
|
|
27
|
+
* or rejects fails `connect` with its own error; it is read again for each
|
|
28
|
+
* renewal, and a provider that fails then leaves the old credential to expire,
|
|
29
|
+
* which the server ends the session at. Incoming messages are handled one at
|
|
30
|
+
* a time, in arrival order, with the socket's close after them. A message
|
|
31
|
+
* with a `t` this client doesn't know is ignored, as the protocol says; one
|
|
32
|
+
* that is broken ends the session, as does a frame cursor that isn't a
|
|
33
|
+
* position. Nothing reads the socket once the session ends, so a failure this
|
|
34
|
+
* client detected closes it too. After a resync, a frame whose event the
|
|
35
|
+
* client already had is a duplicate and is dropped. Progress is lossy by
|
|
36
|
+
* design: one this client can't read is dropped and the session goes on. The
|
|
37
|
+
* holder ignores a resync acknowledgment before the member's own replay; a
|
|
38
|
+
* second one after it is harmless.
|
|
39
|
+
*/
|
|
40
|
+
export const connect = ({ member, url, authorization, params, options, }) => Effect.runPromise(Effect.gen(function* () {
|
|
41
|
+
const services = yield* Effect.context();
|
|
42
|
+
const run = Effect.runForkWith(services);
|
|
43
|
+
const encodeParams = Schema.encodeUnknownEffect(Schema.toCodecJson(member.params));
|
|
44
|
+
const encodeFrame = Schema.encodeUnknownEffect(Schema.toCodecJson(member.client));
|
|
45
|
+
const decodeFrame = Schema.decodeUnknownEffect(Schema.toCodecJson(member.server));
|
|
46
|
+
const progressDecoders = new Map([...member.progress].map(([tag, schema]) => [
|
|
47
|
+
tag,
|
|
48
|
+
Schema.decodeUnknownEffect(Schema.toCodecJson(schema)),
|
|
49
|
+
]));
|
|
50
|
+
const declared = member.errors.length === 0
|
|
51
|
+
? () => Option.none()
|
|
52
|
+
: Schema.decodeUnknownOption(Schema.toCodecJson(Schema.Union(member.errors)));
|
|
53
|
+
const failureOf = (error) => error === undefined
|
|
54
|
+
? Effect.succeed(ended("ServerClosed", false))
|
|
55
|
+
: encodeJson(error).pipe(Effect.orDie, Effect.map((text) => decodeFailure(declared)({ status: 0, headers: new Headers(), text, sentAt: 0 })));
|
|
56
|
+
const hello = yield* encodeParams(params).pipe(Effect.mapError(undecodableFailure));
|
|
57
|
+
const messages = yield* Queue.unbounded();
|
|
58
|
+
const inbox = yield* Queue.unbounded();
|
|
59
|
+
const opened = yield* Deferred.make();
|
|
60
|
+
const credential = yield* authorization;
|
|
61
|
+
const ws = new WebSocket(url, SUBPROTOCOL);
|
|
62
|
+
let finished = false;
|
|
63
|
+
let highest = -1n;
|
|
64
|
+
let resync = undefined;
|
|
65
|
+
const write = (message) => encodeClient(message).pipe(Effect.orDie, Effect.map((text) => {
|
|
66
|
+
if (ws.readyState === WebSocket.OPEN)
|
|
67
|
+
ws.send(text);
|
|
68
|
+
}));
|
|
69
|
+
const finish = (failure) => Effect.gen(function* () {
|
|
70
|
+
if (finished)
|
|
71
|
+
return;
|
|
72
|
+
finished = true;
|
|
73
|
+
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)
|
|
74
|
+
ws.close(1000);
|
|
75
|
+
yield* Queue.fail(messages, isClientClosed(failure) ? DONE : failure);
|
|
76
|
+
yield* Deferred.fail(opened, failure);
|
|
77
|
+
});
|
|
78
|
+
const acknowledge = Effect.suspend(() => resync?.settled === true ? write({ t: "resyncDone" }) : Effect.void);
|
|
79
|
+
const frame = (message) => decodeFrame(message.frame).pipe(Effect.flatMap((decoded) => Effect.suspend(() => {
|
|
80
|
+
if (message.event !== undefined) {
|
|
81
|
+
const event = eventPosition(message.event);
|
|
82
|
+
if (event === undefined)
|
|
83
|
+
return finish(undecodableFailure());
|
|
84
|
+
if (event <= highest)
|
|
85
|
+
return Effect.void;
|
|
86
|
+
highest = event;
|
|
87
|
+
}
|
|
88
|
+
return Queue.offer(messages, ConnectionMessage.Frame({
|
|
89
|
+
frame: decoded,
|
|
90
|
+
cursor: message.cursor,
|
|
91
|
+
event: message.event,
|
|
92
|
+
}));
|
|
93
|
+
})), Effect.catch(() => finish(undecodableFailure())), Effect.asVoid);
|
|
94
|
+
const progress = (message) => Option.match(Option.fromNullishOr(progressDecoders.get(message.job)), {
|
|
95
|
+
onNone: () => Effect.void,
|
|
96
|
+
onSome: (decode) => decode(message.frame).pipe(Effect.flatMap((frame) => Queue.offer(messages, ConnectionMessage.Progress({
|
|
97
|
+
job: message.job,
|
|
98
|
+
jobId: message.jobId,
|
|
99
|
+
attempt: message.attempt,
|
|
100
|
+
seq: message.seq,
|
|
101
|
+
frame,
|
|
102
|
+
}))), Effect.catch(() => Effect.void), Effect.asVoid),
|
|
103
|
+
});
|
|
104
|
+
const resyncing = (message) => {
|
|
105
|
+
const state = { settled: false };
|
|
106
|
+
resync = state;
|
|
107
|
+
const settle = Effect.promise(() => Promise.resolve()
|
|
108
|
+
.then(() => options.onResync?.({ after: message.after }))
|
|
109
|
+
.catch(() => undefined)).pipe(Effect.andThen(Effect.sync(() => {
|
|
110
|
+
state.settled = true;
|
|
111
|
+
})), Effect.andThen(acknowledge));
|
|
112
|
+
return Queue.offer(messages, ConnectionMessage.Resync({
|
|
113
|
+
after: message.after,
|
|
114
|
+
reason: message.reason,
|
|
115
|
+
deadline: message.deadline,
|
|
116
|
+
})).pipe(Effect.andThen(Effect.sync(() => run(settle))), Effect.asVoid);
|
|
117
|
+
};
|
|
118
|
+
const handle = Match.type().pipe(Match.discriminatorsExhaustive("t")({
|
|
119
|
+
open: (message) => Deferred.succeed(opened, {
|
|
120
|
+
connectionId: message.connectionId,
|
|
121
|
+
baseline: message.baseline,
|
|
122
|
+
}).pipe(Effect.asVoid),
|
|
123
|
+
frame,
|
|
124
|
+
resync: resyncing,
|
|
125
|
+
resyncReplayed: () => Queue.offer(messages, ConnectionMessage.ResyncReplayed()).pipe(Effect.andThen(acknowledge)),
|
|
126
|
+
progress,
|
|
127
|
+
reauthenticate: () => authorization.pipe(Effect.flatMap((fresh) => fresh === undefined
|
|
128
|
+
? Effect.void
|
|
129
|
+
: write({ t: "reauthenticate", authorization: fresh })), Effect.ignoreCause),
|
|
130
|
+
reauthenticated: () => Effect.void,
|
|
131
|
+
end: (message) => failureOf(message.error).pipe(Effect.flatMap(finish)),
|
|
132
|
+
}));
|
|
133
|
+
ws.onopen = () => run(write(credential === undefined
|
|
134
|
+
? { t: "hello", params: hello }
|
|
135
|
+
: { t: "hello", authorization: credential, params: hello }));
|
|
136
|
+
ws.onmessage = (event) => Queue.offerUnsafe(inbox, String(event.data));
|
|
137
|
+
ws.onclose = () => Queue.offerUnsafe(inbox, DONE);
|
|
138
|
+
run(Queue.take(inbox).pipe(Effect.flatMap((text) => text === DONE
|
|
139
|
+
? finish(holderLost)
|
|
140
|
+
: Option.match(decodeTagged(text), {
|
|
141
|
+
onNone: () => finish(undecodableFailure()),
|
|
142
|
+
onSome: ({ t }) => KNOWN.has(t)
|
|
143
|
+
? Option.match(decodeServer(text), {
|
|
144
|
+
onNone: () => finish(undecodableFailure()),
|
|
145
|
+
onSome: handle,
|
|
146
|
+
})
|
|
147
|
+
: Effect.void,
|
|
148
|
+
})), Effect.forever));
|
|
149
|
+
const open = yield* Effect.raceFirst(Deferred.await(opened), aborted(options.signal).pipe(Effect.andThen(Effect.sync(() => ws.close(1000))), Effect.andThen(Effect.fail(ended("ClientClosed", false)))));
|
|
150
|
+
const stream = Stream.fromQueue(messages).pipe(Stream.catch((failure) => (failure === DONE ? Stream.empty : Stream.fail(failure))));
|
|
151
|
+
const connection = {
|
|
152
|
+
connectionId: open.connectionId,
|
|
153
|
+
cursor: open.baseline,
|
|
154
|
+
messages: Stream.toAsyncIterable(stream),
|
|
155
|
+
frames: Stream.toAsyncIterable(stream.pipe(Stream.filter((message) => Predicate.isTagged(message, "Frame")), Stream.map((message) => message.frame))),
|
|
156
|
+
send: (value) => Effect.runPromiseWith(services)(encodeFrame(value).pipe(Effect.mapError(undecodableFailure), Effect.flatMap((json) => finished || ws.readyState !== WebSocket.OPEN
|
|
157
|
+
? Effect.fail(holderLost)
|
|
158
|
+
: write({ t: "frame", frame: json })))),
|
|
159
|
+
close: () => Effect.runPromiseWith(services)(Effect.sync(() => ws.close(1000)).pipe(Effect.andThen(finish(ended("ClientClosed", false))))),
|
|
160
|
+
};
|
|
161
|
+
return connection;
|
|
162
|
+
}));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import type { ActorError } from "../../errors/actor.ts";
|
|
3
|
+
import type { EventClass } from "../../members/event.ts";
|
|
4
|
+
import { type Failure } from "../transport.ts";
|
|
5
|
+
/** One committed event a feed delivered, with the cursor to resume after it. */
|
|
6
|
+
export interface FeedEntry<E> {
|
|
7
|
+
/** Exclusive resume point: pass it as `after` to read the events that follow. */
|
|
8
|
+
readonly cursor: string;
|
|
9
|
+
/** The decoded event. */
|
|
10
|
+
readonly event: E;
|
|
11
|
+
/** The id of the command that committed the event. */
|
|
12
|
+
readonly commandId: string;
|
|
13
|
+
/** When the event committed, in milliseconds since the epoch. */
|
|
14
|
+
readonly timestamp: number;
|
|
15
|
+
}
|
|
16
|
+
/** Options of one event feed iteration. */
|
|
17
|
+
export interface FeedOptions {
|
|
18
|
+
/** Resume after this cursor; omitted, the feed starts at the actor's first retained event. */
|
|
19
|
+
readonly after?: string;
|
|
20
|
+
/** Ends the iteration; the feed stops at once. */
|
|
21
|
+
readonly signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
interface FeedSource<E extends EventClass> {
|
|
24
|
+
/** Fetches the feed after `cursor`, sent as `Last-Event-ID`, with fresh headers each time. */
|
|
25
|
+
readonly open: (cursor: string | undefined, signal: AbortSignal) => Effect.Effect<Response, ActorError>;
|
|
26
|
+
/** The event class the feed delivers; its identifier is the tag asked for. */
|
|
27
|
+
readonly event: E;
|
|
28
|
+
readonly options: FeedOptions;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The committed `event`s of one actor after `after`, as they commit: read
|
|
32
|
+
* from the server's event feed and reopened from the last cursor delivered
|
|
33
|
+
* whenever the connection drops, the server restarts, or the credential
|
|
34
|
+
* expires and is refreshed. It fails with `RetentionGap` if events after the
|
|
35
|
+
* cursor were pruned, and with `UnknownCursor` for a cursor the actor never
|
|
36
|
+
* issued. A dropped or refused feed reopens after the server's `retryAfter`,
|
|
37
|
+
* never sooner, or after a jittered, growing delay. Every event carries its
|
|
38
|
+
* cursor as `id`; the feed's own `end` carries none, so an event named `end` is
|
|
39
|
+
* still an event.
|
|
40
|
+
*/
|
|
41
|
+
export declare const feedStream: <E extends EventClass>({ open, event, options, }: FeedSource<E>) => Stream.Stream<FeedEntry<E["Type"]>, Failure>;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Effect, Schema, Stream } from "effect";
|
|
2
|
+
import { RetentionGap, UnknownCursor } from "../../errors/events.js";
|
|
3
|
+
import { decodeFailure, undecodableFailure } from "../transport.js";
|
|
4
|
+
import { IDLE_MS, readEvents, reconnecting, session } from "./sse.js";
|
|
5
|
+
const decodeData = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Struct({ event: Schema.Json, commandId: Schema.String, timestamp: Schema.Finite })));
|
|
6
|
+
const cursorError = Schema.decodeUnknownOption(Schema.toCodecJson(Schema.Union([UnknownCursor, RetentionGap])));
|
|
7
|
+
/** A refusal's body, with its response's headers so a `Retry-After` is kept; an `end` message has none. */
|
|
8
|
+
const failureOf = (text, status, headers = new Headers()) => decodeFailure(cursorError)({ status, headers, text, sentAt: 0 });
|
|
9
|
+
/**
|
|
10
|
+
* The committed `event`s of one actor after `after`, as they commit: read
|
|
11
|
+
* from the server's event feed and reopened from the last cursor delivered
|
|
12
|
+
* whenever the connection drops, the server restarts, or the credential
|
|
13
|
+
* expires and is refreshed. It fails with `RetentionGap` if events after the
|
|
14
|
+
* cursor were pruned, and with `UnknownCursor` for a cursor the actor never
|
|
15
|
+
* issued. A dropped or refused feed reopens after the server's `retryAfter`,
|
|
16
|
+
* never sooner, or after a jittered, growing delay. Every event carries its
|
|
17
|
+
* cursor as `id`; the feed's own `end` carries none, so an event named `end` is
|
|
18
|
+
* still an event.
|
|
19
|
+
*/
|
|
20
|
+
export const feedStream = ({ open, event, options, }) => session({
|
|
21
|
+
signal: options.signal,
|
|
22
|
+
run: (emit) => {
|
|
23
|
+
const decodeEvent = Schema.decodeUnknownEffect(Schema.toCodecJson(event));
|
|
24
|
+
let last = options.after;
|
|
25
|
+
return reconnecting((delivered) => Effect.gen(function* () {
|
|
26
|
+
const response = yield* open(last, yield* Effect.abortSignal);
|
|
27
|
+
yield* readEvents({ response, refused: failureOf, idleMs: IDLE_MS }).pipe(Stream.runForEach((message) => Effect.gen(function* () {
|
|
28
|
+
if (message.id === undefined)
|
|
29
|
+
return message.event === "end" ? yield* failureOf(message.data, 0) : undefined;
|
|
30
|
+
const data = yield* decodeData(message.data).pipe(Effect.mapError(undecodableFailure));
|
|
31
|
+
const decoded = yield* decodeEvent(data.event).pipe(Effect.mapError(undecodableFailure));
|
|
32
|
+
last = message.id;
|
|
33
|
+
yield* delivered;
|
|
34
|
+
yield* emit({
|
|
35
|
+
cursor: message.id,
|
|
36
|
+
event: decoded,
|
|
37
|
+
commandId: data.commandId,
|
|
38
|
+
timestamp: data.timestamp,
|
|
39
|
+
});
|
|
40
|
+
})));
|
|
41
|
+
}));
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Effect, type Scope, Stream } from "effect";
|
|
2
|
+
import { type Failure } from "../transport.ts";
|
|
3
|
+
/**
|
|
4
|
+
* One SSE message as a session reads it. `id` is set only when the message
|
|
5
|
+
* introduced a new, non-empty last event id. A standard parser gives every
|
|
6
|
+
* message the last id seen, so a message without its own `id` line, such as a
|
|
7
|
+
* feed's terminal `end`, inherits the previous one; `id` hides that.
|
|
8
|
+
*/
|
|
9
|
+
export interface Message {
|
|
10
|
+
readonly event: string;
|
|
11
|
+
readonly id: string | undefined;
|
|
12
|
+
readonly data: string;
|
|
13
|
+
}
|
|
14
|
+
/** No bytes for this long, keepalive comments included, means the stream is dead. */
|
|
15
|
+
export declare const IDLE_MS = 45000;
|
|
16
|
+
/**
|
|
17
|
+
* The messages of an SSE response, parsed by the standard parser: CR, LF, and
|
|
18
|
+
* CRLF line ends split anywhere across chunks, a leading BOM, UTF-8 split
|
|
19
|
+
* across chunks, and an `id` containing NUL ignored. A `200` without a body
|
|
20
|
+
* fails as undecodable, and any other status fails with `refused` of its body. With `idleMs`, a body that
|
|
21
|
+
* sends no bytes for that long ends the stream. Ending the stream cancels the
|
|
22
|
+
* body.
|
|
23
|
+
*/
|
|
24
|
+
export declare const readEvents: ({ response, refused, idleMs, }: {
|
|
25
|
+
readonly response: Response;
|
|
26
|
+
readonly refused: (text: string, status: number, headers: Headers) => Failure;
|
|
27
|
+
readonly idleMs?: number | undefined;
|
|
28
|
+
}) => Stream.Stream<Message, Failure>;
|
|
29
|
+
/**
|
|
30
|
+
* The values `run` emits as a Stream that ends when `run` returns and fails
|
|
31
|
+
* with what it fails with. `signal` interrupts it, closing `run`'s scope.
|
|
32
|
+
*/
|
|
33
|
+
export declare const session: <A>({ signal, run, }: {
|
|
34
|
+
readonly signal: AbortSignal | undefined;
|
|
35
|
+
readonly run: (emit: (value: A) => Effect.Effect<void>) => Effect.Effect<void, Failure, Scope.Scope>;
|
|
36
|
+
}) => Stream.Stream<A, Failure>;
|
|
37
|
+
/**
|
|
38
|
+
* Runs `attempt`, one connection of a feed or a watch, again after every end
|
|
39
|
+
* that another attempt can resolve: a closed or idle body, a retryable
|
|
40
|
+
* `ActorError`, or one expired credential. An attempt calls `delivered` after
|
|
41
|
+
* each value, which resets the backoff and permits one more credential
|
|
42
|
+
* refresh. The next attempt waits for the server's `retryAfter` when the end
|
|
43
|
+
* carried one, else a jittered delay growing from 100 ms to 5 s. Any other
|
|
44
|
+
* failure ends the session. Which position the next attempt resumes from is
|
|
45
|
+
* the attempt's own state, not this loop's.
|
|
46
|
+
*/
|
|
47
|
+
export declare const reconnecting: (attempt: (delivered: Effect.Effect<void>) => Effect.Effect<void, Failure, Scope.Scope>) => Effect.Effect<never, Failure, never>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Cause, Clock, Duration, Effect, Option, Queue, Random, Schema, Stream, } from "effect";
|
|
2
|
+
import { Sse } from "effect/encoding";
|
|
3
|
+
import { ActorError, Unauthorized } from "../../errors/actor.js";
|
|
4
|
+
import { aborted, networkFailure, undecodableFailure } from "../transport.js";
|
|
5
|
+
/**
|
|
6
|
+
* The framework bounds no single served message except a feed's events, at
|
|
7
|
+
* the 1 MiB a turn may emit; watch results and stream elements are as large as
|
|
8
|
+
* the query or handler makes them. The parser therefore takes any size the
|
|
9
|
+
* server sends instead of Effect's 10 MiB default.
|
|
10
|
+
*/
|
|
11
|
+
const DECODE = { maxEventSize: Number.POSITIVE_INFINITY };
|
|
12
|
+
/** No bytes for this long, keepalive comments included, means the stream is dead. */
|
|
13
|
+
export const IDLE_MS = 45_000;
|
|
14
|
+
const MAX_BACKOFF_MS = 5_000;
|
|
15
|
+
/**
|
|
16
|
+
* The chunks of `body`, read in the consuming fiber so the first read is
|
|
17
|
+
* issued as soon as the response arrives, ending when the body closes or,
|
|
18
|
+
* with `idleMs`, once no chunk arrived for that long. The idle watchdog
|
|
19
|
+
* cancels the body, which ends the pending read, instead of racing each read
|
|
20
|
+
* against a timer: a raced or forked read can miss a chunk that arrives just
|
|
21
|
+
* before the body fails. Closing the stream cancels the body.
|
|
22
|
+
*/
|
|
23
|
+
const chunks = (body, idleMs) => Stream.unwrap(Effect.gen(function* () {
|
|
24
|
+
const reader = body.getReader();
|
|
25
|
+
const cancel = Effect.promise(() => reader.cancel().catch(() => undefined));
|
|
26
|
+
let last = yield* Clock.currentTimeMillis;
|
|
27
|
+
yield* Effect.addFinalizer(() => cancel);
|
|
28
|
+
if (idleMs !== undefined)
|
|
29
|
+
yield* Effect.gen(function* () {
|
|
30
|
+
while (true) {
|
|
31
|
+
const wait = last + idleMs - (yield* Clock.currentTimeMillis);
|
|
32
|
+
if (wait <= 0)
|
|
33
|
+
return yield* cancel;
|
|
34
|
+
yield* Effect.sleep(Duration.millis(wait));
|
|
35
|
+
}
|
|
36
|
+
}).pipe(Effect.forkScoped);
|
|
37
|
+
return Stream.fromEffectRepeat(Effect.tryPromise({ try: () => reader.read(), catch: networkFailure }).pipe(Effect.flatMap((read) => (read.done ? Cause.done() : Effect.succeed(read.value))), Effect.tap(() => Clock.currentTimeMillis.pipe(Effect.map((now) => {
|
|
38
|
+
last = now;
|
|
39
|
+
})))));
|
|
40
|
+
}));
|
|
41
|
+
/**
|
|
42
|
+
* The messages of an SSE response, parsed by the standard parser: CR, LF, and
|
|
43
|
+
* CRLF line ends split anywhere across chunks, a leading BOM, UTF-8 split
|
|
44
|
+
* across chunks, and an `id` containing NUL ignored. A `200` without a body
|
|
45
|
+
* fails as undecodable, and any other status fails with `refused` of its body. With `idleMs`, a body that
|
|
46
|
+
* sends no bytes for that long ends the stream. Ending the stream cancels the
|
|
47
|
+
* body.
|
|
48
|
+
*/
|
|
49
|
+
export const readEvents = ({ response, refused, idleMs, }) => {
|
|
50
|
+
if (response.status !== 200)
|
|
51
|
+
return Stream.fromEffect(Effect.tryPromise({ try: () => response.text(), catch: networkFailure }).pipe(Effect.flatMap((text) => Effect.fail(refused(text, response.status, response.headers)))));
|
|
52
|
+
const body = response.body;
|
|
53
|
+
if (body === null)
|
|
54
|
+
return Stream.fail(undecodableFailure());
|
|
55
|
+
return chunks(body, idleMs).pipe(Stream.decodeText, Stream.pipeThroughChannel(Sse.decode(DECODE)), Stream.mapError((error) => Sse.Retry.is(error)
|
|
56
|
+
? networkFailure()
|
|
57
|
+
: Schema.is(ActorError)(error)
|
|
58
|
+
? error
|
|
59
|
+
: undecodableFailure()), Stream.mapAccum(() => undefined, (seen, message) => [
|
|
60
|
+
message.id,
|
|
61
|
+
[
|
|
62
|
+
{
|
|
63
|
+
event: message.event,
|
|
64
|
+
data: message.data,
|
|
65
|
+
id: message.id === seen || message.id === "" ? undefined : message.id,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
]));
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The values `run` emits as a Stream that ends when `run` returns and fails
|
|
72
|
+
* with what it fails with. `signal` interrupts it, closing `run`'s scope.
|
|
73
|
+
*/
|
|
74
|
+
export const session = ({ signal, run, }) => Stream.callback((out) => run((value) => Queue.offer(out, value).pipe(Effect.asVoid)).pipe(Effect.scoped, Effect.catch((failure) => Queue.fail(out, failure)), Effect.andThen(Queue.end(out)))).pipe(Stream.interruptWhen(aborted(signal)));
|
|
75
|
+
const isExpired = (failure) => Schema.is(Unauthorized)(failure.reason) && failure.reason.code === "expired";
|
|
76
|
+
/**
|
|
77
|
+
* Runs `attempt`, one connection of a feed or a watch, again after every end
|
|
78
|
+
* that another attempt can resolve: a closed or idle body, a retryable
|
|
79
|
+
* `ActorError`, or one expired credential. An attempt calls `delivered` after
|
|
80
|
+
* each value, which resets the backoff and permits one more credential
|
|
81
|
+
* refresh. The next attempt waits for the server's `retryAfter` when the end
|
|
82
|
+
* carried one, else a jittered delay growing from 100 ms to 5 s. Any other
|
|
83
|
+
* failure ends the session. Which position the next attempt resumes from is
|
|
84
|
+
* the attempt's own state, not this loop's.
|
|
85
|
+
*/
|
|
86
|
+
export const reconnecting = Effect.fnUntraced(function* (attempt) {
|
|
87
|
+
let failures = 0;
|
|
88
|
+
let authRetried = false;
|
|
89
|
+
const delivered = Effect.sync(() => {
|
|
90
|
+
failures = 0;
|
|
91
|
+
authRetried = false;
|
|
92
|
+
});
|
|
93
|
+
while (true) {
|
|
94
|
+
const ended = yield* attempt(delivered).pipe(Effect.scoped, Effect.flip, Effect.option);
|
|
95
|
+
let hinted = undefined;
|
|
96
|
+
if (Option.isSome(ended)) {
|
|
97
|
+
const failure = ended.value;
|
|
98
|
+
if (!Schema.is(ActorError)(failure))
|
|
99
|
+
return yield* failure;
|
|
100
|
+
const refresh = !authRetried && isExpired(failure);
|
|
101
|
+
if (!failure.isRetryable && !refresh)
|
|
102
|
+
return yield* failure;
|
|
103
|
+
if (refresh)
|
|
104
|
+
authRetried = true;
|
|
105
|
+
hinted = Option.getOrUndefined(failure.retryAfter);
|
|
106
|
+
}
|
|
107
|
+
const backoff = Math.min(MAX_BACKOFF_MS, 100 * 2 ** failures);
|
|
108
|
+
failures += 1;
|
|
109
|
+
const jitter = yield* Random.nextBetween(0.5, 1.5);
|
|
110
|
+
yield* Effect.sleep(Duration.millis(hinted ?? Math.round(backoff * jitter)));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Effect, type Option, Schema, Stream } from "effect";
|
|
2
|
+
import type { ServedMember } from "../../actor/served.ts";
|
|
3
|
+
import type { ValueSchema } from "../../members/command.ts";
|
|
4
|
+
import { type Failure } from "../transport.ts";
|
|
5
|
+
/** Options of one stream subscription. */
|
|
6
|
+
export interface StreamOptions {
|
|
7
|
+
/** Ends the subscription. */
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
interface StreamSource {
|
|
11
|
+
/** The served stream member subscribed to. */
|
|
12
|
+
readonly member: ServedMember;
|
|
13
|
+
/** Posts the subscription with its encoded input and fresh headers. */
|
|
14
|
+
readonly open: (signal: AbortSignal) => Effect.Effect<Response, Failure>;
|
|
15
|
+
/** Decodes the member's declared errors from a served body. */
|
|
16
|
+
readonly declared: (body: Schema.Json) => Option.Option<Failure>;
|
|
17
|
+
readonly options: StreamOptions;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* One subscription to an `Actor.stream` member: its elements as they arrive,
|
|
21
|
+
* ending when the stream ends by itself and failing with the `ActorError` or
|
|
22
|
+
* declared error that ended it. Streams have no cursor, so a dropped
|
|
23
|
+
* subscription is not resumed: it fails with a retryable `TransportError`,
|
|
24
|
+
* and the caller subscribes again. A stream that closes without an `end`
|
|
25
|
+
* message was cut, not finished.
|
|
26
|
+
*/
|
|
27
|
+
export declare const subscription: ({ member, open, declared, options, }: StreamSource) => Stream.Stream<ValueSchema["Type"], Failure>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Effect, Schema, Stream } from "effect";
|
|
2
|
+
import { decodeFailure, networkFailure, undecodableFailure } from "../transport.js";
|
|
3
|
+
import { readEvents, session } from "./sse.js";
|
|
4
|
+
const decodeJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Json));
|
|
5
|
+
/** Ends the subscription's read loop after the stream's own successful `end`. */
|
|
6
|
+
class Finished {
|
|
7
|
+
_tag = "Finished";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* One subscription to an `Actor.stream` member: its elements as they arrive,
|
|
11
|
+
* ending when the stream ends by itself and failing with the `ActorError` or
|
|
12
|
+
* declared error that ended it. Streams have no cursor, so a dropped
|
|
13
|
+
* subscription is not resumed: it fails with a retryable `TransportError`,
|
|
14
|
+
* and the caller subscribes again. A stream that closes without an `end`
|
|
15
|
+
* message was cut, not finished.
|
|
16
|
+
*/
|
|
17
|
+
export const subscription = ({ member, open, declared, options, }) => session({
|
|
18
|
+
signal: options.signal,
|
|
19
|
+
run: (emit) => Effect.gen(function* () {
|
|
20
|
+
const decodeElement = Schema.decodeUnknownEffect(Schema.toCodecJson(member.output));
|
|
21
|
+
const failureOf = (text, status) => decodeFailure(declared)({ status, headers: new Headers(), text, sentAt: 0 });
|
|
22
|
+
const response = yield* open(yield* Effect.abortSignal);
|
|
23
|
+
const read = readEvents({ response, refused: failureOf }).pipe(Stream.runForEach((message) => Effect.gen(function* () {
|
|
24
|
+
const json = yield* decodeJson(message.data).pipe(Effect.mapError(undecodableFailure));
|
|
25
|
+
if (message.event !== "end")
|
|
26
|
+
return yield* emit(yield* decodeElement(json).pipe(Effect.mapError(undecodableFailure)));
|
|
27
|
+
return yield* json === null
|
|
28
|
+
? Effect.fail(new Finished())
|
|
29
|
+
: Effect.fail(failureOf(message.data, 0));
|
|
30
|
+
})));
|
|
31
|
+
const cut = yield* read.pipe(Effect.as(true), Effect.catchIf((error) => error instanceof Finished, () => Effect.succeed(false)));
|
|
32
|
+
if (cut)
|
|
33
|
+
return yield* networkFailure();
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect, type Option, Schema, Stream } from "effect";
|
|
2
|
+
import { type Failure } from "../transport.ts";
|
|
3
|
+
/** Options of one watch. */
|
|
4
|
+
export interface WatchOptions {
|
|
5
|
+
/** Ends the iteration; the watch stops at once. */
|
|
6
|
+
readonly signal?: AbortSignal;
|
|
7
|
+
}
|
|
8
|
+
interface WatchSource<A> {
|
|
9
|
+
/** Decodes one result's JSON: the watched query's output, or a fleet page. */
|
|
10
|
+
readonly decode: (json: Schema.Json) => Effect.Effect<A, Failure>;
|
|
11
|
+
/**
|
|
12
|
+
* Posts the watch with its encoded input and fresh headers. `version` is the
|
|
13
|
+
* least commit version its first result must reflect, sent as
|
|
14
|
+
* `durable-min-version`.
|
|
15
|
+
*/
|
|
16
|
+
readonly open: (version: string | undefined, signal: AbortSignal) => Effect.Effect<Response, Failure>;
|
|
17
|
+
/** Decodes the query's declared errors from a served body. */
|
|
18
|
+
readonly declared: (body: Schema.Json) => Option.Option<Failure>;
|
|
19
|
+
/** The consistency token the client holds when the watch starts. */
|
|
20
|
+
readonly token: () => string | undefined;
|
|
21
|
+
readonly options: WatchOptions;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One watch of served state, a query declared `watch: true` or a fleet view:
|
|
25
|
+
* its current result, then the newest result after each change. A watch is
|
|
26
|
+
* state, not history, so a dropped connection is reopened after a jittered,
|
|
27
|
+
* growing delay, or the server's `retryAfter`, with the greatest version any
|
|
28
|
+
* result carried as `durable-min-version`; its first result is the current
|
|
29
|
+
* state, never older than one already delivered. It fails with the query's
|
|
30
|
+
* declared error or the `ActorError` that ended it when a retry cannot help,
|
|
31
|
+
* and an expired credential is retried once.
|
|
32
|
+
*/
|
|
33
|
+
export declare const watchStream: <A>({ decode, open, declared, token, options, }: WatchSource<A>) => Stream.Stream<A, Failure>;
|
|
34
|
+
export {};
|