@shipfox/api-triggers 6.0.0 → 7.1.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,21 +1,18 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 57 files with swc (584.37ms)
3
- 2026-07-21T08:10:32.735Z [INFO] asset workflow-bundle-c6357fb5676e5edf087a.js 1.45 MiB [emitted] [immutable] (name: main)
4
- runtime modules 670 bytes 3 modules
5
- modules by path ../../../node_modules/.pnpm/ 424 KiB
6
- modules by path ../../../node_modules/.pnpm/@temporalio+common@1.18.1/node_modules/@temporal...(truncated) 155 KiB 34 modules
7
- modules by path ../../../node_modules/.pnpm/@temporalio+workflow@1.18.1/node_modules/@tempor...(truncated) 201 KiB 26 modules
8
- modules by path ../../../node_modules/.pnpm/nexus-rpc@0.0.2/node_modules/nexus-rpc/lib/ 22.3 KiB 13 modules
9
- ../../../node_modules/.pnpm/long@5.3.2/node_modules/long/index.js 43.2 KiB [built] [code generated]
10
- ../../../node_modules/.pnpm/ms@3.0.0-canary.1/node_modules/ms/dist/index.mjs 3.26 KiB [built] [code generated]
11
- modules by path ./dist/temporal/workflows/ 3.72 KiB
12
- ./dist/temporal/workflows/index-autogenerated-entrypoint.cjs 527 bytes [built] [code generated]
2
+ Successfully compiled: 58 files with swc (521.02ms)
3
+ 2026-07-22T13:11:53.445Z [INFO] asset workflow-bundle-69915b80080285c7230d.js 3.17 MiB [emitted] [immutable] (name: main)
4
+ orphan modules 33.5 KiB [orphan] 21 modules
5
+ runtime modules 1.13 KiB 5 modules
6
+ modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
7
+ modules by path ./dist/temporal/workflows/ 4.11 KiB
8
+ ./dist/temporal/workflows/index-autogenerated-entrypoint.cjs 933 bytes [built] [code generated]
13
9
  ./dist/temporal/workflows/index.js 126 bytes [built] [code generated]
14
10
  ./dist/temporal/workflows/cron-tick-cron.js 2.56 KiB [built] [code generated]
15
11
  ./dist/temporal/workflows/prune-trigger-events-cron.js 528 bytes [built] [code generated]
16
12
  optional modules 30 bytes [optional]
17
13
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
18
14
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
19
- webpack 5.107.2 compiled successfully in 4048 ms
20
- 2026-07-21T08:10:32.755Z [INFO] Workflow bundle created { size: '1.45MB' }
21
- /home/runner/work/shipfox/shipfox/libs/api/triggers/dist/temporal/workflows/index.js: 1524360 bytes
15
+ ../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
16
+ webpack 5.107.2 compiled successfully in 7776 ms
17
+ 2026-07-22T13:11:53.465Z [INFO] Workflow bundle created { size: '3.17MB' }
18
+ /home/runner/work/shipfox/shipfox/libs/api/triggers/dist/temporal/workflows/index.js: 3329015 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @shipfox/api-triggers
2
2
 
3
+ ## 7.1.0
4
+
5
+ ### Patch Changes
6
+
7
+ - ac42c96: Adds boundary-owned reporting for unexpected API runtime failures while preserving expected client and provider outcomes.
8
+ - Updated dependencies [ac42c96]
9
+ - Updated dependencies [6ce08c0]
10
+ - @shipfox/node-error-monitoring@0.2.0
11
+ - @shipfox/node-fastify@0.3.0
12
+ - @shipfox/node-module@0.5.0
13
+ - @shipfox/node-temporal@0.4.0
14
+ - @shipfox/node-opentelemetry@0.6.0
15
+ - @shipfox/api-auth-context@7.1.0
16
+ - @shipfox/api-projects@7.1.0
17
+
18
+ ## 7.0.1
19
+
20
+ ### Patch Changes
21
+
22
+ - ffc7fc9: Republishes the affected release set after recovering package publication.
23
+
24
+ ## 7.0.0
25
+
26
+ ### Patch Changes
27
+
28
+ - 10d60f6: Adds deterministic E2E listener-subscription readiness checks for workflow batching tests.
29
+
3
30
  ## 6.0.0
4
31
 
5
32
  ### Major Changes
@@ -1 +1 @@
1
- {"version":3,"file":"drain-cron-schedules.d.ts","sourceRoot":"","sources":["../../src/core/drain-cron-schedules.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEjE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAoD3B"}
1
+ {"version":3,"file":"drain-cron-schedules.d.ts","sourceRoot":"","sources":["../../src/core/drain-cron-schedules.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEjE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAyD3B"}
@@ -1,3 +1,4 @@
1
+ import { reportError } from '@shipfox/node-error-monitoring';
1
2
  import { logger } from '@shipfox/node-opentelemetry';
2
3
  import { advanceCronSchedule, claimDueCronSchedules, selectDbNow } from '#db/cron-schedules.js';
3
4
  import { db } from '#db/db.js';
@@ -62,6 +63,13 @@ import { fireCronSubscription } from './fire-cron.js';
62
63
  err: error,
63
64
  subscriptionId: schedule.subscriptionId
64
65
  }, 'cron drain: transient fire failure; schedule left due for retry');
66
+ reportError(error, {
67
+ boundary: 'triggers.maintenance',
68
+ operation: 'drain-cron-schedules',
69
+ extra: {
70
+ subscriptionId: schedule.subscriptionId
71
+ }
72
+ });
65
73
  }
66
74
  params.onScheduleProcessed?.();
67
75
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/drain-cron-schedules.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport {advanceCronSchedule, claimDueCronSchedules, selectDbNow} from '#db/cron-schedules.js';\nimport {db} from '#db/db.js';\nimport {computeNextFireAt} from './compute-next-fire-at.js';\nimport {fireCronSubscription} from './fire-cron.js';\nimport type {WorkflowsModuleClient} from './workflows-client.js';\n\nexport interface DrainDueCronSchedulesParams {\n readonly workflows: WorkflowsModuleClient;\n readonly batchSize: number;\n readonly jitterWindowSeconds: number;\n /**\n * Liveness signal invoked once per processed schedule (e.g. the Temporal activity\n * heartbeat), so a batch stuck on a slow `runWorkflow` is visible rather than\n * looking hung until the start-to-close timeout fires.\n */\n readonly onScheduleProcessed?: (() => void) | undefined;\n}\n\nexport interface CronDrainSummary {\n readonly claimed: number;\n readonly fired: number;\n readonly errored: number;\n readonly retried: number;\n}\n\n/**\n * Claims one bounded batch of due cron schedules and, per row, advances the schedule\n * and fires the workflow. There is no internal drain loop, so the per-activity ceiling\n * stays a hard `batchSize`.\n *\n * The batch is claimed and processed inside a single transaction, so its `FOR UPDATE\n * SKIP LOCKED` locks are held until commit and concurrent activities/pods claim disjoint\n * rows. Each row runs in a nested savepoint that advances `next_fire_at` before firing:\n * on a transient failure the savepoint rolls back only that row's advance, leaving it due\n * for retry, without blocking the rest of the batch. Firing before the advance commits\n * makes a crash between the two re-fire the (idempotent) occurrence rather than skip it.\n */\nexport async function drainDueCronSchedules(\n params: DrainDueCronSchedulesParams,\n): Promise<CronDrainSummary> {\n let claimed = 0;\n let fired = 0;\n let errored = 0;\n let retried = 0;\n\n await db().transaction(async (tx) => {\n // One database-clock reading shared by the due check and every advance, so the two\n // never disagree under application/database clock skew.\n const now = await selectDbNow(tx);\n const due = await claimDueCronSchedules({tx, limit: params.batchSize, now});\n claimed = due.length;\n\n for (const schedule of due) {\n const scheduledSlot = schedule.nextFireAt;\n try {\n const result = await tx.transaction(async (rowTx) => {\n const nextFireAt = computeNextFireAt({\n cronExpression: schedule.cronExpression,\n timezone: schedule.timezone,\n from: now,\n subscriptionId: schedule.subscriptionId,\n jitterWindowSeconds: params.jitterWindowSeconds,\n });\n await advanceCronSchedule({\n tx: rowTx,\n subscriptionId: schedule.subscriptionId,\n nextFireAt,\n lastFiredAt: scheduledSlot,\n });\n return await fireCronSubscription({\n workflows: params.workflows,\n subscriptionId: schedule.subscriptionId,\n scheduledSlot,\n });\n });\n if (result.outcome === 'fired') fired += 1;\n else errored += 1;\n } catch (error) {\n // Transient failure: the savepoint rolled back the advance, so the schedule\n // stays due and the next tick (or an activity retry) re-claims it.\n retried += 1;\n logger().warn(\n {err: error, subscriptionId: schedule.subscriptionId},\n 'cron drain: transient fire failure; schedule left due for retry',\n );\n }\n params.onScheduleProcessed?.();\n }\n });\n\n return {claimed, fired, errored, retried};\n}\n"],"names":["logger","advanceCronSchedule","claimDueCronSchedules","selectDbNow","db","computeNextFireAt","fireCronSubscription","drainDueCronSchedules","params","claimed","fired","errored","retried","transaction","tx","now","due","limit","batchSize","length","schedule","scheduledSlot","nextFireAt","result","rowTx","cronExpression","timezone","from","subscriptionId","jitterWindowSeconds","lastFiredAt","workflows","outcome","error","warn","err","onScheduleProcessed"],"mappings":"AAAA,SAAQA,MAAM,QAAO,8BAA8B;AACnD,SAAQC,mBAAmB,EAAEC,qBAAqB,EAAEC,WAAW,QAAO,wBAAwB;AAC9F,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,iBAAiB,QAAO,4BAA4B;AAC5D,SAAQC,oBAAoB,QAAO,iBAAiB;AAsBpD;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,sBACpBC,MAAmC;IAEnC,IAAIC,UAAU;IACd,IAAIC,QAAQ;IACZ,IAAIC,UAAU;IACd,IAAIC,UAAU;IAEd,MAAMR,KAAKS,WAAW,CAAC,OAAOC;QAC5B,mFAAmF;QACnF,wDAAwD;QACxD,MAAMC,MAAM,MAAMZ,YAAYW;QAC9B,MAAME,MAAM,MAAMd,sBAAsB;YAACY;YAAIG,OAAOT,OAAOU,SAAS;YAAEH;QAAG;QACzEN,UAAUO,IAAIG,MAAM;QAEpB,KAAK,MAAMC,YAAYJ,IAAK;YAC1B,MAAMK,gBAAgBD,SAASE,UAAU;YACzC,IAAI;gBACF,MAAMC,SAAS,MAAMT,GAAGD,WAAW,CAAC,OAAOW;oBACzC,MAAMF,aAAajB,kBAAkB;wBACnCoB,gBAAgBL,SAASK,cAAc;wBACvCC,UAAUN,SAASM,QAAQ;wBAC3BC,MAAMZ;wBACNa,gBAAgBR,SAASQ,cAAc;wBACvCC,qBAAqBrB,OAAOqB,mBAAmB;oBACjD;oBACA,MAAM5B,oBAAoB;wBACxBa,IAAIU;wBACJI,gBAAgBR,SAASQ,cAAc;wBACvCN;wBACAQ,aAAaT;oBACf;oBACA,OAAO,MAAMf,qBAAqB;wBAChCyB,WAAWvB,OAAOuB,SAAS;wBAC3BH,gBAAgBR,SAASQ,cAAc;wBACvCP;oBACF;gBACF;gBACA,IAAIE,OAAOS,OAAO,KAAK,SAAStB,SAAS;qBACpCC,WAAW;YAClB,EAAE,OAAOsB,OAAO;gBACd,4EAA4E;gBAC5E,mEAAmE;gBACnErB,WAAW;gBACXZ,SAASkC,IAAI,CACX;oBAACC,KAAKF;oBAAOL,gBAAgBR,SAASQ,cAAc;gBAAA,GACpD;YAEJ;YACApB,OAAO4B,mBAAmB;QAC5B;IACF;IAEA,OAAO;QAAC3B;QAASC;QAAOC;QAASC;IAAO;AAC1C"}
1
+ {"version":3,"sources":["../../src/core/drain-cron-schedules.ts"],"sourcesContent":["import {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {advanceCronSchedule, claimDueCronSchedules, selectDbNow} from '#db/cron-schedules.js';\nimport {db} from '#db/db.js';\nimport {computeNextFireAt} from './compute-next-fire-at.js';\nimport {fireCronSubscription} from './fire-cron.js';\nimport type {WorkflowsModuleClient} from './workflows-client.js';\n\nexport interface DrainDueCronSchedulesParams {\n readonly workflows: WorkflowsModuleClient;\n readonly batchSize: number;\n readonly jitterWindowSeconds: number;\n /**\n * Liveness signal invoked once per processed schedule (e.g. the Temporal activity\n * heartbeat), so a batch stuck on a slow `runWorkflow` is visible rather than\n * looking hung until the start-to-close timeout fires.\n */\n readonly onScheduleProcessed?: (() => void) | undefined;\n}\n\nexport interface CronDrainSummary {\n readonly claimed: number;\n readonly fired: number;\n readonly errored: number;\n readonly retried: number;\n}\n\n/**\n * Claims one bounded batch of due cron schedules and, per row, advances the schedule\n * and fires the workflow. There is no internal drain loop, so the per-activity ceiling\n * stays a hard `batchSize`.\n *\n * The batch is claimed and processed inside a single transaction, so its `FOR UPDATE\n * SKIP LOCKED` locks are held until commit and concurrent activities/pods claim disjoint\n * rows. Each row runs in a nested savepoint that advances `next_fire_at` before firing:\n * on a transient failure the savepoint rolls back only that row's advance, leaving it due\n * for retry, without blocking the rest of the batch. Firing before the advance commits\n * makes a crash between the two re-fire the (idempotent) occurrence rather than skip it.\n */\nexport async function drainDueCronSchedules(\n params: DrainDueCronSchedulesParams,\n): Promise<CronDrainSummary> {\n let claimed = 0;\n let fired = 0;\n let errored = 0;\n let retried = 0;\n\n await db().transaction(async (tx) => {\n // One database-clock reading shared by the due check and every advance, so the two\n // never disagree under application/database clock skew.\n const now = await selectDbNow(tx);\n const due = await claimDueCronSchedules({tx, limit: params.batchSize, now});\n claimed = due.length;\n\n for (const schedule of due) {\n const scheduledSlot = schedule.nextFireAt;\n try {\n const result = await tx.transaction(async (rowTx) => {\n const nextFireAt = computeNextFireAt({\n cronExpression: schedule.cronExpression,\n timezone: schedule.timezone,\n from: now,\n subscriptionId: schedule.subscriptionId,\n jitterWindowSeconds: params.jitterWindowSeconds,\n });\n await advanceCronSchedule({\n tx: rowTx,\n subscriptionId: schedule.subscriptionId,\n nextFireAt,\n lastFiredAt: scheduledSlot,\n });\n return await fireCronSubscription({\n workflows: params.workflows,\n subscriptionId: schedule.subscriptionId,\n scheduledSlot,\n });\n });\n if (result.outcome === 'fired') fired += 1;\n else errored += 1;\n } catch (error) {\n // Transient failure: the savepoint rolled back the advance, so the schedule\n // stays due and the next tick (or an activity retry) re-claims it.\n retried += 1;\n logger().warn(\n {err: error, subscriptionId: schedule.subscriptionId},\n 'cron drain: transient fire failure; schedule left due for retry',\n );\n reportError(error, {\n boundary: 'triggers.maintenance',\n operation: 'drain-cron-schedules',\n extra: {subscriptionId: schedule.subscriptionId},\n });\n }\n params.onScheduleProcessed?.();\n }\n });\n\n return {claimed, fired, errored, retried};\n}\n"],"names":["reportError","logger","advanceCronSchedule","claimDueCronSchedules","selectDbNow","db","computeNextFireAt","fireCronSubscription","drainDueCronSchedules","params","claimed","fired","errored","retried","transaction","tx","now","due","limit","batchSize","length","schedule","scheduledSlot","nextFireAt","result","rowTx","cronExpression","timezone","from","subscriptionId","jitterWindowSeconds","lastFiredAt","workflows","outcome","error","warn","err","boundary","operation","extra","onScheduleProcessed"],"mappings":"AAAA,SAAQA,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,MAAM,QAAO,8BAA8B;AACnD,SAAQC,mBAAmB,EAAEC,qBAAqB,EAAEC,WAAW,QAAO,wBAAwB;AAC9F,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,iBAAiB,QAAO,4BAA4B;AAC5D,SAAQC,oBAAoB,QAAO,iBAAiB;AAsBpD;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,sBACpBC,MAAmC;IAEnC,IAAIC,UAAU;IACd,IAAIC,QAAQ;IACZ,IAAIC,UAAU;IACd,IAAIC,UAAU;IAEd,MAAMR,KAAKS,WAAW,CAAC,OAAOC;QAC5B,mFAAmF;QACnF,wDAAwD;QACxD,MAAMC,MAAM,MAAMZ,YAAYW;QAC9B,MAAME,MAAM,MAAMd,sBAAsB;YAACY;YAAIG,OAAOT,OAAOU,SAAS;YAAEH;QAAG;QACzEN,UAAUO,IAAIG,MAAM;QAEpB,KAAK,MAAMC,YAAYJ,IAAK;YAC1B,MAAMK,gBAAgBD,SAASE,UAAU;YACzC,IAAI;gBACF,MAAMC,SAAS,MAAMT,GAAGD,WAAW,CAAC,OAAOW;oBACzC,MAAMF,aAAajB,kBAAkB;wBACnCoB,gBAAgBL,SAASK,cAAc;wBACvCC,UAAUN,SAASM,QAAQ;wBAC3BC,MAAMZ;wBACNa,gBAAgBR,SAASQ,cAAc;wBACvCC,qBAAqBrB,OAAOqB,mBAAmB;oBACjD;oBACA,MAAM5B,oBAAoB;wBACxBa,IAAIU;wBACJI,gBAAgBR,SAASQ,cAAc;wBACvCN;wBACAQ,aAAaT;oBACf;oBACA,OAAO,MAAMf,qBAAqB;wBAChCyB,WAAWvB,OAAOuB,SAAS;wBAC3BH,gBAAgBR,SAASQ,cAAc;wBACvCP;oBACF;gBACF;gBACA,IAAIE,OAAOS,OAAO,KAAK,SAAStB,SAAS;qBACpCC,WAAW;YAClB,EAAE,OAAOsB,OAAO;gBACd,4EAA4E;gBAC5E,mEAAmE;gBACnErB,WAAW;gBACXZ,SAASkC,IAAI,CACX;oBAACC,KAAKF;oBAAOL,gBAAgBR,SAASQ,cAAc;gBAAA,GACpD;gBAEF7B,YAAYkC,OAAO;oBACjBG,UAAU;oBACVC,WAAW;oBACXC,OAAO;wBAACV,gBAAgBR,SAASQ,cAAc;oBAAA;gBACjD;YACF;YACApB,OAAO+B,mBAAmB;QAC5B;IACF;IAEA,OAAO;QAAC9B;QAASC;QAAOC;QAASC;IAAO;AAC1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"record-trigger-history.d.ts","sourceRoot":"","sources":["../../src/core/record-trigger-history.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,6CAA6C,CAAC;AACzF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAmBxE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQ/C;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,YAAY,EAAE,mBAAmB,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,aAAa,CAAC,YAAY,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,eAAe,CAAC,YAAY,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,iBAAiB,CAAC,YAAY,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,qBAAqB,CAAC,YAAY,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,uBAAuB,CAAC,YAAY,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,UAAU,EAAE,IAAI,CAAC;CAClB;AAID,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,sBAAsB,CAAC,CA2DjC"}
1
+ {"version":3,"file":"record-trigger-history.d.ts","sourceRoot":"","sources":["../../src/core/record-trigger-history.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,6CAA6C,CAAC;AACzF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAmBxE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQ/C;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,YAAY,EAAE,mBAAmB,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,aAAa,CAAC,YAAY,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,eAAe,CAAC,YAAY,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,iBAAiB,CAAC,YAAY,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,qBAAqB,CAAC,YAAY,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,uBAAuB,CAAC,YAAY,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,UAAU,EAAE,IAAI,CAAC;CAClB;AAID,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,sBAAsB,CAAC,CA2DjC"}
@@ -1,3 +1,4 @@
1
+ import { reportError } from '@shipfox/node-error-monitoring';
1
2
  import { logger } from '@shipfox/node-opentelemetry';
2
3
  import { insertReceivedEvent, markReceivedEventDiscarded, markReceivedEventErrored, markReceivedEventFailed, markReceivedEventRouted, upsertDispatchErrorDecision, upsertFilterErrorDecision, upsertListenerDispatchErrorDecision, upsertListenerFilterErrorDecision, upsertListenerTriggeredDecision, upsertTriggeredDecision } from '#db/event-history.js';
3
4
  const MAX_REASON_LENGTH = 2000;
@@ -68,6 +69,14 @@ async function safe(eventRef, label, fn, subscriptionId) {
68
69
  subscriptionId
69
70
  } : {}
70
71
  }, 'trigger history write failed; ignored (best-effort)');
72
+ reportError(error, {
73
+ boundary: 'triggers.history',
74
+ operation: label,
75
+ extra: {
76
+ eventRef,
77
+ subscriptionId
78
+ }
79
+ });
71
80
  return undefined;
72
81
  }
73
82
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/record-trigger-history.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport type {JobListenerSubscription} from '#core/entities/job-listener-subscription.js';\nimport type {TriggerEventOrigin} from '#core/entities/received-event.js';\nimport type {TriggerSubscription} from '#core/entities/subscription.js';\nimport {\n insertReceivedEvent,\n markReceivedEventDiscarded,\n markReceivedEventErrored,\n markReceivedEventFailed,\n markReceivedEventRouted,\n upsertDispatchErrorDecision,\n upsertFilterErrorDecision,\n upsertListenerDispatchErrorDecision,\n upsertListenerFilterErrorDecision,\n upsertListenerTriggeredDecision,\n upsertTriggeredDecision,\n} from '#db/event-history.js';\n\nconst MAX_REASON_LENGTH = 2000;\n\n// A bounded, deterministic reason string safe to persist: error messages can be\n// long or carry untrusted data, so cap the length and never serialize the object.\nexport function toReason(error: unknown): string {\n let message: string;\n try {\n message = error instanceof Error ? error.message : String(error);\n } catch {\n message = '[unprintable thrown value]';\n }\n return message.slice(0, MAX_REASON_LENGTH);\n}\n\nexport interface TriggerRun {\n id: string;\n name: string;\n}\n\nexport interface TriggerHistoryRecorder {\n triggered(subscription: TriggerSubscription, run: TriggerRun): Promise<void>;\n filterErrored(subscription: TriggerSubscription, reason: string): Promise<void>;\n dispatchErrored(subscription: TriggerSubscription, reason: string): Promise<void>;\n listenerTriggered(subscription: JobListenerSubscription): Promise<void>;\n listenerFilterErrored(subscription: JobListenerSubscription, reason: string): Promise<void>;\n listenerDispatchErrored(subscription: JobListenerSubscription, reason: string): Promise<void>;\n discarded(): Promise<void>;\n routed(matchedCount: number): Promise<void>;\n failed(matchedCount: number): Promise<void>;\n allErrored(matchedCount: number): Promise<void>;\n}\n\nexport interface BeginTriggerHistoryParams {\n eventRef: string;\n origin: TriggerEventOrigin;\n workspaceId: string;\n provider: string | null;\n source: string;\n event: string;\n deliveryId: string | null;\n connectionId: string | null;\n connectionName: string | null;\n payload: Record<string, unknown> | null;\n receivedAt: Date;\n}\n\n// History writes are best-effort and log stable ids only, never payloads or tokens.\n// If the parent insert fails there is no row to attach to, so later calls no-op.\nexport async function beginTriggerHistory(\n params: BeginTriggerHistoryParams,\n): Promise<TriggerHistoryRecorder> {\n const receivedEventId = await safe(params.eventRef, 'insert-received-event', () =>\n insertReceivedEvent(params),\n );\n\n const record = async (\n label: string,\n write: (receivedEventId: string) => Promise<unknown>,\n subscriptionId?: string,\n ): Promise<void> => {\n if (receivedEventId === undefined) return;\n await safe(params.eventRef, label, () => write(receivedEventId), subscriptionId);\n };\n\n return {\n triggered: (subscription, run) =>\n record(\n 'triggered-decision',\n (id) => upsertTriggeredDecision({receivedEventId: id, subscription, run}),\n subscription.id,\n ),\n filterErrored: (subscription, reason) =>\n record(\n 'filter-error-decision',\n (id) => upsertFilterErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n dispatchErrored: (subscription, reason) =>\n record(\n 'dispatch-error-decision',\n (id) => upsertDispatchErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n listenerTriggered: (subscription) =>\n record(\n 'listener-triggered-decision',\n (id) => upsertListenerTriggeredDecision({receivedEventId: id, subscription}),\n subscription.id,\n ),\n listenerFilterErrored: (subscription, reason) =>\n record(\n 'listener-filter-error-decision',\n (id) => upsertListenerFilterErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n listenerDispatchErrored: (subscription, reason) =>\n record(\n 'listener-dispatch-error-decision',\n (id) => upsertListenerDispatchErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n discarded: () => record('discard-event', (id) => markReceivedEventDiscarded(id)),\n routed: (matchedCount) =>\n record('route-event', (id) => markReceivedEventRouted(id, matchedCount)),\n failed: (matchedCount) =>\n record('fail-event', (id) => markReceivedEventFailed(id, matchedCount)),\n allErrored: (matchedCount) =>\n record('all-errored-event', (id) => markReceivedEventErrored(id, matchedCount)),\n };\n}\n\nasync function safe<T>(\n eventRef: string,\n label: string,\n fn: () => Promise<T>,\n subscriptionId?: string,\n): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n logger().warn(\n {err: error, label, eventRef, ...(subscriptionId ? {subscriptionId} : {})},\n 'trigger history write failed; ignored (best-effort)',\n );\n return undefined;\n }\n}\n"],"names":["logger","insertReceivedEvent","markReceivedEventDiscarded","markReceivedEventErrored","markReceivedEventFailed","markReceivedEventRouted","upsertDispatchErrorDecision","upsertFilterErrorDecision","upsertListenerDispatchErrorDecision","upsertListenerFilterErrorDecision","upsertListenerTriggeredDecision","upsertTriggeredDecision","MAX_REASON_LENGTH","toReason","error","message","Error","String","slice","beginTriggerHistory","params","receivedEventId","safe","eventRef","record","label","write","subscriptionId","undefined","triggered","subscription","run","id","filterErrored","reason","dispatchErrored","listenerTriggered","listenerFilterErrored","listenerDispatchErrored","discarded","routed","matchedCount","failed","allErrored","fn","warn","err"],"mappings":"AAAA,SAAQA,MAAM,QAAO,8BAA8B;AAInD,SACEC,mBAAmB,EACnBC,0BAA0B,EAC1BC,wBAAwB,EACxBC,uBAAuB,EACvBC,uBAAuB,EACvBC,2BAA2B,EAC3BC,yBAAyB,EACzBC,mCAAmC,EACnCC,iCAAiC,EACjCC,+BAA+B,EAC/BC,uBAAuB,QAClB,uBAAuB;AAE9B,MAAMC,oBAAoB;AAE1B,gFAAgF;AAChF,kFAAkF;AAClF,OAAO,SAASC,SAASC,KAAc;IACrC,IAAIC;IACJ,IAAI;QACFA,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;IAC5D,EAAE,OAAM;QACNC,UAAU;IACZ;IACA,OAAOA,QAAQG,KAAK,CAAC,GAAGN;AAC1B;AAkCA,oFAAoF;AACpF,iFAAiF;AACjF,OAAO,eAAeO,oBACpBC,MAAiC;IAEjC,MAAMC,kBAAkB,MAAMC,KAAKF,OAAOG,QAAQ,EAAE,yBAAyB,IAC3EtB,oBAAoBmB;IAGtB,MAAMI,SAAS,OACbC,OACAC,OACAC;QAEA,IAAIN,oBAAoBO,WAAW;QACnC,MAAMN,KAAKF,OAAOG,QAAQ,EAAEE,OAAO,IAAMC,MAAML,kBAAkBM;IACnE;IAEA,OAAO;QACLE,WAAW,CAACC,cAAcC,MACxBP,OACE,sBACA,CAACQ,KAAOrB,wBAAwB;oBAACU,iBAAiBW;oBAAIF;oBAAcC;gBAAG,IACvED,aAAaE,EAAE;QAEnBC,eAAe,CAACH,cAAcI,SAC5BV,OACE,yBACA,CAACQ,KAAOzB,0BAA0B;oBAACc,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IAC5EJ,aAAaE,EAAE;QAEnBG,iBAAiB,CAACL,cAAcI,SAC9BV,OACE,2BACA,CAACQ,KAAO1B,4BAA4B;oBAACe,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IAC9EJ,aAAaE,EAAE;QAEnBI,mBAAmB,CAACN,eAClBN,OACE,+BACA,CAACQ,KAAOtB,gCAAgC;oBAACW,iBAAiBW;oBAAIF;gBAAY,IAC1EA,aAAaE,EAAE;QAEnBK,uBAAuB,CAACP,cAAcI,SACpCV,OACE,kCACA,CAACQ,KAAOvB,kCAAkC;oBAACY,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IACpFJ,aAAaE,EAAE;QAEnBM,yBAAyB,CAACR,cAAcI,SACtCV,OACE,oCACA,CAACQ,KAAOxB,oCAAoC;oBAACa,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IACtFJ,aAAaE,EAAE;QAEnBO,WAAW,IAAMf,OAAO,iBAAiB,CAACQ,KAAO9B,2BAA2B8B;QAC5EQ,QAAQ,CAACC,eACPjB,OAAO,eAAe,CAACQ,KAAO3B,wBAAwB2B,IAAIS;QAC5DC,QAAQ,CAACD,eACPjB,OAAO,cAAc,CAACQ,KAAO5B,wBAAwB4B,IAAIS;QAC3DE,YAAY,CAACF,eACXjB,OAAO,qBAAqB,CAACQ,KAAO7B,yBAAyB6B,IAAIS;IACrE;AACF;AAEA,eAAenB,KACbC,QAAgB,EAChBE,KAAa,EACbmB,EAAoB,EACpBjB,cAAuB;IAEvB,IAAI;QACF,OAAO,MAAMiB;IACf,EAAE,OAAO9B,OAAO;QACdd,SAAS6C,IAAI,CACX;YAACC,KAAKhC;YAAOW;YAAOF;YAAU,GAAII,iBAAiB;gBAACA;YAAc,IAAI,CAAC,CAAC;QAAC,GACzE;QAEF,OAAOC;IACT;AACF"}
1
+ {"version":3,"sources":["../../src/core/record-trigger-history.ts"],"sourcesContent":["import {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {JobListenerSubscription} from '#core/entities/job-listener-subscription.js';\nimport type {TriggerEventOrigin} from '#core/entities/received-event.js';\nimport type {TriggerSubscription} from '#core/entities/subscription.js';\nimport {\n insertReceivedEvent,\n markReceivedEventDiscarded,\n markReceivedEventErrored,\n markReceivedEventFailed,\n markReceivedEventRouted,\n upsertDispatchErrorDecision,\n upsertFilterErrorDecision,\n upsertListenerDispatchErrorDecision,\n upsertListenerFilterErrorDecision,\n upsertListenerTriggeredDecision,\n upsertTriggeredDecision,\n} from '#db/event-history.js';\n\nconst MAX_REASON_LENGTH = 2000;\n\n// A bounded, deterministic reason string safe to persist: error messages can be\n// long or carry untrusted data, so cap the length and never serialize the object.\nexport function toReason(error: unknown): string {\n let message: string;\n try {\n message = error instanceof Error ? error.message : String(error);\n } catch {\n message = '[unprintable thrown value]';\n }\n return message.slice(0, MAX_REASON_LENGTH);\n}\n\nexport interface TriggerRun {\n id: string;\n name: string;\n}\n\nexport interface TriggerHistoryRecorder {\n triggered(subscription: TriggerSubscription, run: TriggerRun): Promise<void>;\n filterErrored(subscription: TriggerSubscription, reason: string): Promise<void>;\n dispatchErrored(subscription: TriggerSubscription, reason: string): Promise<void>;\n listenerTriggered(subscription: JobListenerSubscription): Promise<void>;\n listenerFilterErrored(subscription: JobListenerSubscription, reason: string): Promise<void>;\n listenerDispatchErrored(subscription: JobListenerSubscription, reason: string): Promise<void>;\n discarded(): Promise<void>;\n routed(matchedCount: number): Promise<void>;\n failed(matchedCount: number): Promise<void>;\n allErrored(matchedCount: number): Promise<void>;\n}\n\nexport interface BeginTriggerHistoryParams {\n eventRef: string;\n origin: TriggerEventOrigin;\n workspaceId: string;\n provider: string | null;\n source: string;\n event: string;\n deliveryId: string | null;\n connectionId: string | null;\n connectionName: string | null;\n payload: Record<string, unknown> | null;\n receivedAt: Date;\n}\n\n// History writes are best-effort and log stable ids only, never payloads or tokens.\n// If the parent insert fails there is no row to attach to, so later calls no-op.\nexport async function beginTriggerHistory(\n params: BeginTriggerHistoryParams,\n): Promise<TriggerHistoryRecorder> {\n const receivedEventId = await safe(params.eventRef, 'insert-received-event', () =>\n insertReceivedEvent(params),\n );\n\n const record = async (\n label: string,\n write: (receivedEventId: string) => Promise<unknown>,\n subscriptionId?: string,\n ): Promise<void> => {\n if (receivedEventId === undefined) return;\n await safe(params.eventRef, label, () => write(receivedEventId), subscriptionId);\n };\n\n return {\n triggered: (subscription, run) =>\n record(\n 'triggered-decision',\n (id) => upsertTriggeredDecision({receivedEventId: id, subscription, run}),\n subscription.id,\n ),\n filterErrored: (subscription, reason) =>\n record(\n 'filter-error-decision',\n (id) => upsertFilterErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n dispatchErrored: (subscription, reason) =>\n record(\n 'dispatch-error-decision',\n (id) => upsertDispatchErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n listenerTriggered: (subscription) =>\n record(\n 'listener-triggered-decision',\n (id) => upsertListenerTriggeredDecision({receivedEventId: id, subscription}),\n subscription.id,\n ),\n listenerFilterErrored: (subscription, reason) =>\n record(\n 'listener-filter-error-decision',\n (id) => upsertListenerFilterErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n listenerDispatchErrored: (subscription, reason) =>\n record(\n 'listener-dispatch-error-decision',\n (id) => upsertListenerDispatchErrorDecision({receivedEventId: id, subscription, reason}),\n subscription.id,\n ),\n discarded: () => record('discard-event', (id) => markReceivedEventDiscarded(id)),\n routed: (matchedCount) =>\n record('route-event', (id) => markReceivedEventRouted(id, matchedCount)),\n failed: (matchedCount) =>\n record('fail-event', (id) => markReceivedEventFailed(id, matchedCount)),\n allErrored: (matchedCount) =>\n record('all-errored-event', (id) => markReceivedEventErrored(id, matchedCount)),\n };\n}\n\nasync function safe<T>(\n eventRef: string,\n label: string,\n fn: () => Promise<T>,\n subscriptionId?: string,\n): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n logger().warn(\n {err: error, label, eventRef, ...(subscriptionId ? {subscriptionId} : {})},\n 'trigger history write failed; ignored (best-effort)',\n );\n reportError(error, {\n boundary: 'triggers.history',\n operation: label,\n extra: {eventRef, subscriptionId},\n });\n return undefined;\n }\n}\n"],"names":["reportError","logger","insertReceivedEvent","markReceivedEventDiscarded","markReceivedEventErrored","markReceivedEventFailed","markReceivedEventRouted","upsertDispatchErrorDecision","upsertFilterErrorDecision","upsertListenerDispatchErrorDecision","upsertListenerFilterErrorDecision","upsertListenerTriggeredDecision","upsertTriggeredDecision","MAX_REASON_LENGTH","toReason","error","message","Error","String","slice","beginTriggerHistory","params","receivedEventId","safe","eventRef","record","label","write","subscriptionId","undefined","triggered","subscription","run","id","filterErrored","reason","dispatchErrored","listenerTriggered","listenerFilterErrored","listenerDispatchErrored","discarded","routed","matchedCount","failed","allErrored","fn","warn","err","boundary","operation","extra"],"mappings":"AAAA,SAAQA,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,MAAM,QAAO,8BAA8B;AAInD,SACEC,mBAAmB,EACnBC,0BAA0B,EAC1BC,wBAAwB,EACxBC,uBAAuB,EACvBC,uBAAuB,EACvBC,2BAA2B,EAC3BC,yBAAyB,EACzBC,mCAAmC,EACnCC,iCAAiC,EACjCC,+BAA+B,EAC/BC,uBAAuB,QAClB,uBAAuB;AAE9B,MAAMC,oBAAoB;AAE1B,gFAAgF;AAChF,kFAAkF;AAClF,OAAO,SAASC,SAASC,KAAc;IACrC,IAAIC;IACJ,IAAI;QACFA,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;IAC5D,EAAE,OAAM;QACNC,UAAU;IACZ;IACA,OAAOA,QAAQG,KAAK,CAAC,GAAGN;AAC1B;AAkCA,oFAAoF;AACpF,iFAAiF;AACjF,OAAO,eAAeO,oBACpBC,MAAiC;IAEjC,MAAMC,kBAAkB,MAAMC,KAAKF,OAAOG,QAAQ,EAAE,yBAAyB,IAC3EtB,oBAAoBmB;IAGtB,MAAMI,SAAS,OACbC,OACAC,OACAC;QAEA,IAAIN,oBAAoBO,WAAW;QACnC,MAAMN,KAAKF,OAAOG,QAAQ,EAAEE,OAAO,IAAMC,MAAML,kBAAkBM;IACnE;IAEA,OAAO;QACLE,WAAW,CAACC,cAAcC,MACxBP,OACE,sBACA,CAACQ,KAAOrB,wBAAwB;oBAACU,iBAAiBW;oBAAIF;oBAAcC;gBAAG,IACvED,aAAaE,EAAE;QAEnBC,eAAe,CAACH,cAAcI,SAC5BV,OACE,yBACA,CAACQ,KAAOzB,0BAA0B;oBAACc,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IAC5EJ,aAAaE,EAAE;QAEnBG,iBAAiB,CAACL,cAAcI,SAC9BV,OACE,2BACA,CAACQ,KAAO1B,4BAA4B;oBAACe,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IAC9EJ,aAAaE,EAAE;QAEnBI,mBAAmB,CAACN,eAClBN,OACE,+BACA,CAACQ,KAAOtB,gCAAgC;oBAACW,iBAAiBW;oBAAIF;gBAAY,IAC1EA,aAAaE,EAAE;QAEnBK,uBAAuB,CAACP,cAAcI,SACpCV,OACE,kCACA,CAACQ,KAAOvB,kCAAkC;oBAACY,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IACpFJ,aAAaE,EAAE;QAEnBM,yBAAyB,CAACR,cAAcI,SACtCV,OACE,oCACA,CAACQ,KAAOxB,oCAAoC;oBAACa,iBAAiBW;oBAAIF;oBAAcI;gBAAM,IACtFJ,aAAaE,EAAE;QAEnBO,WAAW,IAAMf,OAAO,iBAAiB,CAACQ,KAAO9B,2BAA2B8B;QAC5EQ,QAAQ,CAACC,eACPjB,OAAO,eAAe,CAACQ,KAAO3B,wBAAwB2B,IAAIS;QAC5DC,QAAQ,CAACD,eACPjB,OAAO,cAAc,CAACQ,KAAO5B,wBAAwB4B,IAAIS;QAC3DE,YAAY,CAACF,eACXjB,OAAO,qBAAqB,CAACQ,KAAO7B,yBAAyB6B,IAAIS;IACrE;AACF;AAEA,eAAenB,KACbC,QAAgB,EAChBE,KAAa,EACbmB,EAAoB,EACpBjB,cAAuB;IAEvB,IAAI;QACF,OAAO,MAAMiB;IACf,EAAE,OAAO9B,OAAO;QACdd,SAAS6C,IAAI,CACX;YAACC,KAAKhC;YAAOW;YAAOF;YAAU,GAAII,iBAAiB;gBAACA;YAAc,IAAI,CAAC,CAAC;QAAC,GACzE;QAEF5B,YAAYe,OAAO;YACjBiC,UAAU;YACVC,WAAWvB;YACXwB,OAAO;gBAAC1B;gBAAUI;YAAc;QAClC;QACA,OAAOC;IACT;AACF"}
@@ -21,4 +21,5 @@ export interface FindMatchingJobListenerSubscriptionsParams {
21
21
  event: string;
22
22
  }
23
23
  export declare function findMatchingJobListenerSubscriptions(params: FindMatchingJobListenerSubscriptionsParams): Promise<JobListenerSubscription[]>;
24
+ export declare function hasJobListenerSubscriptions(jobId: string): Promise<boolean>;
24
25
  //# sourceMappingURL=job-listener-subscriptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"job-listener-subscriptions.d.ts","sourceRoot":"","sources":["../../src/db/job-listener-subscriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EACxB,MAAM,6CAA6C,CAAC;AASrD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC;IACtC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,IAAI,CAAC,CA4Cf;AA6BD,wBAAsB,oCAAoC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzF;AAED,MAAM,WAAW,0CAA0C;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,oCAAoC,CACxD,MAAM,EAAE,0CAA0C,GACjD,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAYpC"}
1
+ {"version":3,"file":"job-listener-subscriptions.d.ts","sourceRoot":"","sources":["../../src/db/job-listener-subscriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EACxB,MAAM,6CAA6C,CAAC;AASrD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC;IACtC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,IAAI,CAAC,CA4Cf;AA6BD,wBAAsB,oCAAoC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzF;AAED,MAAM,WAAW,0CAA0C;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,oCAAoC,CACxD,MAAM,EAAE,0CAA0C,GACjD,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAYpC;AAED,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOjF"}
@@ -65,5 +65,11 @@ export async function findMatchingJobListenerSubscriptions(params) {
65
65
  const rows = await db().select().from(jobListenerSubscriptions).where(and(eq(jobListenerSubscriptions.workspaceId, params.workspaceId), eq(jobListenerSubscriptions.source, params.source), eq(jobListenerSubscriptions.event, params.event)));
66
66
  return rows.map(toJobListenerSubscription);
67
67
  }
68
+ export async function hasJobListenerSubscriptions(jobId) {
69
+ const [subscription] = await db().select({
70
+ id: jobListenerSubscriptions.id
71
+ }).from(jobListenerSubscriptions).where(eq(jobListenerSubscriptions.jobId, jobId)).limit(1);
72
+ return subscription !== undefined;
73
+ }
68
74
 
69
75
  //# sourceMappingURL=job-listener-subscriptions.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/job-listener-subscriptions.ts"],"sourcesContent":["import {and, eq, notInArray} from 'drizzle-orm';\nimport type {\n JobListenerMatcherKind,\n JobListenerSubscription,\n} from '#core/entities/job-listener-subscription.js';\nimport {db} from './db.js';\nimport {\n jobListenerSubscriptions,\n toJobListenerSubscription,\n} from './schema/job-listener-subscriptions.js';\n\ntype Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];\n\nexport interface ListenerMatcher {\n source: string;\n event: string;\n inputs?: Readonly<Record<string, unknown>> | undefined;\n filter?: string | undefined;\n filter_snapshot?: Readonly<Record<string, unknown>> | undefined;\n}\n\nexport interface ProjectJobListenerSubscriptionsParams {\n workspaceId: string;\n workflowRunId: string;\n jobId: string;\n on: readonly ListenerMatcher[] | null;\n until: readonly ListenerMatcher[] | null;\n}\n\nexport async function projectJobListenerSubscriptions(\n params: ProjectJobListenerSubscriptionsParams,\n): Promise<void> {\n await db().transaction(async (tx) => {\n await pruneStaleMatchers(tx, params.jobId, 'on', params.on ?? []);\n await pruneStaleMatchers(tx, params.jobId, 'until', params.until ?? []);\n\n for (const [kind, matchers] of [\n ['on', params.on ?? []],\n ['until', params.until ?? []],\n ] as const) {\n for (const [matcherOrdinal, matcher] of matchers.entries()) {\n const config: Record<string, unknown> = {};\n if (matcher.inputs !== undefined) config.inputs = matcher.inputs;\n if (matcher.filter !== undefined) config.filter = matcher.filter;\n if (matcher.filter_snapshot !== undefined) config.filter_snapshot = matcher.filter_snapshot;\n\n await tx\n .insert(jobListenerSubscriptions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n jobId: params.jobId,\n kind,\n matcherOrdinal,\n source: matcher.source,\n event: matcher.event,\n config,\n })\n .onConflictDoUpdate({\n target: [\n jobListenerSubscriptions.jobId,\n jobListenerSubscriptions.kind,\n jobListenerSubscriptions.matcherOrdinal,\n ],\n set: {\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n source: matcher.source,\n event: matcher.event,\n config,\n },\n });\n }\n }\n });\n}\n\nasync function pruneStaleMatchers(\n tx: Tx,\n jobId: string,\n kind: JobListenerMatcherKind,\n matchers: readonly ListenerMatcher[],\n): Promise<void> {\n const base = and(\n eq(jobListenerSubscriptions.jobId, jobId),\n eq(jobListenerSubscriptions.kind, kind),\n );\n\n if (matchers.length === 0) {\n await tx.delete(jobListenerSubscriptions).where(base);\n return;\n }\n\n await tx.delete(jobListenerSubscriptions).where(\n and(\n base,\n notInArray(\n jobListenerSubscriptions.matcherOrdinal,\n matchers.map((_matcher, index) => index),\n ),\n ),\n );\n}\n\nexport async function removeJobListenerSubscriptionsForJob(jobId: string): Promise<number> {\n const rows = await db()\n .delete(jobListenerSubscriptions)\n .where(eq(jobListenerSubscriptions.jobId, jobId))\n .returning({id: jobListenerSubscriptions.id});\n return rows.length;\n}\n\nexport interface FindMatchingJobListenerSubscriptionsParams {\n workspaceId: string;\n source: string;\n event: string;\n}\n\nexport async function findMatchingJobListenerSubscriptions(\n params: FindMatchingJobListenerSubscriptionsParams,\n): Promise<JobListenerSubscription[]> {\n const rows = await db()\n .select()\n .from(jobListenerSubscriptions)\n .where(\n and(\n eq(jobListenerSubscriptions.workspaceId, params.workspaceId),\n eq(jobListenerSubscriptions.source, params.source),\n eq(jobListenerSubscriptions.event, params.event),\n ),\n );\n return rows.map(toJobListenerSubscription);\n}\n"],"names":["and","eq","notInArray","db","jobListenerSubscriptions","toJobListenerSubscription","projectJobListenerSubscriptions","params","transaction","tx","pruneStaleMatchers","jobId","on","until","kind","matchers","matcherOrdinal","matcher","entries","config","inputs","undefined","filter","filter_snapshot","insert","values","workspaceId","workflowRunId","source","event","onConflictDoUpdate","target","set","base","length","delete","where","map","_matcher","index","removeJobListenerSubscriptionsForJob","rows","returning","id","findMatchingJobListenerSubscriptions","select","from"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/db/job-listener-subscriptions.ts"],"sourcesContent":["import {and, eq, notInArray} from 'drizzle-orm';\nimport type {\n JobListenerMatcherKind,\n JobListenerSubscription,\n} from '#core/entities/job-listener-subscription.js';\nimport {db} from './db.js';\nimport {\n jobListenerSubscriptions,\n toJobListenerSubscription,\n} from './schema/job-listener-subscriptions.js';\n\ntype Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];\n\nexport interface ListenerMatcher {\n source: string;\n event: string;\n inputs?: Readonly<Record<string, unknown>> | undefined;\n filter?: string | undefined;\n filter_snapshot?: Readonly<Record<string, unknown>> | undefined;\n}\n\nexport interface ProjectJobListenerSubscriptionsParams {\n workspaceId: string;\n workflowRunId: string;\n jobId: string;\n on: readonly ListenerMatcher[] | null;\n until: readonly ListenerMatcher[] | null;\n}\n\nexport async function projectJobListenerSubscriptions(\n params: ProjectJobListenerSubscriptionsParams,\n): Promise<void> {\n await db().transaction(async (tx) => {\n await pruneStaleMatchers(tx, params.jobId, 'on', params.on ?? []);\n await pruneStaleMatchers(tx, params.jobId, 'until', params.until ?? []);\n\n for (const [kind, matchers] of [\n ['on', params.on ?? []],\n ['until', params.until ?? []],\n ] as const) {\n for (const [matcherOrdinal, matcher] of matchers.entries()) {\n const config: Record<string, unknown> = {};\n if (matcher.inputs !== undefined) config.inputs = matcher.inputs;\n if (matcher.filter !== undefined) config.filter = matcher.filter;\n if (matcher.filter_snapshot !== undefined) config.filter_snapshot = matcher.filter_snapshot;\n\n await tx\n .insert(jobListenerSubscriptions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n jobId: params.jobId,\n kind,\n matcherOrdinal,\n source: matcher.source,\n event: matcher.event,\n config,\n })\n .onConflictDoUpdate({\n target: [\n jobListenerSubscriptions.jobId,\n jobListenerSubscriptions.kind,\n jobListenerSubscriptions.matcherOrdinal,\n ],\n set: {\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n source: matcher.source,\n event: matcher.event,\n config,\n },\n });\n }\n }\n });\n}\n\nasync function pruneStaleMatchers(\n tx: Tx,\n jobId: string,\n kind: JobListenerMatcherKind,\n matchers: readonly ListenerMatcher[],\n): Promise<void> {\n const base = and(\n eq(jobListenerSubscriptions.jobId, jobId),\n eq(jobListenerSubscriptions.kind, kind),\n );\n\n if (matchers.length === 0) {\n await tx.delete(jobListenerSubscriptions).where(base);\n return;\n }\n\n await tx.delete(jobListenerSubscriptions).where(\n and(\n base,\n notInArray(\n jobListenerSubscriptions.matcherOrdinal,\n matchers.map((_matcher, index) => index),\n ),\n ),\n );\n}\n\nexport async function removeJobListenerSubscriptionsForJob(jobId: string): Promise<number> {\n const rows = await db()\n .delete(jobListenerSubscriptions)\n .where(eq(jobListenerSubscriptions.jobId, jobId))\n .returning({id: jobListenerSubscriptions.id});\n return rows.length;\n}\n\nexport interface FindMatchingJobListenerSubscriptionsParams {\n workspaceId: string;\n source: string;\n event: string;\n}\n\nexport async function findMatchingJobListenerSubscriptions(\n params: FindMatchingJobListenerSubscriptionsParams,\n): Promise<JobListenerSubscription[]> {\n const rows = await db()\n .select()\n .from(jobListenerSubscriptions)\n .where(\n and(\n eq(jobListenerSubscriptions.workspaceId, params.workspaceId),\n eq(jobListenerSubscriptions.source, params.source),\n eq(jobListenerSubscriptions.event, params.event),\n ),\n );\n return rows.map(toJobListenerSubscription);\n}\n\nexport async function hasJobListenerSubscriptions(jobId: string): Promise<boolean> {\n const [subscription] = await db()\n .select({id: jobListenerSubscriptions.id})\n .from(jobListenerSubscriptions)\n .where(eq(jobListenerSubscriptions.jobId, jobId))\n .limit(1);\n return subscription !== undefined;\n}\n"],"names":["and","eq","notInArray","db","jobListenerSubscriptions","toJobListenerSubscription","projectJobListenerSubscriptions","params","transaction","tx","pruneStaleMatchers","jobId","on","until","kind","matchers","matcherOrdinal","matcher","entries","config","inputs","undefined","filter","filter_snapshot","insert","values","workspaceId","workflowRunId","source","event","onConflictDoUpdate","target","set","base","length","delete","where","map","_matcher","index","removeJobListenerSubscriptionsForJob","rows","returning","id","findMatchingJobListenerSubscriptions","select","from","hasJobListenerSubscriptions","subscription","limit"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AACnF,OAAO,EAAC,KAAK,aAAa,EAAoB,MAAM,sBAAsB,CAAC;AAiB3E,YAAY,EACV,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,6CAA6C,CAAC;AACrD,YAAY,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACxE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,+BAA+B,EAC/B,gCAAgC,EAChC,iCAAiC,EACjC,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,EAAE,EACF,oCAAoC,EACpC,yBAAyB,EACzB,mCAAmC,EACnC,0BAA0B,EAC1B,wBAAwB,EACxB,wCAAwC,EACxC,cAAc,EACd,+BAA+B,EAC/B,oCAAoC,EACpC,cAAc,GACf,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,wBAAgB,oBAAoB,CAAC,EAAC,SAAS,EAAC,EAAE,2BAA2B,GAAG,aAAa,CAyC5F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AACnF,OAAO,EAAC,KAAK,aAAa,EAAoB,MAAM,sBAAsB,CAAC;AAkB3E,YAAY,EACV,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,6CAA6C,CAAC;AACrD,YAAY,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACxE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,+BAA+B,EAC/B,gCAAgC,EAChC,iCAAiC,EACjC,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,EAAE,EACF,oCAAoC,EACpC,yBAAyB,EACzB,mCAAmC,EACnC,0BAA0B,EAC1B,wBAAwB,EACxB,wCAAwC,EACxC,cAAc,EACd,+BAA+B,EAC/B,oCAAoC,EACpC,cAAc,GACf,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,wBAAgB,oBAAoB,CAAC,EAAC,SAAS,EAAC,EAAE,2BAA2B,GAAG,aAAa,CA0C5F"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { WORKFLOWS_JOB_ACTIVATED, WORKFLOWS_JOB_TERMINATED } from '@shipfox/api-
6
6
  import { subscriberFactory } from '@shipfox/node-module';
7
7
  import { db, migrationsPath, triggersOutbox } from '#db/index.js';
8
8
  import { registerTriggersServiceMetrics } from '#metrics/index.js';
9
+ import { triggersE2eRoutes } from '#presentation/e2e-routes.js';
9
10
  import { createTriggerRoutes } from '#presentation/index.js';
10
11
  import { createOnIntegrationEventReceived, onDefinitionDeleted, onDefinitionResolved, onJobActivated, onJobTerminated } from '#presentation/subscribers/index.js';
11
12
  import { createTriggersCronActivities, createTriggersMaintenanceActivities } from '#temporal/activities/index.js';
@@ -23,6 +24,9 @@ export function createTriggersModule({ workflows }) {
23
24
  migrationsPath
24
25
  },
25
26
  routes: createTriggerRoutes(workflows),
27
+ e2eRoutes: [
28
+ triggersE2eRoutes
29
+ ],
26
30
  metrics: registerTriggersServiceMetrics,
27
31
  publishers: [
28
32
  {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {\n DEFINITION_DELETED,\n DEFINITION_RESOLVED,\n type DefinitionsEventMap,\n} from '@shipfox/api-definitions-dto';\nimport {\n INTEGRATION_EVENT_RECEIVED,\n type IntegrationsEventMap,\n} from '@shipfox/api-integration-core-dto';\nimport {\n WORKFLOWS_JOB_ACTIVATED,\n WORKFLOWS_JOB_TERMINATED,\n type WorkflowsEventMapDto,\n} from '@shipfox/api-workflows-dto';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport {type ShipfoxModule, subscriberFactory} from '@shipfox/node-module';\nimport {db, migrationsPath, triggersOutbox} from '#db/index.js';\nimport {registerTriggersServiceMetrics} from '#metrics/index.js';\nimport {createTriggerRoutes} from '#presentation/index.js';\nimport {\n createOnIntegrationEventReceived,\n onDefinitionDeleted,\n onDefinitionResolved,\n onJobActivated,\n onJobTerminated,\n} from '#presentation/subscribers/index.js';\nimport {\n createTriggersCronActivities,\n createTriggersMaintenanceActivities,\n} from '#temporal/activities/index.js';\nimport {TRIGGERS_CRON_TASK_QUEUE, TRIGGERS_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';\n\nexport type {\n JobListenerMatcherKind,\n JobListenerSubscription,\n} from '#core/entities/job-listener-subscription.js';\nexport type {TriggerSubscription} from '#core/entities/subscription.js';\nexport {\n fireCronSubscription,\n fireManualSubscription,\n ManualTriggerNotFoundError,\n TriggerSubscriptionNotCronError,\n TriggerSubscriptionNotFoundError,\n TriggerSubscriptionNotManualError,\n TriggerWorkspaceMismatchError,\n} from '#core/index.js';\nexport {\n db,\n findMatchingJobListenerSubscriptions,\n findMatchingSubscriptions,\n getManualSubscriptionByDefinitionId,\n getTriggerSubscriptionById,\n jobListenerSubscriptions,\n listSubscriptionsByWorkflowDefinitionIds,\n migrationsPath,\n projectJobListenerSubscriptions,\n removeJobListenerSubscriptionsForJob,\n triggersOutbox,\n} from '#db/index.js';\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');\nconst temporalWorkflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');\n\nconst subscriber = subscriberFactory<\n DefinitionsEventMap & IntegrationsEventMap & WorkflowsEventMapDto\n>();\n\nexport interface CreateTriggersModuleOptions {\n workflows: WorkflowsModuleClient;\n}\n\nexport function createTriggersModule({workflows}: CreateTriggersModuleOptions): ShipfoxModule {\n return {\n name: 'triggers',\n database: {db, migrationsPath},\n routes: createTriggerRoutes(workflows),\n metrics: registerTriggersServiceMetrics,\n publishers: [{name: 'triggers', table: triggersOutbox, db}],\n subscribers: [\n subscriber(DEFINITION_RESOLVED, onDefinitionResolved),\n subscriber(DEFINITION_DELETED, onDefinitionDeleted),\n subscriber(INTEGRATION_EVENT_RECEIVED, createOnIntegrationEventReceived(workflows)),\n subscriber(WORKFLOWS_JOB_ACTIVATED, onJobActivated),\n subscriber(WORKFLOWS_JOB_TERMINATED, onJobTerminated),\n ],\n workers: [\n {\n taskQueue: TRIGGERS_MAINTENANCE_TASK_QUEUE,\n workflowsPath: temporalWorkflowsPath,\n activities: createTriggersMaintenanceActivities,\n workflows: [\n {\n name: 'pruneTriggerEventsCron',\n id: 'triggers-prune-trigger-events',\n cronSchedule: '0 * * * *',\n },\n ],\n },\n {\n taskQueue: TRIGGERS_CRON_TASK_QUEUE,\n workflowsPath: temporalWorkflowsPath,\n activities: () => createTriggersCronActivities(workflows),\n workflows: [\n {\n name: 'cronTickCron',\n id: 'triggers-cron-tick',\n cronSchedule: '* * * * *',\n },\n ],\n },\n ],\n };\n}\n"],"names":["dirname","resolve","fileURLToPath","DEFINITION_DELETED","DEFINITION_RESOLVED","INTEGRATION_EVENT_RECEIVED","WORKFLOWS_JOB_ACTIVATED","WORKFLOWS_JOB_TERMINATED","subscriberFactory","db","migrationsPath","triggersOutbox","registerTriggersServiceMetrics","createTriggerRoutes","createOnIntegrationEventReceived","onDefinitionDeleted","onDefinitionResolved","onJobActivated","onJobTerminated","createTriggersCronActivities","createTriggersMaintenanceActivities","TRIGGERS_CRON_TASK_QUEUE","TRIGGERS_MAINTENANCE_TASK_QUEUE","fireCronSubscription","fireManualSubscription","ManualTriggerNotFoundError","TriggerSubscriptionNotCronError","TriggerSubscriptionNotFoundError","TriggerSubscriptionNotManualError","TriggerWorkspaceMismatchError","findMatchingJobListenerSubscriptions","findMatchingSubscriptions","getManualSubscriptionByDefinitionId","getTriggerSubscriptionById","jobListenerSubscriptions","listSubscriptionsByWorkflowDefinitionIds","projectJobListenerSubscriptions","removeJobListenerSubscriptionsForJob","packageRoot","url","temporalWorkflowsPath","subscriber","createTriggersModule","workflows","name","database","routes","metrics","publishers","table","subscribers","workers","taskQueue","workflowsPath","activities","id","cronSchedule"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AACvC,SACEC,kBAAkB,EAClBC,mBAAmB,QAEd,+BAA+B;AACtC,SACEC,0BAA0B,QAErB,oCAAoC;AAC3C,SACEC,uBAAuB,EACvBC,wBAAwB,QAEnB,6BAA6B;AAEpC,SAA4BC,iBAAiB,QAAO,uBAAuB;AAC3E,SAAQC,EAAE,EAAEC,cAAc,EAAEC,cAAc,QAAO,eAAe;AAChE,SAAQC,8BAA8B,QAAO,oBAAoB;AACjE,SAAQC,mBAAmB,QAAO,yBAAyB;AAC3D,SACEC,gCAAgC,EAChCC,mBAAmB,EACnBC,oBAAoB,EACpBC,cAAc,EACdC,eAAe,QACV,qCAAqC;AAC5C,SACEC,4BAA4B,EAC5BC,mCAAmC,QAC9B,gCAAgC;AACvC,SAAQC,wBAAwB,EAAEC,+BAA+B,QAAO,yBAAyB;AAOjG,SACEC,oBAAoB,EACpBC,sBAAsB,EACtBC,0BAA0B,EAC1BC,+BAA+B,EAC/BC,gCAAgC,EAChCC,iCAAiC,EACjCC,6BAA6B,QACxB,iBAAiB;AACxB,SACEpB,EAAE,EACFqB,oCAAoC,EACpCC,yBAAyB,EACzBC,mCAAmC,EACnCC,0BAA0B,EAC1BC,wBAAwB,EACxBC,wCAAwC,EACxCzB,cAAc,EACd0B,+BAA+B,EAC/BC,oCAAoC,EACpC1B,cAAc,QACT,eAAe;AAEtB,MAAM2B,cAAcrC,QAAQD,QAAQE,cAAc,YAAYqC,GAAG,IAAI;AACrE,MAAMC,wBAAwBvC,QAAQqC,aAAa;AAEnD,MAAMG,aAAajC;AAQnB,OAAO,SAASkC,qBAAqB,EAACC,SAAS,EAA8B;IAC3E,OAAO;QACLC,MAAM;QACNC,UAAU;YAACpC;YAAIC;QAAc;QAC7BoC,QAAQjC,oBAAoB8B;QAC5BI,SAASnC;QACToC,YAAY;YAAC;gBAACJ,MAAM;gBAAYK,OAAOtC;gBAAgBF;YAAE;SAAE;QAC3DyC,aAAa;YACXT,WAAWrC,qBAAqBY;YAChCyB,WAAWtC,oBAAoBY;YAC/B0B,WAAWpC,4BAA4BS,iCAAiC6B;YACxEF,WAAWnC,yBAAyBW;YACpCwB,WAAWlC,0BAA0BW;SACtC;QACDiC,SAAS;YACP;gBACEC,WAAW9B;gBACX+B,eAAeb;gBACfc,YAAYlC;gBACZuB,WAAW;oBACT;wBACEC,MAAM;wBACNW,IAAI;wBACJC,cAAc;oBAChB;iBACD;YACH;YACA;gBACEJ,WAAW/B;gBACXgC,eAAeb;gBACfc,YAAY,IAAMnC,6BAA6BwB;gBAC/CA,WAAW;oBACT;wBACEC,MAAM;wBACNW,IAAI;wBACJC,cAAc;oBAChB;iBACD;YACH;SACD;IACH;AACF"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {\n DEFINITION_DELETED,\n DEFINITION_RESOLVED,\n type DefinitionsEventMap,\n} from '@shipfox/api-definitions-dto';\nimport {\n INTEGRATION_EVENT_RECEIVED,\n type IntegrationsEventMap,\n} from '@shipfox/api-integration-core-dto';\nimport {\n WORKFLOWS_JOB_ACTIVATED,\n WORKFLOWS_JOB_TERMINATED,\n type WorkflowsEventMapDto,\n} from '@shipfox/api-workflows-dto';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport {type ShipfoxModule, subscriberFactory} from '@shipfox/node-module';\nimport {db, migrationsPath, triggersOutbox} from '#db/index.js';\nimport {registerTriggersServiceMetrics} from '#metrics/index.js';\nimport {triggersE2eRoutes} from '#presentation/e2e-routes.js';\nimport {createTriggerRoutes} from '#presentation/index.js';\nimport {\n createOnIntegrationEventReceived,\n onDefinitionDeleted,\n onDefinitionResolved,\n onJobActivated,\n onJobTerminated,\n} from '#presentation/subscribers/index.js';\nimport {\n createTriggersCronActivities,\n createTriggersMaintenanceActivities,\n} from '#temporal/activities/index.js';\nimport {TRIGGERS_CRON_TASK_QUEUE, TRIGGERS_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';\n\nexport type {\n JobListenerMatcherKind,\n JobListenerSubscription,\n} from '#core/entities/job-listener-subscription.js';\nexport type {TriggerSubscription} from '#core/entities/subscription.js';\nexport {\n fireCronSubscription,\n fireManualSubscription,\n ManualTriggerNotFoundError,\n TriggerSubscriptionNotCronError,\n TriggerSubscriptionNotFoundError,\n TriggerSubscriptionNotManualError,\n TriggerWorkspaceMismatchError,\n} from '#core/index.js';\nexport {\n db,\n findMatchingJobListenerSubscriptions,\n findMatchingSubscriptions,\n getManualSubscriptionByDefinitionId,\n getTriggerSubscriptionById,\n jobListenerSubscriptions,\n listSubscriptionsByWorkflowDefinitionIds,\n migrationsPath,\n projectJobListenerSubscriptions,\n removeJobListenerSubscriptionsForJob,\n triggersOutbox,\n} from '#db/index.js';\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');\nconst temporalWorkflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');\n\nconst subscriber = subscriberFactory<\n DefinitionsEventMap & IntegrationsEventMap & WorkflowsEventMapDto\n>();\n\nexport interface CreateTriggersModuleOptions {\n workflows: WorkflowsModuleClient;\n}\n\nexport function createTriggersModule({workflows}: CreateTriggersModuleOptions): ShipfoxModule {\n return {\n name: 'triggers',\n database: {db, migrationsPath},\n routes: createTriggerRoutes(workflows),\n e2eRoutes: [triggersE2eRoutes],\n metrics: registerTriggersServiceMetrics,\n publishers: [{name: 'triggers', table: triggersOutbox, db}],\n subscribers: [\n subscriber(DEFINITION_RESOLVED, onDefinitionResolved),\n subscriber(DEFINITION_DELETED, onDefinitionDeleted),\n subscriber(INTEGRATION_EVENT_RECEIVED, createOnIntegrationEventReceived(workflows)),\n subscriber(WORKFLOWS_JOB_ACTIVATED, onJobActivated),\n subscriber(WORKFLOWS_JOB_TERMINATED, onJobTerminated),\n ],\n workers: [\n {\n taskQueue: TRIGGERS_MAINTENANCE_TASK_QUEUE,\n workflowsPath: temporalWorkflowsPath,\n activities: createTriggersMaintenanceActivities,\n workflows: [\n {\n name: 'pruneTriggerEventsCron',\n id: 'triggers-prune-trigger-events',\n cronSchedule: '0 * * * *',\n },\n ],\n },\n {\n taskQueue: TRIGGERS_CRON_TASK_QUEUE,\n workflowsPath: temporalWorkflowsPath,\n activities: () => createTriggersCronActivities(workflows),\n workflows: [\n {\n name: 'cronTickCron',\n id: 'triggers-cron-tick',\n cronSchedule: '* * * * *',\n },\n ],\n },\n ],\n };\n}\n"],"names":["dirname","resolve","fileURLToPath","DEFINITION_DELETED","DEFINITION_RESOLVED","INTEGRATION_EVENT_RECEIVED","WORKFLOWS_JOB_ACTIVATED","WORKFLOWS_JOB_TERMINATED","subscriberFactory","db","migrationsPath","triggersOutbox","registerTriggersServiceMetrics","triggersE2eRoutes","createTriggerRoutes","createOnIntegrationEventReceived","onDefinitionDeleted","onDefinitionResolved","onJobActivated","onJobTerminated","createTriggersCronActivities","createTriggersMaintenanceActivities","TRIGGERS_CRON_TASK_QUEUE","TRIGGERS_MAINTENANCE_TASK_QUEUE","fireCronSubscription","fireManualSubscription","ManualTriggerNotFoundError","TriggerSubscriptionNotCronError","TriggerSubscriptionNotFoundError","TriggerSubscriptionNotManualError","TriggerWorkspaceMismatchError","findMatchingJobListenerSubscriptions","findMatchingSubscriptions","getManualSubscriptionByDefinitionId","getTriggerSubscriptionById","jobListenerSubscriptions","listSubscriptionsByWorkflowDefinitionIds","projectJobListenerSubscriptions","removeJobListenerSubscriptionsForJob","packageRoot","url","temporalWorkflowsPath","subscriber","createTriggersModule","workflows","name","database","routes","e2eRoutes","metrics","publishers","table","subscribers","workers","taskQueue","workflowsPath","activities","id","cronSchedule"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AACvC,SACEC,kBAAkB,EAClBC,mBAAmB,QAEd,+BAA+B;AACtC,SACEC,0BAA0B,QAErB,oCAAoC;AAC3C,SACEC,uBAAuB,EACvBC,wBAAwB,QAEnB,6BAA6B;AAEpC,SAA4BC,iBAAiB,QAAO,uBAAuB;AAC3E,SAAQC,EAAE,EAAEC,cAAc,EAAEC,cAAc,QAAO,eAAe;AAChE,SAAQC,8BAA8B,QAAO,oBAAoB;AACjE,SAAQC,iBAAiB,QAAO,8BAA8B;AAC9D,SAAQC,mBAAmB,QAAO,yBAAyB;AAC3D,SACEC,gCAAgC,EAChCC,mBAAmB,EACnBC,oBAAoB,EACpBC,cAAc,EACdC,eAAe,QACV,qCAAqC;AAC5C,SACEC,4BAA4B,EAC5BC,mCAAmC,QAC9B,gCAAgC;AACvC,SAAQC,wBAAwB,EAAEC,+BAA+B,QAAO,yBAAyB;AAOjG,SACEC,oBAAoB,EACpBC,sBAAsB,EACtBC,0BAA0B,EAC1BC,+BAA+B,EAC/BC,gCAAgC,EAChCC,iCAAiC,EACjCC,6BAA6B,QACxB,iBAAiB;AACxB,SACErB,EAAE,EACFsB,oCAAoC,EACpCC,yBAAyB,EACzBC,mCAAmC,EACnCC,0BAA0B,EAC1BC,wBAAwB,EACxBC,wCAAwC,EACxC1B,cAAc,EACd2B,+BAA+B,EAC/BC,oCAAoC,EACpC3B,cAAc,QACT,eAAe;AAEtB,MAAM4B,cAActC,QAAQD,QAAQE,cAAc,YAAYsC,GAAG,IAAI;AACrE,MAAMC,wBAAwBxC,QAAQsC,aAAa;AAEnD,MAAMG,aAAalC;AAQnB,OAAO,SAASmC,qBAAqB,EAACC,SAAS,EAA8B;IAC3E,OAAO;QACLC,MAAM;QACNC,UAAU;YAACrC;YAAIC;QAAc;QAC7BqC,QAAQjC,oBAAoB8B;QAC5BI,WAAW;YAACnC;SAAkB;QAC9BoC,SAASrC;QACTsC,YAAY;YAAC;gBAACL,MAAM;gBAAYM,OAAOxC;gBAAgBF;YAAE;SAAE;QAC3D2C,aAAa;YACXV,WAAWtC,qBAAqBa;YAChCyB,WAAWvC,oBAAoBa;YAC/B0B,WAAWrC,4BAA4BU,iCAAiC6B;YACxEF,WAAWpC,yBAAyBY;YACpCwB,WAAWnC,0BAA0BY;SACtC;QACDkC,SAAS;YACP;gBACEC,WAAW/B;gBACXgC,eAAed;gBACfe,YAAYnC;gBACZuB,WAAW;oBACT;wBACEC,MAAM;wBACNY,IAAI;wBACJC,cAAc;oBAChB;iBACD;YACH;YACA;gBACEJ,WAAWhC;gBACXiC,eAAed;gBACfe,YAAY,IAAMpC,6BAA6BwB;gBAC/CA,WAAW;oBACT;wBACEC,MAAM;wBACNY,IAAI;wBACJC,cAAc;oBAChB;iBACD;YACH;SACD;IACH;AACF"}
@@ -0,0 +1,3 @@
1
+ import { type RouteGroup } from '@shipfox/node-fastify';
2
+ export declare const triggersE2eRoutes: RouteGroup;
3
+ //# sourceMappingURL=e2e-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-routes.d.ts","sourceRoot":"","sources":["../../src/presentation/e2e-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAoBnE,eAAO,MAAM,iBAAiB,EAAE,UAG/B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { defineRoute } from '@shipfox/node-fastify';
2
+ import { z } from 'zod';
3
+ import { hasJobListenerSubscriptions } from '#db/job-listener-subscriptions.js';
4
+ const listenerReadinessParamsSchema = z.object({
5
+ jobId: z.string().uuid()
6
+ });
7
+ const listenerReadinessResponseSchema = z.object({
8
+ ready: z.boolean()
9
+ });
10
+ const listenerReadinessRoute = defineRoute({
11
+ method: 'GET',
12
+ path: '/listeners/:jobId/readiness',
13
+ description: 'Report whether trigger subscriptions for a listener job are ready in E2E tests.',
14
+ schema: {
15
+ params: listenerReadinessParamsSchema,
16
+ response: {
17
+ 200: listenerReadinessResponseSchema
18
+ }
19
+ },
20
+ handler: async (request)=>({
21
+ ready: await hasJobListenerSubscriptions(request.params.jobId)
22
+ })
23
+ });
24
+ export const triggersE2eRoutes = {
25
+ prefix: '/triggers',
26
+ routes: [
27
+ listenerReadinessRoute
28
+ ]
29
+ };
30
+
31
+ //# sourceMappingURL=e2e-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/presentation/e2e-routes.ts"],"sourcesContent":["import {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {hasJobListenerSubscriptions} from '#db/job-listener-subscriptions.js';\n\nconst listenerReadinessParamsSchema = z.object({jobId: z.string().uuid()});\nconst listenerReadinessResponseSchema = z.object({ready: z.boolean()});\n\nconst listenerReadinessRoute = defineRoute({\n method: 'GET',\n path: '/listeners/:jobId/readiness',\n description: 'Report whether trigger subscriptions for a listener job are ready in E2E tests.',\n schema: {\n params: listenerReadinessParamsSchema,\n response: {200: listenerReadinessResponseSchema},\n },\n handler: async (request) => ({\n ready: await hasJobListenerSubscriptions(request.params.jobId),\n }),\n});\n\nexport const triggersE2eRoutes: RouteGroup = {\n prefix: '/triggers',\n routes: [listenerReadinessRoute],\n};\n"],"names":["defineRoute","z","hasJobListenerSubscriptions","listenerReadinessParamsSchema","object","jobId","string","uuid","listenerReadinessResponseSchema","ready","boolean","listenerReadinessRoute","method","path","description","schema","params","response","handler","request","triggersE2eRoutes","prefix","routes"],"mappings":"AAAA,SAAQA,WAAW,QAAwB,wBAAwB;AACnE,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,2BAA2B,QAAO,oCAAoC;AAE9E,MAAMC,gCAAgCF,EAAEG,MAAM,CAAC;IAACC,OAAOJ,EAAEK,MAAM,GAAGC,IAAI;AAAE;AACxE,MAAMC,kCAAkCP,EAAEG,MAAM,CAAC;IAACK,OAAOR,EAAES,OAAO;AAAE;AAEpE,MAAMC,yBAAyBX,YAAY;IACzCY,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,QAAQb;QACRc,UAAU;YAAC,KAAKT;QAA+B;IACjD;IACAU,SAAS,OAAOC,UAAa,CAAA;YAC3BV,OAAO,MAAMP,4BAA4BiB,QAAQH,MAAM,CAACX,KAAK;QAC/D,CAAA;AACF;AAEA,OAAO,MAAMe,oBAAgC;IAC3CC,QAAQ;IACRC,QAAQ;QAACX;KAAuB;AAClC,EAAE"}