@cat-factory/worker 0.171.2 → 0.172.0

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.
@@ -1,17 +1,19 @@
1
- import type { NotificationWebhookRecord, NotificationWebhookRepository } from '@cat-factory/kernel';
1
+ import type { NotificationWebhookPutOutcome, NotificationWebhookRecord, NotificationWebhookRepository } from '@cat-factory/kernel';
2
2
  import type { D1Database } from '@cloudflare/workers-types';
3
3
  /**
4
- * A workspace's outbound webhook, one row per workspace (migration 0061; `run_events` added in
5
- * 0072, `alert_events` in 0080). All three JSON filter columns are decoded through the SHARED
6
- * parsers the Drizzle repo uses, so the columns can't drift between runtimes.
4
+ * A workspace's outbound webhooks, keyed by (workspace, endpoint id) (migration 0061; `run_events`
5
+ * added in 0072, `alert_events` in 0080, the named-collection key in 0085). All three JSON filter
6
+ * columns are decoded through the SHARED parsers the Drizzle repo uses, so the columns can't drift
7
+ * between runtimes.
7
8
  */
8
9
  export declare class D1NotificationWebhookRepository implements NotificationWebhookRepository {
9
10
  private readonly db;
10
11
  constructor({ db }: {
11
12
  db: D1Database;
12
13
  });
13
- get(workspaceId: string): Promise<NotificationWebhookRecord | null>;
14
- put(record: NotificationWebhookRecord): Promise<void>;
15
- delete(workspaceId: string): Promise<void>;
14
+ get(workspaceId: string, id: string): Promise<NotificationWebhookRecord | null>;
15
+ list(workspaceId: string): Promise<NotificationWebhookRecord[]>;
16
+ put(record: NotificationWebhookRecord, limit: number): Promise<NotificationWebhookPutOutcome>;
17
+ delete(workspaceId: string, id: string): Promise<void>;
16
18
  }
17
19
  //# sourceMappingURL=D1NotificationWebhookRepository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"D1NotificationWebhookRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1NotificationWebhookRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAA;AACnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAkB3D;;;;GAIG;AACH,qBAAa,+BAAgC,YAAW,6BAA6B;IACnF,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,UAAU,CAAA;KAAE,EAErC;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAgBxE;IAEK,GAAG,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B1D;IAEK,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/C;CACF"}
1
+ {"version":3,"file":"D1NotificationWebhookRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1NotificationWebhookRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,yBAAyB,EACzB,6BAA6B,EAC9B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAoB3D;;;;;GAKG;AACH,qBAAa,+BAAgC,YAAW,6BAA6B;IACnF,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,UAAU,CAAA;KAAE,EAErC;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAMpF;IAEK,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAYpE;IAEK,GAAG,CACP,MAAM,EAAE,yBAAyB,EACjC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,6BAA6B,CAAC,CAmDxC;IAEK,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3D;CACF"}
@@ -1,38 +1,55 @@
1
1
  import { parseNotificationWebhookTypes, parsePlatformAlertEvents, parseRunLifecycleEvents, } from '@cat-factory/server';
2
2
  /**
3
- * A workspace's outbound webhook, one row per workspace (migration 0061; `run_events` added in
4
- * 0072, `alert_events` in 0080). All three JSON filter columns are decoded through the SHARED
5
- * parsers the Drizzle repo uses, so the columns can't drift between runtimes.
3
+ * A workspace's outbound webhooks, keyed by (workspace, endpoint id) (migration 0061; `run_events`
4
+ * added in 0072, `alert_events` in 0080, the named-collection key in 0085). All three JSON filter
5
+ * columns are decoded through the SHARED parsers the Drizzle repo uses, so the columns can't drift
6
+ * between runtimes.
6
7
  */
7
8
  export class D1NotificationWebhookRepository {
8
9
  db;
9
10
  constructor({ db }) {
10
11
  this.db = db;
11
12
  }
12
- async get(workspaceId) {
13
+ async get(workspaceId, id) {
13
14
  const row = await this.db
14
- .prepare(`SELECT * FROM notification_webhooks WHERE workspace_id = ?`)
15
- .bind(workspaceId)
15
+ .prepare(`SELECT * FROM notification_webhooks WHERE workspace_id = ? AND id = ?`)
16
+ .bind(workspaceId, id)
16
17
  .first();
17
- if (!row)
18
- return null;
19
- return {
20
- workspaceId: row.workspace_id,
21
- url: row.url,
22
- types: parseNotificationWebhookTypes(row.types),
23
- runEvents: parseRunLifecycleEvents(row.run_events),
24
- alertEvents: parsePlatformAlertEvents(row.alert_events),
25
- enabled: row.enabled === 1,
26
- secretSealed: row.secret_sealed,
27
- updatedAt: row.updated_at,
28
- };
18
+ return row ? toRecord(row) : null;
29
19
  }
30
- async put(record) {
31
- await this.db
20
+ async list(workspaceId) {
21
+ // `COLLATE BINARY` is SQLite's default for a text column and is spelled out only to name the
22
+ // order this port promises: the Drizzle mirror has to ask Postgres for `COLLATE "C"` to match,
23
+ // because its database-locale default would sort `web-hook` after `webhook` by ignoring the
24
+ // punctuation. Byte order on both, so the two runtimes return one sequence.
25
+ const { results } = await this.db
26
+ .prepare(`SELECT * FROM notification_webhooks WHERE workspace_id = ? ORDER BY id COLLATE BINARY`)
27
+ .bind(workspaceId)
28
+ .all();
29
+ return (results ?? []).map(toRecord);
30
+ }
31
+ async put(record, limit) {
32
+ // ONE statement, so the cap and the write cannot be separated by another writer. The row
33
+ // source is a `SELECT ... WHERE` rather than `VALUES` precisely so the admission test rides
34
+ // inside the insert: SQLite serializes statements, so a concurrent enrolment either sees this
35
+ // row or is seen by it, and can never read the same free slot twice.
36
+ //
37
+ // The predicate admits an existing endpoint unconditionally (`EXISTS`) before it consults the
38
+ // count, because the count includes that row: without the first half, a workspace sitting
39
+ // exactly at the limit could no longer edit, disable or re-point what it had already
40
+ // registered, which are the only ways back under it.
41
+ //
42
+ // The `WHERE` also disambiguates the parse. SQLite cannot otherwise tell an upsert's `ON
43
+ // CONFLICT` from a join's `ON` in an `INSERT ... SELECT`, and its documented fix is exactly a
44
+ // `WHERE` clause on the SELECT, which this needs anyway.
45
+ const result = await this.db
32
46
  .prepare(`INSERT INTO notification_webhooks
33
- (workspace_id, url, types, run_events, alert_events, enabled, secret_sealed, updated_at)
34
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
35
- ON CONFLICT (workspace_id) DO UPDATE SET
47
+ (workspace_id, id, name, url, types, run_events, alert_events, enabled, secret_sealed, updated_at)
48
+ SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
49
+ WHERE EXISTS (SELECT 1 FROM notification_webhooks WHERE workspace_id = ? AND id = ?)
50
+ OR (SELECT COUNT(*) FROM notification_webhooks WHERE workspace_id = ?) < ?
51
+ ON CONFLICT (workspace_id, id) DO UPDATE SET
52
+ name = excluded.name,
36
53
  url = excluded.url,
37
54
  types = excluded.types,
38
55
  run_events = excluded.run_events,
@@ -40,14 +57,31 @@ export class D1NotificationWebhookRepository {
40
57
  enabled = excluded.enabled,
41
58
  secret_sealed = excluded.secret_sealed,
42
59
  updated_at = excluded.updated_at`)
43
- .bind(record.workspaceId, record.url, JSON.stringify(record.types), JSON.stringify(record.runEvents), JSON.stringify(record.alertEvents), record.enabled ? 1 : 0, record.secretSealed, record.updatedAt)
60
+ .bind(record.workspaceId, record.id, record.name, record.url, JSON.stringify(record.types), JSON.stringify(record.runEvents), JSON.stringify(record.alertEvents), record.enabled ? 1 : 0, record.secretSealed, record.updatedAt, record.workspaceId, record.id, record.workspaceId, limit)
44
61
  .run();
62
+ // A filtered-out row writes nothing, which is the refusal. An admitted one always reports a
63
+ // change, whether it inserted or took the conflict branch.
64
+ return (result.meta?.changes ?? 0) > 0 ? 'stored' : 'limit_reached';
45
65
  }
46
- async delete(workspaceId) {
66
+ async delete(workspaceId, id) {
47
67
  await this.db
48
- .prepare(`DELETE FROM notification_webhooks WHERE workspace_id = ?`)
49
- .bind(workspaceId)
68
+ .prepare(`DELETE FROM notification_webhooks WHERE workspace_id = ? AND id = ?`)
69
+ .bind(workspaceId, id)
50
70
  .run();
51
71
  }
52
72
  }
73
+ function toRecord(row) {
74
+ return {
75
+ workspaceId: row.workspace_id,
76
+ id: row.id,
77
+ name: row.name,
78
+ url: row.url,
79
+ types: parseNotificationWebhookTypes(row.types),
80
+ runEvents: parseRunLifecycleEvents(row.run_events),
81
+ alertEvents: parsePlatformAlertEvents(row.alert_events),
82
+ enabled: row.enabled === 1,
83
+ secretSealed: row.secret_sealed,
84
+ updatedAt: row.updated_at,
85
+ };
86
+ }
53
87
  //# sourceMappingURL=D1NotificationWebhookRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"D1NotificationWebhookRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1NotificationWebhookRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,qBAAqB,CAAA;AAa5B;;;;GAIG;AACH,MAAM,OAAO,+BAA+B;IACzB,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAsB;QACpC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAmB;QAC3B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE;aACtB,OAAO,CAAC,4DAA4D,CAAC;aACrE,IAAI,CAAC,WAAW,CAAC;aACjB,KAAK,EAA0B,CAAA;QAClC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QACrB,OAAO;YACL,WAAW,EAAE,GAAG,CAAC,YAAY;YAC7B,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,KAAK,EAAE,6BAA6B,CAAC,GAAG,CAAC,KAAK,CAAC;YAC/C,SAAS,EAAE,uBAAuB,CAAC,GAAG,CAAC,UAAU,CAAC;YAClD,WAAW,EAAE,wBAAwB,CAAC,GAAG,CAAC,YAAY,CAAC;YACvD,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,CAAC;YAC1B,YAAY,EAAE,GAAG,CAAC,aAAa;YAC/B,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAA;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAiC;QACzC,MAAM,IAAI,CAAC,EAAE;aACV,OAAO,CACN;;;;;;;;;;4CAUoC,CACrC;aACA,IAAI,CACH,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,GAAG,EACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAC5B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,EAClC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACtB,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,SAAS,CACjB;aACA,GAAG,EAAE,CAAA;IACV,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,MAAM,IAAI,CAAC,EAAE;aACV,OAAO,CAAC,0DAA0D,CAAC;aACnE,IAAI,CAAC,WAAW,CAAC;aACjB,GAAG,EAAE,CAAA;IACV,CAAC;CACF"}
1
+ {"version":3,"file":"D1NotificationWebhookRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1NotificationWebhookRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ -- Several NAMED outbound webhooks per workspace, replacing the one-row-per-workspace shape from
2
+ -- migration 0061. One endpoint per workspace made a second integration's enrolment a hostile act:
3
+ -- registering it overwrote whatever was already there, and the only symptom was that the previous
4
+ -- receiver went quiet. Each row now carries a caller-chosen `id` (the key, alongside the workspace)
5
+ -- and an operator-facing `name`.
6
+ --
7
+ -- SQLite cannot re-key a table in place, so this is the standard rebuild. Existing rows migrate to
8
+ -- the id `default`, which is exactly what the singular `/api/v1/notification-webhook` routes now
9
+ -- address: an already-registered endpoint keeps delivering, and the caller that registered it keeps
10
+ -- addressing it through the same route.
11
+
12
+ CREATE TABLE notification_webhooks_new (
13
+ workspace_id TEXT NOT NULL,
14
+ id TEXT NOT NULL,
15
+ name TEXT NOT NULL,
16
+ url TEXT NOT NULL,
17
+ types TEXT NOT NULL DEFAULT '[]',
18
+ run_events TEXT NOT NULL DEFAULT '[]',
19
+ alert_events TEXT NOT NULL DEFAULT '[]',
20
+ enabled INTEGER NOT NULL DEFAULT 1,
21
+ secret_sealed TEXT,
22
+ updated_at INTEGER NOT NULL,
23
+ PRIMARY KEY (workspace_id, id)
24
+ );
25
+
26
+ INSERT INTO notification_webhooks_new
27
+ (workspace_id, id, name, url, types, run_events, alert_events, enabled, secret_sealed, updated_at)
28
+ SELECT
29
+ workspace_id, 'default', 'Default', url, types, run_events, alert_events, enabled, secret_sealed, updated_at
30
+ FROM notification_webhooks;
31
+
32
+ DROP TABLE notification_webhooks;
33
+
34
+ ALTER TABLE notification_webhooks_new RENAME TO notification_webhooks;
35
+
36
+ -- No extra index on `workspace_id`: it is the leading column of the composite primary key, so the
37
+ -- per-workspace list every delivery reads is already served by that index.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/worker",
3
- "version": "0.171.2",
3
+ "version": "0.172.0",
4
4
  "description": "Reusable Cloudflare Worker library (Hono + D1) exposing the Agent Architecture Board core: the `createApp()` Hono factory, the default fetch/scheduled/queue handler, and the Durable Object + Workflow classes. Deployments (see deploy/backend) supply the wrangler.toml + config and re-export these.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,22 +43,22 @@
43
43
  "pino": "^10.3.1",
44
44
  "valibot": "^1.4.2",
45
45
  "workers-ai-provider": "^4.0.0",
46
- "@cat-factory/agents": "0.117.5",
47
- "@cat-factory/caching": "0.18.6",
48
- "@cat-factory/consensus": "0.14.51",
49
- "@cat-factory/contracts": "0.267.0",
50
- "@cat-factory/eks": "0.1.263",
51
- "@cat-factory/gates": "0.9.31",
52
- "@cat-factory/gitlab": "0.17.2",
53
- "@cat-factory/integrations": "0.143.1",
54
- "@cat-factory/kernel": "0.265.0",
55
- "@cat-factory/observability-langfuse": "0.10.35",
56
- "@cat-factory/observability-otel": "0.17.6",
57
- "@cat-factory/orchestration": "0.234.0",
58
- "@cat-factory/prompt-fragments": "1.0.15",
59
- "@cat-factory/provider-cloudflare": "0.7.413",
60
- "@cat-factory/server": "0.245.0",
61
- "@cat-factory/spend": "0.15.33"
46
+ "@cat-factory/agents": "0.117.6",
47
+ "@cat-factory/caching": "0.18.7",
48
+ "@cat-factory/eks": "0.1.264",
49
+ "@cat-factory/consensus": "0.14.52",
50
+ "@cat-factory/gitlab": "0.17.3",
51
+ "@cat-factory/contracts": "0.268.0",
52
+ "@cat-factory/gates": "0.9.32",
53
+ "@cat-factory/observability-langfuse": "0.10.36",
54
+ "@cat-factory/orchestration": "0.234.1",
55
+ "@cat-factory/prompt-fragments": "1.0.16",
56
+ "@cat-factory/provider-cloudflare": "0.7.414",
57
+ "@cat-factory/kernel": "0.266.0",
58
+ "@cat-factory/spend": "0.15.34",
59
+ "@cat-factory/integrations": "0.144.0",
60
+ "@cat-factory/observability-otel": "0.17.7",
61
+ "@cat-factory/server": "0.246.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@cloudflare/vitest-pool-workers": "^0.20.1",
@@ -66,7 +66,7 @@
66
66
  "typescript": "7.0.2",
67
67
  "vitest": "^4.1.10",
68
68
  "wrangler": "^4.118.0",
69
- "@cat-factory/conformance": "0.31.27"
69
+ "@cat-factory/conformance": "0.31.28"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "tsc -b tsconfig.build.json",