@demlik/tea 0.5.0 → 0.5.1

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 (126) hide show
  1. package/LICENSE +1 -1
  2. package/dist/agent/index.d.ts +5 -5
  3. package/dist/agent/index.js +10 -10
  4. package/dist/authed-call/index.d.ts +3 -3
  5. package/dist/authed-call/index.js +7 -7
  6. package/dist/await-terminal/index.d.ts +2 -2
  7. package/dist/await-terminal/index.js +3 -2
  8. package/dist/await-terminal/index.js.map +1 -1
  9. package/dist/batch-window/index.d.ts +4 -4
  10. package/dist/batch-window/index.js +3 -3
  11. package/dist/cache/index.d.ts +2 -2
  12. package/dist/cache/index.js +4 -4
  13. package/dist/{chunk-PUTHY7LR.js → chunk-2KBEIGYP.js} +3 -3
  14. package/dist/{chunk-PUTHY7LR.js.map → chunk-2KBEIGYP.js.map} +1 -1
  15. package/dist/{chunk-QKUWDC4P.js → chunk-2UGTDYOK.js} +3 -3
  16. package/dist/{chunk-QKUWDC4P.js.map → chunk-2UGTDYOK.js.map} +1 -1
  17. package/dist/{chunk-ZILCH3WS.js → chunk-66S2KEQQ.js} +4 -4
  18. package/dist/{chunk-ZILCH3WS.js.map → chunk-66S2KEQQ.js.map} +1 -1
  19. package/dist/{chunk-362SZ6CS.js → chunk-A7USKARI.js} +3 -3
  20. package/dist/{chunk-362SZ6CS.js.map → chunk-A7USKARI.js.map} +1 -1
  21. package/dist/{chunk-ZT3MGQB7.js → chunk-ASX7PL2K.js} +3 -3
  22. package/dist/{chunk-ZT3MGQB7.js.map → chunk-ASX7PL2K.js.map} +1 -1
  23. package/dist/{chunk-62QBHM3T.js → chunk-AZ3NHUPD.js} +3 -3
  24. package/dist/{chunk-62QBHM3T.js.map → chunk-AZ3NHUPD.js.map} +1 -1
  25. package/dist/{chunk-7FYQGDMF.js → chunk-AZZLE7XR.js} +3 -3
  26. package/dist/{chunk-7FYQGDMF.js.map → chunk-AZZLE7XR.js.map} +1 -1
  27. package/dist/{chunk-W2S4HK7J.js → chunk-EC6FO42Q.js} +6 -6
  28. package/dist/{chunk-W2S4HK7J.js.map → chunk-EC6FO42Q.js.map} +1 -1
  29. package/dist/{chunk-T6HDAPMR.js → chunk-ERYY5P6W.js} +3 -3
  30. package/dist/{chunk-T6HDAPMR.js.map → chunk-ERYY5P6W.js.map} +1 -1
  31. package/dist/{chunk-CIDS43FH.js → chunk-IVHQCVFX.js} +3 -3
  32. package/dist/{chunk-CIDS43FH.js.map → chunk-IVHQCVFX.js.map} +1 -1
  33. package/dist/{chunk-DBOJ2UC6.js → chunk-O7ED34JH.js} +4 -2
  34. package/dist/chunk-O7ED34JH.js.map +1 -0
  35. package/dist/{chunk-LFW66IIV.js → chunk-S6Y3RNX4.js} +4 -4
  36. package/dist/{chunk-LFW66IIV.js.map → chunk-S6Y3RNX4.js.map} +1 -1
  37. package/dist/{chunk-KEFMI24G.js → chunk-UV7VCTNC.js} +7 -7
  38. package/dist/{chunk-KEFMI24G.js.map → chunk-UV7VCTNC.js.map} +1 -1
  39. package/dist/{chunk-7UU5P2CX.js → chunk-WF46FABO.js} +3 -3
  40. package/dist/{chunk-7UU5P2CX.js.map → chunk-WF46FABO.js.map} +1 -1
  41. package/dist/{chunk-KWPB6BM6.js → chunk-XMHZ44QC.js} +4 -4
  42. package/dist/{chunk-KWPB6BM6.js.map → chunk-XMHZ44QC.js.map} +1 -1
  43. package/dist/{chunk-7A74NSG4.js → chunk-XOAP3LOT.js} +3 -3
  44. package/dist/{chunk-7A74NSG4.js.map → chunk-XOAP3LOT.js.map} +1 -1
  45. package/dist/{chunk-PBAYOJJO.js → chunk-ZH454CR5.js} +9 -3
  46. package/dist/chunk-ZH454CR5.js.map +1 -0
  47. package/dist/{core-DPYOyOJv.d.ts → core-JPHsMZVB.d.ts} +1 -1
  48. package/dist/deadline/index.d.ts +2 -2
  49. package/dist/deadline/index.js +3 -3
  50. package/dist/do/index.d.ts +9 -9
  51. package/dist/do/index.js +10 -10
  52. package/dist/do/index.js.map +1 -1
  53. package/dist/{durable-effects-B0YpoCHg.d.ts → durable-effects-MRnCBCxV.d.ts} +2 -2
  54. package/dist/extension/index.d.ts +2 -2
  55. package/dist/extension/index.js +3 -3
  56. package/dist/extension/react.js +3 -3
  57. package/dist/extension/subs/index.d.ts +2 -2
  58. package/dist/extension/test-utils.d.ts +1 -1
  59. package/dist/extension/test-utils.js.map +1 -1
  60. package/dist/fan-out/index.d.ts +2 -2
  61. package/dist/idempotent-intake/index.d.ts +2 -2
  62. package/dist/index.d.ts +4 -4
  63. package/dist/index.js +2 -2
  64. package/dist/llm-call/index.d.ts +3 -3
  65. package/dist/llm-call/index.js +7 -7
  66. package/dist/{machine-Q_Bsm7Vu.d.ts → machine-nGXCMyHn.d.ts} +3 -3
  67. package/dist/machine-viz/index.d.ts +1 -1
  68. package/dist/machine-viz/index.js +2 -2
  69. package/dist/mem/index.d.ts +2 -2
  70. package/dist/monitored-run/index.d.ts +4 -4
  71. package/dist/monitored-run/index.js +5 -5
  72. package/dist/node/index.d.ts +2 -2
  73. package/dist/paginated-walk/index.d.ts +3 -3
  74. package/dist/paginated-walk/index.js +7 -7
  75. package/dist/parity/index.d.ts +2 -2
  76. package/dist/parity/index.js +3 -3
  77. package/dist/pbt/arbitraries/index.d.ts +3 -3
  78. package/dist/pbt/arbitraries/index.js +1 -1
  79. package/dist/pbt/index.d.ts +1 -1
  80. package/dist/pbt/index.js +4 -4
  81. package/dist/pbt/runners/index.d.ts +1 -1
  82. package/dist/pbt/runners/index.js +3 -3
  83. package/dist/poller/index.d.ts +3 -3
  84. package/dist/poller/index.js +3 -3
  85. package/dist/prediction/index.d.ts +1 -1
  86. package/dist/prediction/index.js +2 -2
  87. package/dist/pure/index.d.ts +1 -1
  88. package/dist/pure/index.js +2 -2
  89. package/dist/react/index.d.ts +2 -2
  90. package/dist/react/index.js +2 -2
  91. package/dist/reconciler/index.d.ts +3 -3
  92. package/dist/reconciler/index.js +7 -7
  93. package/dist/recorder/index.d.ts +2 -2
  94. package/dist/resilient-call/index.d.ts +2 -2
  95. package/dist/resilient-call/index.js +6 -6
  96. package/dist/retry-to-success/index.js +2 -0
  97. package/dist/retry-to-success/index.js.map +1 -1
  98. package/dist/{runtime-types-uBuVvZqa.d.ts → runtime-types-BbBq4LWo.d.ts} +2 -2
  99. package/dist/saga/index.d.ts +2 -2
  100. package/dist/snapshot/index.d.ts +1 -1
  101. package/dist/snapshot/index.js +3 -3
  102. package/dist/subs/index.d.ts +3 -3
  103. package/dist/subs/index.js +3 -3
  104. package/dist/testing/index.d.ts +2 -2
  105. package/dist/testing/index.js +2 -2
  106. package/dist/throttled-input/index.d.ts +2 -2
  107. package/dist/throttled-input/index.js +6 -6
  108. package/dist/token-refresh/index.d.ts +1 -1
  109. package/dist/token-refresh/index.js +3 -3
  110. package/dist/trace-replay/index.d.ts +2 -2
  111. package/dist/trace-replay/index.js +3 -3
  112. package/dist/{types-C6mXL9wA.d.ts → types-BMZ7IMrd.d.ts} +1 -1
  113. package/dist/with-deadline/index.d.ts +1 -1
  114. package/dist/with-deadline/index.js +2 -2
  115. package/dist/with-resilience/index.d.ts +2 -2
  116. package/dist/with-resilience/index.js +6 -6
  117. package/dist/with-telemetry/index.d.ts +1 -1
  118. package/dist/with-telemetry/index.js +2 -2
  119. package/dist/work-queue/adapter.d.ts +2 -2
  120. package/dist/work-queue/index.d.ts +3 -3
  121. package/dist/work-queue/index.js.map +1 -1
  122. package/dist/work-queue/ops.d.ts +2 -2
  123. package/dist/workflow/index.d.ts +3 -3
  124. package/package.json +12 -4
  125. package/dist/chunk-DBOJ2UC6.js.map +0 -1
  126. package/dist/chunk-PBAYOJJO.js.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import { CircuitConfig, RateLimitConfig, DeadlineConfig, ResilientPorts, RunCmd, FailMsg, SucceedMsg } from '../resilient-call/index.js';
2
2
  import { TtlCache } from '../cache/index.js';
3
- import { C as Cmd } from '../core-DPYOyOJv.js';
4
- import { PaginatedWalkState, FetchPageCmd, PageOkMsg, PageErrMsg, PaginatedWalkTimerMsg } from '../paginated-walk/index.js';
3
+ import { C as Cmd } from '../core-JPHsMZVB.js';
4
+ import { PaginatedWalkState, PaginatedWalkTimerMsg, FetchPageCmd, PageErrMsg, PageOkMsg } from '../paginated-walk/index.js';
5
5
  import { RetryPolicy } from '../retry-backoff/index.js';
6
6
  import { DeadlineSub } from '../deadline/index.js';
7
7
  export { deadlineSub, subscribeDeadline } from '../deadline/index.js';
8
8
  import '../circuit-breaker/index.js';
9
9
  import '../protocol-B5YmJr0d.js';
10
10
  import '../rate-limit/index.js';
11
- import '../types-C6mXL9wA.js';
11
+ import '../types-BMZ7IMrd.js';
12
12
  import '../paginator/index.js';
13
13
 
14
14
  /**
@@ -1,17 +1,17 @@
1
- import { createPaginatedWalk, PAGE_KEY } from '../chunk-7A74NSG4.js';
1
+ import { createPaginatedWalk, PAGE_KEY } from '../chunk-XOAP3LOT.js';
2
2
  import '../chunk-SINXE47Y.js';
3
- import '../chunk-W2S4HK7J.js';
3
+ import '../chunk-EC6FO42Q.js';
4
4
  import '../chunk-JELSZN25.js';
5
- export { deadlineSub, subscribeDeadline } from '../chunk-ZT3MGQB7.js';
5
+ export { deadlineSub, subscribeDeadline } from '../chunk-ASX7PL2K.js';
6
6
  import '../chunk-Q2UM7BXU.js';
7
7
  import '../chunk-S2EGRPCM.js';
8
8
  import '../chunk-UF4MZSLT.js';
9
- import { initCache, get, set } from '../chunk-7UU5P2CX.js';
10
- import '../chunk-QKUWDC4P.js';
9
+ import { initCache, get, set } from '../chunk-WF46FABO.js';
10
+ import '../chunk-2UGTDYOK.js';
11
11
  import '../chunk-2YFLOCWX.js';
12
12
  import '../chunk-ZJ5AOYBH.js';
13
- import '../chunk-PBAYOJJO.js';
14
- import '../chunk-DBOJ2UC6.js';
13
+ import '../chunk-ZH454CR5.js';
14
+ import '../chunk-O7ED34JH.js';
15
15
 
16
16
  // src/reconciler/index.ts
17
17
  function createReconciler(config, rng = Math.random) {
@@ -1,5 +1,5 @@
1
- import { B as BootingRuntime } from '../runtime-types-uBuVvZqa.js';
2
- import '../core-DPYOyOJv.js';
1
+ import { B as BootingRuntime } from '../runtime-types-BbBq4LWo.js';
2
+ import '../core-JPHsMZVB.js';
3
3
 
4
4
  /**
5
5
  * A recorded run, sufficient to reproduce it via `../trace-replay`.
@@ -2,11 +2,11 @@ import { TtlCache } from '../cache/index.js';
2
2
  import { CircuitState } from '../circuit-breaker/index.js';
3
3
  import { DeadlineExceeded, DeadlineSub } from '../deadline/index.js';
4
4
  export { deadlineSub, subscribeDeadline } from '../deadline/index.js';
5
- import { C as Cmd } from '../core-DPYOyOJv.js';
5
+ import { C as Cmd } from '../core-JPHsMZVB.js';
6
6
  import { M as MsgType } from '../protocol-B5YmJr0d.js';
7
7
  import { TokenBucket } from '../rate-limit/index.js';
8
8
  import { RetryState, AnyRetryPolicy } from '../retry-backoff/index.js';
9
- import '../types-C6mXL9wA.js';
9
+ import '../types-BMZ7IMrd.js';
10
10
 
11
11
  /**
12
12
  * @packageDocumentation
@@ -1,14 +1,14 @@
1
- export { createResilientCall, liftResilience } from '../chunk-W2S4HK7J.js';
1
+ export { createResilientCall, liftResilience } from '../chunk-EC6FO42Q.js';
2
2
  import '../chunk-JELSZN25.js';
3
- export { deadlineSub, subscribeDeadline } from '../chunk-ZT3MGQB7.js';
3
+ export { deadlineSub, subscribeDeadline } from '../chunk-ASX7PL2K.js';
4
4
  import '../chunk-Q2UM7BXU.js';
5
5
  import '../chunk-S2EGRPCM.js';
6
6
  import '../chunk-UF4MZSLT.js';
7
- import '../chunk-7UU5P2CX.js';
8
- import '../chunk-QKUWDC4P.js';
7
+ import '../chunk-WF46FABO.js';
8
+ import '../chunk-2UGTDYOK.js';
9
9
  import '../chunk-2YFLOCWX.js';
10
10
  import '../chunk-ZJ5AOYBH.js';
11
- import '../chunk-PBAYOJJO.js';
12
- import '../chunk-DBOJ2UC6.js';
11
+ import '../chunk-ZH454CR5.js';
12
+ import '../chunk-O7ED34JH.js';
13
13
  //# sourceMappingURL=index.js.map
14
14
  //# sourceMappingURL=index.js.map
@@ -9,6 +9,8 @@ var RetryExhaustedError = class extends Error {
9
9
  this.attempts = attempts;
10
10
  this.lastError = lastError;
11
11
  }
12
+ attempts;
13
+ lastError;
12
14
  name = "RetryExhaustedError";
13
15
  _tag = "RetryExhaustedError";
14
16
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/retry-to-success/index.ts"],"names":[],"mappings":";;;AAiEO,IAAM,mBAAA,GAAN,cAAkC,KAAA,CAAM;AAAA,EAG7C,WAAA,CAEkB,UAEA,SAAA,EAChB;AACA,IAAA,KAAA;AAAA,MACE,6CAA6C,QAAQ,CAAA,iHAAA;AAAA,KAGvD;AARgB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAEA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AAAA,EAOlB;AAAA,EAbkB,IAAA,GAAO,qBAAA;AAAA,EAChB,IAAA,GAAO,qBAAA;AAalB;AAGA,IAAM,YAAA,GAAe,CAAC,EAAA,KACpB,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAuClD,eAAsB,cAAA,CACpB,IAAA,EACA,MAAA,EACA,IAAA,GAA8B,EAAC,EACnB;AACZ,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,IAAO,UAAA;AACxB,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,YAAA;AAI5B,EAAA,IAAI,QAAQ,SAAA,EAAU;AACtB,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,EAAK;AAAA,IACpB,SAAS,KAAA,EAAO;AAId,MAAA,KAAA,GAAQ,aAAA,CAAc,OAAO,KAAK,CAAA;AAClC,MAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,MAAM,CAAA,EAAG;AAG/B,QAAA,MAAM,IAAI,mBAAA,CAAoB,KAAA,CAAM,OAAA,EAAS,KAAK,CAAA;AAAA,MACpD;AACA,MAAA,MAAM,KAAA,CAAM,WAAA,CAAY,KAAA,EAAO,MAAA,EAAQ,GAAG,CAAC,CAAA;AAAA,IAC7C;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * @demlik/tea/retry-to-success — run a fallible async port through BOUNDED\n * retry + exponential backoff to success-or-terminal-give-up, and hand the\n * caller a `Promise<R>` that resolves on the first success or REJECTS with a\n * checkable {@link RetryExhaustedError} the moment the retry bound is hit.\n *\n * This is the retry-side parallel to `./await-terminal`. `runToTerminal` gives a\n * caller with a one-shot decision *machine* a fire-and-await `Promise<State>`\n * without wiring `observe`; this gives a caller with a one-shot fallible *port*\n * a fire-and-await `Promise<R>` without either hand-folding the\n * `./retry-backoff` primitives (`recordFailure` / `shouldRetry` / `nextDelayMs`)\n * into their own reducer each time, or standing up the full `./resilient-call`\n * verb contract (`init` + `attempt`/`succeed`/`fail`/`onTimer` + `subs` +\n * `handlers`) when they want retry only and none of cache / circuit / rate-limit\n * / deadline.\n *\n * It adds NO new runtime capability and NO new backoff math — the whole retry\n * decision is `./retry-backoff` exactly as `resilient-call`'s `backoff` verb\n * wires it:\n * - `initRetry()` seeds the per-call attempt counter.\n * - `recordFailure(retry, error)` folds each thrown failure (attempt++).\n * - `shouldRetry(retry, policy)` is the terminal-at-`maxAttempts` bound — the\n * `maxAttempts`-th recorded failure refuses another attempt (attempts\n * `0 .. maxAttempts-1` run; the port is invoked at most `maxAttempts` times).\n * - `nextDelayMs(retry, policy, rng)` is the exp+jitter+cap delay before the\n * next attempt, computed on the incremented state — same call order as\n * `resilient-call`.\n *\n * Where the clock / RNG live: injected, never read on the module's own behalf,\n * mirroring `retry-backoff`'s purity discipline. `rng` is an {@link Rng} (branded\n * `[0, 1)` via `asRng` at the caller boundary) threaded straight into\n * `nextDelayMs`; the wait itself is a `sleep(ms)` port defaulting to a real\n * `setTimeout`, injectable so a test can drive the backoff schedule\n * deterministically without touching wall-clock timers.\n *\n * Exhaustion is NEVER a silent swallow: at the bound the returned promise\n * rejects with {@link RetryExhaustedError} (carrying the attempt count and the\n * final failure), the retry-side dialect of `await-terminal`'s\n * `TerminalTimeoutError` — a distinct `instanceof`- and `_tag`-checkable\n * rejection.\n *\n * NOT a substrate primitive: it depends on nothing from `../index`, only on the\n * leaf `../retry-backoff` utility. Callers reach it via the\n * `@demlik/tea/retry-to-success` subpath.\n */\n\nimport {\n defaultRng,\n initRetry,\n nextDelayMs,\n type RetryPolicy,\n type Rng,\n recordFailure,\n shouldRetry,\n} from \"../retry-backoff\";\n\n/**\n * Raised when `retryToSuccess` exhausts the retry bound without a success — the\n * `maxAttempts`-th recorded failure refuses another attempt. Follows the tea\n * error dialect (`override readonly name`) and carries a `_tag` discriminant, so\n * a caller can branch on it by `instanceof` or on the tag. It carries the number\n * of attempts made and the final failure (`lastError`) so the terminal give-up\n * is a distinct, checkable rejection — never a silent resolve, and never a\n * swallowed error.\n */\nexport class RetryExhaustedError extends Error {\n override readonly name = \"RetryExhaustedError\";\n readonly _tag = \"RetryExhaustedError\" as const;\n constructor(\n /** How many times the port was invoked before giving up (= `policy.maxAttempts`). */\n public readonly attempts: number,\n /** The failure the final attempt threw — carried, never interpreted. */\n public readonly lastError: unknown,\n ) {\n super(\n `@demlik/tea: retryToSuccess gave up after ${attempts} attempt(s) — the ` +\n `bounded retry reached maxAttempts without a success. See .lastError ` +\n `for the final failure.`,\n );\n }\n}\n\n/** Default wait: a real `setTimeout(ms)`, the sole clock read this module makes. */\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Options for {@link retryToSuccess}. */\nexport interface RetryToSuccessOptions {\n /**\n * The `[0, 1)` jitter source threaded into `nextDelayMs`, branded via\n * `asRng` at construction (a raw `() => number` is rejected by the type).\n * Injected for deterministic backoff in tests; defaults to `defaultRng`\n * (`Math.random`), read only at the delay boundary — never inside the loop's\n * decision.\n */\n readonly rng?: Rng;\n /**\n * The wait between attempts, given the backoff delay in ms. Injectable so a\n * test can drive the retry schedule without wall-clock timers (and assert the\n * exact delays); defaults to a real `setTimeout`. The delay value is always\n * `./retry-backoff`'s `nextDelayMs` — this port only realizes the wait.\n */\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\n/**\n * Fire-and-await bounded retry: invoke the fallible `port`, and on each thrown\n * failure fold it through `./retry-backoff` — record it, and if the policy\n * still permits an attempt, back off `nextDelayMs` and retry; otherwise REJECT\n * with {@link RetryExhaustedError}. Resolves with the port's value on the first\n * success.\n *\n * The port is invoked at most `policy.maxAttempts` times (attempts\n * `0 .. maxAttempts-1`); the `maxAttempts`-th failure is terminal. Every failure\n * is either retried or surfaced on the rejection's `lastError` — none is\n * swallowed.\n *\n * @param port the fallible work — throws on failure, resolves with `R` on success.\n * @param policy the bounded-retry curve (`baseMs` / `factor` / `capMs` /\n * `maxAttempts` / `jitter`) from `./retry-backoff`.\n * @param opts optional injected `rng` (jitter) and `sleep` (the wait) — see\n * {@link RetryToSuccessOptions}.\n */\nexport async function retryToSuccess<R>(\n port: () => Promise<R>,\n policy: RetryPolicy,\n opts: RetryToSuccessOptions = {},\n): Promise<R> {\n const rng = opts.rng ?? defaultRng;\n const sleep = opts.sleep ?? defaultSleep;\n\n // The retry counter folds over `./retry-backoff` exactly as resilient-call's\n // `backoff` verb does — no local attempt bookkeeping, no local backoff math.\n let retry = initRetry();\n for (;;) {\n try {\n return await port();\n } catch (error) {\n // Fold the failure first (attempt++), then consult the bound on the\n // incremented state — same order as resilient-call so the semantics of\n // `maxAttempts` are identical across both surfaces.\n retry = recordFailure(retry, error);\n if (!shouldRetry(retry, policy)) {\n // Terminal give-up at the bound: reject, never swallow. `retry.attempt`\n // is the number of failures = the number of port invocations made.\n throw new RetryExhaustedError(retry.attempt, error);\n }\n await sleep(nextDelayMs(retry, policy, rng));\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/retry-to-success/index.ts"],"names":[],"mappings":";;;AAiEO,IAAM,mBAAA,GAAN,cAAkC,KAAA,CAAM;AAAA,EAG7C,WAAA,CAEkB,UAEA,SAAA,EAChB;AACA,IAAA,KAAA;AAAA,MACE,6CAA6C,QAAQ,CAAA,iHAAA;AAAA,KAGvD;AARgB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAEA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AAAA,EAOlB;AAAA,EATkB,QAAA;AAAA,EAEA,SAAA;AAAA,EANA,IAAA,GAAO,qBAAA;AAAA,EAChB,IAAA,GAAO,qBAAA;AAalB;AAGA,IAAM,YAAA,GAAe,CAAC,EAAA,KACpB,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAuClD,eAAsB,cAAA,CACpB,IAAA,EACA,MAAA,EACA,IAAA,GAA8B,EAAC,EACnB;AACZ,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,IAAO,UAAA;AACxB,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,YAAA;AAI5B,EAAA,IAAI,QAAQ,SAAA,EAAU;AACtB,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,EAAK;AAAA,IACpB,SAAS,KAAA,EAAO;AAId,MAAA,KAAA,GAAQ,aAAA,CAAc,OAAO,KAAK,CAAA;AAClC,MAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,MAAM,CAAA,EAAG;AAG/B,QAAA,MAAM,IAAI,mBAAA,CAAoB,KAAA,CAAM,OAAA,EAAS,KAAK,CAAA;AAAA,MACpD;AACA,MAAA,MAAM,KAAA,CAAM,WAAA,CAAY,KAAA,EAAO,MAAA,EAAQ,GAAG,CAAC,CAAA;AAAA,IAC7C;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * @demlik/tea/retry-to-success — run a fallible async port through BOUNDED\n * retry + exponential backoff to success-or-terminal-give-up, and hand the\n * caller a `Promise<R>` that resolves on the first success or REJECTS with a\n * checkable {@link RetryExhaustedError} the moment the retry bound is hit.\n *\n * This is the retry-side parallel to `./await-terminal`. `runToTerminal` gives a\n * caller with a one-shot decision *machine* a fire-and-await `Promise<State>`\n * without wiring `observe`; this gives a caller with a one-shot fallible *port*\n * a fire-and-await `Promise<R>` without either hand-folding the\n * `./retry-backoff` primitives (`recordFailure` / `shouldRetry` / `nextDelayMs`)\n * into their own reducer each time, or standing up the full `./resilient-call`\n * verb contract (`init` + `attempt`/`succeed`/`fail`/`onTimer` + `subs` +\n * `handlers`) when they want retry only and none of cache / circuit / rate-limit\n * / deadline.\n *\n * It adds NO new runtime capability and NO new backoff math — the whole retry\n * decision is `./retry-backoff` exactly as `resilient-call`'s `backoff` verb\n * wires it:\n * - `initRetry()` seeds the per-call attempt counter.\n * - `recordFailure(retry, error)` folds each thrown failure (attempt++).\n * - `shouldRetry(retry, policy)` is the terminal-at-`maxAttempts` bound — the\n * `maxAttempts`-th recorded failure refuses another attempt (attempts\n * `0 .. maxAttempts-1` run; the port is invoked at most `maxAttempts` times).\n * - `nextDelayMs(retry, policy, rng)` is the exp+jitter+cap delay before the\n * next attempt, computed on the incremented state — same call order as\n * `resilient-call`.\n *\n * Where the clock / RNG live: injected, never read on the module's own behalf,\n * mirroring `retry-backoff`'s purity discipline. `rng` is an {@link Rng} (branded\n * `[0, 1)` via `asRng` at the caller boundary) threaded straight into\n * `nextDelayMs`; the wait itself is a `sleep(ms)` port defaulting to a real\n * `setTimeout`, injectable so a test can drive the backoff schedule\n * deterministically without touching wall-clock timers.\n *\n * Exhaustion is NEVER a silent swallow: at the bound the returned promise\n * rejects with {@link RetryExhaustedError} (carrying the attempt count and the\n * final failure), the retry-side dialect of `await-terminal`'s\n * `TerminalTimeoutError` — a distinct `instanceof`- and `_tag`-checkable\n * rejection.\n *\n * NOT a substrate primitive: it depends on nothing from `../index`, only on the\n * leaf `../retry-backoff` utility. Callers reach it via the\n * `@demlik/tea/retry-to-success` subpath.\n */\n\nimport {\n defaultRng,\n initRetry,\n nextDelayMs,\n type RetryPolicy,\n type Rng,\n recordFailure,\n shouldRetry,\n} from \"../retry-backoff\";\n\n/**\n * Raised when `retryToSuccess` exhausts the retry bound without a success — the\n * `maxAttempts`-th recorded failure refuses another attempt. Follows the tea\n * error dialect (`override readonly name`) and carries a `_tag` discriminant, so\n * a caller can branch on it by `instanceof` or on the tag. It carries the number\n * of attempts made and the final failure (`lastError`) so the terminal give-up\n * is a distinct, checkable rejection — never a silent resolve, and never a\n * swallowed error.\n */\nexport class RetryExhaustedError extends Error {\n override readonly name = \"RetryExhaustedError\";\n readonly _tag = \"RetryExhaustedError\" as const;\n constructor(\n /** How many times the port was invoked before giving up (= `policy.maxAttempts`). */\n public readonly attempts: number,\n /** The failure the final attempt threw — carried, never interpreted. */\n public readonly lastError: unknown,\n ) {\n super(\n `@demlik/tea: retryToSuccess gave up after ${attempts} attempt(s) — the ` +\n `bounded retry reached maxAttempts without a success. See .lastError ` +\n `for the final failure.`,\n );\n }\n}\n\n/** Default wait: a real `setTimeout(ms)`, the sole clock read this module makes. */\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Options for {@link retryToSuccess}. */\nexport interface RetryToSuccessOptions {\n /**\n * The `[0, 1)` jitter source threaded into `nextDelayMs`, branded via\n * `asRng` at construction (a raw `() => number` is rejected by the type).\n * Injected for deterministic backoff in tests; defaults to `defaultRng`\n * (`Math.random`), read only at the delay boundary — never inside the loop's\n * decision.\n */\n readonly rng?: Rng;\n /**\n * The wait between attempts, given the backoff delay in ms. Injectable so a\n * test can drive the retry schedule without wall-clock timers (and assert the\n * exact delays); defaults to a real `setTimeout`. The delay value is always\n * `./retry-backoff`'s `nextDelayMs` — this port only realizes the wait.\n */\n readonly sleep?: (ms: number) => Promise<void>;\n}\n\n/**\n * Fire-and-await bounded retry: invoke the fallible `port`, and on each thrown\n * failure fold it through `./retry-backoff` — record it, and if the policy\n * still permits an attempt, back off `nextDelayMs` and retry; otherwise REJECT\n * with {@link RetryExhaustedError}. Resolves with the port's value on the first\n * success.\n *\n * The port is invoked at most `policy.maxAttempts` times (attempts\n * `0 .. maxAttempts-1`); the `maxAttempts`-th failure is terminal. Every failure\n * is either retried or surfaced on the rejection's `lastError` — none is\n * swallowed.\n *\n * @param port the fallible work — throws on failure, resolves with `R` on success.\n * @param policy the bounded-retry curve (`baseMs` / `factor` / `capMs` /\n * `maxAttempts` / `jitter`) from `./retry-backoff`.\n * @param opts optional injected `rng` (jitter) and `sleep` (the wait) — see\n * {@link RetryToSuccessOptions}.\n */\nexport async function retryToSuccess<R>(\n port: () => Promise<R>,\n policy: RetryPolicy,\n opts: RetryToSuccessOptions = {},\n): Promise<R> {\n const rng = opts.rng ?? defaultRng;\n const sleep = opts.sleep ?? defaultSleep;\n\n // The retry counter folds over `./retry-backoff` exactly as resilient-call's\n // `backoff` verb does — no local attempt bookkeeping, no local backoff math.\n let retry = initRetry();\n for (;;) {\n try {\n return await port();\n } catch (error) {\n // Fold the failure first (attempt++), then consult the bound on the\n // incremented state — same order as resilient-call so the semantics of\n // `maxAttempts` are identical across both surfaces.\n retry = recordFailure(retry, error);\n if (!shouldRetry(retry, policy)) {\n // Terminal give-up at the bound: reject, never swallow. `retry.attempt`\n // is the number of failures = the number of port invocations made.\n throw new RetryExhaustedError(retry.attempt, error);\n }\n await sleep(nextDelayMs(retry, policy, rng));\n }\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { P as Port, C as Cmd, S as Sub, M as Machine, T as Transitions, R as Reducer, I as InterpretDetached, b as PortEmitter } from './core-DPYOyOJv.js';
1
+ import { a as Port, C as Cmd, R as Reducer, S as Sub, M as Machine, T as Transitions, c as InterpretDetached, P as PortEmitter } from './core-JPHsMZVB.js';
2
2
 
3
3
  /**
4
4
  * @demlik/tea runtime interface surface + pure helpers — the public types,
@@ -448,4 +448,4 @@ declare function wrapDetached<C extends Cmd, M extends {
448
448
  }, Allowed extends M, Ctx>(handler: InterpretDetached<C, Allowed, Ctx>): (cmd: C, ctx: Ctx & PortEmitter, dispatch?: (msg: M) => void) => Promise<void>;
449
449
  declare function tryInterpret<C extends Cmd, Ok, M, Ctx>(work: (cmd: C, ctx: Ctx) => Promise<Ok>, onOk: (value: Ok, cmd: C) => M, onErr: (error: unknown, cmd: C) => M): (cmd: C, ctx: Ctx) => Promise<M>;
450
450
 
451
- export { type BootingRuntime as B, type CtxArg as C, DisposeTimeoutNotice as D, IdentityDropNotice as I, type OnError as O, PortNameCollisionError as P, QuiescenceTimeoutError as Q, type Runtime as R, type Store as S, __resetPortRegistry as _, type Supervision as a, type Branded as b, absurd as c, SubIdCollisionError as d, type RuntimeErrorPhase as e, type RuntimeErrorContext as f, type SupervisionStrategy as g, RuntimeDiscardNotice as h, RuntimeDiscardedError as i, DispatchDiscardedError as j, definePort as k, type Schema as l, type DispatchSettle as m, noop as n, type RuntimeRef as o, defineMachine as p, asReducer as q, replay as r, schemaMigrate as s, tryInterpret as t, wrapDetached as w };
451
+ export { type BootingRuntime as B, type CtxArg as C, DispatchDiscardedError as D, IdentityDropNotice as I, type OnError as O, PortNameCollisionError as P, QuiescenceTimeoutError as Q, type Runtime as R, type Store as S, __resetPortRegistry as _, type Supervision as a, type Branded as b, type DispatchSettle as c, DisposeTimeoutNotice as d, RuntimeDiscardNotice as e, RuntimeDiscardedError as f, type RuntimeErrorContext as g, type RuntimeErrorPhase as h, type RuntimeRef as i, type Schema as j, SubIdCollisionError as k, type SupervisionStrategy as l, absurd as m, asReducer as n, defineMachine as o, definePort as p, noop as q, replay as r, schemaMigrate as s, tryInterpret as t, wrapDetached as w };
@@ -1,6 +1,6 @@
1
- import { C as Cmd } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd } from '../core-JPHsMZVB.js';
2
2
  import { QueueItem } from '../work-queue/index.js';
3
- import '../runtime-types-uBuVvZqa.js';
3
+ import '../runtime-types-BbBq4LWo.js';
4
4
 
5
5
  /**
6
6
  * @packageDocumentation
@@ -1,4 +1,4 @@
1
- import { C as Cmd, c as Interpret } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, I as Interpret } from '../core-JPHsMZVB.js';
2
2
 
3
3
  /**
4
4
  * @demlik/tea/snapshot — periodic state checkpoint to a host store (R2/KV-shaped).
@@ -1,5 +1,5 @@
1
- export { createSnapshot, snapshotFailed, snapshotLoadFailed, snapshotLoaded, snapshotSaved } from '../chunk-KWPB6BM6.js';
2
- import '../chunk-PBAYOJJO.js';
3
- import '../chunk-DBOJ2UC6.js';
1
+ export { createSnapshot, snapshotFailed, snapshotLoadFailed, snapshotLoaded, snapshotSaved } from '../chunk-XMHZ44QC.js';
2
+ import '../chunk-ZH454CR5.js';
3
+ import '../chunk-O7ED34JH.js';
4
4
  //# sourceMappingURL=index.js.map
5
5
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- import { S as Sub, P as Port, e as Dispose, D as DepKeyedSub, a as SubId } from '../core-DPYOyOJv.js';
2
- import { S as SubscribeHandler } from '../types-C6mXL9wA.js';
3
- import { R as Runtime } from '../runtime-types-uBuVvZqa.js';
1
+ import { S as Sub, a as Port, e as Dispose, D as DepKeyedSub, b as SubId } from '../core-JPHsMZVB.js';
2
+ import { S as SubscribeHandler } from '../types-BMZ7IMrd.js';
3
+ import { R as Runtime } from '../runtime-types-BbBq4LWo.js';
4
4
 
5
5
  /**
6
6
  * The imperative listener target, expressed as the `add`/`remove` pair the
@@ -1,7 +1,7 @@
1
- export { combineManagedResources, defineListener, defineManagedResource, fromBroadcastChannel, fromEventSource, fromEventTarget, fromInterval, fromPort, fromReconnectingWebSocket, fromTransport, fromWebSocket } from '../chunk-QKUWDC4P.js';
1
+ export { combineManagedResources, defineListener, defineManagedResource, fromBroadcastChannel, fromEventSource, fromEventTarget, fromInterval, fromPort, fromReconnectingWebSocket, fromTransport, fromWebSocket } from '../chunk-2UGTDYOK.js';
2
2
  export { fromTimeout } from '../chunk-2YFLOCWX.js';
3
3
  import '../chunk-ZJ5AOYBH.js';
4
- import '../chunk-PBAYOJJO.js';
5
- import '../chunk-DBOJ2UC6.js';
4
+ import '../chunk-ZH454CR5.js';
5
+ import '../chunk-O7ED34JH.js';
6
6
  //# sourceMappingURL=index.js.map
7
7
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
- import { C as Cmd, S as Sub, M as Machine } from '../core-DPYOyOJv.js';
2
- import { R as Runtime } from '../runtime-types-uBuVvZqa.js';
1
+ import { C as Cmd, S as Sub, M as Machine } from '../core-JPHsMZVB.js';
2
+ import { R as Runtime } from '../runtime-types-BbBq4LWo.js';
3
3
 
4
4
  /**
5
5
  * The composed Model shape every `withX` wrapper produces: the base machine's
@@ -1,5 +1,5 @@
1
- import { replay } from '../chunk-PBAYOJJO.js';
2
- import '../chunk-DBOJ2UC6.js';
1
+ import { replay } from '../chunk-ZH454CR5.js';
2
+ import '../chunk-O7ED34JH.js';
3
3
  import { expect, vi } from 'vitest';
4
4
 
5
5
  function assertWrapperFaithful(base, makeWrapped, opts) {
@@ -1,10 +1,10 @@
1
1
  import { TtlCache } from '../cache/index.js';
2
2
  import { DeadlineSub } from '../deadline/index.js';
3
3
  export { DeadlineExceeded as ThrottledInputSettled, subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../deadline/index.js';
4
- import { C as Cmd, S as Sub } from '../core-DPYOyOJv.js';
4
+ import { C as Cmd, S as Sub } from '../core-JPHsMZVB.js';
5
5
  export { Debounced, debounce } from '../debounce/index.js';
6
6
  export { Throttled, throttle } from '../throttle/index.js';
7
- import '../types-C6mXL9wA.js';
7
+ import '../types-BMZ7IMrd.js';
8
8
 
9
9
  /**
10
10
  * @demlik/tea/throttled-input — gate a high-frequency input stream into a
@@ -1,13 +1,13 @@
1
1
  export { debounce } from '../chunk-J6527VRQ.js';
2
2
  export { throttle } from '../chunk-HCEVHFJ7.js';
3
- import { deadlineSub } from '../chunk-ZT3MGQB7.js';
4
- export { subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../chunk-ZT3MGQB7.js';
5
- import { initCache, get, set } from '../chunk-7UU5P2CX.js';
6
- import '../chunk-QKUWDC4P.js';
3
+ import { deadlineSub } from '../chunk-ASX7PL2K.js';
4
+ export { subscribeDeadline as subscribeThrottledInput, deadlineExceeded as throttledInputSettled } from '../chunk-ASX7PL2K.js';
5
+ import { initCache, get, set } from '../chunk-WF46FABO.js';
6
+ import '../chunk-2UGTDYOK.js';
7
7
  import '../chunk-2YFLOCWX.js';
8
8
  import '../chunk-ZJ5AOYBH.js';
9
- import '../chunk-PBAYOJJO.js';
10
- import '../chunk-DBOJ2UC6.js';
9
+ import '../chunk-ZH454CR5.js';
10
+ import '../chunk-O7ED34JH.js';
11
11
 
12
12
  // src/throttled-input/index.ts
13
13
  var DEFAULT_SUB_ID = "throttled-input:settle";
@@ -1,4 +1,4 @@
1
- import { C as Cmd, c as Interpret } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, I as Interpret } from '../core-JPHsMZVB.js';
2
2
  import { M as MsgType } from '../protocol-B5YmJr0d.js';
3
3
 
4
4
  /**
@@ -1,6 +1,6 @@
1
- export { createTokenRefresh, initTokenRefresh, refreshTokenCmd, tokenRefreshFailedMsg, tokenRefreshedMsg } from '../chunk-PUTHY7LR.js';
1
+ export { createTokenRefresh, initTokenRefresh, refreshTokenCmd, tokenRefreshFailedMsg, tokenRefreshedMsg } from '../chunk-2KBEIGYP.js';
2
2
  import '../chunk-JELSZN25.js';
3
- import '../chunk-PBAYOJJO.js';
4
- import '../chunk-DBOJ2UC6.js';
3
+ import '../chunk-ZH454CR5.js';
4
+ import '../chunk-O7ED34JH.js';
5
5
  //# sourceMappingURL=index.js.map
6
6
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- import { C as Cmd, S as Sub, M as Machine } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, S as Sub, M as Machine } from '../core-JPHsMZVB.js';
2
2
  import { Trace } from '../recorder/index.js';
3
- import '../runtime-types-uBuVvZqa.js';
3
+ import '../runtime-types-BbBq4LWo.js';
4
4
 
5
5
  /**
6
6
  * The outcome of {@link replayTrace}.
@@ -1,6 +1,6 @@
1
- export { deepEqual, replayTrace } from '../chunk-362SZ6CS.js';
1
+ export { deepEqual, replayTrace } from '../chunk-A7USKARI.js';
2
2
  import '../chunk-EWJP3YYP.js';
3
- import '../chunk-PBAYOJJO.js';
4
- import '../chunk-DBOJ2UC6.js';
3
+ import '../chunk-ZH454CR5.js';
4
+ import '../chunk-O7ED34JH.js';
5
5
  //# sourceMappingURL=index.js.map
6
6
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { S as Sub } from './core-DPYOyOJv.js';
1
+ import { S as Sub } from './core-JPHsMZVB.js';
2
2
 
3
3
  type SubscribeHandler<S extends Sub, M, Ctx> = (sub: S, ctx: Ctx, dispatch: (msg: M) => void) => () => void;
4
4
 
@@ -1,4 +1,4 @@
1
- import { S as Sub, C as Cmd, M as Machine } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, S as Sub, M as Machine } from '../core-JPHsMZVB.js';
2
2
 
3
3
  /**
4
4
  * @demlik/tea/with-deadline — auto-fail a wrapped machine at T+N, re-arm on
@@ -1,6 +1,6 @@
1
1
  import { fromTimeout } from '../chunk-2YFLOCWX.js';
2
- import '../chunk-PBAYOJJO.js';
3
- import { msgKeysOf, applyCell, subId } from '../chunk-DBOJ2UC6.js';
2
+ import '../chunk-ZH454CR5.js';
3
+ import { msgKeysOf, applyCell, subId } from '../chunk-O7ED34JH.js';
4
4
 
5
5
  // src/with-deadline/index.ts
6
6
  function deadlineExceededMsg(seq) {
@@ -1,7 +1,7 @@
1
- import { C as Cmd, S as Sub, M as Machine } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, S as Sub, M as Machine } from '../core-JPHsMZVB.js';
2
2
  import { ResilientConfig, ResilientState } from '../resilient-call/index.js';
3
3
  import '../cache/index.js';
4
- import '../types-C6mXL9wA.js';
4
+ import '../types-BMZ7IMrd.js';
5
5
  import '../circuit-breaker/index.js';
6
6
  import '../deadline/index.js';
7
7
  import '../protocol-B5YmJr0d.js';
@@ -1,15 +1,15 @@
1
- import { createResilientCall } from '../chunk-W2S4HK7J.js';
1
+ import { createResilientCall } from '../chunk-EC6FO42Q.js';
2
2
  import { MsgType } from '../chunk-JELSZN25.js';
3
- import { subscribeDeadline } from '../chunk-ZT3MGQB7.js';
3
+ import { subscribeDeadline } from '../chunk-ASX7PL2K.js';
4
4
  import '../chunk-Q2UM7BXU.js';
5
5
  import '../chunk-S2EGRPCM.js';
6
6
  import '../chunk-UF4MZSLT.js';
7
- import '../chunk-7UU5P2CX.js';
8
- import '../chunk-QKUWDC4P.js';
7
+ import '../chunk-WF46FABO.js';
8
+ import '../chunk-2UGTDYOK.js';
9
9
  import '../chunk-2YFLOCWX.js';
10
10
  import '../chunk-ZJ5AOYBH.js';
11
- import { tryInterpret } from '../chunk-PBAYOJJO.js';
12
- import { msgKeysOf, applyCell, subId, formOf } from '../chunk-DBOJ2UC6.js';
11
+ import { tryInterpret } from '../chunk-ZH454CR5.js';
12
+ import { msgKeysOf, applyCell, subId, formOf } from '../chunk-O7ED34JH.js';
13
13
 
14
14
  // src/with-resilience/index.ts
15
15
  var RC_RETRY_PREFIX = "resilient:retry:";
@@ -1,4 +1,4 @@
1
- import { C as Cmd, S as Sub, M as Machine } from '../core-DPYOyOJv.js';
1
+ import { C as Cmd, S as Sub, M as Machine } from '../core-JPHsMZVB.js';
2
2
 
3
3
  /**
4
4
  * @demlik/tea/with-telemetry — the pattern-setting wrapper of the wrapper tier.
@@ -1,5 +1,5 @@
1
- import '../chunk-PBAYOJJO.js';
2
- import { msgKeysOf, applyCell } from '../chunk-DBOJ2UC6.js';
1
+ import '../chunk-ZH454CR5.js';
2
+ import { msgKeysOf, applyCell } from '../chunk-O7ED34JH.js';
3
3
 
4
4
  // src/with-telemetry/index.ts
5
5
  function withTelemetry(base, config = {}) {
@@ -1,6 +1,6 @@
1
1
  import { QueueItem } from './index.js';
2
- import '../runtime-types-uBuVvZqa.js';
3
- import '../core-DPYOyOJv.js';
2
+ import '../runtime-types-BbBq4LWo.js';
3
+ import '../core-JPHsMZVB.js';
4
4
 
5
5
  /**
6
6
  * @demlik/tea/work-queue/adapter — the verb seam over the pure queue ops.
@@ -1,5 +1,5 @@
1
- import { S as Store } from '../runtime-types-uBuVvZqa.js';
2
- import '../core-DPYOyOJv.js';
1
+ import { S as Store } from '../runtime-types-BbBq4LWo.js';
2
+ import '../core-JPHsMZVB.js';
3
3
 
4
4
  /**
5
5
  * @packageDocumentation
@@ -16,7 +16,7 @@ import '../core-DPYOyOJv.js';
16
16
  * one place. This mirrors `@demlik/tea/do`'s one-shape-per-package rule.
17
17
  *
18
18
  * The package is generic in the input payload `I` (audit-specific fields go
19
- * here in apps/extension). `output` is a free-form side-channel correlation
19
+ * here in the extension host). `output` is a free-form side-channel correlation
20
20
  * token (a backend id, URL, trace id) — typed as `string` because that's its
21
21
  * only honest type. Consumers that need structured per-item data persist it in
22
22
  * their own store and put the foreign-key string in `output`.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/work-queue/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @packageDocumentation\n * @demlik/tea/work-queue — substrate-agnostic work-queue lifecycle on `Store<S>`.\n *\n * Two public surfaces, one shape:\n * - `createQueue(store)` (this file) is the in-process adapter — it binds the\n * pure ops to an injected `Store` and runs `load → mutate → save`.\n * - `@demlik/tea/work-queue/ops` (`./ops`) is the BLESSED, importable surface\n * of those same pure ops. L2 compositions that own their own Model slice\n * (`monitored-run`, `idempotent-intake`, …) import the ops directly and\n * delegate status flips to them instead of re-rolling the transitions.\n * Both routes call the identical ops, so the lifecycle rules live in exactly\n * one place. This mirrors `@demlik/tea/do`'s one-shape-per-package rule.\n *\n * The package is generic in the input payload `I` (audit-specific fields go\n * here in apps/extension). `output` is a free-form side-channel correlation\n * token (a backend id, URL, trace id) — typed as `string` because that's its\n * only honest type. Consumers that need structured per-item data persist it in\n * their own store and put the foreign-key string in `output`.\n */\n\nimport type { Store } from \"../index\";\nimport {\n claimNextOp,\n enqueueOp,\n markDoneOp,\n patchItemOp,\n removeOp,\n resetRunningOp,\n} from \"./ops\";\n\n/**\n * Generate a queue-item id at the adapter boundary. Reads `Date.now()` and\n * `Math.random()` — impure helpers belong in the adapter (`index.ts`),\n * never in `ops.ts` (which is purely-functional by contract). Uses native\n * UUID when available, falls back to timestamp + random for environments\n * without `crypto.randomUUID`.\n */\nfunction genId(): string {\n return (\n globalThis.crypto?.randomUUID?.() ??\n `q_${Date.now()}_${Math.random().toString(36).slice(2)}`\n );\n}\n\nexport type QueueItemStatus =\n | \"pending\"\n | \"running\"\n | \"done\"\n | \"failed\"\n | \"cancelled\";\n\n/**\n * A single queue entry. Every field is `readonly`: a persisted slice is\n * immutable, so a transition returns a NEW item (the ops always spread —\n * `{ ...item, status: … }`) rather than mutating in place. This type-enforces\n * the durability invariant the consumers already honor by convention, and\n * keeps a slice round-trippable through JSON unchanged across a reload.\n */\nexport interface QueueItem<I> {\n readonly id: string;\n readonly status: QueueItemStatus;\n readonly input: I;\n readonly enqueuedAt: number;\n readonly startedAt?: number;\n readonly finishedAt?: number;\n readonly output?: string;\n readonly error?: string;\n}\n\n/**\n * Caller-facing enqueue payload. Just `I` today — kept named so future\n * variants (priority, deferUntil, …) can grow without breaking callers.\n */\nexport type EnqueueInput<I> = I;\n\n/**\n * Adapter that binds the pure ops to an injected `Store<QueueItem<I>[]>`.\n *\n * `load → mutate → save` is the only durability discipline this package\n * imposes. The store decides what \"save\" means (chrome.storage, KV, DO\n * storage, in-memory) — that decision belongs at the caller.\n *\n * Ops that don't change the queue (e.g. `markDone` on an unknown id) skip the\n * save call so the underlying store doesn't observe a write churn.\n */\nexport function createQueue<I>(store: Store<QueueItem<I>[]>) {\n // `Store<S>.load()` returns `unknown` (invariant 8 boundary). Route\n // through `store.migrate(raw)` to get the typed value before any\n // queue operation reads it — same wiring the substrate's `run()` uses at\n // boot. The work queue is a substrate-agnostic primitive on top of\n // `Store<S>`, so it honors the same contract.\n async function loadParsed(): Promise<QueueItem<I>[] | null> {\n const raw = await store.load();\n return store.migrate(raw);\n }\n\n async function list(): Promise<QueueItem<I>[]> {\n return (await loadParsed()) ?? [];\n }\n\n async function enqueue(input: EnqueueInput<I>): Promise<QueueItem<I>> {\n const queue = await list();\n const { next, item } = enqueueOp<I>(queue, input, Date.now(), genId());\n await store.save(next);\n return item;\n }\n\n async function claimNext(): Promise<QueueItem<I> | null> {\n const queue = await list();\n const result = claimNextOp<I>(queue, Date.now());\n if (!result) return null;\n await store.save(result.next);\n return result.claimed;\n }\n\n // `markDone` ignores the optional second arg by design: completed runs leave\n // the queue, and the consumer is expected to persist any output (auditId,\n // etc.) wherever those completed records belong. Kept in the signature for\n // call-site readability and forward-compat with `bindOutput`.\n async function markDone(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = markDoneOp<I>(queue, id);\n if (changed) await store.save(next);\n }\n\n async function markFailed(id: string, error: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"failed\",\n finishedAt: Date.now(),\n error,\n }));\n if (changed) await store.save(next);\n }\n\n async function markCancelled(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"cancelled\",\n finishedAt: Date.now(),\n }));\n if (changed) await store.save(next);\n }\n\n async function resetRunningToPending(): Promise<void> {\n const queue = await list();\n const { next, changed } = resetRunningOp<I>(queue);\n if (changed) await store.save(next);\n }\n\n async function removeItem(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = removeOp<I>(queue, id);\n if (changed) await store.save(next);\n }\n\n async function retryItem(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"pending\",\n startedAt: undefined,\n finishedAt: undefined,\n error: undefined,\n output: undefined,\n }));\n if (changed) await store.save(next);\n }\n\n // `bindOutput` attaches a side-channel correlation token (string) to a\n // running item without changing its status. The queue can't reach into\n // `I` to mutate it (the substrate is domain-agnostic), so callers that\n // need to thread a backend id / URL / trace id through the lifecycle\n // route it here. Consumers needing structured payloads should persist\n // them in their own store and put the foreign-key string in `output`.\n async function bindOutput(id: string, value: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n output: value,\n }));\n if (changed) await store.save(next);\n }\n\n return {\n enqueue,\n claimNext,\n markDone,\n markFailed,\n markCancelled,\n resetRunningToPending,\n removeItem,\n retryItem,\n bindOutput,\n list,\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/work-queue/index.ts"],"names":[],"mappings":";;;AAsCA,SAAS,KAAA,GAAgB;AACvB,EAAA,OACE,WAAW,MAAA,EAAQ,UAAA,IAAa,IAChC,CAAA,EAAA,EAAK,KAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAE1D;AA2CO,SAAS,YAAe,KAAA,EAA8B;AAM3D,EAAA,eAAe,UAAA,GAA6C;AAC1D,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,EAAK;AAC7B,IAAA,OAAO,KAAA,CAAM,QAAQ,GAAG,CAAA;AAAA,EAC1B;AAEA,EAAA,eAAe,IAAA,GAAgC;AAC7C,IAAA,OAAQ,MAAM,UAAA,EAAW,IAAM,EAAC;AAAA,EAClC;AAEA,EAAA,eAAe,QAAQ,KAAA,EAA+C;AACpE,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,SAAA,CAAa,KAAA,EAAO,KAAA,EAAO,IAAA,CAAK,GAAA,EAAI,EAAG,KAAA,EAAO,CAAA;AACrE,IAAA,MAAM,KAAA,CAAM,KAAK,IAAI,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,eAAe,SAAA,GAA0C;AACvD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,MAAA,GAAS,WAAA,CAAe,KAAA,EAAO,IAAA,CAAK,KAAK,CAAA;AAC/C,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,IAAA,MAAM,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AAC5B,IAAA,OAAO,MAAA,CAAO,OAAA;AAAA,EAChB;AAMA,EAAA,eAAe,SAAS,EAAA,EAA2B;AACjD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,UAAA,CAAc,OAAO,EAAE,CAAA;AACjD,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,eAAe,UAAA,CAAW,IAAY,KAAA,EAA8B;AAClE,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,MAAM,OAAA,EAAQ,GAAI,YAAe,KAAA,EAAO,EAAA,EAAI,CAAC,IAAA,MAAU;AAAA,MAC7D,GAAG,IAAA;AAAA,MACH,MAAA,EAAQ,QAAA;AAAA,MACR,UAAA,EAAY,KAAK,GAAA,EAAI;AAAA,MACrB;AAAA,KACF,CAAE,CAAA;AACF,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,eAAe,cAAc,EAAA,EAA2B;AACtD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,MAAM,OAAA,EAAQ,GAAI,YAAe,KAAA,EAAO,EAAA,EAAI,CAAC,IAAA,MAAU;AAAA,MAC7D,GAAG,IAAA;AAAA,MACH,MAAA,EAAQ,WAAA;AAAA,MACR,UAAA,EAAY,KAAK,GAAA;AAAI,KACvB,CAAE,CAAA;AACF,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,eAAe,qBAAA,GAAuC;AACpD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,eAAkB,KAAK,CAAA;AACjD,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,eAAe,WAAW,EAAA,EAA2B;AACnD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,QAAA,CAAY,OAAO,EAAE,CAAA;AAC/C,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,eAAe,UAAU,EAAA,EAA2B;AAClD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,MAAM,OAAA,EAAQ,GAAI,YAAe,KAAA,EAAO,EAAA,EAAI,CAAC,IAAA,MAAU;AAAA,MAC7D,GAAG,IAAA;AAAA,MACH,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAW,MAAA;AAAA,MACX,UAAA,EAAY,MAAA;AAAA,MACZ,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ;AAAA,KACV,CAAE,CAAA;AACF,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAQA,EAAA,eAAe,UAAA,CAAW,IAAY,KAAA,EAA8B;AAClE,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,EAAK;AACzB,IAAA,MAAM,EAAE,MAAM,OAAA,EAAQ,GAAI,YAAe,KAAA,EAAO,EAAA,EAAI,CAAC,IAAA,MAAU;AAAA,MAC7D,GAAG,IAAA;AAAA,MACH,MAAA,EAAQ;AAAA,KACV,CAAE,CAAA;AACF,IAAA,IAAI,OAAA,EAAS,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,EACpC;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,qBAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * @packageDocumentation\n * @demlik/tea/work-queue — substrate-agnostic work-queue lifecycle on `Store<S>`.\n *\n * Two public surfaces, one shape:\n * - `createQueue(store)` (this file) is the in-process adapter — it binds the\n * pure ops to an injected `Store` and runs `load → mutate → save`.\n * - `@demlik/tea/work-queue/ops` (`./ops`) is the BLESSED, importable surface\n * of those same pure ops. L2 compositions that own their own Model slice\n * (`monitored-run`, `idempotent-intake`, …) import the ops directly and\n * delegate status flips to them instead of re-rolling the transitions.\n * Both routes call the identical ops, so the lifecycle rules live in exactly\n * one place. This mirrors `@demlik/tea/do`'s one-shape-per-package rule.\n *\n * The package is generic in the input payload `I` (audit-specific fields go\n * here in the extension host). `output` is a free-form side-channel correlation\n * token (a backend id, URL, trace id) — typed as `string` because that's its\n * only honest type. Consumers that need structured per-item data persist it in\n * their own store and put the foreign-key string in `output`.\n */\n\nimport type { Store } from \"../index\";\nimport {\n claimNextOp,\n enqueueOp,\n markDoneOp,\n patchItemOp,\n removeOp,\n resetRunningOp,\n} from \"./ops\";\n\n/**\n * Generate a queue-item id at the adapter boundary. Reads `Date.now()` and\n * `Math.random()` — impure helpers belong in the adapter (`index.ts`),\n * never in `ops.ts` (which is purely-functional by contract). Uses native\n * UUID when available, falls back to timestamp + random for environments\n * without `crypto.randomUUID`.\n */\nfunction genId(): string {\n return (\n globalThis.crypto?.randomUUID?.() ??\n `q_${Date.now()}_${Math.random().toString(36).slice(2)}`\n );\n}\n\nexport type QueueItemStatus =\n | \"pending\"\n | \"running\"\n | \"done\"\n | \"failed\"\n | \"cancelled\";\n\n/**\n * A single queue entry. Every field is `readonly`: a persisted slice is\n * immutable, so a transition returns a NEW item (the ops always spread —\n * `{ ...item, status: … }`) rather than mutating in place. This type-enforces\n * the durability invariant the consumers already honor by convention, and\n * keeps a slice round-trippable through JSON unchanged across a reload.\n */\nexport interface QueueItem<I> {\n readonly id: string;\n readonly status: QueueItemStatus;\n readonly input: I;\n readonly enqueuedAt: number;\n readonly startedAt?: number;\n readonly finishedAt?: number;\n readonly output?: string;\n readonly error?: string;\n}\n\n/**\n * Caller-facing enqueue payload. Just `I` today — kept named so future\n * variants (priority, deferUntil, …) can grow without breaking callers.\n */\nexport type EnqueueInput<I> = I;\n\n/**\n * Adapter that binds the pure ops to an injected `Store<QueueItem<I>[]>`.\n *\n * `load → mutate → save` is the only durability discipline this package\n * imposes. The store decides what \"save\" means (chrome.storage, KV, DO\n * storage, in-memory) — that decision belongs at the caller.\n *\n * Ops that don't change the queue (e.g. `markDone` on an unknown id) skip the\n * save call so the underlying store doesn't observe a write churn.\n */\nexport function createQueue<I>(store: Store<QueueItem<I>[]>) {\n // `Store<S>.load()` returns `unknown` (invariant 8 boundary). Route\n // through `store.migrate(raw)` to get the typed value before any\n // queue operation reads it — same wiring the substrate's `run()` uses at\n // boot. The work queue is a substrate-agnostic primitive on top of\n // `Store<S>`, so it honors the same contract.\n async function loadParsed(): Promise<QueueItem<I>[] | null> {\n const raw = await store.load();\n return store.migrate(raw);\n }\n\n async function list(): Promise<QueueItem<I>[]> {\n return (await loadParsed()) ?? [];\n }\n\n async function enqueue(input: EnqueueInput<I>): Promise<QueueItem<I>> {\n const queue = await list();\n const { next, item } = enqueueOp<I>(queue, input, Date.now(), genId());\n await store.save(next);\n return item;\n }\n\n async function claimNext(): Promise<QueueItem<I> | null> {\n const queue = await list();\n const result = claimNextOp<I>(queue, Date.now());\n if (!result) return null;\n await store.save(result.next);\n return result.claimed;\n }\n\n // `markDone` ignores the optional second arg by design: completed runs leave\n // the queue, and the consumer is expected to persist any output (auditId,\n // etc.) wherever those completed records belong. Kept in the signature for\n // call-site readability and forward-compat with `bindOutput`.\n async function markDone(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = markDoneOp<I>(queue, id);\n if (changed) await store.save(next);\n }\n\n async function markFailed(id: string, error: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"failed\",\n finishedAt: Date.now(),\n error,\n }));\n if (changed) await store.save(next);\n }\n\n async function markCancelled(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"cancelled\",\n finishedAt: Date.now(),\n }));\n if (changed) await store.save(next);\n }\n\n async function resetRunningToPending(): Promise<void> {\n const queue = await list();\n const { next, changed } = resetRunningOp<I>(queue);\n if (changed) await store.save(next);\n }\n\n async function removeItem(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = removeOp<I>(queue, id);\n if (changed) await store.save(next);\n }\n\n async function retryItem(id: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n status: \"pending\",\n startedAt: undefined,\n finishedAt: undefined,\n error: undefined,\n output: undefined,\n }));\n if (changed) await store.save(next);\n }\n\n // `bindOutput` attaches a side-channel correlation token (string) to a\n // running item without changing its status. The queue can't reach into\n // `I` to mutate it (the substrate is domain-agnostic), so callers that\n // need to thread a backend id / URL / trace id through the lifecycle\n // route it here. Consumers needing structured payloads should persist\n // them in their own store and put the foreign-key string in `output`.\n async function bindOutput(id: string, value: string): Promise<void> {\n const queue = await list();\n const { next, changed } = patchItemOp<I>(queue, id, (item) => ({\n ...item,\n output: value,\n }));\n if (changed) await store.save(next);\n }\n\n return {\n enqueue,\n claimNext,\n markDone,\n markFailed,\n markCancelled,\n resetRunningToPending,\n removeItem,\n retryItem,\n bindOutput,\n list,\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { QueueItem } from './index.js';
2
- import '../runtime-types-uBuVvZqa.js';
3
- import '../core-DPYOyOJv.js';
2
+ import '../runtime-types-BbBq4LWo.js';
3
+ import '../core-JPHsMZVB.js';
4
4
 
5
5
  /**
6
6
  * Pure queue-lifecycle ops over `QueueItem<I>[]` — the BLESSED delegation
@@ -1,6 +1,6 @@
1
- import { D as DeliveryId, E as EffectLedgerEvent } from '../durable-effects-B0YpoCHg.js';
2
- export { a as EffectConfirmed, b as EffectOwed, e as emptyLedger } from '../durable-effects-B0YpoCHg.js';
3
- import { C as Cmd } from '../core-DPYOyOJv.js';
1
+ import { D as DeliveryId, E as EffectLedgerEvent } from '../durable-effects-MRnCBCxV.js';
2
+ export { a as EffectConfirmed, b as EffectOwed, e as emptyLedger } from '../durable-effects-MRnCBCxV.js';
3
+ import { C as Cmd } from '../core-JPHsMZVB.js';
4
4
 
5
5
  /**
6
6
  * @packageDocumentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@demlik/tea",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "TEA-faithful state machine substrate — one package, every host adapter. Core + subs + testing, plus React, Durable Object, Chrome extension, Node, in-memory, work-queue, devtools, and property-testing modules as subpaths.",
5
5
  "keywords": [
6
6
  "tea",
@@ -15,8 +15,7 @@
15
15
  "homepage": "https://demlik.run",
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/cansirin/monorepo.git",
19
- "directory": "packages/tea"
18
+ "url": "git+https://github.com/kamp-us/demlik.git"
20
19
  },
21
20
  "license": "MIT",
22
21
  "author": "Can Sirin",
@@ -279,6 +278,8 @@
279
278
  }
280
279
  },
281
280
  "devDependencies": {
281
+ "@biomejs/biome": "2.3.14",
282
+ "@changesets/cli": "^2.27.11",
282
283
  "@cloudflare/workers-types": "4.20260312.1",
283
284
  "@types/chrome": "^0.1.42",
284
285
  "@types/node": "^22",
@@ -298,6 +299,12 @@
298
299
  "publishConfig": {
299
300
  "access": "public"
300
301
  },
302
+ "bugs": {
303
+ "url": "https://github.com/kamp-us/demlik/issues"
304
+ },
305
+ "volta": {
306
+ "node": "23.7.0"
307
+ },
301
308
  "scripts": {
302
309
  "build": "NODE_OPTIONS=--max-old-space-size=8192 tsup",
303
310
  "lint": "biome check src package.json",
@@ -307,6 +314,7 @@
307
314
  "typecheck:examples": "tsc -p examples/tsconfig.json",
308
315
  "docs:reference": "TEA_DOCS_WRITE=1 vitest run src/docs/reference/generate-reference.test.ts",
309
316
  "docs:reference:check": "pnpm run docs:reference && git diff --exit-code -- docs/reference",
310
- "verify-exports": "node scripts/verify-exports.mjs"
317
+ "verify-exports": "node scripts/verify-exports.mjs",
318
+ "release": "changeset"
311
319
  }
312
320
  }