@yolk-sdk/harness 0.1.0-canary.77 → 0.1.0-canary.78

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.
Files changed (42) hide show
  1. package/README.md +64 -2
  2. package/dist/coordinator.d.mts +12 -2
  3. package/dist/coordinator.d.mts.map +1 -1
  4. package/dist/coordinator.mjs +31 -6
  5. package/dist/coordinator.mjs.map +1 -1
  6. package/dist/driver/durable-object.d.mts +1 -1
  7. package/dist/driver/durable-object.d.mts.map +1 -1
  8. package/dist/driver/durable-object.mjs +4 -4
  9. package/dist/driver/durable-object.mjs.map +1 -1
  10. package/dist/driver/memory.d.mts +1 -1
  11. package/dist/driver/memory.d.mts.map +1 -1
  12. package/dist/driver/memory.mjs +5 -5
  13. package/dist/driver/memory.mjs.map +1 -1
  14. package/dist/driver.d.mts +68 -9
  15. package/dist/driver.d.mts.map +1 -1
  16. package/dist/driver.mjs +84 -83
  17. package/dist/driver.mjs.map +1 -1
  18. package/dist/inbox.d.mts +274 -5
  19. package/dist/inbox.d.mts.map +1 -1
  20. package/dist/inbox.mjs +201 -196
  21. package/dist/inbox.mjs.map +1 -1
  22. package/dist/outcome-constructors-internal.d.mts +403 -0
  23. package/dist/outcome-constructors-internal.d.mts.map +1 -0
  24. package/dist/outcome-constructors-internal.mjs +11 -0
  25. package/dist/outcome-constructors-internal.mjs.map +1 -0
  26. package/dist/outcome.d.mts +325 -25
  27. package/dist/outcome.d.mts.map +1 -1
  28. package/dist/outcome.mjs +47 -70
  29. package/dist/outcome.mjs.map +1 -1
  30. package/dist/store.d.mts +22 -8
  31. package/dist/store.d.mts.map +1 -1
  32. package/dist/store.mjs +80 -68
  33. package/dist/store.mjs.map +1 -1
  34. package/package.json +3 -3
  35. package/src/coordinator.ts +108 -7
  36. package/src/driver/durable-object.ts +6 -12
  37. package/src/driver/memory.ts +9 -8
  38. package/src/driver.ts +179 -160
  39. package/src/inbox.ts +330 -268
  40. package/src/outcome-constructors-internal.ts +18 -0
  41. package/src/outcome.ts +165 -118
  42. package/src/store.ts +123 -99
package/README.md CHANGED
@@ -8,7 +8,7 @@ Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- pnpm add @yolk-sdk/harness@canary effect@4.0.0-beta.80
11
+ pnpm add @yolk-sdk/harness@canary effect@4.0.0-rc.115
12
12
  ```
13
13
 
14
14
  ## Subpaths
@@ -24,6 +24,34 @@ pnpm add @yolk-sdk/harness@canary effect@4.0.0-beta.80
24
24
  | `@yolk-sdk/harness/driver/durable-object` | Durable Object storage-backed claims + driver |
25
25
  | `@yolk-sdk/harness/outcome` | Classify one model/tool attempt: Completed / Retry / Continue / RecoverFull / Compacted / AwaitingInput |
26
26
 
27
+ ## Tagged constructors
28
+
29
+ Inbox, driver, and outcome ADTs are `Data.taggedEnum` **values** on the existing subpaths. They are
30
+ plain objects with `_tag` last, not `Equal`/`Hash` Data classes.
31
+
32
+ ```ts
33
+ import {
34
+ DrainBegin,
35
+ HitlDecision,
36
+ PauseDecision,
37
+ RecoveryAdmission,
38
+ RecoveryAttempt
39
+ } from '@yolk-sdk/harness/inbox'
40
+ import { StopDecision } from '@yolk-sdk/harness/driver'
41
+ import { HitlMatch, OverflowCompactionResult, StepOutcome } from '@yolk-sdk/harness/outcome'
42
+ ```
43
+
44
+ | Subpath | Value constructors |
45
+ | --------- | ------------------------------------------------------------------------------------- |
46
+ | `inbox` | `HitlDecision`, `PauseDecision`, `RecoveryAttempt`, `RecoveryAdmission`, `DrainBegin` |
47
+ | `driver` | `StopDecision` (`Idle` / `Interrupted` / `ParkCleared`) |
48
+ | `outcome` | `OverflowCompactionResult`, `StepOutcome`, `HitlMatch` |
49
+
50
+ `StopDecision` is the same internal tagged enum, re-exported as `export type` + `export const` from
51
+ `./driver`. Driver recovery uses Inbox `RecoveryAttempt` (`Skip` / `Exhausted` / `Resume`). Prefer
52
+ `Match.tag` / `Predicate.isTagged` over `_tag ===`. `HitlMatch.Match({ requestId })` /
53
+ `HitlMatch.Mismatch()` replace handwritten `{ _tag: 'Match' | 'Mismatch' }` objects.
54
+
27
55
  ## Example
28
56
 
29
57
  Omitting `drain` uses a no-op (`Effect.void`): `driver.run` only claims and releases ownership. Attach host work with a custom drain. `Inbox.takePromotable` requires that drain's live `drainToken`.
@@ -33,7 +61,7 @@ Omitting `drain` uses a no-op (`Effect.void`): `driver.run` only claims and rele
33
61
  Setup:
34
62
 
35
63
  ```bash
36
- pnpm add @yolk-sdk/harness@canary effect@4.0.0-beta.80
64
+ pnpm add @yolk-sdk/harness@canary effect@4.0.0-rc.115
37
65
  pnpm add -D tsx
38
66
  ```
39
67
 
@@ -115,6 +143,40 @@ Startup is explicit: build the shared Driver/Inbox/Store, restore host-owned wai
115
143
  - Human pause releases the busy claim. User `stop` is terminal at the captured owner's settlement (including shutdown then user-stop). Shutdown interrupt keeps the claim. The Durable Object snapshot claim store does not make Inbox durable.
116
144
  - After process restart, hosts enumerate their own persisted waiting checkpoints and rebuild a fresh park with the current drain token. Do not import old Inbox parks, drain tokens, or generation strings. Correlate later responses to the new park and host identity policy. Persisted partial responses may be re-admitted only after protocol/host validation against that fresh park.
117
145
 
146
+ ## Type imports (breaking)
147
+
148
+ Runtime/wire is unchanged. These public type exports were renamed; there are no `Shape` aliases.
149
+
150
+ ```ts
151
+ import type { RunStoreApi } from '@yolk-sdk/harness/store'
152
+ import type { InboxApi } from '@yolk-sdk/harness/inbox'
153
+ import type { DriverApi } from '@yolk-sdk/harness/driver'
154
+ ```
155
+
156
+ | Old type import | New type import |
157
+ | ---------------------------------------------- | --------------- |
158
+ | `RunStoreShape` from `@yolk-sdk/harness/store` | `RunStoreApi` |
159
+ | `InboxShape` from `@yolk-sdk/harness/inbox` | `InboxApi` |
160
+ | `DriverShape` from `@yolk-sdk/harness/driver` | `DriverApi` |
161
+
162
+ ## Owner layers
163
+
164
+ Each service is acquired through its owning static layer factory, which holds the real
165
+ construction logic. The historical `make*` factories keep their signatures and behavior
166
+ and delegate to these canonical owners:
167
+
168
+ | Canonical owner layer | Backward-compatible factory |
169
+ | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
170
+ | `RunStore.inMemoryLayer()` / `snapshotLayer()` | `makeInMemoryRunStoreLayer` / `makeSnapshotRunStoreLayer` |
171
+ | `Inbox.layer()` | `makeInMemoryInboxLayer` |
172
+ | `RunCoordinator.layer()` (claims via `RunStore`) | `makeCoordinator` stays as the scoped doorbell factory |
173
+ | `Driver.layer()` (requires `RunStore` + `Inbox` + `RunCoordinator`) + `Driver.coordinatedLayer()` (default coordinator, lazy options) | `makeDriverLayer` delegates to `coordinatedLayer`, keeping the `RunStore` + `Inbox` requirement |
174
+
175
+ Every factory call builds fresh layers, so composed harnesses never share `Ref` state.
176
+ Within one composed harness, the driver and the merged output share a single store
177
+ instance. `InterruptReason` is owned by `@yolk-sdk/harness/coordinator` and re-exported
178
+ from `@yolk-sdk/harness/driver`.
179
+
118
180
  ## Step outcomes
119
181
 
120
182
  `attemptModelTurn` classifies **one `runModelTurn` invocation** after that stream's configured loop/provider retries. It does not add another retry loop or persist. Hosts that schedule physical attempts themselves should pass `LoopConfig.maxRetries: 0` and skip retry decorators.
@@ -1,8 +1,11 @@
1
- import { Effect, Exit, Scope } from "effect";
1
+ import { RunStore } from "./store.mjs";
2
+ import { Context, Effect, Exit, Layer, Scope } from "effect";
2
3
 
3
4
  //#region src/coordinator.d.ts
4
5
  /** `"input"` subsumes `"steer"` when coalescing wakes. */
5
6
  type Promotable = 'input' | 'steer';
7
+ /** Shutdown retains the claim; explicit user stop releases it after settlement. */
8
+ type InterruptReason = 'user' | 'shutdown';
6
9
  type CapturedRun<E> = {
7
10
  readonly _tag: 'Started';
8
11
  readonly join: Effect.Effect<void, E>;
@@ -57,6 +60,13 @@ declare const makeCoordinator: <Key, E, Reason = never>(options: {
57
60
  readonly started?: (key: Key) => Effect.Effect<void>;
58
61
  readonly settled?: (key: Key, exit: Exit.Exit<void, E>, reason?: Reason) => Effect.Effect<void>;
59
62
  }) => Effect.Effect<Coordinator<Key, E, Reason>, never, Scope.Scope>;
63
+ declare const RunCoordinator_base: Context.ServiceClass<RunCoordinator, "@yolk-sdk/harness/RunCoordinator", Coordinator<string, never, InterruptReason>>;
64
+ /** Owning coordinator layer, with per-acquisition claim receipts and settlement policy. */
65
+ declare class RunCoordinator extends RunCoordinator_base {
66
+ static layer: (options?: {
67
+ readonly drain?: (runId: string, force: boolean, scope: Promotable) => Effect.Effect<void>;
68
+ }) => Layer.Layer<RunCoordinator, never, RunStore>;
69
+ }
60
70
  //#endregion
61
- export { CapturedRun, Coordinator, Promotable, StopReceipt, makeCoordinator };
71
+ export { CapturedRun, Coordinator, InterruptReason, Promotable, RunCoordinator, StopReceipt, makeCoordinator };
62
72
  //# sourceMappingURL=coordinator.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.d.mts","names":[],"sources":["../src/coordinator.ts"],"mappings":";;;;KAmBY,UAAA;AAAA,KAEA,WAAA;EAAA,SACG,IAAA;EAAA,SAA0B,IAAA,EAAM,MAAA,CAAO,MAAA,OAAa,CAAA;AAAA;EAAA,SACpD,IAAA;EAAA,SAAyB,IAAA,EAAM,MAAA,CAAO,MAAA,OAAa,CAAA;AAAA;EAAA,SACnD,IAAA;EAAA,SAA2B,eAAA,EAAiB,MAAA,CAAO,MAAA;AAAA;AAAA,KAEtD,WAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAEH,WAAA;EAAA,SACD,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,GAAA;EAAA,SAClC,QAAA,GAAW,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,WAR9B;EAAA,SAUD,GAAA,GAAM,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,OAAa,CAAA;;;;;;;WAOvC,UAAA,GAAa,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,CAAA,IAb5C;EAAA,SAeR,IAAA,GAAO,GAAA,EAAK,GAAA,EAAK,KAAA,GAAQ,UAAA,KAAe,MAAA,CAAO,MAAA;EAbnC;;;;;EAAA,SAmBZ,SAAA,GACP,GAAA,EAAK,GAAA,EACL,MAAA,GAAS,MAAA,EACT,OAAA;IAAA,SAAqB,eAAA;EAAA,MAClB,MAAA,CAAO,MAAA;EAnBoC;;;;;;;EAAA,SA2BvC,YAAA,GAAe,GAAA,EAAK,GAAA,EAAK,MAAA,EAAQ,MAAA,KAAW,MAAA,CAAO,MAAA,CAAO,WAAA,GAlBlB;EAAA,SAoBxC,SAAA,GAAY,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA;AAAA;AAAA,cAgB9B,eAAA,2BAA2C,OAAA;EAAA,SAC7C,KAAA,GAAQ,GAAA,EAAK,GAAA,EAAK,KAAA,WAAgB,KAAA,EAAO,UAAA,KAAe,MAAA,CAAO,MAAA,OAAa,CAAA;EAAA,SAC5E,OAAA,IAAW,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA;EAAA,SAC/B,OAAA,IAAW,GAAA,EAAK,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,IAAA,OAAW,CAAA,GAAI,MAAA,GAAS,MAAA,KAAW,MAAA,CAAO,MAAA;AAAA,MACjF,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,GAAA,EAAK,CAAA,EAAG,MAAA,UAAgB,KAAA,CAAM,KAAA"}
1
+ {"version":3,"file":"coordinator.d.mts","names":[],"sources":["../src/coordinator.ts"],"mappings":";;;;;KAqBY,UAAA;AAKZ;AAAA,KAFY,eAAA;AAAA,KAEA,WAAA;EAAA,SACG,IAAA;EAAA,SAA0B,IAAA,EAAM,MAAA,CAAO,MAAA,OAAa,CAAA;AAAA;EAAA,SACpD,IAAA;EAAA,SAAyB,IAAA,EAAM,MAAA,CAAO,MAAA,OAAa,CAAA;AAAA;EAAA,SACnD,IAAA;EAAA,SAA2B,eAAA,EAAiB,MAAA,CAAO,MAAA;AAAA;AAAA,KAEtD,WAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAEH,WAAA;EAAA,SACD,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,GAAA;EAAA,SAClC,QAAA,GAAW,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,WAVwB;EAAA,SAYvD,GAAA,GAAM,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,OAAa,CAAA;EAZsB;AAExE;;;;;EAFwE,SAmB7D,UAAA,GAAa,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,CAAA,IAdhD;EAAA,SAgBJ,IAAA,GAAO,GAAA,EAAK,GAAA,EAAK,KAAA,GAAQ,UAAA,KAAe,MAAA,CAAO,MAAA;EAfvC;AAAA;AAEnB;;;EAFmB,SAqBR,SAAA,GACP,GAAA,EAAK,GAAA,EACL,MAAA,GAAS,MAAA,EACT,OAAA;IAAA,SAAqB,eAAA;EAAA,MAClB,MAAA,CAAO,MAAA;EArBa;;;;;;;EAAA,SA6BhB,YAAA,GAAe,GAAA,EAAK,GAAA,EAAK,MAAA,EAAQ,MAAA,KAAW,MAAA,CAAO,MAAA,CAAO,WAAA,GApBhC;EAAA,SAsB1B,SAAA,GAAY,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA;AAAA;AAAA,cAgB9B,eAAA,2BAA2C,OAAA;EAAA,SAC7C,KAAA,GAAQ,GAAA,EAAK,GAAA,EAAK,KAAA,WAAgB,KAAA,EAAO,UAAA,KAAe,MAAA,CAAO,MAAA,OAAa,CAAA;EAAA,SAC5E,OAAA,IAAW,GAAA,EAAK,GAAA,KAAQ,MAAA,CAAO,MAAA;EAAA,SAC/B,OAAA,IAAW,GAAA,EAAK,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,IAAA,OAAW,CAAA,GAAI,MAAA,GAAS,MAAA,KAAW,MAAA,CAAO,MAAA;AAAA,MACjF,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,GAAA,EAAK,CAAA,EAAG,MAAA,UAAgB,KAAA,CAAM,KAAA;AAAA,cAyMxD,mBAAA;;cAGS,cAAA,SAAuB,mBAAA;EAAA,OAI3B,KAAA,GAAS,OAAA;IAAA,SACL,KAAA,IAAS,KAAA,UAAe,KAAA,WAAgB,KAAA,EAAO,UAAA,KAAe,MAAA,CAAO,MAAA;EAAA,MAC5E,KAAA,CAAM,KAAA,CAAM,cAAA,SAAuB,QAAA;AAAA"}
@@ -1,4 +1,6 @@
1
- import { Deferred, Effect, Fiber, FiberSet } from "effect";
1
+ import { StopReceipt } from "./outcome-constructors-internal.mjs";
2
+ import { RunStore } from "./store.mjs";
3
+ import { Cause, Context, Deferred, Effect, Exit, Fiber, FiberSet, Layer } from "effect";
2
4
  //#region src/coordinator.ts
3
5
  /**
4
6
  * Process-local run coordinator.
@@ -103,27 +105,50 @@ const makeCoordinator = (options) => Effect.gen(function* () {
103
105
  }),
104
106
  terminalStop: (key, reason) => Effect.suspend(() => {
105
107
  const execution = executions.get(key);
106
- if (execution === void 0) return Effect.succeed({ _tag: "Idle" });
108
+ if (execution === void 0) return Effect.succeed(StopReceipt.Idle());
107
109
  execution.pendingWake = void 0;
108
110
  if (execution.owner === void 0) {
109
111
  execution.stopping = true;
110
- return Effect.succeed({ _tag: "Settling" });
112
+ return Effect.succeed(StopReceipt.Settling());
111
113
  }
112
114
  execution.interruptionReason = reason;
113
115
  if (execution.stopping) {
114
116
  const request = execution.request;
115
- return request === void 0 ? Effect.succeed({ _tag: "LiveStopping" }) : Fiber.join(request).pipe(Effect.as({ _tag: "LiveStopping" }));
117
+ return request === void 0 ? Effect.succeed(StopReceipt.LiveStopping()) : Fiber.join(request).pipe(Effect.as(StopReceipt.LiveStopping()));
116
118
  }
117
119
  const owner = execution.owner;
118
120
  execution.stopping = true;
119
121
  const request = forkInterruptionRequest(owner);
120
122
  execution.request = request;
121
- return Fiber.join(request).pipe(Effect.as({ _tag: "Interrupted" }));
123
+ return Fiber.join(request).pipe(Effect.as(StopReceipt.Interrupted()));
122
124
  }),
123
125
  awaitIdle
124
126
  };
125
127
  });
128
+ /** Owning coordinator layer, with per-acquisition claim receipts and settlement policy. */
129
+ var RunCoordinator = class extends Context.Service()("@yolk-sdk/harness/RunCoordinator") {
130
+ static layer = (options) => Layer.effect(this, Effect.gen(function* () {
131
+ const store = yield* RunStore;
132
+ const drain = options?.drain ?? ((_runId, _force, _scope) => Effect.void);
133
+ const acquired = /* @__PURE__ */ new Set();
134
+ return yield* makeCoordinator({
135
+ drain,
136
+ started: (runId) => store.claim(runId).pipe(Effect.tap(() => Effect.sync(() => {
137
+ acquired.add(runId);
138
+ }))),
139
+ settled: (runId, exit, reason) => Effect.suspend(() => {
140
+ const owned = acquired.delete(runId);
141
+ if (owned && (reason === "user" || reason === void 0 && !Exit.hasInterrupts(exit))) return store.release(runId);
142
+ if (reason === "user" && !owned) return store.isClaimed(runId).pipe(Effect.flatMap((claimed) => claimed ? store.release(runId) : Effect.void));
143
+ return Effect.void;
144
+ }).pipe(Effect.exit, Effect.flatMap((settledExit) => {
145
+ if (Exit.isSuccess(settledExit)) return Effect.void;
146
+ return Effect.failCause(Exit.isFailure(exit) ? Cause.combine(exit.cause, settledExit.cause) : settledExit.cause);
147
+ }))
148
+ });
149
+ }));
150
+ };
126
151
  //#endregion
127
- export { makeCoordinator };
152
+ export { RunCoordinator, makeCoordinator };
128
153
 
129
154
  //# sourceMappingURL=coordinator.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.mjs","names":[],"sources":["../src/coordinator.ts"],"sourcesContent":["/**\n * Process-local run coordinator.\n *\n * Port of OpenCode v2 `SessionRunCoordinator` (MIT): one busy period per key,\n * a doorbell that coalesces wakes, and interrupt that claims pending wakes so a\n * dead intent cannot restart. Steering lands at the next drain boundary.\n *\n * @see https://github.com/sst/opencode (packages/core/src/session/run-coordinator.ts)\n */\nimport { Deferred, Effect, Fiber, FiberSet } from 'effect'\nimport type { Exit, Scope } from 'effect'\n\n// Private settlement receipt: succeed the Deferred with Exit as a value so\n// interrupt fan-out does not skip Effect 4.0.0-beta.80 Deferred listeners.\n// Public waiters flatten that Exit; this is not a global Deferred fix.\nconst awaitDone = <E>(done: Deferred.Deferred<Exit.Exit<void, E>>): Effect.Effect<void, E> =>\n Deferred.await(done).pipe(Effect.flatMap(exit => exit))\n\n/** `\"input\"` subsumes `\"steer\"` when coalescing wakes. */\nexport type Promotable = 'input' | 'steer'\n\nexport type CapturedRun<E> =\n | { readonly _tag: 'Started'; readonly join: Effect.Effect<void, E> }\n | { readonly _tag: 'Joined'; readonly join: Effect.Effect<void, E> }\n | { readonly _tag: 'Stopping'; readonly awaitSettlement: Effect.Effect<void> }\n\nexport type StopReceipt =\n | { readonly _tag: 'Idle' }\n | { readonly _tag: 'Interrupted' }\n | { readonly _tag: 'LiveStopping' }\n | { readonly _tag: 'Settling' }\n\nexport type Coordinator<Key, E, Reason = never> = {\n readonly active: Effect.Effect<ReadonlySet<Key>>\n readonly isActive: (key: Key) => Effect.Effect<boolean>\n /** Starts an execution while idle, or joins the active execution. */\n readonly run: (key: Key) => Effect.Effect<void, E>\n /**\n * Captures a run waiter without awaiting settlement.\n * Idle starts force=true (`Started`); an active owner is joined (`Joined`),\n * including during natural settlement. A stopping owner yields `Stopping` with a\n * settlement waiter and no start.\n */\n readonly captureRun: (key: Key) => Effect.Effect<CapturedRun<E>>\n /** Rings the doorbell: idle starts; active drains again before settling. */\n readonly wake: (key: Key, scope?: Promotable) => Effect.Effect<void>\n /**\n * Stops the active execution and clears its doorbell. No-op when idle.\n * Resolves once the interruption request is delivered, not when cleanup settles.\n * First accepted `reason` is kept; use `terminalStop` to escalate.\n */\n readonly interrupt: (\n key: Key,\n reason?: Reason,\n options?: { readonly awaitSettlement?: boolean }\n ) => Effect.Effect<boolean>\n /**\n * Terminal stop receipt. Always clears pendingWake. Settling means the owner\n * is already gone and the settled callback is chosen; Driver may release the\n * claim under the Inbox gate. LiveStopping/Interrupted leave release to that\n * owner's future settled callback. LiveStopping joins the same outstanding\n * interruption request rather than forking a second one.\n */\n readonly terminalStop: (key: Key, reason: Reason) => Effect.Effect<StopReceipt>\n /** Resolves once no execution is active. Never starts work. */\n readonly awaitIdle: (key: Key) => Effect.Effect<void>\n}\n\ntype Execution<E, Reason> = {\n readonly done: Deferred.Deferred<Exit.Exit<void, E>>\n owner?: Fiber.Fiber<void>\n request?: Fiber.Fiber<void>\n scope: Promotable\n pendingWake?: Promotable\n stopping: boolean\n interruptionReason?: Reason\n}\n\nconst widerScope = (current: Promotable | undefined, next: Promotable): Promotable =>\n current === 'input' || next === 'input' ? 'input' : 'steer'\n\nexport const makeCoordinator = <Key, E, Reason = never>(options: {\n readonly drain: (key: Key, force: boolean, scope: Promotable) => Effect.Effect<void, E>\n readonly started?: (key: Key) => Effect.Effect<void>\n readonly settled?: (key: Key, exit: Exit.Exit<void, E>, reason?: Reason) => Effect.Effect<void>\n}): Effect.Effect<Coordinator<Key, E, Reason>, never, Scope.Scope> =>\n Effect.gen(function* () {\n const executions = new Map<Key, Execution<E, Reason>>()\n const fork = yield* FiberSet.makeRuntime<never, void, never>()\n\n const loop = (\n key: Key,\n execution: Execution<E, Reason>,\n force: boolean\n ): Effect.Effect<void, E> =>\n Effect.suspend(() => {\n if (execution.stopping) return Effect.void\n return options.drain(key, force, execution.scope)\n }).pipe(\n Effect.andThen(\n Effect.suspend(() => {\n if (execution.stopping || execution.pendingWake === undefined) return Effect.void\n execution.scope = execution.pendingWake\n execution.pendingWake = undefined\n return Effect.yieldNow.pipe(Effect.andThen(loop(key, execution, false)))\n })\n )\n )\n\n const settle = (key: Key, execution: Execution<E, Reason>, exit: Exit.Exit<void, E>) => {\n if (execution.pendingWake !== undefined) start(key, false, execution.pendingWake)\n else executions.delete(key)\n return Deferred.succeed(execution.done, exit).pipe(Effect.asVoid)\n }\n\n const start = (key: Key, force: boolean, scope: Promotable) => {\n const execution: Execution<E, Reason> = {\n done: Deferred.makeUnsafe<Exit.Exit<void, E>>(),\n scope,\n stopping: false\n }\n executions.set(key, execution)\n execution.owner = fork(\n Effect.yieldNow.pipe(\n Effect.andThen(\n Effect.uninterruptible(Effect.suspend(() => options.started?.(key) ?? Effect.void))\n ),\n Effect.andThen(loop(key, execution, force)),\n Effect.onExit(exit =>\n Effect.suspend(() => {\n execution.owner = undefined\n return options.settled?.(key, exit, execution.interruptionReason) ?? Effect.void\n })\n ),\n Effect.onExit(exit => settle(key, execution, exit)),\n Effect.exit,\n Effect.asVoid\n )\n )\n return execution\n }\n\n const forkInterruptionRequest = (owner: Fiber.Fiber<void>): Fiber.Fiber<void> =>\n fork(Effect.yieldNow.pipe(Effect.andThen(Effect.sync(() => owner.interruptUnsafe()))))\n\n const interruptNow = (key: Key, reason?: Reason): Effect.Effect<boolean> =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n if (execution === undefined || execution.stopping) return Effect.succeed(false)\n if (execution.owner === undefined) {\n execution.pendingWake = undefined\n return Effect.succeed(false)\n }\n const owner = execution.owner\n execution.stopping = true\n execution.pendingWake = undefined\n execution.interruptionReason = reason\n // Capture the exact old owner and fork the request in this same lazy\n // transition so cancellation cannot leave stopping=true with no request.\n // Initial yield breaks owner -> resumed caller -> owner reentrancy.\n // Join the request fiber only; interruptUnsafe may run interruptible\n // finalizers inline until they suspend. Do not await owner settlement.\n const request = forkInterruptionRequest(owner)\n execution.request = request\n return Fiber.join(request).pipe(Effect.as(true))\n })\n\n const awaitIdle = (key: Key): Effect.Effect<void> =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n if (execution === undefined) return Effect.void\n return awaitDone(execution.done).pipe(Effect.ignoreCause, Effect.andThen(awaitIdle(key)))\n })\n\n return {\n active: Effect.sync(() => new Set(executions.keys())),\n isActive: key => Effect.sync(() => executions.has(key)),\n run: key =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n if (execution === undefined) return awaitDone(start(key, true, 'input').done)\n if (!execution.stopping) return awaitDone(execution.done)\n return awaitDone(execution.done).pipe(\n Effect.ignoreCause,\n Effect.andThen(\n Effect.suspend(() => {\n const next = executions.get(key)\n return next === undefined\n ? awaitDone(start(key, true, 'input').done)\n : awaitDone(next.done)\n })\n )\n )\n }),\n captureRun: key =>\n Effect.sync(() => {\n const execution = executions.get(key)\n if (execution === undefined) {\n const started = start(key, true, 'input')\n return { _tag: 'Started' as const, join: awaitDone(started.done) }\n }\n if (!execution.stopping) {\n return { _tag: 'Joined' as const, join: awaitDone(execution.done) }\n }\n return {\n _tag: 'Stopping' as const,\n awaitSettlement: awaitDone(execution.done).pipe(Effect.ignoreCause)\n }\n }),\n wake: (key, scope = 'input') =>\n Effect.sync(() => {\n const execution = executions.get(key)\n if (execution !== undefined) {\n execution.pendingWake = widerScope(execution.pendingWake, scope)\n return\n }\n start(key, false, scope)\n }),\n interrupt: (key, reason, options) =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n return interruptNow(key, reason).pipe(\n Effect.tap(() =>\n options?.awaitSettlement === true && execution !== undefined\n ? awaitDone(execution.done).pipe(Effect.ignoreCause)\n : Effect.void\n )\n )\n }),\n terminalStop: (key, reason) =>\n Effect.suspend((): Effect.Effect<StopReceipt> => {\n const execution = executions.get(key)\n if (execution === undefined) return Effect.succeed({ _tag: 'Idle' } as const)\n execution.pendingWake = undefined\n if (execution.owner === undefined) {\n execution.stopping = true\n return Effect.succeed({ _tag: 'Settling' } as const)\n }\n execution.interruptionReason = reason\n if (execution.stopping) {\n const request = execution.request\n return request === undefined\n ? Effect.succeed({ _tag: 'LiveStopping' } as const)\n : Fiber.join(request).pipe(Effect.as({ _tag: 'LiveStopping' } as const))\n }\n const owner = execution.owner\n execution.stopping = true\n const request = forkInterruptionRequest(owner)\n execution.request = request\n return Fiber.join(request).pipe(Effect.as({ _tag: 'Interrupted' } as const))\n }),\n awaitIdle\n }\n })\n"],"mappings":"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"}
1
+ {"version":3,"file":"coordinator.mjs","names":["stopReceipt"],"sources":["../src/coordinator.ts"],"sourcesContent":["/**\n * Process-local run coordinator.\n *\n * Port of OpenCode v2 `SessionRunCoordinator` (MIT): one busy period per key,\n * a doorbell that coalesces wakes, and interrupt that claims pending wakes so a\n * dead intent cannot restart. Steering lands at the next drain boundary.\n *\n * @see https://github.com/sst/opencode (packages/core/src/session/run-coordinator.ts)\n */\nimport { Cause, Context, Deferred, Effect, Exit, Fiber, FiberSet, Layer } from 'effect'\nimport type { Scope } from 'effect'\nimport { StopReceipt as stopReceipt } from './outcome-constructors-internal.ts'\nimport { RunStore } from './store.ts'\n\n// Private settlement receipt: succeed the Deferred with Exit as a value so\n// interrupt fan-out does not skip Effect 4.0.0-beta.80 Deferred listeners.\n// Public waiters flatten that Exit; this is not a global Deferred fix.\nconst awaitDone = <E>(done: Deferred.Deferred<Exit.Exit<void, E>>): Effect.Effect<void, E> =>\n Deferred.await(done).pipe(Effect.flatMap(exit => exit))\n\n/** `\"input\"` subsumes `\"steer\"` when coalescing wakes. */\nexport type Promotable = 'input' | 'steer'\n\n/** Shutdown retains the claim; explicit user stop releases it after settlement. */\nexport type InterruptReason = 'user' | 'shutdown'\n\nexport type CapturedRun<E> =\n | { readonly _tag: 'Started'; readonly join: Effect.Effect<void, E> }\n | { readonly _tag: 'Joined'; readonly join: Effect.Effect<void, E> }\n | { readonly _tag: 'Stopping'; readonly awaitSettlement: Effect.Effect<void> }\n\nexport type StopReceipt =\n | { readonly _tag: 'Idle' }\n | { readonly _tag: 'Interrupted' }\n | { readonly _tag: 'LiveStopping' }\n | { readonly _tag: 'Settling' }\n\nexport type Coordinator<Key, E, Reason = never> = {\n readonly active: Effect.Effect<ReadonlySet<Key>>\n readonly isActive: (key: Key) => Effect.Effect<boolean>\n /** Starts an execution while idle, or joins the active execution. */\n readonly run: (key: Key) => Effect.Effect<void, E>\n /**\n * Captures a run waiter without awaiting settlement.\n * Idle starts force=true (`Started`); an active owner is joined (`Joined`),\n * including during natural settlement. A stopping owner yields `Stopping` with a\n * settlement waiter and no start.\n */\n readonly captureRun: (key: Key) => Effect.Effect<CapturedRun<E>>\n /** Rings the doorbell: idle starts; active drains again before settling. */\n readonly wake: (key: Key, scope?: Promotable) => Effect.Effect<void>\n /**\n * Stops the active execution and clears its doorbell. No-op when idle.\n * Resolves once the interruption request is delivered, not when cleanup settles.\n * First accepted `reason` is kept; use `terminalStop` to escalate.\n */\n readonly interrupt: (\n key: Key,\n reason?: Reason,\n options?: { readonly awaitSettlement?: boolean }\n ) => Effect.Effect<boolean>\n /**\n * Terminal stop receipt. Always clears pendingWake. Settling means the owner\n * is already gone and the settled callback is chosen; Driver may release the\n * claim under the Inbox gate. LiveStopping/Interrupted leave release to that\n * owner's future settled callback. LiveStopping joins the same outstanding\n * interruption request rather than forking a second one.\n */\n readonly terminalStop: (key: Key, reason: Reason) => Effect.Effect<StopReceipt>\n /** Resolves once no execution is active. Never starts work. */\n readonly awaitIdle: (key: Key) => Effect.Effect<void>\n}\n\ntype Execution<E, Reason> = {\n readonly done: Deferred.Deferred<Exit.Exit<void, E>>\n owner?: Fiber.Fiber<void>\n request?: Fiber.Fiber<void>\n scope: Promotable\n pendingWake?: Promotable\n stopping: boolean\n interruptionReason?: Reason\n}\n\nconst widerScope = (current: Promotable | undefined, next: Promotable): Promotable =>\n current === 'input' || next === 'input' ? 'input' : 'steer'\n\nexport const makeCoordinator = <Key, E, Reason = never>(options: {\n readonly drain: (key: Key, force: boolean, scope: Promotable) => Effect.Effect<void, E>\n readonly started?: (key: Key) => Effect.Effect<void>\n readonly settled?: (key: Key, exit: Exit.Exit<void, E>, reason?: Reason) => Effect.Effect<void>\n}): Effect.Effect<Coordinator<Key, E, Reason>, never, Scope.Scope> =>\n Effect.gen(function* () {\n const executions = new Map<Key, Execution<E, Reason>>()\n const fork = yield* FiberSet.makeRuntime<never, void, never>()\n\n const loop = (\n key: Key,\n execution: Execution<E, Reason>,\n force: boolean\n ): Effect.Effect<void, E> =>\n Effect.suspend(() => {\n if (execution.stopping) return Effect.void\n\n return options.drain(key, force, execution.scope)\n }).pipe(\n Effect.andThen(\n Effect.suspend(() => {\n if (execution.stopping || execution.pendingWake === undefined) return Effect.void\n execution.scope = execution.pendingWake\n execution.pendingWake = undefined\n\n return Effect.yieldNow.pipe(Effect.andThen(loop(key, execution, false)))\n })\n )\n )\n\n const settle = (key: Key, execution: Execution<E, Reason>, exit: Exit.Exit<void, E>) => {\n if (execution.pendingWake !== undefined) start(key, false, execution.pendingWake)\n else executions.delete(key)\n\n return Deferred.succeed(execution.done, exit).pipe(Effect.asVoid)\n }\n\n const start = (key: Key, force: boolean, scope: Promotable) => {\n const execution: Execution<E, Reason> = {\n done: Deferred.makeUnsafe<Exit.Exit<void, E>>(),\n scope,\n stopping: false\n }\n\n executions.set(key, execution)\n execution.owner = fork(\n Effect.yieldNow.pipe(\n Effect.andThen(\n Effect.uninterruptible(Effect.suspend(() => options.started?.(key) ?? Effect.void))\n ),\n Effect.andThen(loop(key, execution, force)),\n Effect.onExit(exit =>\n Effect.suspend(() => {\n execution.owner = undefined\n\n return options.settled?.(key, exit, execution.interruptionReason) ?? Effect.void\n })\n ),\n Effect.onExit(exit => settle(key, execution, exit)),\n Effect.exit,\n Effect.asVoid\n )\n )\n\n return execution\n }\n\n const forkInterruptionRequest = (owner: Fiber.Fiber<void>): Fiber.Fiber<void> =>\n fork(Effect.yieldNow.pipe(Effect.andThen(Effect.sync(() => owner.interruptUnsafe()))))\n\n const interruptNow = (key: Key, reason?: Reason): Effect.Effect<boolean> =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n\n if (execution === undefined || execution.stopping) return Effect.succeed(false)\n\n if (execution.owner === undefined) {\n execution.pendingWake = undefined\n\n return Effect.succeed(false)\n }\n\n const owner = execution.owner\n execution.stopping = true\n execution.pendingWake = undefined\n execution.interruptionReason = reason\n // Capture the exact old owner and fork the request in this same lazy\n // transition so cancellation cannot leave stopping=true with no request.\n // Initial yield breaks owner -> resumed caller -> owner reentrancy.\n // Join the request fiber only; interruptUnsafe may run interruptible\n // finalizers inline until they suspend. Do not await owner settlement.\n const request = forkInterruptionRequest(owner)\n execution.request = request\n\n return Fiber.join(request).pipe(Effect.as(true))\n })\n\n const awaitIdle = (key: Key): Effect.Effect<void> =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n\n if (execution === undefined) return Effect.void\n\n return awaitDone(execution.done).pipe(Effect.ignoreCause, Effect.andThen(awaitIdle(key)))\n })\n\n return {\n active: Effect.sync(() => new Set(executions.keys())),\n isActive: key => Effect.sync(() => executions.has(key)),\n run: key =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n\n if (execution === undefined) return awaitDone(start(key, true, 'input').done)\n\n if (!execution.stopping) return awaitDone(execution.done)\n\n return awaitDone(execution.done).pipe(\n Effect.ignoreCause,\n Effect.andThen(\n Effect.suspend(() => {\n const next = executions.get(key)\n\n return next === undefined\n ? awaitDone(start(key, true, 'input').done)\n : awaitDone(next.done)\n })\n )\n )\n }),\n captureRun: key =>\n Effect.sync(() => {\n const execution = executions.get(key)\n\n if (execution === undefined) {\n const started = start(key, true, 'input')\n\n return { _tag: 'Started' as const, join: awaitDone(started.done) }\n }\n\n if (!execution.stopping) {\n return { _tag: 'Joined' as const, join: awaitDone(execution.done) }\n }\n\n return {\n _tag: 'Stopping' as const,\n awaitSettlement: awaitDone(execution.done).pipe(Effect.ignoreCause)\n }\n }),\n wake: (key, scope = 'input') =>\n Effect.sync(() => {\n const execution = executions.get(key)\n\n if (execution !== undefined) {\n execution.pendingWake = widerScope(execution.pendingWake, scope)\n\n return\n }\n\n start(key, false, scope)\n }),\n interrupt: (key, reason, options) =>\n Effect.suspend(() => {\n const execution = executions.get(key)\n\n return interruptNow(key, reason).pipe(\n Effect.tap(() =>\n options?.awaitSettlement === true && execution !== undefined\n ? awaitDone(execution.done).pipe(Effect.ignoreCause)\n : Effect.void\n )\n )\n }),\n terminalStop: (key, reason) =>\n Effect.suspend((): Effect.Effect<StopReceipt> => {\n const execution = executions.get(key)\n\n if (execution === undefined) return Effect.succeed(stopReceipt.Idle())\n execution.pendingWake = undefined\n\n if (execution.owner === undefined) {\n execution.stopping = true\n\n return Effect.succeed(stopReceipt.Settling())\n }\n\n execution.interruptionReason = reason\n\n if (execution.stopping) {\n const request = execution.request\n\n return request === undefined\n ? Effect.succeed(stopReceipt.LiveStopping())\n : Fiber.join(request).pipe(Effect.as(stopReceipt.LiveStopping()))\n }\n\n const owner = execution.owner\n execution.stopping = true\n const request = forkInterruptionRequest(owner)\n execution.request = request\n\n return Fiber.join(request).pipe(Effect.as(stopReceipt.Interrupted()))\n }),\n awaitIdle\n }\n })\n\n/** Owning coordinator layer, with per-acquisition claim receipts and settlement policy. */\nexport class RunCoordinator extends Context.Service<\n RunCoordinator,\n Coordinator<string, never, InterruptReason>\n>()('@yolk-sdk/harness/RunCoordinator') {\n static layer = (options?: {\n readonly drain?: (runId: string, force: boolean, scope: Promotable) => Effect.Effect<void>\n }): Layer.Layer<RunCoordinator, never, RunStore> =>\n Layer.effect(\n this,\n Effect.gen(function* () {\n const store = yield* RunStore\n const drain = options?.drain ?? ((_runId, _force, _scope) => Effect.void)\n const acquired = new Set<string>()\n\n return yield* makeCoordinator<string, never, InterruptReason>({\n drain,\n started: runId =>\n store.claim(runId).pipe(\n Effect.tap(() =>\n Effect.sync(() => {\n acquired.add(runId)\n })\n )\n ),\n settled: (runId, exit, reason) =>\n Effect.suspend(() => {\n const owned = acquired.delete(runId)\n\n if (\n owned &&\n (reason === 'user' || (reason === undefined && !Exit.hasInterrupts(exit)))\n ) {\n return store.release(runId)\n }\n\n // Acquisition receipt guards automatic failed-start settlement only.\n // Explicit user-terminal authority still releases a leftover claim\n // after this owner has actually settled, matching Idle/Settling stop.\n if (reason === 'user' && !owned) {\n return store\n .isClaimed(runId)\n .pipe(Effect.flatMap(claimed => (claimed ? store.release(runId) : Effect.void)))\n }\n\n return Effect.void\n }).pipe(\n Effect.exit,\n Effect.flatMap(settledExit => {\n if (Exit.isSuccess(settledExit)) return Effect.void\n\n return Effect.failCause(\n Exit.isFailure(exit)\n ? Cause.combine(exit.cause, settledExit.cause)\n : settledExit.cause\n )\n })\n )\n })\n })\n )\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { Inbox } from "../inbox.mjs";
2
1
  import { DurableRunStoreSnapshot, RunStore } from "../store.mjs";
2
+ import { Inbox } from "../inbox.mjs";
3
3
  import { Drain, Driver, InvalidMaxResumeAttempts } from "../driver.mjs";
4
4
  import { Effect, Layer } from "effect";
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"durable-object.d.mts","names":[],"sources":["../../src/driver/durable-object.ts"],"mappings":";;;;;;KAcK,uBAAA;EAAA,SACM,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,uBAAA;EAAA,SACpB,IAAA,GAAO,QAAA,EAAU,uBAAA,KAA4B,MAAA,CAAO,MAAA;EAAA,SACpD,KAAA,GAAQ,KAAA;AAAA;AAAA,iBAGH,4BAAA,CACd,OAAA,EAAS,uBAAA;EAAA,SAAqC,iBAAA;AAAA,IAC7C,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBACnB,4BAAA,CACd,OAAA,EAAS,uBAAA;EAAA,SAAqC,iBAAA;AAAA,IAC7C,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA,EAAO,wBAAA"}
1
+ {"version":3,"file":"durable-object.d.mts","names":[],"sources":["../../src/driver/durable-object.ts"],"mappings":";;;;;;KAQK,uBAAA;EAAA,SACM,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,uBAAA;EAAA,SACpB,IAAA,GAAO,QAAA,EAAU,uBAAA,KAA4B,MAAA,CAAO,MAAA;EAAA,SACpD,KAAA,GAAQ,KAAA;AAAA;AAAA,iBAGH,4BAAA,CACd,OAAA,EAAS,uBAAA;EAAA,SAAqC,iBAAA;AAAA,IAC7C,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBACnB,4BAAA,CACd,OAAA,EAAS,uBAAA;EAAA,SAAqC,iBAAA;AAAA,IAC7C,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA,EAAO,wBAAA"}
@@ -1,10 +1,10 @@
1
- import { makeInMemoryInboxLayer } from "../inbox.mjs";
2
- import { makeSnapshotRunStoreLayer } from "../store.mjs";
3
- import { makeDriverLayer } from "../driver.mjs";
1
+ import { RunStore } from "../store.mjs";
2
+ import { Inbox } from "../inbox.mjs";
3
+ import { Driver } from "../driver.mjs";
4
4
  import { Layer } from "effect";
5
5
  //#region src/driver/durable-object.ts
6
6
  function makeDurableObjectDriverLayer(options) {
7
- return makeDriverLayer(options).pipe(Layer.provideMerge(makeSnapshotRunStoreLayer(options)), Layer.provideMerge(makeInMemoryInboxLayer()));
7
+ return Driver.coordinatedLayer(options).pipe(Layer.provideMerge(RunStore.snapshotLayer(options)), Layer.provideMerge(Inbox.layer()));
8
8
  }
9
9
  //#endregion
10
10
  export { makeDurableObjectDriverLayer };
@@ -1 +1 @@
1
- {"version":3,"file":"durable-object.mjs","names":[],"sources":["../../src/driver/durable-object.ts"],"sourcesContent":["import { Layer } from 'effect'\nimport type { Effect } from 'effect'\nimport {\n makeDriverLayer,\n type Drain,\n type Driver,\n type InvalidMaxResumeAttempts\n} from '../driver.ts'\nimport { makeInMemoryInboxLayer } from '../inbox.ts'\nimport type { Inbox } from '../inbox.ts'\nimport { makeSnapshotRunStoreLayer, type DurableRunStoreSnapshot, type RunStore } from '../store.ts'\n\nexport type { DurableRunStoreSnapshot }\n\ntype DurableObjectDriverBase = {\n readonly load: Effect.Effect<DurableRunStoreSnapshot | undefined>\n readonly save: (snapshot: DurableRunStoreSnapshot) => Effect.Effect<void>\n readonly drain?: Drain\n}\n\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: undefined }\n): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: number }\n): Layer.Layer<Driver | RunStore | Inbox, InvalidMaxResumeAttempts>\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: number }\n) {\n return makeDriverLayer(options).pipe(\n Layer.provideMerge(makeSnapshotRunStoreLayer(options)),\n Layer.provideMerge(makeInMemoryInboxLayer())\n )\n}\n"],"mappings":";;;;;AA0BA,SAAgB,6BACd,SACA;CACA,OAAO,gBAAgB,OAAO,EAAE,KAC9B,MAAM,aAAa,0BAA0B,OAAO,CAAC,GACrD,MAAM,aAAa,uBAAuB,CAAC,CAC7C;AACF"}
1
+ {"version":3,"file":"durable-object.mjs","names":[],"sources":["../../src/driver/durable-object.ts"],"sourcesContent":["import { Layer } from 'effect'\nimport type { Effect } from 'effect'\nimport { Driver, type Drain, type InvalidMaxResumeAttempts } from '../driver.ts'\nimport { Inbox } from '../inbox.ts'\nimport { RunStore, type DurableRunStoreSnapshot } from '../store.ts'\n\nexport type { DurableRunStoreSnapshot }\n\ntype DurableObjectDriverBase = {\n readonly load: Effect.Effect<DurableRunStoreSnapshot | undefined>\n readonly save: (snapshot: DurableRunStoreSnapshot) => Effect.Effect<void>\n readonly drain?: Drain\n}\n\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: undefined }\n): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: number }\n): Layer.Layer<Driver | RunStore | Inbox, InvalidMaxResumeAttempts>\nexport function makeDurableObjectDriverLayer(\n options: DurableObjectDriverBase & { readonly maxResumeAttempts?: number }\n) {\n return Driver.coordinatedLayer(options).pipe(\n Layer.provideMerge(RunStore.snapshotLayer(options)),\n Layer.provideMerge(Inbox.layer())\n )\n}\n"],"mappings":";;;;;AAoBA,SAAgB,6BACd,SACA;CACA,OAAO,OAAO,iBAAiB,OAAO,EAAE,KACtC,MAAM,aAAa,SAAS,cAAc,OAAO,CAAC,GAClD,MAAM,aAAa,MAAM,MAAM,CAAC,CAClC;AACF"}
@@ -1,5 +1,5 @@
1
- import { Inbox } from "../inbox.mjs";
2
1
  import { RunStore } from "../store.mjs";
2
+ import { Inbox } from "../inbox.mjs";
3
3
  import { Drain, Driver, DriverLayerOptions, InvalidMaxResumeAttempts } from "../driver.mjs";
4
4
  import { Layer } from "effect";
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/driver/memory.ts"],"mappings":";;;;;;iBAWgB,uBAAA,CAAA,GAA2B,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBACjE,uBAAA,CAAwB,OAAA;EAAA,SAC7B,KAAA,GAAQ,KAAA;EAAA,SACR,iBAAA;AAAA,IACP,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBAC1B,uBAAA,CACd,OAAA,GAAU,kBAAA,GACT,KAAA,CAAM,KAAA,CAAM,MAAA,EAAQ,wBAAA,EAA0B,QAAA,GAAW,KAAA;AAAA,iBAK5C,wBAAA,CAAA,GAA4B,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBAC5D,wBAAA,CAAyB,OAAA;EAAA,SAC9B,KAAA,GAAQ,KAAA;EAAA,SACR,iBAAA;AAAA,IACP,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBACpB,wBAAA,CACd,OAAA,GAAU,kBAAA,GACT,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA,EAAO,wBAAA"}
1
+ {"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/driver/memory.ts"],"mappings":";;;;;;iBAUgB,uBAAA,CAAA,GAA2B,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBACjE,uBAAA,CAAwB,OAAA;EAAA,SAC7B,KAAA,GAAQ,KAAA;EAAA,SACR,iBAAA;AAAA,IACP,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBAC1B,uBAAA,CACd,OAAA,GAAU,kBAAA,GACT,KAAA,CAAM,KAAA,CAAM,MAAA,EAAQ,wBAAA,EAA0B,QAAA,GAAW,KAAA;AAAA,iBAK5C,wBAAA,CAAA,GAA4B,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBAC5D,wBAAA,CAAyB,OAAA;EAAA,SAC9B,KAAA,GAAQ,KAAA;EAAA,SACR,iBAAA;AAAA,IACP,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA;AAAA,iBACpB,wBAAA,CACd,OAAA,GAAU,kBAAA,GACT,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA,EAAO,wBAAA"}
@@ -1,13 +1,13 @@
1
- import { makeInMemoryInboxLayer } from "../inbox.mjs";
2
- import { makeInMemoryRunStoreLayer } from "../store.mjs";
3
- import { makeDriverLayer } from "../driver.mjs";
1
+ import { RunStore } from "../store.mjs";
2
+ import { Inbox } from "../inbox.mjs";
3
+ import { Driver } from "../driver.mjs";
4
4
  import { Layer } from "effect";
5
5
  //#region src/driver/memory.ts
6
6
  function makeInMemoryDriverLayer(options) {
7
- return options === void 0 ? makeDriverLayer() : makeDriverLayer(options);
7
+ return options === void 0 ? Driver.coordinatedLayer() : Driver.coordinatedLayer(options);
8
8
  }
9
9
  function makeInMemoryHarnessLayer(options) {
10
- return (options === void 0 ? makeDriverLayer() : makeDriverLayer(options)).pipe(Layer.provideMerge(makeInMemoryRunStoreLayer()), Layer.provideMerge(makeInMemoryInboxLayer()));
10
+ return (options === void 0 ? Driver.coordinatedLayer() : Driver.coordinatedLayer(options)).pipe(Layer.provideMerge(RunStore.inMemoryLayer()), Layer.provideMerge(Inbox.layer()));
11
11
  }
12
12
  //#endregion
13
13
  export { makeInMemoryDriverLayer, makeInMemoryHarnessLayer };
@@ -1 +1 @@
1
- {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/driver/memory.ts"],"sourcesContent":["import { Layer } from 'effect'\nimport {\n makeDriverLayer,\n type Drain,\n type Driver,\n type DriverLayerOptions,\n type InvalidMaxResumeAttempts\n} from '../driver.ts'\nimport { makeInMemoryInboxLayer, type Inbox } from '../inbox.ts'\nimport { makeInMemoryRunStoreLayer, type RunStore } from '../store.ts'\n\nexport function makeInMemoryDriverLayer(): Layer.Layer<Driver, never, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(options?: {\n readonly drain?: Drain\n readonly maxResumeAttempts?: undefined\n}): Layer.Layer<Driver, never, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(\n options?: DriverLayerOptions\n): Layer.Layer<Driver, InvalidMaxResumeAttempts, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(options?: DriverLayerOptions) {\n return options === undefined ? makeDriverLayer() : makeDriverLayer(options)\n}\n\nexport function makeInMemoryHarnessLayer(): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeInMemoryHarnessLayer(options?: {\n readonly drain?: Drain\n readonly maxResumeAttempts?: undefined\n}): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeInMemoryHarnessLayer(\n options?: DriverLayerOptions\n): Layer.Layer<Driver | RunStore | Inbox, InvalidMaxResumeAttempts>\nexport function makeInMemoryHarnessLayer(options?: DriverLayerOptions) {\n const driver = options === undefined ? makeDriverLayer() : makeDriverLayer(options)\n return driver.pipe(\n Layer.provideMerge(makeInMemoryRunStoreLayer()),\n Layer.provideMerge(makeInMemoryInboxLayer())\n )\n}\n"],"mappings":";;;;;AAmBA,SAAgB,wBAAwB,SAA8B;CACpE,OAAO,YAAY,KAAA,IAAY,gBAAgB,IAAI,gBAAgB,OAAO;AAC5E;AAUA,SAAgB,yBAAyB,SAA8B;CAErE,QADe,YAAY,KAAA,IAAY,gBAAgB,IAAI,gBAAgB,OAAO,GACpE,KACZ,MAAM,aAAa,0BAA0B,CAAC,GAC9C,MAAM,aAAa,uBAAuB,CAAC,CAC7C;AACF"}
1
+ {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/driver/memory.ts"],"sourcesContent":["import { Layer } from 'effect'\nimport {\n Driver,\n type Drain,\n type DriverLayerOptions,\n type InvalidMaxResumeAttempts\n} from '../driver.ts'\nimport { Inbox } from '../inbox.ts'\nimport { RunStore } from '../store.ts'\n\nexport function makeInMemoryDriverLayer(): Layer.Layer<Driver, never, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(options?: {\n readonly drain?: Drain\n readonly maxResumeAttempts?: undefined\n}): Layer.Layer<Driver, never, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(\n options?: DriverLayerOptions\n): Layer.Layer<Driver, InvalidMaxResumeAttempts, RunStore | Inbox>\nexport function makeInMemoryDriverLayer(options?: DriverLayerOptions) {\n return options === undefined ? Driver.coordinatedLayer() : Driver.coordinatedLayer(options)\n}\n\nexport function makeInMemoryHarnessLayer(): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeInMemoryHarnessLayer(options?: {\n readonly drain?: Drain\n readonly maxResumeAttempts?: undefined\n}): Layer.Layer<Driver | RunStore | Inbox>\nexport function makeInMemoryHarnessLayer(\n options?: DriverLayerOptions\n): Layer.Layer<Driver | RunStore | Inbox, InvalidMaxResumeAttempts>\nexport function makeInMemoryHarnessLayer(options?: DriverLayerOptions) {\n const driver =\n options === undefined ? Driver.coordinatedLayer() : Driver.coordinatedLayer(options)\n\n return driver.pipe(\n Layer.provideMerge(RunStore.inMemoryLayer()),\n Layer.provideMerge(Inbox.layer())\n )\n}\n"],"mappings":";;;;;AAkBA,SAAgB,wBAAwB,SAA8B;CACpE,OAAO,YAAY,KAAA,IAAY,OAAO,iBAAiB,IAAI,OAAO,iBAAiB,OAAO;AAC5F;AAUA,SAAgB,yBAAyB,SAA8B;CAIrE,QAFE,YAAY,KAAA,IAAY,OAAO,iBAAiB,IAAI,OAAO,iBAAiB,OAAO,GAEvE,KACZ,MAAM,aAAa,SAAS,cAAc,CAAC,GAC3C,MAAM,aAAa,MAAM,MAAM,CAAC,CAClC;AACF"}
package/dist/driver.d.mts CHANGED
@@ -1,12 +1,11 @@
1
- import { Promotable } from "./coordinator.mjs";
2
- import { HitlAdmission, HitlDecision, Inbox, InboxItem, ParkedResponse, PauseDecision } from "./inbox.mjs";
3
1
  import { RunStore } from "./store.mjs";
4
- import { Cause, Context, Effect, Layer } from "effect";
2
+ import { InterruptReason, Promotable, RunCoordinator } from "./coordinator.mjs";
3
+ import { HitlAdmission, HitlDecision, Inbox, InboxItem, ParkedResponse, PauseDecision } from "./inbox.mjs";
4
+ import { Context, Data, Effect, Layer } from "effect";
5
5
 
6
6
  //#region src/driver.d.ts
7
- type InterruptReason = 'user' | 'shutdown';
8
7
  declare const defaultMaxResumeAttempts = 10;
9
- declare const InvalidMaxResumeAttempts_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] }>) => Cause.YieldableError & {
8
+ declare const InvalidMaxResumeAttempts_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 & {
10
9
  readonly _tag: "InvalidMaxResumeAttempts";
11
10
  } & Readonly<A>;
12
11
  declare class InvalidMaxResumeAttempts extends InvalidMaxResumeAttempts_base<{
@@ -32,7 +31,55 @@ type StopDecision = {
32
31
  } | {
33
32
  readonly _tag: 'Idle';
34
33
  };
35
- type DriverShape = {
34
+ declare const StopDecision: {
35
+ readonly Interrupted: Data.TaggedEnum.ConstructorFrom<{
36
+ readonly _tag: "Interrupted";
37
+ }, "_tag">;
38
+ readonly ParkCleared: Data.TaggedEnum.ConstructorFrom<{
39
+ readonly _tag: "ParkCleared";
40
+ }, "_tag">;
41
+ readonly Idle: Data.TaggedEnum.ConstructorFrom<{
42
+ readonly _tag: "Idle";
43
+ }, "_tag">;
44
+ readonly $is: <Tag extends "Interrupted" | "ParkCleared" | "Idle">(tag: Tag) => (u: unknown) => u is Extract<{
45
+ readonly _tag: "Interrupted";
46
+ }, {
47
+ readonly _tag: Tag;
48
+ }> | Extract<{
49
+ readonly _tag: "ParkCleared";
50
+ }, {
51
+ readonly _tag: Tag;
52
+ }> | Extract<{
53
+ readonly _tag: "Idle";
54
+ }, {
55
+ readonly _tag: Tag;
56
+ }>;
57
+ readonly $match: {
58
+ <Cases extends {
59
+ readonly Interrupted: (args: {
60
+ readonly _tag: "Interrupted";
61
+ }) => any;
62
+ readonly ParkCleared: (args: {
63
+ readonly _tag: "ParkCleared";
64
+ }) => any;
65
+ readonly Idle: (args: {
66
+ readonly _tag: "Idle";
67
+ }) => any;
68
+ }>(cases: Cases): (value: StopDecision) => import("effect/Unify").Unify<ReturnType<Cases["Interrupted" | "ParkCleared" | "Idle"]>>;
69
+ <Cases extends {
70
+ readonly Interrupted: (args: {
71
+ readonly _tag: "Interrupted";
72
+ }) => any;
73
+ readonly ParkCleared: (args: {
74
+ readonly _tag: "ParkCleared";
75
+ }) => any;
76
+ readonly Idle: (args: {
77
+ readonly _tag: "Idle";
78
+ }) => any;
79
+ }>(value: StopDecision, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Interrupted" | "ParkCleared" | "Idle"]>>;
80
+ };
81
+ };
82
+ type DriverApi = {
36
83
  readonly active: Effect.Effect<ReadonlySet<string>>;
37
84
  readonly isActive: (runId: string) => Effect.Effect<boolean>;
38
85
  readonly run: (runId: string) => Effect.Effect<void>;
@@ -48,8 +95,20 @@ type DriverShape = {
48
95
  readonly resumeHitl: (runId: string, admission: HitlAdmission) => Effect.Effect<HitlDecision>;
49
96
  readonly stop: (runId: string) => Effect.Effect<StopDecision>;
50
97
  };
51
- declare const Driver_base: Context.ServiceClass<Driver, "@yolk-sdk/harness/Driver", DriverShape>;
52
- declare class Driver extends Driver_base {}
98
+ declare const Driver_base: Context.ServiceClass<Driver, "@yolk-sdk/harness/Driver", DriverApi>;
99
+ declare class Driver extends Driver_base {
100
+ static layer(): Layer.Layer<Driver, never, RunStore | Inbox | RunCoordinator>;
101
+ static layer(options?: {
102
+ readonly maxResumeAttempts?: undefined;
103
+ }): Layer.Layer<Driver, never, RunStore | Inbox | RunCoordinator>;
104
+ static layer(options?: Pick<DriverLayerOptions, 'maxResumeAttempts'>): Layer.Layer<Driver, InvalidMaxResumeAttempts, RunStore | Inbox | RunCoordinator>;
105
+ static coordinatedLayer(): Layer.Layer<Driver, never, RunStore | Inbox>;
106
+ static coordinatedLayer(options?: {
107
+ readonly drain?: Drain;
108
+ readonly maxResumeAttempts?: undefined;
109
+ }): Layer.Layer<Driver, never, RunStore | Inbox>;
110
+ static coordinatedLayer(options?: DriverLayerOptions): Layer.Layer<Driver, InvalidMaxResumeAttempts, RunStore | Inbox>;
111
+ }
53
112
  declare const makeHarness: <DE, DR, SE, SR, IE, IR>(input: {
54
113
  readonly driver: Layer.Layer<Driver, DE, DR>;
55
114
  readonly store: Layer.Layer<RunStore, SE, SR>;
@@ -63,5 +122,5 @@ declare function makeDriverLayer(options?: {
63
122
  }): Layer.Layer<Driver, never, RunStore | Inbox>;
64
123
  declare function makeDriverLayer(options?: DriverLayerOptions): Layer.Layer<Driver, InvalidMaxResumeAttempts, RunStore | Inbox>;
65
124
  //#endregion
66
- export { Drain, DrainContext, Driver, DriverLayerOptions, DriverShape, InterruptReason, InvalidMaxResumeAttempts, ResumeSuspendedResult, StopDecision, admit, defaultMaxResumeAttempts, makeDriverLayer, makeHarness };
125
+ export { Drain, DrainContext, Driver, DriverApi, DriverLayerOptions, type InterruptReason, InvalidMaxResumeAttempts, ResumeSuspendedResult, StopDecision, admit, defaultMaxResumeAttempts, makeDriverLayer, makeHarness };
67
126
  //# sourceMappingURL=driver.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"driver.d.mts","names":[],"sources":["../src/driver.ts"],"mappings":";;;;;;KAYY,eAAA;AAAA,cAEC,wBAAA;AAAA,cAA6B,6BAAA;;;cAE7B,wBAAA,SAAiC,6BAAA;EAAA,SACnC,iBAAiB;AAAA;AAAA,KAKhB,qBAAA;EAAA,SACD,OAAA,EAAS,aAAA;EAAA,SACT,SAAA,EAAW,aAAa;AAAA;AAAA,KAGvB,YAAA;EAAA,SACD,UAAA;EAAA,SACA,cAAA,EAAgB,aAAa,CAAC,cAAA;AAAA;AAAA,KAG7B,KAAA,IACV,KAAA,UACA,KAAA,WACA,KAAA,EAAO,UAAA,EACP,OAAA,EAAS,YAAA,KACN,MAAA,CAAO,MAAA,cAAoB,KAAA,GAAQ,QAAA;AAAA,KAE5B,kBAAA;EAAA,SACD,KAAA,GAAQ,KAAK;EAAA,SACb,iBAAA;AAAA;AAAA,KAGC,YAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAEH,WAAA;EAAA,SACD,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,WAAA;EAAA,SACtB,QAAA,GAAW,KAAA,aAAkB,MAAA,CAAO,MAAA;EAAA,SACpC,GAAA,GAAM,KAAA,aAAkB,MAAA,CAAO,MAAA;EAAA,SAC/B,IAAA,GAAO,KAAA,UAAe,KAAA,GAAQ,UAAA,KAAe,MAAA,CAAO,MAAA;EAAA,SACpD,SAAA,GACP,KAAA,UACA,OAAA;IAAA,SAAqB,MAAA,GAAS,eAAA;IAAA,SAA0B,eAAA;EAAA,MACrD,MAAA,CAAO,MAAA;EAAA,SACH,SAAA,GAAY,KAAA,aAAkB,MAAA,CAAO,MAAA;EAAA,SACrC,eAAA,EAAiB,MAAA,CAAO,MAAA,CAAO,qBAAA;EAAA,SAC/B,KAAA,GAAQ,IAAA,EAAM,SAAA,KAAc,MAAA,CAAO,MAAA;EAAA,SACnC,KAAA,GACP,KAAA,UACA,UAAA,EAAY,aAAA,UACZ,UAAA,aACG,MAAA,CAAO,MAAA,CAAO,aAAA;EAAA,SACV,UAAA,GAAa,KAAA,UAAe,SAAA,EAAW,aAAA,KAAkB,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA,SACvE,IAAA,GAAO,KAAA,aAAkB,MAAA,CAAO,MAAA,CAAO,YAAA;AAAA;AAAA,cACjD,WAAA;cAEY,MAAA,SAAe,WAAkE;AAAA,cAEjF,WAAA,2BAAuC,KAAA;EAAA,SACzC,MAAA,EAAQ,KAAA,CAAM,KAAA,CAAM,MAAA,EAAQ,EAAA,EAAI,EAAA;EAAA,SAChC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,QAAA,EAAU,EAAA,EAAI,EAAA;EAAA,SACjC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,EAAA,EAAI,EAAA;AAAA,MACrC,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,KAAA,EAAO,EAAA,GAAK,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,GAAK,EAAA;AAAA,cAGtD,KAAA,GAAS,IAAA,EAAM,SAAA,KAAS,MAAA,CAAA,MAAA,cAAA,MAAA;AAAA,iBA2JrB,eAAA,CAAA,GAAmB,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBACzD,eAAA,CAAgB,OAAA;EAAA,SACrB,KAAA,GAAQ,KAAA;EAAA,SACR,iBAAA;AAAA,IACP,KAAA,CAAM,KAAA,CAAM,MAAA,SAAe,QAAA,GAAW,KAAA;AAAA,iBAC1B,eAAA,CACd,OAAA,GAAU,kBAAA,GACT,KAAA,CAAM,KAAA,CAAM,MAAA,EAAQ,wBAAA,EAA0B,QAAA,GAAW,KAAA"}
1
+ {"version":3,"file":"driver.d.mts","names":[],"sources":["../src/driver.ts"],"mappings":"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"}