@smthrs/triggers 1.0.0-rc.5 → 1.0.0-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/SqlTriggerStore.d.ts +1 -1
- package/dist/cjs/SqlTriggerStore.d.ts.map +1 -1
- package/dist/cjs/SqlTriggerStore.js +1 -1
- package/dist/cjs/SqlTriggerStore.js.map +1 -1
- package/dist/cjs/migrations/0001_triggers.d.ts +1 -1
- package/dist/cjs/migrations/0001_triggers.d.ts.map +1 -1
- package/dist/cjs/migrations/0001_triggers.js +1 -1
- package/dist/cjs/migrations/0001_triggers.js.map +1 -1
- package/dist/cjs/migrations/0002_reservation_lease.d.ts +1 -1
- package/dist/cjs/migrations/0002_reservation_lease.d.ts.map +1 -1
- package/dist/cjs/migrations/0002_reservation_lease.js +1 -1
- package/dist/cjs/migrations/0002_reservation_lease.js.map +1 -1
- package/dist/cjs/migrations/0003_heartbeat.d.ts +1 -1
- package/dist/cjs/migrations/0003_heartbeat.d.ts.map +1 -1
- package/dist/cjs/migrations/0003_heartbeat.js +1 -1
- package/dist/cjs/migrations/0003_heartbeat.js.map +1 -1
- package/dist/cjs/migrations/0004_fire_run_index.d.ts +1 -1
- package/dist/cjs/migrations/0004_fire_run_index.d.ts.map +1 -1
- package/dist/cjs/migrations/0004_fire_run_index.js +1 -1
- package/dist/cjs/migrations/0004_fire_run_index.js.map +1 -1
- package/dist/cjs/migrations/index.d.ts +7 -7
- package/dist/cjs/migrations/index.d.ts.map +1 -1
- package/dist/cjs/migrations/index.js +1 -1
- package/dist/cjs/migrations/index.js.map +1 -1
- package/dist/esm/SqlTriggerStore.d.ts +1 -1
- package/dist/esm/SqlTriggerStore.d.ts.map +1 -1
- package/dist/esm/SqlTriggerStore.js +1 -1
- package/dist/esm/SqlTriggerStore.js.map +1 -1
- package/dist/esm/migrations/0001_triggers.d.ts +1 -1
- package/dist/esm/migrations/0001_triggers.d.ts.map +1 -1
- package/dist/esm/migrations/0001_triggers.js +1 -1
- package/dist/esm/migrations/0001_triggers.js.map +1 -1
- package/dist/esm/migrations/0002_reservation_lease.d.ts +1 -1
- package/dist/esm/migrations/0002_reservation_lease.d.ts.map +1 -1
- package/dist/esm/migrations/0002_reservation_lease.js +1 -1
- package/dist/esm/migrations/0002_reservation_lease.js.map +1 -1
- package/dist/esm/migrations/0003_heartbeat.d.ts +1 -1
- package/dist/esm/migrations/0003_heartbeat.d.ts.map +1 -1
- package/dist/esm/migrations/0003_heartbeat.js +1 -1
- package/dist/esm/migrations/0003_heartbeat.js.map +1 -1
- package/dist/esm/migrations/0004_fire_run_index.d.ts +1 -1
- package/dist/esm/migrations/0004_fire_run_index.d.ts.map +1 -1
- package/dist/esm/migrations/0004_fire_run_index.js +1 -1
- package/dist/esm/migrations/0004_fire_run_index.js.map +1 -1
- package/dist/esm/migrations/index.d.ts +7 -7
- package/dist/esm/migrations/index.d.ts.map +1 -1
- package/dist/esm/migrations/index.js +1 -1
- package/dist/esm/migrations/index.js.map +1 -1
- package/docs/installation.md +1 -1
- package/package.json +6 -6
- package/src/SqlTriggerStore.ts +1 -1
- package/src/migrations/0001_triggers.ts +1 -1
- package/src/migrations/0002_reservation_lease.ts +1 -1
- package/src/migrations/0003_heartbeat.ts +1 -1
- package/src/migrations/0004_fire_run_index.ts +1 -1
- package/src/migrations/index.ts +1 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ cd smithers
|
|
|
25
25
|
pnpm install
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
It needs Node.js 26.4.0 or later and `effect` 4.0.
|
|
28
|
+
It needs Node.js 26.4.0 or later and `effect` `^4.0.4`. The full
|
|
29
29
|
requirements, the import forms, and the layers a running host adds are on
|
|
30
30
|
the [installation page](https://triggers.smithers.sh/installation/).
|
|
31
31
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { DurableWriter } from "@smthrs/database/DurableWriter";
|
|
9
9
|
import * as Effect from "effect/Effect";
|
|
10
10
|
import * as Layer from "effect/Layer";
|
|
11
|
-
import * as SqlClient from "effect/
|
|
11
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
12
12
|
import { TriggerError } from "./TriggerError.ts";
|
|
13
13
|
import { type Service, TriggerStore } from "./TriggerStore.ts";
|
|
14
14
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlTriggerStore.d.ts","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAgB,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAE5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAIrC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"SqlTriggerStore.d.ts","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAgB,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAE5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAIrC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAMjD,OAAO,EAAmB,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAcL,KAAK,OAAO,EACZ,YAAY,EACb,MAAM,mBAAmB,CAAA;AAiG1B;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,CAC9B,OAAO,EACP,YAAY,EACZ,aAAa,GAAG,SAAS,CAAC,SAAS,CA+dnC,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAC7B,YAAY,EACZ,YAAY,EACZ,aAAa,GAAG,SAAS,CAAC,SAAS,CACD,CAAA"}
|
|
@@ -40,7 +40,7 @@ var Layer = __toESM(require("effect/Layer"), 1);
|
|
|
40
40
|
var Option = __toESM(require("effect/Option"), 1);
|
|
41
41
|
var Result = __toESM(require("effect/Result"), 1);
|
|
42
42
|
var Schema = __toESM(require("effect/Schema"), 1);
|
|
43
|
-
var SqlClient = __toESM(require("effect/
|
|
43
|
+
var SqlClient = __toESM(require("effect/sql/SqlClient"), 1);
|
|
44
44
|
var ClaimDecision = __toESM(require("./ClaimDecision.js"), 1);
|
|
45
45
|
var Migrations = __toESM(require("./migrations/index.js"), 1);
|
|
46
46
|
var Overlap = __toESM(require("./Overlap.js"), 1);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/SqlTriggerStore.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * SQLite-backed trigger store.\n *\n * @see packages/smithers/agent/triggers/docs/api.md\n *\n * @since 0.1.0\n */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport { affectedRows, DurableWriter } from \"@smthrs/database/DurableWriter\"\nimport * as Clock from \"effect/Clock\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SqlClient from \"effect/unstable/sql/SqlClient\"\nimport * as ClaimDecision from \"./ClaimDecision.ts\"\nimport * as Migrations from \"./migrations/index.ts\"\nimport * as Overlap from \"./Overlap.ts\"\nimport * as Schedule from \"./Schedule.ts\"\nimport * as Trigger from \"./Trigger.ts\"\nimport { fromSchemaError, TriggerError } from \"./TriggerError.ts\"\nimport {\n type ClaimFire,\n type FireRecord,\n type Heartbeat,\n historyLimit,\n historyPage,\n isReservation,\n type Listed,\n type Outcome,\n pruneCutoff,\n type Registered,\n reservationId,\n reservationOccurrence,\n resultRefusal,\n type Service,\n TriggerStore\n} from \"./TriggerStore.ts\"\n\ninterface Row {\n readonly trigger_id: string\n readonly flow_id: string\n readonly input_json: string\n readonly cron: string\n readonly timezone: string | null\n readonly overlap: string\n readonly catch_up: string\n readonly max_catch_up: number\n readonly enabled: number\n readonly revision: number\n readonly last_fired_at_ms: number | null\n readonly active_run_id: string | null\n readonly pending_at_ms: number | null\n}\n\ninterface FireRow {\n readonly trigger_id: string\n readonly occurrence_at_ms: number\n readonly outcome: Outcome | null\n readonly run_id: string | null\n readonly error: string | null\n}\n\nconst fireRecord = (row: FireRow): FireRecord => ({\n triggerId: row.trigger_id,\n occurrence: row.occurrence_at_ms,\n outcome: row.outcome,\n ...(row.run_id === null ? {} : { runId: row.run_id }),\n ...(row.error === null ? {} : { error: row.error })\n})\n\ninterface ClaimRow {\n readonly enabled: number\n readonly revision: number\n readonly overlap: Registered[\"overlap\"]\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n}\n\nconst storeError = (message: string, cause?: unknown) =>\n new TriggerError({\n code: \"store\",\n message,\n ...(cause === undefined ? {} : { cause })\n })\n\nconst unknownTrigger = (triggerId: string) =>\n new TriggerError({ code: \"unknown_trigger\", message: `unknown trigger ${triggerId}` })\n\n// A stored row is decoded through the same schema `register` accepts, plus the\n// store-owned fields, rather than cast. The table's CHECKs cover the policy\n// literals but not the catch-up bound or the non-empty strings, and a row\n// anyone rewrote must not reach the scheduler as a declaration `register`\n// would have refused.\nconst StoredDeclaration = Schema.Struct({\n ...Trigger.Trigger.fields,\n revision: Schema.Int,\n lastFiredAt: Schema.optional(Schema.Number)\n})\nconst decodeDeclaration = Schema.decodeUnknownSync(StoredDeclaration)\n\nconst declaration = (row: Row): Registered =>\n decodeDeclaration({\n id: row.trigger_id,\n flowId: row.flow_id,\n input: JSON.parse(row.input_json),\n cron: row.cron,\n ...(row.timezone === null ? {} : { timezone: row.timezone }),\n overlap: row.overlap,\n catchUp: row.catch_up,\n maxCatchUp: row.max_catch_up,\n enabled: row.enabled === 1,\n revision: row.revision,\n ...(row.last_fired_at_ms === null ? {} : { lastFiredAt: row.last_fired_at_ms })\n })\n\n// The offending id belongs in the message: a store failure that only says a\n// row would not decode leaves an operator grepping a shared database for it.\nconst decodeFailure = (row: Row, cause: unknown) => storeError(`could not decode trigger row ${row.trigger_id}`, cause)\n\nconst decode = (row: Row): Effect.Effect<Registered, TriggerError> =>\n Effect.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) })\n\n// A listing decodes row by row. One corrupt `input_json` used to fail the\n// whole read, and because a scheduler tick lists every trigger before it\n// isolates them, that one row stopped every healthy schedule in the store.\nconst listedRow = (row: Row): Listed => ({\n triggerId: row.trigger_id,\n trigger: Result.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) }),\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n})\n\n/**\n * Builds a {@link TriggerStore.Service} over the ambient SQL client, with\n * every write going through the durable writer.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make: Effect.Effect<\n Service,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Effect.gen(function*() {\n const sql = yield* Effect.service(SqlClient.SqlClient)\n const writer = yield* DurableWriter\n // The migrator raises a schema it cannot apply as a defect, not as a typed\n // failure, so mapping the error channel alone left a defect escaping a\n // constructor whose signature promises `TriggerError`. Defects are caught\n // separately from failures, which leaves interruption alone.\n const migrationFailed = (cause: unknown) => storeError(\"could not run trigger migrations\", cause)\n yield* Migrations.run.pipe(\n Effect.mapError(migrationFailed),\n Effect.catchDefect((defect) => Effect.fail(migrationFailed(defect)))\n )\n // A failure the store itself typed already says which refusal it is, so it\n // travels out unchanged. Re-wrapping it turned `unknown trigger x` into the\n // generic write failure and erased the one code a caller could branch on.\n const asTriggerError = (message: string) => (cause: unknown): TriggerError =>\n cause instanceof TriggerError ? cause : storeError(message, cause)\n const read = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n effect.pipe(Effect.mapError(asTriggerError(\"trigger store read failed\")))\n const write = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n writer.write(effect).pipe(Effect.mapError(asTriggerError(\"trigger store write failed\")))\n const requireTrigger = (triggerId: string) =>\n sql<{ readonly trigger_id: string }>`SELECT trigger_id FROM flows_triggers WHERE trigger_id = ${triggerId}`.pipe(\n Effect.flatMap((rows) => rows[0] === undefined ? Effect.fail(unknownTrigger(triggerId)) : Effect.void)\n )\n const get: Service[\"get\"] = (triggerId) =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE trigger_id = ${triggerId}`).pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? Effect.succeed(Option.none()) : decode(rows[0]).pipe(Effect.map(Option.some))\n )\n )\n const fireSnapshot = (\n row: { readonly outcome: string | null; readonly run_id: string | null } | undefined\n ): ClaimDecision.Fire | undefined =>\n row === undefined ? undefined : {\n outcome: row.outcome as Outcome | null,\n ...(row.run_id === null ? {} : { runId: row.run_id })\n }\n const claimInTransaction = (\n fire: ClaimFire,\n claimedAt: number,\n suppliedRow?: ClaimRow\n ) =>\n Effect.gen(function*() {\n // The declaration is read first and inside the transaction, so the\n // policy applied is the stored one and a caller holding a snapshot from\n // before an edit is refused rather than obeyed.\n const row = suppliedRow ?? (yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `)[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const activeRunId = row.active_run_id ?? undefined\n // The fences run before the insert below, so a refused claim leaves no\n // ledger row behind.\n const refusal = ClaimDecision.refuse({ enabled: row.enabled === 1, revision: row.revision }, fire)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n const insertResult = yield* sql`\n INSERT INTO flows_trigger_fires (trigger_id, occurrence_at_ms)\n VALUES (${fire.triggerId}, ${fire.occurrence})\n ON CONFLICT (trigger_id, occurrence_at_ms) DO NOTHING\n `.raw\n const inserted = yield* affectedRows(insertResult)\n const existing = inserted === 0\n ? yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${fire.occurrence}\n `\n : []\n // Both the expired-reservation reclaim and the supersede predecessor\n // lookup read the row the reservation holds, so one read serves both.\n const activeOccurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const active = activeOccurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${activeOccurrence}\n `\n const existingFire = fireSnapshot(existing[0])\n const activeFire = fireSnapshot(active[0])\n const decision = ClaimDecision.decideFenced({\n fire,\n claimedAt,\n reservationId: reservationId(fire.triggerId, fire.occurrence, globalThis.crypto.randomUUID()),\n snapshot: {\n revision: row.revision,\n enabled: row.enabled === 1,\n overlap: row.overlap,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(existingFire === undefined ? {} : { existingFire }),\n ...(activeFire === undefined ? {} : { activeFire })\n }\n })\n for (const write of decision.writes) {\n switch (write._tag) {\n case \"SetOutcome\": {\n yield* write.whileOpen\n ? sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')`\n : sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"SetRunId\": {\n yield* sql`UPDATE flows_trigger_fires SET run_id = ${write.runId}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"ReleaseReservation\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.activeRunId ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${write.pending ?? null}\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${write.expected}`\n break\n }\n case \"AdvanceCursor\": {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${write.occurrence}), ${write.occurrence})\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"SetPending\": {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${write.occurrence}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"Reserve\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.reservationId}, active_claimed_at_ms = ${write.claimedAt}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n }\n }\n return decision.claim\n })\n\n return {\n register: (trigger) => {\n const decoded = Schema.decodeUnknownResult(Trigger.Trigger)(trigger)\n if (Result.isFailure(decoded)) {\n return Effect.fail(\n fromSchemaError(\"invalid_trigger\", \"Trigger declaration is invalid\", decoded.failure)\n )\n }\n const snapshot = decoded.success\n let input: string | undefined\n try {\n input = JSON.stringify(snapshot.input)\n } catch (cause) {\n return Effect.fail(storeError(\"trigger input is not JSON-serializable\", cause))\n }\n // `JSON.stringify` answers `undefined` rather than throwing for an input\n // it cannot represent. Keep this guard even though Schema.Json currently\n // refuses every such input before serialization.\n if (input === undefined) {\n return Effect.fail(\n new TriggerError({\n code: \"invalid_trigger\",\n message: \"trigger input has no JSON representation\",\n path: \"input\"\n })\n )\n }\n // Registration is the last point where an unsatisfiable expression can\n // still be refused. The decoded declaration and its input string were\n // already copied at the call boundary, before this lazy work begins.\n return Effect.suspend(() =>\n Schedule.validate(snapshot).pipe(\n Effect.andThen(\n write(sql`\n INSERT INTO flows_triggers (trigger_id, flow_id, input_json, cron, timezone, overlap, catch_up, max_catch_up, enabled, revision)\n VALUES (${snapshot.id}, ${snapshot.flowId}, ${input}, ${snapshot.cron}, ${\n snapshot.timezone ?? null\n }, ${snapshot.overlap}, ${snapshot.catchUp}, ${snapshot.maxCatchUp}, ${snapshot.enabled ? 1 : 0}, 1)\n ON CONFLICT (trigger_id) DO UPDATE SET flow_id = excluded.flow_id, input_json = excluded.input_json, cron = excluded.cron,\n timezone = excluded.timezone, overlap = excluded.overlap, catch_up = excluded.catch_up, max_catch_up = excluded.max_catch_up,\n enabled = excluded.enabled, revision = flows_triggers.revision + 1\n `.pipe(\n Effect.flatMap(() => get(snapshot.id)),\n Effect.flatMap((registered) =>\n Option.isSome(registered)\n ? Effect.succeed(registered.value)\n : Effect.fail(storeError(\"registered trigger disappeared\"))\n )\n ))\n )\n )\n )\n },\n get,\n list: () =>\n read(sql<Row>`SELECT * FROM flows_triggers ORDER BY trigger_id`).pipe(\n Effect.map((rows) => rows.map(listedRow))\n ),\n listEnabled: () =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE enabled = 1 ORDER BY trigger_id`).pipe(\n Effect.flatMap((rows) => Effect.all(rows.map(decode)))\n ),\n claimFire: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(claimInTransaction(fire, claimedAt))\n }),\n claimPending: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n if (row.pending_at_ms === null) return Option.none()\n const occurrence = row.pending_at_ms\n const claim = yield* claimInTransaction(\n {\n triggerId: fire.triggerId,\n occurrence,\n expectedRevision: fire.expectedRevision,\n resumeBuffered: true\n },\n claimedAt,\n row\n )\n if (claim.claimed && claim.action !== \"buffer\") {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = NULL WHERE trigger_id = ${fire.triggerId}`\n }\n return Option.some({ occurrence, claim })\n }))\n }),\n recordResult: (result) =>\n write(\n Effect.gen(function*() {\n yield* requireTrigger(result.triggerId)\n const rows = yield* sql<FireRow>`SELECT * FROM flows_trigger_fires\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n const held = yield* sql<{ readonly active_run_id: string | null }>`\n SELECT active_run_id FROM flows_triggers WHERE trigger_id = ${result.triggerId}`\n const existing = rows[0] === undefined ? undefined : fireRecord(rows[0])\n const active = held[0]!.active_run_id ?? undefined\n const refusal = resultRefusal(result, existing, active)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n if (result.outcome !== \"launched\" && existing?.outcome === result.outcome) return\n const terminal = result.outcome === \"completed\" || result.outcome === \"failed\" ||\n result.outcome === \"superseded\"\n const resultOwner = (existing?.outcome === \"launched\"\n ? existing.runId\n : result.reservationId ?? result.runId ?? active) ?? null\n if (terminal && result.runId === undefined) {\n // Keep the recorded owner so an unqualified late result can only\n // clear the run launched by this occurrence, never a newer one.\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n } else {\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, run_id = ${result.runId ?? null}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n }\n // `last_fired_at_ms` is the cursor catch-up resumes from, so it only\n // ever moves forward. An older run settling after a newer occurrence\n // was skipped used to drag it backwards and replay settled work.\n if (result.outcome === \"launched\") {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = ${result.runId},\n active_claimed_at_ms = NULL\n WHERE trigger_id = ${result.triggerId} AND active_run_id = ${result.reservationId}`\n return\n }\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_run_id\n END,\n active_claimed_at_ms = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_claimed_at_ms\n END\n WHERE trigger_id = ${result.triggerId}`\n })\n ).pipe(\n Effect.asVoid\n ),\n restorePending: (fire) =>\n write(Effect.gen(function*() {\n yield* requireTrigger(fire.triggerId)\n const rows = yield* sql<{ readonly pending_at_ms: number | null; readonly run_id: string | null }>`\n SELECT t.pending_at_ms, f.run_id FROM flows_triggers t JOIN flows_trigger_fires f\n ON f.trigger_id = t.trigger_id\n WHERE t.trigger_id = ${fire.triggerId} AND t.active_run_id = ${fire.reservationId}\n AND f.occurrence_at_ms = ${fire.occurrence} AND (f.outcome IS NULL OR f.outcome = 'buffered')`\n const row = rows[0]\n if (row === undefined || reservationOccurrence(fire.reservationId) !== fire.occurrence) {\n return yield* Effect.fail(\n new TriggerError({ code: \"stale_owner\", message: \"pending restoration no longer owns reservation\" })\n )\n }\n const pending = Overlap.pendingAfter({\n running: false,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n const predecessors = row.run_id === null || isReservation(row.run_id) ?\n [] :\n yield* sql<{ readonly run_id: string }>`\n SELECT run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND run_id = ${row.run_id} AND outcome = 'launched'`\n const predecessor = predecessors[0]?.run_id ?? null\n yield* sql`UPDATE flows_triggers\n SET pending_at_ms = ${pending}, active_run_id = ${predecessor}, active_claimed_at_ms = NULL\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${fire.reservationId}`\n })).pipe(Effect.asVoid),\n setPending: (fire) =>\n write(Effect.gen(function*() {\n const rows = yield* sql<{ readonly pending_at_ms: number | null }>`\n SELECT pending_at_ms FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const pending = Overlap.pendingAfter({\n running: true,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${pending} WHERE trigger_id = ${fire.triggerId}`\n })).pipe(Effect.asVoid),\n activeRun: (triggerId) =>\n Effect.gen(function*() {\n const now = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<{\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n }>`SELECT active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${triggerId}`\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(triggerId))\n const activeRunId = row.active_run_id ?? undefined\n const occurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const unfinished = occurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND occurrence_at_ms = ${occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')\n `\n const unfinishedFire = fireSnapshot(unfinished[0])\n const lease = ClaimDecision.lease({\n now,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(unfinishedFire === undefined ? {} : { unfinished: unfinishedFire })\n })\n if (lease._tag === \"Idle\") return Option.none()\n if (lease._tag === \"Held\") return Option.some(lease.runId)\n yield* lease.pending === undefined\n ? sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n : sql`UPDATE flows_triggers\n SET active_run_id = ${lease.recovered ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${lease.pending}\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n return lease.recovered === undefined ? Option.none() : Option.some(lease.recovered)\n }))\n }),\n activeOccurrence: (triggerId, runId) =>\n read(Effect.gen(function*() {\n yield* requireTrigger(triggerId)\n const reserved = reservationOccurrence(runId)\n if (reserved !== undefined) return Option.some(reserved)\n if (isReservation(runId)) return Option.none()\n const rows = yield* sql<{ readonly occurrence_at_ms: number }>`\n SELECT occurrence_at_ms FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND run_id = ${runId} AND outcome = 'launched'\n ORDER BY occurrence_at_ms DESC LIMIT 1\n `\n return rows[0] === undefined ? Option.none() : Option.some(rows[0].occurrence_at_ms)\n })),\n clearActive: (triggerId, runId) =>\n write(sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${runId}`).pipe(\n Effect.asVoid\n ),\n history: (query = {}) =>\n historyLimit(query.limit).pipe(\n Effect.flatMap((limit) =>\n // One statement for every query shape: a null parameter disables\n // its predicate, and SQLite reads `LIMIT -1` as no limit. One row\n // past the limit is fetched so the page knows whether a next page\n // exists without a second count query.\n read(sql<FireRow>`\n SELECT trigger_id, occurrence_at_ms, outcome, run_id, error FROM flows_trigger_fires\n WHERE ${query.triggerId === undefined ? sql`1 = 1` : sql`trigger_id = ${query.triggerId}`}\n AND ${query.runId === undefined ? sql`1 = 1` : sql`run_id = ${query.runId}`}\n AND ${query.outcome === undefined ? sql`1 = 1` : sql`outcome = ${query.outcome}`}\n AND (${query.cursor === undefined ? 1 : 0} = 1\n OR occurrence_at_ms < ${query.cursor?.occurrence ?? null}\n OR (occurrence_at_ms = ${query.cursor?.occurrence ?? null} AND trigger_id < ${\n query.cursor?.triggerId ?? null\n }))\n ORDER BY occurrence_at_ms DESC, trigger_id DESC\n LIMIT ${limit === undefined ? (Dialect.isPostgres(sql) ? null : -1) : limit + 1}\n `).pipe(Effect.map((rows) => historyPage(rows.map(fireRecord), limit)))\n )\n ),\n pruneFires: ({ olderThan }) =>\n pruneCutoff(olderThan).pipe(\n Effect.flatMap((cutoff) =>\n // The trigger row names the state the scheduler still reads: the\n // buffered occurrence and the run or reservation on `active_run_id`.\n // An unsettled row carries no outcome, so the outcome filter already\n // spares a reserved occurrence.\n write(Effect.gen(function*() {\n const deleted = yield* sql`\n DELETE FROM flows_trigger_fires\n WHERE occurrence_at_ms < ${cutoff}\n AND outcome IN ('completed', 'failed', 'skipped', 'superseded')\n AND NOT EXISTS (\n SELECT 1 FROM flows_triggers t\n WHERE t.trigger_id = flows_trigger_fires.trigger_id\n AND (t.pending_at_ms = flows_trigger_fires.occurrence_at_ms\n OR t.active_run_id = flows_trigger_fires.run_id)\n )\n `.raw\n return yield* affectedRows(deleted)\n }))\n )\n ),\n inspect: (triggerId) =>\n read(sql<{ readonly active_run_id: string | null; readonly pending_at_ms: number | null }>`\n SELECT active_run_id, pending_at_ms FROM flows_triggers WHERE trigger_id = ${triggerId}\n `).pipe(\n Effect.flatMap((rows) => {\n const row = rows[0]\n if (row === undefined) return Effect.fail(unknownTrigger(triggerId))\n return Effect.succeed({\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n })\n })\n ),\n heartbeat: (host) =>\n Effect.flatMap(\n Clock.currentTimeMillis,\n (tickedAt) =>\n write(sql`INSERT INTO flows_scheduler_heartbeat (host, ticked_at_ms) VALUES (${host}, ${tickedAt})\n ON CONFLICT (host) DO UPDATE SET ticked_at_ms = excluded.ticked_at_ms`)\n ).pipe(Effect.asVoid),\n lastHeartbeat: () =>\n read(sql<{ readonly host: string; readonly ticked_at_ms: number }>`\n SELECT host, ticked_at_ms FROM flows_scheduler_heartbeat ORDER BY ticked_at_ms DESC, host ASC LIMIT 1\n `).pipe(\n Effect.map((rows) =>\n rows[0] === undefined\n ? Option.none<Heartbeat>()\n : Option.some({ host: rows[0].host, tickedAt: rows[0].ticked_at_ms })\n )\n )\n }\n})\n\n/**\n * Provides {@link TriggerStore.TriggerStore} backed by SQL.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<\n TriggerStore,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Layer.effect(TriggerStore)(make)\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * SQLite-backed trigger store.\n *\n * @see packages/smithers/agent/triggers/docs/api.md\n *\n * @since 0.1.0\n */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport { affectedRows, DurableWriter } from \"@smthrs/database/DurableWriter\"\nimport * as Clock from \"effect/Clock\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\nimport * as ClaimDecision from \"./ClaimDecision.ts\"\nimport * as Migrations from \"./migrations/index.ts\"\nimport * as Overlap from \"./Overlap.ts\"\nimport * as Schedule from \"./Schedule.ts\"\nimport * as Trigger from \"./Trigger.ts\"\nimport { fromSchemaError, TriggerError } from \"./TriggerError.ts\"\nimport {\n type ClaimFire,\n type FireRecord,\n type Heartbeat,\n historyLimit,\n historyPage,\n isReservation,\n type Listed,\n type Outcome,\n pruneCutoff,\n type Registered,\n reservationId,\n reservationOccurrence,\n resultRefusal,\n type Service,\n TriggerStore\n} from \"./TriggerStore.ts\"\n\ninterface Row {\n readonly trigger_id: string\n readonly flow_id: string\n readonly input_json: string\n readonly cron: string\n readonly timezone: string | null\n readonly overlap: string\n readonly catch_up: string\n readonly max_catch_up: number\n readonly enabled: number\n readonly revision: number\n readonly last_fired_at_ms: number | null\n readonly active_run_id: string | null\n readonly pending_at_ms: number | null\n}\n\ninterface FireRow {\n readonly trigger_id: string\n readonly occurrence_at_ms: number\n readonly outcome: Outcome | null\n readonly run_id: string | null\n readonly error: string | null\n}\n\nconst fireRecord = (row: FireRow): FireRecord => ({\n triggerId: row.trigger_id,\n occurrence: row.occurrence_at_ms,\n outcome: row.outcome,\n ...(row.run_id === null ? {} : { runId: row.run_id }),\n ...(row.error === null ? {} : { error: row.error })\n})\n\ninterface ClaimRow {\n readonly enabled: number\n readonly revision: number\n readonly overlap: Registered[\"overlap\"]\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n}\n\nconst storeError = (message: string, cause?: unknown) =>\n new TriggerError({\n code: \"store\",\n message,\n ...(cause === undefined ? {} : { cause })\n })\n\nconst unknownTrigger = (triggerId: string) =>\n new TriggerError({ code: \"unknown_trigger\", message: `unknown trigger ${triggerId}` })\n\n// A stored row is decoded through the same schema `register` accepts, plus the\n// store-owned fields, rather than cast. The table's CHECKs cover the policy\n// literals but not the catch-up bound or the non-empty strings, and a row\n// anyone rewrote must not reach the scheduler as a declaration `register`\n// would have refused.\nconst StoredDeclaration = Schema.Struct({\n ...Trigger.Trigger.fields,\n revision: Schema.Int,\n lastFiredAt: Schema.optional(Schema.Number)\n})\nconst decodeDeclaration = Schema.decodeUnknownSync(StoredDeclaration)\n\nconst declaration = (row: Row): Registered =>\n decodeDeclaration({\n id: row.trigger_id,\n flowId: row.flow_id,\n input: JSON.parse(row.input_json),\n cron: row.cron,\n ...(row.timezone === null ? {} : { timezone: row.timezone }),\n overlap: row.overlap,\n catchUp: row.catch_up,\n maxCatchUp: row.max_catch_up,\n enabled: row.enabled === 1,\n revision: row.revision,\n ...(row.last_fired_at_ms === null ? {} : { lastFiredAt: row.last_fired_at_ms })\n })\n\n// The offending id belongs in the message: a store failure that only says a\n// row would not decode leaves an operator grepping a shared database for it.\nconst decodeFailure = (row: Row, cause: unknown) => storeError(`could not decode trigger row ${row.trigger_id}`, cause)\n\nconst decode = (row: Row): Effect.Effect<Registered, TriggerError> =>\n Effect.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) })\n\n// A listing decodes row by row. One corrupt `input_json` used to fail the\n// whole read, and because a scheduler tick lists every trigger before it\n// isolates them, that one row stopped every healthy schedule in the store.\nconst listedRow = (row: Row): Listed => ({\n triggerId: row.trigger_id,\n trigger: Result.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) }),\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n})\n\n/**\n * Builds a {@link TriggerStore.Service} over the ambient SQL client, with\n * every write going through the durable writer.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make: Effect.Effect<\n Service,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Effect.gen(function*() {\n const sql = yield* Effect.service(SqlClient.SqlClient)\n const writer = yield* DurableWriter\n // The migrator raises a schema it cannot apply as a defect, not as a typed\n // failure, so mapping the error channel alone left a defect escaping a\n // constructor whose signature promises `TriggerError`. Defects are caught\n // separately from failures, which leaves interruption alone.\n const migrationFailed = (cause: unknown) => storeError(\"could not run trigger migrations\", cause)\n yield* Migrations.run.pipe(\n Effect.mapError(migrationFailed),\n Effect.catchDefect((defect) => Effect.fail(migrationFailed(defect)))\n )\n // A failure the store itself typed already says which refusal it is, so it\n // travels out unchanged. Re-wrapping it turned `unknown trigger x` into the\n // generic write failure and erased the one code a caller could branch on.\n const asTriggerError = (message: string) => (cause: unknown): TriggerError =>\n cause instanceof TriggerError ? cause : storeError(message, cause)\n const read = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n effect.pipe(Effect.mapError(asTriggerError(\"trigger store read failed\")))\n const write = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n writer.write(effect).pipe(Effect.mapError(asTriggerError(\"trigger store write failed\")))\n const requireTrigger = (triggerId: string) =>\n sql<{ readonly trigger_id: string }>`SELECT trigger_id FROM flows_triggers WHERE trigger_id = ${triggerId}`.pipe(\n Effect.flatMap((rows) => rows[0] === undefined ? Effect.fail(unknownTrigger(triggerId)) : Effect.void)\n )\n const get: Service[\"get\"] = (triggerId) =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE trigger_id = ${triggerId}`).pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? Effect.succeed(Option.none()) : decode(rows[0]).pipe(Effect.map(Option.some))\n )\n )\n const fireSnapshot = (\n row: { readonly outcome: string | null; readonly run_id: string | null } | undefined\n ): ClaimDecision.Fire | undefined =>\n row === undefined ? undefined : {\n outcome: row.outcome as Outcome | null,\n ...(row.run_id === null ? {} : { runId: row.run_id })\n }\n const claimInTransaction = (\n fire: ClaimFire,\n claimedAt: number,\n suppliedRow?: ClaimRow\n ) =>\n Effect.gen(function*() {\n // The declaration is read first and inside the transaction, so the\n // policy applied is the stored one and a caller holding a snapshot from\n // before an edit is refused rather than obeyed.\n const row = suppliedRow ?? (yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `)[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const activeRunId = row.active_run_id ?? undefined\n // The fences run before the insert below, so a refused claim leaves no\n // ledger row behind.\n const refusal = ClaimDecision.refuse({ enabled: row.enabled === 1, revision: row.revision }, fire)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n const insertResult = yield* sql`\n INSERT INTO flows_trigger_fires (trigger_id, occurrence_at_ms)\n VALUES (${fire.triggerId}, ${fire.occurrence})\n ON CONFLICT (trigger_id, occurrence_at_ms) DO NOTHING\n `.raw\n const inserted = yield* affectedRows(insertResult)\n const existing = inserted === 0\n ? yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${fire.occurrence}\n `\n : []\n // Both the expired-reservation reclaim and the supersede predecessor\n // lookup read the row the reservation holds, so one read serves both.\n const activeOccurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const active = activeOccurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${activeOccurrence}\n `\n const existingFire = fireSnapshot(existing[0])\n const activeFire = fireSnapshot(active[0])\n const decision = ClaimDecision.decideFenced({\n fire,\n claimedAt,\n reservationId: reservationId(fire.triggerId, fire.occurrence, globalThis.crypto.randomUUID()),\n snapshot: {\n revision: row.revision,\n enabled: row.enabled === 1,\n overlap: row.overlap,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(existingFire === undefined ? {} : { existingFire }),\n ...(activeFire === undefined ? {} : { activeFire })\n }\n })\n for (const write of decision.writes) {\n switch (write._tag) {\n case \"SetOutcome\": {\n yield* write.whileOpen\n ? sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')`\n : sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"SetRunId\": {\n yield* sql`UPDATE flows_trigger_fires SET run_id = ${write.runId}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"ReleaseReservation\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.activeRunId ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${write.pending ?? null}\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${write.expected}`\n break\n }\n case \"AdvanceCursor\": {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${write.occurrence}), ${write.occurrence})\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"SetPending\": {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${write.occurrence}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"Reserve\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.reservationId}, active_claimed_at_ms = ${write.claimedAt}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n }\n }\n return decision.claim\n })\n\n return {\n register: (trigger) => {\n const decoded = Schema.decodeUnknownResult(Trigger.Trigger)(trigger)\n if (Result.isFailure(decoded)) {\n return Effect.fail(\n fromSchemaError(\"invalid_trigger\", \"Trigger declaration is invalid\", decoded.failure)\n )\n }\n const snapshot = decoded.success\n let input: string | undefined\n try {\n input = JSON.stringify(snapshot.input)\n } catch (cause) {\n return Effect.fail(storeError(\"trigger input is not JSON-serializable\", cause))\n }\n // `JSON.stringify` answers `undefined` rather than throwing for an input\n // it cannot represent. Keep this guard even though Schema.Json currently\n // refuses every such input before serialization.\n if (input === undefined) {\n return Effect.fail(\n new TriggerError({\n code: \"invalid_trigger\",\n message: \"trigger input has no JSON representation\",\n path: \"input\"\n })\n )\n }\n // Registration is the last point where an unsatisfiable expression can\n // still be refused. The decoded declaration and its input string were\n // already copied at the call boundary, before this lazy work begins.\n return Effect.suspend(() =>\n Schedule.validate(snapshot).pipe(\n Effect.andThen(\n write(sql`\n INSERT INTO flows_triggers (trigger_id, flow_id, input_json, cron, timezone, overlap, catch_up, max_catch_up, enabled, revision)\n VALUES (${snapshot.id}, ${snapshot.flowId}, ${input}, ${snapshot.cron}, ${\n snapshot.timezone ?? null\n }, ${snapshot.overlap}, ${snapshot.catchUp}, ${snapshot.maxCatchUp}, ${snapshot.enabled ? 1 : 0}, 1)\n ON CONFLICT (trigger_id) DO UPDATE SET flow_id = excluded.flow_id, input_json = excluded.input_json, cron = excluded.cron,\n timezone = excluded.timezone, overlap = excluded.overlap, catch_up = excluded.catch_up, max_catch_up = excluded.max_catch_up,\n enabled = excluded.enabled, revision = flows_triggers.revision + 1\n `.pipe(\n Effect.flatMap(() => get(snapshot.id)),\n Effect.flatMap((registered) =>\n Option.isSome(registered)\n ? Effect.succeed(registered.value)\n : Effect.fail(storeError(\"registered trigger disappeared\"))\n )\n ))\n )\n )\n )\n },\n get,\n list: () =>\n read(sql<Row>`SELECT * FROM flows_triggers ORDER BY trigger_id`).pipe(\n Effect.map((rows) => rows.map(listedRow))\n ),\n listEnabled: () =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE enabled = 1 ORDER BY trigger_id`).pipe(\n Effect.flatMap((rows) => Effect.all(rows.map(decode)))\n ),\n claimFire: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(claimInTransaction(fire, claimedAt))\n }),\n claimPending: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n if (row.pending_at_ms === null) return Option.none()\n const occurrence = row.pending_at_ms\n const claim = yield* claimInTransaction(\n {\n triggerId: fire.triggerId,\n occurrence,\n expectedRevision: fire.expectedRevision,\n resumeBuffered: true\n },\n claimedAt,\n row\n )\n if (claim.claimed && claim.action !== \"buffer\") {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = NULL WHERE trigger_id = ${fire.triggerId}`\n }\n return Option.some({ occurrence, claim })\n }))\n }),\n recordResult: (result) =>\n write(\n Effect.gen(function*() {\n yield* requireTrigger(result.triggerId)\n const rows = yield* sql<FireRow>`SELECT * FROM flows_trigger_fires\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n const held = yield* sql<{ readonly active_run_id: string | null }>`\n SELECT active_run_id FROM flows_triggers WHERE trigger_id = ${result.triggerId}`\n const existing = rows[0] === undefined ? undefined : fireRecord(rows[0])\n const active = held[0]!.active_run_id ?? undefined\n const refusal = resultRefusal(result, existing, active)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n if (result.outcome !== \"launched\" && existing?.outcome === result.outcome) return\n const terminal = result.outcome === \"completed\" || result.outcome === \"failed\" ||\n result.outcome === \"superseded\"\n const resultOwner = (existing?.outcome === \"launched\"\n ? existing.runId\n : result.reservationId ?? result.runId ?? active) ?? null\n if (terminal && result.runId === undefined) {\n // Keep the recorded owner so an unqualified late result can only\n // clear the run launched by this occurrence, never a newer one.\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n } else {\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, run_id = ${result.runId ?? null}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n }\n // `last_fired_at_ms` is the cursor catch-up resumes from, so it only\n // ever moves forward. An older run settling after a newer occurrence\n // was skipped used to drag it backwards and replay settled work.\n if (result.outcome === \"launched\") {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = ${result.runId},\n active_claimed_at_ms = NULL\n WHERE trigger_id = ${result.triggerId} AND active_run_id = ${result.reservationId}`\n return\n }\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_run_id\n END,\n active_claimed_at_ms = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_claimed_at_ms\n END\n WHERE trigger_id = ${result.triggerId}`\n })\n ).pipe(\n Effect.asVoid\n ),\n restorePending: (fire) =>\n write(Effect.gen(function*() {\n yield* requireTrigger(fire.triggerId)\n const rows = yield* sql<{ readonly pending_at_ms: number | null; readonly run_id: string | null }>`\n SELECT t.pending_at_ms, f.run_id FROM flows_triggers t JOIN flows_trigger_fires f\n ON f.trigger_id = t.trigger_id\n WHERE t.trigger_id = ${fire.triggerId} AND t.active_run_id = ${fire.reservationId}\n AND f.occurrence_at_ms = ${fire.occurrence} AND (f.outcome IS NULL OR f.outcome = 'buffered')`\n const row = rows[0]\n if (row === undefined || reservationOccurrence(fire.reservationId) !== fire.occurrence) {\n return yield* Effect.fail(\n new TriggerError({ code: \"stale_owner\", message: \"pending restoration no longer owns reservation\" })\n )\n }\n const pending = Overlap.pendingAfter({\n running: false,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n const predecessors = row.run_id === null || isReservation(row.run_id) ?\n [] :\n yield* sql<{ readonly run_id: string }>`\n SELECT run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND run_id = ${row.run_id} AND outcome = 'launched'`\n const predecessor = predecessors[0]?.run_id ?? null\n yield* sql`UPDATE flows_triggers\n SET pending_at_ms = ${pending}, active_run_id = ${predecessor}, active_claimed_at_ms = NULL\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${fire.reservationId}`\n })).pipe(Effect.asVoid),\n setPending: (fire) =>\n write(Effect.gen(function*() {\n const rows = yield* sql<{ readonly pending_at_ms: number | null }>`\n SELECT pending_at_ms FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const pending = Overlap.pendingAfter({\n running: true,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${pending} WHERE trigger_id = ${fire.triggerId}`\n })).pipe(Effect.asVoid),\n activeRun: (triggerId) =>\n Effect.gen(function*() {\n const now = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<{\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n }>`SELECT active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${triggerId}`\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(triggerId))\n const activeRunId = row.active_run_id ?? undefined\n const occurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const unfinished = occurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND occurrence_at_ms = ${occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')\n `\n const unfinishedFire = fireSnapshot(unfinished[0])\n const lease = ClaimDecision.lease({\n now,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(unfinishedFire === undefined ? {} : { unfinished: unfinishedFire })\n })\n if (lease._tag === \"Idle\") return Option.none()\n if (lease._tag === \"Held\") return Option.some(lease.runId)\n yield* lease.pending === undefined\n ? sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n : sql`UPDATE flows_triggers\n SET active_run_id = ${lease.recovered ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${lease.pending}\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n return lease.recovered === undefined ? Option.none() : Option.some(lease.recovered)\n }))\n }),\n activeOccurrence: (triggerId, runId) =>\n read(Effect.gen(function*() {\n yield* requireTrigger(triggerId)\n const reserved = reservationOccurrence(runId)\n if (reserved !== undefined) return Option.some(reserved)\n if (isReservation(runId)) return Option.none()\n const rows = yield* sql<{ readonly occurrence_at_ms: number }>`\n SELECT occurrence_at_ms FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND run_id = ${runId} AND outcome = 'launched'\n ORDER BY occurrence_at_ms DESC LIMIT 1\n `\n return rows[0] === undefined ? Option.none() : Option.some(rows[0].occurrence_at_ms)\n })),\n clearActive: (triggerId, runId) =>\n write(sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${runId}`).pipe(\n Effect.asVoid\n ),\n history: (query = {}) =>\n historyLimit(query.limit).pipe(\n Effect.flatMap((limit) =>\n // One statement for every query shape: a null parameter disables\n // its predicate, and SQLite reads `LIMIT -1` as no limit. One row\n // past the limit is fetched so the page knows whether a next page\n // exists without a second count query.\n read(sql<FireRow>`\n SELECT trigger_id, occurrence_at_ms, outcome, run_id, error FROM flows_trigger_fires\n WHERE ${query.triggerId === undefined ? sql`1 = 1` : sql`trigger_id = ${query.triggerId}`}\n AND ${query.runId === undefined ? sql`1 = 1` : sql`run_id = ${query.runId}`}\n AND ${query.outcome === undefined ? sql`1 = 1` : sql`outcome = ${query.outcome}`}\n AND (${query.cursor === undefined ? 1 : 0} = 1\n OR occurrence_at_ms < ${query.cursor?.occurrence ?? null}\n OR (occurrence_at_ms = ${query.cursor?.occurrence ?? null} AND trigger_id < ${\n query.cursor?.triggerId ?? null\n }))\n ORDER BY occurrence_at_ms DESC, trigger_id DESC\n LIMIT ${limit === undefined ? (Dialect.isPostgres(sql) ? null : -1) : limit + 1}\n `).pipe(Effect.map((rows) => historyPage(rows.map(fireRecord), limit)))\n )\n ),\n pruneFires: ({ olderThan }) =>\n pruneCutoff(olderThan).pipe(\n Effect.flatMap((cutoff) =>\n // The trigger row names the state the scheduler still reads: the\n // buffered occurrence and the run or reservation on `active_run_id`.\n // An unsettled row carries no outcome, so the outcome filter already\n // spares a reserved occurrence.\n write(Effect.gen(function*() {\n const deleted = yield* sql`\n DELETE FROM flows_trigger_fires\n WHERE occurrence_at_ms < ${cutoff}\n AND outcome IN ('completed', 'failed', 'skipped', 'superseded')\n AND NOT EXISTS (\n SELECT 1 FROM flows_triggers t\n WHERE t.trigger_id = flows_trigger_fires.trigger_id\n AND (t.pending_at_ms = flows_trigger_fires.occurrence_at_ms\n OR t.active_run_id = flows_trigger_fires.run_id)\n )\n `.raw\n return yield* affectedRows(deleted)\n }))\n )\n ),\n inspect: (triggerId) =>\n read(sql<{ readonly active_run_id: string | null; readonly pending_at_ms: number | null }>`\n SELECT active_run_id, pending_at_ms FROM flows_triggers WHERE trigger_id = ${triggerId}\n `).pipe(\n Effect.flatMap((rows) => {\n const row = rows[0]\n if (row === undefined) return Effect.fail(unknownTrigger(triggerId))\n return Effect.succeed({\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n })\n })\n ),\n heartbeat: (host) =>\n Effect.flatMap(\n Clock.currentTimeMillis,\n (tickedAt) =>\n write(sql`INSERT INTO flows_scheduler_heartbeat (host, ticked_at_ms) VALUES (${host}, ${tickedAt})\n ON CONFLICT (host) DO UPDATE SET ticked_at_ms = excluded.ticked_at_ms`)\n ).pipe(Effect.asVoid),\n lastHeartbeat: () =>\n read(sql<{ readonly host: string; readonly ticked_at_ms: number }>`\n SELECT host, ticked_at_ms FROM flows_scheduler_heartbeat ORDER BY ticked_at_ms DESC, host ASC LIMIT 1\n `).pipe(\n Effect.map((rows) =>\n rows[0] === undefined\n ? Option.none<Heartbeat>()\n : Option.some({ host: rows[0].host, tickedAt: rows[0].ticked_at_ms })\n )\n )\n }\n})\n\n/**\n * Provides {@link TriggerStore.TriggerStore} backed by SQL.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<\n TriggerStore,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Layer.effect(TriggerStore)(make)\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,cAAyB;AACzB,2BAA4C;AAC5C,YAAuB;AACvB,aAAwB;AACxB,YAAuB;AACvB,aAAwB;AACxB,aAAwB;AACxB,aAAwB;AACxB,gBAA2B;AAC3B,oBAA+B;AAC/B,iBAA4B;AAC5B,cAAyB;AACzB,eAA0B;AAC1B,cAAyB;AACzB,0BAA8C;AAC9C,0BAgBO;AA0BP,MAAM,aAAa,CAAC,SAA8B;AAAA,EAChD,WAAW,IAAI;AAAA,EACf,YAAY,IAAI;AAAA,EAChB,SAAS,IAAI;AAAA,EACb,GAAI,IAAI,WAAW,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,OAAO;AAAA,EACnD,GAAI,IAAI,UAAU,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,MAAM;AACnD;AAWA,MAAM,aAAa,CAAC,SAAiB,UACnC,IAAI,iCAAa;AAAA,EACf,MAAM;AAAA,EACN;AAAA,EACA,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;AACzC,CAAC;AAEH,MAAM,iBAAiB,CAAC,cACtB,IAAI,iCAAa,EAAE,MAAM,mBAAmB,SAAS,mBAAmB,SAAS,GAAG,CAAC;AAOvF,MAAM,oBAAoB,OAAO,OAAO;AAAA,EACtC,GAAG,QAAQ,QAAQ;AAAA,EACnB,UAAU,OAAO;AAAA,EACjB,aAAa,OAAO,SAAS,OAAO,MAAM;AAC5C,CAAC;AACD,MAAM,oBAAoB,OAAO,kBAAkB,iBAAiB;AAEpE,MAAM,cAAc,CAAC,QACnB,kBAAkB;AAAA,EAChB,IAAI,IAAI;AAAA,EACR,QAAQ,IAAI;AAAA,EACZ,OAAO,KAAK,MAAM,IAAI,UAAU;AAAA,EAChC,MAAM,IAAI;AAAA,EACV,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;AAAA,EAC1D,SAAS,IAAI;AAAA,EACb,SAAS,IAAI;AAAA,EACb,YAAY,IAAI;AAAA,EAChB,SAAS,IAAI,YAAY;AAAA,EACzB,UAAU,IAAI;AAAA,EACd,GAAI,IAAI,qBAAqB,OAAO,CAAC,IAAI,EAAE,aAAa,IAAI,iBAAiB;AAC/E,CAAC;AAIH,MAAM,gBAAgB,CAAC,KAAU,UAAmB,WAAW,gCAAgC,IAAI,UAAU,IAAI,KAAK;AAEtH,MAAM,SAAS,CAAC,QACd,OAAO,IAAI,EAAE,KAAK,MAAM,YAAY,GAAG,GAAG,OAAO,CAAC,UAAU,cAAc,KAAK,KAAK,EAAE,CAAC;AAKzF,MAAM,YAAY,CAAC,SAAsB;AAAA,EACvC,WAAW,IAAI;AAAA,EACf,SAAS,OAAO,IAAI,EAAE,KAAK,MAAM,YAAY,GAAG,GAAG,OAAO,CAAC,UAAU,cAAc,KAAK,KAAK,EAAE,CAAC;AAAA,EAChG,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,aAAa,IAAI,cAAc;AAAA,EACvE,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,WAAW,IAAI,cAAc;AACvE;AASO,MAAM,OAIT,OAAO,IAAI,aAAY;AACzB,QAAM,MAAM,OAAO,OAAO,QAAQ,UAAU,SAAS;AACrD,QAAM,SAAS,OAAO;AAKtB,QAAM,kBAAkB,CAAC,UAAmB,WAAW,oCAAoC,KAAK;AAChG,SAAO,WAAW,IAAI;AAAA,IACpB,OAAO,SAAS,eAAe;AAAA,IAC/B,OAAO,YAAY,CAAC,WAAW,OAAO,KAAK,gBAAgB,MAAM,CAAC,CAAC;AAAA,EACrE;AAIA,QAAM,iBAAiB,CAAC,YAAoB,CAAC,UAC3C,iBAAiB,mCAAe,QAAQ,WAAW,SAAS,KAAK;AACnE,QAAM,OAAO,CAAI,WACf,OAAO,KAAK,OAAO,SAAS,eAAe,2BAA2B,CAAC,CAAC;AAC1E,QAAM,QAAQ,CAAI,WAChB,OAAO,MAAM,MAAM,EAAE,KAAK,OAAO,SAAS,eAAe,4BAA4B,CAAC,CAAC;AACzF,QAAM,iBAAiB,CAAC,cACtB,+DAAgG,SAAS,GAAG;AAAA,IAC1G,OAAO,QAAQ,CAAC,SAAS,KAAK,CAAC,MAAM,SAAY,OAAO,KAAK,eAAe,SAAS,CAAC,IAAI,OAAO,IAAI;AAAA,EACvG;AACF,QAAM,MAAsB,CAAC,cAC3B,KAAK,sDAA2D,SAAS,EAAE,EAAE;AAAA,IAC3E,OAAO;AAAA,MAAQ,CAAC,SACd,KAAK,CAAC,MAAM,SAAY,OAAO,QAAQ,OAAO,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,KAAK,OAAO,IAAI,OAAO,IAAI,CAAC;AAAA,IACtG;AAAA,EACF;AACF,QAAM,eAAe,CACnB,QAEA,QAAQ,SAAY,SAAY;AAAA,IAC9B,SAAS,IAAI;AAAA,IACb,GAAI,IAAI,WAAW,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,OAAO;AAAA,EACrD;AACF,QAAM,qBAAqB,CACzB,MACA,WACA,gBAEA,OAAO,IAAI,aAAY;AAIrB,UAAM,MAAM,gBAAgB,OAAO;AAAA;AAAA,iDAEQ,KAAK,SAAS;AAAA,SACtD,CAAC;AACJ,QAAI,QAAQ,OAAW,QAAO,OAAO,OAAO,KAAK,eAAe,KAAK,SAAS,CAAC;AAC/E,UAAM,cAAc,IAAI,iBAAiB;AAGzC,UAAM,UAAU,cAAc,OAAO,EAAE,SAAS,IAAI,YAAY,GAAG,UAAU,IAAI,SAAS,GAAG,IAAI;AACjG,QAAI,YAAY,OAAW,QAAO,OAAO,OAAO,KAAK,OAAO;AAC5D,UAAM,eAAe,OAAO;AAAA;AAAA,kBAEhB,KAAK,SAAS,KAAK,KAAK,UAAU;AAAA;AAAA,QAE5C;AACF,UAAM,WAAW,WAAO,mCAAa,YAAY;AACjD,UAAM,WAAW,aAAa,IAC1B,OAAO;AAAA;AAAA,+BAEc,KAAK,SAAS,2BAA2B,KAAK,UAAU;AAAA,YAE7E,CAAC;AAGL,UAAM,mBAAmB,gBAAgB,cAAa,mCAAc,WAAW,QAC3E,2CAAsB,WAAW,IACjC;AACJ,UAAM,SAAS,qBAAqB,SAChC,CAAC,IACD,OAAO;AAAA;AAAA,+BAEc,KAAK,SAAS,2BAA2B,gBAAgB;AAAA;AAElF,UAAM,eAAe,aAAa,SAAS,CAAC,CAAC;AAC7C,UAAM,aAAa,aAAa,OAAO,CAAC,CAAC;AACzC,UAAM,WAAW,cAAc,aAAa;AAAA,MAC1C;AAAA,MACA;AAAA,MACA,mBAAe,mCAAc,KAAK,WAAW,KAAK,YAAY,WAAW,OAAO,WAAW,CAAC;AAAA,MAC5F,UAAU;AAAA,QACR,UAAU,IAAI;AAAA,QACd,SAAS,IAAI,YAAY;AAAA,QACzB,SAAS,IAAI;AAAA,QACb,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;AAAA,QACnD,GAAI,IAAI,yBAAyB,OAAO,CAAC,IAAI,EAAE,iBAAiB,IAAI,qBAAqB;AAAA,QACzF,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,SAAS,IAAI,cAAc;AAAA,QACnE,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,QACrD,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,MACnD;AAAA,IACF,CAAC;AACD,eAAWA,UAAS,SAAS,QAAQ;AACnC,cAAQA,OAAM,MAAM;AAAA,QAClB,KAAK,cAAc;AACjB,iBAAOA,OAAM,YACT,+CAA+CA,OAAM,OAAO;AAAA,qCACvC,KAAK,SAAS,2BAA2BA,OAAM,UAAU;AAAA,mEAE9E,+CAA+CA,OAAM,OAAO;AAAA,qCACvC,KAAK,SAAS,2BAA2BA,OAAM,UAAU;AAClF;AAAA,QACF;AAAA,QACA,KAAK,YAAY;AACf,iBAAO,8CAA8CA,OAAM,KAAK;AAAA,mCACzC,KAAK,SAAS,2BAA2BA,OAAM,UAAU;AAChF;AAAA,QACF;AAAA,QACA,KAAK,sBAAsB;AACzB,iBAAO;AAAA,oCACiBA,OAAM,eAAe,IAAI;AAAA,kCAC3BA,OAAM,WAAW,IAAI;AAAA,mCACpB,KAAK,SAAS,wBAAwBA,OAAM,QAAQ;AAC3E;AAAA,QACF;AAAA,QACA,KAAK,iBAAiB;AACpB,iBAAO;AAAA,uCAEL,QAAQ,SAAS,GAAG,CACtB,+BAA+BA,OAAM,UAAU,MAAMA,OAAM,UAAU;AAAA,mCAC9C,KAAK,SAAS;AACrC;AAAA,QACF;AAAA,QACA,KAAK,cAAc;AACjB,iBAAO,gDAAgDA,OAAM,UAAU;AAAA,mCAChD,KAAK,SAAS;AACrC;AAAA,QACF;AAAA,QACA,KAAK,WAAW;AACd,iBAAO;AAAA,oCACiBA,OAAM,aAAa,4BAA4BA,OAAM,SAAS;AAAA,mCAC/D,KAAK,SAAS;AACrC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB,CAAC;AAEH,SAAO;AAAA,IACL,UAAU,CAAC,YAAY;AACrB,YAAM,UAAU,OAAO,oBAAoB,QAAQ,OAAO,EAAE,OAAO;AACnE,UAAI,OAAO,UAAU,OAAO,GAAG;AAC7B,eAAO,OAAO;AAAA,cACZ,qCAAgB,mBAAmB,kCAAkC,QAAQ,OAAO;AAAA,QACtF;AAAA,MACF;AACA,YAAM,WAAW,QAAQ;AACzB,UAAI;AACJ,UAAI;AACF,gBAAQ,KAAK,UAAU,SAAS,KAAK;AAAA,MACvC,SAAS,OAAO;AACd,eAAO,OAAO,KAAK,WAAW,0CAA0C,KAAK,CAAC;AAAA,MAChF;AAIA,UAAI,UAAU,QAAW;AACvB,eAAO,OAAO;AAAA,UACZ,IAAI,iCAAa;AAAA,YACf,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AAIA,aAAO,OAAO;AAAA,QAAQ,MACpB,SAAS,SAAS,QAAQ,EAAE;AAAA,UAC1B,OAAO;AAAA,YACL,MAAM;AAAA;AAAA,wBAEM,SAAS,EAAE,KAAK,SAAS,MAAM,KAAK,KAAK,KAAK,SAAS,IAAI,KACrE,SAAS,YAAY,IACvB,KAAK,SAAS,OAAO,KAAK,SAAS,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS,UAAU,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,cAI7F;AAAA,cACA,OAAO,QAAQ,MAAM,IAAI,SAAS,EAAE,CAAC;AAAA,cACrC,OAAO;AAAA,gBAAQ,CAAC,eACd,OAAO,OAAO,UAAU,IACpB,OAAO,QAAQ,WAAW,KAAK,IAC/B,OAAO,KAAK,WAAW,gCAAgC,CAAC;AAAA,cAC9D;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,MAAM,MACJ,KAAK,qDAA0D,EAAE;AAAA,MAC/D,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI,SAAS,CAAC;AAAA,IAC1C;AAAA,IACF,aAAa,MACX,KAAK,uEAA4E,EAAE;AAAA,MACjF,OAAO,QAAQ,CAAC,SAAS,OAAO,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC;AAAA,IACvD;AAAA,IACF,WAAW,CAAC,SACV,OAAO,IAAI,aAAY;AACrB,YAAM,YAAY,OAAO,MAAM;AAC/B,aAAO,OAAO,MAAM,mBAAmB,MAAM,SAAS,CAAC;AAAA,IACzD,CAAC;AAAA,IACH,cAAc,CAAC,SACb,OAAO,IAAI,aAAY;AACrB,YAAM,YAAY,OAAO,MAAM;AAC/B,aAAO,OAAO,MAAM,OAAO,IAAI,aAAY;AACzC,cAAM,OAAO,OAAO;AAAA;AAAA,qDAEuB,KAAK,SAAS;AAAA;AAEzD,cAAM,MAAM,KAAK,CAAC;AAClB,YAAI,QAAQ,OAAW,QAAO,OAAO,OAAO,KAAK,eAAe,KAAK,SAAS,CAAC;AAC/E,YAAI,IAAI,kBAAkB,KAAM,QAAO,OAAO,KAAK;AACnD,cAAM,aAAa,IAAI;AACvB,cAAM,QAAQ,OAAO;AAAA,UACnB;AAAA,YACE,WAAW,KAAK;AAAA,YAChB;AAAA,YACA,kBAAkB,KAAK;AAAA,YACvB,gBAAgB;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAI,MAAM,WAAW,MAAM,WAAW,UAAU;AAC9C,iBAAO,wEAAwE,KAAK,SAAS;AAAA,QAC/F;AACA,eAAO,OAAO,KAAK,EAAE,YAAY,MAAM,CAAC;AAAA,MAC1C,CAAC,CAAC;AAAA,IACJ,CAAC;AAAA,IACH,cAAc,CAAC,WACb;AAAA,MACE,OAAO,IAAI,aAAY;AACrB,eAAO,eAAe,OAAO,SAAS;AACtC,cAAM,OAAO,OAAO;AAAA,iCACG,OAAO,SAAS,2BAA2B,OAAO,UAAU;AACnF,cAAM,OAAO,OAAO;AAAA,0EAC4C,OAAO,SAAS;AAChF,cAAM,WAAW,KAAK,CAAC,MAAM,SAAY,SAAY,WAAW,KAAK,CAAC,CAAC;AACvE,cAAM,SAAS,KAAK,CAAC,EAAG,iBAAiB;AACzC,cAAM,cAAU,mCAAc,QAAQ,UAAU,MAAM;AACtD,YAAI,YAAY,OAAW,QAAO,OAAO,OAAO,KAAK,OAAO;AAC5D,YAAI,OAAO,YAAY,cAAc,UAAU,YAAY,OAAO,QAAS;AAC3E,cAAM,WAAW,OAAO,YAAY,eAAe,OAAO,YAAY,YACpE,OAAO,YAAY;AACrB,cAAM,eAAe,UAAU,YAAY,aACvC,SAAS,QACT,OAAO,iBAAiB,OAAO,SAAS,WAAW;AACvD,YAAI,YAAY,OAAO,UAAU,QAAW;AAG1C,iBAAO;AAAA,8BACW,OAAO,OAAO,aAAa,OAAO,SAAS,IAAI;AAAA,mCAC1C,OAAO,SAAS,2BAA2B,OAAO,UAAU;AAAA,QACrF,OAAO;AACL,iBAAO;AAAA,8BACW,OAAO,OAAO,cAAc,OAAO,SAAS,IAAI,aAAa,OAAO,SAAS,IAAI;AAAA,mCAC5E,OAAO,SAAS,2BAA2B,OAAO,UAAU;AAAA,QACrF;AAIA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO;AAAA,uCAEL,QAAQ,SAAS,GAAG,CACtB,+BAA+B,OAAO,UAAU,MAAM,OAAO,UAAU;AAAA,kCACjD,OAAO,KAAK;AAAA;AAAA,mCAEX,OAAO,SAAS,wBAAwB,OAAO,aAAa;AACnF;AAAA,QACF;AACA,eAAO;AAAA,qCAEL,QAAQ,SAAS,GAAG,CACtB,+BAA+B,OAAO,UAAU,MAAM,OAAO,UAAU;AAAA;AAAA,uCAE1C,WAAW;AAAA;AAAA;AAAA;AAAA,uCAIX,WAAW;AAAA;AAAA;AAAA,iCAGjB,OAAO,SAAS;AAAA,MACzC,CAAC;AAAA,IACH,EAAE;AAAA,MACA,OAAO;AAAA,IACT;AAAA,IACF,gBAAgB,CAAC,SACf,MAAM,OAAO,IAAI,aAAY;AAC3B,aAAO,eAAe,KAAK,SAAS;AACpC,YAAM,OAAO,OAAO;AAAA;AAAA;AAAA,+BAGG,KAAK,SAAS,0BAA0B,KAAK,aAAa;AAAA,qCACpD,KAAK,UAAU;AAC5C,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,QAAQ,cAAa,2CAAsB,KAAK,aAAa,MAAM,KAAK,YAAY;AACtF,eAAO,OAAO,OAAO;AAAA,UACnB,IAAI,iCAAa,EAAE,MAAM,eAAe,SAAS,iDAAiD,CAAC;AAAA,QACrG;AAAA,MACF;AACA,YAAM,UAAU,QAAQ,aAAa;AAAA,QACnC,SAAS;AAAA,QACT,SAAS,IAAI,iBAAiB;AAAA,QAC9B,KAAK,KAAK;AAAA,MACZ,CAAC;AACD,YAAM,eAAe,IAAI,WAAW,YAAQ,mCAAc,IAAI,MAAM,IAClE,CAAC,IACD,OAAO;AAAA;AAAA,6BAEY,KAAK,SAAS,iBAAiB,IAAI,MAAM;AAC9D,YAAM,cAAc,aAAa,CAAC,GAAG,UAAU;AAC/C,aAAO;AAAA,8BACe,OAAO,qBAAqB,WAAW;AAAA,6BACxC,KAAK,SAAS,wBAAwB,KAAK,aAAa;AAAA,IAC/E,CAAC,CAAC,EAAE,KAAK,OAAO,MAAM;AAAA,IACxB,YAAY,CAAC,SACX,MAAM,OAAO,IAAI,aAAY;AAC3B,YAAM,OAAO,OAAO;AAAA,wEAC4C,KAAK,SAAS;AAAA;AAE9E,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,QAAQ,OAAW,QAAO,OAAO,OAAO,KAAK,eAAe,KAAK,SAAS,CAAC;AAC/E,YAAM,UAAU,QAAQ,aAAa;AAAA,QACnC,SAAS;AAAA,QACT,SAAS,IAAI,iBAAiB;AAAA,QAC9B,KAAK,KAAK;AAAA,MACZ,CAAC;AACD,aAAO,gDAAgD,OAAO,uBAAuB,KAAK,SAAS;AAAA,IACrG,CAAC,CAAC,EAAE,KAAK,OAAO,MAAM;AAAA,IACxB,WAAW,CAAC,cACV,OAAO,IAAI,aAAY;AACrB,YAAM,MAAM,OAAO,MAAM;AACzB,aAAO,OAAO,MAAM,OAAO,IAAI,aAAY;AACzC,cAAM,OAAO,OAAO;AAAA,qDAKuB,SAAS;AACpD,cAAM,MAAM,KAAK,CAAC;AAClB,YAAI,QAAQ,OAAW,QAAO,OAAO,OAAO,KAAK,eAAe,SAAS,CAAC;AAC1E,cAAM,cAAc,IAAI,iBAAiB;AACzC,cAAM,aAAa,gBAAgB,cAAa,mCAAc,WAAW,QACrE,2CAAsB,WAAW,IACjC;AACJ,cAAM,aAAa,eAAe,SAC9B,CAAC,IACD,OAAO;AAAA;AAAA,mCAEc,SAAS,2BAA2B,UAAU;AAAA;AAAA;AAGvE,cAAM,iBAAiB,aAAa,WAAW,CAAC,CAAC;AACjD,cAAM,QAAQ,cAAc,MAAM;AAAA,UAChC;AAAA,UACA,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;AAAA,UACnD,GAAI,IAAI,yBAAyB,OAAO,CAAC,IAAI,EAAE,iBAAiB,IAAI,qBAAqB;AAAA,UACzF,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,SAAS,IAAI,cAAc;AAAA,UACnE,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,YAAY,eAAe;AAAA,QACvE,CAAC;AACD,YAAI,MAAM,SAAS,OAAQ,QAAO,OAAO,KAAK;AAC9C,YAAI,MAAM,SAAS,OAAQ,QAAO,OAAO,KAAK,MAAM,KAAK;AACzD,eAAO,MAAM,YAAY,SACrB;AAAA,mCACqB,SAAS,wBAAwB,MAAM,QAAQ,KACpE;AAAA,oCACsB,MAAM,aAAa,IAAI;AAAA,kCACzB,MAAM,OAAO;AAAA,mCACZ,SAAS,wBAAwB,MAAM,QAAQ;AACxE,eAAO,MAAM,cAAc,SAAY,OAAO,KAAK,IAAI,OAAO,KAAK,MAAM,SAAS;AAAA,MACpF,CAAC,CAAC;AAAA,IACJ,CAAC;AAAA,IACH,kBAAkB,CAAC,WAAW,UAC5B,KAAK,OAAO,IAAI,aAAY;AAC1B,aAAO,eAAe,SAAS;AAC/B,YAAM,eAAW,2CAAsB,KAAK;AAC5C,UAAI,aAAa,OAAW,QAAO,OAAO,KAAK,QAAQ;AACvD,cAAI,mCAAc,KAAK,EAAG,QAAO,OAAO,KAAK;AAC7C,YAAM,OAAO,OAAO;AAAA;AAAA,+BAEG,SAAS,iBAAiB,KAAK;AAAA;AAAA;AAGtD,aAAO,KAAK,CAAC,MAAM,SAAY,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,CAAC,EAAE,gBAAgB;AAAA,IACrF,CAAC,CAAC;AAAA,IACJ,aAAa,CAAC,WAAW,UACvB,MAAM;AAAA,6BACiB,SAAS,wBAAwB,KAAK,EAAE,EAAE;AAAA,MAC/D,OAAO;AAAA,IACT;AAAA,IACF,SAAS,CAAC,QAAQ,CAAC,UACjB,kCAAa,MAAM,KAAK,EAAE;AAAA,MACxB,OAAO;AAAA,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,UAKd,KAAK;AAAA;AAAA,oBAEK,MAAM,cAAc,SAAY,aAAa,mBAAmB,MAAM,SAAS,EAAE;AAAA,oBACjF,MAAM,UAAU,SAAY,aAAa,eAAe,MAAM,KAAK,EAAE;AAAA,oBACrE,MAAM,YAAY,SAAY,aAAa,gBAAgB,MAAM,OAAO,EAAE;AAAA,qBACzE,MAAM,WAAW,SAAY,IAAI,CAAC;AAAA,wCACf,MAAM,QAAQ,cAAc,IAAI;AAAA,yCAC/B,MAAM,QAAQ,cAAc,IAAI,qBAC7D,MAAM,QAAQ,aAAa,IAC7B;AAAA;AAAA,oBAEU,UAAU,SAAa,QAAQ,WAAW,GAAG,IAAI,OAAO,KAAM,QAAQ,CAAC;AAAA,WAChF,EAAE,KAAK,OAAO,IAAI,CAAC,aAAS,iCAAY,KAAK,IAAI,UAAU,GAAG,KAAK,CAAC,CAAC;AAAA;AAAA,MACxE;AAAA,IACF;AAAA,IACF,YAAY,CAAC,EAAE,UAAU,UACvB,iCAAY,SAAS,EAAE;AAAA,MACrB,OAAO;AAAA,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,UAKd,MAAM,OAAO,IAAI,aAAY;AAC3B,kBAAM,UAAU,OAAO;AAAA;AAAA,yCAEM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAQjC;AACF,mBAAO,WAAO,mCAAa,OAAO;AAAA,UACpC,CAAC,CAAC;AAAA;AAAA,MACJ;AAAA,IACF;AAAA,IACF,SAAS,CAAC,cACR,KAAK;AAAA,qFAC0E,SAAS;AAAA,OACvF,EAAE;AAAA,MACD,OAAO,QAAQ,CAAC,SAAS;AACvB,cAAM,MAAM,KAAK,CAAC;AAClB,YAAI,QAAQ,OAAW,QAAO,OAAO,KAAK,eAAe,SAAS,CAAC;AACnE,eAAO,OAAO,QAAQ;AAAA,UACpB,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,aAAa,IAAI,cAAc;AAAA,UACvE,GAAI,IAAI,kBAAkB,OAAO,CAAC,IAAI,EAAE,WAAW,IAAI,cAAc;AAAA,QACvE,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACF,WAAW,CAAC,SACV,OAAO;AAAA,MACL,MAAM;AAAA,MACN,CAAC,aACC,MAAM,yEAAyE,IAAI,KAAK,QAAQ;AAAA,gFAC1B;AAAA,IAC1E,EAAE,KAAK,OAAO,MAAM;AAAA,IACtB,eAAe,MACb,KAAK;AAAA;AAAA,OAEJ,EAAE;AAAA,MACD,OAAO;AAAA,QAAI,CAAC,SACV,KAAK,CAAC,MAAM,SACR,OAAO,KAAgB,IACvB,OAAO,KAAK,EAAE,MAAM,KAAK,CAAC,EAAE,MAAM,UAAU,KAAK,CAAC,EAAE,aAAa,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACJ;AACF,CAAC;AAQM,MAAM,QAIT,MAAM,OAAO,gCAAY,EAAE,IAAI;",
|
|
6
6
|
"names": ["write"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0001_triggers.d.ts","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0001_triggers.d.ts","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CA0BrE,CAAA"}
|
|
@@ -33,7 +33,7 @@ __export(triggers_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(triggers_exports);
|
|
34
34
|
var Dialect = __toESM(require("@smthrs/database/Dialect"), 1);
|
|
35
35
|
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
-
var SqlClient = __toESM(require("effect/
|
|
36
|
+
var SqlClient = __toESM(require("effect/sql/SqlClient"), 1);
|
|
37
37
|
const triggers = Effect.gen(function* () {
|
|
38
38
|
const sql = yield* SqlClient.SqlClient;
|
|
39
39
|
yield* sql`CREATE TABLE IF NOT EXISTS flows_triggers (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/migrations/0001_triggers.ts"],
|
|
4
|
-
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/
|
|
4
|
+
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Creates the `flows_triggers` and `flows_trigger_fires` tables.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const triggers: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE TABLE IF NOT EXISTS flows_triggers (\n trigger_id TEXT PRIMARY KEY,\n flow_id TEXT NOT NULL,\n input_json TEXT NOT NULL,\n cron TEXT NOT NULL,\n timezone TEXT,\n overlap TEXT NOT NULL CHECK (overlap IN ('skip', 'buffer-one', 'supersede')),\n catch_up TEXT NOT NULL CHECK (catch_up IN ('none', 'one', 'all')),\n max_catch_up ${Dialect.integer(sql)} NOT NULL CHECK (max_catch_up >= 0),\n enabled ${Dialect.integer(sql)} NOT NULL CHECK (enabled IN (0, 1)),\n revision ${Dialect.integer(sql)} NOT NULL,\n last_fired_at_ms ${Dialect.integer(sql)},\n pending_at_ms ${Dialect.integer(sql)},\n active_run_id TEXT\n )`\n yield* sql`CREATE TABLE IF NOT EXISTS flows_trigger_fires (\n trigger_id TEXT NOT NULL,\n occurrence_at_ms ${Dialect.integer(sql)} NOT NULL,\n outcome TEXT,\n run_id TEXT,\n error TEXT,\n PRIMARY KEY (trigger_id, occurrence_at_ms),\n FOREIGN KEY (trigger_id) REFERENCES flows_triggers (trigger_id)\n )`\n})\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,cAAyB;AACzB,aAAwB;AACxB,gBAA2B;AAYpB,MAAM,WAA8D,OAAO,IAAI,aAAY;AAChG,QAAM,MAAM,OAAO,UAAU;AAC7B,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAQU,QAAQ,QAAQ,GAAG,CAAC;AAAA,cACzB,QAAQ,QAAQ,GAAG,CAAC;AAAA,eACnB,QAAQ,QAAQ,GAAG,CAAC;AAAA,uBACZ,QAAQ,QAAQ,GAAG,CAAC;AAAA,oBACvB,QAAQ,QAAQ,GAAG,CAAC;AAAA;AAAA;AAGtC,SAAO;AAAA;AAAA,uBAEc,QAAQ,QAAQ,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAO3C,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0002_reservation_lease.d.ts","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0002_reservation_lease.d.ts","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAG7E,CAAA"}
|
|
@@ -33,7 +33,7 @@ __export(reservation_lease_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(reservation_lease_exports);
|
|
34
34
|
var Dialect = __toESM(require("@smthrs/database/Dialect"), 1);
|
|
35
35
|
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
-
var SqlClient = __toESM(require("effect/
|
|
36
|
+
var SqlClient = __toESM(require("effect/sql/SqlClient"), 1);
|
|
37
37
|
const reservationLease = Effect.gen(function* () {
|
|
38
38
|
const sql = yield* SqlClient.SqlClient;
|
|
39
39
|
yield* sql`ALTER TABLE flows_triggers ADD COLUMN active_claimed_at_ms ${Dialect.integer(sql)}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/migrations/0002_reservation_lease.ts"],
|
|
4
|
-
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/
|
|
4
|
+
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Adds `active_claimed_at_ms`, the lease start of a launch reservation.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const reservationLease: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`ALTER TABLE flows_triggers ADD COLUMN active_claimed_at_ms ${Dialect.integer(sql)}`\n})\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,cAAyB;AACzB,aAAwB;AACxB,gBAA2B;AAYpB,MAAM,mBAAsE,OAAO,IAAI,aAAY;AACxG,QAAM,MAAM,OAAO,UAAU;AAC7B,SAAO,iEAAiE,QAAQ,QAAQ,GAAG,CAAC;AAC9F,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.0 */
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as SqlClient from "effect/
|
|
3
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
4
4
|
/**
|
|
5
5
|
* Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the
|
|
6
6
|
* last poll it recorded, so a listing can say whether anything is listening.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0003_heartbeat.d.ts","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAGxB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0003_heartbeat.d.ts","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAGxB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAM/E,CAAA"}
|
|
@@ -33,7 +33,7 @@ __export(heartbeat_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(heartbeat_exports);
|
|
34
34
|
var Dialect = __toESM(require("@smthrs/database/Dialect"), 1);
|
|
35
35
|
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
-
var SqlClient = __toESM(require("effect/
|
|
36
|
+
var SqlClient = __toESM(require("effect/sql/SqlClient"), 1);
|
|
37
37
|
const schedulerHeartbeat = Effect.gen(function* () {
|
|
38
38
|
const sql = yield* SqlClient.SqlClient;
|
|
39
39
|
yield* sql`CREATE TABLE IF NOT EXISTS flows_scheduler_heartbeat (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/migrations/0003_heartbeat.ts"],
|
|
4
|
-
"sourcesContent": ["/** @since 1.0.0-rc.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/
|
|
4
|
+
"sourcesContent": ["/** @since 1.0.0-rc.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the\n * last poll it recorded, so a listing can say whether anything is listening.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 1.0.0-rc.0\n */\nexport const schedulerHeartbeat: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE TABLE IF NOT EXISTS flows_scheduler_heartbeat (\n host TEXT PRIMARY KEY,\n ticked_at_ms ${Dialect.integer(sql)} NOT NULL\n )`\n})\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,cAAyB;AACzB,aAAwB;AACxB,gBAA2B;AAapB,MAAM,qBAAwE,OAAO,IAAI,aAAY;AAC1G,QAAM,MAAM,OAAO,UAAU;AAC7B,SAAO;AAAA;AAAA,mBAEU,QAAQ,QAAQ,GAAG,CAAC;AAAA;AAEvC,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.1 */
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as SqlClient from "effect/
|
|
3
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
4
4
|
/**
|
|
5
5
|
* Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to
|
|
6
6
|
* one run and the prune's active-run check read an index instead of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0004_fire_run_index.d.ts","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0004_fire_run_index.d.ts","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAGzE,CAAA"}
|
|
@@ -32,7 +32,7 @@ __export(fire_run_index_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(fire_run_index_exports);
|
|
34
34
|
var Effect = __toESM(require("effect/Effect"), 1);
|
|
35
|
-
var SqlClient = __toESM(require("effect/
|
|
35
|
+
var SqlClient = __toESM(require("effect/sql/SqlClient"), 1);
|
|
36
36
|
const fireRunIndex = Effect.gen(function* () {
|
|
37
37
|
const sql = yield* SqlClient.SqlClient;
|
|
38
38
|
yield* sql`CREATE INDEX IF NOT EXISTS flows_trigger_fires_run_id ON flows_trigger_fires (run_id)`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/migrations/0004_fire_run_index.ts"],
|
|
4
|
-
"sourcesContent": ["/** @since 1.0.0-rc.1 */\n\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/
|
|
4
|
+
"sourcesContent": ["/** @since 1.0.0-rc.1 */\n\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to\n * one run and the prune's active-run check read an index instead of the\n * whole ledger.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 1.0.0-rc.1\n */\nexport const fireRunIndex: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE INDEX IF NOT EXISTS flows_trigger_fires_run_id ON flows_trigger_fires (run_id)`\n})\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,aAAwB;AACxB,gBAA2B;AAcpB,MAAM,eAAkE,OAAO,IAAI,aAAY;AACpG,QAAM,MAAM,OAAO,UAAU;AAC7B,SAAO;AACT,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import * as Migrator from "effect/
|
|
3
|
+
import * as Migrator from "effect/sql/Migrator";
|
|
4
4
|
/**
|
|
5
5
|
* The migration record {@link run} applies, keyed by migration file name.
|
|
6
6
|
*
|
|
@@ -11,10 +11,10 @@ import * as Migrator from "effect/unstable/sql/Migrator";
|
|
|
11
11
|
* @since 1.0.0-rc.0
|
|
12
12
|
*/
|
|
13
13
|
export declare const migrations: {
|
|
14
|
-
"0001_triggers": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
15
|
-
"0002_reservation_lease": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
16
|
-
"0003_heartbeat": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
17
|
-
"0004_fire_run_index": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
14
|
+
"0001_triggers": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
15
|
+
"0002_reservation_lease": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
16
|
+
"0003_heartbeat": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
17
|
+
"0004_fire_run_index": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Applies the triggers schema migrations.
|
|
@@ -22,12 +22,12 @@ export declare const migrations: {
|
|
|
22
22
|
* @category migrations
|
|
23
23
|
* @since 0.1.0
|
|
24
24
|
*/
|
|
25
|
-
export declare const run: import("effect/Effect").Effect<readonly (readonly [id: number, name: string])[], import("effect/
|
|
25
|
+
export declare const run: import("effect/Effect").Effect<readonly (readonly [id: number, name: string])[], import("effect/sql/SqlError").SqlError | Migrator.MigrationError, import("effect/sql/SqlClient").SqlClient>;
|
|
26
26
|
/**
|
|
27
27
|
* Runs {@link run} once as a layer.
|
|
28
28
|
*
|
|
29
29
|
* @category layers
|
|
30
30
|
* @since 0.1.0
|
|
31
31
|
*/
|
|
32
|
-
export declare const layer: Layer.Layer<never, import("effect/
|
|
32
|
+
export declare const layer: Layer.Layer<never, import("effect/sql/SqlError").SqlError | Migrator.MigrationError, import("effect/sql/SqlClient").SqlClient>;
|
|
33
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAM/C;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU;;;;;CAKtB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,GAAG,8LAAoG,CAAA;AAEpH;;;;;GAKG;AACH,eAAO,MAAM,KAAK,gIAA2B,CAAA"}
|
|
@@ -34,7 +34,7 @@ __export(migrations_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(migrations_exports);
|
|
36
36
|
var Layer = __toESM(require("effect/Layer"), 1);
|
|
37
|
-
var Migrator = __toESM(require("effect/
|
|
37
|
+
var Migrator = __toESM(require("effect/sql/Migrator"), 1);
|
|
38
38
|
var import_triggers = require("./0001_triggers.js");
|
|
39
39
|
var import_reservation_lease = require("./0002_reservation_lease.js");
|
|
40
40
|
var import_heartbeat = require("./0003_heartbeat.js");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/migrations/index.ts"],
|
|
4
|
-
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Layer from \"effect/Layer\"\nimport * as Migrator from \"effect/
|
|
4
|
+
"sourcesContent": ["/** @since 0.1.0 */\n\nimport * as Layer from \"effect/Layer\"\nimport * as Migrator from \"effect/sql/Migrator\"\nimport { triggers } from \"./0001_triggers.ts\"\nimport { reservationLease } from \"./0002_reservation_lease.ts\"\nimport { schedulerHeartbeat } from \"./0003_heartbeat.ts\"\nimport { fireRunIndex } from \"./0004_fire_run_index.ts\"\n\n/**\n * The migration record {@link run} applies, keyed by migration file name.\n *\n * Exported so a test and the release smoke can assert that every entry is the\n * migration Effect itself in both the ESM and the CommonJS build.\n *\n * @category migrations\n * @since 1.0.0-rc.0\n */\nexport const migrations = {\n \"0001_triggers\": triggers,\n \"0002_reservation_lease\": reservationLease,\n \"0003_heartbeat\": schedulerHeartbeat,\n \"0004_fire_run_index\": fireRunIndex\n}\n\n/**\n * Applies the triggers schema migrations.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const run = Migrator.make({})({ loader: Migrator.fromRecord(migrations), table: \"flows_trigger_migrations\" })\n\n/**\n * Runs {@link run} once as a layer.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = Layer.effectDiscard(run)\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,YAAuB;AACvB,eAA0B;AAC1B,sBAAyB;AACzB,+BAAiC;AACjC,uBAAmC;AACnC,4BAA6B;AAWtB,MAAM,aAAa;AAAA,EACxB,iBAAiB;AAAA,EACjB,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,uBAAuB;AACzB;AAQO,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC,EAAE,EAAE,QAAQ,SAAS,WAAW,UAAU,GAAG,OAAO,2BAA2B,CAAC;AAQ5G,MAAM,QAAQ,MAAM,cAAc,GAAG;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { DurableWriter } from "@smthrs/database/DurableWriter";
|
|
9
9
|
import * as Effect from "effect/Effect";
|
|
10
10
|
import * as Layer from "effect/Layer";
|
|
11
|
-
import * as SqlClient from "effect/
|
|
11
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
12
12
|
import { TriggerError } from "./TriggerError.ts";
|
|
13
13
|
import { type Service, TriggerStore } from "./TriggerStore.ts";
|
|
14
14
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlTriggerStore.d.ts","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAgB,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAE5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAIrC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"SqlTriggerStore.d.ts","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAgB,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAE5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAIrC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAMjD,OAAO,EAAmB,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAcL,KAAK,OAAO,EACZ,YAAY,EACb,MAAM,mBAAmB,CAAA;AAiG1B;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,CAC9B,OAAO,EACP,YAAY,EACZ,aAAa,GAAG,SAAS,CAAC,SAAS,CA+dnC,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAC7B,YAAY,EACZ,YAAY,EACZ,aAAa,GAAG,SAAS,CAAC,SAAS,CACD,CAAA"}
|
|
@@ -13,7 +13,7 @@ import * as Layer from "effect/Layer";
|
|
|
13
13
|
import * as Option from "effect/Option";
|
|
14
14
|
import * as Result from "effect/Result";
|
|
15
15
|
import * as Schema from "effect/Schema";
|
|
16
|
-
import * as SqlClient from "effect/
|
|
16
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
17
17
|
import * as ClaimDecision from "./ClaimDecision.js";
|
|
18
18
|
import * as Migrations from "./migrations/index.js";
|
|
19
19
|
import * as Overlap from "./Overlap.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlTriggerStore.js","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SQLite-backed trigger store.\n *\n * @see packages/smithers/agent/triggers/docs/api.md\n *\n * @since 0.1.0\n */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport { affectedRows, DurableWriter } from \"@smthrs/database/DurableWriter\"\nimport * as Clock from \"effect/Clock\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SqlClient from \"effect/unstable/sql/SqlClient\"\nimport * as ClaimDecision from \"./ClaimDecision.ts\"\nimport * as Migrations from \"./migrations/index.ts\"\nimport * as Overlap from \"./Overlap.ts\"\nimport * as Schedule from \"./Schedule.ts\"\nimport * as Trigger from \"./Trigger.ts\"\nimport { fromSchemaError, TriggerError } from \"./TriggerError.ts\"\nimport {\n type ClaimFire,\n type FireRecord,\n type Heartbeat,\n historyLimit,\n historyPage,\n isReservation,\n type Listed,\n type Outcome,\n pruneCutoff,\n type Registered,\n reservationId,\n reservationOccurrence,\n resultRefusal,\n type Service,\n TriggerStore\n} from \"./TriggerStore.ts\"\n\ninterface Row {\n readonly trigger_id: string\n readonly flow_id: string\n readonly input_json: string\n readonly cron: string\n readonly timezone: string | null\n readonly overlap: string\n readonly catch_up: string\n readonly max_catch_up: number\n readonly enabled: number\n readonly revision: number\n readonly last_fired_at_ms: number | null\n readonly active_run_id: string | null\n readonly pending_at_ms: number | null\n}\n\ninterface FireRow {\n readonly trigger_id: string\n readonly occurrence_at_ms: number\n readonly outcome: Outcome | null\n readonly run_id: string | null\n readonly error: string | null\n}\n\nconst fireRecord = (row: FireRow): FireRecord => ({\n triggerId: row.trigger_id,\n occurrence: row.occurrence_at_ms,\n outcome: row.outcome,\n ...(row.run_id === null ? {} : { runId: row.run_id }),\n ...(row.error === null ? {} : { error: row.error })\n})\n\ninterface ClaimRow {\n readonly enabled: number\n readonly revision: number\n readonly overlap: Registered[\"overlap\"]\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n}\n\nconst storeError = (message: string, cause?: unknown) =>\n new TriggerError({\n code: \"store\",\n message,\n ...(cause === undefined ? {} : { cause })\n })\n\nconst unknownTrigger = (triggerId: string) =>\n new TriggerError({ code: \"unknown_trigger\", message: `unknown trigger ${triggerId}` })\n\n// A stored row is decoded through the same schema `register` accepts, plus the\n// store-owned fields, rather than cast. The table's CHECKs cover the policy\n// literals but not the catch-up bound or the non-empty strings, and a row\n// anyone rewrote must not reach the scheduler as a declaration `register`\n// would have refused.\nconst StoredDeclaration = Schema.Struct({\n ...Trigger.Trigger.fields,\n revision: Schema.Int,\n lastFiredAt: Schema.optional(Schema.Number)\n})\nconst decodeDeclaration = Schema.decodeUnknownSync(StoredDeclaration)\n\nconst declaration = (row: Row): Registered =>\n decodeDeclaration({\n id: row.trigger_id,\n flowId: row.flow_id,\n input: JSON.parse(row.input_json),\n cron: row.cron,\n ...(row.timezone === null ? {} : { timezone: row.timezone }),\n overlap: row.overlap,\n catchUp: row.catch_up,\n maxCatchUp: row.max_catch_up,\n enabled: row.enabled === 1,\n revision: row.revision,\n ...(row.last_fired_at_ms === null ? {} : { lastFiredAt: row.last_fired_at_ms })\n })\n\n// The offending id belongs in the message: a store failure that only says a\n// row would not decode leaves an operator grepping a shared database for it.\nconst decodeFailure = (row: Row, cause: unknown) => storeError(`could not decode trigger row ${row.trigger_id}`, cause)\n\nconst decode = (row: Row): Effect.Effect<Registered, TriggerError> =>\n Effect.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) })\n\n// A listing decodes row by row. One corrupt `input_json` used to fail the\n// whole read, and because a scheduler tick lists every trigger before it\n// isolates them, that one row stopped every healthy schedule in the store.\nconst listedRow = (row: Row): Listed => ({\n triggerId: row.trigger_id,\n trigger: Result.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) }),\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n})\n\n/**\n * Builds a {@link TriggerStore.Service} over the ambient SQL client, with\n * every write going through the durable writer.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make: Effect.Effect<\n Service,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Effect.gen(function*() {\n const sql = yield* Effect.service(SqlClient.SqlClient)\n const writer = yield* DurableWriter\n // The migrator raises a schema it cannot apply as a defect, not as a typed\n // failure, so mapping the error channel alone left a defect escaping a\n // constructor whose signature promises `TriggerError`. Defects are caught\n // separately from failures, which leaves interruption alone.\n const migrationFailed = (cause: unknown) => storeError(\"could not run trigger migrations\", cause)\n yield* Migrations.run.pipe(\n Effect.mapError(migrationFailed),\n Effect.catchDefect((defect) => Effect.fail(migrationFailed(defect)))\n )\n // A failure the store itself typed already says which refusal it is, so it\n // travels out unchanged. Re-wrapping it turned `unknown trigger x` into the\n // generic write failure and erased the one code a caller could branch on.\n const asTriggerError = (message: string) => (cause: unknown): TriggerError =>\n cause instanceof TriggerError ? cause : storeError(message, cause)\n const read = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n effect.pipe(Effect.mapError(asTriggerError(\"trigger store read failed\")))\n const write = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n writer.write(effect).pipe(Effect.mapError(asTriggerError(\"trigger store write failed\")))\n const requireTrigger = (triggerId: string) =>\n sql<{ readonly trigger_id: string }>`SELECT trigger_id FROM flows_triggers WHERE trigger_id = ${triggerId}`.pipe(\n Effect.flatMap((rows) => rows[0] === undefined ? Effect.fail(unknownTrigger(triggerId)) : Effect.void)\n )\n const get: Service[\"get\"] = (triggerId) =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE trigger_id = ${triggerId}`).pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? Effect.succeed(Option.none()) : decode(rows[0]).pipe(Effect.map(Option.some))\n )\n )\n const fireSnapshot = (\n row: { readonly outcome: string | null; readonly run_id: string | null } | undefined\n ): ClaimDecision.Fire | undefined =>\n row === undefined ? undefined : {\n outcome: row.outcome as Outcome | null,\n ...(row.run_id === null ? {} : { runId: row.run_id })\n }\n const claimInTransaction = (\n fire: ClaimFire,\n claimedAt: number,\n suppliedRow?: ClaimRow\n ) =>\n Effect.gen(function*() {\n // The declaration is read first and inside the transaction, so the\n // policy applied is the stored one and a caller holding a snapshot from\n // before an edit is refused rather than obeyed.\n const row = suppliedRow ?? (yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `)[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const activeRunId = row.active_run_id ?? undefined\n // The fences run before the insert below, so a refused claim leaves no\n // ledger row behind.\n const refusal = ClaimDecision.refuse({ enabled: row.enabled === 1, revision: row.revision }, fire)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n const insertResult = yield* sql`\n INSERT INTO flows_trigger_fires (trigger_id, occurrence_at_ms)\n VALUES (${fire.triggerId}, ${fire.occurrence})\n ON CONFLICT (trigger_id, occurrence_at_ms) DO NOTHING\n `.raw\n const inserted = yield* affectedRows(insertResult)\n const existing = inserted === 0\n ? yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${fire.occurrence}\n `\n : []\n // Both the expired-reservation reclaim and the supersede predecessor\n // lookup read the row the reservation holds, so one read serves both.\n const activeOccurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const active = activeOccurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${activeOccurrence}\n `\n const existingFire = fireSnapshot(existing[0])\n const activeFire = fireSnapshot(active[0])\n const decision = ClaimDecision.decideFenced({\n fire,\n claimedAt,\n reservationId: reservationId(fire.triggerId, fire.occurrence, globalThis.crypto.randomUUID()),\n snapshot: {\n revision: row.revision,\n enabled: row.enabled === 1,\n overlap: row.overlap,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(existingFire === undefined ? {} : { existingFire }),\n ...(activeFire === undefined ? {} : { activeFire })\n }\n })\n for (const write of decision.writes) {\n switch (write._tag) {\n case \"SetOutcome\": {\n yield* write.whileOpen\n ? sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')`\n : sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"SetRunId\": {\n yield* sql`UPDATE flows_trigger_fires SET run_id = ${write.runId}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"ReleaseReservation\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.activeRunId ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${write.pending ?? null}\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${write.expected}`\n break\n }\n case \"AdvanceCursor\": {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${write.occurrence}), ${write.occurrence})\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"SetPending\": {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${write.occurrence}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"Reserve\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.reservationId}, active_claimed_at_ms = ${write.claimedAt}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n }\n }\n return decision.claim\n })\n\n return {\n register: (trigger) => {\n const decoded = Schema.decodeUnknownResult(Trigger.Trigger)(trigger)\n if (Result.isFailure(decoded)) {\n return Effect.fail(\n fromSchemaError(\"invalid_trigger\", \"Trigger declaration is invalid\", decoded.failure)\n )\n }\n const snapshot = decoded.success\n let input: string | undefined\n try {\n input = JSON.stringify(snapshot.input)\n } catch (cause) {\n return Effect.fail(storeError(\"trigger input is not JSON-serializable\", cause))\n }\n // `JSON.stringify` answers `undefined` rather than throwing for an input\n // it cannot represent. Keep this guard even though Schema.Json currently\n // refuses every such input before serialization.\n if (input === undefined) {\n return Effect.fail(\n new TriggerError({\n code: \"invalid_trigger\",\n message: \"trigger input has no JSON representation\",\n path: \"input\"\n })\n )\n }\n // Registration is the last point where an unsatisfiable expression can\n // still be refused. The decoded declaration and its input string were\n // already copied at the call boundary, before this lazy work begins.\n return Effect.suspend(() =>\n Schedule.validate(snapshot).pipe(\n Effect.andThen(\n write(sql`\n INSERT INTO flows_triggers (trigger_id, flow_id, input_json, cron, timezone, overlap, catch_up, max_catch_up, enabled, revision)\n VALUES (${snapshot.id}, ${snapshot.flowId}, ${input}, ${snapshot.cron}, ${\n snapshot.timezone ?? null\n }, ${snapshot.overlap}, ${snapshot.catchUp}, ${snapshot.maxCatchUp}, ${snapshot.enabled ? 1 : 0}, 1)\n ON CONFLICT (trigger_id) DO UPDATE SET flow_id = excluded.flow_id, input_json = excluded.input_json, cron = excluded.cron,\n timezone = excluded.timezone, overlap = excluded.overlap, catch_up = excluded.catch_up, max_catch_up = excluded.max_catch_up,\n enabled = excluded.enabled, revision = flows_triggers.revision + 1\n `.pipe(\n Effect.flatMap(() => get(snapshot.id)),\n Effect.flatMap((registered) =>\n Option.isSome(registered)\n ? Effect.succeed(registered.value)\n : Effect.fail(storeError(\"registered trigger disappeared\"))\n )\n ))\n )\n )\n )\n },\n get,\n list: () =>\n read(sql<Row>`SELECT * FROM flows_triggers ORDER BY trigger_id`).pipe(\n Effect.map((rows) => rows.map(listedRow))\n ),\n listEnabled: () =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE enabled = 1 ORDER BY trigger_id`).pipe(\n Effect.flatMap((rows) => Effect.all(rows.map(decode)))\n ),\n claimFire: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(claimInTransaction(fire, claimedAt))\n }),\n claimPending: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n if (row.pending_at_ms === null) return Option.none()\n const occurrence = row.pending_at_ms\n const claim = yield* claimInTransaction(\n {\n triggerId: fire.triggerId,\n occurrence,\n expectedRevision: fire.expectedRevision,\n resumeBuffered: true\n },\n claimedAt,\n row\n )\n if (claim.claimed && claim.action !== \"buffer\") {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = NULL WHERE trigger_id = ${fire.triggerId}`\n }\n return Option.some({ occurrence, claim })\n }))\n }),\n recordResult: (result) =>\n write(\n Effect.gen(function*() {\n yield* requireTrigger(result.triggerId)\n const rows = yield* sql<FireRow>`SELECT * FROM flows_trigger_fires\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n const held = yield* sql<{ readonly active_run_id: string | null }>`\n SELECT active_run_id FROM flows_triggers WHERE trigger_id = ${result.triggerId}`\n const existing = rows[0] === undefined ? undefined : fireRecord(rows[0])\n const active = held[0]!.active_run_id ?? undefined\n const refusal = resultRefusal(result, existing, active)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n if (result.outcome !== \"launched\" && existing?.outcome === result.outcome) return\n const terminal = result.outcome === \"completed\" || result.outcome === \"failed\" ||\n result.outcome === \"superseded\"\n const resultOwner = (existing?.outcome === \"launched\"\n ? existing.runId\n : result.reservationId ?? result.runId ?? active) ?? null\n if (terminal && result.runId === undefined) {\n // Keep the recorded owner so an unqualified late result can only\n // clear the run launched by this occurrence, never a newer one.\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n } else {\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, run_id = ${result.runId ?? null}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n }\n // `last_fired_at_ms` is the cursor catch-up resumes from, so it only\n // ever moves forward. An older run settling after a newer occurrence\n // was skipped used to drag it backwards and replay settled work.\n if (result.outcome === \"launched\") {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = ${result.runId},\n active_claimed_at_ms = NULL\n WHERE trigger_id = ${result.triggerId} AND active_run_id = ${result.reservationId}`\n return\n }\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_run_id\n END,\n active_claimed_at_ms = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_claimed_at_ms\n END\n WHERE trigger_id = ${result.triggerId}`\n })\n ).pipe(\n Effect.asVoid\n ),\n restorePending: (fire) =>\n write(Effect.gen(function*() {\n yield* requireTrigger(fire.triggerId)\n const rows = yield* sql<{ readonly pending_at_ms: number | null; readonly run_id: string | null }>`\n SELECT t.pending_at_ms, f.run_id FROM flows_triggers t JOIN flows_trigger_fires f\n ON f.trigger_id = t.trigger_id\n WHERE t.trigger_id = ${fire.triggerId} AND t.active_run_id = ${fire.reservationId}\n AND f.occurrence_at_ms = ${fire.occurrence} AND (f.outcome IS NULL OR f.outcome = 'buffered')`\n const row = rows[0]\n if (row === undefined || reservationOccurrence(fire.reservationId) !== fire.occurrence) {\n return yield* Effect.fail(\n new TriggerError({ code: \"stale_owner\", message: \"pending restoration no longer owns reservation\" })\n )\n }\n const pending = Overlap.pendingAfter({\n running: false,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n const predecessors = row.run_id === null || isReservation(row.run_id) ?\n [] :\n yield* sql<{ readonly run_id: string }>`\n SELECT run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND run_id = ${row.run_id} AND outcome = 'launched'`\n const predecessor = predecessors[0]?.run_id ?? null\n yield* sql`UPDATE flows_triggers\n SET pending_at_ms = ${pending}, active_run_id = ${predecessor}, active_claimed_at_ms = NULL\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${fire.reservationId}`\n })).pipe(Effect.asVoid),\n setPending: (fire) =>\n write(Effect.gen(function*() {\n const rows = yield* sql<{ readonly pending_at_ms: number | null }>`\n SELECT pending_at_ms FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const pending = Overlap.pendingAfter({\n running: true,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${pending} WHERE trigger_id = ${fire.triggerId}`\n })).pipe(Effect.asVoid),\n activeRun: (triggerId) =>\n Effect.gen(function*() {\n const now = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<{\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n }>`SELECT active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${triggerId}`\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(triggerId))\n const activeRunId = row.active_run_id ?? undefined\n const occurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const unfinished = occurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND occurrence_at_ms = ${occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')\n `\n const unfinishedFire = fireSnapshot(unfinished[0])\n const lease = ClaimDecision.lease({\n now,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(unfinishedFire === undefined ? {} : { unfinished: unfinishedFire })\n })\n if (lease._tag === \"Idle\") return Option.none()\n if (lease._tag === \"Held\") return Option.some(lease.runId)\n yield* lease.pending === undefined\n ? sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n : sql`UPDATE flows_triggers\n SET active_run_id = ${lease.recovered ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${lease.pending}\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n return lease.recovered === undefined ? Option.none() : Option.some(lease.recovered)\n }))\n }),\n activeOccurrence: (triggerId, runId) =>\n read(Effect.gen(function*() {\n yield* requireTrigger(triggerId)\n const reserved = reservationOccurrence(runId)\n if (reserved !== undefined) return Option.some(reserved)\n if (isReservation(runId)) return Option.none()\n const rows = yield* sql<{ readonly occurrence_at_ms: number }>`\n SELECT occurrence_at_ms FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND run_id = ${runId} AND outcome = 'launched'\n ORDER BY occurrence_at_ms DESC LIMIT 1\n `\n return rows[0] === undefined ? Option.none() : Option.some(rows[0].occurrence_at_ms)\n })),\n clearActive: (triggerId, runId) =>\n write(sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${runId}`).pipe(\n Effect.asVoid\n ),\n history: (query = {}) =>\n historyLimit(query.limit).pipe(\n Effect.flatMap((limit) =>\n // One statement for every query shape: a null parameter disables\n // its predicate, and SQLite reads `LIMIT -1` as no limit. One row\n // past the limit is fetched so the page knows whether a next page\n // exists without a second count query.\n read(sql<FireRow>`\n SELECT trigger_id, occurrence_at_ms, outcome, run_id, error FROM flows_trigger_fires\n WHERE ${query.triggerId === undefined ? sql`1 = 1` : sql`trigger_id = ${query.triggerId}`}\n AND ${query.runId === undefined ? sql`1 = 1` : sql`run_id = ${query.runId}`}\n AND ${query.outcome === undefined ? sql`1 = 1` : sql`outcome = ${query.outcome}`}\n AND (${query.cursor === undefined ? 1 : 0} = 1\n OR occurrence_at_ms < ${query.cursor?.occurrence ?? null}\n OR (occurrence_at_ms = ${query.cursor?.occurrence ?? null} AND trigger_id < ${\n query.cursor?.triggerId ?? null\n }))\n ORDER BY occurrence_at_ms DESC, trigger_id DESC\n LIMIT ${limit === undefined ? (Dialect.isPostgres(sql) ? null : -1) : limit + 1}\n `).pipe(Effect.map((rows) => historyPage(rows.map(fireRecord), limit)))\n )\n ),\n pruneFires: ({ olderThan }) =>\n pruneCutoff(olderThan).pipe(\n Effect.flatMap((cutoff) =>\n // The trigger row names the state the scheduler still reads: the\n // buffered occurrence and the run or reservation on `active_run_id`.\n // An unsettled row carries no outcome, so the outcome filter already\n // spares a reserved occurrence.\n write(Effect.gen(function*() {\n const deleted = yield* sql`\n DELETE FROM flows_trigger_fires\n WHERE occurrence_at_ms < ${cutoff}\n AND outcome IN ('completed', 'failed', 'skipped', 'superseded')\n AND NOT EXISTS (\n SELECT 1 FROM flows_triggers t\n WHERE t.trigger_id = flows_trigger_fires.trigger_id\n AND (t.pending_at_ms = flows_trigger_fires.occurrence_at_ms\n OR t.active_run_id = flows_trigger_fires.run_id)\n )\n `.raw\n return yield* affectedRows(deleted)\n }))\n )\n ),\n inspect: (triggerId) =>\n read(sql<{ readonly active_run_id: string | null; readonly pending_at_ms: number | null }>`\n SELECT active_run_id, pending_at_ms FROM flows_triggers WHERE trigger_id = ${triggerId}\n `).pipe(\n Effect.flatMap((rows) => {\n const row = rows[0]\n if (row === undefined) return Effect.fail(unknownTrigger(triggerId))\n return Effect.succeed({\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n })\n })\n ),\n heartbeat: (host) =>\n Effect.flatMap(\n Clock.currentTimeMillis,\n (tickedAt) =>\n write(sql`INSERT INTO flows_scheduler_heartbeat (host, ticked_at_ms) VALUES (${host}, ${tickedAt})\n ON CONFLICT (host) DO UPDATE SET ticked_at_ms = excluded.ticked_at_ms`)\n ).pipe(Effect.asVoid),\n lastHeartbeat: () =>\n read(sql<{ readonly host: string; readonly ticked_at_ms: number }>`\n SELECT host, ticked_at_ms FROM flows_scheduler_heartbeat ORDER BY ticked_at_ms DESC, host ASC LIMIT 1\n `).pipe(\n Effect.map((rows) =>\n rows[0] === undefined\n ? Option.none<Heartbeat>()\n : Option.some({ host: rows[0].host, tickedAt: rows[0].ticked_at_ms })\n )\n )\n }\n})\n\n/**\n * Provides {@link TriggerStore.TriggerStore} backed by SQL.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<\n TriggerStore,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Layer.effect(TriggerStore)(make)\n"]}
|
|
1
|
+
{"version":3,"file":"SqlTriggerStore.js","sourceRoot":"","sources":["../../src/SqlTriggerStore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SQLite-backed trigger store.\n *\n * @see packages/smithers/agent/triggers/docs/api.md\n *\n * @since 0.1.0\n */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport { affectedRows, DurableWriter } from \"@smthrs/database/DurableWriter\"\nimport * as Clock from \"effect/Clock\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\nimport * as ClaimDecision from \"./ClaimDecision.ts\"\nimport * as Migrations from \"./migrations/index.ts\"\nimport * as Overlap from \"./Overlap.ts\"\nimport * as Schedule from \"./Schedule.ts\"\nimport * as Trigger from \"./Trigger.ts\"\nimport { fromSchemaError, TriggerError } from \"./TriggerError.ts\"\nimport {\n type ClaimFire,\n type FireRecord,\n type Heartbeat,\n historyLimit,\n historyPage,\n isReservation,\n type Listed,\n type Outcome,\n pruneCutoff,\n type Registered,\n reservationId,\n reservationOccurrence,\n resultRefusal,\n type Service,\n TriggerStore\n} from \"./TriggerStore.ts\"\n\ninterface Row {\n readonly trigger_id: string\n readonly flow_id: string\n readonly input_json: string\n readonly cron: string\n readonly timezone: string | null\n readonly overlap: string\n readonly catch_up: string\n readonly max_catch_up: number\n readonly enabled: number\n readonly revision: number\n readonly last_fired_at_ms: number | null\n readonly active_run_id: string | null\n readonly pending_at_ms: number | null\n}\n\ninterface FireRow {\n readonly trigger_id: string\n readonly occurrence_at_ms: number\n readonly outcome: Outcome | null\n readonly run_id: string | null\n readonly error: string | null\n}\n\nconst fireRecord = (row: FireRow): FireRecord => ({\n triggerId: row.trigger_id,\n occurrence: row.occurrence_at_ms,\n outcome: row.outcome,\n ...(row.run_id === null ? {} : { runId: row.run_id }),\n ...(row.error === null ? {} : { error: row.error })\n})\n\ninterface ClaimRow {\n readonly enabled: number\n readonly revision: number\n readonly overlap: Registered[\"overlap\"]\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n}\n\nconst storeError = (message: string, cause?: unknown) =>\n new TriggerError({\n code: \"store\",\n message,\n ...(cause === undefined ? {} : { cause })\n })\n\nconst unknownTrigger = (triggerId: string) =>\n new TriggerError({ code: \"unknown_trigger\", message: `unknown trigger ${triggerId}` })\n\n// A stored row is decoded through the same schema `register` accepts, plus the\n// store-owned fields, rather than cast. The table's CHECKs cover the policy\n// literals but not the catch-up bound or the non-empty strings, and a row\n// anyone rewrote must not reach the scheduler as a declaration `register`\n// would have refused.\nconst StoredDeclaration = Schema.Struct({\n ...Trigger.Trigger.fields,\n revision: Schema.Int,\n lastFiredAt: Schema.optional(Schema.Number)\n})\nconst decodeDeclaration = Schema.decodeUnknownSync(StoredDeclaration)\n\nconst declaration = (row: Row): Registered =>\n decodeDeclaration({\n id: row.trigger_id,\n flowId: row.flow_id,\n input: JSON.parse(row.input_json),\n cron: row.cron,\n ...(row.timezone === null ? {} : { timezone: row.timezone }),\n overlap: row.overlap,\n catchUp: row.catch_up,\n maxCatchUp: row.max_catch_up,\n enabled: row.enabled === 1,\n revision: row.revision,\n ...(row.last_fired_at_ms === null ? {} : { lastFiredAt: row.last_fired_at_ms })\n })\n\n// The offending id belongs in the message: a store failure that only says a\n// row would not decode leaves an operator grepping a shared database for it.\nconst decodeFailure = (row: Row, cause: unknown) => storeError(`could not decode trigger row ${row.trigger_id}`, cause)\n\nconst decode = (row: Row): Effect.Effect<Registered, TriggerError> =>\n Effect.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) })\n\n// A listing decodes row by row. One corrupt `input_json` used to fail the\n// whole read, and because a scheduler tick lists every trigger before it\n// isolates them, that one row stopped every healthy schedule in the store.\nconst listedRow = (row: Row): Listed => ({\n triggerId: row.trigger_id,\n trigger: Result.try({ try: () => declaration(row), catch: (cause) => decodeFailure(row, cause) }),\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n})\n\n/**\n * Builds a {@link TriggerStore.Service} over the ambient SQL client, with\n * every write going through the durable writer.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make: Effect.Effect<\n Service,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Effect.gen(function*() {\n const sql = yield* Effect.service(SqlClient.SqlClient)\n const writer = yield* DurableWriter\n // The migrator raises a schema it cannot apply as a defect, not as a typed\n // failure, so mapping the error channel alone left a defect escaping a\n // constructor whose signature promises `TriggerError`. Defects are caught\n // separately from failures, which leaves interruption alone.\n const migrationFailed = (cause: unknown) => storeError(\"could not run trigger migrations\", cause)\n yield* Migrations.run.pipe(\n Effect.mapError(migrationFailed),\n Effect.catchDefect((defect) => Effect.fail(migrationFailed(defect)))\n )\n // A failure the store itself typed already says which refusal it is, so it\n // travels out unchanged. Re-wrapping it turned `unknown trigger x` into the\n // generic write failure and erased the one code a caller could branch on.\n const asTriggerError = (message: string) => (cause: unknown): TriggerError =>\n cause instanceof TriggerError ? cause : storeError(message, cause)\n const read = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n effect.pipe(Effect.mapError(asTriggerError(\"trigger store read failed\")))\n const write = <A>(effect: Effect.Effect<A, unknown>): Effect.Effect<A, TriggerError> =>\n writer.write(effect).pipe(Effect.mapError(asTriggerError(\"trigger store write failed\")))\n const requireTrigger = (triggerId: string) =>\n sql<{ readonly trigger_id: string }>`SELECT trigger_id FROM flows_triggers WHERE trigger_id = ${triggerId}`.pipe(\n Effect.flatMap((rows) => rows[0] === undefined ? Effect.fail(unknownTrigger(triggerId)) : Effect.void)\n )\n const get: Service[\"get\"] = (triggerId) =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE trigger_id = ${triggerId}`).pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? Effect.succeed(Option.none()) : decode(rows[0]).pipe(Effect.map(Option.some))\n )\n )\n const fireSnapshot = (\n row: { readonly outcome: string | null; readonly run_id: string | null } | undefined\n ): ClaimDecision.Fire | undefined =>\n row === undefined ? undefined : {\n outcome: row.outcome as Outcome | null,\n ...(row.run_id === null ? {} : { runId: row.run_id })\n }\n const claimInTransaction = (\n fire: ClaimFire,\n claimedAt: number,\n suppliedRow?: ClaimRow\n ) =>\n Effect.gen(function*() {\n // The declaration is read first and inside the transaction, so the\n // policy applied is the stored one and a caller holding a snapshot from\n // before an edit is refused rather than obeyed.\n const row = suppliedRow ?? (yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `)[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const activeRunId = row.active_run_id ?? undefined\n // The fences run before the insert below, so a refused claim leaves no\n // ledger row behind.\n const refusal = ClaimDecision.refuse({ enabled: row.enabled === 1, revision: row.revision }, fire)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n const insertResult = yield* sql`\n INSERT INTO flows_trigger_fires (trigger_id, occurrence_at_ms)\n VALUES (${fire.triggerId}, ${fire.occurrence})\n ON CONFLICT (trigger_id, occurrence_at_ms) DO NOTHING\n `.raw\n const inserted = yield* affectedRows(insertResult)\n const existing = inserted === 0\n ? yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${fire.occurrence}\n `\n : []\n // Both the expired-reservation reclaim and the supersede predecessor\n // lookup read the row the reservation holds, so one read serves both.\n const activeOccurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const active = activeOccurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${activeOccurrence}\n `\n const existingFire = fireSnapshot(existing[0])\n const activeFire = fireSnapshot(active[0])\n const decision = ClaimDecision.decideFenced({\n fire,\n claimedAt,\n reservationId: reservationId(fire.triggerId, fire.occurrence, globalThis.crypto.randomUUID()),\n snapshot: {\n revision: row.revision,\n enabled: row.enabled === 1,\n overlap: row.overlap,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(existingFire === undefined ? {} : { existingFire }),\n ...(activeFire === undefined ? {} : { activeFire })\n }\n })\n for (const write of decision.writes) {\n switch (write._tag) {\n case \"SetOutcome\": {\n yield* write.whileOpen\n ? sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')`\n : sql`UPDATE flows_trigger_fires SET outcome = ${write.outcome}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"SetRunId\": {\n yield* sql`UPDATE flows_trigger_fires SET run_id = ${write.runId}\n WHERE trigger_id = ${fire.triggerId} AND occurrence_at_ms = ${write.occurrence}`\n break\n }\n case \"ReleaseReservation\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.activeRunId ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${write.pending ?? null}\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${write.expected}`\n break\n }\n case \"AdvanceCursor\": {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${write.occurrence}), ${write.occurrence})\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"SetPending\": {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${write.occurrence}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n case \"Reserve\": {\n yield* sql`UPDATE flows_triggers\n SET active_run_id = ${write.reservationId}, active_claimed_at_ms = ${write.claimedAt}\n WHERE trigger_id = ${fire.triggerId}`\n break\n }\n }\n }\n return decision.claim\n })\n\n return {\n register: (trigger) => {\n const decoded = Schema.decodeUnknownResult(Trigger.Trigger)(trigger)\n if (Result.isFailure(decoded)) {\n return Effect.fail(\n fromSchemaError(\"invalid_trigger\", \"Trigger declaration is invalid\", decoded.failure)\n )\n }\n const snapshot = decoded.success\n let input: string | undefined\n try {\n input = JSON.stringify(snapshot.input)\n } catch (cause) {\n return Effect.fail(storeError(\"trigger input is not JSON-serializable\", cause))\n }\n // `JSON.stringify` answers `undefined` rather than throwing for an input\n // it cannot represent. Keep this guard even though Schema.Json currently\n // refuses every such input before serialization.\n if (input === undefined) {\n return Effect.fail(\n new TriggerError({\n code: \"invalid_trigger\",\n message: \"trigger input has no JSON representation\",\n path: \"input\"\n })\n )\n }\n // Registration is the last point where an unsatisfiable expression can\n // still be refused. The decoded declaration and its input string were\n // already copied at the call boundary, before this lazy work begins.\n return Effect.suspend(() =>\n Schedule.validate(snapshot).pipe(\n Effect.andThen(\n write(sql`\n INSERT INTO flows_triggers (trigger_id, flow_id, input_json, cron, timezone, overlap, catch_up, max_catch_up, enabled, revision)\n VALUES (${snapshot.id}, ${snapshot.flowId}, ${input}, ${snapshot.cron}, ${\n snapshot.timezone ?? null\n }, ${snapshot.overlap}, ${snapshot.catchUp}, ${snapshot.maxCatchUp}, ${snapshot.enabled ? 1 : 0}, 1)\n ON CONFLICT (trigger_id) DO UPDATE SET flow_id = excluded.flow_id, input_json = excluded.input_json, cron = excluded.cron,\n timezone = excluded.timezone, overlap = excluded.overlap, catch_up = excluded.catch_up, max_catch_up = excluded.max_catch_up,\n enabled = excluded.enabled, revision = flows_triggers.revision + 1\n `.pipe(\n Effect.flatMap(() => get(snapshot.id)),\n Effect.flatMap((registered) =>\n Option.isSome(registered)\n ? Effect.succeed(registered.value)\n : Effect.fail(storeError(\"registered trigger disappeared\"))\n )\n ))\n )\n )\n )\n },\n get,\n list: () =>\n read(sql<Row>`SELECT * FROM flows_triggers ORDER BY trigger_id`).pipe(\n Effect.map((rows) => rows.map(listedRow))\n ),\n listEnabled: () =>\n read(sql<Row>`SELECT * FROM flows_triggers WHERE enabled = 1 ORDER BY trigger_id`).pipe(\n Effect.flatMap((rows) => Effect.all(rows.map(decode)))\n ),\n claimFire: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(claimInTransaction(fire, claimedAt))\n }),\n claimPending: (fire) =>\n Effect.gen(function*() {\n const claimedAt = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<ClaimRow>`\n SELECT enabled, revision, overlap, active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n if (row.pending_at_ms === null) return Option.none()\n const occurrence = row.pending_at_ms\n const claim = yield* claimInTransaction(\n {\n triggerId: fire.triggerId,\n occurrence,\n expectedRevision: fire.expectedRevision,\n resumeBuffered: true\n },\n claimedAt,\n row\n )\n if (claim.claimed && claim.action !== \"buffer\") {\n yield* sql`UPDATE flows_triggers SET pending_at_ms = NULL WHERE trigger_id = ${fire.triggerId}`\n }\n return Option.some({ occurrence, claim })\n }))\n }),\n recordResult: (result) =>\n write(\n Effect.gen(function*() {\n yield* requireTrigger(result.triggerId)\n const rows = yield* sql<FireRow>`SELECT * FROM flows_trigger_fires\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n const held = yield* sql<{ readonly active_run_id: string | null }>`\n SELECT active_run_id FROM flows_triggers WHERE trigger_id = ${result.triggerId}`\n const existing = rows[0] === undefined ? undefined : fireRecord(rows[0])\n const active = held[0]!.active_run_id ?? undefined\n const refusal = resultRefusal(result, existing, active)\n if (refusal !== undefined) return yield* Effect.fail(refusal)\n if (result.outcome !== \"launched\" && existing?.outcome === result.outcome) return\n const terminal = result.outcome === \"completed\" || result.outcome === \"failed\" ||\n result.outcome === \"superseded\"\n const resultOwner = (existing?.outcome === \"launched\"\n ? existing.runId\n : result.reservationId ?? result.runId ?? active) ?? null\n if (terminal && result.runId === undefined) {\n // Keep the recorded owner so an unqualified late result can only\n // clear the run launched by this occurrence, never a newer one.\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n } else {\n yield* sql`UPDATE flows_trigger_fires\n SET outcome = ${result.outcome}, run_id = ${result.runId ?? null}, error = ${result.error ?? null}\n WHERE trigger_id = ${result.triggerId} AND occurrence_at_ms = ${result.occurrence}`\n }\n // `last_fired_at_ms` is the cursor catch-up resumes from, so it only\n // ever moves forward. An older run settling after a newer occurrence\n // was skipped used to drag it backwards and replay settled work.\n if (result.outcome === \"launched\") {\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = ${result.runId},\n active_claimed_at_ms = NULL\n WHERE trigger_id = ${result.triggerId} AND active_run_id = ${result.reservationId}`\n return\n }\n yield* sql`UPDATE flows_triggers\n SET last_fired_at_ms = ${\n Dialect.greatest(sql)\n }(COALESCE(last_fired_at_ms, ${result.occurrence}), ${result.occurrence}),\n active_run_id = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_run_id\n END,\n active_claimed_at_ms = CASE\n WHEN active_run_id = ${resultOwner} THEN NULL\n ELSE active_claimed_at_ms\n END\n WHERE trigger_id = ${result.triggerId}`\n })\n ).pipe(\n Effect.asVoid\n ),\n restorePending: (fire) =>\n write(Effect.gen(function*() {\n yield* requireTrigger(fire.triggerId)\n const rows = yield* sql<{ readonly pending_at_ms: number | null; readonly run_id: string | null }>`\n SELECT t.pending_at_ms, f.run_id FROM flows_triggers t JOIN flows_trigger_fires f\n ON f.trigger_id = t.trigger_id\n WHERE t.trigger_id = ${fire.triggerId} AND t.active_run_id = ${fire.reservationId}\n AND f.occurrence_at_ms = ${fire.occurrence} AND (f.outcome IS NULL OR f.outcome = 'buffered')`\n const row = rows[0]\n if (row === undefined || reservationOccurrence(fire.reservationId) !== fire.occurrence) {\n return yield* Effect.fail(\n new TriggerError({ code: \"stale_owner\", message: \"pending restoration no longer owns reservation\" })\n )\n }\n const pending = Overlap.pendingAfter({\n running: false,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n const predecessors = row.run_id === null || isReservation(row.run_id) ?\n [] :\n yield* sql<{ readonly run_id: string }>`\n SELECT run_id FROM flows_trigger_fires\n WHERE trigger_id = ${fire.triggerId} AND run_id = ${row.run_id} AND outcome = 'launched'`\n const predecessor = predecessors[0]?.run_id ?? null\n yield* sql`UPDATE flows_triggers\n SET pending_at_ms = ${pending}, active_run_id = ${predecessor}, active_claimed_at_ms = NULL\n WHERE trigger_id = ${fire.triggerId} AND active_run_id = ${fire.reservationId}`\n })).pipe(Effect.asVoid),\n setPending: (fire) =>\n write(Effect.gen(function*() {\n const rows = yield* sql<{ readonly pending_at_ms: number | null }>`\n SELECT pending_at_ms FROM flows_triggers WHERE trigger_id = ${fire.triggerId}\n `\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(fire.triggerId))\n const pending = Overlap.pendingAfter({\n running: true,\n pending: row.pending_at_ms ?? undefined,\n due: fire.occurrence\n })\n yield* sql`UPDATE flows_triggers SET pending_at_ms = ${pending} WHERE trigger_id = ${fire.triggerId}`\n })).pipe(Effect.asVoid),\n activeRun: (triggerId) =>\n Effect.gen(function*() {\n const now = yield* Clock.currentTimeMillis\n return yield* write(Effect.gen(function*() {\n const rows = yield* sql<{\n readonly active_run_id: string | null\n readonly active_claimed_at_ms: number | null\n readonly pending_at_ms: number | null\n }>`SELECT active_run_id, active_claimed_at_ms, pending_at_ms\n FROM flows_triggers WHERE trigger_id = ${triggerId}`\n const row = rows[0]\n if (row === undefined) return yield* Effect.fail(unknownTrigger(triggerId))\n const activeRunId = row.active_run_id ?? undefined\n const occurrence = activeRunId !== undefined && isReservation(activeRunId)\n ? reservationOccurrence(activeRunId)\n : undefined\n const unfinished = occurrence === undefined\n ? []\n : yield* sql<{ readonly outcome: string | null; readonly run_id: string | null }>`\n SELECT outcome, run_id FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND occurrence_at_ms = ${occurrence}\n AND (outcome IS NULL OR outcome = 'buffered')\n `\n const unfinishedFire = fireSnapshot(unfinished[0])\n const lease = ClaimDecision.lease({\n now,\n ...(activeRunId === undefined ? {} : { activeRunId }),\n ...(row.active_claimed_at_ms === null ? {} : { activeClaimedAt: row.active_claimed_at_ms }),\n ...(row.pending_at_ms === null ? {} : { pending: row.pending_at_ms }),\n ...(unfinishedFire === undefined ? {} : { unfinished: unfinishedFire })\n })\n if (lease._tag === \"Idle\") return Option.none()\n if (lease._tag === \"Held\") return Option.some(lease.runId)\n yield* lease.pending === undefined\n ? sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n : sql`UPDATE flows_triggers\n SET active_run_id = ${lease.recovered ?? null}, active_claimed_at_ms = NULL,\n pending_at_ms = ${lease.pending}\n WHERE trigger_id = ${triggerId} AND active_run_id = ${lease.expected}`\n return lease.recovered === undefined ? Option.none() : Option.some(lease.recovered)\n }))\n }),\n activeOccurrence: (triggerId, runId) =>\n read(Effect.gen(function*() {\n yield* requireTrigger(triggerId)\n const reserved = reservationOccurrence(runId)\n if (reserved !== undefined) return Option.some(reserved)\n if (isReservation(runId)) return Option.none()\n const rows = yield* sql<{ readonly occurrence_at_ms: number }>`\n SELECT occurrence_at_ms FROM flows_trigger_fires\n WHERE trigger_id = ${triggerId} AND run_id = ${runId} AND outcome = 'launched'\n ORDER BY occurrence_at_ms DESC LIMIT 1\n `\n return rows[0] === undefined ? Option.none() : Option.some(rows[0].occurrence_at_ms)\n })),\n clearActive: (triggerId, runId) =>\n write(sql`UPDATE flows_triggers SET active_run_id = NULL, active_claimed_at_ms = NULL\n WHERE trigger_id = ${triggerId} AND active_run_id = ${runId}`).pipe(\n Effect.asVoid\n ),\n history: (query = {}) =>\n historyLimit(query.limit).pipe(\n Effect.flatMap((limit) =>\n // One statement for every query shape: a null parameter disables\n // its predicate, and SQLite reads `LIMIT -1` as no limit. One row\n // past the limit is fetched so the page knows whether a next page\n // exists without a second count query.\n read(sql<FireRow>`\n SELECT trigger_id, occurrence_at_ms, outcome, run_id, error FROM flows_trigger_fires\n WHERE ${query.triggerId === undefined ? sql`1 = 1` : sql`trigger_id = ${query.triggerId}`}\n AND ${query.runId === undefined ? sql`1 = 1` : sql`run_id = ${query.runId}`}\n AND ${query.outcome === undefined ? sql`1 = 1` : sql`outcome = ${query.outcome}`}\n AND (${query.cursor === undefined ? 1 : 0} = 1\n OR occurrence_at_ms < ${query.cursor?.occurrence ?? null}\n OR (occurrence_at_ms = ${query.cursor?.occurrence ?? null} AND trigger_id < ${\n query.cursor?.triggerId ?? null\n }))\n ORDER BY occurrence_at_ms DESC, trigger_id DESC\n LIMIT ${limit === undefined ? (Dialect.isPostgres(sql) ? null : -1) : limit + 1}\n `).pipe(Effect.map((rows) => historyPage(rows.map(fireRecord), limit)))\n )\n ),\n pruneFires: ({ olderThan }) =>\n pruneCutoff(olderThan).pipe(\n Effect.flatMap((cutoff) =>\n // The trigger row names the state the scheduler still reads: the\n // buffered occurrence and the run or reservation on `active_run_id`.\n // An unsettled row carries no outcome, so the outcome filter already\n // spares a reserved occurrence.\n write(Effect.gen(function*() {\n const deleted = yield* sql`\n DELETE FROM flows_trigger_fires\n WHERE occurrence_at_ms < ${cutoff}\n AND outcome IN ('completed', 'failed', 'skipped', 'superseded')\n AND NOT EXISTS (\n SELECT 1 FROM flows_triggers t\n WHERE t.trigger_id = flows_trigger_fires.trigger_id\n AND (t.pending_at_ms = flows_trigger_fires.occurrence_at_ms\n OR t.active_run_id = flows_trigger_fires.run_id)\n )\n `.raw\n return yield* affectedRows(deleted)\n }))\n )\n ),\n inspect: (triggerId) =>\n read(sql<{ readonly active_run_id: string | null; readonly pending_at_ms: number | null }>`\n SELECT active_run_id, pending_at_ms FROM flows_triggers WHERE trigger_id = ${triggerId}\n `).pipe(\n Effect.flatMap((rows) => {\n const row = rows[0]\n if (row === undefined) return Effect.fail(unknownTrigger(triggerId))\n return Effect.succeed({\n ...(row.active_run_id === null ? {} : { activeRunId: row.active_run_id }),\n ...(row.pending_at_ms === null ? {} : { pendingAt: row.pending_at_ms })\n })\n })\n ),\n heartbeat: (host) =>\n Effect.flatMap(\n Clock.currentTimeMillis,\n (tickedAt) =>\n write(sql`INSERT INTO flows_scheduler_heartbeat (host, ticked_at_ms) VALUES (${host}, ${tickedAt})\n ON CONFLICT (host) DO UPDATE SET ticked_at_ms = excluded.ticked_at_ms`)\n ).pipe(Effect.asVoid),\n lastHeartbeat: () =>\n read(sql<{ readonly host: string; readonly ticked_at_ms: number }>`\n SELECT host, ticked_at_ms FROM flows_scheduler_heartbeat ORDER BY ticked_at_ms DESC, host ASC LIMIT 1\n `).pipe(\n Effect.map((rows) =>\n rows[0] === undefined\n ? Option.none<Heartbeat>()\n : Option.some({ host: rows[0].host, tickedAt: rows[0].ticked_at_ms })\n )\n )\n }\n})\n\n/**\n * Provides {@link TriggerStore.TriggerStore} backed by SQL.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<\n TriggerStore,\n TriggerError,\n DurableWriter | SqlClient.SqlClient\n> = Layer.effect(TriggerStore)(make)\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0001_triggers.d.ts","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0001_triggers.d.ts","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CA0BrE,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
import * as Dialect from "@smthrs/database/Dialect";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as SqlClient from "effect/
|
|
4
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
5
5
|
/**
|
|
6
6
|
* Creates the `flows_triggers` and `flows_trigger_fires` tables.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0001_triggers.js","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0001_triggers.js","sourceRoot":"","sources":["../../../src/migrations/0001_triggers.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAsD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC7F,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAA;IACtC,KAAK,CAAC,CAAC,GAAG,CAAA;;;;;;;;mBAQO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;cACzB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;eACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;uBACZ,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;oBACvB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;;IAEpC,CAAA;IACF,KAAK,CAAC,CAAC,GAAG,CAAA;;uBAEW,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;;IAMvC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Creates the `flows_triggers` and `flows_trigger_fires` tables.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const triggers: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE TABLE IF NOT EXISTS flows_triggers (\n trigger_id TEXT PRIMARY KEY,\n flow_id TEXT NOT NULL,\n input_json TEXT NOT NULL,\n cron TEXT NOT NULL,\n timezone TEXT,\n overlap TEXT NOT NULL CHECK (overlap IN ('skip', 'buffer-one', 'supersede')),\n catch_up TEXT NOT NULL CHECK (catch_up IN ('none', 'one', 'all')),\n max_catch_up ${Dialect.integer(sql)} NOT NULL CHECK (max_catch_up >= 0),\n enabled ${Dialect.integer(sql)} NOT NULL CHECK (enabled IN (0, 1)),\n revision ${Dialect.integer(sql)} NOT NULL,\n last_fired_at_ms ${Dialect.integer(sql)},\n pending_at_ms ${Dialect.integer(sql)},\n active_run_id TEXT\n )`\n yield* sql`CREATE TABLE IF NOT EXISTS flows_trigger_fires (\n trigger_id TEXT NOT NULL,\n occurrence_at_ms ${Dialect.integer(sql)} NOT NULL,\n outcome TEXT,\n run_id TEXT,\n error TEXT,\n PRIMARY KEY (trigger_id, occurrence_at_ms),\n FOREIGN KEY (trigger_id) REFERENCES flows_triggers (trigger_id)\n )`\n})\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0002_reservation_lease.d.ts","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0002_reservation_lease.d.ts","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAGnB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAG7E,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
import * as Dialect from "@smthrs/database/Dialect";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as SqlClient from "effect/
|
|
4
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
5
5
|
/**
|
|
6
6
|
* Adds `active_claimed_at_ms`, the lease start of a launch reservation.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0002_reservation_lease.js","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0002_reservation_lease.js","sourceRoot":"","sources":["../../../src/migrations/0002_reservation_lease.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrG,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAA;IACtC,KAAK,CAAC,CAAC,GAAG,CAAA,8DAA8D,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAA;AAChG,CAAC,CAAC,CAAA","sourcesContent":["/** @since 0.1.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Adds `active_claimed_at_ms`, the lease start of a launch reservation.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const reservationLease: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`ALTER TABLE flows_triggers ADD COLUMN active_claimed_at_ms ${Dialect.integer(sql)}`\n})\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.0 */
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as SqlClient from "effect/
|
|
3
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
4
4
|
/**
|
|
5
5
|
* Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the
|
|
6
6
|
* last poll it recorded, so a listing can say whether anything is listening.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0003_heartbeat.d.ts","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAGxB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0003_heartbeat.d.ts","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAGxB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAM/E,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.0 */
|
|
2
2
|
import * as Dialect from "@smthrs/database/Dialect";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as SqlClient from "effect/
|
|
4
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
5
5
|
/**
|
|
6
6
|
* Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the
|
|
7
7
|
* last poll it recorded, so a listing can say whether anything is listening.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0003_heartbeat.js","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0003_heartbeat.js","sourceRoot":"","sources":["../../../src/migrations/0003_heartbeat.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACvG,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAA;IACtC,KAAK,CAAC,CAAC,GAAG,CAAA;;mBAEO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;IACnC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["/** @since 1.0.0-rc.0 */\n\nimport * as Dialect from \"@smthrs/database/Dialect\"\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the\n * last poll it recorded, so a listing can say whether anything is listening.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 1.0.0-rc.0\n */\nexport const schedulerHeartbeat: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE TABLE IF NOT EXISTS flows_scheduler_heartbeat (\n host TEXT PRIMARY KEY,\n ticked_at_ms ${Dialect.integer(sql)} NOT NULL\n )`\n})\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.1 */
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as SqlClient from "effect/
|
|
3
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
4
4
|
/**
|
|
5
5
|
* Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to
|
|
6
6
|
* one run and the prune's active-run check read an index instead of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0004_fire_run_index.d.ts","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0004_fire_run_index.d.ts","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,SAAS,CAGzE,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.1 */
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as SqlClient from "effect/
|
|
3
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
4
4
|
/**
|
|
5
5
|
* Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to
|
|
6
6
|
* one run and the prune's active-run check read an index instead of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0004_fire_run_index.js","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM
|
|
1
|
+
{"version":3,"file":"0004_fire_run_index.js","sourceRoot":"","sources":["../../../src/migrations/0004_fire_run_index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAsD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACjG,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAA;IACtC,KAAK,CAAC,CAAC,GAAG,CAAA,uFAAuF,CAAA;AACnG,CAAC,CAAC,CAAA","sourcesContent":["/** @since 1.0.0-rc.1 */\n\nimport * as Effect from \"effect/Effect\"\nimport * as SqlClient from \"effect/sql/SqlClient\"\n\n/**\n * Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to\n * one run and the prune's active-run check read an index instead of the\n * whole ledger.\n *\n * A named export rather than `export default`: the CommonJS build reads a\n * default import of a sibling module as the whole exports object, so the\n * migrator received `{ default }` instead of this Effect.\n *\n * @category migrations\n * @since 1.0.0-rc.1\n */\nexport const fireRunIndex: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {\n const sql = yield* SqlClient.SqlClient\n yield* sql`CREATE INDEX IF NOT EXISTS flows_trigger_fires_run_id ON flows_trigger_fires (run_id)`\n})\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import * as Migrator from "effect/
|
|
3
|
+
import * as Migrator from "effect/sql/Migrator";
|
|
4
4
|
/**
|
|
5
5
|
* The migration record {@link run} applies, keyed by migration file name.
|
|
6
6
|
*
|
|
@@ -11,10 +11,10 @@ import * as Migrator from "effect/unstable/sql/Migrator";
|
|
|
11
11
|
* @since 1.0.0-rc.0
|
|
12
12
|
*/
|
|
13
13
|
export declare const migrations: {
|
|
14
|
-
"0001_triggers": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
15
|
-
"0002_reservation_lease": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
16
|
-
"0003_heartbeat": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
17
|
-
"0004_fire_run_index": import("effect/Effect").Effect<void, unknown, import("effect/
|
|
14
|
+
"0001_triggers": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
15
|
+
"0002_reservation_lease": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
16
|
+
"0003_heartbeat": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
17
|
+
"0004_fire_run_index": import("effect/Effect").Effect<void, unknown, import("effect/sql/SqlClient").SqlClient>;
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Applies the triggers schema migrations.
|
|
@@ -22,12 +22,12 @@ export declare const migrations: {
|
|
|
22
22
|
* @category migrations
|
|
23
23
|
* @since 0.1.0
|
|
24
24
|
*/
|
|
25
|
-
export declare const run: import("effect/Effect").Effect<readonly (readonly [id: number, name: string])[], import("effect/
|
|
25
|
+
export declare const run: import("effect/Effect").Effect<readonly (readonly [id: number, name: string])[], import("effect/sql/SqlError").SqlError | Migrator.MigrationError, import("effect/sql/SqlClient").SqlClient>;
|
|
26
26
|
/**
|
|
27
27
|
* Runs {@link run} once as a layer.
|
|
28
28
|
*
|
|
29
29
|
* @category layers
|
|
30
30
|
* @since 0.1.0
|
|
31
31
|
*/
|
|
32
|
-
export declare const layer: Layer.Layer<never, import("effect/
|
|
32
|
+
export declare const layer: Layer.Layer<never, import("effect/sql/SqlError").SqlError | Migrator.MigrationError, import("effect/sql/SqlClient").SqlClient>;
|
|
33
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAM/C;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU;;;;;CAKtB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,GAAG,8LAAoG,CAAA;AAEpH;;;;;GAKG;AACH,eAAO,MAAM,KAAK,gIAA2B,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import * as Migrator from "effect/
|
|
3
|
+
import * as Migrator from "effect/sql/Migrator";
|
|
4
4
|
import { triggers } from "./0001_triggers.js";
|
|
5
5
|
import { reservationLease } from "./0002_reservation_lease.js";
|
|
6
6
|
import { schedulerHeartbeat } from "./0003_heartbeat.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AAEnB,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEvD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,eAAe,EAAE,QAAQ;IACzB,wBAAwB,EAAE,gBAAgB;IAC1C,gBAAgB,EAAE,kBAAkB;IACpC,qBAAqB,EAAE,YAAY;CACpC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAA;AAEpH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA","sourcesContent":["/** @since 0.1.0 */\n\nimport * as Layer from \"effect/Layer\"\nimport * as Migrator from \"effect/sql/Migrator\"\nimport { triggers } from \"./0001_triggers.ts\"\nimport { reservationLease } from \"./0002_reservation_lease.ts\"\nimport { schedulerHeartbeat } from \"./0003_heartbeat.ts\"\nimport { fireRunIndex } from \"./0004_fire_run_index.ts\"\n\n/**\n * The migration record {@link run} applies, keyed by migration file name.\n *\n * Exported so a test and the release smoke can assert that every entry is the\n * migration Effect itself in both the ESM and the CommonJS build.\n *\n * @category migrations\n * @since 1.0.0-rc.0\n */\nexport const migrations = {\n \"0001_triggers\": triggers,\n \"0002_reservation_lease\": reservationLease,\n \"0003_heartbeat\": schedulerHeartbeat,\n \"0004_fire_run_index\": fireRunIndex\n}\n\n/**\n * Applies the triggers schema migrations.\n *\n * @category migrations\n * @since 0.1.0\n */\nexport const run = Migrator.make({})({ loader: Migrator.fromRecord(migrations), table: \"flows_trigger_migrations\" })\n\n/**\n * Runs {@link run} once as a layer.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = Layer.effectDiscard(run)\n"]}
|
package/docs/installation.md
CHANGED
|
@@ -22,7 +22,7 @@ The installed manifest resolves to the synchronized RC:
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
24
24
|
- Node.js 26.4.0 or later.
|
|
25
|
-
- [`effect`](https://effect.website) 4.0.
|
|
25
|
+
- [`effect`](https://effect.website) `^4.0.4`, which supplies the `Effect`,
|
|
26
26
|
`Schema`, `Clock`, and SQL client types this package's signatures use.
|
|
27
27
|
- [`@smthrs/control`](/api/control), the authoritative launch boundary. The
|
|
28
28
|
scheduler's Control-backed runner and every channel dispatch go through it.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smthrs/triggers",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.7",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"smthrs": {
|
|
7
7
|
"group": "agent"
|
|
@@ -206,20 +206,20 @@
|
|
|
206
206
|
"tag": "next"
|
|
207
207
|
},
|
|
208
208
|
"dependencies": {
|
|
209
|
-
"@smthrs/control": "1.0.0-rc.
|
|
210
|
-
"@smthrs/database": "1.0.0-rc.
|
|
209
|
+
"@smthrs/control": "1.0.0-rc.7",
|
|
210
|
+
"@smthrs/database": "1.0.0-rc.7"
|
|
211
211
|
},
|
|
212
212
|
"peerDependencies": {
|
|
213
|
-
"effect": "4.0.
|
|
213
|
+
"effect": "^4.0.4"
|
|
214
214
|
},
|
|
215
215
|
"devDependencies": {
|
|
216
216
|
"@effect/language-service": "0.87.2",
|
|
217
|
-
"@effect/vitest": "4.0.
|
|
217
|
+
"@effect/vitest": "4.0.4",
|
|
218
218
|
"@eslint/js": "9.39.5",
|
|
219
219
|
"@types/node": "26.4.1",
|
|
220
220
|
"@vitest/coverage-v8": "5.0.0",
|
|
221
221
|
"dprint": "0.57.1",
|
|
222
|
-
"effect": "4.0.
|
|
222
|
+
"effect": "4.0.4",
|
|
223
223
|
"esbuild": "0.28.2",
|
|
224
224
|
"eslint": "9.39.5",
|
|
225
225
|
"eslint-import-resolver-typescript": "4.4.5",
|
package/src/SqlTriggerStore.ts
CHANGED
|
@@ -14,7 +14,7 @@ import * as Layer from "effect/Layer"
|
|
|
14
14
|
import * as Option from "effect/Option"
|
|
15
15
|
import * as Result from "effect/Result"
|
|
16
16
|
import * as Schema from "effect/Schema"
|
|
17
|
-
import * as SqlClient from "effect/
|
|
17
|
+
import * as SqlClient from "effect/sql/SqlClient"
|
|
18
18
|
import * as ClaimDecision from "./ClaimDecision.ts"
|
|
19
19
|
import * as Migrations from "./migrations/index.ts"
|
|
20
20
|
import * as Overlap from "./Overlap.ts"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Dialect from "@smthrs/database/Dialect"
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
|
-
import * as SqlClient from "effect/
|
|
5
|
+
import * as SqlClient from "effect/sql/SqlClient"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Creates the `flows_triggers` and `flows_trigger_fires` tables.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Dialect from "@smthrs/database/Dialect"
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
|
-
import * as SqlClient from "effect/
|
|
5
|
+
import * as SqlClient from "effect/sql/SqlClient"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Adds `active_claimed_at_ms`, the lease start of a launch reservation.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Dialect from "@smthrs/database/Dialect"
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
|
-
import * as SqlClient from "effect/
|
|
5
|
+
import * as SqlClient from "effect/sql/SqlClient"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Creates `flows_scheduler_heartbeat`, one row per scheduler host holding the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @since 1.0.0-rc.1 */
|
|
2
2
|
|
|
3
3
|
import * as Effect from "effect/Effect"
|
|
4
|
-
import * as SqlClient from "effect/
|
|
4
|
+
import * as SqlClient from "effect/sql/SqlClient"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Indexes `flows_trigger_fires` by `run_id`, so a fires listing filtered to
|
package/src/migrations/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @since 0.1.0 */
|
|
2
2
|
|
|
3
3
|
import * as Layer from "effect/Layer"
|
|
4
|
-
import * as Migrator from "effect/
|
|
4
|
+
import * as Migrator from "effect/sql/Migrator"
|
|
5
5
|
import { triggers } from "./0001_triggers.ts"
|
|
6
6
|
import { reservationLease } from "./0002_reservation_lease.ts"
|
|
7
7
|
import { schedulerHeartbeat } from "./0003_heartbeat.ts"
|