@swirls/looms 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +2 -0
- 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 +55 -32
- 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/definitions-store.d.ts +2 -3
- package/dist/agent/definitions-store.js +2 -4
- package/dist/agent/definitions.d.ts +46 -20
- package/dist/agent/definitions.js +36 -8
- 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 +24 -1
- package/dist/agent/signals.js +77 -0
- package/dist/agent/threads.d.ts +3 -33
- package/dist/agent/threads.js +20 -25
- package/dist/agent/tool-schema.js +0 -1
- 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 +23 -0
- package/dist/ai-vercel/vercel-evaluator.js +68 -0
- package/dist/ai-vercel/vercel-llm.js +64 -44
- 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 +1195 -18
- package/dist/client/client.js +118 -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.js +13 -14
- 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 +18 -2
- 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 +5 -1
- package/dist/core/index.js +5 -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 +16 -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/replay.d.ts +312 -3
- package/dist/core/replay.js +11 -1
- package/dist/core/schema.d.ts +8 -19
- package/dist/core/schema.js +25 -80
- package/dist/core/serialize.js +2 -4
- package/dist/core/snapshot-store.d.ts +2 -1
- package/dist/core/snapshot-store.js +8 -2
- package/dist/core/snapshots.d.ts +5 -1
- package/dist/core/snapshots.js +10 -15
- package/dist/core/sqlite-store.js +56 -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/components/event-stream.js +9 -10
- package/dist/debugger/events/protocol-summarize.js +26 -0
- package/dist/debugger/lib/event-meta.js +1 -2
- 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 +2 -2
- 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 +22 -4
- package/dist/runtime/looms.js +54 -36
- 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 +278 -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 +233 -470
- package/dist/runtime/server/auth.d.ts +40 -0
- package/dist/runtime/server/auth.js +40 -0
- package/dist/runtime/server/fetch-handler.d.ts +14 -0
- package/dist/runtime/server/fetch-handler.js +51 -0
- package/dist/runtime/server/http.d.ts +37 -0
- package/dist/runtime/server/http.js +62 -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/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 +192 -0
- package/dist/runtime/server.d.ts +2 -8
- package/dist/runtime/server.js +4 -211
- package/dist/runtime/sse.d.ts +2 -1
- package/dist/runtime/sse.js +24 -17
- package/dist/runtime/types.d.ts +115 -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 +148 -163
- 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/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 +359 -13
- 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 +8 -2
- package/dist/runtime/events-api.d.ts +0 -4
- package/dist/runtime/events-api.js +0 -84
package/dist/core/state.js
CHANGED
|
@@ -1,11 +1,89 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect';
|
|
2
|
+
import { RuntimeEffectSchema, WaitConditionSchema, } from './effects.js';
|
|
3
|
+
import { JsonValueSchema } from './envelope.js';
|
|
4
|
+
import { DEFAULT_DEFINITION_VERSION } from './module.js';
|
|
5
|
+
export const RunStateSchema = Schema.Struct({
|
|
6
|
+
runId: Schema.String,
|
|
7
|
+
status: Schema.Union([
|
|
8
|
+
Schema.Literal('running'),
|
|
9
|
+
Schema.Literal('completed'),
|
|
10
|
+
Schema.Literal('failed'),
|
|
11
|
+
Schema.Literal('cancelled'),
|
|
12
|
+
]),
|
|
13
|
+
rootThreadId: Schema.NullOr(Schema.String),
|
|
14
|
+
startIdentity: Schema.NullOr(Schema.Struct({
|
|
15
|
+
kind: Schema.String,
|
|
16
|
+
definitionName: Schema.String,
|
|
17
|
+
definitionVersion: Schema.String,
|
|
18
|
+
input: JsonValueSchema,
|
|
19
|
+
requestedThreadId: Schema.NullOr(Schema.String),
|
|
20
|
+
idempotencyKey: Schema.NullOr(Schema.String),
|
|
21
|
+
rootThreadId: Schema.String,
|
|
22
|
+
})).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
|
|
23
|
+
threads: Schema.Record(Schema.String, Schema.Struct({
|
|
24
|
+
threadId: Schema.String,
|
|
25
|
+
kind: Schema.String,
|
|
26
|
+
definitionName: Schema.String,
|
|
27
|
+
definitionVersion: Schema.String.pipe(Schema.withDecodingDefaultKey(Effect.succeed(DEFAULT_DEFINITION_VERSION))),
|
|
28
|
+
parentThreadId: Schema.NullOr(Schema.String),
|
|
29
|
+
status: Schema.Union([
|
|
30
|
+
Schema.Literal('running'),
|
|
31
|
+
Schema.Literal('waiting'),
|
|
32
|
+
Schema.Literal('completed'),
|
|
33
|
+
Schema.Literal('failed'),
|
|
34
|
+
Schema.Literal('cancelled'),
|
|
35
|
+
]),
|
|
36
|
+
input: JsonValueSchema,
|
|
37
|
+
output: Schema.NullOr(JsonValueSchema),
|
|
38
|
+
error: Schema.NullOr(Schema.String),
|
|
39
|
+
state: JsonValueSchema,
|
|
40
|
+
})),
|
|
41
|
+
waits: Schema.Record(Schema.String, Schema.Struct({
|
|
42
|
+
waitId: Schema.String,
|
|
43
|
+
threadId: Schema.String,
|
|
44
|
+
on: WaitConditionSchema,
|
|
45
|
+
tag: Schema.optional(JsonValueSchema),
|
|
46
|
+
})),
|
|
47
|
+
outstandingEffects: Schema.Array(Schema.Struct({
|
|
48
|
+
effectId: Schema.String,
|
|
49
|
+
threadId: Schema.String,
|
|
50
|
+
causingSeq: Schema.Finite,
|
|
51
|
+
causingEventId: Schema.String,
|
|
52
|
+
effect: RuntimeEffectSchema,
|
|
53
|
+
})),
|
|
54
|
+
effectExecutions: Schema.Record(Schema.String, Schema.Struct({
|
|
55
|
+
effectId: Schema.String,
|
|
56
|
+
attempt: Schema.Finite,
|
|
57
|
+
status: Schema.Union([
|
|
58
|
+
Schema.Literal('queued'),
|
|
59
|
+
Schema.Literal('dispatched'),
|
|
60
|
+
Schema.Literal('started'),
|
|
61
|
+
Schema.Literal('heartbeat'),
|
|
62
|
+
Schema.Literal('retry_wait'),
|
|
63
|
+
Schema.Literal('cancel_requested'),
|
|
64
|
+
Schema.Literal('timed_out'),
|
|
65
|
+
Schema.Literal('ambiguous'),
|
|
66
|
+
Schema.Literal('running'),
|
|
67
|
+
]),
|
|
68
|
+
nextAttemptAt: Schema.NullOr(Schema.Finite),
|
|
69
|
+
deadlineAt: Schema.NullOr(Schema.Finite).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
|
|
70
|
+
startedAt: Schema.NullOr(Schema.Finite).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
|
|
71
|
+
lastHeartbeatAt: Schema.NullOr(Schema.Finite).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
|
|
72
|
+
lastError: Schema.NullOr(Schema.String),
|
|
73
|
+
})).pipe(Schema.withDecodingDefaultKey(Effect.succeed({}))),
|
|
74
|
+
completedEffectIds: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
75
|
+
processedIdempotencyKeys: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
76
|
+
});
|
|
1
77
|
export function emptyRunState(runId) {
|
|
2
78
|
return {
|
|
3
79
|
runId,
|
|
4
80
|
status: 'running',
|
|
5
81
|
rootThreadId: null,
|
|
82
|
+
startIdentity: null,
|
|
6
83
|
threads: {},
|
|
7
84
|
waits: {},
|
|
8
85
|
outstandingEffects: [],
|
|
86
|
+
effectExecutions: {},
|
|
9
87
|
completedEffectIds: [],
|
|
10
88
|
processedIdempotencyKeys: [],
|
|
11
89
|
};
|
package/dist/core/store.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Stream } from 'effect';
|
|
2
2
|
import { type AppendableEvent, type EventEnvelope } from './envelope';
|
|
3
|
+
import { EventPayloadTooLargeError } from './limits';
|
|
3
4
|
declare const EventStoreError_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
5
|
readonly _tag: "EventStoreError";
|
|
5
6
|
} & Readonly<A>;
|
|
@@ -59,8 +60,31 @@ export declare class EventStoreFencedError extends EventStoreFencedError_base<{
|
|
|
59
60
|
}> {
|
|
60
61
|
constructor(runId: string, token: string);
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
declare const UnsafeEventStoreTrimError_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 & {
|
|
64
|
+
readonly _tag: "UnsafeEventStoreTrimError";
|
|
65
|
+
} & Readonly<A>;
|
|
66
|
+
export declare class UnsafeEventStoreTrimError extends UnsafeEventStoreTrimError_base<{
|
|
67
|
+
readonly runId: string;
|
|
68
|
+
readonly trimThrough: number;
|
|
69
|
+
readonly message: string;
|
|
70
|
+
}> {
|
|
71
|
+
constructor(runId: string, trimThrough: number);
|
|
72
|
+
}
|
|
73
|
+
export type EventStoreTrimCoverage = {
|
|
74
|
+
/** Durable archive contains every event through this sequence. */
|
|
75
|
+
readonly archiveCursor: number;
|
|
76
|
+
readonly requiredProjectors?: never;
|
|
77
|
+
readonly projectorCursors?: never;
|
|
78
|
+
} | {
|
|
79
|
+
readonly archiveCursor?: never;
|
|
80
|
+
/** Authoritative identities of every projector required before trimming. */
|
|
81
|
+
readonly requiredProjectors: readonly string[];
|
|
82
|
+
/** Durable checkpoint by projector identity. Every required projector must be present. */
|
|
83
|
+
readonly projectorCursors: Readonly<Record<string, number>>;
|
|
84
|
+
};
|
|
85
|
+
export declare function trimEventStoreSafely(store: EventStore, runId: string, beforeSeq: number, coverage: EventStoreTrimCoverage): Effect.Effect<void, EventStoreError | UnsafeEventStoreTrimError>;
|
|
86
|
+
export type EventStoreAppendError = EventStoreError | EventStoreConflictError | EventStoreFencedError | EventPayloadTooLargeError;
|
|
87
|
+
export type AnyEventStoreError = EventStoreError | EventStoreConflictError | EventStoreTruncationError | EventStoreTrimmedError | EventStoreFencedError | EventPayloadTooLargeError;
|
|
64
88
|
export declare function isEventStoreError(err: unknown): err is AnyEventStoreError;
|
|
65
89
|
export interface StreamBounds {
|
|
66
90
|
readonly head: number;
|
|
@@ -68,6 +92,16 @@ export interface StreamBounds {
|
|
|
68
92
|
}
|
|
69
93
|
export interface AppendOptions {
|
|
70
94
|
readonly expectedTail?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Atomically claims an ingress command with the append. Reusing the key
|
|
97
|
+
* returns a deduplicated result without appending events. Stores without a
|
|
98
|
+
* command table may ignore this; callers must pair it with `expectedTail`
|
|
99
|
+
* so a retried command conflicts instead of appending twice.
|
|
100
|
+
*/
|
|
101
|
+
readonly idempotency?: {
|
|
102
|
+
readonly key: string;
|
|
103
|
+
readonly fingerprint?: string;
|
|
104
|
+
};
|
|
71
105
|
/** Set the stream fencing token atomically in this batch (`''` clears). */
|
|
72
106
|
readonly fence?: string;
|
|
73
107
|
/** Must match the stream's current fencing token, or the append fails. */
|
|
@@ -92,6 +126,7 @@ export declare function paginatePages<T, SCursor, E = never, R = never>(options:
|
|
|
92
126
|
export interface AppendResult {
|
|
93
127
|
sequences: number[];
|
|
94
128
|
tail: number;
|
|
129
|
+
deduplicated?: boolean;
|
|
95
130
|
}
|
|
96
131
|
export interface EventStore {
|
|
97
132
|
readonly append: (runId: string, events: ReadonlyArray<AppendableEvent>, options?: AppendOptions) => Effect.Effect<AppendResult, EventStoreAppendError>;
|
|
@@ -128,7 +163,7 @@ export interface EventStore {
|
|
|
128
163
|
readonly subscribe: (runId: string, options?: {
|
|
129
164
|
fromSeq?: number;
|
|
130
165
|
}) => Stream.Stream<EventEnvelope, EventStoreError>;
|
|
131
|
-
readonly listRuns:
|
|
166
|
+
readonly listRuns: Effect.Effect<string[], EventStoreError>;
|
|
132
167
|
}
|
|
133
168
|
/**
|
|
134
169
|
* Utility to read an EventStore as a Stream.Stream, using `store.readStream` if implemented
|
package/dist/core/store.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context, Data, Effect, Layer, Option, Queue, Ref, Stream } from 'effect';
|
|
2
2
|
import { withAssignedSeq } from './envelope.js';
|
|
3
|
+
import { assertEventByteLimits, EventPayloadTooLargeError } from './limits.js';
|
|
3
4
|
export class EventStoreError extends Data.TaggedError('EventStoreError') {
|
|
4
5
|
conflict;
|
|
5
6
|
cause;
|
|
@@ -55,12 +56,34 @@ export class EventStoreFencedError extends Data.TaggedError('EventStoreFencedErr
|
|
|
55
56
|
this.name = 'EventStoreFencedError';
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
export class UnsafeEventStoreTrimError extends Data.TaggedError('UnsafeEventStoreTrimError') {
|
|
60
|
+
constructor(runId, trimThrough) {
|
|
61
|
+
super({
|
|
62
|
+
runId,
|
|
63
|
+
trimThrough,
|
|
64
|
+
message: `UnsafeEventStoreTrim: refusing to trim run "${runId}" through seq ${trimThrough}; no archive or complete projector checkpoint coverage was supplied`,
|
|
65
|
+
});
|
|
66
|
+
this.name = 'UnsafeEventStoreTrimError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function trimEventStoreSafely(store, runId, beforeSeq, coverage) {
|
|
70
|
+
const trimThrough = Math.max(0, beforeSeq - 1);
|
|
71
|
+
const covered = coverage.archiveCursor !== undefined
|
|
72
|
+
? coverage.archiveCursor >= trimThrough
|
|
73
|
+
: coverage.requiredProjectors.length > 0 &&
|
|
74
|
+
coverage.requiredProjectors.every((projector) => (coverage.projectorCursors[projector] ?? -1) >= trimThrough);
|
|
75
|
+
if (!store.trim || !covered) {
|
|
76
|
+
return Effect.fail(new UnsafeEventStoreTrimError(runId, trimThrough));
|
|
77
|
+
}
|
|
78
|
+
return store.trim(runId, beforeSeq);
|
|
79
|
+
}
|
|
58
80
|
export function isEventStoreError(err) {
|
|
59
81
|
return (err instanceof EventStoreError ||
|
|
60
82
|
err instanceof EventStoreConflictError ||
|
|
61
83
|
err instanceof EventStoreTruncationError ||
|
|
62
84
|
err instanceof EventStoreTrimmedError ||
|
|
63
|
-
err instanceof EventStoreFencedError
|
|
85
|
+
err instanceof EventStoreFencedError ||
|
|
86
|
+
err instanceof EventPayloadTooLargeError);
|
|
64
87
|
}
|
|
65
88
|
/**
|
|
66
89
|
* Pure Effect-native stream pagination primitive.
|
|
@@ -99,16 +122,41 @@ export const makeMemoryEventStore = Effect.gen(function* () {
|
|
|
99
122
|
if (existing) {
|
|
100
123
|
return existing;
|
|
101
124
|
}
|
|
102
|
-
const created = {
|
|
125
|
+
const created = {
|
|
126
|
+
events: [],
|
|
127
|
+
waiters: [],
|
|
128
|
+
head: 1,
|
|
129
|
+
tail: 0,
|
|
130
|
+
commands: new Map(),
|
|
131
|
+
};
|
|
103
132
|
map.set(runId, created);
|
|
104
133
|
return created;
|
|
105
134
|
};
|
|
106
135
|
const service = {
|
|
107
136
|
append: (runId, events, options) => Effect.gen(function* () {
|
|
137
|
+
yield* Effect.try({
|
|
138
|
+
try: () => assertEventByteLimits(runId, events),
|
|
139
|
+
catch: (cause) => cause instanceof EventPayloadTooLargeError
|
|
140
|
+
? cause
|
|
141
|
+
: new EventStoreError('event size validation failed', cause),
|
|
142
|
+
});
|
|
108
143
|
const sequences = [];
|
|
144
|
+
let deduplicated = false;
|
|
109
145
|
yield* Ref.update(logs, (map) => {
|
|
110
146
|
const next = new Map(map);
|
|
111
147
|
const log = getOrCreate(next, runId);
|
|
148
|
+
const command = options?.idempotency
|
|
149
|
+
? log.commands.get(options.idempotency.key)
|
|
150
|
+
: undefined;
|
|
151
|
+
if (command) {
|
|
152
|
+
if (options?.idempotency?.fingerprint !== undefined &&
|
|
153
|
+
command.fingerprint !== undefined &&
|
|
154
|
+
command.fingerprint !== options.idempotency.fingerprint) {
|
|
155
|
+
throw new EventStoreError(`Idempotency key "${options.idempotency.key}" was reused with different content`);
|
|
156
|
+
}
|
|
157
|
+
deduplicated = true;
|
|
158
|
+
return map;
|
|
159
|
+
}
|
|
112
160
|
if (options?.expectedTail !== undefined && log.tail !== options.expectedTail) {
|
|
113
161
|
throw new EventStoreConflictError(runId, options.expectedTail, log.tail);
|
|
114
162
|
}
|
|
@@ -135,7 +183,14 @@ export const makeMemoryEventStore = Effect.gen(function* () {
|
|
|
135
183
|
head: log.head,
|
|
136
184
|
tail: nextTail,
|
|
137
185
|
fenceToken,
|
|
186
|
+
commands: new Map(log.commands),
|
|
138
187
|
};
|
|
188
|
+
if (options?.idempotency) {
|
|
189
|
+
updated.commands.set(options.idempotency.key, {
|
|
190
|
+
fingerprint: options.idempotency.fingerprint,
|
|
191
|
+
committedTail: nextTail,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
139
194
|
next.set(runId, updated);
|
|
140
195
|
for (const event of appended) {
|
|
141
196
|
for (const waiter of log.waiters) {
|
|
@@ -145,11 +200,16 @@ export const makeMemoryEventStore = Effect.gen(function* () {
|
|
|
145
200
|
return next;
|
|
146
201
|
}).pipe(Effect.catchDefect((cause) => Effect.fail(cause instanceof EventStoreConflictError ||
|
|
147
202
|
cause instanceof EventStoreFencedError ||
|
|
148
|
-
cause instanceof EventStoreError
|
|
203
|
+
cause instanceof EventStoreError ||
|
|
204
|
+
cause instanceof EventPayloadTooLargeError
|
|
149
205
|
? cause
|
|
150
206
|
: new EventStoreError('append failed', cause))));
|
|
151
207
|
const tail = yield* service.tail(runId);
|
|
152
|
-
|
|
208
|
+
const result = { sequences, tail };
|
|
209
|
+
if (deduplicated) {
|
|
210
|
+
result.deduplicated = true;
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
153
213
|
}),
|
|
154
214
|
read: (runId, options) => Effect.gen(function* () {
|
|
155
215
|
const map = yield* Ref.get(logs);
|
|
@@ -174,21 +234,19 @@ export const makeMemoryEventStore = Effect.gen(function* () {
|
|
|
174
234
|
}
|
|
175
235
|
return { head: log.head, tail: log.tail };
|
|
176
236
|
}),
|
|
177
|
-
trim: (runId, beforeSeq) =>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
head: Math.max(log.head, beforeSeq),
|
|
189
|
-
});
|
|
190
|
-
return next;
|
|
237
|
+
trim: (runId, beforeSeq) => Ref.update(logs, (map) => {
|
|
238
|
+
const log = map.get(runId);
|
|
239
|
+
if (!log) {
|
|
240
|
+
return map;
|
|
241
|
+
}
|
|
242
|
+
const next = new Map(map);
|
|
243
|
+
const retained = log.events.filter((e) => e.seq >= beforeSeq);
|
|
244
|
+
next.set(runId, {
|
|
245
|
+
...log,
|
|
246
|
+
events: retained,
|
|
247
|
+
head: Math.max(log.head, beforeSeq),
|
|
191
248
|
});
|
|
249
|
+
return next;
|
|
192
250
|
}),
|
|
193
251
|
subscribe: (runId, options) => Stream.callback((queue) => Effect.gen(function* () {
|
|
194
252
|
const fromSeq = options?.fromSeq ?? 1;
|
|
@@ -219,10 +277,7 @@ export const makeMemoryEventStore = Effect.gen(function* () {
|
|
|
219
277
|
}
|
|
220
278
|
}));
|
|
221
279
|
})),
|
|
222
|
-
listRuns: () =>
|
|
223
|
-
const map = yield* Ref.get(logs);
|
|
224
|
-
return [...map.keys()];
|
|
225
|
-
}),
|
|
280
|
+
listRuns: Ref.get(logs).pipe(Effect.map((map) => [...map.keys()])),
|
|
226
281
|
};
|
|
227
282
|
return service;
|
|
228
283
|
});
|
package/dist/core/thread.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface StartContext<TInput = JsonValue> {
|
|
|
7
7
|
readonly threadId: string;
|
|
8
8
|
readonly parentThreadId: string | null;
|
|
9
9
|
readonly definitionName: string;
|
|
10
|
+
readonly definitionVersion: string;
|
|
10
11
|
readonly input: TInput;
|
|
11
12
|
}
|
|
12
13
|
export interface ThreadContext {
|
|
@@ -22,20 +23,20 @@ export interface ThreadDefinition<S = any> {
|
|
|
22
23
|
step(state: S, event: EventEnvelope, ctx: ThreadContext): S;
|
|
23
24
|
effects(state: S, ctx: ThreadContext): RuntimeEffect[];
|
|
24
25
|
}
|
|
25
|
-
export declare function defineThread<TShape, TInputSchema extends SchemaInput | undefined = undefined>(def: {
|
|
26
|
-
readonly kind: string;
|
|
27
|
-
readonly shape: TShape;
|
|
28
|
-
readonly input?: TInputSchema;
|
|
29
|
-
initialState(ctx: StartContext<InferDefinedSchema<TInputSchema>>): InferSchemaOutput<TShape>;
|
|
30
|
-
step(state: InferSchemaOutput<TShape>, event: EventEnvelope, ctx: ThreadContext): InferSchemaOutput<TShape>;
|
|
31
|
-
effects?(state: InferSchemaOutput<TShape>, ctx: ThreadContext): RuntimeEffect[];
|
|
32
|
-
}): ThreadDefinition<InferSchemaOutput<TShape>>;
|
|
33
26
|
export declare function defineThread<S = JsonValue, TInputSchema extends SchemaInput | undefined = undefined>(def: {
|
|
34
27
|
readonly kind: string;
|
|
35
|
-
readonly shape?:
|
|
28
|
+
readonly shape?: undefined;
|
|
36
29
|
readonly input?: TInputSchema;
|
|
37
30
|
initialState(ctx: StartContext<InferDefinedSchema<TInputSchema>>): S;
|
|
38
31
|
step(state: S, event: EventEnvelope, ctx: ThreadContext): S;
|
|
39
32
|
effects?(state: S, ctx: ThreadContext): RuntimeEffect[];
|
|
40
33
|
}): ThreadDefinition<S>;
|
|
34
|
+
export declare function defineThread<TShape extends SchemaInput, TInputSchema extends SchemaInput | undefined = undefined>(def: {
|
|
35
|
+
readonly kind: string;
|
|
36
|
+
readonly shape: TShape;
|
|
37
|
+
readonly input?: TInputSchema;
|
|
38
|
+
initialState(ctx: StartContext<InferDefinedSchema<TInputSchema>>): InferSchemaOutput<TShape>;
|
|
39
|
+
step(state: NoInfer<InferSchemaOutput<TShape>>, event: EventEnvelope, ctx: ThreadContext): InferSchemaOutput<TShape>;
|
|
40
|
+
effects?(state: NoInfer<InferSchemaOutput<TShape>>, ctx: ThreadContext): RuntimeEffect[];
|
|
41
|
+
}): ThreadDefinition<InferSchemaOutput<TShape>>;
|
|
41
42
|
export declare function isTerminalStatus(status: ThreadStatus): boolean;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -9,15 +9,12 @@ export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
|
|
|
9
9
|
export interface JsonPayload {
|
|
10
10
|
readonly [key: string]: JsonValue | JsonPayload | readonly (JsonValue | JsonPayload)[] | undefined;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare function cleanUndefined<T>(value: T): T;
|
|
12
|
+
export declare const stringifyJson: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => string;
|
|
13
|
+
export declare const stringifyJsonPretty: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => string;
|
|
14
|
+
/** Convert a value to its JSON wire representation, dropping undefined object properties. */
|
|
15
|
+
export declare function cleanUndefined(value: unknown): JsonValue;
|
|
17
16
|
/** Mark a JSON-serializable struct as a log payload, stripping undefined fields. */
|
|
18
|
-
export declare
|
|
19
|
-
/** Recover a typed struct previously written as JSON. */
|
|
20
|
-
export declare function fromJsonStruct<T>(value: JsonValue): T;
|
|
17
|
+
export declare const asJson: typeof cleanUndefined;
|
|
21
18
|
export declare function isJsonObject(value: unknown): value is {
|
|
22
19
|
[key: string]: JsonValue;
|
|
23
20
|
};
|
package/dist/core/types.js
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
import { Predicate } from 'effect';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Predicate, Schema } from 'effect';
|
|
2
|
+
const encodeUnknownJson = Schema.encodeSync(Schema.fromJsonString(Schema.Unknown));
|
|
3
|
+
const encodeUnknownJsonPretty = Schema.encodeSync(Schema.fromJsonString(Schema.Unknown, { space: 2 }));
|
|
4
|
+
export const stringifyJson = encodeUnknownJson;
|
|
5
|
+
export const stringifyJsonPretty = encodeUnknownJsonPretty;
|
|
6
|
+
// This recursive serializer is the parser for unknown JSON-like boundary values.
|
|
7
|
+
// oxlint-disable-next-line anti-slop/no-unknown-parameters
|
|
8
|
+
function cleanJsonValue(value) {
|
|
9
|
+
if (value === null || Predicate.isString(value) || Predicate.isBoolean(value)) {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (Predicate.isNumber(value)) {
|
|
13
|
+
return Number.isFinite(value) ? value : null;
|
|
14
|
+
}
|
|
7
15
|
if (Array.isArray(value)) {
|
|
8
|
-
|
|
9
|
-
return value.map(cleanUndefined);
|
|
16
|
+
return value.map((item) => cleanJsonValue(item) ?? null);
|
|
10
17
|
}
|
|
11
|
-
if (
|
|
12
|
-
return
|
|
18
|
+
if (!Predicate.isReadonlyObject(value)) {
|
|
19
|
+
return undefined;
|
|
13
20
|
}
|
|
14
21
|
const result = {};
|
|
15
|
-
for (const [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
result[
|
|
22
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
23
|
+
const cleaned = cleanJsonValue(nested);
|
|
24
|
+
if (cleaned !== undefined) {
|
|
25
|
+
result[key] = cleaned;
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
|
-
// SAFETY: Rebuilding an object without undefined keys preserves its record shape.
|
|
22
28
|
return result;
|
|
23
29
|
}
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/** Recover a typed struct previously written as JSON. */
|
|
30
|
-
export function fromJsonStruct(value) {
|
|
31
|
-
// SAFETY: value is a JSON struct previously produced as T.
|
|
32
|
-
return value;
|
|
30
|
+
/** Convert a value to its JSON wire representation, dropping undefined object properties. */
|
|
31
|
+
// Public JSON normalization intentionally accepts unknown input and returns the parsed domain type.
|
|
32
|
+
// oxlint-disable-next-line anti-slop/no-unknown-parameters
|
|
33
|
+
export function cleanUndefined(value) {
|
|
34
|
+
return cleanJsonValue(value) ?? null;
|
|
33
35
|
}
|
|
36
|
+
/** Mark a JSON-serializable struct as a log payload, stripping undefined fields. */
|
|
37
|
+
export const asJson = cleanUndefined;
|
|
34
38
|
export function isJsonObject(value) {
|
|
35
39
|
return Predicate.isObject(value) && !Array.isArray(value);
|
|
36
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Data, Effect } from 'effect';
|
|
1
|
+
import { Data, Effect, Predicate, Schema } from 'effect';
|
|
2
2
|
import { validateInputEffect } from './schema.js';
|
|
3
3
|
import { cleanUndefined } from './types.js';
|
|
4
4
|
export class InvalidEventError extends Data.TaggedError('InvalidEventError') {
|
|
@@ -25,16 +25,26 @@ function findCatalogAndEntry(catalogs, type) {
|
|
|
25
25
|
}
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
|
+
function isStandardSchema(entry) {
|
|
29
|
+
return Predicate.isReadonlyObject(entry) && '~standard' in entry;
|
|
30
|
+
}
|
|
31
|
+
function isEffectSchema(entry) {
|
|
32
|
+
return Schema.isSchema(entry);
|
|
33
|
+
}
|
|
28
34
|
export function validateEventInput(catalogs, input) {
|
|
29
35
|
const match = findCatalogAndEntry(catalogs, input.type);
|
|
30
36
|
if (!match) {
|
|
31
37
|
return Effect.succeed(input);
|
|
32
38
|
}
|
|
33
39
|
const cleanedPayload = cleanUndefined(input.payload);
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
const validated = isEffectSchema(match.entry)
|
|
41
|
+
? validateInputEffect(match.entry, cleanedPayload)
|
|
42
|
+
: isStandardSchema(match.entry)
|
|
43
|
+
? validateInputEffect(match.entry, cleanedPayload)
|
|
44
|
+
: Effect.succeed(cleanedPayload);
|
|
45
|
+
return validated.pipe(Effect.map((validatedPayload) => ({
|
|
36
46
|
...input,
|
|
37
|
-
payload: validatedPayload,
|
|
47
|
+
payload: cleanUndefined(validatedPayload),
|
|
38
48
|
})), Effect.mapError((err) => new InvalidEventError(input.type, `Invalid payload for event "${input.type}": ${err.message}`, err.issues)));
|
|
39
49
|
}
|
|
40
50
|
export function validateEventsEffect(catalogs, events) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EventInput } from './envelope';
|
|
2
|
+
/** Identifies one attempt of an effect executed by an external worker. */
|
|
3
|
+
export interface WorkerCallback {
|
|
4
|
+
readonly effectId: string;
|
|
5
|
+
readonly attempt: number;
|
|
6
|
+
}
|
|
7
|
+
/** What an external worker reports about an effect attempt. */
|
|
8
|
+
export type WorkerCallbackInput = (WorkerCallback & {
|
|
9
|
+
readonly kind: 'started' | 'heartbeat' | 'cancelled';
|
|
10
|
+
}) | (WorkerCallback & {
|
|
11
|
+
readonly kind: 'complete';
|
|
12
|
+
readonly events: ReadonlyArray<EventInput>;
|
|
13
|
+
}) | (WorkerCallback & {
|
|
14
|
+
readonly kind: 'fail';
|
|
15
|
+
readonly error: string;
|
|
16
|
+
});
|
|
17
|
+
export type WorkerCallbackKind = WorkerCallbackInput['kind'];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
3
|
+
import { Effect, Fiber } from 'effect';
|
|
3
4
|
import { Check, Search, SlidersHorizontal } from 'lucide-react';
|
|
4
5
|
import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';
|
|
5
|
-
import {
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
7
|
import { defaultEventCatalog } from '../events/catalog.js';
|
|
7
8
|
import { cn, shortId } from '../lib/cn.js';
|
|
8
9
|
import { getEventMeta } from '../lib/event-meta.js';
|
|
@@ -53,17 +54,17 @@ export function EventStream({ events, startedAt, threadId, threadLabel, selected
|
|
|
53
54
|
return () => undefined;
|
|
54
55
|
}
|
|
55
56
|
followLock.current = true;
|
|
56
|
-
let
|
|
57
|
+
let followRelease;
|
|
57
58
|
const rafId = requestAnimationFrame(() => {
|
|
58
59
|
virtualizer.scrollToIndex(visible.length - 1, { align: 'end' });
|
|
59
|
-
|
|
60
|
+
followRelease = Effect.runFork(Effect.sleep(50).pipe(Effect.andThen(Effect.sync(() => {
|
|
60
61
|
followLock.current = false;
|
|
61
|
-
}
|
|
62
|
+
}))));
|
|
62
63
|
});
|
|
63
64
|
return () => {
|
|
64
65
|
cancelAnimationFrame(rafId);
|
|
65
|
-
if (
|
|
66
|
-
|
|
66
|
+
if (followRelease !== undefined) {
|
|
67
|
+
Effect.runFork(Fiber.interrupt(followRelease));
|
|
67
68
|
}
|
|
68
69
|
followLock.current = false;
|
|
69
70
|
};
|
|
@@ -107,13 +108,11 @@ export function EventStream({ events, startedAt, threadId, threadLabel, selected
|
|
|
107
108
|
? (renderInspector?.(selected) ?? (_jsx(EventInspector, { event: selected, loadReplayStep: loadReplayStep })))
|
|
108
109
|
: null] }));
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
const EventRow = memo(function EventRow({ event, catalog, startedAt, selected, onSelectSeq, }) {
|
|
111
|
+
function EventRow({ event, catalog, startedAt, selected, onSelectSeq, }) {
|
|
112
112
|
const meta = getEventMeta(event, catalog);
|
|
113
113
|
const offset = startedAt !== undefined ? Math.max(0, event.ts - startedAt) : undefined;
|
|
114
114
|
const handleClick = useCallback(() => {
|
|
115
115
|
onSelectSeq(selected ? undefined : event.seq);
|
|
116
116
|
}, [onSelectSeq, selected, event.seq]);
|
|
117
117
|
return (_jsxs("button", { type: "button", onClick: handleClick, title: [meta.summary.title, meta.summary.detail].filter(Boolean).join(' — '), className: cn('flex w-full items-start gap-1.5 rounded-sm px-1.5 py-1 text-left font-mono text-[11px]', selected ? 'bg-accent' : 'hover:bg-accent/40', event.ephemeral && 'opacity-50'), children: [_jsx("span", { className: cn('mt-1.5 size-1.5 shrink-0 rounded-full', catalog.familyClass(meta.family)) }), _jsx("span", { className: "text-muted-foreground w-6 shrink-0 text-right tabular-nums", children: event.seq }), _jsx("span", { className: "debugger-event-offset text-muted-foreground w-10 shrink-0 text-right tabular-nums", children: offset !== undefined ? `+${offset}` : '' }), _jsxs("span", { className: "min-w-0 flex-1 truncate whitespace-nowrap", children: [_jsx("span", { className: "text-foreground", children: meta.summary.title }), meta.summary.detail ? (_jsx("span", { className: "text-muted-foreground ml-1", children: meta.summary.detail })) : null] }), event.causationId ? (_jsxs("span", { className: "debugger-event-causation text-muted-foreground shrink-0", children: ["\u2190 ", shortId(event.causationId)] })) : null, event.threadId ? (_jsx("span", { className: "debugger-event-thread text-muted-foreground shrink-0", children: shortId(event.threadId) })) : null] }));
|
|
118
|
-
|
|
119
|
-
});
|
|
118
|
+
}
|
|
@@ -25,6 +25,8 @@ export function summarizeProtocolEvent(event) {
|
|
|
25
25
|
title: text(payload.error) ? 'run failed' : 'run completed',
|
|
26
26
|
detail: text(payload.error) ?? compactJson(payload.output ?? null),
|
|
27
27
|
};
|
|
28
|
+
case 'runtime.run.cancelled':
|
|
29
|
+
return { title: 'run cancelled', detail: text(payload.reason) };
|
|
28
30
|
case 'runtime.thread.started':
|
|
29
31
|
return {
|
|
30
32
|
title: 'thread started',
|
|
@@ -58,10 +60,34 @@ export function summarizeProtocolEvent(event) {
|
|
|
58
60
|
return { title: 'timer fired' };
|
|
59
61
|
case 'runtime.effect.failed':
|
|
60
62
|
return { title: 'effect failed', detail: text(payload.error) };
|
|
63
|
+
case 'runtime.effect.attempt.started':
|
|
64
|
+
return { title: 'effect attempt started', detail: numeric(payload.attempt) };
|
|
65
|
+
case 'runtime.effect.queued':
|
|
66
|
+
return { title: 'effect queued', detail: numeric(payload.attempt) };
|
|
67
|
+
case 'runtime.effect.dispatched':
|
|
68
|
+
return { title: 'effect dispatched', detail: numeric(payload.attempt) };
|
|
69
|
+
case 'runtime.effect.worker.started':
|
|
70
|
+
return { title: 'worker started effect', detail: numeric(payload.attempt) };
|
|
71
|
+
case 'runtime.effect.heartbeat':
|
|
72
|
+
return { title: 'effect heartbeat', detail: numeric(payload.attempt) };
|
|
73
|
+
case 'runtime.effect.completed':
|
|
74
|
+
return { title: 'effect completed', detail: numeric(payload.attempt) };
|
|
75
|
+
case 'runtime.effect.cancel.requested':
|
|
76
|
+
return { title: 'effect cancellation requested', detail: numeric(payload.attempt) };
|
|
77
|
+
case 'runtime.effect.cancelled':
|
|
78
|
+
return { title: 'effect cancelled', detail: numeric(payload.attempt) };
|
|
79
|
+
case 'runtime.effect.timed_out':
|
|
80
|
+
return { title: 'effect timed out', detail: text(payload.timeout) };
|
|
81
|
+
case 'runtime.effect.ambiguous':
|
|
82
|
+
return { title: 'effect outcome ambiguous', detail: text(payload.error) };
|
|
83
|
+
case 'runtime.effect.retry.scheduled':
|
|
84
|
+
return { title: 'effect retry scheduled', detail: text(payload.error) };
|
|
61
85
|
case 'runtime.snapshot.taken':
|
|
62
86
|
return { title: 'snapshot', detail: `seq ${numeric(payload.seq) ?? ''}` };
|
|
63
87
|
case 'runtime.signal.received':
|
|
64
88
|
return { title: 'signal', detail: compactJson(event.payload) };
|
|
89
|
+
case 'runtime.thread.cancel.requested':
|
|
90
|
+
return { title: 'thread cancellation requested', detail: text(payload.threadId) };
|
|
65
91
|
default: {
|
|
66
92
|
const exhaustiveType = event.type;
|
|
67
93
|
return { title: 'event', detail: compactJson(obj(exhaustiveType)) };
|
|
@@ -12,8 +12,7 @@ export function getEventMeta(event, catalog) {
|
|
|
12
12
|
: searchText(event, catalog ? catalog.summarize : summarizeEvent);
|
|
13
13
|
const meta = { summary, searchText: text, family };
|
|
14
14
|
metaCache.set(event, {
|
|
15
|
-
|
|
16
|
-
catalog: catalog,
|
|
15
|
+
catalog,
|
|
17
16
|
meta,
|
|
18
17
|
});
|
|
19
18
|
return meta;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context, Layer } from 'effect';
|
|
2
|
+
import type { EvaluatorDefinition } from './definitions';
|
|
3
|
+
export interface EvaluatorDefinitionStore {
|
|
4
|
+
get(name: string): EvaluatorDefinition | undefined;
|
|
5
|
+
}
|
|
6
|
+
declare const EvaluatorDefinitionsTag_base: Context.ServiceClass<EvaluatorDefinitionsTag, "looms/EvaluatorDefinitions", EvaluatorDefinitionStore>;
|
|
7
|
+
export declare class EvaluatorDefinitionsTag extends EvaluatorDefinitionsTag_base {
|
|
8
|
+
}
|
|
9
|
+
export declare function makeEvaluatorDefinitionStore(definitions: ReadonlyArray<EvaluatorDefinition>): EvaluatorDefinitionStore;
|
|
10
|
+
export declare const EvaluatorDefinitionsLive: (definitions: ReadonlyArray<EvaluatorDefinition>) => Layer.Layer<EvaluatorDefinitionsTag, never, never>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Context, Layer } from 'effect';
|
|
2
|
+
export class EvaluatorDefinitionsTag extends Context.Service()('looms/EvaluatorDefinitions') {
|
|
3
|
+
}
|
|
4
|
+
export function makeEvaluatorDefinitionStore(definitions) {
|
|
5
|
+
const map = new Map(definitions.map((def) => [def.name, def]));
|
|
6
|
+
return { get: (name) => map.get(name) };
|
|
7
|
+
}
|
|
8
|
+
export const EvaluatorDefinitionsLive = (definitions) => Layer.succeed(EvaluatorDefinitionsTag, makeEvaluatorDefinitionStore(definitions));
|