@swirls/looms 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -2
- package/dist/actor/cell.d.ts +9 -4
- package/dist/actor/cell.js +7 -11
- package/dist/actor/host.d.ts +7 -3
- package/dist/actor/host.js +57 -33
- package/dist/actor/index.d.ts +1 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/routing.d.ts +12 -1
- package/dist/actor/routing.js +57 -51
- package/dist/agent/agent-session.d.ts +5 -0
- package/dist/agent/agent-session.js +270 -0
- package/dist/agent/debugger/agent-chat.d.ts +2 -0
- package/dist/agent/debugger/agent-chat.js +176 -0
- package/dist/agent/debugger/index.d.ts +5 -0
- package/dist/agent/debugger/index.js +19 -0
- package/dist/agent/debugger/summarize.d.ts +2 -0
- package/dist/agent/debugger/summarize.js +51 -0
- package/dist/agent/debugger/token-usage.d.ts +3 -0
- package/dist/agent/debugger/token-usage.js +11 -0
- package/dist/agent/definitions-store.d.ts +2 -3
- package/dist/agent/definitions-store.js +2 -4
- package/dist/agent/definitions.d.ts +47 -29
- package/dist/agent/definitions.js +39 -12
- package/dist/agent/effects.d.ts +359 -2
- package/dist/agent/effects.js +60 -34
- package/dist/agent/events.d.ts +175 -19
- package/dist/agent/events.js +45 -10
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/llm.d.ts +11 -2
- package/dist/agent/llm.js +13 -3
- package/dist/agent/module.d.ts +812 -78
- package/dist/agent/module.js +16 -4
- package/dist/agent/scope.d.ts +174 -18
- package/dist/agent/signals.d.ts +26 -1
- package/dist/agent/signals.js +79 -0
- package/dist/agent/threads.d.ts +3 -33
- package/dist/agent/threads.js +20 -25
- package/dist/agent/tool-schema.d.ts +1 -17
- package/dist/agent/tool-schema.js +3 -43
- package/dist/agent/types.d.ts +49 -4
- package/dist/agent/types.js +5 -5
- package/dist/ai-vercel/index.d.ts +1 -0
- package/dist/ai-vercel/index.js +1 -0
- package/dist/ai-vercel/messages.js +22 -7
- package/dist/ai-vercel/vercel-evaluator.d.ts +36 -0
- package/dist/ai-vercel/vercel-evaluator.js +73 -0
- package/dist/ai-vercel/vercel-llm.js +64 -44
- package/dist/approval/debugger/approvals-view.d.ts +3 -0
- package/dist/approval/debugger/approvals-view.js +16 -0
- package/dist/approval/debugger/index.d.ts +4 -0
- package/dist/approval/debugger/index.js +11 -0
- package/dist/approval/debugger/summarize.d.ts +2 -0
- package/dist/approval/debugger/summarize.js +17 -0
- package/dist/approval/effects.d.ts +89 -0
- package/dist/approval/module.d.ts +179 -29
- package/dist/approval/projections.d.ts +0 -14
- package/dist/approval/projections.js +20 -3
- package/dist/approval/signals.d.ts +2 -0
- package/dist/approval/signals.js +18 -2
- package/dist/cli/cli.js +2 -0
- package/dist/cli/commands.js +12 -16
- package/dist/client/client.d.ts +1213 -18
- package/dist/client/client.js +120 -120
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/sse.d.ts +13 -0
- package/dist/client/sse.js +38 -44
- package/dist/cloudflare/alarm-scheduler.d.ts +12 -2
- package/dist/cloudflare/alarm-scheduler.js +34 -7
- package/dist/cloudflare/durable-object.d.ts +10 -2
- package/dist/cloudflare/durable-object.js +59 -28
- package/dist/cloudflare/event-store.d.ts +7 -2
- package/dist/cloudflare/event-store.js +8 -7
- package/dist/cloudflare/index.d.ts +2 -2
- package/dist/cloudflare/index.js +2 -2
- package/dist/cloudflare/router.d.ts +1 -1
- package/dist/cloudflare/router.js +15 -16
- package/dist/core/catalog.d.ts +3 -3
- package/dist/core/catalog.js +2 -5
- package/dist/core/coalesce.js +5 -3
- package/dist/core/compose.d.ts +2 -1
- package/dist/core/compose.js +19 -2
- package/dist/core/debugger-host.d.ts +16 -0
- package/dist/core/debugger-host.js +1 -0
- package/dist/core/definition-store.d.ts +11 -0
- package/dist/core/definition-store.js +6 -0
- package/dist/core/effects.d.ts +127 -15
- package/dist/core/effects.js +89 -17
- package/dist/core/envelope.d.ts +27 -7
- package/dist/core/envelope.js +20 -6
- package/dist/core/event-codec.d.ts +4 -2
- package/dist/core/event-codec.js +10 -5
- package/dist/core/event-index.js +1 -3
- package/dist/core/fold.d.ts +3 -0
- package/dist/core/fold.js +171 -24
- package/dist/core/ids.d.ts +5 -0
- package/dist/core/ids.js +35 -2
- package/dist/core/index.d.ts +7 -1
- package/dist/core/index.js +6 -1
- package/dist/core/kind.d.ts +22 -0
- package/dist/core/kind.js +17 -0
- package/dist/core/limits.d.ts +34 -0
- package/dist/core/limits.js +46 -0
- package/dist/core/match.d.ts +1 -0
- package/dist/core/match.js +10 -1
- package/dist/core/module-scope.d.ts +22 -20
- package/dist/core/module-scope.js +38 -28
- package/dist/core/module.d.ts +18 -5
- package/dist/core/module.js +4 -0
- package/dist/core/projection.d.ts +13 -13
- package/dist/core/projection.js +9 -5
- package/dist/core/protocol.d.ts +68 -11
- package/dist/core/protocol.js +82 -11
- package/dist/core/published.d.ts +43 -0
- package/dist/core/published.js +44 -0
- package/dist/core/replay.d.ts +312 -3
- package/dist/core/replay.js +11 -1
- package/dist/core/schema.d.ts +11 -20
- package/dist/core/schema.js +63 -80
- package/dist/core/serialize.js +2 -4
- package/dist/core/snapshot-store.d.ts +6 -1
- package/dist/core/snapshot-store.js +15 -2
- package/dist/core/snapshots.d.ts +5 -1
- package/dist/core/snapshots.js +10 -15
- package/dist/core/sqlite-store.js +95 -11
- package/dist/core/state.d.ts +142 -4
- package/dist/core/state.js +78 -0
- package/dist/core/store.d.ts +38 -3
- package/dist/core/store.js +77 -22
- package/dist/core/thread.d.ts +10 -9
- package/dist/core/types.d.ts +5 -8
- package/dist/core/types.js +28 -24
- package/dist/core/validate-event.js +14 -4
- package/dist/core/worker-callback.d.ts +17 -0
- package/dist/core/worker-callback.js +1 -0
- package/dist/debugger/app/assets/index-B3Ah8WAE.css +2 -0
- package/dist/debugger/app/assets/index-Qb371t_O.js +22 -0
- package/dist/debugger/app/assets/rolldown-runtime-CbXtAM7H.js +1 -0
- package/dist/debugger/app/assets/routes-CjtEHgPQ.js +47 -0
- package/dist/debugger/app/index.html +14 -0
- package/dist/debugger/components/composer.d.ts +17 -0
- package/dist/debugger/components/composer.js +25 -0
- package/dist/debugger/components/debugger-split.d.ts +2 -1
- package/dist/debugger/components/debugger-split.js +2 -2
- package/dist/debugger/components/event-inspector.d.ts +2 -1
- package/dist/debugger/components/event-inspector.js +25 -16
- package/dist/debugger/components/event-stream.d.ts +2 -1
- package/dist/debugger/components/event-stream.js +14 -74
- package/dist/debugger/components/follow-list.d.ts +19 -0
- package/dist/debugger/components/follow-list.js +96 -0
- package/dist/debugger/components/json-tree.d.ts +11 -0
- package/dist/debugger/components/json-tree.js +120 -0
- package/dist/debugger/components/json-view.js +2 -2
- package/dist/debugger/components/run-tree.js +53 -20
- package/dist/debugger/components/status-dot.d.ts +4 -0
- package/dist/debugger/components/status-dot.js +6 -2
- package/dist/debugger/context.d.ts +14 -0
- package/dist/debugger/context.js +17 -0
- package/dist/debugger/contracts.d.ts +7 -4
- package/dist/debugger/events/builtin-families.d.ts +3 -0
- package/dist/debugger/events/builtin-families.js +9 -0
- package/dist/debugger/events/catalog.d.ts +3 -4
- package/dist/debugger/events/catalog.js +27 -17
- package/dist/debugger/events/protocol-summarize.d.ts +1 -2
- package/dist/debugger/events/protocol-summarize.js +42 -24
- package/dist/debugger/index.d.ts +20 -6
- package/dist/debugger/index.js +19 -5
- package/dist/debugger/lib/cn.d.ts +1 -0
- package/dist/debugger/lib/cn.js +3 -0
- package/dist/debugger/lib/event-meta.d.ts +2 -3
- package/dist/debugger/lib/event-meta.js +6 -12
- package/dist/debugger/lib/json.d.ts +25 -0
- package/dist/debugger/lib/json.js +87 -0
- package/dist/debugger/lib/payload.d.ts +7 -0
- package/dist/debugger/lib/payload.js +11 -0
- package/dist/debugger/lib/time.d.ts +3 -0
- package/dist/debugger/lib/time.js +24 -0
- package/dist/debugger/plugin.d.ts +36 -0
- package/dist/debugger/plugin.js +14 -0
- package/dist/debugger/server/index.d.ts +14 -0
- package/dist/debugger/server/index.js +114 -0
- package/dist/debugger/shell/debugger-shell.d.ts +15 -0
- package/dist/debugger/shell/debugger-shell.js +43 -0
- package/dist/debugger/shell/definition-key.d.ts +3 -0
- package/dist/debugger/shell/definition-key.js +4 -0
- package/dist/debugger/shell/events-pane.d.ts +12 -0
- package/dist/debugger/shell/events-pane.js +25 -0
- package/dist/debugger/shell/projections-panel.d.ts +4 -0
- package/dist/debugger/shell/projections-panel.js +59 -0
- package/dist/debugger/shell/run-controls.d.ts +4 -0
- package/dist/debugger/shell/run-controls.js +72 -0
- package/dist/debugger/shell/run-search.d.ts +6 -0
- package/dist/debugger/shell/run-search.js +102 -0
- package/dist/debugger/shell/run-type-menu.d.ts +6 -0
- package/dist/debugger/shell/run-type-menu.js +11 -0
- package/dist/debugger/shell/schema-form.d.ts +31 -0
- package/dist/debugger/shell/schema-form.js +117 -0
- package/dist/debugger/shell/start-form.d.ts +3 -0
- package/dist/debugger/shell/start-form.js +75 -0
- package/dist/debugger/shell/use-start-run.d.ts +14 -0
- package/dist/debugger/shell/use-start-run.js +32 -0
- package/dist/debugger/shell/workspace.d.ts +6 -0
- package/dist/debugger/shell/workspace.js +15 -0
- package/dist/debugger/styles.css +111 -27
- package/dist/debugger/ui/button.d.ts +24 -0
- package/dist/debugger/ui/button.js +24 -0
- package/dist/debugger/ui/command.d.ts +9 -0
- package/dist/debugger/ui/command.js +24 -0
- package/dist/debugger/ui/dropdown-menu.d.ts +13 -0
- package/dist/debugger/ui/dropdown-menu.js +37 -0
- package/dist/debugger/ui/panel.d.ts +14 -0
- package/dist/debugger/ui/panel.js +16 -0
- package/dist/debugger/ui/popover.d.ts +7 -0
- package/dist/debugger/ui/popover.js +17 -0
- package/dist/debugger/ui/resizable.d.ts +7 -0
- package/dist/debugger/ui/resizable.js +14 -0
- package/dist/debugger/ui/scroll-area.d.ts +2 -1
- package/dist/debugger/ui/scroll-area.js +5 -3
- package/dist/debugger/ui/select.d.ts +10 -0
- package/dist/debugger/ui/select.js +21 -0
- package/dist/debugger/ui/tabs.js +2 -2
- package/dist/debugger/ui/textarea.d.ts +3 -0
- package/dist/debugger/ui/textarea.js +7 -0
- package/dist/evaluator/definitions-store.d.ts +11 -0
- package/dist/evaluator/definitions-store.js +8 -0
- package/dist/evaluator/definitions.d.ts +18 -0
- package/dist/evaluator/definitions.js +4 -0
- package/dist/evaluator/effects.d.ts +226 -0
- package/dist/evaluator/effects.js +132 -0
- package/dist/evaluator/evaluator.d.ts +24 -0
- package/dist/evaluator/evaluator.js +67 -0
- package/dist/evaluator/events.d.ts +59 -0
- package/dist/evaluator/events.js +21 -0
- package/dist/evaluator/index.d.ts +11 -0
- package/dist/evaluator/index.js +11 -0
- package/dist/evaluator/module.d.ts +606 -0
- package/dist/evaluator/module.js +25 -0
- package/dist/evaluator/projections.d.ts +50 -0
- package/dist/evaluator/projections.js +20 -0
- package/dist/evaluator/scope.d.ts +59 -0
- package/dist/evaluator/scope.js +7 -0
- package/dist/evaluator/signals.d.ts +3 -0
- package/dist/evaluator/signals.js +17 -0
- package/dist/evaluator/threads.d.ts +62 -0
- package/dist/evaluator/threads.js +117 -0
- package/dist/evaluator/types.d.ts +125 -0
- package/dist/evaluator/types.js +51 -0
- package/dist/projectors/delivery.d.ts +83 -0
- package/dist/projectors/delivery.js +182 -0
- package/dist/projectors/index-model.d.ts +1 -1
- package/dist/projectors/index-model.js +4 -6
- package/dist/projectors/index.d.ts +2 -0
- package/dist/projectors/index.js +2 -0
- package/dist/projectors/memory.d.ts +1 -1
- package/dist/projectors/memory.js +10 -8
- package/dist/projectors/postgres.js +44 -58
- package/dist/projectors/projector.d.ts +17 -0
- package/dist/projectors/projector.js +26 -1
- package/dist/projectors/sqlite-delivery.d.ts +4 -0
- package/dist/projectors/sqlite-delivery.js +147 -0
- package/dist/projectors/sqlite.js +23 -23
- package/dist/projectors/with-projectors.d.ts +7 -2
- package/dist/projectors/with-projectors.js +27 -28
- package/dist/react/notify.js +11 -8
- package/dist/react/react.d.ts +2 -3
- package/dist/react/react.js +14 -30
- package/dist/react/sse.d.ts +1 -1
- package/dist/react/sse.js +1 -1
- package/dist/react/store.d.ts +3 -3
- package/dist/react/store.js +109 -119
- package/dist/runtime/cancellation.d.ts +16 -0
- package/dist/runtime/cancellation.js +129 -0
- package/dist/runtime/deadline-transition-planner.d.ts +31 -0
- package/dist/runtime/deadline-transition-planner.js +139 -0
- package/dist/runtime/dispatch-effect.d.ts +3 -2
- package/dist/runtime/dispatch-effect.js +7 -13
- package/dist/runtime/errors.d.ts +51 -0
- package/dist/runtime/errors.js +39 -0
- package/dist/runtime/{runtime-helpers.d.ts → helpers.d.ts} +24 -4
- package/dist/runtime/{runtime-helpers.js → helpers.js} +56 -19
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +3 -3
- package/dist/runtime/ingress.d.ts +15 -0
- package/dist/runtime/ingress.js +42 -0
- package/dist/runtime/local-effect-executor.d.ts +21 -0
- package/dist/runtime/local-effect-executor.js +137 -0
- package/dist/runtime/looms.d.ts +30 -4
- package/dist/runtime/looms.js +57 -37
- package/dist/runtime/observer.d.ts +45 -0
- package/dist/runtime/observer.js +11 -0
- package/dist/runtime/repository.d.ts +55 -0
- package/dist/runtime/repository.js +293 -0
- package/dist/runtime/retry-policy.d.ts +16 -0
- package/dist/runtime/retry-policy.js +29 -0
- package/dist/runtime/run-execution-context.d.ts +30 -0
- package/dist/runtime/run-execution-context.js +56 -0
- package/dist/runtime/run-start.d.ts +4 -0
- package/dist/runtime/run-start.js +44 -0
- package/dist/runtime/runtime.d.ts +6 -87
- package/dist/runtime/runtime.js +248 -470
- package/dist/runtime/server/auth.d.ts +41 -0
- package/dist/runtime/server/auth.js +45 -0
- package/dist/runtime/server/debugger-host.d.ts +11 -0
- package/dist/runtime/server/debugger-host.js +32 -0
- package/dist/runtime/server/fetch-handler.d.ts +18 -0
- package/dist/runtime/server/fetch-handler.js +62 -0
- package/dist/runtime/server/http.d.ts +38 -0
- package/dist/runtime/server/http.js +66 -0
- package/dist/runtime/server/route-table.d.ts +55 -0
- package/dist/runtime/server/route-table.js +74 -0
- package/dist/runtime/server/routes/definitions.d.ts +3 -0
- package/dist/runtime/server/routes/definitions.js +20 -0
- package/dist/runtime/server/routes/effects.d.ts +3 -0
- package/dist/runtime/server/routes/effects.js +59 -0
- package/dist/runtime/server/routes/operations.d.ts +3 -0
- package/dist/runtime/server/routes/operations.js +14 -0
- package/dist/runtime/server/routes/runs.d.ts +3 -0
- package/dist/runtime/server/routes/runs.js +199 -0
- package/dist/runtime/server.d.ts +4 -8
- package/dist/runtime/server.js +6 -211
- package/dist/runtime/sse.d.ts +2 -1
- package/dist/runtime/sse.js +24 -17
- package/dist/runtime/types.d.ts +117 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/wake-engine.d.ts +20 -0
- package/dist/runtime/wake-engine.js +311 -0
- package/dist/runtime/wake-scheduler.d.ts +3 -4
- package/dist/runtime/wake-scheduler.js +25 -31
- package/dist/runtime/worker-callbacks.d.ts +16 -0
- package/dist/runtime/worker-callbacks.js +167 -0
- package/dist/runtime/worker-effect-dispatch.d.ts +36 -0
- package/dist/runtime/worker-effect-dispatch.js +126 -0
- package/dist/s2/config.d.ts +1 -1
- package/dist/s2/config.js +1 -1
- package/dist/s2/lite.js +70 -82
- package/dist/s2/pagination.d.ts +15 -0
- package/dist/s2/pagination.js +36 -0
- package/dist/s2/projector.js +6 -5
- package/dist/s2/snapshot-store.js +188 -161
- package/dist/s2/store.d.ts +3 -21
- package/dist/s2/store.js +71 -165
- package/dist/testing/index.d.ts +15 -0
- package/dist/testing/index.js +53 -16
- package/dist/workflow/debugger/index.d.ts +4 -0
- package/dist/workflow/debugger/index.js +11 -0
- package/dist/workflow/debugger/nodes-view.d.ts +3 -0
- package/dist/workflow/debugger/nodes-view.js +13 -0
- package/dist/workflow/debugger/summarize.d.ts +2 -0
- package/dist/workflow/debugger/summarize.js +30 -0
- package/dist/workflow/definitions-store.d.ts +2 -3
- package/dist/workflow/definitions-store.js +2 -2
- package/dist/workflow/definitions.d.ts +78 -22
- package/dist/workflow/definitions.js +80 -14
- package/dist/workflow/effects.d.ts +453 -107
- package/dist/workflow/effects.js +214 -115
- package/dist/workflow/events.d.ts +149 -5
- package/dist/workflow/events.js +27 -5
- package/dist/workflow/graph.d.ts +56 -0
- package/dist/workflow/graph.js +207 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +1 -0
- package/dist/workflow/module.d.ts +1047 -266
- package/dist/workflow/projections.d.ts +14 -12
- package/dist/workflow/projections.js +30 -8
- package/dist/workflow/scope.d.ts +146 -4
- package/dist/workflow/threads.d.ts +383 -155
- package/dist/workflow/threads.js +308 -110
- package/package.json +26 -2
- package/dist/debugger/events/domain-summarize.d.ts +0 -3
- package/dist/debugger/events/domain-summarize.js +0 -107
- package/dist/debugger/events/family.d.ts +0 -8
- package/dist/debugger/events/family.js +0 -44
- package/dist/runtime/events-api.d.ts +0 -4
- package/dist/runtime/events-api.js +0 -84
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Effect
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
2
|
import { asJson, isPrimitiveEffect, isWaitOnTimer, } from '@swirls/looms/core';
|
|
3
|
-
import { threadStartedEvents } from './
|
|
3
|
+
import { threadStartedEvents } from './helpers.js';
|
|
4
4
|
export function dispatchEffect(registry, services, definitions, effect, ctx) {
|
|
5
5
|
const currentThreadId = ctx.threadId;
|
|
6
6
|
const baseDispatch = (eff, effCtx) => {
|
|
@@ -11,6 +11,7 @@ export function dispatchEffect(registry, services, definitions, effect, ctx) {
|
|
|
11
11
|
return threadStartedEvents(definitions, {
|
|
12
12
|
kind: eff.kind,
|
|
13
13
|
definitionName: eff.definitionName,
|
|
14
|
+
definitionVersion: eff.definitionVersion,
|
|
14
15
|
input: eff.input,
|
|
15
16
|
threadId: childThreadId,
|
|
16
17
|
parentThreadId: currentThreadId,
|
|
@@ -83,17 +84,10 @@ export function dispatchEffect(registry, services, definitions, effect, ctx) {
|
|
|
83
84
|
]);
|
|
84
85
|
}
|
|
85
86
|
const input = 'input' in eff ? eff.input : {};
|
|
86
|
-
|
|
87
|
-
.
|
|
88
|
-
.pipe(Effect.provide(
|
|
89
|
-
|
|
90
|
-
const retryPolicy = handler.retry;
|
|
91
|
-
const backoff = retryPolicy.backoffMs ?? 100;
|
|
92
|
-
execution = execution.pipe(Effect.retry({
|
|
93
|
-
times: retryPolicy.maxAttempts - 1,
|
|
94
|
-
schedule: Schedule.spaced(backoff),
|
|
95
|
-
}));
|
|
96
|
-
}
|
|
87
|
+
const execution = Effect.gen(function* () {
|
|
88
|
+
const serviceContext = yield* services.contextEffect;
|
|
89
|
+
return yield* handler.execute(input, effCtx).pipe(Effect.provide(serviceContext));
|
|
90
|
+
});
|
|
97
91
|
return execution.pipe(Effect.catch((err) => Effect.succeed([
|
|
98
92
|
{
|
|
99
93
|
type: 'runtime.effect.failed',
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { JsonValue, RunStartIdentity as DurableRunStartIdentity } from '@swirls/looms/core';
|
|
2
|
+
export interface RunStartIdentity {
|
|
3
|
+
readonly kind: string;
|
|
4
|
+
readonly definitionName: string;
|
|
5
|
+
readonly definitionVersion: string;
|
|
6
|
+
readonly input: JsonValue;
|
|
7
|
+
readonly requestedThreadId: string | null;
|
|
8
|
+
readonly idempotencyKey: string | null;
|
|
9
|
+
}
|
|
10
|
+
declare const StartRunConflictError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
11
|
+
readonly _tag: "StartRunConflictError";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
export declare class StartRunConflictError extends StartRunConflictError_base<{
|
|
14
|
+
readonly runId: string;
|
|
15
|
+
readonly requested: RunStartIdentity;
|
|
16
|
+
readonly existing: DurableRunStartIdentity;
|
|
17
|
+
readonly mismatches: readonly (keyof RunStartIdentity)[];
|
|
18
|
+
readonly message: string;
|
|
19
|
+
}> {
|
|
20
|
+
constructor(runId: string, requested: RunStartIdentity, existing: DurableRunStartIdentity, mismatches: readonly (keyof RunStartIdentity)[]);
|
|
21
|
+
}
|
|
22
|
+
declare const DuplicateEffectDispatchError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
23
|
+
readonly _tag: "DuplicateEffectDispatchError";
|
|
24
|
+
} & Readonly<A>;
|
|
25
|
+
export declare class DuplicateEffectDispatchError extends DuplicateEffectDispatchError_base<{
|
|
26
|
+
readonly runId: string;
|
|
27
|
+
readonly effectId: string;
|
|
28
|
+
readonly threadId: string;
|
|
29
|
+
readonly message: string;
|
|
30
|
+
}> {
|
|
31
|
+
constructor(runId: string, effectId: string, threadId: string);
|
|
32
|
+
}
|
|
33
|
+
declare const MaxWakeIterationsError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
34
|
+
readonly _tag: "MaxWakeIterationsError";
|
|
35
|
+
} & Readonly<A>;
|
|
36
|
+
export declare class MaxWakeIterationsError extends MaxWakeIterationsError_base<{
|
|
37
|
+
readonly runId: string;
|
|
38
|
+
readonly maxIterations: number;
|
|
39
|
+
readonly message: string;
|
|
40
|
+
}> {
|
|
41
|
+
constructor(runId: string, maxIterations: number);
|
|
42
|
+
}
|
|
43
|
+
declare const RuntimeExecutionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
44
|
+
readonly _tag: "RuntimeExecutionError";
|
|
45
|
+
} & Readonly<A>;
|
|
46
|
+
export declare class RuntimeExecutionError extends RuntimeExecutionError_base<{
|
|
47
|
+
readonly message: string;
|
|
48
|
+
}> {
|
|
49
|
+
constructor(message: string);
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Data } from 'effect';
|
|
2
|
+
export class StartRunConflictError extends Data.TaggedError('StartRunConflictError') {
|
|
3
|
+
constructor(runId, requested, existing, mismatches) {
|
|
4
|
+
super({
|
|
5
|
+
runId,
|
|
6
|
+
requested,
|
|
7
|
+
existing,
|
|
8
|
+
mismatches,
|
|
9
|
+
message: `Run "${runId}" already has a different durable start (${mismatches.join(', ')})`,
|
|
10
|
+
});
|
|
11
|
+
this.name = 'StartRunConflictError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class DuplicateEffectDispatchError extends Data.TaggedError('DuplicateEffectDispatchError') {
|
|
15
|
+
constructor(runId, effectId, threadId) {
|
|
16
|
+
super({
|
|
17
|
+
runId,
|
|
18
|
+
effectId,
|
|
19
|
+
threadId,
|
|
20
|
+
message: `Duplicate effect dispatch detected for effectId "${effectId}" on thread "${threadId}"; refusing to re-dispatch already executed effect`,
|
|
21
|
+
});
|
|
22
|
+
this.name = 'DuplicateEffectDispatchError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class MaxWakeIterationsError extends Data.TaggedError('MaxWakeIterationsError') {
|
|
26
|
+
constructor(runId, maxIterations) {
|
|
27
|
+
super({
|
|
28
|
+
runId,
|
|
29
|
+
maxIterations,
|
|
30
|
+
message: `Max wake iterations exceeded (${maxIterations}) for run "${runId}"; possible infinite loop`,
|
|
31
|
+
});
|
|
32
|
+
this.name = 'MaxWakeIterationsError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class RuntimeExecutionError extends Data.TaggedError('RuntimeExecutionError') {
|
|
36
|
+
constructor(message) {
|
|
37
|
+
super({ message });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import { Effect, Layer } from 'effect';
|
|
2
|
-
import { type AnyRuntimeModule, type AppendableEvent, type EventCatalog, type EventEnvelope, type EventInput, type EventOrigin, type EventStore,
|
|
1
|
+
import { Effect, Layer, type Context } from 'effect';
|
|
2
|
+
import { type AnyRuntimeModule, type AppendableEvent, type EventCatalog, type EventEnvelope, type EventInput, type EventOrigin, type EventStore, InvalidEventError, type JsonValue, type OutstandingEffect, type RegisteredDefinition, type RunCursor, type RunState, type SnapshotStore } from '@swirls/looms/core';
|
|
3
|
+
import type { EffectWorkerTask } from './types';
|
|
4
|
+
export declare function workerTask(runId: string, item: OutstandingEffect, attempt: number): EffectWorkerTask;
|
|
5
|
+
declare const UnknownDefinitionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
6
|
+
readonly _tag: "UnknownDefinitionError";
|
|
7
|
+
} & Readonly<A>;
|
|
8
|
+
export declare class UnknownDefinitionError extends UnknownDefinitionError_base<{
|
|
9
|
+
readonly kind: string;
|
|
10
|
+
readonly definitionName: string;
|
|
11
|
+
readonly definitionVersion: string;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}> {
|
|
14
|
+
constructor(kind: string, definitionName: string, definitionVersion: string);
|
|
15
|
+
}
|
|
3
16
|
export declare function resolveSnapshotStore(explicit: SnapshotStore | undefined, store: EventStore | undefined): SnapshotStore;
|
|
4
17
|
export declare class RunCursorCache {
|
|
5
18
|
private readonly max;
|
|
@@ -10,7 +23,7 @@ export declare class RunCursorCache {
|
|
|
10
23
|
delete(runId: string): void;
|
|
11
24
|
}
|
|
12
25
|
export declare function stripSeq(events: ReadonlyArray<EventEnvelope>): AppendableEvent[];
|
|
13
|
-
export declare function moduleServices(modules: readonly AnyRuntimeModule[]): Layer.Layer<
|
|
26
|
+
export declare function moduleServices(modules: readonly AnyRuntimeModule[]): Layer.Layer<Context.Service.Any>;
|
|
14
27
|
export declare function groupOutstanding(items: readonly {
|
|
15
28
|
threadId: string;
|
|
16
29
|
causingSeq: number;
|
|
@@ -24,10 +37,11 @@ export declare function groupOutstanding(items: readonly {
|
|
|
24
37
|
export declare function threadStartedEvents(definitions: ReadonlyMap<string, RegisteredDefinition>, args: {
|
|
25
38
|
kind: string;
|
|
26
39
|
definitionName: string;
|
|
40
|
+
definitionVersion: string;
|
|
27
41
|
input: JsonValue;
|
|
28
42
|
threadId: string;
|
|
29
43
|
parentThreadId: string | null;
|
|
30
|
-
}): Effect.Effect<ReadonlyArray<EventInput>,
|
|
44
|
+
}): Effect.Effect<ReadonlyArray<EventInput>, UnknownDefinitionError>;
|
|
31
45
|
export declare function synthesizedThreadFailed(before: RunState, after: RunState, written: readonly EventEnvelope[]): EventInput[];
|
|
32
46
|
export declare function waitSatisfiedEvents(state: RunState, events: readonly EventEnvelope[]): EventInput[];
|
|
33
47
|
export declare function createEffectFailedEvent(runId: string, item: {
|
|
@@ -45,7 +59,13 @@ export declare function createLiveEvent(runId: string, item: {
|
|
|
45
59
|
causingEventId: string;
|
|
46
60
|
threadId: string;
|
|
47
61
|
}, validated: EventInput): AppendableEvent | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Admit events from an external caller. Runtime protocol events are reserved for the runtime
|
|
64
|
+
* itself, and external events can never claim an effect outcome or a non-external origin.
|
|
65
|
+
*/
|
|
66
|
+
export declare function admitExternalEvents(events: readonly EventInput[]): Effect.Effect<EventInput[], InvalidEventError>;
|
|
48
67
|
export declare function validateAndCreateEvents(catalogs: readonly EventCatalog[], runId: string, events: readonly EventInput[], defaults: {
|
|
49
68
|
origin: EventOrigin;
|
|
50
69
|
threadId?: string | null;
|
|
51
70
|
}): Effect.Effect<EventEnvelope[], InvalidEventError>;
|
|
71
|
+
export {};
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
import { Effect, Layer, Predicate } from 'effect';
|
|
2
|
-
import { asJson, createEvent, makeMemorySnapshotStore, matchingWaits, snapshotStoreOf, validateEventInput, validateEventsEffect,
|
|
1
|
+
import { Data, Effect, Layer, Predicate } from 'effect';
|
|
2
|
+
import { asJson, createEvent, definitionKey, makeMemorySnapshotStore, matchingWaits, snapshotStoreOf, validateEventInput, validateEventsEffect, validateInputEffect, withSnapshotStore, InvalidEventError, } from '@swirls/looms/core';
|
|
3
|
+
export function workerTask(runId, item, attempt) {
|
|
4
|
+
return {
|
|
5
|
+
runId,
|
|
6
|
+
effectId: item.effectId,
|
|
7
|
+
attempt,
|
|
8
|
+
type: item.effect.type,
|
|
9
|
+
input: 'input' in item.effect ? item.effect.input : null,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export class UnknownDefinitionError extends Data.TaggedError('UnknownDefinitionError') {
|
|
13
|
+
constructor(kind, definitionName, definitionVersion) {
|
|
14
|
+
super({
|
|
15
|
+
kind,
|
|
16
|
+
definitionName,
|
|
17
|
+
definitionVersion,
|
|
18
|
+
message: `Unknown definition ${definitionKey(kind, definitionName, definitionVersion)}`,
|
|
19
|
+
});
|
|
20
|
+
this.name = 'UnknownDefinitionError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
3
23
|
export function resolveSnapshotStore(explicit, store) {
|
|
4
24
|
if (explicit) {
|
|
5
25
|
if (store) {
|
|
@@ -52,15 +72,17 @@ export class RunCursorCache {
|
|
|
52
72
|
export function stripSeq(events) {
|
|
53
73
|
return events.map(({ seq: _seq, ...rest }) => rest);
|
|
54
74
|
}
|
|
75
|
+
// Heterogeneous module service identifiers are intentionally erased after composition.
|
|
76
|
+
// oxlint-disable-next-line effecttsgo/any-unknown-in-error-context
|
|
55
77
|
export function moduleServices(modules) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
const layers = modules.flatMap((module) => (module.services ? [module.services()] : []));
|
|
79
|
+
const [first, ...rest] = layers;
|
|
80
|
+
if (!first) {
|
|
81
|
+
// SAFETY: An empty service set satisfies the erased registry boundary.
|
|
82
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
83
|
+
return Layer.empty;
|
|
62
84
|
}
|
|
63
|
-
return merged;
|
|
85
|
+
return rest.reduce((merged, layer) => Layer.merge(merged, layer), first);
|
|
64
86
|
}
|
|
65
87
|
export function groupOutstanding(items) {
|
|
66
88
|
const keys = [];
|
|
@@ -83,21 +105,18 @@ export function groupOutstanding(items) {
|
|
|
83
105
|
*/
|
|
84
106
|
export function threadStartedEvents(definitions, args) {
|
|
85
107
|
return Effect.gen(function* () {
|
|
86
|
-
const def = definitions.get(
|
|
108
|
+
const def = definitions.get(definitionKey(args.kind, args.definitionName, args.definitionVersion));
|
|
87
109
|
if (!def) {
|
|
88
|
-
return yield*
|
|
110
|
+
return yield* new UnknownDefinitionError(args.kind, args.definitionName, args.definitionVersion);
|
|
89
111
|
}
|
|
90
112
|
const raw = args.input ?? null;
|
|
91
113
|
let startedInput = raw;
|
|
92
114
|
let validationError;
|
|
93
115
|
if (def?.input) {
|
|
94
|
-
const validated = yield* Effect.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
catch: (err) => (err instanceof Error ? err : new Error(String(err))),
|
|
100
|
-
}).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })));
|
|
116
|
+
const validated = yield* validateInputEffect(def.input, raw).pipe(Effect.match({
|
|
117
|
+
onFailure: (error) => ({ ok: false, error: error.message }),
|
|
118
|
+
onSuccess: (value) => ({ ok: true, value }),
|
|
119
|
+
}));
|
|
101
120
|
if (validated.ok) {
|
|
102
121
|
startedInput = validated.value;
|
|
103
122
|
}
|
|
@@ -111,6 +130,7 @@ export function threadStartedEvents(definitions, args) {
|
|
|
111
130
|
threadId: args.threadId,
|
|
112
131
|
kind: args.kind,
|
|
113
132
|
definitionName: args.definitionName,
|
|
133
|
+
definitionVersion: args.definitionVersion,
|
|
114
134
|
input: startedInput,
|
|
115
135
|
parentThreadId: args.parentThreadId,
|
|
116
136
|
},
|
|
@@ -215,12 +235,29 @@ export function createLiveEvent(runId, item, validated) {
|
|
|
215
235
|
effectId: item.effectId,
|
|
216
236
|
causationId: item.causingEventId,
|
|
217
237
|
threadId: targetThreadId,
|
|
218
|
-
ephemeral:
|
|
238
|
+
ephemeral: true,
|
|
219
239
|
origin: validated.origin ?? { type: 'thread', threadId: item.threadId },
|
|
220
240
|
});
|
|
221
241
|
const [liveEvent] = stripSeq([ephemeral]);
|
|
222
242
|
return liveEvent;
|
|
223
243
|
}
|
|
244
|
+
const EXTERNAL_RUNTIME_EVENT_TYPES = new Set([
|
|
245
|
+
'runtime.signal.received',
|
|
246
|
+
'runtime.thread.cancel.requested',
|
|
247
|
+
]);
|
|
248
|
+
/**
|
|
249
|
+
* Admit events from an external caller. Runtime protocol events are reserved for the runtime
|
|
250
|
+
* itself, and external events can never claim an effect outcome or a non-external origin.
|
|
251
|
+
*/
|
|
252
|
+
export function admitExternalEvents(events) {
|
|
253
|
+
return Effect.forEach(events, (input) => input.type.startsWith('runtime.') && !EXTERNAL_RUNTIME_EVENT_TYPES.has(input.type)
|
|
254
|
+
? Effect.fail(new InvalidEventError(input.type, `Event type "${input.type}" is reserved for the runtime`))
|
|
255
|
+
: Effect.succeed({
|
|
256
|
+
...input,
|
|
257
|
+
effectId: null,
|
|
258
|
+
origin: input.origin?.type === 'external' ? input.origin : { type: 'external' },
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
224
261
|
export function validateAndCreateEvents(catalogs, runId, events, defaults) {
|
|
225
262
|
return validateEventsEffect(catalogs, events).pipe(Effect.map((validated) => validated.map((input) => createEvent(runId, {
|
|
226
263
|
...input,
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, type CreateRuntimeOptions, type LoomsRuntime, type RegisteredDefinition, type StartRunArgs, type WakeError, type WakeScheduler, } from './runtime';
|
|
1
|
+
export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, RunOverloadedError, StartRunConflictError, type CreateRuntimeOptions, type EffectWorker, type EffectWorkerTask, type LoomsRuntime, type RunOperationalStatus, type RegisteredDefinition, type StartRunArgs, type WakeError, type WakeScheduler, type WorkerCallback, type WorkerCallbackInput, } from './runtime';
|
|
2
2
|
export { createLooms, type Looms, type CreateLoomsOptions, type StartResult } from './looms';
|
|
3
|
-
export { serveHttp, createFetchHandler, isLoomsApiPath, type FetchHandlerOptions, type RunningServer, type LoomsFetchResult, } from './server';
|
|
4
|
-
export { handleEventsApi, encodeLoomsEvent, type EncodedLoomsEvent } from './events-api';
|
|
3
|
+
export { serveHttp, createFetchHandler, isLoomsApiPath, type FetchHandlerOptions, authAllowed, authDenied, bearerAuth, defaultAuthorize, type AuthDecision, type AuthorizedAccess, type Authorize, type BearerTokens, type RouteAccess, type RouteInfo, type RunningServer, type LoomsFetchResult, } from './server';
|
|
5
4
|
export { createEventStreamResponse, type EventStreamOptions } from './sse';
|
|
5
|
+
export { notifyObserver, type RuntimeObservation, type RuntimeObserver } from './observer';
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, } from './runtime.js';
|
|
1
|
+
export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, RunOverloadedError, StartRunConflictError, } from './runtime.js';
|
|
2
2
|
export { createLooms } from './looms.js';
|
|
3
|
-
export { serveHttp, createFetchHandler, isLoomsApiPath, } from './server.js';
|
|
4
|
-
export { handleEventsApi, encodeLoomsEvent } from './events-api.js';
|
|
3
|
+
export { serveHttp, createFetchHandler, isLoomsApiPath, authAllowed, authDenied, bearerAuth, defaultAuthorize, } from './server.js';
|
|
5
4
|
export { createEventStreamResponse } from './sse.js';
|
|
5
|
+
export { notifyObserver } from './observer.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import type { RunExecutionContexts } from './run-execution-context';
|
|
3
|
+
declare const RunOverloadedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
4
|
+
readonly _tag: "RunOverloadedError";
|
|
5
|
+
} & Readonly<A>;
|
|
6
|
+
export declare class RunOverloadedError extends RunOverloadedError_base<{
|
|
7
|
+
readonly runId: string;
|
|
8
|
+
readonly limit: number;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
}> {
|
|
11
|
+
constructor(runId: string, limit: number);
|
|
12
|
+
}
|
|
13
|
+
export type RunIngress = <A, E, R>(runId: string, operation: Effect.Effect<A, E, R>) => Effect.Effect<A, E | RunOverloadedError, R>;
|
|
14
|
+
export declare function createRunIngress(executionContexts: RunExecutionContexts, maxPendingRunOperations: number): RunIngress;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Data, Effect } from 'effect';
|
|
2
|
+
export class RunOverloadedError extends Data.TaggedError('RunOverloadedError') {
|
|
3
|
+
constructor(runId, limit) {
|
|
4
|
+
super({
|
|
5
|
+
runId,
|
|
6
|
+
limit,
|
|
7
|
+
message: `Run "${runId}" has reached its pending operation limit (${limit})`,
|
|
8
|
+
});
|
|
9
|
+
this.name = 'RunOverloadedError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function createRunIngress(executionContexts, maxPendingRunOperations) {
|
|
13
|
+
return (runId, operation) => Effect.suspend(() => {
|
|
14
|
+
const context = executionContexts.get(runId);
|
|
15
|
+
const current = context.ingress ?? { pending: 0, tail: Promise.resolve() };
|
|
16
|
+
if (current.pending >= maxPendingRunOperations) {
|
|
17
|
+
return Effect.fail(new RunOverloadedError(runId, maxPendingRunOperations));
|
|
18
|
+
}
|
|
19
|
+
let release;
|
|
20
|
+
// Promise chaining is the admission queue; the workload itself remains an Effect.
|
|
21
|
+
// oxlint-disable-next-line effecttsgo/new-promise
|
|
22
|
+
const own = new Promise((resolve) => {
|
|
23
|
+
release = resolve;
|
|
24
|
+
});
|
|
25
|
+
const previous = current.tail;
|
|
26
|
+
context.ingress = { pending: current.pending + 1, tail: own };
|
|
27
|
+
return Effect.promise(() => previous).pipe(Effect.andThen(operation), Effect.ensuring(Effect.sync(() => {
|
|
28
|
+
release();
|
|
29
|
+
const latest = context.ingress;
|
|
30
|
+
if (!latest) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (latest.pending <= 1) {
|
|
34
|
+
context.ingress = null;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
context.ingress = { ...latest, pending: latest.pending - 1 };
|
|
38
|
+
}
|
|
39
|
+
executionContexts.releaseIfIdle(runId);
|
|
40
|
+
})));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect, type Context, type ManagedRuntime } from 'effect';
|
|
2
|
+
import { type ComposedRegistry, type EventEnvelope, type OutstandingEffect, type RegisteredDefinition } from '@swirls/looms/core';
|
|
3
|
+
import type { RuntimeObserver } from './observer';
|
|
4
|
+
import type { RuntimeRepository } from './repository';
|
|
5
|
+
import type { RunExecutionContext } from './run-execution-context';
|
|
6
|
+
export interface LocalEffectExecutorOptions {
|
|
7
|
+
readonly registry: ComposedRegistry;
|
|
8
|
+
readonly services: ManagedRuntime.ManagedRuntime<Context.Service.Any, never>;
|
|
9
|
+
readonly definitions: ReadonlyMap<string, RegisteredDefinition>;
|
|
10
|
+
readonly executionContext: RunExecutionContext;
|
|
11
|
+
readonly liveAppends: RuntimeRepository['liveAppends'];
|
|
12
|
+
readonly runInContext: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>;
|
|
13
|
+
readonly observe: (event: Parameters<RuntimeObserver['observe']>[0]) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface ExecuteLocalEffectsInput {
|
|
16
|
+
readonly runId: string;
|
|
17
|
+
readonly outstanding: ReadonlyArray<OutstandingEffect>;
|
|
18
|
+
readonly attempts: ReadonlyMap<string, number>;
|
|
19
|
+
readonly now: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function executeLocalEffects(options: LocalEffectExecutorOptions, input: ExecuteLocalEffectsInput): Effect.Effect<ReadonlyArray<EventEnvelope>, Error>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Effect, Option, Predicate } from 'effect';
|
|
2
|
+
import { createEvent, validateEventInput, withdrawnError, } from '@swirls/looms/core';
|
|
3
|
+
import { dispatchEffect } from './dispatch-effect.js';
|
|
4
|
+
import { RuntimeExecutionError } from './errors.js';
|
|
5
|
+
import { createEffectFailedEvent, createLiveEvent, groupOutstanding, materializeEffectOutcome, } from './helpers.js';
|
|
6
|
+
import { planAttemptFailure } from './retry-policy.js';
|
|
7
|
+
function makeAbortController() {
|
|
8
|
+
return new AbortController();
|
|
9
|
+
}
|
|
10
|
+
/** Completes when the signal aborts, so racing it interrupts a handler that ignores the signal. */
|
|
11
|
+
function abortion(signal) {
|
|
12
|
+
return Effect.callback((resume) => {
|
|
13
|
+
const onAbort = () => resume(Effect.succeed({ _tag: 'aborted' }));
|
|
14
|
+
if (signal.aborted) {
|
|
15
|
+
onAbort();
|
|
16
|
+
return Effect.void;
|
|
17
|
+
}
|
|
18
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
19
|
+
return Effect.sync(() => signal.removeEventListener('abort', onAbort));
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function executeLocalEffects(options, input) {
|
|
23
|
+
const { registry, services, definitions, executionContext, liveAppends, runInContext, observe } = options;
|
|
24
|
+
return Effect.forEach(groupOutstanding(input.outstanding), (groupKey) => Effect.gen(function* () {
|
|
25
|
+
const group = input.outstanding.filter((item) => `${item.threadId}:${item.causingSeq}` === groupKey);
|
|
26
|
+
const produced = [];
|
|
27
|
+
let failedEffectId;
|
|
28
|
+
for (const item of group) {
|
|
29
|
+
if (failedEffectId && item.effect.type === 'runtime.wait') {
|
|
30
|
+
produced.push(createEffectFailedEvent(input.runId, item, withdrawnError(failedEffectId)));
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const appendLive = (eventInput) => runInContext(Effect.gen(function* () {
|
|
34
|
+
const validated = yield* validateEventInput(registry.catalogs, eventInput);
|
|
35
|
+
const liveEvent = createLiveEvent(input.runId, item, validated);
|
|
36
|
+
if (liveEvent) {
|
|
37
|
+
yield* liveAppends.push(input.runId, liveEvent);
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
const controller = makeAbortController();
|
|
41
|
+
executionContext.activeEffects.set(item.effectId, {
|
|
42
|
+
controller,
|
|
43
|
+
threadId: item.threadId,
|
|
44
|
+
});
|
|
45
|
+
const retry = registry.effects.get(item.effect.type)?.retry;
|
|
46
|
+
const dispatched = dispatchEffect(registry, services, definitions, item.effect, {
|
|
47
|
+
effectId: item.effectId,
|
|
48
|
+
runId: input.runId,
|
|
49
|
+
threadId: item.threadId,
|
|
50
|
+
causingEventId: item.causingEventId,
|
|
51
|
+
signal: controller.signal,
|
|
52
|
+
emit: appendLive,
|
|
53
|
+
}).pipe(Effect.map((outcomes) => ({ _tag: 'completed', outcomes })), Effect.raceFirst(abortion(controller.signal)));
|
|
54
|
+
const settled = yield* (retry?.startToCloseTimeoutMs
|
|
55
|
+
? dispatched.pipe(Effect.timeoutOption(retry.startToCloseTimeoutMs), Effect.map(Option.getOrElse(() => ({ _tag: 'timed-out' }))))
|
|
56
|
+
: dispatched).pipe(Effect.ensuring(Effect.sync(() => {
|
|
57
|
+
executionContext.activeEffects.delete(item.effectId);
|
|
58
|
+
})));
|
|
59
|
+
if (settled._tag === 'aborted') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const before = produced.length;
|
|
63
|
+
if (settled._tag === 'timed-out') {
|
|
64
|
+
controller.abort(new RuntimeExecutionError('start-to-close timeout'));
|
|
65
|
+
const attemptNumber = input.attempts.get(item.effectId) ?? 1;
|
|
66
|
+
observe({
|
|
67
|
+
type: 'effect.timeout',
|
|
68
|
+
runId: input.runId,
|
|
69
|
+
at: input.now,
|
|
70
|
+
effectId: item.effectId,
|
|
71
|
+
attempt: attemptNumber,
|
|
72
|
+
detail: 'start-to-close',
|
|
73
|
+
});
|
|
74
|
+
produced.push(createEvent(input.runId, {
|
|
75
|
+
type: 'runtime.effect.timed_out',
|
|
76
|
+
payload: {
|
|
77
|
+
effectId: item.effectId,
|
|
78
|
+
attempt: attemptNumber,
|
|
79
|
+
timeout: 'start-to-close',
|
|
80
|
+
},
|
|
81
|
+
threadId: item.threadId,
|
|
82
|
+
causationId: item.causingEventId,
|
|
83
|
+
origin: { type: 'system' },
|
|
84
|
+
}), planAttemptFailure({
|
|
85
|
+
runId: input.runId,
|
|
86
|
+
item,
|
|
87
|
+
attempt: attemptNumber,
|
|
88
|
+
error: 'start-to-close timeout',
|
|
89
|
+
now: input.now,
|
|
90
|
+
retry,
|
|
91
|
+
origin: { type: 'system' },
|
|
92
|
+
}).event);
|
|
93
|
+
failedEffectId = item.effectId;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const { outcomes } = settled;
|
|
97
|
+
if (outcomes.length === 0) {
|
|
98
|
+
produced.push(createEffectFailedEvent(input.runId, item, 'empty-outcome'));
|
|
99
|
+
}
|
|
100
|
+
for (const outcome of outcomes) {
|
|
101
|
+
if (outcome.type === 'runtime.effect.failed') {
|
|
102
|
+
const attempt = input.attempts.get(item.effectId) ?? 1;
|
|
103
|
+
const payload = Predicate.isObject(outcome.payload) ? outcome.payload : {};
|
|
104
|
+
const error = Predicate.isString(payload.error) ? payload.error : 'effect failed';
|
|
105
|
+
const failure = planAttemptFailure({
|
|
106
|
+
runId: input.runId,
|
|
107
|
+
item,
|
|
108
|
+
attempt,
|
|
109
|
+
error,
|
|
110
|
+
now: input.now,
|
|
111
|
+
retry,
|
|
112
|
+
origin: { type: 'system' },
|
|
113
|
+
});
|
|
114
|
+
if (failure.retrying) {
|
|
115
|
+
observe({
|
|
116
|
+
type: 'effect.retry',
|
|
117
|
+
runId: input.runId,
|
|
118
|
+
at: input.now,
|
|
119
|
+
effectId: item.effectId,
|
|
120
|
+
attempt,
|
|
121
|
+
detail: error,
|
|
122
|
+
});
|
|
123
|
+
produced.push(failure.event);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
produced.push(yield* materializeEffectOutcome(registry.catalogs, input.runId, item, outcome));
|
|
128
|
+
}
|
|
129
|
+
const itemOutcomes = produced.slice(before);
|
|
130
|
+
if (item.effect.type !== 'runtime.wait' &&
|
|
131
|
+
itemOutcomes.some((event) => event.type === 'runtime.effect.failed')) {
|
|
132
|
+
failedEffectId = item.effectId;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return produced;
|
|
136
|
+
}), { concurrency: 'unbounded' }).pipe(Effect.map((groups) => groups.flat()));
|
|
137
|
+
}
|
package/dist/runtime/looms.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type AnyRuntimeModule, type DefinitionInput, type DefinitionRef, type EventEnvelope, type EventInput, type EventStore, type JsonValue, type SnapshotStore, type ProjectionDefinition, type ReplayStep, type RunState } from '@swirls/looms/core';
|
|
2
|
-
import
|
|
3
|
-
import { type
|
|
1
|
+
import { type AnyRuntimeModule, type DebuggerHost, type DefinitionInput, type DefinitionRef, type EventEnvelope, type EventInput, type EventStore, type EventStoreTrimCoverage, type JsonValue, type SnapshotStore, type ProjectionDefinition, type ReplayStep, type RunState } from '@swirls/looms/core';
|
|
2
|
+
import type { RuntimeObserver } from './observer';
|
|
3
|
+
import { type EffectWorker, type LoomsRuntime, type RunOperationalStatus, type WakeScheduler, type WorkerCallbackInput } from './runtime';
|
|
4
|
+
import { type Authorize, type RunningServer } from './server';
|
|
4
5
|
export interface CreateLoomsOptions {
|
|
5
6
|
/** Runtime modules to enable. Pass `agent()`, `workflow()`, `approval()`, and/or your own. */
|
|
6
7
|
readonly modules?: readonly AnyRuntimeModule[];
|
|
@@ -10,19 +11,38 @@ export interface CreateLoomsOptions {
|
|
|
10
11
|
hostname?: string;
|
|
11
12
|
};
|
|
12
13
|
readonly maxWakeIterations?: number;
|
|
14
|
+
/** Maximum active and queued mutation operations per run. Default 256. */
|
|
15
|
+
readonly maxPendingRunOperations?: number;
|
|
13
16
|
/** Durable events between mid-wake snapshots. Default 200; `0` disables. Parking always snapshots. */
|
|
14
17
|
readonly snapshotEvery?: number;
|
|
15
18
|
/** Defaults to the EventStore's attached store (S2) or an in-memory SnapshotStore. */
|
|
16
19
|
readonly snapshotStore?: SnapshotStore;
|
|
17
20
|
readonly trimAfterSnapshot?: {
|
|
18
21
|
keepSnapshots: number;
|
|
22
|
+
coverage?: (runId: string) => EventStoreTrimCoverage | Promise<EventStoreTrimCoverage>;
|
|
19
23
|
};
|
|
20
24
|
/** In-process cursor cache size. Default `0` (stateless between calls). */
|
|
21
25
|
readonly runCacheSize?: number;
|
|
22
26
|
/** Scan existing runs for pending timers on boot. Default true. */
|
|
23
27
|
readonly rescanTimers?: boolean;
|
|
24
|
-
/** Pluggable wake scheduler for timer waits. Defaults to an in-process
|
|
28
|
+
/** Pluggable wake scheduler for timer waits. Defaults to an in-process Effect fiber scheduler. */
|
|
25
29
|
readonly scheduler?: WakeScheduler;
|
|
30
|
+
readonly worker?: EffectWorker;
|
|
31
|
+
/** Failure-isolated runtime observation sink. */
|
|
32
|
+
readonly observer?: RuntimeObserver;
|
|
33
|
+
/**
|
|
34
|
+
* Authorizes HTTP API requests. Without it, run reads and writes are open while worker callback
|
|
35
|
+
* and operations routes return 503; `bearerAuth({ worker, operations })` enables them.
|
|
36
|
+
*
|
|
37
|
+
* A mounted debugger is authorized as `{ access: 'read', name: 'debugger' }`. Bearer tokens on
|
|
38
|
+
* reads block browser navigation, so hosts that need auth should use a cookie or session policy.
|
|
39
|
+
*/
|
|
40
|
+
readonly authorize?: Authorize;
|
|
41
|
+
/**
|
|
42
|
+
* Serves a debugger UI under `debugger.basePath` (for example `/debugger`). The runtime does not
|
|
43
|
+
* bundle a UI; pass `debuggerUi()` from `@swirls/looms/debugger/server`.
|
|
44
|
+
*/
|
|
45
|
+
readonly debugger?: DebuggerHost;
|
|
26
46
|
}
|
|
27
47
|
export interface StartResult {
|
|
28
48
|
readonly runId: string;
|
|
@@ -46,6 +66,7 @@ export interface Looms {
|
|
|
46
66
|
startRun(args: {
|
|
47
67
|
kind: string;
|
|
48
68
|
definitionName: string;
|
|
69
|
+
definitionVersion?: string;
|
|
49
70
|
input?: JsonValue;
|
|
50
71
|
runId?: string;
|
|
51
72
|
threadId?: string;
|
|
@@ -61,9 +82,14 @@ export interface Looms {
|
|
|
61
82
|
}): Promise<RunState>;
|
|
62
83
|
wake(runId: string): Promise<RunState>;
|
|
63
84
|
rescanTimers(): Promise<number>;
|
|
85
|
+
recoverDeadlines(): Promise<number>;
|
|
86
|
+
inspectRun(runId: string): Promise<RunOperationalStatus>;
|
|
87
|
+
retryEffect(runId: string, effectId: string): Promise<RunState>;
|
|
88
|
+
listRuns(): Promise<string[]>;
|
|
64
89
|
project<S>(runId: string, definition: ProjectionDefinition<S>): Promise<S>;
|
|
65
90
|
replayTo(runId: string, seq: number): Promise<ReplayStep | null>;
|
|
66
91
|
cancel(runId: string, threadId?: string): Promise<RunState>;
|
|
92
|
+
workerCallback(runId: string, input: WorkerCallbackInput): Promise<RunState>;
|
|
67
93
|
fetch(req: Request): Promise<Response | null>;
|
|
68
94
|
serve(options?: {
|
|
69
95
|
port?: number;
|