@smthrs/triggers 0.0.0-stage → 1.0.0-rc.3

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 (226) hide show
  1. package/CHANGELOG.md +219 -0
  2. package/LICENSE +21 -0
  3. package/README.md +109 -2
  4. package/dist/cjs/CatchUp.d.ts +25 -0
  5. package/dist/cjs/CatchUp.d.ts.map +1 -0
  6. package/dist/cjs/CatchUp.js +72 -0
  7. package/dist/cjs/CatchUp.js.map +7 -0
  8. package/dist/cjs/Channel.d.ts +108 -0
  9. package/dist/cjs/Channel.d.ts.map +1 -0
  10. package/dist/cjs/Channel.js +25 -0
  11. package/dist/cjs/Channel.js.map +7 -0
  12. package/dist/cjs/ClaimDecision.d.ts +183 -0
  13. package/dist/cjs/ClaimDecision.d.ts.map +1 -0
  14. package/dist/cjs/ClaimDecision.js +144 -0
  15. package/dist/cjs/ClaimDecision.js.map +7 -0
  16. package/dist/cjs/Cron.d.ts +91 -0
  17. package/dist/cjs/Cron.d.ts.map +1 -0
  18. package/dist/cjs/Cron.js +108 -0
  19. package/dist/cjs/Cron.js.map +7 -0
  20. package/dist/cjs/DispatchReader.d.ts +77 -0
  21. package/dist/cjs/DispatchReader.d.ts.map +1 -0
  22. package/dist/cjs/DispatchReader.js +121 -0
  23. package/dist/cjs/DispatchReader.js.map +7 -0
  24. package/dist/cjs/Overlap.d.ts +40 -0
  25. package/dist/cjs/Overlap.d.ts.map +1 -0
  26. package/dist/cjs/Overlap.js +37 -0
  27. package/dist/cjs/Overlap.js.map +7 -0
  28. package/dist/cjs/Schedule.d.ts +96 -0
  29. package/dist/cjs/Schedule.d.ts.map +1 -0
  30. package/dist/cjs/Schedule.js +61 -0
  31. package/dist/cjs/Schedule.js.map +7 -0
  32. package/dist/cjs/Scheduler.d.ts +248 -0
  33. package/dist/cjs/Scheduler.d.ts.map +1 -0
  34. package/dist/cjs/Scheduler.js +647 -0
  35. package/dist/cjs/Scheduler.js.map +7 -0
  36. package/dist/cjs/SqlTriggerStore.d.ts +29 -0
  37. package/dist/cjs/SqlTriggerStore.d.ts.map +1 -0
  38. package/dist/cjs/SqlTriggerStore.js +483 -0
  39. package/dist/cjs/SqlTriggerStore.js.map +7 -0
  40. package/dist/cjs/Trigger.d.ts +81 -0
  41. package/dist/cjs/Trigger.d.ts.map +1 -0
  42. package/dist/cjs/Trigger.js +54 -0
  43. package/dist/cjs/Trigger.js.map +7 -0
  44. package/dist/cjs/TriggerError.d.ts +58 -0
  45. package/dist/cjs/TriggerError.d.ts.map +1 -0
  46. package/dist/cjs/TriggerError.js +83 -0
  47. package/dist/cjs/TriggerError.js.map +7 -0
  48. package/dist/cjs/TriggerStore.d.ts +411 -0
  49. package/dist/cjs/TriggerStore.d.ts.map +1 -0
  50. package/dist/cjs/TriggerStore.js +127 -0
  51. package/dist/cjs/TriggerStore.js.map +7 -0
  52. package/dist/cjs/Webhook.d.ts +118 -0
  53. package/dist/cjs/Webhook.d.ts.map +1 -0
  54. package/dist/cjs/Webhook.js +153 -0
  55. package/dist/cjs/Webhook.js.map +7 -0
  56. package/dist/cjs/index.d.ts +30 -0
  57. package/dist/cjs/index.d.ts.map +1 -0
  58. package/dist/cjs/index.js +57 -0
  59. package/dist/cjs/index.js.map +7 -0
  60. package/dist/cjs/internal/ActiveRuns.d.ts +51 -0
  61. package/dist/cjs/internal/ActiveRuns.d.ts.map +1 -0
  62. package/dist/cjs/internal/ActiveRuns.js +56 -0
  63. package/dist/cjs/internal/ActiveRuns.js.map +7 -0
  64. package/dist/cjs/internal/DueOccurrences.d.ts +32 -0
  65. package/dist/cjs/internal/DueOccurrences.d.ts.map +1 -0
  66. package/dist/cjs/internal/DueOccurrences.js +80 -0
  67. package/dist/cjs/internal/DueOccurrences.js.map +7 -0
  68. package/dist/cjs/internal/WallClock.d.ts +59 -0
  69. package/dist/cjs/internal/WallClock.d.ts.map +1 -0
  70. package/dist/cjs/internal/WallClock.js +132 -0
  71. package/dist/cjs/internal/WallClock.js.map +7 -0
  72. package/dist/cjs/migrations/0001_triggers.d.ts +15 -0
  73. package/dist/cjs/migrations/0001_triggers.d.ts.map +1 -0
  74. package/dist/cjs/migrations/0001_triggers.js +64 -0
  75. package/dist/cjs/migrations/0001_triggers.js.map +7 -0
  76. package/dist/cjs/migrations/0002_reservation_lease.d.ts +15 -0
  77. package/dist/cjs/migrations/0002_reservation_lease.d.ts.map +1 -0
  78. package/dist/cjs/migrations/0002_reservation_lease.js +41 -0
  79. package/dist/cjs/migrations/0002_reservation_lease.js.map +7 -0
  80. package/dist/cjs/migrations/0003_heartbeat.d.ts +16 -0
  81. package/dist/cjs/migrations/0003_heartbeat.d.ts.map +1 -0
  82. package/dist/cjs/migrations/0003_heartbeat.js +44 -0
  83. package/dist/cjs/migrations/0003_heartbeat.js.map +7 -0
  84. package/dist/cjs/migrations/0004_fire_run_index.d.ts +17 -0
  85. package/dist/cjs/migrations/0004_fire_run_index.d.ts.map +1 -0
  86. package/dist/cjs/migrations/0004_fire_run_index.js +40 -0
  87. package/dist/cjs/migrations/0004_fire_run_index.js.map +7 -0
  88. package/dist/cjs/migrations/index.d.ts +33 -0
  89. package/dist/cjs/migrations/index.d.ts.map +1 -0
  90. package/dist/cjs/migrations/index.js +50 -0
  91. package/dist/cjs/migrations/index.js.map +7 -0
  92. package/dist/cjs/package.json +1 -0
  93. package/dist/cjs/test/TestTriggers.d.ts +12 -0
  94. package/dist/cjs/test/TestTriggers.d.ts.map +1 -0
  95. package/dist/cjs/test/TestTriggers.js +421 -0
  96. package/dist/cjs/test/TestTriggers.js.map +7 -0
  97. package/dist/esm/CatchUp.d.ts +25 -0
  98. package/dist/esm/CatchUp.d.ts.map +1 -0
  99. package/dist/esm/CatchUp.js +52 -0
  100. package/dist/esm/CatchUp.js.map +1 -0
  101. package/dist/esm/Channel.d.ts +108 -0
  102. package/dist/esm/Channel.d.ts.map +1 -0
  103. package/dist/esm/Channel.js +19 -0
  104. package/dist/esm/Channel.js.map +1 -0
  105. package/dist/esm/ClaimDecision.d.ts +183 -0
  106. package/dist/esm/ClaimDecision.d.ts.map +1 -0
  107. package/dist/esm/ClaimDecision.js +172 -0
  108. package/dist/esm/ClaimDecision.js.map +1 -0
  109. package/dist/esm/Cron.d.ts +91 -0
  110. package/dist/esm/Cron.d.ts.map +1 -0
  111. package/dist/esm/Cron.js +132 -0
  112. package/dist/esm/Cron.js.map +1 -0
  113. package/dist/esm/DispatchReader.d.ts +77 -0
  114. package/dist/esm/DispatchReader.d.ts.map +1 -0
  115. package/dist/esm/DispatchReader.js +152 -0
  116. package/dist/esm/DispatchReader.js.map +1 -0
  117. package/dist/esm/Overlap.d.ts +40 -0
  118. package/dist/esm/Overlap.d.ts.map +1 -0
  119. package/dist/esm/Overlap.js +31 -0
  120. package/dist/esm/Overlap.js.map +1 -0
  121. package/dist/esm/Schedule.d.ts +96 -0
  122. package/dist/esm/Schedule.d.ts.map +1 -0
  123. package/dist/esm/Schedule.js +73 -0
  124. package/dist/esm/Schedule.js.map +1 -0
  125. package/dist/esm/Scheduler.d.ts +248 -0
  126. package/dist/esm/Scheduler.d.ts.map +1 -0
  127. package/dist/esm/Scheduler.js +734 -0
  128. package/dist/esm/Scheduler.js.map +1 -0
  129. package/dist/esm/SqlTriggerStore.d.ts +29 -0
  130. package/dist/esm/SqlTriggerStore.d.ts.map +1 -0
  131. package/dist/esm/SqlTriggerStore.js +483 -0
  132. package/dist/esm/SqlTriggerStore.js.map +1 -0
  133. package/dist/esm/Trigger.d.ts +81 -0
  134. package/dist/esm/Trigger.d.ts.map +1 -0
  135. package/dist/esm/Trigger.js +56 -0
  136. package/dist/esm/Trigger.js.map +1 -0
  137. package/dist/esm/TriggerError.d.ts +58 -0
  138. package/dist/esm/TriggerError.d.ts.map +1 -0
  139. package/dist/esm/TriggerError.js +110 -0
  140. package/dist/esm/TriggerError.js.map +1 -0
  141. package/dist/esm/TriggerStore.d.ts +411 -0
  142. package/dist/esm/TriggerStore.d.ts.map +1 -0
  143. package/dist/esm/TriggerStore.js +209 -0
  144. package/dist/esm/TriggerStore.js.map +1 -0
  145. package/dist/esm/Webhook.d.ts +118 -0
  146. package/dist/esm/Webhook.d.ts.map +1 -0
  147. package/dist/esm/Webhook.js +186 -0
  148. package/dist/esm/Webhook.js.map +1 -0
  149. package/dist/esm/index.d.ts +30 -0
  150. package/dist/esm/index.d.ts.map +1 -0
  151. package/dist/esm/index.js +30 -0
  152. package/dist/esm/index.js.map +1 -0
  153. package/dist/esm/internal/ActiveRuns.d.ts +51 -0
  154. package/dist/esm/internal/ActiveRuns.d.ts.map +1 -0
  155. package/dist/esm/internal/ActiveRuns.js +34 -0
  156. package/dist/esm/internal/ActiveRuns.js.map +1 -0
  157. package/dist/esm/internal/DueOccurrences.d.ts +32 -0
  158. package/dist/esm/internal/DueOccurrences.d.ts.map +1 -0
  159. package/dist/esm/internal/DueOccurrences.js +55 -0
  160. package/dist/esm/internal/DueOccurrences.js.map +1 -0
  161. package/dist/esm/internal/WallClock.d.ts +59 -0
  162. package/dist/esm/internal/WallClock.d.ts.map +1 -0
  163. package/dist/esm/internal/WallClock.js +155 -0
  164. package/dist/esm/internal/WallClock.js.map +1 -0
  165. package/dist/esm/migrations/0001_triggers.d.ts +15 -0
  166. package/dist/esm/migrations/0001_triggers.d.ts.map +1 -0
  167. package/dist/esm/migrations/0001_triggers.js +42 -0
  168. package/dist/esm/migrations/0001_triggers.js.map +1 -0
  169. package/dist/esm/migrations/0002_reservation_lease.d.ts +15 -0
  170. package/dist/esm/migrations/0002_reservation_lease.d.ts.map +1 -0
  171. package/dist/esm/migrations/0002_reservation_lease.js +19 -0
  172. package/dist/esm/migrations/0002_reservation_lease.js.map +1 -0
  173. package/dist/esm/migrations/0003_heartbeat.d.ts +16 -0
  174. package/dist/esm/migrations/0003_heartbeat.d.ts.map +1 -0
  175. package/dist/esm/migrations/0003_heartbeat.js +23 -0
  176. package/dist/esm/migrations/0003_heartbeat.js.map +1 -0
  177. package/dist/esm/migrations/0004_fire_run_index.d.ts +17 -0
  178. package/dist/esm/migrations/0004_fire_run_index.d.ts.map +1 -0
  179. package/dist/esm/migrations/0004_fire_run_index.js +20 -0
  180. package/dist/esm/migrations/0004_fire_run_index.js.map +1 -0
  181. package/dist/esm/migrations/index.d.ts +33 -0
  182. package/dist/esm/migrations/index.d.ts.map +1 -0
  183. package/dist/esm/migrations/index.js +37 -0
  184. package/dist/esm/migrations/index.js.map +1 -0
  185. package/dist/esm/test/TestTriggers.d.ts +12 -0
  186. package/dist/esm/test/TestTriggers.d.ts.map +1 -0
  187. package/dist/esm/test/TestTriggers.js +439 -0
  188. package/dist/esm/test/TestTriggers.js.map +1 -0
  189. package/docs/README.md +140 -0
  190. package/docs/api.md +1186 -0
  191. package/docs/concepts/channels.md +103 -0
  192. package/docs/concepts/claim-protocol.md +229 -0
  193. package/docs/concepts/policies.md +124 -0
  194. package/docs/concepts/schedules.md +134 -0
  195. package/docs/guides/choose-a-policy.md +113 -0
  196. package/docs/guides/declare-a-trigger.md +136 -0
  197. package/docs/guides/ingest-a-webhook.md +164 -0
  198. package/docs/guides/run-the-scheduler.md +173 -0
  199. package/docs/guides/testing.md +157 -0
  200. package/docs/installation.md +81 -0
  201. package/docs/quickstart.md +163 -0
  202. package/docs/troubleshooting.md +281 -0
  203. package/package.json +241 -3
  204. package/src/CatchUp.ts +73 -0
  205. package/src/Channel.ts +121 -0
  206. package/src/ClaimDecision.ts +303 -0
  207. package/src/Cron.ts +173 -0
  208. package/src/DispatchReader.ts +179 -0
  209. package/src/Overlap.ts +53 -0
  210. package/src/Schedule.ts +112 -0
  211. package/src/Scheduler.ts +1154 -0
  212. package/src/SqlTriggerStore.ts +638 -0
  213. package/src/Trigger.ts +84 -0
  214. package/src/TriggerError.ts +129 -0
  215. package/src/TriggerStore.ts +514 -0
  216. package/src/Webhook.ts +270 -0
  217. package/src/index.ts +30 -0
  218. package/src/internal/ActiveRuns.ts +83 -0
  219. package/src/internal/DueOccurrences.ts +101 -0
  220. package/src/internal/WallClock.ts +172 -0
  221. package/src/migrations/0001_triggers.ts +43 -0
  222. package/src/migrations/0002_reservation_lease.ts +20 -0
  223. package/src/migrations/0003_heartbeat.ts +24 -0
  224. package/src/migrations/0004_fire_run_index.ts +21 -0
  225. package/src/migrations/index.ts +40 -0
  226. package/src/test/TestTriggers.ts +563 -0
@@ -0,0 +1,411 @@
1
+ /**
2
+ * Durable trigger declaration and fire store.
3
+ *
4
+ * @see packages/smithers/agent/triggers/docs/api.md
5
+ *
6
+ * @since 0.1.0
7
+ */
8
+ import * as Context from "effect/Context";
9
+ import * as Effect from "effect/Effect";
10
+ import * as Layer from "effect/Layer";
11
+ import type * as Option from "effect/Option";
12
+ import * as Decode from "effect/Result";
13
+ import type { Action } from "./Overlap.ts";
14
+ import type { Trigger } from "./Trigger.ts";
15
+ import { TriggerError } from "./TriggerError.ts";
16
+ /**
17
+ * A stored trigger, with the revision that fences concurrent edits and
18
+ * when it last fired.
19
+ *
20
+ * @category models
21
+ * @since 0.1.0
22
+ */
23
+ export interface Registered extends Trigger {
24
+ readonly revision: number;
25
+ readonly lastFiredAt?: number | undefined;
26
+ }
27
+ /**
28
+ * One scheduled occurrence of a trigger, addressed by its occurrence
29
+ * number so a retry cannot fire it twice.
30
+ *
31
+ * @category models
32
+ * @since 0.1.0
33
+ */
34
+ export interface Fire {
35
+ readonly triggerId: string;
36
+ readonly occurrence: number;
37
+ }
38
+ /**
39
+ * A {@link Fire} together with the revision it was computed from and whether
40
+ * it is resuming a buffered occurrence.
41
+ *
42
+ * The overlap policy is deliberately absent. A claim applies the policy stored
43
+ * on the trigger row, read inside the same transaction, so a caller holding a
44
+ * stale snapshot cannot fire a trigger that has since been disabled, cannot
45
+ * point it at a different flow, and cannot supersede a run that the stored
46
+ * declaration says to leave alone. `expectedRevision` is the fence: a claim
47
+ * whose revision no longer matches the row is refused with `revision_mismatch`
48
+ * so the caller re-reads before deciding again.
49
+ *
50
+ * @category models
51
+ * @since 0.1.0
52
+ */
53
+ export interface ClaimFire extends Fire {
54
+ readonly expectedRevision: number;
55
+ readonly resumeBuffered?: boolean | undefined;
56
+ }
57
+ /**
58
+ * The outcome of claiming an occurrence: either another worker holds it, or
59
+ * this caller does and must take `action`.
60
+ *
61
+ * A claim that hands the caller work to launch always names the reservation it
62
+ * wrote against the trigger row, so the caller has an id to release. A claim
63
+ * that only records a decision has no reservation and names none: the two
64
+ * shapes are separate so a caller cannot read a reservation id that was never
65
+ * written.
66
+ *
67
+ * @category models
68
+ * @since 0.1.0
69
+ */
70
+ export type Claim = {
71
+ readonly claimed: false;
72
+ } | {
73
+ readonly claimed: true;
74
+ readonly action: Extract<Action, "skip" | "buffer">;
75
+ } | {
76
+ readonly claimed: true;
77
+ readonly action: Extract<Action, "fire" | "supersede">;
78
+ readonly reservationId: string;
79
+ readonly activeRunId?: string | undefined;
80
+ };
81
+ /**
82
+ * Time after which an uncommitted launch reservation may be reclaimed.
83
+ *
84
+ * Both store implementations use this value so swapping the test store for
85
+ * the SQL store cannot change recovery timing.
86
+ *
87
+ * @category constants
88
+ * @since 0.1.0
89
+ */
90
+ export declare const reservationLeaseMs: number;
91
+ /**
92
+ * The prefix marking an `active_run_id` that is a launch reservation rather
93
+ * than a run the runtime knows about.
94
+ *
95
+ * A reservation is written by the claim and replaced by the real run id once
96
+ * the launch reports one, so both stores and the scheduler read this prefix.
97
+ * It is a contract between them and lives here rather than being re-spelled at
98
+ * each site.
99
+ *
100
+ * @category constants
101
+ * @since 0.1.0
102
+ */
103
+ export declare const reservationPrefix = "trigger-reservation:";
104
+ /**
105
+ * The reservation id one occurrence of one trigger claims.
106
+ *
107
+ * @category constructors
108
+ * @since 0.1.0
109
+ */
110
+ export declare const reservationId: (triggerId: string, occurrence: number, attempt?: string) => string;
111
+ /**
112
+ * Whether a stored `active_run_id` is a launch reservation.
113
+ *
114
+ * @category predicates
115
+ * @since 0.1.0
116
+ */
117
+ export declare const isReservation: (runId: string | undefined) => boolean;
118
+ /**
119
+ * Reads the occurrence encoded in a launch reservation.
120
+ *
121
+ * @category getters
122
+ * @since 0.1.0
123
+ */
124
+ export declare const reservationOccurrence: (runId: string) => number | undefined;
125
+ /**
126
+ * How a claimed occurrence ended.
127
+ *
128
+ * @category models
129
+ * @since 0.1.0
130
+ */
131
+ export type Outcome = "launched" | "completed" | "skipped" | "buffered" | "superseded" | "failed";
132
+ /**
133
+ * The reported end of one occurrence, with the run it started when it
134
+ * launched one.
135
+ *
136
+ * @category models
137
+ * @since 0.1.0
138
+ */
139
+ export type Result = Fire & {
140
+ readonly error?: string | undefined;
141
+ } & ({
142
+ readonly outcome: "launched";
143
+ readonly runId: string;
144
+ readonly reservationId: string;
145
+ } | {
146
+ readonly outcome: Exclude<Outcome, "launched">;
147
+ readonly runId?: string | undefined;
148
+ readonly reservationId?: string | undefined;
149
+ });
150
+ /**
151
+ * Refuses results that no longer own a permissible fire transition.
152
+ * Launched run ids are validated at runtime for adapters outside TypeScript.
153
+ *
154
+ * @category predicates
155
+ * @since 1.0.0-rc.0
156
+ */
157
+ export declare const resultRefusal: (result: Result, fire: FireRecord | undefined, activeRunId: string | undefined) => TriggerError | undefined;
158
+ /**
159
+ * One row of the fire ledger: a claimed occurrence and what became of it.
160
+ *
161
+ * `outcome` is `null` between a claim and its `recordResult`, the window in
162
+ * which a launch is reserved but not yet reported.
163
+ *
164
+ * @category models
165
+ * @since 1.0.0-rc.0
166
+ */
167
+ export interface FireRecord extends Fire {
168
+ readonly outcome: Outcome | null;
169
+ readonly runId?: string | undefined;
170
+ readonly error?: string | undefined;
171
+ }
172
+ /**
173
+ * A ledger query. Every filter narrows; `cursor` is the last record of the
174
+ * previous page, so the page after it holds only older records; `limit` caps
175
+ * a page and must be a positive safe integer when stated. With no limit the
176
+ * whole ledger answers in one page.
177
+ *
178
+ * @category models
179
+ * @since 1.0.0-rc.0
180
+ */
181
+ export interface HistoryQuery {
182
+ readonly triggerId?: string | undefined;
183
+ readonly runId?: string | undefined;
184
+ readonly outcome?: Outcome | undefined;
185
+ readonly cursor?: Fire | undefined;
186
+ readonly limit?: number | undefined;
187
+ }
188
+ /**
189
+ * One page of the ledger, newest occurrence first, with the cursor that
190
+ * addresses the next page when the limit cut the page short.
191
+ *
192
+ * @category models
193
+ * @since 1.0.0-rc.0
194
+ */
195
+ export interface HistoryPage {
196
+ readonly items: ReadonlyArray<FireRecord>;
197
+ readonly nextCursor?: Fire | undefined;
198
+ }
199
+ /**
200
+ * What one trigger holds right now: the run or launch reservation on its row
201
+ * and the occurrence buffered behind it. A plain read; `activeRun` is the read
202
+ * that expires a stale reservation.
203
+ *
204
+ * @category models
205
+ * @since 1.0.0-rc.0
206
+ */
207
+ export interface Held {
208
+ readonly activeRunId?: string | undefined;
209
+ readonly pendingAt?: number | undefined;
210
+ }
211
+ /**
212
+ * One row of a listing: what the trigger holds right now, and either the
213
+ * declaration the row decoded to or the failure it could not be read through.
214
+ *
215
+ * `trigger` is an `effect/Result`: narrow it with `Result.isFailure` before
216
+ * reading the declaration. An undecodable row is isolated here rather than
217
+ * failing the whole listing,
218
+ * so one corrupt input cannot stop every other trigger from being scheduled.
219
+ * The held state travels with the row because a scheduler tick would otherwise
220
+ * ask for it again per trigger, once to expire a reservation that is not there
221
+ * and once for a buffered occurrence that is not there either.
222
+ *
223
+ * @category models
224
+ * @since 1.0.0-rc.0
225
+ */
226
+ export interface Listed extends Held {
227
+ readonly triggerId: string;
228
+ readonly trigger: Decode.Result<Registered, TriggerError>;
229
+ }
230
+ /**
231
+ * A listed row for a declaration that decoded, holding what the trigger holds
232
+ * right now. Both stores build their rows through this, so a caller composing
233
+ * a store or a scheduler fixture of its own does not restate the shape.
234
+ *
235
+ * @category constructors
236
+ * @since 1.0.0-rc.0
237
+ */
238
+ export declare const listed: (trigger: Registered, held?: Held) => Listed;
239
+ /**
240
+ * The last poll one scheduler host recorded.
241
+ *
242
+ * @category models
243
+ * @since 1.0.0-rc.0
244
+ */
245
+ export interface Heartbeat {
246
+ readonly host: string;
247
+ readonly tickedAt: number;
248
+ }
249
+ /**
250
+ * Validates a {@link HistoryQuery} limit: absent, or a positive safe integer.
251
+ * Both stores apply this before reading so swapping one for the other cannot
252
+ * change which queries are refused.
253
+ *
254
+ * @category constructors
255
+ * @since 1.0.0-rc.0
256
+ */
257
+ export declare const historyLimit: (limit: number | undefined) => Effect.Effect<number | undefined, TriggerError>;
258
+ /**
259
+ * Validates a prune cutoff: any safe integer. Both stores apply this before
260
+ * deleting so swapping one for the other cannot change which cutoffs are
261
+ * refused.
262
+ *
263
+ * @category constructors
264
+ * @since 1.0.0-rc.0
265
+ */
266
+ export declare const pruneCutoff: (olderThan: number) => Effect.Effect<number, TriggerError>;
267
+ /**
268
+ * Newest occurrence first; equal occurrences of different triggers order by
269
+ * descending trigger id so a cursor names one position.
270
+ *
271
+ * @category ordering
272
+ * @since 1.0.0-rc.0
273
+ */
274
+ export declare const compareNewestFirst: (left: Fire, right: Fire) => number;
275
+ /**
276
+ * Whether a record lies after `cursor` in {@link compareNewestFirst} order.
277
+ *
278
+ * @category predicates
279
+ * @since 1.0.0-rc.0
280
+ */
281
+ export declare const isAfterCursor: (record: Fire, cursor: Fire) => boolean;
282
+ /**
283
+ * Cuts an ordered, filtered record list to one page. The caller fetches one
284
+ * record past the limit; that record's presence is what says a next page
285
+ * exists, and the page's last record is the cursor addressing it.
286
+ *
287
+ * @category constructors
288
+ * @since 1.0.0-rc.0
289
+ */
290
+ export declare const historyPage: (records: ReadonlyArray<FireRecord>, limit: number | undefined) => HistoryPage;
291
+ /**
292
+ * Durable trigger state: registration, listing, and the claim protocol that
293
+ * keeps two schedulers from firing the same occurrence.
294
+ *
295
+ * Neither listing is a due-time query. Due-ness is a cron computation the
296
+ * scheduler performs against its own watermark, so the store is asked only for
297
+ * the rows eligible to be considered. A scheduler tick reads `list`, not
298
+ * `listEnabled`: a disabled trigger can still hold an active occurrence that
299
+ * has to recover, and the tick skips only its new claims. `listEnabled`
300
+ * answers the narrower question for a caller that wants the declarations.
301
+ *
302
+ * A claim, result, pending-state, or active-run method fails with
303
+ * `unknown_trigger` when the row it addresses does not exist. `get` answers
304
+ * `None` for an absent row and `register` creates one. `clearActive` is a
305
+ * compare-and-swap that cannot tell a missing trigger from a run id that no
306
+ * longer matches, so it stays a no-op for both. `history`, `pruneFires`,
307
+ * `heartbeat`, and `lastHeartbeat` address the whole store.
308
+ *
309
+ * @category models
310
+ * @since 0.1.0
311
+ */
312
+ export interface Service {
313
+ readonly register: (trigger: Trigger) => Effect.Effect<Registered, TriggerError>;
314
+ readonly get: (triggerId: string) => Effect.Effect<Option.Option<Registered>, TriggerError>;
315
+ /**
316
+ * Every trigger, enabled or not, ordered by id. This is what a scheduler
317
+ * tick polls: see {@link Listed} for why a row carries its decode result and
318
+ * its held state rather than a bare declaration.
319
+ */
320
+ readonly list: () => Effect.Effect<ReadonlyArray<Listed>, TriggerError>;
321
+ readonly listEnabled: () => Effect.Effect<ReadonlyArray<Registered>, TriggerError>;
322
+ readonly claimFire: (fire: ClaimFire) => Effect.Effect<Claim, TriggerError>;
323
+ /**
324
+ * Claims the buffered occurrence, when one exists.
325
+ *
326
+ * One transaction reads the occurrence, applies the same claim protocol as
327
+ * {@link Service.claimFire}, and clears the buffer only when the decision
328
+ * consumes it. A concurrent buffer decision keeps it pending. No failure can
329
+ * land between reading the buffer and claiming it.
330
+ */
331
+ readonly claimPending: (fire: {
332
+ readonly triggerId: string;
333
+ readonly expectedRevision: number;
334
+ }) => Effect.Effect<Option.Option<{
335
+ readonly occurrence: number;
336
+ readonly claim: Claim;
337
+ }>, TriggerError>;
338
+ readonly recordResult: (result: Result) => Effect.Effect<void, TriggerError>;
339
+ /** Atomically re-arms unfinished work and releases only its matching reservation.
340
+ * A retained predecessor is restored with the pending pointer in the same write.
341
+ * A stale token fails with `stale_owner`; a failed write leaves the lease intact.
342
+ */
343
+ readonly restorePending: (fire: Fire & {
344
+ readonly reservationId: string;
345
+ }) => Effect.Effect<void, TriggerError>;
346
+ readonly setPending: (fire: Fire) => Effect.Effect<void, TriggerError>;
347
+ readonly activeRun: (triggerId: string) => Effect.Effect<Option.Option<string>, TriggerError>;
348
+ /**
349
+ * Returns the occurrence owned by one active run or launch reservation.
350
+ *
351
+ * `lastFiredAt` cannot answer this: later skipped and buffered occurrences
352
+ * advance that cursor while an older run remains active.
353
+ */
354
+ readonly activeOccurrence: (triggerId: string, runId: string) => Effect.Effect<Option.Option<number>, TriggerError>;
355
+ readonly clearActive: (triggerId: string, runId: string) => Effect.Effect<void, TriggerError>;
356
+ /**
357
+ * Reads the fire ledger newest first. See {@link HistoryQuery} for the
358
+ * filters and paging contract; a limit that is not a positive safe integer
359
+ * is refused with `invalid_options`.
360
+ */
361
+ readonly history: (query?: HistoryQuery) => Effect.Effect<HistoryPage, TriggerError>;
362
+ /**
363
+ * Deletes settled fire ledger rows older than `olderThan`, answering how
364
+ * many it removed. Nothing else in the store deletes from the ledger, so a
365
+ * host that never calls this keeps one row per occurrence forever.
366
+ *
367
+ * A row is settled when its outcome is `completed`, `failed`, `skipped`, or
368
+ * `superseded`. The occurrence a trigger currently buffers and the row
369
+ * naming its active run are kept whatever their age, so pruning cannot take
370
+ * state the scheduler still reads. `olderThan` that is not a safe integer is
371
+ * refused with `invalid_options`.
372
+ */
373
+ readonly pruneFires: (options: {
374
+ readonly olderThan: number;
375
+ }) => Effect.Effect<number, TriggerError>;
376
+ /**
377
+ * Reads what one trigger holds without expiring anything, so a listing can
378
+ * report a reservation or a buffered occurrence exactly as the row has it.
379
+ */
380
+ readonly inspect: (triggerId: string) => Effect.Effect<Held, TriggerError>;
381
+ /** Records that `host` polled the store at the store clock's current time. */
382
+ readonly heartbeat: (host: string) => Effect.Effect<void, TriggerError>;
383
+ /** The most recent heartbeat across every host, or `None` when no scheduler has ever polled. */
384
+ readonly lastHeartbeat: () => Effect.Effect<Option.Option<Heartbeat>, TriggerError>;
385
+ }
386
+ declare const TriggerStore_base: Context.ServiceClass<TriggerStore, "flows/triggers/TriggerStore", Service>;
387
+ /**
388
+ * The {@link Service} tag.
389
+ *
390
+ * @category services
391
+ * @since 0.1.0
392
+ */
393
+ export declare class TriggerStore extends TriggerStore_base {
394
+ }
395
+ /**
396
+ * A {@link Service} that fails every method as unavailable, for an
397
+ * environment with no trigger store. Overrides replace individual methods.
398
+ *
399
+ * @category constructors
400
+ * @since 0.1.0
401
+ */
402
+ export declare const makeNoop: (overrides?: Partial<Service>) => Service;
403
+ /**
404
+ * Provides {@link makeNoop}.
405
+ *
406
+ * @category layers
407
+ * @since 0.1.0
408
+ */
409
+ export declare const layerNoop: (overrides?: Partial<Service>) => Layer.Layer<TriggerStore>;
410
+ export {};
411
+ //# sourceMappingURL=TriggerStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TriggerStore.d.ts","sourceRoot":"","sources":["../../src/TriggerStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var TriggerStore_exports = {};
30
+ __export(TriggerStore_exports, {
31
+ TriggerStore: () => TriggerStore,
32
+ compareNewestFirst: () => compareNewestFirst,
33
+ historyLimit: () => historyLimit,
34
+ historyPage: () => historyPage,
35
+ isAfterCursor: () => isAfterCursor,
36
+ isReservation: () => isReservation,
37
+ layerNoop: () => layerNoop,
38
+ listed: () => listed,
39
+ makeNoop: () => makeNoop,
40
+ pruneCutoff: () => pruneCutoff,
41
+ reservationId: () => reservationId,
42
+ reservationLeaseMs: () => reservationLeaseMs,
43
+ reservationOccurrence: () => reservationOccurrence,
44
+ reservationPrefix: () => reservationPrefix,
45
+ resultRefusal: () => resultRefusal
46
+ });
47
+ module.exports = __toCommonJS(TriggerStore_exports);
48
+ var Context = __toESM(require("effect/Context"), 1);
49
+ var Effect = __toESM(require("effect/Effect"), 1);
50
+ var Layer = __toESM(require("effect/Layer"), 1);
51
+ var Decode = __toESM(require("effect/Result"), 1);
52
+ var import_TriggerError = require("./TriggerError.js");
53
+ const reservationLeaseMs = 5 * 60 * 1e3;
54
+ const reservationPrefix = "trigger-reservation:";
55
+ const reservationId = (triggerId, occurrence, attempt) => `${reservationPrefix}${triggerId}:${attempt === void 0 ? "" : `${attempt}:`}${occurrence}`;
56
+ const isReservation = (runId) => runId !== void 0 && runId.startsWith(reservationPrefix);
57
+ const reservationOccurrence = (runId) => {
58
+ if (!isReservation(runId)) return void 0;
59
+ const occurrence = Number(runId.slice(runId.lastIndexOf(":") + 1));
60
+ return Number.isFinite(occurrence) ? occurrence : void 0;
61
+ };
62
+ const resultRefusal = (result, fire, activeRunId) => {
63
+ if (result.outcome === "launched" && (typeof result.runId !== "string" || result.runId.trim().length === 0)) {
64
+ return new import_TriggerError.TriggerError({ code: "invalid_options", message: "launched requires a non-empty runId", path: "runId" });
65
+ }
66
+ const unfinished = fire?.outcome === null || fire?.outcome === "buffered";
67
+ const reservation = activeRunId !== void 0 && isReservation(activeRunId) && reservationOccurrence(activeRunId) === result.occurrence;
68
+ const owner = result.reservationId ?? result.runId ?? (reservation ? activeRunId : void 0);
69
+ const permitted = result.outcome === "launched" ? unfinished && reservation && result.reservationId === activeRunId : fire !== void 0 && // A repeated decision or settlement is harmless; callers do not rewrite it.
70
+ (fire.outcome === result.outcome && (result.runId === void 0 || result.runId === fire.runId) || fire.outcome === "launched" && result.outcome !== "skipped" && result.outcome !== "buffered" && result.reservationId === void 0 && (result.runId === void 0 || result.runId === fire.runId) || unfinished && reservation && owner === activeRunId);
71
+ return permitted ? void 0 : new import_TriggerError.TriggerError({
72
+ code: "stale_owner",
73
+ message: `result no longer owns trigger ${result.triggerId} occurrence ${result.occurrence}`
74
+ });
75
+ };
76
+ const listed = (trigger, held = {}) => ({
77
+ triggerId: trigger.id,
78
+ trigger: Decode.succeed(trigger),
79
+ ...held
80
+ });
81
+ const historyLimit = (limit) => limit === void 0 || Number.isSafeInteger(limit) && limit > 0 ? Effect.succeed(limit) : Effect.fail(
82
+ new import_TriggerError.TriggerError({
83
+ code: "invalid_options",
84
+ message: `history limit must be a positive safe integer, received ${limit}`,
85
+ path: "limit"
86
+ })
87
+ );
88
+ const pruneCutoff = (olderThan) => Number.isSafeInteger(olderThan) ? Effect.succeed(olderThan) : Effect.fail(
89
+ new import_TriggerError.TriggerError({
90
+ code: "invalid_options",
91
+ message: `prune cutoff must be a safe integer, received ${olderThan}`,
92
+ path: "olderThan"
93
+ })
94
+ );
95
+ const compareNewestFirst = (left, right) => right.occurrence - left.occurrence || (right.triggerId < left.triggerId ? -1 : right.triggerId > left.triggerId ? 1 : 0);
96
+ const isAfterCursor = (record, cursor) => compareNewestFirst(cursor, record) < 0;
97
+ const historyPage = (records, limit) => {
98
+ if (limit === void 0 || records.length <= limit) return { items: records };
99
+ const items = records.slice(0, limit);
100
+ const last = items[items.length - 1];
101
+ return { items, nextCursor: { triggerId: last.triggerId, occurrence: last.occurrence } };
102
+ };
103
+ class TriggerStore extends Context.Service()("flows/triggers/TriggerStore") {
104
+ }
105
+ const unavailable = (method) => Effect.fail(new import_TriggerError.TriggerError({ code: "store", message: `${method} is unavailable` }));
106
+ const makeNoop = (overrides = {}) => ({
107
+ register: () => unavailable("register"),
108
+ get: () => unavailable("get"),
109
+ list: () => unavailable("list"),
110
+ listEnabled: () => unavailable("listEnabled"),
111
+ claimFire: () => unavailable("claimFire"),
112
+ claimPending: () => unavailable("claimPending"),
113
+ recordResult: () => unavailable("recordResult"),
114
+ restorePending: () => unavailable("restorePending"),
115
+ setPending: () => unavailable("setPending"),
116
+ activeRun: () => unavailable("activeRun"),
117
+ activeOccurrence: () => unavailable("activeOccurrence"),
118
+ clearActive: () => unavailable("clearActive"),
119
+ history: () => unavailable("history"),
120
+ pruneFires: () => unavailable("pruneFires"),
121
+ inspect: () => unavailable("inspect"),
122
+ heartbeat: () => unavailable("heartbeat"),
123
+ lastHeartbeat: () => unavailable("lastHeartbeat"),
124
+ ...overrides
125
+ });
126
+ const layerNoop = (overrides = {}) => Layer.succeed(TriggerStore)(makeNoop(overrides));
127
+ //# sourceMappingURL=TriggerStore.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/TriggerStore.ts"],
4
+ "sourcesContent": ["/**\n * Durable trigger declaration and fire store.\n *\n * @see packages/smithers/agent/triggers/docs/api.md\n *\n * @since 0.1.0\n */\n\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport type * as Option from \"effect/Option\"\n// `Result` already names the reported end of an occurrence in this module, so\n// the `effect/Result` a listed row decodes to is imported as `Decode`.\nimport * as Decode from \"effect/Result\"\nimport type { Action } from \"./Overlap.ts\"\nimport type { Trigger } from \"./Trigger.ts\"\nimport { TriggerError } from \"./TriggerError.ts\"\n\n/**\n * A stored trigger, with the revision that fences concurrent edits and\n * when it last fired.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Registered extends Trigger {\n readonly revision: number\n readonly lastFiredAt?: number | undefined\n}\n/**\n * One scheduled occurrence of a trigger, addressed by its occurrence\n * number so a retry cannot fire it twice.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Fire {\n readonly triggerId: string\n readonly occurrence: number\n}\n/**\n * A {@link Fire} together with the revision it was computed from and whether\n * it is resuming a buffered occurrence.\n *\n * The overlap policy is deliberately absent. A claim applies the policy stored\n * on the trigger row, read inside the same transaction, so a caller holding a\n * stale snapshot cannot fire a trigger that has since been disabled, cannot\n * point it at a different flow, and cannot supersede a run that the stored\n * declaration says to leave alone. `expectedRevision` is the fence: a claim\n * whose revision no longer matches the row is refused with `revision_mismatch`\n * so the caller re-reads before deciding again.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface ClaimFire extends Fire {\n readonly expectedRevision: number\n readonly resumeBuffered?: boolean | undefined\n}\n/**\n * The outcome of claiming an occurrence: either another worker holds it, or\n * this caller does and must take `action`.\n *\n * A claim that hands the caller work to launch always names the reservation it\n * wrote against the trigger row, so the caller has an id to release. A claim\n * that only records a decision has no reservation and names none: the two\n * shapes are separate so a caller cannot read a reservation id that was never\n * written.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Claim =\n | { readonly claimed: false }\n | { readonly claimed: true; readonly action: Extract<Action, \"skip\" | \"buffer\"> }\n | {\n readonly claimed: true\n readonly action: Extract<Action, \"fire\" | \"supersede\">\n readonly reservationId: string\n readonly activeRunId?: string | undefined\n }\n\n/**\n * Time after which an uncommitted launch reservation may be reclaimed.\n *\n * Both store implementations use this value so swapping the test store for\n * the SQL store cannot change recovery timing.\n *\n * @category constants\n * @since 0.1.0\n */\nexport const reservationLeaseMs = 5 * 60 * 1000\n\n/**\n * The prefix marking an `active_run_id` that is a launch reservation rather\n * than a run the runtime knows about.\n *\n * A reservation is written by the claim and replaced by the real run id once\n * the launch reports one, so both stores and the scheduler read this prefix.\n * It is a contract between them and lives here rather than being re-spelled at\n * each site.\n *\n * @category constants\n * @since 0.1.0\n */\nexport const reservationPrefix = \"trigger-reservation:\"\n\n/**\n * The reservation id one occurrence of one trigger claims.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const reservationId = (triggerId: string, occurrence: number, attempt?: string): string =>\n `${reservationPrefix}${triggerId}:${attempt === undefined ? \"\" : `${attempt}:`}${occurrence}`\n\n/**\n * Whether a stored `active_run_id` is a launch reservation.\n *\n * @category predicates\n * @since 0.1.0\n */\nexport const isReservation = (runId: string | undefined): boolean =>\n runId !== undefined && runId.startsWith(reservationPrefix)\n\n/**\n * Reads the occurrence encoded in a launch reservation.\n *\n * @category getters\n * @since 0.1.0\n */\nexport const reservationOccurrence = (runId: string): number | undefined => {\n if (!isReservation(runId)) return undefined\n const occurrence = Number(runId.slice(runId.lastIndexOf(\":\") + 1))\n return Number.isFinite(occurrence) ? occurrence : undefined\n}\n\n/**\n * How a claimed occurrence ended.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Outcome = \"launched\" | \"completed\" | \"skipped\" | \"buffered\" | \"superseded\" | \"failed\"\n/**\n * The reported end of one occurrence, with the run it started when it\n * launched one.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Result =\n & Fire\n & { readonly error?: string | undefined }\n & (\n | { readonly outcome: \"launched\"; readonly runId: string; readonly reservationId: string }\n | {\n readonly outcome: Exclude<Outcome, \"launched\">\n readonly runId?: string | undefined\n readonly reservationId?: string | undefined\n }\n )\n\n/**\n * Refuses results that no longer own a permissible fire transition.\n * Launched run ids are validated at runtime for adapters outside TypeScript.\n *\n * @category predicates\n * @since 1.0.0-rc.0\n */\nexport const resultRefusal = (\n result: Result,\n fire: FireRecord | undefined,\n activeRunId: string | undefined\n): TriggerError | undefined => {\n if (result.outcome === \"launched\" && (typeof result.runId !== \"string\" || result.runId.trim().length === 0)) {\n return new TriggerError({ code: \"invalid_options\", message: \"launched requires a non-empty runId\", path: \"runId\" })\n }\n const unfinished = fire?.outcome === null || fire?.outcome === \"buffered\"\n const reservation = activeRunId !== undefined && isReservation(activeRunId) &&\n reservationOccurrence(activeRunId) === result.occurrence\n const owner = result.reservationId ?? result.runId ?? (reservation ? activeRunId : undefined)\n const permitted = result.outcome === \"launched\"\n ? unfinished && reservation && result.reservationId === activeRunId\n : fire !== undefined && (\n // A repeated decision or settlement is harmless; callers do not rewrite it.\n (fire.outcome === result.outcome && (result.runId === undefined || result.runId === fire.runId)) ||\n (fire.outcome === \"launched\" && result.outcome !== \"skipped\" && result.outcome !== \"buffered\" &&\n result.reservationId === undefined && (result.runId === undefined || result.runId === fire.runId)) ||\n (unfinished && reservation && owner === activeRunId)\n )\n return permitted ? undefined : new TriggerError({\n code: \"stale_owner\",\n message: `result no longer owns trigger ${result.triggerId} occurrence ${result.occurrence}`\n })\n}\n\n/**\n * One row of the fire ledger: a claimed occurrence and what became of it.\n *\n * `outcome` is `null` between a claim and its `recordResult`, the window in\n * which a launch is reserved but not yet reported.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface FireRecord extends Fire {\n readonly outcome: Outcome | null\n readonly runId?: string | undefined\n readonly error?: string | undefined\n}\n\n/**\n * A ledger query. Every filter narrows; `cursor` is the last record of the\n * previous page, so the page after it holds only older records; `limit` caps\n * a page and must be a positive safe integer when stated. With no limit the\n * whole ledger answers in one page.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface HistoryQuery {\n readonly triggerId?: string | undefined\n readonly runId?: string | undefined\n readonly outcome?: Outcome | undefined\n readonly cursor?: Fire | undefined\n readonly limit?: number | undefined\n}\n\n/**\n * One page of the ledger, newest occurrence first, with the cursor that\n * addresses the next page when the limit cut the page short.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface HistoryPage {\n readonly items: ReadonlyArray<FireRecord>\n readonly nextCursor?: Fire | undefined\n}\n\n/**\n * What one trigger holds right now: the run or launch reservation on its row\n * and the occurrence buffered behind it. A plain read; `activeRun` is the read\n * that expires a stale reservation.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Held {\n readonly activeRunId?: string | undefined\n readonly pendingAt?: number | undefined\n}\n\n/**\n * One row of a listing: what the trigger holds right now, and either the\n * declaration the row decoded to or the failure it could not be read through.\n *\n * `trigger` is an `effect/Result`: narrow it with `Result.isFailure` before\n * reading the declaration. An undecodable row is isolated here rather than\n * failing the whole listing,\n * so one corrupt input cannot stop every other trigger from being scheduled.\n * The held state travels with the row because a scheduler tick would otherwise\n * ask for it again per trigger, once to expire a reservation that is not there\n * and once for a buffered occurrence that is not there either.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Listed extends Held {\n readonly triggerId: string\n readonly trigger: Decode.Result<Registered, TriggerError>\n}\n\n/**\n * A listed row for a declaration that decoded, holding what the trigger holds\n * right now. Both stores build their rows through this, so a caller composing\n * a store or a scheduler fixture of its own does not restate the shape.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const listed = (trigger: Registered, held: Held = {}): Listed => ({\n triggerId: trigger.id,\n trigger: Decode.succeed(trigger),\n ...held\n})\n\n/**\n * The last poll one scheduler host recorded.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Heartbeat {\n readonly host: string\n readonly tickedAt: number\n}\n\n/**\n * Validates a {@link HistoryQuery} limit: absent, or a positive safe integer.\n * Both stores apply this before reading so swapping one for the other cannot\n * change which queries are refused.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const historyLimit = (limit: number | undefined): Effect.Effect<number | undefined, TriggerError> =>\n limit === undefined || (Number.isSafeInteger(limit) && limit > 0)\n ? Effect.succeed(limit)\n : Effect.fail(\n new TriggerError({\n code: \"invalid_options\",\n message: `history limit must be a positive safe integer, received ${limit}`,\n path: \"limit\"\n })\n )\n\n/**\n * Validates a prune cutoff: any safe integer. Both stores apply this before\n * deleting so swapping one for the other cannot change which cutoffs are\n * refused.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const pruneCutoff = (olderThan: number): Effect.Effect<number, TriggerError> =>\n Number.isSafeInteger(olderThan)\n ? Effect.succeed(olderThan)\n : Effect.fail(\n new TriggerError({\n code: \"invalid_options\",\n message: `prune cutoff must be a safe integer, received ${olderThan}`,\n path: \"olderThan\"\n })\n )\n\n/**\n * Newest occurrence first; equal occurrences of different triggers order by\n * descending trigger id so a cursor names one position.\n *\n * @category ordering\n * @since 1.0.0-rc.0\n */\nexport const compareNewestFirst = (left: Fire, right: Fire): number =>\n right.occurrence - left.occurrence ||\n (right.triggerId < left.triggerId ? -1 : right.triggerId > left.triggerId ? 1 : 0)\n\n/**\n * Whether a record lies after `cursor` in {@link compareNewestFirst} order.\n *\n * @category predicates\n * @since 1.0.0-rc.0\n */\nexport const isAfterCursor = (record: Fire, cursor: Fire): boolean => compareNewestFirst(cursor, record) < 0\n\n/**\n * Cuts an ordered, filtered record list to one page. The caller fetches one\n * record past the limit; that record's presence is what says a next page\n * exists, and the page's last record is the cursor addressing it.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const historyPage = (records: ReadonlyArray<FireRecord>, limit: number | undefined): HistoryPage => {\n if (limit === undefined || records.length <= limit) return { items: records }\n const items = records.slice(0, limit)\n const last = items[items.length - 1] as FireRecord\n return { items, nextCursor: { triggerId: last.triggerId, occurrence: last.occurrence } }\n}\n\n/**\n * Durable trigger state: registration, listing, and the claim protocol that\n * keeps two schedulers from firing the same occurrence.\n *\n * Neither listing is a due-time query. Due-ness is a cron computation the\n * scheduler performs against its own watermark, so the store is asked only for\n * the rows eligible to be considered. A scheduler tick reads `list`, not\n * `listEnabled`: a disabled trigger can still hold an active occurrence that\n * has to recover, and the tick skips only its new claims. `listEnabled`\n * answers the narrower question for a caller that wants the declarations.\n *\n * A claim, result, pending-state, or active-run method fails with\n * `unknown_trigger` when the row it addresses does not exist. `get` answers\n * `None` for an absent row and `register` creates one. `clearActive` is a\n * compare-and-swap that cannot tell a missing trigger from a run id that no\n * longer matches, so it stays a no-op for both. `history`, `pruneFires`,\n * `heartbeat`, and `lastHeartbeat` address the whole store.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Service {\n readonly register: (trigger: Trigger) => Effect.Effect<Registered, TriggerError>\n readonly get: (triggerId: string) => Effect.Effect<Option.Option<Registered>, TriggerError>\n /**\n * Every trigger, enabled or not, ordered by id. This is what a scheduler\n * tick polls: see {@link Listed} for why a row carries its decode result and\n * its held state rather than a bare declaration.\n */\n readonly list: () => Effect.Effect<ReadonlyArray<Listed>, TriggerError>\n readonly listEnabled: () => Effect.Effect<ReadonlyArray<Registered>, TriggerError>\n readonly claimFire: (fire: ClaimFire) => Effect.Effect<Claim, TriggerError>\n /**\n * Claims the buffered occurrence, when one exists.\n *\n * One transaction reads the occurrence, applies the same claim protocol as\n * {@link Service.claimFire}, and clears the buffer only when the decision\n * consumes it. A concurrent buffer decision keeps it pending. No failure can\n * land between reading the buffer and claiming it.\n */\n readonly claimPending: (fire: {\n readonly triggerId: string\n readonly expectedRevision: number\n }) => Effect.Effect<\n Option.Option<{ readonly occurrence: number; readonly claim: Claim }>,\n TriggerError\n >\n readonly recordResult: (result: Result) => Effect.Effect<void, TriggerError>\n /** Atomically re-arms unfinished work and releases only its matching reservation.\n * A retained predecessor is restored with the pending pointer in the same write.\n * A stale token fails with `stale_owner`; a failed write leaves the lease intact.\n */\n readonly restorePending: (fire: Fire & { readonly reservationId: string }) => Effect.Effect<void, TriggerError>\n readonly setPending: (fire: Fire) => Effect.Effect<void, TriggerError>\n readonly activeRun: (triggerId: string) => Effect.Effect<Option.Option<string>, TriggerError>\n /**\n * Returns the occurrence owned by one active run or launch reservation.\n *\n * `lastFiredAt` cannot answer this: later skipped and buffered occurrences\n * advance that cursor while an older run remains active.\n */\n readonly activeOccurrence: (\n triggerId: string,\n runId: string\n ) => Effect.Effect<Option.Option<number>, TriggerError>\n readonly clearActive: (triggerId: string, runId: string) => Effect.Effect<void, TriggerError>\n /**\n * Reads the fire ledger newest first. See {@link HistoryQuery} for the\n * filters and paging contract; a limit that is not a positive safe integer\n * is refused with `invalid_options`.\n */\n readonly history: (query?: HistoryQuery) => Effect.Effect<HistoryPage, TriggerError>\n /**\n * Deletes settled fire ledger rows older than `olderThan`, answering how\n * many it removed. Nothing else in the store deletes from the ledger, so a\n * host that never calls this keeps one row per occurrence forever.\n *\n * A row is settled when its outcome is `completed`, `failed`, `skipped`, or\n * `superseded`. The occurrence a trigger currently buffers and the row\n * naming its active run are kept whatever their age, so pruning cannot take\n * state the scheduler still reads. `olderThan` that is not a safe integer is\n * refused with `invalid_options`.\n */\n readonly pruneFires: (options: { readonly olderThan: number }) => Effect.Effect<number, TriggerError>\n /**\n * Reads what one trigger holds without expiring anything, so a listing can\n * report a reservation or a buffered occurrence exactly as the row has it.\n */\n readonly inspect: (triggerId: string) => Effect.Effect<Held, TriggerError>\n /** Records that `host` polled the store at the store clock's current time. */\n readonly heartbeat: (host: string) => Effect.Effect<void, TriggerError>\n /** The most recent heartbeat across every host, or `None` when no scheduler has ever polled. */\n readonly lastHeartbeat: () => Effect.Effect<Option.Option<Heartbeat>, TriggerError>\n}\n\n/**\n * The {@link Service} tag.\n *\n * @category services\n * @since 0.1.0\n */\nexport class TriggerStore extends Context.Service<TriggerStore, Service>()(\"flows/triggers/TriggerStore\") {}\n\nconst unavailable = (method: string): Effect.Effect<never, TriggerError> =>\n Effect.fail(new TriggerError({ code: \"store\", message: `${method} is unavailable` }))\n\n/**\n * A {@link Service} that fails every method as unavailable, for an\n * environment with no trigger store. Overrides replace individual methods.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const makeNoop = (overrides: Partial<Service> = {}): Service => ({\n register: () => unavailable(\"register\"),\n get: () => unavailable(\"get\"),\n list: () => unavailable(\"list\"),\n listEnabled: () => unavailable(\"listEnabled\"),\n claimFire: () => unavailable(\"claimFire\"),\n claimPending: () => unavailable(\"claimPending\"),\n recordResult: () => unavailable(\"recordResult\"),\n restorePending: () => unavailable(\"restorePending\"),\n setPending: () => unavailable(\"setPending\"),\n activeRun: () => unavailable(\"activeRun\"),\n activeOccurrence: () => unavailable(\"activeOccurrence\"),\n clearActive: () => unavailable(\"clearActive\"),\n history: () => unavailable(\"history\"),\n pruneFires: () => unavailable(\"pruneFires\"),\n inspect: () => unavailable(\"inspect\"),\n heartbeat: () => unavailable(\"heartbeat\"),\n lastHeartbeat: () => unavailable(\"lastHeartbeat\"),\n ...overrides\n})\n\n/**\n * Provides {@link makeNoop}.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerNoop = (overrides: Partial<Service> = {}): Layer.Layer<TriggerStore> =>\n Layer.succeed(TriggerStore)(makeNoop(overrides))\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }