@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,425 @@
|
|
|
1
|
+
import { Clock, Duration, Effect, Exit, Match, Option, Predicate, Random, Result, Schema, SchemaAST, } from "effect";
|
|
2
|
+
import { Base64Url } from "effect/encoding";
|
|
3
|
+
import { ActorError, InvalidCommandId, InvalidInput, Timeout } from "../errors/actor.js";
|
|
4
|
+
import { ConsistencyToken, DatabaseClock, lifetime, retryDeadline } from "./clock.js";
|
|
5
|
+
import { openCommandQueue } from "./offline/queue.js";
|
|
6
|
+
import { aborted, decodeFailure, decodeSuccess, networkFailure, retryAfterHeader, } from "./transport.js";
|
|
7
|
+
const JwtClaims = Schema.Struct({ iss: Schema.NonEmptyString, sub: Schema.NonEmptyString });
|
|
8
|
+
const decodeJwtPayload = Schema.decodeUnknownOption(Schema.fromJsonString(JwtClaims));
|
|
9
|
+
/**
|
|
10
|
+
* The unverified `iss` and `sub` of a `Bearer` JWT: only a key naming whose
|
|
11
|
+
* queued commands these are, since the server verifies every attempt.
|
|
12
|
+
*/
|
|
13
|
+
const decodeJwtClaims = (header) => {
|
|
14
|
+
const parts = header === undefined ? undefined : /^Bearer[ ]+([^ ]+)[ ]*$/i.exec(header)?.[1]?.split(".");
|
|
15
|
+
if (parts?.length !== 3)
|
|
16
|
+
return Option.none();
|
|
17
|
+
return Result.match(Base64Url.decodeString(parts[1]), {
|
|
18
|
+
onFailure: () => Option.none(),
|
|
19
|
+
onSuccess: decodeJwtPayload,
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
23
|
+
const MAX_BACKOFF_MS = 2_000;
|
|
24
|
+
/** Ids a client remembers minting per origin, so it can tell whether one might have been admitted; the oldest go first. */
|
|
25
|
+
const MINTED_LIMIT = 1_024;
|
|
26
|
+
/** How long a mint waits for the server before it falls back to the retry window and clock offset this page last learned. */
|
|
27
|
+
const MINT_PROBE_MS = 3_000;
|
|
28
|
+
/** Base URLs whose clock and token state are shared per process; the least recently used go first. */
|
|
29
|
+
const ORIGIN_LIMIT = 64;
|
|
30
|
+
const origins = new Map();
|
|
31
|
+
const originOf = (baseUrl) => {
|
|
32
|
+
const existing = origins.get(baseUrl);
|
|
33
|
+
if (existing !== undefined) {
|
|
34
|
+
origins.delete(baseUrl);
|
|
35
|
+
origins.set(baseUrl, existing);
|
|
36
|
+
return existing;
|
|
37
|
+
}
|
|
38
|
+
const origin = {
|
|
39
|
+
clock: new DatabaseClock(),
|
|
40
|
+
token: new ConsistencyToken(),
|
|
41
|
+
window: undefined,
|
|
42
|
+
minted: new Map(),
|
|
43
|
+
};
|
|
44
|
+
origins.set(baseUrl, origin);
|
|
45
|
+
const oldest = origins.keys().next();
|
|
46
|
+
if (origins.size > ORIGIN_LIMIT && oldest.done !== true)
|
|
47
|
+
origins.delete(oldest.value);
|
|
48
|
+
return origin;
|
|
49
|
+
};
|
|
50
|
+
const ProtocolInfo = Schema.Struct({
|
|
51
|
+
protocol: Schema.Literal(1),
|
|
52
|
+
retryWindowMs: Schema.Int,
|
|
53
|
+
now: Schema.Int,
|
|
54
|
+
});
|
|
55
|
+
const decodeProtocol = Schema.decodeUnknownEffect(ProtocolInfo);
|
|
56
|
+
const decodeMinted = Schema.decodeUnknownEffect(Schema.Struct({ commandId: Schema.String }));
|
|
57
|
+
const isFramework = Schema.is(ActorError);
|
|
58
|
+
const isInvalidCommandId = Schema.is(InvalidCommandId);
|
|
59
|
+
/** True when a failure proves the attempt was refused before any turn could run. */
|
|
60
|
+
const refusedBeforeTurn = (failure) => isFramework(failure) &&
|
|
61
|
+
Match.value(failure.reason).pipe(Match.tags({
|
|
62
|
+
InvalidCommandId: () => true,
|
|
63
|
+
InvalidInput: () => true,
|
|
64
|
+
Unauthorized: (reason) => reason.isCredential,
|
|
65
|
+
}), Match.orElse(() => false));
|
|
66
|
+
/** Counts `request` as unanswered for `use` while it runs; an abandoned request might still be admitted. */
|
|
67
|
+
const tracked = (use, request) => use === undefined
|
|
68
|
+
? request
|
|
69
|
+
: Effect.suspend(() => {
|
|
70
|
+
use.inFlight += 1;
|
|
71
|
+
return request.pipe(Effect.onExit((exit) => Effect.sync(() => {
|
|
72
|
+
use.inFlight -= 1;
|
|
73
|
+
if (Exit.hasInterrupts(exit))
|
|
74
|
+
use.admitted = true;
|
|
75
|
+
})));
|
|
76
|
+
});
|
|
77
|
+
const jittered = (ms) => Random.nextBetween(0.5, 1.5).pipe(Effect.map((f) => Math.round(ms * f)));
|
|
78
|
+
const retryAfterOf = (failure) => Effect.succeed(failure.retryAfter);
|
|
79
|
+
/** Milliseconds to wait before retrying with the same id, or none to stop. */
|
|
80
|
+
const retryDelay = (retry, clock) => (attempted) => Effect.gen(function* () {
|
|
81
|
+
const { failure, reply } = attempted;
|
|
82
|
+
if (!isFramework(failure))
|
|
83
|
+
return Option.none();
|
|
84
|
+
const now = yield* Clock.currentTimeMillis;
|
|
85
|
+
const header = Option.fromUndefinedOr(reply === undefined
|
|
86
|
+
? undefined
|
|
87
|
+
: retryAfterHeader({
|
|
88
|
+
headers: reply.headers,
|
|
89
|
+
now,
|
|
90
|
+
elapsed: clock.localNow() - reply.sentAt,
|
|
91
|
+
}));
|
|
92
|
+
return yield* Match.value(failure.reason).pipe(Match.tags({
|
|
93
|
+
ActorUnavailable: () => retryAfterOf(failure),
|
|
94
|
+
RunnerAtCapacity: () => retryAfterOf(failure),
|
|
95
|
+
ConnectionLimitExceeded: () => retryAfterOf(failure),
|
|
96
|
+
MailboxFull: () => retryAfterOf(failure),
|
|
97
|
+
Timeout: () => Effect.asSome(jittered(50)),
|
|
98
|
+
TransportError: (reason) => !reason.retryable
|
|
99
|
+
? Effect.succeedNone
|
|
100
|
+
: Option.isSome(header)
|
|
101
|
+
? Effect.succeed(header)
|
|
102
|
+
: Effect.asSome(jittered(Math.min(MAX_BACKOFF_MS, 100 * 2 ** retry.attempts))),
|
|
103
|
+
InvalidCommandId: (reason) => {
|
|
104
|
+
const issued = lifetime(reason.commandId);
|
|
105
|
+
if (reason.code !== "future" || retry.futureRetried || issued === undefined)
|
|
106
|
+
return Effect.succeedNone;
|
|
107
|
+
retry.futureRetried = true;
|
|
108
|
+
return Effect.succeedSome(Math.max(50, clock.untilReached(issued.issuedAt) + 50));
|
|
109
|
+
},
|
|
110
|
+
Unauthorized: (reason) => {
|
|
111
|
+
if (reason.code !== "expired" || retry.authRetried)
|
|
112
|
+
return Effect.succeedNone;
|
|
113
|
+
retry.authRetried = true;
|
|
114
|
+
return Effect.succeedSome(0);
|
|
115
|
+
},
|
|
116
|
+
}), Match.orElse(() => Effect.succeedNone));
|
|
117
|
+
});
|
|
118
|
+
/** `path` under `baseUrl`, without doubling the slash between them. */
|
|
119
|
+
export const joinUrl = ({ baseUrl, path }) => `${baseUrl.replace(/\/+$/, "")}${path}`;
|
|
120
|
+
const hex = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
121
|
+
const formatUuid = (bytes) => {
|
|
122
|
+
const digits = hex(bytes);
|
|
123
|
+
return `${digits.slice(0, 8)}-${digits.slice(8, 12)}-${digits.slice(12, 16)}-${digits.slice(16, 20)}-${digits.slice(20)}`;
|
|
124
|
+
};
|
|
125
|
+
/** A random RFC 9562 UUID of `version` 4 or 7; a v7 carries the local clock in its first 48 bits. */
|
|
126
|
+
export const uuid = (version) => Effect.gen(function* () {
|
|
127
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
|
|
128
|
+
if (version === 7) {
|
|
129
|
+
let time = yield* Clock.currentTimeMillis;
|
|
130
|
+
for (let index = 5; index >= 0; index -= 1) {
|
|
131
|
+
bytes[index] = time % 256;
|
|
132
|
+
time = Math.floor(time / 256);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
bytes[6] = (bytes[6] & 0x0f) | (version << 4);
|
|
136
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
137
|
+
return formatUuid(bytes);
|
|
138
|
+
});
|
|
139
|
+
const declaredDecoders = new WeakMap();
|
|
140
|
+
export const declaredDecoder = (member) => {
|
|
141
|
+
const cached = declaredDecoders.get(member);
|
|
142
|
+
if (cached !== undefined)
|
|
143
|
+
return cached;
|
|
144
|
+
const decode = member.errors.length === 0
|
|
145
|
+
? () => Option.none()
|
|
146
|
+
: Schema.decodeUnknownOption(Schema.toCodecJson(Schema.Union(member.errors)));
|
|
147
|
+
declaredDecoders.set(member, decode);
|
|
148
|
+
return decode;
|
|
149
|
+
};
|
|
150
|
+
/** Decodes a success body the way the server writes it: empty for void, `null` for undefined. */
|
|
151
|
+
const outputDecoder = (member) => {
|
|
152
|
+
if (SchemaAST.isVoid(member.output.ast))
|
|
153
|
+
return () => Effect.void;
|
|
154
|
+
const decode = Schema.decodeUnknownEffect(Schema.toCodecJson(member.output));
|
|
155
|
+
return (json) => json === null ? decode(null).pipe(Effect.catch(() => decode(undefined))) : decode(json);
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* The transport attempt policy of one actor type's client at one base URL:
|
|
159
|
+
* fresh headers and credentials for each attempt, the database clock and
|
|
160
|
+
* retry window its ids are minted from, which minted ids might have been
|
|
161
|
+
* admitted, bounded retries under one id, and the offline queue. The typed
|
|
162
|
+
* handle projection lives in `clientOf`; nothing here knows member types.
|
|
163
|
+
*/
|
|
164
|
+
export const callsOf = ({ definition, options, }) => {
|
|
165
|
+
const origin = originOf(options.baseUrl);
|
|
166
|
+
const clock = origin.clock;
|
|
167
|
+
const fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
168
|
+
const provided = Effect.suspend(() => {
|
|
169
|
+
const headers = options.headers;
|
|
170
|
+
return Predicate.isFunction(headers)
|
|
171
|
+
? Effect.promise(() => Promise.resolve(headers()))
|
|
172
|
+
: Effect.succeed(headers);
|
|
173
|
+
});
|
|
174
|
+
const authorization = provided.pipe(Effect.map((headers) => new Headers(headers).get("authorization") ?? undefined));
|
|
175
|
+
const identity = options.identity;
|
|
176
|
+
const principal = identity === undefined
|
|
177
|
+
? Effect.flatMap(authorization, (header) => {
|
|
178
|
+
const claims = decodeJwtClaims(header);
|
|
179
|
+
return Option.isSome(claims)
|
|
180
|
+
? Effect.succeed(`${claims.value.iss}\n${claims.value.sub}`)
|
|
181
|
+
: Effect.die(new Error("An offline client needs ClientOptions.identity unless its authorization is a Bearer JWT with iss and sub"));
|
|
182
|
+
})
|
|
183
|
+
: Effect.promise(() => Promise.resolve(identity()));
|
|
184
|
+
const send = (request) => Effect.gen(function* () {
|
|
185
|
+
const headers = new Headers(yield* provided);
|
|
186
|
+
for (const [name, value] of Object.entries(request.headers))
|
|
187
|
+
headers.set(name, value);
|
|
188
|
+
headers.set("durable-protocol", "1");
|
|
189
|
+
headers.set("accept", "application/json");
|
|
190
|
+
const sentAt = clock.localNow();
|
|
191
|
+
const response = yield* Effect.tryPromise({
|
|
192
|
+
try: (signal) => fetch(joinUrl({ baseUrl: options.baseUrl, path: request.path }), {
|
|
193
|
+
method: request.method,
|
|
194
|
+
headers,
|
|
195
|
+
body: request.body,
|
|
196
|
+
signal,
|
|
197
|
+
}),
|
|
198
|
+
catch: networkFailure,
|
|
199
|
+
});
|
|
200
|
+
const text = yield* Effect.tryPromise({ try: () => response.text(), catch: networkFailure });
|
|
201
|
+
const now = response.headers.get("durable-now");
|
|
202
|
+
if (now !== null && response.status !== 504)
|
|
203
|
+
clock.observe(sentAt, clock.localNow(), Number(now));
|
|
204
|
+
origin.token.observe(response.headers.get("durable-version"));
|
|
205
|
+
const reply = { status: response.status, headers: response.headers, text, sentAt };
|
|
206
|
+
return reply;
|
|
207
|
+
});
|
|
208
|
+
/** Opens an SSE response at `path` with fresh headers and `init.headers` set over them. */
|
|
209
|
+
const openEvents = (path, signal, init) => Effect.gen(function* () {
|
|
210
|
+
const headers = new Headers(yield* provided);
|
|
211
|
+
for (const [name, value] of Object.entries(init.headers))
|
|
212
|
+
headers.set(name, value);
|
|
213
|
+
headers.set("accept", "text/event-stream");
|
|
214
|
+
headers.set("durable-protocol", "1");
|
|
215
|
+
const url = joinUrl({ baseUrl: options.baseUrl, path: yield* path });
|
|
216
|
+
return yield* Effect.tryPromise({
|
|
217
|
+
try: () => fetch(url, {
|
|
218
|
+
method: init.method,
|
|
219
|
+
headers,
|
|
220
|
+
body: init.body,
|
|
221
|
+
signal,
|
|
222
|
+
}),
|
|
223
|
+
catch: networkFailure,
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
const isOk = (reply) => reply.status >= 200 && reply.status < 300;
|
|
227
|
+
const retryWindow = Effect.suspend(() => {
|
|
228
|
+
const cached = origin.window;
|
|
229
|
+
if (cached !== undefined && clock.isFresh)
|
|
230
|
+
return Effect.succeed(cached);
|
|
231
|
+
return send({ method: "GET", path: "/protocol", body: undefined, headers: {} }).pipe(Effect.flatMap((reply) => isOk(reply)
|
|
232
|
+
? decodeSuccess((body) => decodeProtocol(body))(reply)
|
|
233
|
+
: Effect.fail(decodeFailure(undefined)(reply))), Effect.map((protocol) => {
|
|
234
|
+
origin.window = protocol.retryWindowMs;
|
|
235
|
+
return protocol.retryWindowMs;
|
|
236
|
+
}));
|
|
237
|
+
});
|
|
238
|
+
const mintServer = send({
|
|
239
|
+
method: "POST",
|
|
240
|
+
path: "/command-ids",
|
|
241
|
+
body: undefined,
|
|
242
|
+
headers: {},
|
|
243
|
+
}).pipe(Effect.flatMap((reply) => isOk(reply)
|
|
244
|
+
? decodeSuccess((body) => decodeMinted(body))(reply)
|
|
245
|
+
: Effect.fail(decodeFailure(undefined)(reply))), Effect.map((minted) => minted.commandId));
|
|
246
|
+
const mintLocal = Effect.gen(function* () {
|
|
247
|
+
const window = yield* retryWindow;
|
|
248
|
+
if (!clock.isFresh)
|
|
249
|
+
return yield* mintServer;
|
|
250
|
+
return clock.mint(window, yield* uuid(4));
|
|
251
|
+
});
|
|
252
|
+
const remember = (commandId) => Effect.sync(() => {
|
|
253
|
+
origin.minted.set(commandId, { admitted: false, inFlight: 0 });
|
|
254
|
+
const oldest = origin.minted.keys().next();
|
|
255
|
+
if (origin.minted.size > MINTED_LIMIT && oldest.done !== true)
|
|
256
|
+
origin.minted.delete(oldest.value);
|
|
257
|
+
});
|
|
258
|
+
const mintOnline = (options.commandIds === "server" ? mintServer : mintLocal).pipe(Effect.tap(remember));
|
|
259
|
+
/**
|
|
260
|
+
* With an offline store, a mint that cannot reach the server within
|
|
261
|
+
* `MINT_PROBE_MS` uses the retry window and the clock offset this page
|
|
262
|
+
* last learned, so a command can be queued while the network is down. A
|
|
263
|
+
* page that never reached the server has learned neither, and fails
|
|
264
|
+
* with the network error rather than guess a window.
|
|
265
|
+
*/
|
|
266
|
+
const mintOffline = mintOnline.pipe(Effect.timeoutOrElse({
|
|
267
|
+
duration: Duration.millis(MINT_PROBE_MS),
|
|
268
|
+
orElse: () => Effect.fail(networkFailure()),
|
|
269
|
+
}), Effect.catch((failure) => {
|
|
270
|
+
const window = origin.window;
|
|
271
|
+
if (window === undefined || !clock.isSampled)
|
|
272
|
+
return Effect.fail(failure);
|
|
273
|
+
return uuid(4).pipe(Effect.map((id) => clock.mint(window, id)), Effect.tap(remember));
|
|
274
|
+
}));
|
|
275
|
+
const mint = options.offline === undefined ? mintOnline : mintOffline;
|
|
276
|
+
/**
|
|
277
|
+
* Waits for `work` until the call's timeout or signal ends the wait, which
|
|
278
|
+
* fails with `Timeout` carrying the command's id: the outcome is unknown,
|
|
279
|
+
* and that id is what a caller retries later.
|
|
280
|
+
*/
|
|
281
|
+
const waiting = (work, call, commandId) => {
|
|
282
|
+
const unanswered = Effect.suspend(() => {
|
|
283
|
+
const id = commandId();
|
|
284
|
+
return Effect.fail(ActorError.make({ reason: Timeout.make(id === undefined ? {} : { commandId: id }) }));
|
|
285
|
+
});
|
|
286
|
+
const bounded = work.pipe(Effect.timeoutOrElse({
|
|
287
|
+
duration: Duration.millis(call.timeoutInMs ?? options.timeoutInMs ?? DEFAULT_TIMEOUT_MS),
|
|
288
|
+
orElse: () => unanswered,
|
|
289
|
+
}));
|
|
290
|
+
return Effect.runPromise(Effect.raceFirst(bounded, aborted(call.signal).pipe(Effect.andThen(unanswered))));
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Runs `attempt` until it succeeds or a stop condition holds, surfacing the last failure.
|
|
294
|
+
* With `after`, the first attempt waits for it, inside the same timeout and abort.
|
|
295
|
+
*/
|
|
296
|
+
const withRetries = (attempt, call, commandId, after) => {
|
|
297
|
+
const retry = { attempts: 0, futureRetried: false, authRetried: false };
|
|
298
|
+
const loop = attempt.pipe(Effect.catch((attempted) => Effect.gen(function* () {
|
|
299
|
+
if (isFramework(attempted.failure) &&
|
|
300
|
+
isInvalidCommandId(attempted.failure.reason) &&
|
|
301
|
+
attempted.failure.reason.code === "window")
|
|
302
|
+
origin.window = undefined;
|
|
303
|
+
const delay = yield* retryDelay(retry, clock)(attempted);
|
|
304
|
+
retry.attempts += 1;
|
|
305
|
+
const id = commandId();
|
|
306
|
+
const deadline = id === undefined || !clock.isFresh ? undefined : retryDeadline(id);
|
|
307
|
+
if (Option.isNone(delay) ||
|
|
308
|
+
(deadline !== undefined && clock.now() + delay.value >= deadline))
|
|
309
|
+
return yield* attempted.failure;
|
|
310
|
+
yield* Effect.sleep(Duration.millis(delay.value));
|
|
311
|
+
return yield* loop;
|
|
312
|
+
})));
|
|
313
|
+
const queued = after === undefined ? loop : Effect.promise(() => after).pipe(Effect.andThen(loop));
|
|
314
|
+
return waiting(queued, call, commandId);
|
|
315
|
+
};
|
|
316
|
+
/** A failure as the call that sent `commandId` reports it, with whether any attempt might have been admitted. */
|
|
317
|
+
const admittedFor = (commandId) => (failure) => {
|
|
318
|
+
const use = commandId === undefined ? undefined : origin.minted.get(commandId);
|
|
319
|
+
if (use === undefined)
|
|
320
|
+
return failure;
|
|
321
|
+
if (!refusedBeforeTurn(failure))
|
|
322
|
+
use.admitted = true;
|
|
323
|
+
if (!isFramework(failure) || !isInvalidCommandId(failure.reason))
|
|
324
|
+
return failure;
|
|
325
|
+
return ActorError.make({
|
|
326
|
+
reason: InvalidCommandId.make({
|
|
327
|
+
commandId: failure.reason.commandId,
|
|
328
|
+
code: failure.reason.code,
|
|
329
|
+
neverAdmitted: !use.admitted && use.inFlight === 0,
|
|
330
|
+
}),
|
|
331
|
+
});
|
|
332
|
+
};
|
|
333
|
+
/** `error` as a failed attempt: its own, or a failure before any request, reported for `commandId`. */
|
|
334
|
+
const asAttempt = (commandId) => (error) => "failure" in error ? error : { failure: admittedFor(commandId)(error), reply: undefined };
|
|
335
|
+
/** One attempt of `member` at `path`, sending `payload` under `commandId`, which a query has none of. */
|
|
336
|
+
const poster = (member) => {
|
|
337
|
+
const decode = outputDecoder(member);
|
|
338
|
+
const isQuery = member.kind === "query";
|
|
339
|
+
const decodeDeclared = declaredDecoder(member);
|
|
340
|
+
return (path, payload, commandId) => Effect.gen(function* () {
|
|
341
|
+
const headers = {};
|
|
342
|
+
if (payload !== undefined)
|
|
343
|
+
headers["content-type"] = "application/json";
|
|
344
|
+
if (commandId !== undefined)
|
|
345
|
+
headers["idempotency-key"] = commandId;
|
|
346
|
+
const token = origin.token.value;
|
|
347
|
+
if (isQuery && token !== undefined)
|
|
348
|
+
headers["durable-min-version"] = token;
|
|
349
|
+
const use = commandId === undefined ? undefined : origin.minted.get(commandId);
|
|
350
|
+
const reply = yield* tracked(use, send({ method: "POST", path, body: payload, headers }));
|
|
351
|
+
if (isOk(reply)) {
|
|
352
|
+
if (use !== undefined)
|
|
353
|
+
use.admitted = true;
|
|
354
|
+
return yield* decodeSuccess(decode)(reply);
|
|
355
|
+
}
|
|
356
|
+
const attempted = {
|
|
357
|
+
failure: admittedFor(commandId)(decodeFailure(decodeDeclared)(reply)),
|
|
358
|
+
reply,
|
|
359
|
+
};
|
|
360
|
+
return yield* Effect.fail(attempted);
|
|
361
|
+
}).pipe(Effect.mapError(asAttempt(commandId)));
|
|
362
|
+
};
|
|
363
|
+
const members = new Map(definition.members.map((member) => [member.tag, member]));
|
|
364
|
+
const unknownMember = () => ActorError.make({ reason: InvalidInput.make({ code: "unknown_route" }) });
|
|
365
|
+
/**
|
|
366
|
+
* The persisted queue of `options.offline`, delivering the commands saved
|
|
367
|
+
* under this base URL for this actor type. Each delivery keeps its own
|
|
368
|
+
* retry state, and a member removed since a command was saved fails that
|
|
369
|
+
* command for good instead of retrying it.
|
|
370
|
+
*/
|
|
371
|
+
const queue = options.offline === undefined
|
|
372
|
+
? undefined
|
|
373
|
+
: openCommandQueue({
|
|
374
|
+
store: options.offline,
|
|
375
|
+
baseUrl: options.baseUrl,
|
|
376
|
+
actor: definition.name,
|
|
377
|
+
principal,
|
|
378
|
+
now: () => clock.now(),
|
|
379
|
+
begin: (command) => {
|
|
380
|
+
const member = members.get(command.member);
|
|
381
|
+
if (member === undefined)
|
|
382
|
+
return Effect.fail({
|
|
383
|
+
failure: unknownMember(),
|
|
384
|
+
retryAfterMs: Option.none(),
|
|
385
|
+
answer: undefined,
|
|
386
|
+
});
|
|
387
|
+
const retry = { attempts: 0, futureRetried: false, authRetried: false };
|
|
388
|
+
return poster(member)(`${command.target}/${member.tag}`, command.body, command.commandId).pipe(Effect.catch((attempted) => retryDelay(retry, clock)(attempted).pipe(Effect.tap(() => Effect.sync(() => {
|
|
389
|
+
retry.attempts += 1;
|
|
390
|
+
})), Effect.flatMap((delay) => Effect.fail({
|
|
391
|
+
failure: attempted.failure,
|
|
392
|
+
retryAfterMs: delay,
|
|
393
|
+
answer: attempted.reply === undefined
|
|
394
|
+
? undefined
|
|
395
|
+
: { status: attempted.reply.status, text: attempted.reply.text },
|
|
396
|
+
})))));
|
|
397
|
+
},
|
|
398
|
+
failureOf: (command) => {
|
|
399
|
+
const member = members.get(command.member);
|
|
400
|
+
const answer = command.answer ?? { status: 0, text: "" };
|
|
401
|
+
if (member === undefined)
|
|
402
|
+
return unknownMember();
|
|
403
|
+
return decodeFailure(declaredDecoder(member))({
|
|
404
|
+
status: answer.status,
|
|
405
|
+
headers: new Headers(),
|
|
406
|
+
text: answer.text,
|
|
407
|
+
sentAt: 0,
|
|
408
|
+
});
|
|
409
|
+
},
|
|
410
|
+
warm: retryWindow.pipe(Effect.asVoid, Effect.ignore),
|
|
411
|
+
});
|
|
412
|
+
return {
|
|
413
|
+
authorization,
|
|
414
|
+
token: origin.token,
|
|
415
|
+
openEvents,
|
|
416
|
+
mint,
|
|
417
|
+
waiting,
|
|
418
|
+
withRetries,
|
|
419
|
+
asAttempt,
|
|
420
|
+
poster,
|
|
421
|
+
queue,
|
|
422
|
+
/** A fresh command id, retried like a call until it is minted. */
|
|
423
|
+
commandId: () => withRetries(mint.pipe(Effect.mapError(asAttempt(undefined))), {}, () => undefined),
|
|
424
|
+
};
|
|
425
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** A monotonic local clock in epoch milliseconds, unaffected by wall-clock steps. */
|
|
2
|
+
export declare const monotonic: () => number;
|
|
3
|
+
/**
|
|
4
|
+
* The database clock as a client estimates it: the offset of the
|
|
5
|
+
* lowest-latency round trip of the last minute, applied to a local clock.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DatabaseClock {
|
|
8
|
+
private samples;
|
|
9
|
+
private readonly local;
|
|
10
|
+
constructor(local?: () => number);
|
|
11
|
+
/** The local time now, for stamping a request before it is sent. */
|
|
12
|
+
readonly localNow: () => number;
|
|
13
|
+
/** Records a response's `durable-now`, stamped between `sentAt` and `receivedAt`. */
|
|
14
|
+
observe(sentAt: number, receivedAt: number, serverNow: number): void;
|
|
15
|
+
private best;
|
|
16
|
+
/** Whether any response has been observed yet. */
|
|
17
|
+
get isSampled(): boolean;
|
|
18
|
+
/** Whether a sample from the last minute exists; an older offset may have drifted. */
|
|
19
|
+
get isFresh(): boolean;
|
|
20
|
+
/** Estimated database time; the local clock alone until a sample exists. */
|
|
21
|
+
now(): number;
|
|
22
|
+
/**
|
|
23
|
+
* Local milliseconds until the database clock has surely reached
|
|
24
|
+
* `epochMillis`. The server may have stamped its sample anywhere within the
|
|
25
|
+
* round trip, so the estimate can run ahead by half of it.
|
|
26
|
+
*/
|
|
27
|
+
untilReached(epochMillis: number): number;
|
|
28
|
+
/**
|
|
29
|
+
* A v1 command id issued behind the estimated database clock, with the
|
|
30
|
+
* deployment's window. The lead is at least a second and the sample's round
|
|
31
|
+
* trip, but a short window caps it at a quarter of the window, never below the
|
|
32
|
+
* sample's error.
|
|
33
|
+
*/
|
|
34
|
+
mint(retryWindowMs: number, uuid: string): string;
|
|
35
|
+
}
|
|
36
|
+
/** The issue and expiry times of a v1 id, or `undefined` for any other string. */
|
|
37
|
+
export declare const lifetime: (commandId: string) => {
|
|
38
|
+
issuedAt: number;
|
|
39
|
+
expiresAt: number;
|
|
40
|
+
} | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* When retries of a v1 id stop, so no attempt races its own expiry: a second
|
|
43
|
+
* before it expires, or a quarter of its window before when that is shorter.
|
|
44
|
+
*/
|
|
45
|
+
export declare const retryDeadline: (commandId: string) => number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* The highest `durable-version` a client has seen: a non-negative decimal
|
|
48
|
+
* string, ordered by length and then digits, never as a number.
|
|
49
|
+
*/
|
|
50
|
+
export declare class ConsistencyToken {
|
|
51
|
+
private highest;
|
|
52
|
+
/** The highest version seen, to send as `durable-min-version`; undefined until one is seen. */
|
|
53
|
+
get value(): string | undefined;
|
|
54
|
+
/** Records a response's `durable-version` header; a missing or malformed one is ignored. */
|
|
55
|
+
observe(value: string | null): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** How long one round trip's sample of the database clock stays eligible. */
|
|
2
|
+
const SAMPLE_WINDOW_MS = 60_000;
|
|
3
|
+
/** A response slower than this says too little about when the server stamped it. */
|
|
4
|
+
const MAX_SAMPLE_RTT_MS = 5_000;
|
|
5
|
+
/** The least lead an id's issue time keeps behind the estimated database clock. */
|
|
6
|
+
const MIN_LEAD_MS = 1_000;
|
|
7
|
+
/** The most samples kept; the slowest is dropped past this. */
|
|
8
|
+
const MAX_SAMPLES = 16;
|
|
9
|
+
/** A monotonic local clock in epoch milliseconds, unaffected by wall-clock steps. */
|
|
10
|
+
export const monotonic = () => performance.timeOrigin + performance.now();
|
|
11
|
+
/**
|
|
12
|
+
* The database clock as a client estimates it: the offset of the
|
|
13
|
+
* lowest-latency round trip of the last minute, applied to a local clock.
|
|
14
|
+
*/
|
|
15
|
+
export class DatabaseClock {
|
|
16
|
+
samples = [];
|
|
17
|
+
local;
|
|
18
|
+
constructor(local = monotonic) {
|
|
19
|
+
this.local = local;
|
|
20
|
+
}
|
|
21
|
+
/** The local time now, for stamping a request before it is sent. */
|
|
22
|
+
localNow = () => this.local();
|
|
23
|
+
/** Records a response's `durable-now`, stamped between `sentAt` and `receivedAt`. */
|
|
24
|
+
observe(sentAt, receivedAt, serverNow) {
|
|
25
|
+
const rtt = Math.max(0, receivedAt - sentAt);
|
|
26
|
+
if (!Number.isFinite(serverNow) || rtt > MAX_SAMPLE_RTT_MS)
|
|
27
|
+
return;
|
|
28
|
+
const sample = { offset: serverNow - (sentAt + receivedAt) / 2, rtt, at: receivedAt };
|
|
29
|
+
const kept = this.samples.filter((older) => receivedAt - older.at < SAMPLE_WINDOW_MS);
|
|
30
|
+
kept.push(sample);
|
|
31
|
+
if (kept.length > MAX_SAMPLES) {
|
|
32
|
+
const slowest = kept.reduce((worst, older, index) => (older.rtt > kept[worst].rtt ? index : worst), 0);
|
|
33
|
+
kept.splice(slowest, 1);
|
|
34
|
+
}
|
|
35
|
+
this.samples = kept;
|
|
36
|
+
}
|
|
37
|
+
best() {
|
|
38
|
+
const now = this.local();
|
|
39
|
+
const recent = this.samples.filter((sample) => now - sample.at < SAMPLE_WINDOW_MS);
|
|
40
|
+
if (recent.length === 0)
|
|
41
|
+
return this.samples.at(-1);
|
|
42
|
+
return recent.reduce((best, sample) => (sample.rtt < best.rtt ? sample : best));
|
|
43
|
+
}
|
|
44
|
+
/** Whether any response has been observed yet. */
|
|
45
|
+
get isSampled() {
|
|
46
|
+
return this.samples.length > 0;
|
|
47
|
+
}
|
|
48
|
+
/** Whether a sample from the last minute exists; an older offset may have drifted. */
|
|
49
|
+
get isFresh() {
|
|
50
|
+
const now = this.local();
|
|
51
|
+
return this.samples.some((sample) => now - sample.at < SAMPLE_WINDOW_MS);
|
|
52
|
+
}
|
|
53
|
+
/** Estimated database time; the local clock alone until a sample exists. */
|
|
54
|
+
now() {
|
|
55
|
+
return this.local() + (this.best()?.offset ?? 0);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Local milliseconds until the database clock has surely reached
|
|
59
|
+
* `epochMillis`. The server may have stamped its sample anywhere within the
|
|
60
|
+
* round trip, so the estimate can run ahead by half of it.
|
|
61
|
+
*/
|
|
62
|
+
untilReached(epochMillis) {
|
|
63
|
+
return epochMillis - this.now() + (this.best()?.rtt ?? 0) / 2;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A v1 command id issued behind the estimated database clock, with the
|
|
67
|
+
* deployment's window. The lead is at least a second and the sample's round
|
|
68
|
+
* trip, but a short window caps it at a quarter of the window, never below the
|
|
69
|
+
* sample's error.
|
|
70
|
+
*/
|
|
71
|
+
mint(retryWindowMs, uuid) {
|
|
72
|
+
const rtt = this.best()?.rtt ?? 0;
|
|
73
|
+
const lead = Math.max(rtt / 2, Math.min(Math.max(MIN_LEAD_MS, rtt), retryWindowMs / 4));
|
|
74
|
+
const issuedAt = Math.floor(this.now() - lead);
|
|
75
|
+
return `v1.${issuedAt}.${issuedAt + retryWindowMs}.${uuid}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const V1 = /^v1\.(\d+)\.(\d+)\.[0-9a-f-]{36}$/i;
|
|
79
|
+
/** The issue and expiry times of a v1 id, or `undefined` for any other string. */
|
|
80
|
+
export const lifetime = (commandId) => {
|
|
81
|
+
const match = V1.exec(commandId);
|
|
82
|
+
if (match === null)
|
|
83
|
+
return undefined;
|
|
84
|
+
return { issuedAt: Number(match[1]), expiresAt: Number(match[2]) };
|
|
85
|
+
};
|
|
86
|
+
/** How long before its expiry retries of an id stop. */
|
|
87
|
+
const EXPIRY_MARGIN_MS = 1_000;
|
|
88
|
+
/**
|
|
89
|
+
* When retries of a v1 id stop, so no attempt races its own expiry: a second
|
|
90
|
+
* before it expires, or a quarter of its window before when that is shorter.
|
|
91
|
+
*/
|
|
92
|
+
export const retryDeadline = (commandId) => {
|
|
93
|
+
const issued = lifetime(commandId);
|
|
94
|
+
if (issued === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
return issued.expiresAt - Math.min(EXPIRY_MARGIN_MS, (issued.expiresAt - issued.issuedAt) / 4);
|
|
97
|
+
};
|
|
98
|
+
const TOKEN = /^(0|[1-9]\d*)$/;
|
|
99
|
+
/**
|
|
100
|
+
* The highest `durable-version` a client has seen: a non-negative decimal
|
|
101
|
+
* string, ordered by length and then digits, never as a number.
|
|
102
|
+
*/
|
|
103
|
+
export class ConsistencyToken {
|
|
104
|
+
highest;
|
|
105
|
+
/** The highest version seen, to send as `durable-min-version`; undefined until one is seen. */
|
|
106
|
+
get value() {
|
|
107
|
+
return this.highest;
|
|
108
|
+
}
|
|
109
|
+
/** Records a response's `durable-version` header; a missing or malformed one is ignored. */
|
|
110
|
+
observe(value) {
|
|
111
|
+
if (value === null || !TOKEN.test(value))
|
|
112
|
+
return;
|
|
113
|
+
const current = this.highest;
|
|
114
|
+
if (current === undefined ||
|
|
115
|
+
value.length > current.length ||
|
|
116
|
+
(value.length === current.length && value > current))
|
|
117
|
+
this.highest = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** The most rows one fleet page returns. */
|
|
3
|
+
export declare const FLEET_PAGE_LIMIT = 1000;
|
|
4
|
+
/** The rows a fleet page returns unless the caller asks for fewer or more. */
|
|
5
|
+
export declare const FLEET_PAGE_DEFAULT = 100;
|
|
6
|
+
/** A fleet page as JSON, before its rows are typed by their view. */
|
|
7
|
+
export declare const FleetPageJson: Schema.Struct<{
|
|
8
|
+
readonly asOf: Schema.NullOr<Schema.String>;
|
|
9
|
+
readonly stale: Schema.Boolean;
|
|
10
|
+
readonly rows: Schema.$Array<Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>>;
|
|
11
|
+
}>;
|
|
12
|
+
/** A filter as the served route takes it: each value in its text form. */
|
|
13
|
+
export declare const fleetFilterText: (filter: Readonly<Record<string, string | number | boolean>>) => {
|
|
14
|
+
[k: string]: string;
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** The most rows one fleet page returns. */
|
|
3
|
+
export const FLEET_PAGE_LIMIT = 1000;
|
|
4
|
+
/** The rows a fleet page returns unless the caller asks for fewer or more. */
|
|
5
|
+
export const FLEET_PAGE_DEFAULT = 100;
|
|
6
|
+
/** A fleet page as JSON, before its rows are typed by their view. */
|
|
7
|
+
export const FleetPageJson = Schema.Struct({
|
|
8
|
+
asOf: Schema.NullOr(Schema.String),
|
|
9
|
+
stale: Schema.Boolean,
|
|
10
|
+
rows: Schema.Array(Schema.Record(Schema.String, Schema.Json)),
|
|
11
|
+
});
|
|
12
|
+
/** A filter as the served route takes it: each value in its text form. */
|
|
13
|
+
export const fleetFilterText = (filter) => Object.fromEntries(Object.entries(filter).map(([key, value]) => [key, String(value)]));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AnyFleetView, FleetFilter, FleetPage, FleetRow } from "../tables/fleet.ts";
|
|
2
|
+
import type { ClientOptions } from "./make.ts";
|
|
3
|
+
import { type WatchOptions } from "./sessions/watch.ts";
|
|
4
|
+
/** Options of one served fleet subscription. */
|
|
5
|
+
export interface FleetSubscribeOptions extends WatchOptions {
|
|
6
|
+
/** The most groups a page holds: default 100, at most 1,000. */
|
|
7
|
+
readonly limit?: number;
|
|
8
|
+
}
|
|
9
|
+
/** One served fleet view: `subscribe` follows its pages for the caller's tenant. */
|
|
10
|
+
export interface FleetViewClient<V extends AnyFleetView> {
|
|
11
|
+
readonly subscribe: (filter?: FleetFilter<V>, options?: FleetSubscribeOptions) => AsyncIterable<FleetPage<FleetRow<V>>>;
|
|
12
|
+
}
|
|
13
|
+
/** The client of served fleet views, by view name. */
|
|
14
|
+
export type FleetClient<Views extends ReadonlyArray<AnyFleetView>> = {
|
|
15
|
+
readonly [V in Views[number] as V["name"]]: FleetViewClient<V>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The Promise client of `options.views`, served by `Actor.serve({ fleet })`. Each
|
|
19
|
+
* `subscribe` is an `AsyncIterable` of pages for the tenant the server
|
|
20
|
+
* authenticates, over `GET /fleet/{View}`: the current page first, then a page
|
|
21
|
+
* whenever the view changed. A dropped connection reopens after a growing,
|
|
22
|
+
* jittered delay, and its first page is the current state. It fails with the
|
|
23
|
+
* `ActorError` that ended it when a retry cannot help, and retries an expired
|
|
24
|
+
* credential once. `options.headers` is read for every attempt.
|
|
25
|
+
*/
|
|
26
|
+
export declare const fleetClient: <const Views extends ReadonlyArray<AnyFleetView>>(options: Pick<ClientOptions, "baseUrl" | "headers" | "fetch"> & {
|
|
27
|
+
/** The views the server lists in `Actor.serve({ fleet })`. */
|
|
28
|
+
readonly views: Views;
|
|
29
|
+
}) => FleetClient<Views>;
|