@shipfox/api-workflows 12.6.0 → 12.7.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,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 124 files with swc (791.43ms)
3
- 2026-08-10T11:40:58.465Z [INFO] asset workflow-bundle-a5487a6112facdf4dd9d.js 3.32 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 124 files with swc (817.5ms)
3
+ 2026-08-10T13:04:49.694Z [INFO] asset workflow-bundle-a5487a6112facdf4dd9d.js 3.32 MiB [emitted] [immutable] (name: main)
4
4
  orphan modules 33.5 KiB [orphan] 21 modules
5
5
  runtime modules 1.13 KiB 5 modules
6
6
  modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
@@ -16,6 +16,6 @@ optional modules 30 bytes [optional]
16
16
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
17
17
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
18
18
  ../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
19
- webpack 5.107.2 compiled successfully in 8919 ms
20
- 2026-08-10T11:40:58.506Z [INFO] Workflow bundle created { size: '3.32MB' }
19
+ webpack 5.107.2 compiled successfully in 11308 ms
20
+ 2026-08-10T13:04:49.735Z [INFO] Workflow bundle created { size: '3.32MB' }
21
21
  /home/runner/work/shipfox/shipfox/libs/api/workflows/dist/temporal/workflows/index.js: 3476109 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @shipfox/api-workflows
2
2
 
3
+ ## 12.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4df5e37: Workflow run list items and run detail now carry `has_started_job_execution`, reporting whether any
8
+ job execution of the attempt reached a runner. Run surfaces no longer show a client-derived `Queued`
9
+ state: the run list and run detail present the API attempt status and duration, and read the new
10
+ field to label a finished run's duration as run or elapsed time.
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [4df5e37]
15
+ - @shipfox/api-workflows-dto@12.7.0
16
+
3
17
  ## 12.6.0
4
18
 
5
19
  ### Minor Changes
@@ -79,5 +79,8 @@ export interface WorkflowRunDetail extends WorkflowRun {
79
79
  runAttempt: WorkflowRunAttempt;
80
80
  latestAttempt: number;
81
81
  jobs: WorkflowJobDetail[];
82
+ /** Whether any job execution of this attempt reached its runner, decided here so the detail
83
+ * and the list cannot answer it differently. */
84
+ hasStartedJobExecution: boolean;
82
85
  }
83
86
  //# sourceMappingURL=workflow-run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run.d.ts","sourceRoot":"","sources":["../../../src/core/entities/workflow-run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-run.d.ts","sourceRoot":"","sources":["../../../src/core/entities/workflow-run.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/entities/workflow-run.ts"],"sourcesContent":["import type {Job} from './job.js';\nimport type {JobExecution} from './job-execution.js';\nimport type {Step, StepAttempt} from './step.js';\nimport type {WorkflowRunAttempt} from './workflow-run-attempt.js';\n\nexport type WorkflowRunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';\n\nexport type TerminalWorkflowRunStatus = Extract<\n WorkflowRunStatus,\n 'succeeded' | 'failed' | 'cancelled'\n>;\n\nconst TERMINAL_WORKFLOW_RUN_STATUSES = new Set<WorkflowRunStatus>([\n 'succeeded',\n 'failed',\n 'cancelled',\n]);\n\nexport function isWorkflowRunTerminal(\n status: WorkflowRunStatus,\n): status is TerminalWorkflowRunStatus {\n return TERMINAL_WORKFLOW_RUN_STATUSES.has(status);\n}\n\nexport interface WorkflowRunTriggerReference {\n project: {id: string} | null;\n repository: string | null;\n ref: string | null;\n commit: string | null;\n actor: string | null;\n}\n\nexport interface WorkflowSourceSnapshot {\n content: string;\n format: 'yaml';\n}\n\nexport type TriggerPayload =\n | {\n source: 'manual';\n provider?: 'manual' | undefined;\n event: 'fire';\n subscriptionId: string;\n userId: string;\n }\n | {\n source: 'cron';\n provider?: 'cron' | undefined;\n event: 'tick';\n scheduleId: string;\n }\n // Integration sources (github, gitlab, sentry, …) flow through opaquely: the\n // run records what fired it and carries the raw event payload, without the\n // triggers module having to know each source's shape.\n | {\n source: string;\n provider?: string | undefined;\n event: string;\n deliveryId: string;\n data: unknown;\n };\n\nexport interface WorkflowRun {\n id: string;\n workspaceId: string;\n projectId: string;\n definitionId: string;\n number: number;\n /** Effective runtime name: the resolved override, or workflowName when absent. */\n name: string;\n /** Static workflow-name snapshot preserved from the definition at creation. */\n workflowName: string;\n /** Nullable resolved override retained for rerun fidelity. */\n nameOverride: string | null;\n status: WorkflowRunStatus;\n currentAttempt: number;\n triggerProvider: string | null;\n triggerSource: string;\n triggerEvent: string;\n triggerPayload: TriggerPayload;\n /** Provider-neutral trigger facts captured at run creation, when available. */\n triggerReference?: WorkflowRunTriggerReference | null | undefined;\n inputs: Record<string, unknown> | null;\n sourceSnapshot: WorkflowSourceSnapshot | null;\n triggerIdempotencyKey: string | null;\n timeoutMs: number;\n version: number;\n createdAt: Date;\n updatedAt: Date;\n startedAt: Date | null;\n finishedAt: Date | null;\n}\n\nexport interface StepDetail extends Step {\n attempts: StepAttempt[];\n}\n\nexport interface JobExecutionDetail extends JobExecution {\n steps: StepDetail[];\n}\n\nexport interface WorkflowJobDetail extends Job {\n jobExecutions: JobExecutionDetail[];\n}\n\nexport interface WorkflowRunDetail extends WorkflowRun {\n runAttempt: WorkflowRunAttempt;\n latestAttempt: number;\n jobs: WorkflowJobDetail[];\n}\n"],"names":["TERMINAL_WORKFLOW_RUN_STATUSES","Set","isWorkflowRunTerminal","status","has"],"mappings":"AAYA,MAAMA,iCAAiC,IAAIC,IAAuB;IAChE;IACA;IACA;CACD;AAED,OAAO,SAASC,sBACdC,MAAyB;IAEzB,OAAOH,+BAA+BI,GAAG,CAACD;AAC5C"}
1
+ {"version":3,"sources":["../../../src/core/entities/workflow-run.ts"],"sourcesContent":["import type {Job} from './job.js';\nimport type {JobExecution} from './job-execution.js';\nimport type {Step, StepAttempt} from './step.js';\nimport type {WorkflowRunAttempt} from './workflow-run-attempt.js';\n\nexport type WorkflowRunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';\n\nexport type TerminalWorkflowRunStatus = Extract<\n WorkflowRunStatus,\n 'succeeded' | 'failed' | 'cancelled'\n>;\n\nconst TERMINAL_WORKFLOW_RUN_STATUSES = new Set<WorkflowRunStatus>([\n 'succeeded',\n 'failed',\n 'cancelled',\n]);\n\nexport function isWorkflowRunTerminal(\n status: WorkflowRunStatus,\n): status is TerminalWorkflowRunStatus {\n return TERMINAL_WORKFLOW_RUN_STATUSES.has(status);\n}\n\nexport interface WorkflowRunTriggerReference {\n project: {id: string} | null;\n repository: string | null;\n ref: string | null;\n commit: string | null;\n actor: string | null;\n}\n\nexport interface WorkflowSourceSnapshot {\n content: string;\n format: 'yaml';\n}\n\nexport type TriggerPayload =\n | {\n source: 'manual';\n provider?: 'manual' | undefined;\n event: 'fire';\n subscriptionId: string;\n userId: string;\n }\n | {\n source: 'cron';\n provider?: 'cron' | undefined;\n event: 'tick';\n scheduleId: string;\n }\n // Integration sources (github, gitlab, sentry, …) flow through opaquely: the\n // run records what fired it and carries the raw event payload, without the\n // triggers module having to know each source's shape.\n | {\n source: string;\n provider?: string | undefined;\n event: string;\n deliveryId: string;\n data: unknown;\n };\n\nexport interface WorkflowRun {\n id: string;\n workspaceId: string;\n projectId: string;\n definitionId: string;\n number: number;\n /** Effective runtime name: the resolved override, or workflowName when absent. */\n name: string;\n /** Static workflow-name snapshot preserved from the definition at creation. */\n workflowName: string;\n /** Nullable resolved override retained for rerun fidelity. */\n nameOverride: string | null;\n status: WorkflowRunStatus;\n currentAttempt: number;\n triggerProvider: string | null;\n triggerSource: string;\n triggerEvent: string;\n triggerPayload: TriggerPayload;\n /** Provider-neutral trigger facts captured at run creation, when available. */\n triggerReference?: WorkflowRunTriggerReference | null | undefined;\n inputs: Record<string, unknown> | null;\n sourceSnapshot: WorkflowSourceSnapshot | null;\n triggerIdempotencyKey: string | null;\n timeoutMs: number;\n version: number;\n createdAt: Date;\n updatedAt: Date;\n startedAt: Date | null;\n finishedAt: Date | null;\n}\n\nexport interface StepDetail extends Step {\n attempts: StepAttempt[];\n}\n\nexport interface JobExecutionDetail extends JobExecution {\n steps: StepDetail[];\n}\n\nexport interface WorkflowJobDetail extends Job {\n jobExecutions: JobExecutionDetail[];\n}\n\nexport interface WorkflowRunDetail extends WorkflowRun {\n runAttempt: WorkflowRunAttempt;\n latestAttempt: number;\n jobs: WorkflowJobDetail[];\n /** Whether any job execution of this attempt reached its runner, decided here so the detail\n * and the list cannot answer it differently. */\n hasStartedJobExecution: boolean;\n}\n"],"names":["TERMINAL_WORKFLOW_RUN_STATUSES","Set","isWorkflowRunTerminal","status","has"],"mappings":"AAYA,MAAMA,iCAAiC,IAAIC,IAAuB;IAChE;IACA;IACA;CACD;AAED,OAAO,SAASC,sBACdC,MAAyB;IAEzB,OAAOH,+BAA+BI,GAAG,CAACD;AAC5C"}
@@ -79,7 +79,8 @@ export interface WorkflowRunJobSummaryTarget {
79
79
  currentAttempt: number;
80
80
  }
81
81
  /**
82
- * A page row's jobs: a bounded slice to draw, and totals describing all of them.
82
+ * A page row's jobs: a bounded slice to draw, totals describing all of them, and whether any
83
+ * execution has reached a runner.
83
84
  *
84
85
  * The preview is what a row can show; `statusCounts` is what it can say. Keeping the counts
85
86
  * server-side is what lets a row report a failure that sits past the preview. Counts use the
@@ -91,6 +92,7 @@ export interface WorkflowRunJobsSummary {
91
92
  preview: WorkflowRunJobSummary[];
92
93
  statusCounts: WorkflowRunJobStatusCount[];
93
94
  rawStatusCounts: WorkflowRunJobRawStatusCount[];
95
+ hasStartedJobExecution: boolean;
94
96
  }
95
97
  export interface WorkflowRunJobStatusCount {
96
98
  status: JobStatus | 'listening';
@@ -116,8 +118,8 @@ export interface WorkflowRunJobRawStatusCount {
116
118
  * attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip
117
119
  * contradicts.
118
120
  *
119
- * The two reads share one repeatable-read snapshot. They describe the same jobs at the same
120
- * instant, and the strip combines them into a single glyph row, so under the default
121
+ * The reads share one repeatable-read snapshot. They describe the same jobs and executions at
122
+ * the same instant, and the strip combines them into a single glyph row, so under the default
121
123
  * read-committed isolation a job settling between the statements would draw a pending glyph
122
124
  * beside a summary counting it as failed. Sequential inside one transaction is the cost of
123
125
  * that; at a four-second poll the extra round trip does not register.
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/queries.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/queries.ts"],"names":[],"mappings":"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"}
@@ -107,8 +107,8 @@ export async function listWorkflowRuns(params) {
107
107
  * attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip
108
108
  * contradicts.
109
109
  *
110
- * The two reads share one repeatable-read snapshot. They describe the same jobs at the same
111
- * instant, and the strip combines them into a single glyph row, so under the default
110
+ * The reads share one repeatable-read snapshot. They describe the same jobs and executions at
111
+ * the same instant, and the strip combines them into a single glyph row, so under the default
112
112
  * read-committed isolation a job settling between the statements would draw a pending glyph
113
113
  * beside a summary counting it as failed. Sequential inside one transaction is the cost of
114
114
  * that; at a four-second poll the extra round trip does not register.
@@ -142,6 +142,14 @@ export async function listWorkflowRuns(params) {
142
142
  position: jobs.position,
143
143
  jobRank: sql`row_number() over (partition by ${workflowRunAttempts.workflowRunId} order by ${jobs.position} asc, ${jobs.id} asc)`.as('job_rank')
144
144
  }).from(jobs).innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id)).leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id)).where(attemptFilter).as('ranked');
145
+ // Correlated per job rather than a grouped scan of `job_executions`: an aggregate over the
146
+ // whole table cannot have the page's filter pushed into it, so it would read every execution
147
+ // ever recorded on each poll and grow with history rather than with the page.
148
+ const hasStartedJobExecution = sql`bool_or(exists (
149
+ select 1
150
+ from ${jobExecutions}
151
+ where ${jobExecutions.jobId} = ${jobs.id} and ${jobExecutions.startedAt} is not null
152
+ ))`;
145
153
  const executionDisplayStatus = sql`
146
154
  ${selectedExecution.executionStatus}
147
155
  `;
@@ -169,7 +177,8 @@ export async function listWorkflowRuns(params) {
169
177
  workflowRunId: workflowRunAttempts.workflowRunId,
170
178
  rawStatus: jobs.status,
171
179
  status: displayStatus,
172
- count: count()
180
+ count: count(),
181
+ hasStartedJobExecution
173
182
  }).from(jobs).innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id)).leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id)).where(attemptFilter).groupBy(workflowRunAttempts.workflowRunId, jobs.status, displayStatus)
174
183
  };
175
184
  }, {
@@ -179,10 +188,12 @@ export async function listWorkflowRuns(params) {
179
188
  for (const { workflowRunId, ...summary } of previewRows){
180
189
  summaryFor(summaries, workflowRunId).preview.push(summary);
181
190
  }
182
- for (const { workflowRunId, rawStatus, status, count: statusCount } of countRows){
191
+ for (const { workflowRunId, rawStatus, status, count: statusCount, hasStartedJobExecution } of countRows){
183
192
  const summary = summaryFor(summaries, workflowRunId);
184
193
  appendStatusCount(summary.rawStatusCounts, rawStatus, statusCount);
185
194
  appendStatusCount(summary.statusCounts, status, statusCount);
195
+ // One row per (run, verdict, display status), so the run's answer is the OR of its groups.
196
+ summary.hasStartedJobExecution ||= hasStartedJobExecution;
186
197
  }
187
198
  return summaries;
188
199
  }
@@ -192,7 +203,8 @@ function summaryFor(summaries, workflowRunId) {
192
203
  const created = {
193
204
  preview: [],
194
205
  statusCounts: [],
195
- rawStatusCounts: []
206
+ rawStatusCounts: [],
207
+ hasStartedJobExecution: false
196
208
  };
197
209
  summaries.set(workflowRunId, created);
198
210
  return created;
@@ -322,7 +334,9 @@ function hydrateWorkflowRunDetail(rows, attempt, latestAttempt) {
322
334
  ...toWorkflowRun(first.run),
323
335
  runAttempt: toWorkflowRunAttempt(attempt),
324
336
  latestAttempt,
325
- jobs: []
337
+ jobs: [],
338
+ // Read off the same rows the executions come from, so the flag cannot contradict them.
339
+ hasStartedJobExecution: rows.some((row)=>row.jobExecution?.startedAt != null)
326
340
  };
327
341
  const jobById = new Map();
328
342
  const jobExecutionById = new Map();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/db/workflow-runs/queries.ts"],"sourcesContent":["import {WORKFLOW_RUN_JOB_PREVIEW_LIMIT} from '@shipfox/api-workflows-dto';\nimport {\n paginateTimestampIdRows,\n type TimestampIdCursor,\n timestampIdCursorWhere,\n} from '@shipfox/node-drizzle';\nimport {and, asc, count, desc, eq, gte, lte, type SQL, sql} from 'drizzle-orm';\nimport type {JobMode, JobStatus, ListenerStatus} from '#core/entities/job.js';\nimport type {JobExecutionStatus} from '#core/entities/job-execution.js';\nimport type {\n JobExecutionDetail,\n StepDetail,\n WorkflowJobDetail,\n WorkflowRun,\n WorkflowRunDetail,\n WorkflowRunStatus,\n} from '#core/entities/workflow-run.js';\nimport {db} from '../db.js';\nimport {jobExecutions, toJobExecution} from '../schema/job-executions.js';\nimport {jobs, toJob} from '../schema/jobs.js';\nimport {stepAttempts, toStepAttempt} from '../schema/step-attempts.js';\nimport {steps, toStep} from '../schema/steps.js';\nimport {toWorkflowRunAttempt, workflowRunAttempts} from '../schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';\n\nexport type WorkflowRunCursor = TimestampIdCursor;\n\nexport interface WorkflowRunFilters {\n status?: WorkflowRunStatus | undefined;\n definitionId?: string | undefined;\n triggerSource?: string | undefined;\n createdFrom?: Date | undefined;\n createdTo?: Date | undefined;\n}\n\nexport interface ListWorkflowRunsParams {\n projectId: string;\n limit: number;\n cursor?: WorkflowRunCursor | undefined;\n filters?: WorkflowRunFilters | undefined;\n includeTotal?: boolean | undefined;\n}\n\nexport interface ListWorkflowRunsResult {\n runs: WorkflowRun[];\n nextCursor: WorkflowRunCursor | null;\n filteredTotalCount: number | null;\n}\n\n/** A run-list job glyph: enough to draw and label it, none of its steps. */\nexport interface WorkflowRunJobSummary {\n id: string;\n key: string;\n name: string | null;\n status: JobStatus;\n mode: JobMode;\n listenerStatus: ListenerStatus;\n executionStatus: JobExecutionStatus | null;\n position: number;\n}\n\nexport interface WorkflowRunAggregates {\n status: Array<{value: WorkflowRunStatus; count: number}>;\n triggerSource: Array<{value: string; count: number}>;\n workflow: Array<{value: string; count: number}>;\n}\n\nexport interface WorkflowJobExecutionDepth {\n runningRuns: number;\n runningJobExecutions: number;\n}\n\nexport interface WorkflowJobExecutionDepthParams {\n workspaceId?: string;\n}\n\nexport async function getWorkflowRunById(id: string): Promise<WorkflowRun | undefined> {\n const rows = await db().select().from(workflowRuns).where(eq(workflowRuns.id, id)).limit(1);\n const row = rows[0];\n if (!row) return undefined;\n return toWorkflowRun(row);\n}\n\nexport async function getWorkflowRunByAttemptId(\n workflowRunAttemptId: string,\n): Promise<WorkflowRun | undefined> {\n const rows = await db()\n .select({run: workflowRuns})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRun(row.run) : undefined;\n}\n\nexport async function getWorkflowRunAttemptById(workflowRunAttemptId: string) {\n const rows = await db()\n .select()\n .from(workflowRunAttempts)\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRunAttempt(row) : undefined;\n}\n\nexport async function listRunAttempts(params: {workflowRunId: string; projectId: string}) {\n return (\n await db()\n .select({\n attempt: workflowRunAttempts,\n })\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .orderBy(asc(workflowRunAttempts.attempt))\n ).map((row) => toWorkflowRunAttempt(row.attempt));\n}\n\nexport async function getLatestAttempt(params: {\n workflowRunId: string;\n projectId: string;\n}): Promise<number> {\n const [row] = await db()\n .select({value: sql<number>`coalesce(max(${workflowRunAttempts.attempt}), 1)`})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .limit(1);\n\n return Number(row?.value ?? 1);\n}\n\nexport function buildWorkflowRunListConditions(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n cursor?: WorkflowRunCursor | undefined;\n omit?: 'status' | 'definitionId' | 'triggerSource' | undefined;\n}): SQL[] {\n const filters = params.filters;\n const conditions: SQL[] = [eq(workflowRuns.projectId, params.projectId)];\n const cursorCondition = timestampIdCursorWhere({\n timestampColumn: workflowRuns.createdAt,\n idColumn: workflowRuns.id,\n cursor: params.cursor,\n });\n if (cursorCondition) conditions.push(cursorCondition);\n if (filters?.status && params.omit !== 'status') {\n conditions.push(eq(workflowRuns.status, filters.status));\n }\n if (filters?.definitionId && params.omit !== 'definitionId') {\n conditions.push(eq(workflowRuns.definitionId, filters.definitionId));\n }\n if (filters?.triggerSource && params.omit !== 'triggerSource') {\n conditions.push(eq(workflowRuns.triggerSource, filters.triggerSource));\n }\n if (filters?.createdFrom) {\n conditions.push(gte(workflowRuns.createdAt, filters.createdFrom));\n }\n if (filters?.createdTo) {\n conditions.push(lte(workflowRuns.createdAt, filters.createdTo));\n }\n return conditions;\n}\n\nexport async function listWorkflowRuns(\n params: ListWorkflowRunsParams,\n): Promise<ListWorkflowRunsResult> {\n const conditions = buildWorkflowRunListConditions(params);\n const rows = await db()\n .select()\n .from(workflowRuns)\n .where(and(...conditions))\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .limit(params.limit + 1);\n\n let totalCount: number | null = null;\n if (params.includeTotal) {\n const [{value} = {value: 0}] = await db()\n .select({value: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({projectId: params.projectId, filters: params.filters}),\n ),\n );\n totalCount = value;\n }\n\n const page = paginateTimestampIdRows({rows, limit: params.limit, timestampKey: 'createdAt'});\n\n return {\n runs: page.pageRows.map(toWorkflowRun),\n nextCursor: page.nextCursor,\n filteredTotalCount: totalCount,\n };\n}\n\n/** The run whose jobs to fetch, pinned to the attempt the caller already read. */\nexport interface WorkflowRunJobSummaryTarget {\n id: string;\n currentAttempt: number;\n}\n\n/**\n * A page row's jobs: a bounded slice to draw, and totals describing all of them.\n *\n * The preview is what a row can show; `statusCounts` is what it can say. Keeping the counts\n * server-side is what lets a row report a failure that sits past the preview. Counts use the\n * display status derived from the job verdict, listener state, and selected execution state;\n * the row keeps the verdict and evidence separate so the client can apply the same display\n * rule as run detail.\n */\nexport interface WorkflowRunJobsSummary {\n preview: WorkflowRunJobSummary[];\n statusCounts: WorkflowRunJobStatusCount[];\n rawStatusCounts: WorkflowRunJobRawStatusCount[];\n}\n\nexport interface WorkflowRunJobStatusCount {\n status: JobStatus | 'listening';\n count: number;\n}\n\nexport interface WorkflowRunJobRawStatusCount {\n status: JobStatus;\n count: number;\n}\n\n/**\n * Jobs for a page of runs, keyed by run id.\n *\n * Issued once per page rather than once per run: the run list is the one surface that needs\n * every run's jobs at once, and a per-row query would put 50 round trips behind it.\n *\n * Both reads are bounded by the page, not by workflow size. A workflow has no job limit and\n * this list polls while runs are active, so returning every job of every row would let one\n * large workflow decide how much the endpoint moves every four seconds. The preview is cut\n * per run in the database, and everything past it is described by a grouped count instead.\n *\n * The attempt comes from the caller's own read rather than from a second look at\n * `current_attempt`. Re-reading it here would let a re-run landing between the queries pair\n * attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip\n * contradicts.\n *\n * The two reads share one repeatable-read snapshot. They describe the same jobs at the same\n * instant, and the strip combines them into a single glyph row, so under the default\n * read-committed isolation a job settling between the statements would draw a pending glyph\n * beside a summary counting it as failed. Sequential inside one transaction is the cost of\n * that; at a four-second poll the extra round trip does not register.\n */\nexport async function listWorkflowRunJobSummaries(\n runs: readonly WorkflowRunJobSummaryTarget[],\n): Promise<Map<string, WorkflowRunJobsSummary>> {\n const summaries = new Map<string, WorkflowRunJobsSummary>();\n if (runs.length === 0) return summaries;\n\n // A row-constructor IN over (run, attempt) so each pair is one lookup on the unique index\n // that already covers those two columns.\n const attemptPairs = sql.join(\n runs.map((run) => sql`(${run.id}::uuid, ${run.currentAttempt})`),\n sql`, `,\n );\n const attemptFilter = sql`(${workflowRunAttempts.workflowRunId}, ${workflowRunAttempts.attempt}) in (${attemptPairs})`;\n\n const {previewRows, countRows} = await db().transaction(\n async (tx) => {\n // Pick the execution the detail view would display once per job before either list\n // statement touches it. The existing (job_id, sequence) index supports the latest\n // execution ordering, while the status-first expression preserves the rule that an\n // active execution wins over a newer completed retry.\n const selectedExecution = tx.$with('selected_execution').as(\n tx\n .selectDistinctOn([jobExecutions.jobId], {\n jobId: jobExecutions.jobId,\n executionStatus: sql<JobExecutionStatus>`${jobExecutions.status}`.as(\n 'execution_status',\n ),\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(attemptFilter)\n .orderBy(\n asc(jobExecutions.jobId),\n sql`case when ${jobExecutions.status} = 'running' then 0 else 1 end`,\n desc(jobExecutions.sequence),\n desc(jobExecutions.id),\n ),\n );\n\n const ranked = tx\n .with(selectedExecution)\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n id: jobs.id,\n key: jobs.key,\n name: jobs.name,\n status: jobs.status,\n mode: jobs.mode,\n listenerStatus: jobs.listenerStatus,\n executionStatus: selectedExecution.executionStatus,\n position: jobs.position,\n jobRank:\n sql<number>`row_number() over (partition by ${workflowRunAttempts.workflowRunId} order by ${jobs.position} asc, ${jobs.id} asc)`.as(\n 'job_rank',\n ),\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id))\n .where(attemptFilter)\n .as('ranked');\n\n const executionDisplayStatus = sql<JobExecutionStatus | null>`\n ${selectedExecution.executionStatus}\n `;\n const displayStatus = sql<WorkflowRunJobStatusCount['status']>`\n case\n when ${jobs.status} in ('succeeded', 'failed', 'cancelled', 'skipped') then ${jobs.status}::text\n when ${jobs.mode} = 'listening' and ${jobs.listenerStatus} = 'listening' then 'listening'\n when ${executionDisplayStatus} is not null then ${executionDisplayStatus}::text\n else 'pending'\n end\n `;\n return {\n previewRows: await tx\n .select({\n workflowRunId: ranked.workflowRunId,\n id: ranked.id,\n key: ranked.key,\n name: ranked.name,\n status: ranked.status,\n mode: ranked.mode,\n listenerStatus: ranked.listenerStatus,\n executionStatus: ranked.executionStatus,\n position: ranked.position,\n })\n .from(ranked)\n .where(lte(ranked.jobRank, WORKFLOW_RUN_JOB_PREVIEW_LIMIT))\n .orderBy(asc(ranked.workflowRunId), asc(ranked.position), asc(ranked.id)),\n countRows: await tx\n .with(selectedExecution)\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n rawStatus: jobs.status,\n status: displayStatus,\n count: count(),\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id))\n .where(attemptFilter)\n .groupBy(workflowRunAttempts.workflowRunId, jobs.status, displayStatus),\n };\n },\n {isolationLevel: 'repeatable read', accessMode: 'read only'},\n );\n\n for (const {workflowRunId, ...summary} of previewRows) {\n summaryFor(summaries, workflowRunId).preview.push(summary);\n }\n for (const {workflowRunId, rawStatus, status, count: statusCount} of countRows) {\n const summary = summaryFor(summaries, workflowRunId);\n appendStatusCount(summary.rawStatusCounts, rawStatus, statusCount);\n appendStatusCount(summary.statusCounts, status, statusCount);\n }\n\n return summaries;\n}\n\nfunction summaryFor(\n summaries: Map<string, WorkflowRunJobsSummary>,\n workflowRunId: string,\n): WorkflowRunJobsSummary {\n const existing = summaries.get(workflowRunId);\n if (existing) return existing;\n const created: WorkflowRunJobsSummary = {preview: [], statusCounts: [], rawStatusCounts: []};\n summaries.set(workflowRunId, created);\n return created;\n}\n\nfunction appendStatusCount<T extends string>(\n counts: Array<{status: T; count: number}>,\n status: T,\n count: number,\n): void {\n const existing = counts.find((entry) => entry.status === status);\n if (existing) {\n existing.count += count;\n } else {\n counts.push({status, count});\n }\n}\n\nexport async function listWorkflowRunsByProject(projectId: string): Promise<WorkflowRun[]> {\n const result = await listWorkflowRuns({projectId, limit: 100});\n return result.runs;\n}\n\nexport async function getWorkflowRunAggregates(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n}): Promise<WorkflowRunAggregates> {\n const [statusRows, triggerRows, workflowRows] = await Promise.all([\n db()\n .select({value: workflowRuns.status, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'status',\n }),\n ),\n )\n .groupBy(workflowRuns.status),\n db()\n .select({value: workflowRuns.triggerSource, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'triggerSource',\n }),\n ),\n )\n .groupBy(workflowRuns.triggerSource),\n db()\n .select({value: workflowRuns.definitionId, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'definitionId',\n }),\n ),\n )\n .groupBy(workflowRuns.definitionId),\n ]);\n\n return {\n status: statusRows,\n triggerSource: triggerRows,\n workflow: workflowRows,\n };\n}\n\nexport async function getWorkflowJobExecutionDepth(\n params: WorkflowJobExecutionDepthParams = {},\n): Promise<WorkflowJobExecutionDepth> {\n const runConditions = [eq(workflowRuns.status, 'running')];\n const jobConditions = [eq(jobExecutions.status, 'running')];\n if (params.workspaceId) {\n runConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n jobConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n }\n\n const [runRows, jobRows] = await Promise.all([\n db()\n .select({value: count()})\n .from(workflowRuns)\n .where(and(...runConditions)),\n db()\n .select({value: count()})\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(and(...jobConditions)),\n ]);\n\n return {\n runningRuns: runRows[0]?.value ?? 0,\n runningJobExecutions: jobRows[0]?.value ?? 0,\n };\n}\n\nexport async function getWorkflowRunDetail(\n workflowRunId: string,\n attempt?: number | undefined,\n): Promise<WorkflowRunDetail | undefined> {\n const [target] = await db()\n .select({run: workflowRuns, attempt: workflowRunAttempts})\n .from(workflowRuns)\n .innerJoin(\n workflowRunAttempts,\n and(\n eq(workflowRunAttempts.workflowRunId, workflowRuns.id),\n eq(workflowRunAttempts.attempt, attempt ?? workflowRuns.currentAttempt),\n ),\n )\n .where(eq(workflowRuns.id, workflowRunId))\n .limit(1);\n if (!target) return undefined;\n\n const latestAttempt = await getLatestAttempt({\n workflowRunId: target.run.id,\n projectId: target.run.projectId,\n });\n\n const rows = await db()\n .select({\n run: workflowRuns,\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(workflowRuns)\n .innerJoin(workflowRunAttempts, eq(workflowRunAttempts.id, target.attempt.id))\n .leftJoin(jobs, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(jobExecutions, eq(jobExecutions.jobId, jobs.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(workflowRuns.id, workflowRunId))\n .orderBy(\n asc(jobs.position),\n asc(jobs.id),\n asc(jobExecutions.sequence),\n asc(jobExecutions.id),\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n return hydrateWorkflowRunDetail(rows, target.attempt, latestAttempt);\n}\n\nexport async function getJobExecutionDetail(\n jobExecutionId: string,\n): Promise<JobExecutionDetail | undefined> {\n const rows = await db()\n .select({\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(jobExecutions.id, jobExecutionId))\n .orderBy(\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: JobExecutionDetail = {\n ...toJobExecution(first.jobExecution, first.job.name ?? first.job.key),\n steps: [],\n };\n const stepById = new Map<string, StepDetail>();\n for (const row of rows) {\n if (row.step) {\n const step = getOrCreateStepDetail(stepById, detail.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n }\n\n return detail;\n}\n\nfunction hydrateWorkflowRunDetail(\n rows: {\n run: typeof workflowRuns.$inferSelect;\n job: typeof jobs.$inferSelect | null;\n jobExecution: typeof jobExecutions.$inferSelect | null;\n step: typeof steps.$inferSelect | null;\n stepAttempt: typeof stepAttempts.$inferSelect | null;\n }[],\n attempt: typeof workflowRunAttempts.$inferSelect,\n latestAttempt: number,\n): WorkflowRunDetail | undefined {\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: WorkflowRunDetail = {\n ...toWorkflowRun(first.run),\n runAttempt: toWorkflowRunAttempt(attempt),\n latestAttempt,\n jobs: [],\n };\n const jobById = new Map<string, WorkflowJobDetail>();\n const jobExecutionById = new Map<string, JobExecutionDetail>();\n const stepById = new Map<string, StepDetail>();\n\n for (const row of rows) {\n if (!row.job) continue;\n let job = jobById.get(row.job.id);\n if (!job) {\n job = {...toJob(row.job), jobExecutions: []};\n jobById.set(row.job.id, job);\n detail.jobs.push(job);\n }\n\n if (!row.jobExecution) continue;\n let jobExecution = jobExecutionById.get(row.jobExecution.id);\n if (!jobExecution) {\n jobExecution = {\n ...toJobExecution(row.jobExecution, row.job.name ?? row.job.key),\n steps: [],\n };\n jobExecutionById.set(row.jobExecution.id, jobExecution);\n job.jobExecutions.push(jobExecution);\n }\n\n if (!row.step) continue;\n const step = getOrCreateStepDetail(stepById, jobExecution.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n\n return detail;\n}\n\nfunction getOrCreateStepDetail(\n stepById: Map<string, StepDetail>,\n target: StepDetail[],\n row: typeof steps.$inferSelect,\n): StepDetail {\n let step = stepById.get(row.id);\n if (!step) {\n step = {...toStep(row), attempts: []};\n stepById.set(row.id, step);\n target.push(step);\n }\n return step;\n}\n"],"names":["WORKFLOW_RUN_JOB_PREVIEW_LIMIT","paginateTimestampIdRows","timestampIdCursorWhere","and","asc","count","desc","eq","gte","lte","sql","db","jobExecutions","toJobExecution","jobs","toJob","stepAttempts","toStepAttempt","steps","toStep","toWorkflowRunAttempt","workflowRunAttempts","toWorkflowRun","workflowRuns","getWorkflowRunById","id","rows","select","from","where","limit","row","undefined","getWorkflowRunByAttemptId","workflowRunAttemptId","run","innerJoin","workflowRunId","getWorkflowRunAttemptById","listRunAttempts","params","attempt","projectId","orderBy","map","getLatestAttempt","value","Number","buildWorkflowRunListConditions","filters","conditions","cursorCondition","timestampColumn","createdAt","idColumn","cursor","push","status","omit","definitionId","triggerSource","createdFrom","createdTo","listWorkflowRuns","totalCount","includeTotal","page","timestampKey","runs","pageRows","nextCursor","filteredTotalCount","listWorkflowRunJobSummaries","summaries","Map","length","attemptPairs","join","currentAttempt","attemptFilter","previewRows","countRows","transaction","tx","selectedExecution","$with","as","selectDistinctOn","jobId","executionStatus","sequence","ranked","with","key","name","mode","listenerStatus","position","jobRank","leftJoin","executionDisplayStatus","displayStatus","rawStatus","groupBy","isolationLevel","accessMode","summary","summaryFor","preview","statusCount","appendStatusCount","rawStatusCounts","statusCounts","existing","get","created","set","counts","find","entry","listWorkflowRunsByProject","result","getWorkflowRunAggregates","statusRows","triggerRows","workflowRows","Promise","all","workflow","getWorkflowJobExecutionDepth","runConditions","jobConditions","workspaceId","runRows","jobRows","runningRuns","runningJobExecutions","getWorkflowRunDetail","target","latestAttempt","job","jobExecution","step","stepAttempt","jobExecutionId","stepId","executionOrder","hydrateWorkflowRunDetail","getJobExecutionDetail","first","detail","stepById","getOrCreateStepDetail","attempts","runAttempt","jobById","jobExecutionById"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/db/workflow-runs/queries.ts"],"sourcesContent":["import {WORKFLOW_RUN_JOB_PREVIEW_LIMIT} from '@shipfox/api-workflows-dto';\nimport {\n paginateTimestampIdRows,\n type TimestampIdCursor,\n timestampIdCursorWhere,\n} from '@shipfox/node-drizzle';\nimport {and, asc, count, desc, eq, gte, lte, type SQL, sql} from 'drizzle-orm';\nimport type {JobMode, JobStatus, ListenerStatus} from '#core/entities/job.js';\nimport type {JobExecutionStatus} from '#core/entities/job-execution.js';\nimport type {\n JobExecutionDetail,\n StepDetail,\n WorkflowJobDetail,\n WorkflowRun,\n WorkflowRunDetail,\n WorkflowRunStatus,\n} from '#core/entities/workflow-run.js';\nimport {db} from '../db.js';\nimport {jobExecutions, toJobExecution} from '../schema/job-executions.js';\nimport {jobs, toJob} from '../schema/jobs.js';\nimport {stepAttempts, toStepAttempt} from '../schema/step-attempts.js';\nimport {steps, toStep} from '../schema/steps.js';\nimport {toWorkflowRunAttempt, workflowRunAttempts} from '../schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';\n\nexport type WorkflowRunCursor = TimestampIdCursor;\n\nexport interface WorkflowRunFilters {\n status?: WorkflowRunStatus | undefined;\n definitionId?: string | undefined;\n triggerSource?: string | undefined;\n createdFrom?: Date | undefined;\n createdTo?: Date | undefined;\n}\n\nexport interface ListWorkflowRunsParams {\n projectId: string;\n limit: number;\n cursor?: WorkflowRunCursor | undefined;\n filters?: WorkflowRunFilters | undefined;\n includeTotal?: boolean | undefined;\n}\n\nexport interface ListWorkflowRunsResult {\n runs: WorkflowRun[];\n nextCursor: WorkflowRunCursor | null;\n filteredTotalCount: number | null;\n}\n\n/** A run-list job glyph: enough to draw and label it, none of its steps. */\nexport interface WorkflowRunJobSummary {\n id: string;\n key: string;\n name: string | null;\n status: JobStatus;\n mode: JobMode;\n listenerStatus: ListenerStatus;\n executionStatus: JobExecutionStatus | null;\n position: number;\n}\n\nexport interface WorkflowRunAggregates {\n status: Array<{value: WorkflowRunStatus; count: number}>;\n triggerSource: Array<{value: string; count: number}>;\n workflow: Array<{value: string; count: number}>;\n}\n\nexport interface WorkflowJobExecutionDepth {\n runningRuns: number;\n runningJobExecutions: number;\n}\n\nexport interface WorkflowJobExecutionDepthParams {\n workspaceId?: string;\n}\n\nexport async function getWorkflowRunById(id: string): Promise<WorkflowRun | undefined> {\n const rows = await db().select().from(workflowRuns).where(eq(workflowRuns.id, id)).limit(1);\n const row = rows[0];\n if (!row) return undefined;\n return toWorkflowRun(row);\n}\n\nexport async function getWorkflowRunByAttemptId(\n workflowRunAttemptId: string,\n): Promise<WorkflowRun | undefined> {\n const rows = await db()\n .select({run: workflowRuns})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRun(row.run) : undefined;\n}\n\nexport async function getWorkflowRunAttemptById(workflowRunAttemptId: string) {\n const rows = await db()\n .select()\n .from(workflowRunAttempts)\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRunAttempt(row) : undefined;\n}\n\nexport async function listRunAttempts(params: {workflowRunId: string; projectId: string}) {\n return (\n await db()\n .select({\n attempt: workflowRunAttempts,\n })\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .orderBy(asc(workflowRunAttempts.attempt))\n ).map((row) => toWorkflowRunAttempt(row.attempt));\n}\n\nexport async function getLatestAttempt(params: {\n workflowRunId: string;\n projectId: string;\n}): Promise<number> {\n const [row] = await db()\n .select({value: sql<number>`coalesce(max(${workflowRunAttempts.attempt}), 1)`})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .limit(1);\n\n return Number(row?.value ?? 1);\n}\n\nexport function buildWorkflowRunListConditions(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n cursor?: WorkflowRunCursor | undefined;\n omit?: 'status' | 'definitionId' | 'triggerSource' | undefined;\n}): SQL[] {\n const filters = params.filters;\n const conditions: SQL[] = [eq(workflowRuns.projectId, params.projectId)];\n const cursorCondition = timestampIdCursorWhere({\n timestampColumn: workflowRuns.createdAt,\n idColumn: workflowRuns.id,\n cursor: params.cursor,\n });\n if (cursorCondition) conditions.push(cursorCondition);\n if (filters?.status && params.omit !== 'status') {\n conditions.push(eq(workflowRuns.status, filters.status));\n }\n if (filters?.definitionId && params.omit !== 'definitionId') {\n conditions.push(eq(workflowRuns.definitionId, filters.definitionId));\n }\n if (filters?.triggerSource && params.omit !== 'triggerSource') {\n conditions.push(eq(workflowRuns.triggerSource, filters.triggerSource));\n }\n if (filters?.createdFrom) {\n conditions.push(gte(workflowRuns.createdAt, filters.createdFrom));\n }\n if (filters?.createdTo) {\n conditions.push(lte(workflowRuns.createdAt, filters.createdTo));\n }\n return conditions;\n}\n\nexport async function listWorkflowRuns(\n params: ListWorkflowRunsParams,\n): Promise<ListWorkflowRunsResult> {\n const conditions = buildWorkflowRunListConditions(params);\n const rows = await db()\n .select()\n .from(workflowRuns)\n .where(and(...conditions))\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .limit(params.limit + 1);\n\n let totalCount: number | null = null;\n if (params.includeTotal) {\n const [{value} = {value: 0}] = await db()\n .select({value: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({projectId: params.projectId, filters: params.filters}),\n ),\n );\n totalCount = value;\n }\n\n const page = paginateTimestampIdRows({rows, limit: params.limit, timestampKey: 'createdAt'});\n\n return {\n runs: page.pageRows.map(toWorkflowRun),\n nextCursor: page.nextCursor,\n filteredTotalCount: totalCount,\n };\n}\n\n/** The run whose jobs to fetch, pinned to the attempt the caller already read. */\nexport interface WorkflowRunJobSummaryTarget {\n id: string;\n currentAttempt: number;\n}\n\n/**\n * A page row's jobs: a bounded slice to draw, totals describing all of them, and whether any\n * execution has reached a runner.\n *\n * The preview is what a row can show; `statusCounts` is what it can say. Keeping the counts\n * server-side is what lets a row report a failure that sits past the preview. Counts use the\n * display status derived from the job verdict, listener state, and selected execution state;\n * the row keeps the verdict and evidence separate so the client can apply the same display\n * rule as run detail.\n */\nexport interface WorkflowRunJobsSummary {\n preview: WorkflowRunJobSummary[];\n statusCounts: WorkflowRunJobStatusCount[];\n rawStatusCounts: WorkflowRunJobRawStatusCount[];\n hasStartedJobExecution: boolean;\n}\n\nexport interface WorkflowRunJobStatusCount {\n status: JobStatus | 'listening';\n count: number;\n}\n\nexport interface WorkflowRunJobRawStatusCount {\n status: JobStatus;\n count: number;\n}\n\n/**\n * Jobs for a page of runs, keyed by run id.\n *\n * Issued once per page rather than once per run: the run list is the one surface that needs\n * every run's jobs at once, and a per-row query would put 50 round trips behind it.\n *\n * Both reads are bounded by the page, not by workflow size. A workflow has no job limit and\n * this list polls while runs are active, so returning every job of every row would let one\n * large workflow decide how much the endpoint moves every four seconds. The preview is cut\n * per run in the database, and everything past it is described by a grouped count instead.\n *\n * The attempt comes from the caller's own read rather than from a second look at\n * `current_attempt`. Re-reading it here would let a re-run landing between the queries pair\n * attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip\n * contradicts.\n *\n * The reads share one repeatable-read snapshot. They describe the same jobs and executions at\n * the same instant, and the strip combines them into a single glyph row, so under the default\n * read-committed isolation a job settling between the statements would draw a pending glyph\n * beside a summary counting it as failed. Sequential inside one transaction is the cost of\n * that; at a four-second poll the extra round trip does not register.\n */\nexport async function listWorkflowRunJobSummaries(\n runs: readonly WorkflowRunJobSummaryTarget[],\n): Promise<Map<string, WorkflowRunJobsSummary>> {\n const summaries = new Map<string, WorkflowRunJobsSummary>();\n if (runs.length === 0) return summaries;\n\n // A row-constructor IN over (run, attempt) so each pair is one lookup on the unique index\n // that already covers those two columns.\n const attemptPairs = sql.join(\n runs.map((run) => sql`(${run.id}::uuid, ${run.currentAttempt})`),\n sql`, `,\n );\n const attemptFilter = sql`(${workflowRunAttempts.workflowRunId}, ${workflowRunAttempts.attempt}) in (${attemptPairs})`;\n\n const {previewRows, countRows} = await db().transaction(\n async (tx) => {\n // Pick the execution the detail view would display once per job before either list\n // statement touches it. The existing (job_id, sequence) index supports the latest\n // execution ordering, while the status-first expression preserves the rule that an\n // active execution wins over a newer completed retry.\n const selectedExecution = tx.$with('selected_execution').as(\n tx\n .selectDistinctOn([jobExecutions.jobId], {\n jobId: jobExecutions.jobId,\n executionStatus: sql<JobExecutionStatus>`${jobExecutions.status}`.as(\n 'execution_status',\n ),\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(attemptFilter)\n .orderBy(\n asc(jobExecutions.jobId),\n sql`case when ${jobExecutions.status} = 'running' then 0 else 1 end`,\n desc(jobExecutions.sequence),\n desc(jobExecutions.id),\n ),\n );\n\n const ranked = tx\n .with(selectedExecution)\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n id: jobs.id,\n key: jobs.key,\n name: jobs.name,\n status: jobs.status,\n mode: jobs.mode,\n listenerStatus: jobs.listenerStatus,\n executionStatus: selectedExecution.executionStatus,\n position: jobs.position,\n jobRank:\n sql<number>`row_number() over (partition by ${workflowRunAttempts.workflowRunId} order by ${jobs.position} asc, ${jobs.id} asc)`.as(\n 'job_rank',\n ),\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id))\n .where(attemptFilter)\n .as('ranked');\n // Correlated per job rather than a grouped scan of `job_executions`: an aggregate over the\n // whole table cannot have the page's filter pushed into it, so it would read every execution\n // ever recorded on each poll and grow with history rather than with the page.\n const hasStartedJobExecution = sql<boolean>`bool_or(exists (\n select 1\n from ${jobExecutions}\n where ${jobExecutions.jobId} = ${jobs.id} and ${jobExecutions.startedAt} is not null\n ))`;\n\n const executionDisplayStatus = sql<JobExecutionStatus | null>`\n ${selectedExecution.executionStatus}\n `;\n const displayStatus = sql<WorkflowRunJobStatusCount['status']>`\n case\n when ${jobs.status} in ('succeeded', 'failed', 'cancelled', 'skipped') then ${jobs.status}::text\n when ${jobs.mode} = 'listening' and ${jobs.listenerStatus} = 'listening' then 'listening'\n when ${executionDisplayStatus} is not null then ${executionDisplayStatus}::text\n else 'pending'\n end\n `;\n return {\n previewRows: await tx\n .select({\n workflowRunId: ranked.workflowRunId,\n id: ranked.id,\n key: ranked.key,\n name: ranked.name,\n status: ranked.status,\n mode: ranked.mode,\n listenerStatus: ranked.listenerStatus,\n executionStatus: ranked.executionStatus,\n position: ranked.position,\n })\n .from(ranked)\n .where(lte(ranked.jobRank, WORKFLOW_RUN_JOB_PREVIEW_LIMIT))\n .orderBy(asc(ranked.workflowRunId), asc(ranked.position), asc(ranked.id)),\n countRows: await tx\n .with(selectedExecution)\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n rawStatus: jobs.status,\n status: displayStatus,\n count: count(),\n hasStartedJobExecution,\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(selectedExecution, eq(selectedExecution.jobId, jobs.id))\n .where(attemptFilter)\n .groupBy(workflowRunAttempts.workflowRunId, jobs.status, displayStatus),\n };\n },\n {isolationLevel: 'repeatable read', accessMode: 'read only'},\n );\n\n for (const {workflowRunId, ...summary} of previewRows) {\n summaryFor(summaries, workflowRunId).preview.push(summary);\n }\n for (const {\n workflowRunId,\n rawStatus,\n status,\n count: statusCount,\n hasStartedJobExecution,\n } of countRows) {\n const summary = summaryFor(summaries, workflowRunId);\n appendStatusCount(summary.rawStatusCounts, rawStatus, statusCount);\n appendStatusCount(summary.statusCounts, status, statusCount);\n // One row per (run, verdict, display status), so the run's answer is the OR of its groups.\n summary.hasStartedJobExecution ||= hasStartedJobExecution;\n }\n\n return summaries;\n}\n\nfunction summaryFor(\n summaries: Map<string, WorkflowRunJobsSummary>,\n workflowRunId: string,\n): WorkflowRunJobsSummary {\n const existing = summaries.get(workflowRunId);\n if (existing) return existing;\n const created: WorkflowRunJobsSummary = {\n preview: [],\n statusCounts: [],\n rawStatusCounts: [],\n hasStartedJobExecution: false,\n };\n summaries.set(workflowRunId, created);\n return created;\n}\n\nfunction appendStatusCount<T extends string>(\n counts: Array<{status: T; count: number}>,\n status: T,\n count: number,\n): void {\n const existing = counts.find((entry) => entry.status === status);\n if (existing) {\n existing.count += count;\n } else {\n counts.push({status, count});\n }\n}\n\nexport async function listWorkflowRunsByProject(projectId: string): Promise<WorkflowRun[]> {\n const result = await listWorkflowRuns({projectId, limit: 100});\n return result.runs;\n}\n\nexport async function getWorkflowRunAggregates(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n}): Promise<WorkflowRunAggregates> {\n const [statusRows, triggerRows, workflowRows] = await Promise.all([\n db()\n .select({value: workflowRuns.status, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'status',\n }),\n ),\n )\n .groupBy(workflowRuns.status),\n db()\n .select({value: workflowRuns.triggerSource, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'triggerSource',\n }),\n ),\n )\n .groupBy(workflowRuns.triggerSource),\n db()\n .select({value: workflowRuns.definitionId, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'definitionId',\n }),\n ),\n )\n .groupBy(workflowRuns.definitionId),\n ]);\n\n return {\n status: statusRows,\n triggerSource: triggerRows,\n workflow: workflowRows,\n };\n}\n\nexport async function getWorkflowJobExecutionDepth(\n params: WorkflowJobExecutionDepthParams = {},\n): Promise<WorkflowJobExecutionDepth> {\n const runConditions = [eq(workflowRuns.status, 'running')];\n const jobConditions = [eq(jobExecutions.status, 'running')];\n if (params.workspaceId) {\n runConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n jobConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n }\n\n const [runRows, jobRows] = await Promise.all([\n db()\n .select({value: count()})\n .from(workflowRuns)\n .where(and(...runConditions)),\n db()\n .select({value: count()})\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(and(...jobConditions)),\n ]);\n\n return {\n runningRuns: runRows[0]?.value ?? 0,\n runningJobExecutions: jobRows[0]?.value ?? 0,\n };\n}\n\nexport async function getWorkflowRunDetail(\n workflowRunId: string,\n attempt?: number | undefined,\n): Promise<WorkflowRunDetail | undefined> {\n const [target] = await db()\n .select({run: workflowRuns, attempt: workflowRunAttempts})\n .from(workflowRuns)\n .innerJoin(\n workflowRunAttempts,\n and(\n eq(workflowRunAttempts.workflowRunId, workflowRuns.id),\n eq(workflowRunAttempts.attempt, attempt ?? workflowRuns.currentAttempt),\n ),\n )\n .where(eq(workflowRuns.id, workflowRunId))\n .limit(1);\n if (!target) return undefined;\n\n const latestAttempt = await getLatestAttempt({\n workflowRunId: target.run.id,\n projectId: target.run.projectId,\n });\n\n const rows = await db()\n .select({\n run: workflowRuns,\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(workflowRuns)\n .innerJoin(workflowRunAttempts, eq(workflowRunAttempts.id, target.attempt.id))\n .leftJoin(jobs, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(jobExecutions, eq(jobExecutions.jobId, jobs.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(workflowRuns.id, workflowRunId))\n .orderBy(\n asc(jobs.position),\n asc(jobs.id),\n asc(jobExecutions.sequence),\n asc(jobExecutions.id),\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n return hydrateWorkflowRunDetail(rows, target.attempt, latestAttempt);\n}\n\nexport async function getJobExecutionDetail(\n jobExecutionId: string,\n): Promise<JobExecutionDetail | undefined> {\n const rows = await db()\n .select({\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(jobExecutions.id, jobExecutionId))\n .orderBy(\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: JobExecutionDetail = {\n ...toJobExecution(first.jobExecution, first.job.name ?? first.job.key),\n steps: [],\n };\n const stepById = new Map<string, StepDetail>();\n for (const row of rows) {\n if (row.step) {\n const step = getOrCreateStepDetail(stepById, detail.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n }\n\n return detail;\n}\n\nfunction hydrateWorkflowRunDetail(\n rows: {\n run: typeof workflowRuns.$inferSelect;\n job: typeof jobs.$inferSelect | null;\n jobExecution: typeof jobExecutions.$inferSelect | null;\n step: typeof steps.$inferSelect | null;\n stepAttempt: typeof stepAttempts.$inferSelect | null;\n }[],\n attempt: typeof workflowRunAttempts.$inferSelect,\n latestAttempt: number,\n): WorkflowRunDetail | undefined {\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: WorkflowRunDetail = {\n ...toWorkflowRun(first.run),\n runAttempt: toWorkflowRunAttempt(attempt),\n latestAttempt,\n jobs: [],\n // Read off the same rows the executions come from, so the flag cannot contradict them.\n hasStartedJobExecution: rows.some((row) => row.jobExecution?.startedAt != null),\n };\n const jobById = new Map<string, WorkflowJobDetail>();\n const jobExecutionById = new Map<string, JobExecutionDetail>();\n const stepById = new Map<string, StepDetail>();\n\n for (const row of rows) {\n if (!row.job) continue;\n let job = jobById.get(row.job.id);\n if (!job) {\n job = {...toJob(row.job), jobExecutions: []};\n jobById.set(row.job.id, job);\n detail.jobs.push(job);\n }\n\n if (!row.jobExecution) continue;\n let jobExecution = jobExecutionById.get(row.jobExecution.id);\n if (!jobExecution) {\n jobExecution = {\n ...toJobExecution(row.jobExecution, row.job.name ?? row.job.key),\n steps: [],\n };\n jobExecutionById.set(row.jobExecution.id, jobExecution);\n job.jobExecutions.push(jobExecution);\n }\n\n if (!row.step) continue;\n const step = getOrCreateStepDetail(stepById, jobExecution.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n\n return detail;\n}\n\nfunction getOrCreateStepDetail(\n stepById: Map<string, StepDetail>,\n target: StepDetail[],\n row: typeof steps.$inferSelect,\n): StepDetail {\n let step = stepById.get(row.id);\n if (!step) {\n step = {...toStep(row), attempts: []};\n stepById.set(row.id, step);\n target.push(step);\n }\n return step;\n}\n"],"names":["WORKFLOW_RUN_JOB_PREVIEW_LIMIT","paginateTimestampIdRows","timestampIdCursorWhere","and","asc","count","desc","eq","gte","lte","sql","db","jobExecutions","toJobExecution","jobs","toJob","stepAttempts","toStepAttempt","steps","toStep","toWorkflowRunAttempt","workflowRunAttempts","toWorkflowRun","workflowRuns","getWorkflowRunById","id","rows","select","from","where","limit","row","undefined","getWorkflowRunByAttemptId","workflowRunAttemptId","run","innerJoin","workflowRunId","getWorkflowRunAttemptById","listRunAttempts","params","attempt","projectId","orderBy","map","getLatestAttempt","value","Number","buildWorkflowRunListConditions","filters","conditions","cursorCondition","timestampColumn","createdAt","idColumn","cursor","push","status","omit","definitionId","triggerSource","createdFrom","createdTo","listWorkflowRuns","totalCount","includeTotal","page","timestampKey","runs","pageRows","nextCursor","filteredTotalCount","listWorkflowRunJobSummaries","summaries","Map","length","attemptPairs","join","currentAttempt","attemptFilter","previewRows","countRows","transaction","tx","selectedExecution","$with","as","selectDistinctOn","jobId","executionStatus","sequence","ranked","with","key","name","mode","listenerStatus","position","jobRank","leftJoin","hasStartedJobExecution","startedAt","executionDisplayStatus","displayStatus","rawStatus","groupBy","isolationLevel","accessMode","summary","summaryFor","preview","statusCount","appendStatusCount","rawStatusCounts","statusCounts","existing","get","created","set","counts","find","entry","listWorkflowRunsByProject","result","getWorkflowRunAggregates","statusRows","triggerRows","workflowRows","Promise","all","workflow","getWorkflowJobExecutionDepth","runConditions","jobConditions","workspaceId","runRows","jobRows","runningRuns","runningJobExecutions","getWorkflowRunDetail","target","latestAttempt","job","jobExecution","step","stepAttempt","jobExecutionId","stepId","executionOrder","hydrateWorkflowRunDetail","getJobExecutionDetail","first","detail","stepById","getOrCreateStepDetail","attempts","runAttempt","some","jobById","jobExecutionById"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/workflow-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAC,WAAW,EAA8B,MAAM,gCAAgC,CAAC;AAC7F,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wCAAwC,CAAC;AAC/E,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,cAAc,CAAC;AAEzD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,SAAqB,GAAG,cAAc,CAuB7F;AAID,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,sBAAmC,GACxC,sBAAsB,CAgBxB;AAgBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,qBAAqB,CAWlF"}
1
+ {"version":3,"file":"workflow-run.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/workflow-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAC,WAAW,EAA8B,MAAM,gCAAgC,CAAC;AAC7F,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wCAAwC,CAAC;AAC/E,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,cAAc,CAAC;AAEzD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,SAAqB,GAAG,cAAc,CAuB7F;AASD,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,sBAAmC,GACxC,sBAAsB,CAiBxB;AAgBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,qBAAqB,CAWlF"}
@@ -25,7 +25,8 @@ export function toRunDto(run, latestAttempt = run.currentAttempt) {
25
25
  const EMPTY_JOBS = {
26
26
  preview: [],
27
27
  statusCounts: [],
28
- rawStatusCounts: []
28
+ rawStatusCounts: [],
29
+ hasStartedJobExecution: false
29
30
  };
30
31
  export function toRunListItemDto(run, jobs = EMPTY_JOBS) {
31
32
  return {
@@ -47,7 +48,8 @@ export function toRunListItemDto(run, jobs = EMPTY_JOBS) {
47
48
  job_display_status_counts: jobs.statusCounts.map(({ status, count })=>({
48
49
  status,
49
50
  count
50
- }))
51
+ })),
52
+ has_started_job_execution: jobs.hasStartedJobExecution
51
53
  };
52
54
  }
53
55
  // The persisted reference predates `actor` and carries an internal project id the client has
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/dto/workflow-run.ts"],"sourcesContent":["import type {\n WorkflowRunAttemptDto,\n WorkflowRunDto,\n WorkflowRunListItemDto,\n WorkflowRunTriggerReferenceDto,\n} from '@shipfox/api-workflows-dto';\nimport type {WorkflowRun, WorkflowRunTriggerReference} from '#core/entities/workflow-run.js';\nimport type {WorkflowRunAttempt} from '#core/entities/workflow-run-attempt.js';\nimport type {WorkflowRunJobsSummary} from '#db/index.js';\n\nexport function toRunDto(run: WorkflowRun, latestAttempt = run.currentAttempt): WorkflowRunDto {\n return {\n id: run.id,\n project_id: run.projectId,\n definition_id: run.definitionId,\n number: run.number,\n name: run.name,\n workflow_name: run.workflowName,\n status: run.status,\n current_attempt: run.currentAttempt,\n latest_attempt: latestAttempt,\n trigger_provider: run.triggerProvider,\n trigger_source: run.triggerSource,\n trigger_event: run.triggerEvent,\n trigger_payload: run.triggerPayload,\n trigger_reference: toTriggerReferenceDto(run.triggerReference),\n inputs: run.inputs,\n source_snapshot: run.sourceSnapshot,\n created_at: run.createdAt.toISOString(),\n updated_at: run.updatedAt.toISOString(),\n started_at: run.startedAt?.toISOString() ?? null,\n finished_at: run.finishedAt?.toISOString() ?? null,\n };\n}\n\nconst EMPTY_JOBS: WorkflowRunJobsSummary = {preview: [], statusCounts: [], rawStatusCounts: []};\n\nexport function toRunListItemDto(\n run: WorkflowRun,\n jobs: WorkflowRunJobsSummary = EMPTY_JOBS,\n): WorkflowRunListItemDto {\n return {\n ...toRunDto(run),\n jobs: jobs.preview.map((job) => ({\n id: job.id,\n key: job.key,\n name: job.name,\n status: job.status,\n mode: job.mode,\n listener_status: job.listenerStatus,\n execution_status: job.executionStatus,\n position: job.position,\n })),\n job_status_counts: jobs.rawStatusCounts.map(({status, count}) => ({status, count})),\n job_display_status_counts: jobs.statusCounts.map(({status, count}) => ({status, count})),\n };\n}\n\n// The persisted reference predates `actor` and carries an internal project id the client has\n// no use for, so each field is read defensively rather than spread onto the response.\nfunction toTriggerReferenceDto(\n reference: WorkflowRunTriggerReference | null | undefined,\n): WorkflowRunTriggerReferenceDto | null {\n if (!reference) return null;\n return {\n repository: reference.repository ?? null,\n ref: reference.ref ?? null,\n commit: reference.commit ?? null,\n actor: reference.actor ?? null,\n };\n}\n\nexport function toRunAttemptDto(attempt: WorkflowRunAttempt): WorkflowRunAttemptDto {\n return {\n id: attempt.id,\n workflow_run_id: attempt.workflowRunId,\n attempt: attempt.attempt,\n status: attempt.status,\n created_at: attempt.createdAt.toISOString(),\n started_at: attempt.startedAt?.toISOString() ?? null,\n finished_at: attempt.finishedAt?.toISOString() ?? null,\n rerun_mode: attempt.rerunMode,\n };\n}\n"],"names":["toRunDto","run","latestAttempt","currentAttempt","id","project_id","projectId","definition_id","definitionId","number","name","workflow_name","workflowName","status","current_attempt","latest_attempt","trigger_provider","triggerProvider","trigger_source","triggerSource","trigger_event","triggerEvent","trigger_payload","triggerPayload","trigger_reference","toTriggerReferenceDto","triggerReference","inputs","source_snapshot","sourceSnapshot","created_at","createdAt","toISOString","updated_at","updatedAt","started_at","startedAt","finished_at","finishedAt","EMPTY_JOBS","preview","statusCounts","rawStatusCounts","toRunListItemDto","jobs","map","job","key","mode","listener_status","listenerStatus","execution_status","executionStatus","position","job_status_counts","count","job_display_status_counts","reference","repository","ref","commit","actor","toRunAttemptDto","attempt","workflow_run_id","workflowRunId","rerun_mode","rerunMode"],"mappings":"AAUA,OAAO,SAASA,SAASC,GAAgB,EAAEC,gBAAgBD,IAAIE,cAAc;IAC3E,OAAO;QACLC,IAAIH,IAAIG,EAAE;QACVC,YAAYJ,IAAIK,SAAS;QACzBC,eAAeN,IAAIO,YAAY;QAC/BC,QAAQR,IAAIQ,MAAM;QAClBC,MAAMT,IAAIS,IAAI;QACdC,eAAeV,IAAIW,YAAY;QAC/BC,QAAQZ,IAAIY,MAAM;QAClBC,iBAAiBb,IAAIE,cAAc;QACnCY,gBAAgBb;QAChBc,kBAAkBf,IAAIgB,eAAe;QACrCC,gBAAgBjB,IAAIkB,aAAa;QACjCC,eAAenB,IAAIoB,YAAY;QAC/BC,iBAAiBrB,IAAIsB,cAAc;QACnCC,mBAAmBC,sBAAsBxB,IAAIyB,gBAAgB;QAC7DC,QAAQ1B,IAAI0B,MAAM;QAClBC,iBAAiB3B,IAAI4B,cAAc;QACnCC,YAAY7B,IAAI8B,SAAS,CAACC,WAAW;QACrCC,YAAYhC,IAAIiC,SAAS,CAACF,WAAW;QACrCG,YAAYlC,IAAImC,SAAS,EAAEJ,iBAAiB;QAC5CK,aAAapC,IAAIqC,UAAU,EAAEN,iBAAiB;IAChD;AACF;AAEA,MAAMO,aAAqC;IAACC,SAAS,EAAE;IAAEC,cAAc,EAAE;IAAEC,iBAAiB,EAAE;AAAA;AAE9F,OAAO,SAASC,iBACd1C,GAAgB,EAChB2C,OAA+BL,UAAU;IAEzC,OAAO;QACL,GAAGvC,SAASC,IAAI;QAChB2C,MAAMA,KAAKJ,OAAO,CAACK,GAAG,CAAC,CAACC,MAAS,CAAA;gBAC/B1C,IAAI0C,IAAI1C,EAAE;gBACV2C,KAAKD,IAAIC,GAAG;gBACZrC,MAAMoC,IAAIpC,IAAI;gBACdG,QAAQiC,IAAIjC,MAAM;gBAClBmC,MAAMF,IAAIE,IAAI;gBACdC,iBAAiBH,IAAII,cAAc;gBACnCC,kBAAkBL,IAAIM,eAAe;gBACrCC,UAAUP,IAAIO,QAAQ;YACxB,CAAA;QACAC,mBAAmBV,KAAKF,eAAe,CAACG,GAAG,CAAC,CAAC,EAAChC,MAAM,EAAE0C,KAAK,EAAC,GAAM,CAAA;gBAAC1C;gBAAQ0C;YAAK,CAAA;QAChFC,2BAA2BZ,KAAKH,YAAY,CAACI,GAAG,CAAC,CAAC,EAAChC,MAAM,EAAE0C,KAAK,EAAC,GAAM,CAAA;gBAAC1C;gBAAQ0C;YAAK,CAAA;IACvF;AACF;AAEA,6FAA6F;AAC7F,sFAAsF;AACtF,SAAS9B,sBACPgC,SAAyD;IAEzD,IAAI,CAACA,WAAW,OAAO;IACvB,OAAO;QACLC,YAAYD,UAAUC,UAAU,IAAI;QACpCC,KAAKF,UAAUE,GAAG,IAAI;QACtBC,QAAQH,UAAUG,MAAM,IAAI;QAC5BC,OAAOJ,UAAUI,KAAK,IAAI;IAC5B;AACF;AAEA,OAAO,SAASC,gBAAgBC,OAA2B;IACzD,OAAO;QACL3D,IAAI2D,QAAQ3D,EAAE;QACd4D,iBAAiBD,QAAQE,aAAa;QACtCF,SAASA,QAAQA,OAAO;QACxBlD,QAAQkD,QAAQlD,MAAM;QACtBiB,YAAYiC,QAAQhC,SAAS,CAACC,WAAW;QACzCG,YAAY4B,QAAQ3B,SAAS,EAAEJ,iBAAiB;QAChDK,aAAa0B,QAAQzB,UAAU,EAAEN,iBAAiB;QAClDkC,YAAYH,QAAQI,SAAS;IAC/B;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/dto/workflow-run.ts"],"sourcesContent":["import type {\n WorkflowRunAttemptDto,\n WorkflowRunDto,\n WorkflowRunListItemDto,\n WorkflowRunTriggerReferenceDto,\n} from '@shipfox/api-workflows-dto';\nimport type {WorkflowRun, WorkflowRunTriggerReference} from '#core/entities/workflow-run.js';\nimport type {WorkflowRunAttempt} from '#core/entities/workflow-run-attempt.js';\nimport type {WorkflowRunJobsSummary} from '#db/index.js';\n\nexport function toRunDto(run: WorkflowRun, latestAttempt = run.currentAttempt): WorkflowRunDto {\n return {\n id: run.id,\n project_id: run.projectId,\n definition_id: run.definitionId,\n number: run.number,\n name: run.name,\n workflow_name: run.workflowName,\n status: run.status,\n current_attempt: run.currentAttempt,\n latest_attempt: latestAttempt,\n trigger_provider: run.triggerProvider,\n trigger_source: run.triggerSource,\n trigger_event: run.triggerEvent,\n trigger_payload: run.triggerPayload,\n trigger_reference: toTriggerReferenceDto(run.triggerReference),\n inputs: run.inputs,\n source_snapshot: run.sourceSnapshot,\n created_at: run.createdAt.toISOString(),\n updated_at: run.updatedAt.toISOString(),\n started_at: run.startedAt?.toISOString() ?? null,\n finished_at: run.finishedAt?.toISOString() ?? null,\n };\n}\n\nconst EMPTY_JOBS: WorkflowRunJobsSummary = {\n preview: [],\n statusCounts: [],\n rawStatusCounts: [],\n hasStartedJobExecution: false,\n};\n\nexport function toRunListItemDto(\n run: WorkflowRun,\n jobs: WorkflowRunJobsSummary = EMPTY_JOBS,\n): WorkflowRunListItemDto {\n return {\n ...toRunDto(run),\n jobs: jobs.preview.map((job) => ({\n id: job.id,\n key: job.key,\n name: job.name,\n status: job.status,\n mode: job.mode,\n listener_status: job.listenerStatus,\n execution_status: job.executionStatus,\n position: job.position,\n })),\n job_status_counts: jobs.rawStatusCounts.map(({status, count}) => ({status, count})),\n job_display_status_counts: jobs.statusCounts.map(({status, count}) => ({status, count})),\n has_started_job_execution: jobs.hasStartedJobExecution,\n };\n}\n\n// The persisted reference predates `actor` and carries an internal project id the client has\n// no use for, so each field is read defensively rather than spread onto the response.\nfunction toTriggerReferenceDto(\n reference: WorkflowRunTriggerReference | null | undefined,\n): WorkflowRunTriggerReferenceDto | null {\n if (!reference) return null;\n return {\n repository: reference.repository ?? null,\n ref: reference.ref ?? null,\n commit: reference.commit ?? null,\n actor: reference.actor ?? null,\n };\n}\n\nexport function toRunAttemptDto(attempt: WorkflowRunAttempt): WorkflowRunAttemptDto {\n return {\n id: attempt.id,\n workflow_run_id: attempt.workflowRunId,\n attempt: attempt.attempt,\n status: attempt.status,\n created_at: attempt.createdAt.toISOString(),\n started_at: attempt.startedAt?.toISOString() ?? null,\n finished_at: attempt.finishedAt?.toISOString() ?? null,\n rerun_mode: attempt.rerunMode,\n };\n}\n"],"names":["toRunDto","run","latestAttempt","currentAttempt","id","project_id","projectId","definition_id","definitionId","number","name","workflow_name","workflowName","status","current_attempt","latest_attempt","trigger_provider","triggerProvider","trigger_source","triggerSource","trigger_event","triggerEvent","trigger_payload","triggerPayload","trigger_reference","toTriggerReferenceDto","triggerReference","inputs","source_snapshot","sourceSnapshot","created_at","createdAt","toISOString","updated_at","updatedAt","started_at","startedAt","finished_at","finishedAt","EMPTY_JOBS","preview","statusCounts","rawStatusCounts","hasStartedJobExecution","toRunListItemDto","jobs","map","job","key","mode","listener_status","listenerStatus","execution_status","executionStatus","position","job_status_counts","count","job_display_status_counts","has_started_job_execution","reference","repository","ref","commit","actor","toRunAttemptDto","attempt","workflow_run_id","workflowRunId","rerun_mode","rerunMode"],"mappings":"AAUA,OAAO,SAASA,SAASC,GAAgB,EAAEC,gBAAgBD,IAAIE,cAAc;IAC3E,OAAO;QACLC,IAAIH,IAAIG,EAAE;QACVC,YAAYJ,IAAIK,SAAS;QACzBC,eAAeN,IAAIO,YAAY;QAC/BC,QAAQR,IAAIQ,MAAM;QAClBC,MAAMT,IAAIS,IAAI;QACdC,eAAeV,IAAIW,YAAY;QAC/BC,QAAQZ,IAAIY,MAAM;QAClBC,iBAAiBb,IAAIE,cAAc;QACnCY,gBAAgBb;QAChBc,kBAAkBf,IAAIgB,eAAe;QACrCC,gBAAgBjB,IAAIkB,aAAa;QACjCC,eAAenB,IAAIoB,YAAY;QAC/BC,iBAAiBrB,IAAIsB,cAAc;QACnCC,mBAAmBC,sBAAsBxB,IAAIyB,gBAAgB;QAC7DC,QAAQ1B,IAAI0B,MAAM;QAClBC,iBAAiB3B,IAAI4B,cAAc;QACnCC,YAAY7B,IAAI8B,SAAS,CAACC,WAAW;QACrCC,YAAYhC,IAAIiC,SAAS,CAACF,WAAW;QACrCG,YAAYlC,IAAImC,SAAS,EAAEJ,iBAAiB;QAC5CK,aAAapC,IAAIqC,UAAU,EAAEN,iBAAiB;IAChD;AACF;AAEA,MAAMO,aAAqC;IACzCC,SAAS,EAAE;IACXC,cAAc,EAAE;IAChBC,iBAAiB,EAAE;IACnBC,wBAAwB;AAC1B;AAEA,OAAO,SAASC,iBACd3C,GAAgB,EAChB4C,OAA+BN,UAAU;IAEzC,OAAO;QACL,GAAGvC,SAASC,IAAI;QAChB4C,MAAMA,KAAKL,OAAO,CAACM,GAAG,CAAC,CAACC,MAAS,CAAA;gBAC/B3C,IAAI2C,IAAI3C,EAAE;gBACV4C,KAAKD,IAAIC,GAAG;gBACZtC,MAAMqC,IAAIrC,IAAI;gBACdG,QAAQkC,IAAIlC,MAAM;gBAClBoC,MAAMF,IAAIE,IAAI;gBACdC,iBAAiBH,IAAII,cAAc;gBACnCC,kBAAkBL,IAAIM,eAAe;gBACrCC,UAAUP,IAAIO,QAAQ;YACxB,CAAA;QACAC,mBAAmBV,KAAKH,eAAe,CAACI,GAAG,CAAC,CAAC,EAACjC,MAAM,EAAE2C,KAAK,EAAC,GAAM,CAAA;gBAAC3C;gBAAQ2C;YAAK,CAAA;QAChFC,2BAA2BZ,KAAKJ,YAAY,CAACK,GAAG,CAAC,CAAC,EAACjC,MAAM,EAAE2C,KAAK,EAAC,GAAM,CAAA;gBAAC3C;gBAAQ2C;YAAK,CAAA;QACrFE,2BAA2Bb,KAAKF,sBAAsB;IACxD;AACF;AAEA,6FAA6F;AAC7F,sFAAsF;AACtF,SAASlB,sBACPkC,SAAyD;IAEzD,IAAI,CAACA,WAAW,OAAO;IACvB,OAAO;QACLC,YAAYD,UAAUC,UAAU,IAAI;QACpCC,KAAKF,UAAUE,GAAG,IAAI;QACtBC,QAAQH,UAAUG,MAAM,IAAI;QAC5BC,OAAOJ,UAAUI,KAAK,IAAI;IAC5B;AACF;AAEA,OAAO,SAASC,gBAAgBC,OAA2B;IACzD,OAAO;QACL7D,IAAI6D,QAAQ7D,EAAE;QACd8D,iBAAiBD,QAAQE,aAAa;QACtCF,SAASA,QAAQA,OAAO;QACxBpD,QAAQoD,QAAQpD,MAAM;QACtBiB,YAAYmC,QAAQlC,SAAS,CAACC,WAAW;QACzCG,YAAY8B,QAAQ7B,SAAS,EAAEJ,iBAAiB;QAChDK,aAAa4B,QAAQ3B,UAAU,EAAEN,iBAAiB;QAClDoC,YAAYH,QAAQI,SAAS;IAC/B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-run.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/get-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AAejF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,oBAAoB,mDAqDzD"}
1
+ {"version":3,"file":"get-run.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/get-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AAejF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,oBAAoB,mDAsDzD"}
@@ -54,7 +54,8 @@ export function getRunRoute(projects) {
54
54
  return {
55
55
  ...toRunDto(run, run.latestAttempt),
56
56
  run_attempt: toRunAttemptDto(run.runAttempt),
57
- jobs: jobDtos
57
+ jobs: jobDtos,
58
+ has_started_job_execution: run.hasStartedJobExecution
58
59
  };
59
60
  }
60
61
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/get-run.ts"],"sourcesContent":["import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport {workflowRunDetailResponseSchema} from '@shipfox/api-workflows-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {getWorkflowRunDetail} from '#db/index.js';\nimport {\n toJobDto,\n toJobExecutionDto,\n toRunAttemptDto,\n toRunDto,\n toStepAttemptDto,\n toStepDto,\n} from '#presentation/dto/index.js';\nimport {requireAccessibleRun} from './require-accessible-run.js';\n\nexport function getRunRoute(projects: ProjectsModuleClient) {\n return defineRoute({\n method: 'GET',\n path: '/:id',\n description: 'Get a workflow run by ID with jobs and steps',\n schema: {\n params: z.object({\n id: z.string().uuid(),\n }),\n querystring: z.object({\n attempt: z.coerce.number().int().positive().optional(),\n }),\n response: {\n 200: workflowRunDetailResponseSchema,\n },\n },\n handler: async (request) => {\n const {id} = request.params;\n await requireAccessibleRun({request, id, projects});\n\n const run = await getWorkflowRunDetail(id, request.query.attempt);\n if (!run) {\n throw new ClientError('Run not found', 'not-found', {status: 404});\n }\n\n const jobDtos = run.jobs.map((job) => ({\n ...toJobDto(job),\n job_executions: job.jobExecutions.map((jobExecution) => ({\n ...toJobExecutionDto(jobExecution),\n steps: jobExecution.steps.map((step) => {\n const attempts = step.attempts.map(toStepAttemptDto);\n const latestTerminalAttempt = attempts\n .filter((attempt) => attempt.status !== 'running')\n .at(-1);\n return {\n ...toStepDto(step),\n exit_code: latestTerminalAttempt?.exit_code ?? null,\n outputs: latestTerminalAttempt?.outputs ?? null,\n response: latestTerminalAttempt?.response ?? null,\n gate_result: latestTerminalAttempt?.gate_result ?? null,\n attempts,\n };\n }),\n })),\n }));\n\n return {\n ...toRunDto(run, run.latestAttempt),\n run_attempt: toRunAttemptDto(run.runAttempt),\n jobs: jobDtos,\n };\n },\n });\n}\n"],"names":["workflowRunDetailResponseSchema","ClientError","defineRoute","z","getWorkflowRunDetail","toJobDto","toJobExecutionDto","toRunAttemptDto","toRunDto","toStepAttemptDto","toStepDto","requireAccessibleRun","getRunRoute","projects","method","path","description","schema","params","object","id","string","uuid","querystring","attempt","coerce","number","int","positive","optional","response","handler","request","run","query","status","jobDtos","jobs","map","job","job_executions","jobExecutions","jobExecution","steps","step","attempts","latestTerminalAttempt","filter","at","exit_code","outputs","gate_result","latestAttempt","run_attempt","runAttempt"],"mappings":"AACA,SAAQA,+BAA+B,QAAO,6BAA6B;AAC3E,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,oBAAoB,QAAO,eAAe;AAClD,SACEC,QAAQ,EACRC,iBAAiB,EACjBC,eAAe,EACfC,QAAQ,EACRC,gBAAgB,EAChBC,SAAS,QACJ,6BAA6B;AACpC,SAAQC,oBAAoB,QAAO,8BAA8B;AAEjE,OAAO,SAASC,YAAYC,QAA8B;IACxD,OAAOX,YAAY;QACjBY,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,QAAQf,EAAEgB,MAAM,CAAC;gBACfC,IAAIjB,EAAEkB,MAAM,GAAGC,IAAI;YACrB;YACAC,aAAapB,EAAEgB,MAAM,CAAC;gBACpBK,SAASrB,EAAEsB,MAAM,CAACC,MAAM,GAAGC,GAAG,GAAGC,QAAQ,GAAGC,QAAQ;YACtD;YACAC,UAAU;gBACR,KAAK9B;YACP;QACF;QACA+B,SAAS,OAAOC;YACd,MAAM,EAACZ,EAAE,EAAC,GAAGY,QAAQd,MAAM;YAC3B,MAAMP,qBAAqB;gBAACqB;gBAASZ;gBAAIP;YAAQ;YAEjD,MAAMoB,MAAM,MAAM7B,qBAAqBgB,IAAIY,QAAQE,KAAK,CAACV,OAAO;YAChE,IAAI,CAACS,KAAK;gBACR,MAAM,IAAIhC,YAAY,iBAAiB,aAAa;oBAACkC,QAAQ;gBAAG;YAClE;YAEA,MAAMC,UAAUH,IAAII,IAAI,CAACC,GAAG,CAAC,CAACC,MAAS,CAAA;oBACrC,GAAGlC,SAASkC,IAAI;oBAChBC,gBAAgBD,IAAIE,aAAa,CAACH,GAAG,CAAC,CAACI,eAAkB,CAAA;4BACvD,GAAGpC,kBAAkBoC,aAAa;4BAClCC,OAAOD,aAAaC,KAAK,CAACL,GAAG,CAAC,CAACM;gCAC7B,MAAMC,WAAWD,KAAKC,QAAQ,CAACP,GAAG,CAAC7B;gCACnC,MAAMqC,wBAAwBD,SAC3BE,MAAM,CAAC,CAACvB,UAAYA,QAAQW,MAAM,KAAK,WACvCa,EAAE,CAAC,CAAC;gCACP,OAAO;oCACL,GAAGtC,UAAUkC,KAAK;oCAClBK,WAAWH,uBAAuBG,aAAa;oCAC/CC,SAASJ,uBAAuBI,WAAW;oCAC3CpB,UAAUgB,uBAAuBhB,YAAY;oCAC7CqB,aAAaL,uBAAuBK,eAAe;oCACnDN;gCACF;4BACF;wBACF,CAAA;gBACF,CAAA;YAEA,OAAO;gBACL,GAAGrC,SAASyB,KAAKA,IAAImB,aAAa,CAAC;gBACnCC,aAAa9C,gBAAgB0B,IAAIqB,UAAU;gBAC3CjB,MAAMD;YACR;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/get-run.ts"],"sourcesContent":["import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport {workflowRunDetailResponseSchema} from '@shipfox/api-workflows-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {getWorkflowRunDetail} from '#db/index.js';\nimport {\n toJobDto,\n toJobExecutionDto,\n toRunAttemptDto,\n toRunDto,\n toStepAttemptDto,\n toStepDto,\n} from '#presentation/dto/index.js';\nimport {requireAccessibleRun} from './require-accessible-run.js';\n\nexport function getRunRoute(projects: ProjectsModuleClient) {\n return defineRoute({\n method: 'GET',\n path: '/:id',\n description: 'Get a workflow run by ID with jobs and steps',\n schema: {\n params: z.object({\n id: z.string().uuid(),\n }),\n querystring: z.object({\n attempt: z.coerce.number().int().positive().optional(),\n }),\n response: {\n 200: workflowRunDetailResponseSchema,\n },\n },\n handler: async (request) => {\n const {id} = request.params;\n await requireAccessibleRun({request, id, projects});\n\n const run = await getWorkflowRunDetail(id, request.query.attempt);\n if (!run) {\n throw new ClientError('Run not found', 'not-found', {status: 404});\n }\n\n const jobDtos = run.jobs.map((job) => ({\n ...toJobDto(job),\n job_executions: job.jobExecutions.map((jobExecution) => ({\n ...toJobExecutionDto(jobExecution),\n steps: jobExecution.steps.map((step) => {\n const attempts = step.attempts.map(toStepAttemptDto);\n const latestTerminalAttempt = attempts\n .filter((attempt) => attempt.status !== 'running')\n .at(-1);\n return {\n ...toStepDto(step),\n exit_code: latestTerminalAttempt?.exit_code ?? null,\n outputs: latestTerminalAttempt?.outputs ?? null,\n response: latestTerminalAttempt?.response ?? null,\n gate_result: latestTerminalAttempt?.gate_result ?? null,\n attempts,\n };\n }),\n })),\n }));\n\n return {\n ...toRunDto(run, run.latestAttempt),\n run_attempt: toRunAttemptDto(run.runAttempt),\n jobs: jobDtos,\n has_started_job_execution: run.hasStartedJobExecution,\n };\n },\n });\n}\n"],"names":["workflowRunDetailResponseSchema","ClientError","defineRoute","z","getWorkflowRunDetail","toJobDto","toJobExecutionDto","toRunAttemptDto","toRunDto","toStepAttemptDto","toStepDto","requireAccessibleRun","getRunRoute","projects","method","path","description","schema","params","object","id","string","uuid","querystring","attempt","coerce","number","int","positive","optional","response","handler","request","run","query","status","jobDtos","jobs","map","job","job_executions","jobExecutions","jobExecution","steps","step","attempts","latestTerminalAttempt","filter","at","exit_code","outputs","gate_result","latestAttempt","run_attempt","runAttempt","has_started_job_execution","hasStartedJobExecution"],"mappings":"AACA,SAAQA,+BAA+B,QAAO,6BAA6B;AAC3E,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,oBAAoB,QAAO,eAAe;AAClD,SACEC,QAAQ,EACRC,iBAAiB,EACjBC,eAAe,EACfC,QAAQ,EACRC,gBAAgB,EAChBC,SAAS,QACJ,6BAA6B;AACpC,SAAQC,oBAAoB,QAAO,8BAA8B;AAEjE,OAAO,SAASC,YAAYC,QAA8B;IACxD,OAAOX,YAAY;QACjBY,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,QAAQf,EAAEgB,MAAM,CAAC;gBACfC,IAAIjB,EAAEkB,MAAM,GAAGC,IAAI;YACrB;YACAC,aAAapB,EAAEgB,MAAM,CAAC;gBACpBK,SAASrB,EAAEsB,MAAM,CAACC,MAAM,GAAGC,GAAG,GAAGC,QAAQ,GAAGC,QAAQ;YACtD;YACAC,UAAU;gBACR,KAAK9B;YACP;QACF;QACA+B,SAAS,OAAOC;YACd,MAAM,EAACZ,EAAE,EAAC,GAAGY,QAAQd,MAAM;YAC3B,MAAMP,qBAAqB;gBAACqB;gBAASZ;gBAAIP;YAAQ;YAEjD,MAAMoB,MAAM,MAAM7B,qBAAqBgB,IAAIY,QAAQE,KAAK,CAACV,OAAO;YAChE,IAAI,CAACS,KAAK;gBACR,MAAM,IAAIhC,YAAY,iBAAiB,aAAa;oBAACkC,QAAQ;gBAAG;YAClE;YAEA,MAAMC,UAAUH,IAAII,IAAI,CAACC,GAAG,CAAC,CAACC,MAAS,CAAA;oBACrC,GAAGlC,SAASkC,IAAI;oBAChBC,gBAAgBD,IAAIE,aAAa,CAACH,GAAG,CAAC,CAACI,eAAkB,CAAA;4BACvD,GAAGpC,kBAAkBoC,aAAa;4BAClCC,OAAOD,aAAaC,KAAK,CAACL,GAAG,CAAC,CAACM;gCAC7B,MAAMC,WAAWD,KAAKC,QAAQ,CAACP,GAAG,CAAC7B;gCACnC,MAAMqC,wBAAwBD,SAC3BE,MAAM,CAAC,CAACvB,UAAYA,QAAQW,MAAM,KAAK,WACvCa,EAAE,CAAC,CAAC;gCACP,OAAO;oCACL,GAAGtC,UAAUkC,KAAK;oCAClBK,WAAWH,uBAAuBG,aAAa;oCAC/CC,SAASJ,uBAAuBI,WAAW;oCAC3CpB,UAAUgB,uBAAuBhB,YAAY;oCAC7CqB,aAAaL,uBAAuBK,eAAe;oCACnDN;gCACF;4BACF;wBACF,CAAA;gBACF,CAAA;YAEA,OAAO;gBACL,GAAGrC,SAASyB,KAAKA,IAAImB,aAAa,CAAC;gBACnCC,aAAa9C,gBAAgB0B,IAAIqB,UAAU;gBAC3CjB,MAAMD;gBACNmB,2BAA2BtB,IAAIuB,sBAAsB;YACvD;QACF;IACF;AACF"}