@helipod/triggers 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +70 -0
  2. package/package.json +8 -8
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # @helipod/triggers
2
+
3
+ React to committed data changes server-side: `defineTriggers` runs a function of yours with batches of changes whenever documents in a watched table are inserted, updated, or deleted — implemented as a durable cursor over the database's own change log, so a missed change is impossible by construction.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ bun add @helipod/triggers
9
+ ```
10
+
11
+ ## Enable
12
+
13
+ Components are opt-in per project. Each key in `defineTriggers(opts)` is a watched table name from your `schema.ts`; its `handler` is an internal (`_`-prefixed) mutation or action path:
14
+
15
+ ```ts
16
+ // helipod.config.ts
17
+ import { defineConfig } from "@helipod/component";
18
+ import { defineTriggers } from "@helipod/triggers";
19
+
20
+ export default defineConfig({
21
+ components: [
22
+ defineTriggers({
23
+ messages: { handler: "audit:_onChange" },
24
+ users: { handler: "audit:_onUserChange", fromStart: true },
25
+ }),
26
+ ],
27
+ });
28
+ ```
29
+
30
+ Per-trigger options: `handler` (required), `batchSize` (default 64), `fromStart` (replay the table's full history instead of starting at the current tip), and `maxDeliveriesPerWindow` (circuit-breaker threshold, default 1000).
31
+
32
+ ## Usage
33
+
34
+ The handler is an ordinary internal function receiving `{ changes: LogChange[] }` — for example, a durable audit log (from `examples/chat`):
35
+
36
+ ```ts
37
+ // helipod/audit.ts
38
+ import { mutation } from "./_generated/server";
39
+ import type { LogChange } from "@helipod/component";
40
+
41
+ export const _onChange = mutation<{ changes: LogChange[] }, null>({
42
+ handler: async (ctx, { changes }) => {
43
+ for (const change of changes) {
44
+ await ctx.db.insert("auditLog", {
45
+ changeId: change.changeId,
46
+ table: change.table,
47
+ docId: change.id,
48
+ op: change.op,
49
+ });
50
+ }
51
+ return null;
52
+ },
53
+ });
54
+ ```
55
+
56
+ ## Features
57
+
58
+ - Durable delivery with no queue: a trigger is a cursor over the storage log, so changes committed while the trigger (or the whole server) was down are delivered on resume.
59
+ - At-least-once, in-order per document; every change carries a stable `changeId` (`<table>:<id>:<ts>`) for idempotent dedup across redelivery.
60
+ - Handlers can be mutations (reactive writes: counters, audit tables, chaining into workflows) or actions (external side effects: webhooks, sync to other systems).
61
+ - Batched invocations (`batchSize`), with `fromStart: true` to replay a table's entire existing history through a new trigger.
62
+ - Safety rails: a trigger pauses itself after 8 consecutive handler failures (un-pause with the `triggers:resume` mutation), and a deliveries-per-window circuit breaker stops a self-triggering handler from melting the node.
63
+ - Boot-time validation: an unknown handler path, a non-internal function, or the wrong function kind fails fast at startup, not at first delivery.
64
+ - Purely declarative — no `ctx.triggers` facade; the watched-table config above is the whole surface.
65
+
66
+ Depends on `@helipod/scheduler` as a library (it reuses its backoff utilities), but does not require the scheduler component to be composed in your config.
67
+
68
+ Part of [Helipod](https://github.com/helipod-sh/helipod) — docs at https://helipod-six.vercel.app/docs
69
+
70
+ License: FSL-1.1-Apache-2.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helipod/triggers",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -14,17 +14,17 @@
14
14
  "scripts": {
15
15
  "build": "tsup",
16
16
  "typecheck": "tsc --noEmit",
17
- "test": "vitest run"
17
+ "test": "vitest run --testTimeout=60000 --hookTimeout=60000"
18
18
  },
19
19
  "dependencies": {
20
- "@helipod/component": "0.1.0",
21
- "@helipod/executor": "0.1.0",
22
- "@helipod/scheduler": "0.1.0",
23
- "@helipod/values": "0.1.0"
20
+ "@helipod/component": "0.1.3",
21
+ "@helipod/executor": "0.1.3",
22
+ "@helipod/scheduler": "0.1.3",
23
+ "@helipod/values": "0.1.3"
24
24
  },
25
25
  "devDependencies": {
26
- "@helipod/docstore-sqlite": "0.1.0",
27
- "@helipod/runtime-embedded": "0.1.0",
26
+ "@helipod/docstore-sqlite": "0.1.3",
27
+ "@helipod/runtime-embedded": "0.1.3",
28
28
  "@types/node": "^22.10.5",
29
29
  "tsup": "^8.3.5",
30
30
  "typescript": "^5.7.2",