@shipfox/api-triggers 4.0.0 → 6.0.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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +65 -0
- package/README.md +23 -3
- package/dist/core/dispatch-integration-event.d.ts +2 -0
- package/dist/core/dispatch-integration-event.d.ts.map +1 -1
- package/dist/core/dispatch-integration-event.js +9 -5
- package/dist/core/dispatch-integration-event.js.map +1 -1
- package/dist/core/drain-cron-schedules.d.ts +2 -0
- package/dist/core/drain-cron-schedules.d.ts.map +1 -1
- package/dist/core/drain-cron-schedules.js +1 -0
- package/dist/core/drain-cron-schedules.js.map +1 -1
- package/dist/core/fire-cron.d.ts +6 -2
- package/dist/core/fire-cron.d.ts.map +1 -1
- package/dist/core/fire-cron.js +8 -5
- package/dist/core/fire-cron.js.map +1 -1
- package/dist/core/fire-manual.d.ts +6 -2
- package/dist/core/fire-manual.d.ts.map +1 -1
- package/dist/core/fire-manual.js +8 -4
- package/dist/core/fire-manual.js.map +1 -1
- package/dist/core/route-event-to-job-listeners.d.ts +2 -0
- package/dist/core/route-event-to-job-listeners.d.ts.map +1 -1
- package/dist/core/route-event-to-job-listeners.js +2 -3
- package/dist/core/route-event-to-job-listeners.js.map +1 -1
- package/dist/core/workflows-client.d.ts +69 -0
- package/dist/core/workflows-client.d.ts.map +1 -0
- package/dist/core/workflows-client.js +20 -0
- package/dist/core/workflows-client.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -50
- package/dist/index.js.map +1 -1
- package/dist/presentation/index.d.ts +2 -2
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +2 -2
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/routes/fire-manual.d.ts +2 -1
- package/dist/presentation/routes/fire-manual.d.ts.map +1 -1
- package/dist/presentation/routes/fire-manual.js +61 -58
- package/dist/presentation/routes/fire-manual.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +2 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +23 -21
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/subscribers/index.d.ts +1 -1
- package/dist/presentation/subscribers/index.d.ts.map +1 -1
- package/dist/presentation/subscribers/index.js +1 -1
- package/dist/presentation/subscribers/index.js.map +1 -1
- package/dist/presentation/subscribers/on-integration-event-received.d.ts +2 -1
- package/dist/presentation/subscribers/on-integration-event-received.d.ts.map +1 -1
- package/dist/presentation/subscribers/on-integration-event-received.js +16 -13
- package/dist/presentation/subscribers/on-integration-event-received.js.map +1 -1
- package/dist/temporal/activities/drain-cron-batch.d.ts +2 -1
- package/dist/temporal/activities/drain-cron-batch.d.ts.map +1 -1
- package/dist/temporal/activities/drain-cron-batch.js +2 -1
- package/dist/temporal/activities/drain-cron-batch.js.map +1 -1
- package/dist/temporal/activities/index.d.ts +4 -3
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/index.js +2 -2
- package/dist/temporal/activities/index.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +27 -35
- package/src/core/dispatch-integration-event.history-failure.test.ts +11 -6
- package/src/core/dispatch-integration-event.test.ts +50 -36
- package/src/core/dispatch-integration-event.ts +8 -5
- package/src/core/drain-cron-schedules.test.ts +30 -29
- package/src/core/drain-cron-schedules.ts +3 -0
- package/src/core/fire-cron.test.ts +35 -24
- package/src/core/fire-cron.ts +9 -7
- package/src/core/fire-manual.test.ts +19 -22
- package/src/core/fire-manual.ts +9 -6
- package/src/core/record-trigger-history.test.ts +3 -5
- package/src/core/route-event-to-job-listeners.test.ts +5 -4
- package/src/core/route-event-to-job-listeners.ts +5 -4
- package/src/core/workflows-client.test.ts +73 -0
- package/src/core/workflows-client.ts +32 -0
- package/src/index.ts +49 -42
- package/src/presentation/index.ts +2 -2
- package/src/presentation/routes/fire-manual.test.ts +14 -30
- package/src/presentation/routes/fire-manual.ts +62 -54
- package/src/presentation/routes/index.ts +18 -15
- package/src/presentation/subscribers/index.ts +1 -1
- package/src/presentation/subscribers/on-integration-event-received.test.ts +6 -3
- package/src/presentation/subscribers/on-integration-event-received.ts +20 -16
- package/src/temporal/activities/drain-cron-batch.ts +5 -1
- package/src/temporal/activities/index.ts +3 -2
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/route-event-to-job-listeners.ts"],"sourcesContent":["import {deliverEventToListener, type JobListenerEventDisposition} from '@shipfox/api-workflows';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {findMatchingJobListenerSubscriptions} from '#db/job-listener-subscriptions.js';\nimport {evaluateStoredFilter, type StoredFilterEvaluation} from './config.js';\nimport type {JobListenerSubscription} from './entities/job-listener-subscription.js';\nimport {type TriggerHistoryRecorder, toReason} from './record-trigger-history.js';\n\nexport interface RouteEventToJobListenersParams {\n history: TriggerHistoryRecorder;\n eventRef: string;\n workspaceId: string;\n provider: string;\n source: string;\n event: string;\n deliveryId: string;\n payload: unknown;\n receivedAt: Date;\n}\n\nexport interface RouteEventToJobListenersResult {\n /**\n * Listener outcomes that should contribute to received_event.matched_count:\n * filter errors, accepted deliveries, and dispatch errors. Stale skipped jobs\n * are intentionally excluded because they did not produce an auditable decision.\n */\n engagedCount: number;\n /**\n * Jobs with an effective matcher after source/event/filter checks, including\n * stale skipped jobs.\n */\n matchedJobCount: number;\n acceptedJobCount: number;\n deliveredCount: number;\n transientErrored: boolean;\n transientError: unknown;\n}\n\nexport async function routeEventToJobListeners(\n params: RouteEventToJobListenersParams,\n): Promise<RouteEventToJobListenersResult> {\n const subscriptions = await findMatchingJobListenerSubscriptions({\n workspaceId: params.workspaceId,\n source: params.source,\n event: params.event,\n });\n\n let filterErrorCount = 0;\n const effectiveMatchByJobId = new Map<string, JobListenerSubscription>();\n for (const subscription of subscriptions) {\n const filterResult = evaluateListenerFilter({subscription, payload: params.payload});\n if (filterResult.kind === 'filtered') continue;\n if (filterResult.kind === 'filter-error') {\n filterErrorCount += 1;\n await params.history.listenerFilterErrored(subscription, filterResult.reason);\n continue;\n }\n\n const previous = effectiveMatchByJobId.get(subscription.jobId);\n if (!previous || shouldReplaceEffectiveMatcher(previous, subscription)) {\n effectiveMatchByJobId.set(subscription.jobId, subscription);\n }\n }\n\n let acceptedJobCount = 0;\n let deliveredCount = 0;\n let sawTransientError = false;\n let dispatchErrorCount = 0;\n let firstTransientError: unknown;\n\n for (const subscription of effectiveMatchByJobId.values()) {\n const disposition = listenerDisposition(subscription);\n try {\n const result = await deliverEventToListener({\n jobId: subscription.jobId,\n disposition,\n eventRef: params.eventRef,\n deliveryId: params.deliveryId,\n source: params.source,\n event: params.event,\n provider: params.provider,\n payload: params.payload,\n receivedAt: params.receivedAt,\n });\n if (!result.skipped) {\n acceptedJobCount += 1;\n await params.history.listenerTriggered(subscription);\n }\n if (result.buffered) deliveredCount += 1;\n } catch (error) {\n dispatchErrorCount += 1;\n await params.history.listenerDispatchErrored(subscription, toReason(error));\n if (!sawTransientError) {\n sawTransientError = true;\n firstTransientError = error;\n }\n }\n }\n\n return {\n engagedCount: filterErrorCount + acceptedJobCount + dispatchErrorCount,\n matchedJobCount: effectiveMatchByJobId.size,\n acceptedJobCount,\n deliveredCount,\n transientErrored: sawTransientError,\n transientError: sawTransientError ? firstTransientError : undefined,\n };\n}\n\ninterface EvaluateListenerFilterParams {\n subscription: JobListenerSubscription;\n payload: unknown;\n}\n\nfunction evaluateListenerFilter(params: EvaluateListenerFilterParams): StoredFilterEvaluation {\n const filter = params.subscription.config.filter;\n if (filter === null || filter === undefined) return {kind: 'matched'};\n if (typeof filter !== 'string' || filter.trim() === '') {\n return evaluateStoredFilter({\n value: filter,\n context: {event: params.payload},\n invalidReason: 'Listener subscription filter must be a non-empty string when set',\n evaluationFailedReason: 'Listener filter evaluation failed',\n });\n }\n\n const snapshot = readFilterSnapshot(params.subscription);\n if (snapshot.kind === 'invalid') return snapshot.result;\n\n return evaluateStoredFilter({\n value: filter,\n context: {...snapshot.value, event: params.payload},\n invalidReason: 'Listener subscription filter must be a non-empty string when set',\n evaluationFailedReason: 'Listener filter evaluation failed',\n });\n}\n\nfunction readFilterSnapshot(\n subscription: JobListenerSubscription,\n):\n | {kind: 'valid'; value: Record<string, unknown>}\n | {kind: 'invalid'; result: Extract<StoredFilterEvaluation, {kind: 'filter-error'}>} {\n const value = subscription.config.filter_snapshot;\n if (value === undefined) return {kind: 'valid', value: {}};\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n return {kind: 'valid', value: value as Record<string, unknown>};\n }\n return {\n kind: 'invalid',\n result: {\n kind: 'filter-error',\n reason: 'Listener filter snapshot must be an object when set',\n },\n };\n}\n\nfunction listenerDisposition(subscription: JobListenerSubscription): JobListenerEventDisposition {\n return subscription.kind === 'until' ? 'resolve' : 'fire';\n}\n\nfunction listenerMatcherSortKey(subscription: JobListenerSubscription): string {\n const kindRank = subscription.kind === 'until' ? '0' : '1';\n return `${kindRank}:${subscription.matcherOrdinal.toString().padStart(10, '0')}`;\n}\n\nfunction shouldReplaceEffectiveMatcher(\n previous: JobListenerSubscription,\n candidate: JobListenerSubscription,\n): boolean {\n const previousKey = listenerMatcherSortKey(previous);\n const candidateKey = listenerMatcherSortKey(candidate);\n if (candidateKey !== previousKey) return candidateKey < previousKey;\n\n logger().warn(\n {\n jobId: candidate.jobId,\n keptSubscriptionId: previous.id,\n candidateSubscriptionId: candidate.id,\n matcherKind: candidate.kind,\n matcherOrdinal: candidate.matcherOrdinal,\n },\n 'duplicate job listener matcher key encountered; choosing deterministic subscription id order',\n );\n return candidate.id < previous.id;\n}\n"],"names":["deliverEventToListener","logger","findMatchingJobListenerSubscriptions","evaluateStoredFilter","toReason","routeEventToJobListeners","params","subscriptions","workspaceId","source","event","filterErrorCount","effectiveMatchByJobId","Map","subscription","filterResult","evaluateListenerFilter","payload","kind","history","listenerFilterErrored","reason","previous","get","jobId","shouldReplaceEffectiveMatcher","set","acceptedJobCount","deliveredCount","sawTransientError","dispatchErrorCount","firstTransientError","values","disposition","listenerDisposition","result","eventRef","deliveryId","provider","receivedAt","skipped","listenerTriggered","buffered","error","listenerDispatchErrored","engagedCount","matchedJobCount","size","transientErrored","transientError","undefined","filter","config","trim","value","context","invalidReason","evaluationFailedReason","snapshot","readFilterSnapshot","filter_snapshot","Array","isArray","listenerMatcherSortKey","kindRank","matcherOrdinal","toString","padStart","candidate","previousKey","candidateKey","warn","keptSubscriptionId","id","candidateSubscriptionId","matcherKind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/route-event-to-job-listeners.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport {findMatchingJobListenerSubscriptions} from '#db/job-listener-subscriptions.js';\nimport {evaluateStoredFilter, type StoredFilterEvaluation} from './config.js';\nimport type {JobListenerSubscription} from './entities/job-listener-subscription.js';\nimport {type TriggerHistoryRecorder, toReason} from './record-trigger-history.js';\nimport type {WorkflowsModuleClient} from './workflows-client.js';\n\nexport interface RouteEventToJobListenersParams {\n workflows: WorkflowsModuleClient;\n history: TriggerHistoryRecorder;\n eventRef: string;\n workspaceId: string;\n provider: string;\n source: string;\n event: string;\n deliveryId: string;\n payload: unknown;\n receivedAt: Date;\n}\n\nexport interface RouteEventToJobListenersResult {\n /**\n * Listener outcomes that should contribute to received_event.matched_count:\n * filter errors, accepted deliveries, and dispatch errors. Stale skipped jobs\n * are intentionally excluded because they did not produce an auditable decision.\n */\n engagedCount: number;\n /**\n * Jobs with an effective matcher after source/event/filter checks, including\n * stale skipped jobs.\n */\n matchedJobCount: number;\n acceptedJobCount: number;\n deliveredCount: number;\n transientErrored: boolean;\n transientError: unknown;\n}\n\nexport async function routeEventToJobListeners(\n params: RouteEventToJobListenersParams,\n): Promise<RouteEventToJobListenersResult> {\n const subscriptions = await findMatchingJobListenerSubscriptions({\n workspaceId: params.workspaceId,\n source: params.source,\n event: params.event,\n });\n\n let filterErrorCount = 0;\n const effectiveMatchByJobId = new Map<string, JobListenerSubscription>();\n for (const subscription of subscriptions) {\n const filterResult = evaluateListenerFilter({subscription, payload: params.payload});\n if (filterResult.kind === 'filtered') continue;\n if (filterResult.kind === 'filter-error') {\n filterErrorCount += 1;\n await params.history.listenerFilterErrored(subscription, filterResult.reason);\n continue;\n }\n\n const previous = effectiveMatchByJobId.get(subscription.jobId);\n if (!previous || shouldReplaceEffectiveMatcher(previous, subscription)) {\n effectiveMatchByJobId.set(subscription.jobId, subscription);\n }\n }\n\n let acceptedJobCount = 0;\n let deliveredCount = 0;\n let sawTransientError = false;\n let dispatchErrorCount = 0;\n let firstTransientError: unknown;\n\n for (const subscription of effectiveMatchByJobId.values()) {\n const disposition = listenerDisposition(subscription);\n try {\n const result = await params.workflows.deliverEventToJobListener({\n jobId: subscription.jobId,\n disposition,\n eventRef: params.eventRef,\n deliveryId: params.deliveryId,\n source: params.source,\n event: params.event,\n provider: params.provider,\n payload: params.payload,\n receivedAt: params.receivedAt.toISOString(),\n });\n if (!result.skipped) {\n acceptedJobCount += 1;\n await params.history.listenerTriggered(subscription);\n }\n if (result.buffered) deliveredCount += 1;\n } catch (error) {\n dispatchErrorCount += 1;\n await params.history.listenerDispatchErrored(subscription, toReason(error));\n if (!sawTransientError) {\n sawTransientError = true;\n firstTransientError = error;\n }\n }\n }\n\n return {\n engagedCount: filterErrorCount + acceptedJobCount + dispatchErrorCount,\n matchedJobCount: effectiveMatchByJobId.size,\n acceptedJobCount,\n deliveredCount,\n transientErrored: sawTransientError,\n transientError: sawTransientError ? firstTransientError : undefined,\n };\n}\n\ninterface EvaluateListenerFilterParams {\n subscription: JobListenerSubscription;\n payload: unknown;\n}\n\nfunction evaluateListenerFilter(params: EvaluateListenerFilterParams): StoredFilterEvaluation {\n const filter = params.subscription.config.filter;\n if (filter === null || filter === undefined) return {kind: 'matched'};\n if (typeof filter !== 'string' || filter.trim() === '') {\n return evaluateStoredFilter({\n value: filter,\n context: {event: params.payload},\n invalidReason: 'Listener subscription filter must be a non-empty string when set',\n evaluationFailedReason: 'Listener filter evaluation failed',\n });\n }\n\n const snapshot = readFilterSnapshot(params.subscription);\n if (snapshot.kind === 'invalid') return snapshot.result;\n\n return evaluateStoredFilter({\n value: filter,\n context: {...snapshot.value, event: params.payload},\n invalidReason: 'Listener subscription filter must be a non-empty string when set',\n evaluationFailedReason: 'Listener filter evaluation failed',\n });\n}\n\nfunction readFilterSnapshot(\n subscription: JobListenerSubscription,\n):\n | {kind: 'valid'; value: Record<string, unknown>}\n | {kind: 'invalid'; result: Extract<StoredFilterEvaluation, {kind: 'filter-error'}>} {\n const value = subscription.config.filter_snapshot;\n if (value === undefined) return {kind: 'valid', value: {}};\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n return {kind: 'valid', value: value as Record<string, unknown>};\n }\n return {\n kind: 'invalid',\n result: {\n kind: 'filter-error',\n reason: 'Listener filter snapshot must be an object when set',\n },\n };\n}\n\nfunction listenerDisposition(subscription: JobListenerSubscription): 'fire' | 'resolve' {\n return subscription.kind === 'until' ? 'resolve' : 'fire';\n}\n\nfunction listenerMatcherSortKey(subscription: JobListenerSubscription): string {\n const kindRank = subscription.kind === 'until' ? '0' : '1';\n return `${kindRank}:${subscription.matcherOrdinal.toString().padStart(10, '0')}`;\n}\n\nfunction shouldReplaceEffectiveMatcher(\n previous: JobListenerSubscription,\n candidate: JobListenerSubscription,\n): boolean {\n const previousKey = listenerMatcherSortKey(previous);\n const candidateKey = listenerMatcherSortKey(candidate);\n if (candidateKey !== previousKey) return candidateKey < previousKey;\n\n logger().warn(\n {\n jobId: candidate.jobId,\n keptSubscriptionId: previous.id,\n candidateSubscriptionId: candidate.id,\n matcherKind: candidate.kind,\n matcherOrdinal: candidate.matcherOrdinal,\n },\n 'duplicate job listener matcher key encountered; choosing deterministic subscription id order',\n );\n return candidate.id < previous.id;\n}\n"],"names":["logger","findMatchingJobListenerSubscriptions","evaluateStoredFilter","toReason","routeEventToJobListeners","params","subscriptions","workspaceId","source","event","filterErrorCount","effectiveMatchByJobId","Map","subscription","filterResult","evaluateListenerFilter","payload","kind","history","listenerFilterErrored","reason","previous","get","jobId","shouldReplaceEffectiveMatcher","set","acceptedJobCount","deliveredCount","sawTransientError","dispatchErrorCount","firstTransientError","values","disposition","listenerDisposition","result","workflows","deliverEventToJobListener","eventRef","deliveryId","provider","receivedAt","toISOString","skipped","listenerTriggered","buffered","error","listenerDispatchErrored","engagedCount","matchedJobCount","size","transientErrored","transientError","undefined","filter","config","trim","value","context","invalidReason","evaluationFailedReason","snapshot","readFilterSnapshot","filter_snapshot","Array","isArray","listenerMatcherSortKey","kindRank","matcherOrdinal","toString","padStart","candidate","previousKey","candidateKey","warn","keptSubscriptionId","id","candidateSubscriptionId","matcherKind"],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
2
|
+
export type { WorkflowsModuleClient };
|
|
3
|
+
/**
|
|
4
|
+
* Workflows declares only failures that can never succeed on retry for trigger
|
|
5
|
+
* run creation. Every other outcome is opaque and must remain retryable because
|
|
6
|
+
* it may have committed before the caller stopped waiting.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isPermanentStartRunError(error: unknown): boolean;
|
|
9
|
+
export declare function isInterpolationUnresolvableError(error: unknown): error is Extract<ReturnType<typeof startRunKnownError>, {
|
|
10
|
+
code: 'interpolation-unresolvable';
|
|
11
|
+
}>;
|
|
12
|
+
declare function startRunKnownError(error: unknown): import("@shipfox/inter-module").InterModuleKnownErrorFor<import("@shipfox/inter-module").InterModuleMethodContract<import("zod").ZodObject<{
|
|
13
|
+
workspaceId: import("zod").ZodString;
|
|
14
|
+
projectId: import("zod").ZodString;
|
|
15
|
+
definitionId: import("zod").ZodString;
|
|
16
|
+
triggerPayload: import("zod").ZodUnion<readonly [import("zod").ZodObject<{
|
|
17
|
+
provider: import("zod").ZodOptional<import("zod").ZodLiteral<"manual">>;
|
|
18
|
+
source: import("zod").ZodLiteral<"manual">;
|
|
19
|
+
event: import("zod").ZodLiteral<"fire">;
|
|
20
|
+
subscriptionId: import("zod").ZodString;
|
|
21
|
+
userId: import("zod").ZodString;
|
|
22
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
23
|
+
provider: import("zod").ZodOptional<import("zod").ZodLiteral<"cron">>;
|
|
24
|
+
source: import("zod").ZodLiteral<"cron">;
|
|
25
|
+
event: import("zod").ZodLiteral<"tick">;
|
|
26
|
+
scheduleId: import("zod").ZodString;
|
|
27
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
28
|
+
provider: import("zod").ZodString;
|
|
29
|
+
source: import("zod").ZodString;
|
|
30
|
+
event: import("zod").ZodString;
|
|
31
|
+
deliveryId: import("zod").ZodString;
|
|
32
|
+
data: import("zod").ZodUnknown;
|
|
33
|
+
}, import("zod/v4/core").$strip>]>;
|
|
34
|
+
inputs: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
|
|
35
|
+
idempotencyKey: import("zod").ZodString;
|
|
36
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
37
|
+
id: import("zod").ZodString;
|
|
38
|
+
name: import("zod").ZodString;
|
|
39
|
+
}, import("zod/v4/core").$strip>, {
|
|
40
|
+
readonly 'definition-not-found': import("zod").ZodObject<{
|
|
41
|
+
definitionId: import("zod").ZodString;
|
|
42
|
+
}, import("zod/v4/core").$strip>;
|
|
43
|
+
readonly 'project-mismatch': import("zod").ZodObject<{}, import("zod/v4/core").$strip>;
|
|
44
|
+
readonly 'agent-config-unresolvable': import("zod").ZodObject<{
|
|
45
|
+
definitionId: import("zod").ZodString;
|
|
46
|
+
}, import("zod/v4/core").$strip>;
|
|
47
|
+
readonly 'agent-integration-materialization-failed': import("zod").ZodObject<{}, import("zod/v4/core").$strip>;
|
|
48
|
+
readonly 'interpolation-unresolvable': import("zod").ZodObject<{
|
|
49
|
+
definitionId: import("zod").ZodString;
|
|
50
|
+
field: import("zod").ZodEnum<{
|
|
51
|
+
run: "run";
|
|
52
|
+
env: "env";
|
|
53
|
+
"agent.prompt": "agent.prompt";
|
|
54
|
+
"agent.model": "agent.model";
|
|
55
|
+
"agent.provider": "agent.provider";
|
|
56
|
+
"job.runner": "job.runner";
|
|
57
|
+
"job.outputs": "job.outputs";
|
|
58
|
+
"job.name": "job.name";
|
|
59
|
+
"step.name": "step.name";
|
|
60
|
+
"step.feedback": "step.feedback";
|
|
61
|
+
}>;
|
|
62
|
+
source: import("zod").ZodString;
|
|
63
|
+
envKey: import("zod").ZodOptional<import("zod").ZodString>;
|
|
64
|
+
}, import("zod/v4/core").$strip>;
|
|
65
|
+
readonly 'invalid-job-runner-labels': import("zod").ZodObject<{
|
|
66
|
+
labels: import("zod").ZodArray<import("zod").ZodString>;
|
|
67
|
+
}, import("zod/v4/core").$strip>;
|
|
68
|
+
}>> | undefined;
|
|
69
|
+
//# sourceMappingURL=workflows-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows-client.d.ts","sourceRoot":"","sources":["../../src/core/workflows-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,yCAAyC,CAAC;AAGjD,YAAY,EAAC,qBAAqB,EAAC,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,EAAE;IAAC,IAAI,EAAE,4BAA4B,CAAA;CAAC,CAAC,CAK/F;AAED,iBAAS,kBAAkB,CAAC,KAAK,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAKzC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { workflowsInterModuleContract } from '@shipfox/api-workflows-dto/inter-module';
|
|
2
|
+
import { isInterModuleKnownError } from '@shipfox/inter-module';
|
|
3
|
+
/**
|
|
4
|
+
* Workflows declares only failures that can never succeed on retry for trigger
|
|
5
|
+
* run creation. Every other outcome is opaque and must remain retryable because
|
|
6
|
+
* it may have committed before the caller stopped waiting.
|
|
7
|
+
*/ export function isPermanentStartRunError(error) {
|
|
8
|
+
return isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error);
|
|
9
|
+
}
|
|
10
|
+
export function isInterpolationUnresolvableError(error) {
|
|
11
|
+
return isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error) && error.code === 'interpolation-unresolvable';
|
|
12
|
+
}
|
|
13
|
+
function startRunKnownError(error) {
|
|
14
|
+
if (!isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error)) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
return error;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=workflows-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/workflows-client.ts"],"sourcesContent":["import {\n type WorkflowsModuleClient,\n workflowsInterModuleContract,\n} from '@shipfox/api-workflows-dto/inter-module';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\n\nexport type {WorkflowsModuleClient};\n\n/**\n * Workflows declares only failures that can never succeed on retry for trigger\n * run creation. Every other outcome is opaque and must remain retryable because\n * it may have committed before the caller stopped waiting.\n */\nexport function isPermanentStartRunError(error: unknown): boolean {\n return isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error);\n}\n\nexport function isInterpolationUnresolvableError(\n error: unknown,\n): error is Extract<ReturnType<typeof startRunKnownError>, {code: 'interpolation-unresolvable'}> {\n return (\n isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error) &&\n error.code === 'interpolation-unresolvable'\n );\n}\n\nfunction startRunKnownError(error: unknown) {\n if (!isInterModuleKnownError(workflowsInterModuleContract.methods.startRunFromTrigger, error)) {\n return undefined;\n }\n return error;\n}\n"],"names":["workflowsInterModuleContract","isInterModuleKnownError","isPermanentStartRunError","error","methods","startRunFromTrigger","isInterpolationUnresolvableError","code","startRunKnownError","undefined"],"mappings":"AAAA,SAEEA,4BAA4B,QACvB,0CAA0C;AACjD,SAAQC,uBAAuB,QAAO,wBAAwB;AAI9D;;;;CAIC,GACD,OAAO,SAASC,yBAAyBC,KAAc;IACrD,OAAOF,wBAAwBD,6BAA6BI,OAAO,CAACC,mBAAmB,EAAEF;AAC3F;AAEA,OAAO,SAASG,iCACdH,KAAc;IAEd,OACEF,wBAAwBD,6BAA6BI,OAAO,CAACC,mBAAmB,EAAEF,UAClFA,MAAMI,IAAI,KAAK;AAEnB;AAEA,SAASC,mBAAmBL,KAAc;IACxC,IAAI,CAACF,wBAAwBD,6BAA6BI,OAAO,CAACC,mBAAmB,EAAEF,QAAQ;QAC7F,OAAOM;IACT;IACA,OAAON;AACT"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
1
2
|
import { type ShipfoxModule } from '@shipfox/node-module';
|
|
2
3
|
export type { JobListenerMatcherKind, JobListenerSubscription, } from '#core/entities/job-listener-subscription.js';
|
|
3
4
|
export type { TriggerSubscription } from '#core/entities/subscription.js';
|
|
4
5
|
export { fireCronSubscription, fireManualSubscription, ManualTriggerNotFoundError, TriggerSubscriptionNotCronError, TriggerSubscriptionNotFoundError, TriggerSubscriptionNotManualError, TriggerWorkspaceMismatchError, } from '#core/index.js';
|
|
5
6
|
export { db, findMatchingJobListenerSubscriptions, findMatchingSubscriptions, getManualSubscriptionByDefinitionId, getTriggerSubscriptionById, jobListenerSubscriptions, listSubscriptionsByWorkflowDefinitionIds, migrationsPath, projectJobListenerSubscriptions, removeJobListenerSubscriptionsForJob, triggersOutbox, } from '#db/index.js';
|
|
6
|
-
export
|
|
7
|
+
export interface CreateTriggersModuleOptions {
|
|
8
|
+
workflows: WorkflowsModuleClient;
|
|
9
|
+
}
|
|
10
|
+
export declare function createTriggersModule({ workflows }: CreateTriggersModuleOptions): ShipfoxModule;
|
|
7
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,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,
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ 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 {
|
|
10
|
-
import { onDefinitionDeleted, onDefinitionResolved,
|
|
9
|
+
import { createTriggerRoutes } from '#presentation/index.js';
|
|
10
|
+
import { createOnIntegrationEventReceived, onDefinitionDeleted, onDefinitionResolved, onJobActivated, onJobTerminated } from '#presentation/subscribers/index.js';
|
|
11
11
|
import { createTriggersCronActivities, createTriggersMaintenanceActivities } from '#temporal/activities/index.js';
|
|
12
12
|
import { TRIGGERS_CRON_TASK_QUEUE, TRIGGERS_MAINTENANCE_TASK_QUEUE } from '#temporal/constants.js';
|
|
13
13
|
export { fireCronSubscription, fireManualSubscription, ManualTriggerNotFoundError, TriggerSubscriptionNotCronError, TriggerSubscriptionNotFoundError, TriggerSubscriptionNotManualError, TriggerWorkspaceMismatchError } from '#core/index.js';
|
|
@@ -15,54 +15,56 @@ export { db, findMatchingJobListenerSubscriptions, findMatchingSubscriptions, ge
|
|
|
15
15
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
16
|
const temporalWorkflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');
|
|
17
17
|
const subscriber = subscriberFactory();
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
routes,
|
|
25
|
-
metrics: registerTriggersServiceMetrics,
|
|
26
|
-
publishers: [
|
|
27
|
-
{
|
|
28
|
-
name: 'triggers',
|
|
29
|
-
table: triggersOutbox,
|
|
30
|
-
db
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
subscribers: [
|
|
34
|
-
subscriber(DEFINITION_RESOLVED, onDefinitionResolved),
|
|
35
|
-
subscriber(DEFINITION_DELETED, onDefinitionDeleted),
|
|
36
|
-
subscriber(INTEGRATION_EVENT_RECEIVED, onIntegrationEventReceived),
|
|
37
|
-
subscriber(WORKFLOWS_JOB_ACTIVATED, onJobActivated),
|
|
38
|
-
subscriber(WORKFLOWS_JOB_TERMINATED, onJobTerminated)
|
|
39
|
-
],
|
|
40
|
-
workers: [
|
|
41
|
-
{
|
|
42
|
-
taskQueue: TRIGGERS_MAINTENANCE_TASK_QUEUE,
|
|
43
|
-
workflowsPath: temporalWorkflowsPath,
|
|
44
|
-
activities: createTriggersMaintenanceActivities,
|
|
45
|
-
workflows: [
|
|
46
|
-
{
|
|
47
|
-
name: 'pruneTriggerEventsCron',
|
|
48
|
-
id: 'triggers-prune-trigger-events',
|
|
49
|
-
cronSchedule: '0 * * * *'
|
|
50
|
-
}
|
|
51
|
-
]
|
|
18
|
+
export function createTriggersModule({ workflows }) {
|
|
19
|
+
return {
|
|
20
|
+
name: 'triggers',
|
|
21
|
+
database: {
|
|
22
|
+
db,
|
|
23
|
+
migrationsPath
|
|
52
24
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
25
|
+
routes: createTriggerRoutes(workflows),
|
|
26
|
+
metrics: registerTriggersServiceMetrics,
|
|
27
|
+
publishers: [
|
|
28
|
+
{
|
|
29
|
+
name: 'triggers',
|
|
30
|
+
table: triggersOutbox,
|
|
31
|
+
db
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
subscribers: [
|
|
35
|
+
subscriber(DEFINITION_RESOLVED, onDefinitionResolved),
|
|
36
|
+
subscriber(DEFINITION_DELETED, onDefinitionDeleted),
|
|
37
|
+
subscriber(INTEGRATION_EVENT_RECEIVED, createOnIntegrationEventReceived(workflows)),
|
|
38
|
+
subscriber(WORKFLOWS_JOB_ACTIVATED, onJobActivated),
|
|
39
|
+
subscriber(WORKFLOWS_JOB_TERMINATED, onJobTerminated)
|
|
40
|
+
],
|
|
41
|
+
workers: [
|
|
42
|
+
{
|
|
43
|
+
taskQueue: TRIGGERS_MAINTENANCE_TASK_QUEUE,
|
|
44
|
+
workflowsPath: temporalWorkflowsPath,
|
|
45
|
+
activities: createTriggersMaintenanceActivities,
|
|
46
|
+
workflows: [
|
|
47
|
+
{
|
|
48
|
+
name: 'pruneTriggerEventsCron',
|
|
49
|
+
id: 'triggers-prune-trigger-events',
|
|
50
|
+
cronSchedule: '0 * * * *'
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
taskQueue: TRIGGERS_CRON_TASK_QUEUE,
|
|
56
|
+
workflowsPath: temporalWorkflowsPath,
|
|
57
|
+
activities: ()=>createTriggersCronActivities(workflows),
|
|
58
|
+
workflows: [
|
|
59
|
+
{
|
|
60
|
+
name: 'cronTickCron',
|
|
61
|
+
id: 'triggers-cron-tick',
|
|
62
|
+
cronSchedule: '* * * * *'
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
67
69
|
|
|
68
70
|
//# sourceMappingURL=index.js.map
|
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 ShipfoxModule, subscriberFactory} from '@shipfox/node-module';\nimport {db, migrationsPath, triggersOutbox} from '#db/index.js';\nimport {registerTriggersServiceMetrics} from '#metrics/index.js';\nimport {
|
|
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,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { onDefinitionDeleted, onDefinitionResolved,
|
|
1
|
+
export { createTriggerRoutes } from './routes/index.js';
|
|
2
|
+
export { createOnIntegrationEventReceived, onDefinitionDeleted, onDefinitionResolved, } from './subscribers/index.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,gCAAgC,EAChC,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { onDefinitionDeleted, onDefinitionResolved
|
|
1
|
+
export { createTriggerRoutes } from './routes/index.js';
|
|
2
|
+
export { createOnIntegrationEventReceived, onDefinitionDeleted, onDefinitionResolved } from './subscribers/index.js';
|
|
3
3
|
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/presentation/index.ts"],"sourcesContent":["export {
|
|
1
|
+
{"version":3,"sources":["../../src/presentation/index.ts"],"sourcesContent":["export {createTriggerRoutes} from './routes/index.js';\nexport {\n createOnIntegrationEventReceived,\n onDefinitionDeleted,\n onDefinitionResolved,\n} from './subscribers/index.js';\n"],"names":["createTriggerRoutes","createOnIntegrationEventReceived","onDefinitionDeleted","onDefinitionResolved"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,oBAAoB;AACtD,SACEC,gCAAgC,EAChCC,mBAAmB,EACnBC,oBAAoB,QACf,yBAAyB"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
import type { WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
2
|
+
export declare function createFireManualTriggerRoute(workflows: WorkflowsModuleClient): import("@shipfox/node-fastify").RouteDefinition;
|
|
2
3
|
//# sourceMappingURL=fire-manual.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fire-manual.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/fire-manual.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fire-manual.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/fire-manual.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAQnF,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,qBAAqB,mDAgE5E"}
|
|
@@ -1,71 +1,74 @@
|
|
|
1
1
|
import { requireUserContext } from '@shipfox/api-auth-context';
|
|
2
2
|
import { fireManualTriggerBodySchema, fireManualTriggerResponseSchema } from '@shipfox/api-triggers-dto';
|
|
3
|
-
import { InterpolationUnresolvableError } from '@shipfox/api-workflows';
|
|
4
3
|
import { ClientError, defineRoute } from '@shipfox/node-fastify';
|
|
5
4
|
import { z } from 'zod';
|
|
6
5
|
import { ManualTriggerNotFoundError } from '#core/errors.js';
|
|
7
6
|
import { fireManualSubscription } from '#core/fire-manual.js';
|
|
7
|
+
import { isInterpolationUnresolvableError } from '#core/workflows-client.js';
|
|
8
8
|
import { getManualSubscriptionByDefinitionId } from '#db/subscriptions.js';
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
export function createFireManualTriggerRoute(workflows) {
|
|
10
|
+
return defineRoute({
|
|
11
|
+
method: 'POST',
|
|
12
|
+
path: '/:definitionId/fire-manual',
|
|
13
|
+
description: 'Fire the manual trigger of a workflow definition, creating a workflow run.',
|
|
14
|
+
schema: {
|
|
15
|
+
params: z.object({
|
|
16
|
+
definitionId: z.string().uuid()
|
|
17
|
+
}),
|
|
18
|
+
body: fireManualTriggerBodySchema,
|
|
19
|
+
response: {
|
|
20
|
+
201: fireManualTriggerResponseSchema,
|
|
21
|
+
422: z.object({
|
|
22
|
+
code: z.string(),
|
|
23
|
+
details: z.object({
|
|
24
|
+
field: z.string(),
|
|
25
|
+
source: z.string(),
|
|
26
|
+
env_key: z.string().optional()
|
|
27
|
+
})
|
|
26
28
|
})
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
errorHandler: (error)=>{
|
|
32
|
+
if (error instanceof ManualTriggerNotFoundError) {
|
|
33
|
+
throw new ClientError(error.message, 'manual-trigger-not-found', {
|
|
34
|
+
status: 404
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (isInterpolationUnresolvableError(error)) {
|
|
38
|
+
throw new ClientError('Workflow interpolation cannot be resolved', 'workflow-interpolation-unresolvable', {
|
|
39
|
+
status: 422,
|
|
40
|
+
details: {
|
|
41
|
+
field: error.details.field,
|
|
42
|
+
source: error.details.source,
|
|
43
|
+
...error.details.envKey === undefined ? {} : {
|
|
44
|
+
env_key: error.details.envKey
|
|
45
|
+
}
|
|
44
46
|
}
|
|
45
|
-
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
},
|
|
51
|
+
handler: async (request, reply)=>{
|
|
52
|
+
const { definitionId } = request.params;
|
|
53
|
+
const userContext = requireUserContext(request);
|
|
54
|
+
const subscription = await getManualSubscriptionByDefinitionId(definitionId);
|
|
55
|
+
// 404 covers both "no such manual trigger" and "not your workspace" to avoid leaking existence.
|
|
56
|
+
if (!subscription || !userContext.canAccess(subscription.workspaceId)) {
|
|
57
|
+
throw new ManualTriggerNotFoundError(definitionId);
|
|
58
|
+
}
|
|
59
|
+
const run = await fireManualSubscription({
|
|
60
|
+
workflows,
|
|
61
|
+
subscriptionId: subscription.id,
|
|
62
|
+
callerWorkspaceId: subscription.workspaceId,
|
|
63
|
+
userId: userContext.userId,
|
|
64
|
+
inputs: request.body.inputs
|
|
46
65
|
});
|
|
66
|
+
reply.status(201);
|
|
67
|
+
return {
|
|
68
|
+
workflow_run_id: run.id
|
|
69
|
+
};
|
|
47
70
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
handler: async (request, reply)=>{
|
|
51
|
-
const { definitionId } = request.params;
|
|
52
|
-
const userContext = requireUserContext(request);
|
|
53
|
-
const subscription = await getManualSubscriptionByDefinitionId(definitionId);
|
|
54
|
-
// 404 covers both "no such manual trigger" and "not your workspace" to avoid leaking existence.
|
|
55
|
-
if (!subscription || !userContext.canAccess(subscription.workspaceId)) {
|
|
56
|
-
throw new ManualTriggerNotFoundError(definitionId);
|
|
57
|
-
}
|
|
58
|
-
const run = await fireManualSubscription({
|
|
59
|
-
subscriptionId: subscription.id,
|
|
60
|
-
callerWorkspaceId: subscription.workspaceId,
|
|
61
|
-
userId: userContext.userId,
|
|
62
|
-
inputs: request.body.inputs
|
|
63
|
-
});
|
|
64
|
-
reply.status(201);
|
|
65
|
-
return {
|
|
66
|
-
workflow_run_id: run.id
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
70
73
|
|
|
71
74
|
//# sourceMappingURL=fire-manual.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/fire-manual.ts"],"sourcesContent":["import {requireUserContext} from '@shipfox/api-auth-context';\nimport {\n fireManualTriggerBodySchema,\n fireManualTriggerResponseSchema,\n} from '@shipfox/api-triggers-dto';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/fire-manual.ts"],"sourcesContent":["import {requireUserContext} from '@shipfox/api-auth-context';\nimport {\n fireManualTriggerBodySchema,\n fireManualTriggerResponseSchema,\n} from '@shipfox/api-triggers-dto';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {ManualTriggerNotFoundError} from '#core/errors.js';\nimport {fireManualSubscription} from '#core/fire-manual.js';\nimport {isInterpolationUnresolvableError} from '#core/workflows-client.js';\nimport {getManualSubscriptionByDefinitionId} from '#db/subscriptions.js';\n\nexport function createFireManualTriggerRoute(workflows: WorkflowsModuleClient) {\n return defineRoute({\n method: 'POST',\n path: '/:definitionId/fire-manual',\n description: 'Fire the manual trigger of a workflow definition, creating a workflow run.',\n schema: {\n params: z.object({\n definitionId: z.string().uuid(),\n }),\n body: fireManualTriggerBodySchema,\n response: {\n 201: fireManualTriggerResponseSchema,\n 422: z.object({\n code: z.string(),\n details: z.object({\n field: z.string(),\n source: z.string(),\n env_key: z.string().optional(),\n }),\n }),\n },\n },\n errorHandler: (error) => {\n if (error instanceof ManualTriggerNotFoundError) {\n throw new ClientError(error.message, 'manual-trigger-not-found', {status: 404});\n }\n if (isInterpolationUnresolvableError(error)) {\n throw new ClientError(\n 'Workflow interpolation cannot be resolved',\n 'workflow-interpolation-unresolvable',\n {\n status: 422,\n details: {\n field: error.details.field,\n source: error.details.source,\n ...(error.details.envKey === undefined ? {} : {env_key: error.details.envKey}),\n },\n },\n );\n }\n throw error;\n },\n handler: async (request, reply) => {\n const {definitionId} = request.params;\n const userContext = requireUserContext(request);\n\n const subscription = await getManualSubscriptionByDefinitionId(definitionId);\n // 404 covers both \"no such manual trigger\" and \"not your workspace\" to avoid leaking existence.\n if (!subscription || !userContext.canAccess(subscription.workspaceId)) {\n throw new ManualTriggerNotFoundError(definitionId);\n }\n\n const run = await fireManualSubscription({\n workflows,\n subscriptionId: subscription.id,\n callerWorkspaceId: subscription.workspaceId,\n userId: userContext.userId,\n inputs: request.body.inputs,\n });\n\n reply.status(201);\n return {workflow_run_id: run.id};\n },\n });\n}\n"],"names":["requireUserContext","fireManualTriggerBodySchema","fireManualTriggerResponseSchema","ClientError","defineRoute","z","ManualTriggerNotFoundError","fireManualSubscription","isInterpolationUnresolvableError","getManualSubscriptionByDefinitionId","createFireManualTriggerRoute","workflows","method","path","description","schema","params","object","definitionId","string","uuid","body","response","code","details","field","source","env_key","optional","errorHandler","error","message","status","envKey","undefined","handler","request","reply","userContext","subscription","canAccess","workspaceId","run","subscriptionId","id","callerWorkspaceId","userId","inputs","workflow_run_id"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,4BAA4B;AAC7D,SACEC,2BAA2B,EAC3BC,+BAA+B,QAC1B,4BAA4B;AAEnC,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,0BAA0B,QAAO,kBAAkB;AAC3D,SAAQC,sBAAsB,QAAO,uBAAuB;AAC5D,SAAQC,gCAAgC,QAAO,4BAA4B;AAC3E,SAAQC,mCAAmC,QAAO,uBAAuB;AAEzE,OAAO,SAASC,6BAA6BC,SAAgC;IAC3E,OAAOP,YAAY;QACjBQ,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,QAAQX,EAAEY,MAAM,CAAC;gBACfC,cAAcb,EAAEc,MAAM,GAAGC,IAAI;YAC/B;YACAC,MAAMpB;YACNqB,UAAU;gBACR,KAAKpB;gBACL,KAAKG,EAAEY,MAAM,CAAC;oBACZM,MAAMlB,EAAEc,MAAM;oBACdK,SAASnB,EAAEY,MAAM,CAAC;wBAChBQ,OAAOpB,EAAEc,MAAM;wBACfO,QAAQrB,EAAEc,MAAM;wBAChBQ,SAAStB,EAAEc,MAAM,GAAGS,QAAQ;oBAC9B;gBACF;YACF;QACF;QACAC,cAAc,CAACC;YACb,IAAIA,iBAAiBxB,4BAA4B;gBAC/C,MAAM,IAAIH,YAAY2B,MAAMC,OAAO,EAAE,4BAA4B;oBAACC,QAAQ;gBAAG;YAC/E;YACA,IAAIxB,iCAAiCsB,QAAQ;gBAC3C,MAAM,IAAI3B,YACR,6CACA,uCACA;oBACE6B,QAAQ;oBACRR,SAAS;wBACPC,OAAOK,MAAMN,OAAO,CAACC,KAAK;wBAC1BC,QAAQI,MAAMN,OAAO,CAACE,MAAM;wBAC5B,GAAII,MAAMN,OAAO,CAACS,MAAM,KAAKC,YAAY,CAAC,IAAI;4BAACP,SAASG,MAAMN,OAAO,CAACS,MAAM;wBAAA,CAAC;oBAC/E;gBACF;YAEJ;YACA,MAAMH;QACR;QACAK,SAAS,OAAOC,SAASC;YACvB,MAAM,EAACnB,YAAY,EAAC,GAAGkB,QAAQpB,MAAM;YACrC,MAAMsB,cAActC,mBAAmBoC;YAEvC,MAAMG,eAAe,MAAM9B,oCAAoCS;YAC/D,gGAAgG;YAChG,IAAI,CAACqB,gBAAgB,CAACD,YAAYE,SAAS,CAACD,aAAaE,WAAW,GAAG;gBACrE,MAAM,IAAInC,2BAA2BY;YACvC;YAEA,MAAMwB,MAAM,MAAMnC,uBAAuB;gBACvCI;gBACAgC,gBAAgBJ,aAAaK,EAAE;gBAC/BC,mBAAmBN,aAAaE,WAAW;gBAC3CK,QAAQR,YAAYQ,MAAM;gBAC1BC,QAAQX,QAAQf,IAAI,CAAC0B,MAAM;YAC7B;YAEAV,MAAML,MAAM,CAAC;YACb,OAAO;gBAACgB,iBAAiBN,IAAIE,EAAE;YAAA;QACjC;IACF;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
1
2
|
import type { RouteGroup } from '@shipfox/node-fastify';
|
|
2
|
-
export declare
|
|
3
|
+
export declare function createTriggerRoutes(workflows: WorkflowsModuleClient): RouteGroup[];
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAMtD,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AACnF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAMtD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,qBAAqB,GAAG,UAAU,EAAE,CAelF"}
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { AUTH_USER } from '@shipfox/api-auth-context';
|
|
2
|
-
import {
|
|
2
|
+
import { createFireManualTriggerRoute } from './fire-manual.js';
|
|
3
3
|
import { getTriggerEventRoute } from './get-trigger-event.js';
|
|
4
4
|
import { listTriggerEventFacetsRoute } from './list-trigger-event-facets.js';
|
|
5
5
|
import { listTriggerEventsRoute } from './list-trigger-events.js';
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
export function createTriggerRoutes(workflows) {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
prefix: '/workflow-definitions',
|
|
10
|
+
auth: AUTH_USER,
|
|
11
|
+
routes: [
|
|
12
|
+
createFireManualTriggerRoute(workflows)
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
// The static /facets path is matched ahead of the /:id detail route by Fastify's
|
|
17
|
+
// radix router, so registration order does not affect resolution.
|
|
18
|
+
prefix: '/trigger-events',
|
|
19
|
+
auth: AUTH_USER,
|
|
20
|
+
routes: [
|
|
21
|
+
listTriggerEventFacetsRoute,
|
|
22
|
+
listTriggerEventsRoute,
|
|
23
|
+
getTriggerEventRoute
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
}
|
|
26
28
|
|
|
27
29
|
//# sourceMappingURL=index.js.map
|