@cascade-flow/backend-postgres 0.2.5 → 0.2.8

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/dist/index.js CHANGED
@@ -4744,6 +4744,7 @@ import {
4744
4744
  projectRunStateFromEvents,
4745
4745
  extractLogsFromEvents,
4746
4746
  getCurrentAttemptNumber,
4747
+ getVersionIdFromEvents,
4747
4748
  getMicrosecondTimestamp,
4748
4749
  computeErrorAnalysis,
4749
4750
  computeRetryAnalysis,
@@ -4773,6 +4774,10 @@ var esm_default = import_lib.default;
4773
4774
 
4774
4775
  // src/db.ts
4775
4776
  var { Pool: Pool2 } = esm_default;
4777
+ function stripEventIdFromJson(event) {
4778
+ const { eventId, ...eventWithoutId } = event;
4779
+ return eventWithoutId;
4780
+ }
4776
4781
 
4777
4782
  class DatabaseClient {
4778
4783
  pool;
@@ -4807,9 +4812,18 @@ class DatabaseClient {
4807
4812
  } else if ("workflowAttemptNumber" in we) {
4808
4813
  workflowAttemptNumber = we.workflowAttemptNumber;
4809
4814
  }
4810
- if (we.type === "WorkflowStarted") {
4815
+ if (we.type === "WorkflowStarted" || we.type === "WorkflowResumed") {
4811
4816
  versionId = we.versionId;
4812
4817
  }
4818
+ if (versionId === null) {
4819
+ const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
4820
+ WHERE workflow_slug = $1 AND run_id = $2
4821
+ AND type IN ('WorkflowStarted', 'RunSubmitted')
4822
+ AND version_id IS NOT NULL
4823
+ ORDER BY timestamp_us DESC, event_id DESC
4824
+ LIMIT 1`, [we.workflowSlug, we.runId]);
4825
+ versionId = versionResult.rows[0]?.version_id ?? null;
4826
+ }
4813
4827
  await client.query(`INSERT INTO ${this.schema}.workflow_events (
4814
4828
  event_id, workflow_slug, run_id, timestamp_us, category, type, event_data,
4815
4829
  workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
@@ -4821,7 +4835,7 @@ class DatabaseClient {
4821
4835
  we.timestampUs,
4822
4836
  we.category,
4823
4837
  we.type,
4824
- JSON.stringify(event),
4838
+ JSON.stringify(stripEventIdFromJson(event)),
4825
4839
  workflowAttemptNumber,
4826
4840
  availableAtUs,
4827
4841
  priority,
@@ -4860,7 +4874,10 @@ class DatabaseClient {
4860
4874
  errorStackPortableHash = se.errorFingerprints.stackPortableHash;
4861
4875
  }
4862
4876
  const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
4863
- WHERE workflow_slug = $1 AND run_id = $2 AND version_id IS NOT NULL
4877
+ WHERE workflow_slug = $1 AND run_id = $2
4878
+ AND type IN ('WorkflowStarted', 'RunSubmitted')
4879
+ AND version_id IS NOT NULL
4880
+ ORDER BY timestamp_us DESC, event_id DESC
4864
4881
  LIMIT 1`, [se.workflowSlug, se.runId]);
4865
4882
  const versionId = versionResult.rows[0]?.version_id ?? null;
4866
4883
  await client.query(`INSERT INTO ${this.schema}.step_events (
@@ -4877,7 +4894,7 @@ class DatabaseClient {
4877
4894
  se.timestampUs,
4878
4895
  se.category,
4879
4896
  se.type,
4880
- JSON.stringify(event),
4897
+ JSON.stringify(stripEventIdFromJson(event)),
4881
4898
  workerId,
4882
4899
  attemptNumber,
4883
4900
  availableAtUs,
@@ -4915,6 +4932,15 @@ class DatabaseClient {
4915
4932
  if (we.type === "WorkflowStarted") {
4916
4933
  versionId = we.versionId;
4917
4934
  }
4935
+ if (versionId === null) {
4936
+ const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
4937
+ WHERE workflow_slug = $1 AND run_id = $2
4938
+ AND type IN ('WorkflowStarted', 'RunSubmitted')
4939
+ AND version_id IS NOT NULL
4940
+ ORDER BY timestamp_us DESC, event_id DESC
4941
+ LIMIT 1`, [we.workflowSlug, we.runId]);
4942
+ versionId = versionResult.rows[0]?.version_id ?? null;
4943
+ }
4918
4944
  await client.query(`INSERT INTO ${this.schema}.workflow_events (
4919
4945
  event_id, workflow_slug, run_id, timestamp_us, category, type, event_data,
4920
4946
  workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
@@ -4926,7 +4952,7 @@ class DatabaseClient {
4926
4952
  we.timestampUs,
4927
4953
  we.category,
4928
4954
  we.type,
4929
- JSON.stringify(event),
4955
+ JSON.stringify(stripEventIdFromJson(event)),
4930
4956
  workflowAttemptNumber,
4931
4957
  availableAtUs,
4932
4958
  priority,
@@ -4965,7 +4991,10 @@ class DatabaseClient {
4965
4991
  errorStackPortableHash = se.errorFingerprints.stackPortableHash;
4966
4992
  }
4967
4993
  const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
4968
- WHERE workflow_slug = $1 AND run_id = $2 AND version_id IS NOT NULL
4994
+ WHERE workflow_slug = $1 AND run_id = $2
4995
+ AND type IN ('WorkflowStarted', 'RunSubmitted')
4996
+ AND version_id IS NOT NULL
4997
+ ORDER BY timestamp_us DESC, event_id DESC
4969
4998
  LIMIT 1`, [se.workflowSlug, se.runId]);
4970
4999
  const versionId = versionResult.rows[0]?.version_id ?? null;
4971
5000
  await client.query(`INSERT INTO ${this.schema}.step_events (
@@ -4982,7 +5011,7 @@ class DatabaseClient {
4982
5011
  se.timestampUs,
4983
5012
  se.category,
4984
5013
  se.type,
4985
- JSON.stringify(event),
5014
+ JSON.stringify(stripEventIdFromJson(event)),
4986
5015
  workerId,
4987
5016
  attemptNumber,
4988
5017
  availableAtUs,
@@ -5024,12 +5053,12 @@ class DatabaseClient {
5024
5053
  }
5025
5054
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
5026
5055
  const query = `
5027
- SELECT event_data FROM ${this.schema}.${table}
5056
+ SELECT event_data, event_id FROM ${this.schema}.${table}
5028
5057
  ${whereClause}
5029
5058
  ORDER BY timestamp_us ASC, event_id ASC
5030
5059
  `;
5031
5060
  const result = await client.query(query, values);
5032
- return result.rows.map((row) => row.event_data);
5061
+ return result.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
5033
5062
  } finally {
5034
5063
  client.release();
5035
5064
  }
@@ -5046,7 +5075,7 @@ class DatabaseClient {
5046
5075
  ORDER BY timestamp_us ASC, event_id ASC
5047
5076
  `;
5048
5077
  const result = await client.query(query, [workflowSlug, runId]);
5049
- return result.rows.map((row) => row.event_data);
5078
+ return result.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
5050
5079
  } finally {
5051
5080
  client.release();
5052
5081
  }
@@ -5090,13 +5119,20 @@ class DatabaseClient {
5090
5119
  errorStackNormalizedHash = eventToWrite.errorFingerprints.stackNormalizedHash;
5091
5120
  errorStackPortableHash = eventToWrite.errorFingerprints.stackPortableHash;
5092
5121
  }
5122
+ const versionResult = await client.query(`SELECT version_id FROM ${this.schema}.workflow_events
5123
+ WHERE workflow_slug = $1 AND run_id = $2
5124
+ AND type IN ('WorkflowStarted', 'RunSubmitted')
5125
+ AND version_id IS NOT NULL
5126
+ ORDER BY timestamp_us DESC, event_id DESC
5127
+ LIMIT 1`, [eventToWrite.workflowSlug, eventToWrite.runId]);
5128
+ const versionId = versionResult.rows[0]?.version_id ?? null;
5093
5129
  await client.query(`INSERT INTO ${this.schema}.step_events (
5094
5130
  event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data,
5095
5131
  worker_id, attempt_number, available_at_us, export_output,
5096
5132
  error_name_hash, error_message_hash, error_stack_exact_hash,
5097
- error_stack_normalized_hash, error_stack_portable_hash
5133
+ error_stack_normalized_hash, error_stack_portable_hash, version_id
5098
5134
  )
5099
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`, [
5135
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)`, [
5100
5136
  eventToWrite.eventId,
5101
5137
  eventToWrite.workflowSlug,
5102
5138
  eventToWrite.runId,
@@ -5104,7 +5140,7 @@ class DatabaseClient {
5104
5140
  eventToWrite.timestampUs,
5105
5141
  eventToWrite.category,
5106
5142
  eventToWrite.type,
5107
- JSON.stringify(eventToWrite),
5143
+ JSON.stringify(stripEventIdFromJson(eventToWrite)),
5108
5144
  workerId2,
5109
5145
  attemptNumber,
5110
5146
  null,
@@ -5113,7 +5149,8 @@ class DatabaseClient {
5113
5149
  errorMessageHash,
5114
5150
  errorStackExactHash,
5115
5151
  errorStackNormalizedHash,
5116
- errorStackPortableHash
5152
+ errorStackPortableHash,
5153
+ versionId
5117
5154
  ]);
5118
5155
  await client.query("COMMIT");
5119
5156
  return true;
@@ -5309,6 +5346,59 @@ class DatabaseClient {
5309
5346
  client.release();
5310
5347
  }
5311
5348
  }
5349
+ async getWorkflowVersion(workflowSlug, versionId) {
5350
+ const client = await this.pool.connect();
5351
+ try {
5352
+ const result = await client.query(`WITH numbered_versions AS (
5353
+ SELECT *,
5354
+ ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
5355
+ FROM ${this.schema}.workflow_versions
5356
+ WHERE workflow_slug = $1
5357
+ )
5358
+ SELECT * FROM numbered_versions WHERE version_id = $2`, [workflowSlug, versionId]);
5359
+ if (result.rows.length === 0)
5360
+ return null;
5361
+ return result.rows[0];
5362
+ } finally {
5363
+ client.release();
5364
+ }
5365
+ }
5366
+ async getCurrentWorkflowVersion(workflowSlug) {
5367
+ const client = await this.pool.connect();
5368
+ try {
5369
+ const result = await client.query(`WITH numbered_versions AS (
5370
+ SELECT *,
5371
+ ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
5372
+ FROM ${this.schema}.workflow_versions
5373
+ WHERE workflow_slug = $1
5374
+ )
5375
+ SELECT * FROM numbered_versions
5376
+ ORDER BY created_at DESC
5377
+ LIMIT 1`, [workflowSlug]);
5378
+ if (result.rows.length === 0)
5379
+ return null;
5380
+ return result.rows[0];
5381
+ } finally {
5382
+ client.release();
5383
+ }
5384
+ }
5385
+ async listWorkflowVersions(workflowSlug, limit) {
5386
+ const client = await this.pool.connect();
5387
+ try {
5388
+ const result = await client.query(`WITH numbered_versions AS (
5389
+ SELECT *,
5390
+ ROW_NUMBER() OVER (PARTITION BY workflow_slug ORDER BY created_at ASC) as version_number
5391
+ FROM ${this.schema}.workflow_versions
5392
+ WHERE workflow_slug = $1
5393
+ )
5394
+ SELECT * FROM numbered_versions
5395
+ ORDER BY created_at DESC
5396
+ LIMIT $2`, [workflowSlug, limit]);
5397
+ return result.rows;
5398
+ } finally {
5399
+ client.release();
5400
+ }
5401
+ }
5312
5402
  async saveIdempotencyKey(hash, runId) {
5313
5403
  const client = await this.pool.connect();
5314
5404
  try {
@@ -5734,6 +5824,200 @@ class PostgresBackend extends Backend {
5734
5824
  return this.db.loadAllRunEvents(workflowSlug, runId);
5735
5825
  }
5736
5826
  }
5827
+ async copyEntireRun(workflowSlug, sourceRunId, targetRunId) {
5828
+ await this.copyEntireRunWithClient(workflowSlug, sourceRunId, targetRunId, this.db.getPool());
5829
+ }
5830
+ async copyEntireRunWithClient(workflowSlug, sourceRunId, targetRunId, client) {
5831
+ const schema = this.db.getSchema();
5832
+ await client.query(`INSERT INTO ${schema}.workflow_events (
5833
+ event_id, workflow_slug, run_id, timestamp_us, category, type, event_data, created_at,
5834
+ workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
5835
+ )
5836
+ SELECT
5837
+ gen_random_uuid()::text,
5838
+ workflow_slug,
5839
+ $2,
5840
+ timestamp_us,
5841
+ category,
5842
+ type,
5843
+ jsonb_set(event_data, '{runId}', to_jsonb($2::text)),
5844
+ created_at,
5845
+ workflow_attempt_number,
5846
+ available_at_us,
5847
+ priority,
5848
+ timeout_us,
5849
+ idempotency_key,
5850
+ version_id
5851
+ FROM ${schema}.workflow_events
5852
+ WHERE workflow_slug = $1 AND run_id = $3`, [workflowSlug, targetRunId, sourceRunId]);
5853
+ await client.query(`INSERT INTO ${schema}.step_events (
5854
+ event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data, created_at,
5855
+ worker_id, attempt_number, available_at_us, export_output,
5856
+ error_name_hash, error_message_hash, error_stack_exact_hash, error_stack_normalized_hash, error_stack_portable_hash,
5857
+ version_id
5858
+ )
5859
+ SELECT
5860
+ gen_random_uuid()::text,
5861
+ workflow_slug,
5862
+ $2,
5863
+ step_id,
5864
+ timestamp_us,
5865
+ category,
5866
+ type,
5867
+ jsonb_set(event_data, '{runId}', to_jsonb($2::text)),
5868
+ created_at,
5869
+ worker_id,
5870
+ attempt_number,
5871
+ available_at_us,
5872
+ export_output,
5873
+ error_name_hash,
5874
+ error_message_hash,
5875
+ error_stack_exact_hash,
5876
+ error_stack_normalized_hash,
5877
+ error_stack_portable_hash,
5878
+ version_id
5879
+ FROM ${schema}.step_events
5880
+ WHERE workflow_slug = $1 AND run_id = $3`, [workflowSlug, targetRunId, sourceRunId]);
5881
+ }
5882
+ async deleteStepEvents(workflowSlug, runId, stepIds) {
5883
+ await this.deleteStepEventsWithClient(workflowSlug, runId, stepIds, this.db.getPool());
5884
+ }
5885
+ async deleteStepEventsWithClient(workflowSlug, runId, stepIds, client) {
5886
+ if (stepIds.size === 0)
5887
+ return;
5888
+ const schema = this.db.getSchema();
5889
+ const stepIdsArray = Array.from(stepIds);
5890
+ await client.query(`DELETE FROM ${schema}.step_events
5891
+ WHERE workflow_slug = $1 AND run_id = $2 AND step_id = ANY($3)`, [workflowSlug, runId, stepIdsArray]);
5892
+ }
5893
+ async deleteWorkflowTerminalEvents(workflowSlug, runId) {
5894
+ await this.deleteWorkflowTerminalEventsWithClient(workflowSlug, runId, this.db.getPool());
5895
+ }
5896
+ async deleteWorkflowTerminalEventsWithClient(workflowSlug, runId, client) {
5897
+ const schema = this.db.getSchema();
5898
+ await client.query(`DELETE FROM ${schema}.workflow_events
5899
+ WHERE workflow_slug = $1
5900
+ AND run_id = $2
5901
+ AND type IN ('WorkflowCompleted', 'WorkflowFailed', 'WorkflowCancelled')`, [workflowSlug, runId]);
5902
+ }
5903
+ async copyWorkflowEvents(workflowSlug, sourceRunId, targetRunId, excludeTerminal) {
5904
+ const pool = this.db.getPool();
5905
+ const schema = this.db.getSchema();
5906
+ const terminalFilter = excludeTerminal ? `AND type NOT IN ('WorkflowCompleted', 'WorkflowFailed', 'WorkflowCancelled')` : "";
5907
+ await pool.query(`INSERT INTO ${schema}.workflow_events (
5908
+ event_id, workflow_slug, run_id, timestamp_us, category, type, event_data, created_at,
5909
+ workflow_attempt_number, available_at_us, priority, timeout_us, idempotency_key, version_id
5910
+ )
5911
+ SELECT
5912
+ gen_random_uuid()::text,
5913
+ workflow_slug,
5914
+ $3,
5915
+ timestamp_us,
5916
+ category,
5917
+ type,
5918
+ jsonb_set(event_data, '{runId}', to_jsonb($3::text)),
5919
+ created_at,
5920
+ workflow_attempt_number,
5921
+ available_at_us,
5922
+ priority,
5923
+ timeout_us,
5924
+ idempotency_key,
5925
+ version_id
5926
+ FROM ${schema}.workflow_events
5927
+ WHERE workflow_slug = $1
5928
+ AND run_id = $2
5929
+ ${terminalFilter}`, [workflowSlug, sourceRunId, targetRunId]);
5930
+ }
5931
+ async copyStepEvents(workflowSlug, sourceRunId, targetRunId, includeStepIds) {
5932
+ const pool = this.db.getPool();
5933
+ const schema = this.db.getSchema();
5934
+ const stepIdsArray = Array.from(includeStepIds);
5935
+ if (stepIdsArray.length === 0)
5936
+ return;
5937
+ await pool.query(`INSERT INTO ${schema}.step_events (
5938
+ event_id, workflow_slug, run_id, step_id, timestamp_us, category, type, event_data, created_at,
5939
+ worker_id, attempt_number, available_at_us, export_output,
5940
+ error_name_hash, error_message_hash, error_stack_exact_hash, error_stack_normalized_hash, error_stack_portable_hash,
5941
+ version_id
5942
+ )
5943
+ SELECT
5944
+ gen_random_uuid()::text,
5945
+ workflow_slug,
5946
+ $3,
5947
+ step_id,
5948
+ timestamp_us,
5949
+ category,
5950
+ type,
5951
+ jsonb_set(event_data, '{runId}', to_jsonb($3::text)),
5952
+ created_at,
5953
+ worker_id,
5954
+ attempt_number,
5955
+ available_at_us,
5956
+ export_output,
5957
+ error_name_hash,
5958
+ error_message_hash,
5959
+ error_stack_exact_hash,
5960
+ error_stack_normalized_hash,
5961
+ error_stack_portable_hash,
5962
+ version_id
5963
+ FROM ${schema}.step_events
5964
+ WHERE workflow_slug = $1
5965
+ AND run_id = $2
5966
+ AND step_id = ANY($4)`, [workflowSlug, sourceRunId, targetRunId, stepIdsArray]);
5967
+ }
5968
+ async rerunFrom(params) {
5969
+ const parentRun = await this.getRun(params.parentRunId);
5970
+ if (!parentRun) {
5971
+ throw new Error(`Parent run "${params.parentRunId}" not found`);
5972
+ }
5973
+ const dependents = await this.calculateDependents(parentRun.workflowSlug, params.fromStepId);
5974
+ const rerunStepIds = new Set([params.fromStepId, ...dependents]);
5975
+ const newRunId = getMicrosecondTimestamp().toString();
5976
+ const pool = this.db.getPool();
5977
+ const client = await pool.connect();
5978
+ try {
5979
+ await client.query("BEGIN");
5980
+ await this.copyEntireRunWithClient(parentRun.workflowSlug, params.parentRunId, newRunId, client);
5981
+ await this.deleteStepEventsWithClient(parentRun.workflowSlug, newRunId, rerunStepIds, client);
5982
+ await this.deleteWorkflowTerminalEventsWithClient(parentRun.workflowSlug, newRunId, client);
5983
+ await client.query("COMMIT");
5984
+ } catch (error) {
5985
+ await client.query("ROLLBACK");
5986
+ throw error;
5987
+ } finally {
5988
+ client.release();
5989
+ }
5990
+ const currentVersion = await this.getCurrentWorkflowVersion(parentRun.workflowSlug);
5991
+ if (!currentVersion) {
5992
+ throw new Error(`Workflow ${parentRun.workflowSlug} not registered. Please ensure the worker has started and registered workflows.`);
5993
+ }
5994
+ const parentWorkflowEvents = await this.loadEvents(parentRun.workflowSlug, params.parentRunId, {
5995
+ category: "workflow"
5996
+ });
5997
+ const parentVersionId = getVersionIdFromEvents(parentWorkflowEvents);
5998
+ const timestamp = getMicrosecondTimestamp();
5999
+ await this.appendEvent(parentRun.workflowSlug, newRunId, {
6000
+ category: "workflow",
6001
+ type: "WorkflowRerunFromStep",
6002
+ eventId: this.generateEventId(timestamp),
6003
+ timestampUs: timestamp,
6004
+ workflowSlug: parentRun.workflowSlug,
6005
+ runId: newRunId,
6006
+ parentRunId: params.parentRunId,
6007
+ rerunFromStepId: params.fromStepId,
6008
+ rerunStepIds: Array.from(rerunStepIds),
6009
+ versionId: currentVersion.versionId,
6010
+ parentVersionId
6011
+ });
6012
+ await this.submitRun({
6013
+ workflowSlug: parentRun.workflowSlug,
6014
+ runId: newRunId,
6015
+ input: params.input
6016
+ });
6017
+ return {
6018
+ runId: newRunId
6019
+ };
6020
+ }
5737
6021
  async saveStepScheduled(workflowSlug, runId, stepId, metadata) {
5738
6022
  const now = getMicrosecondTimestamp();
5739
6023
  const event = {
@@ -6025,6 +6309,7 @@ class PostgresBackend extends Backend {
6025
6309
  timestampUs: timestamp,
6026
6310
  workflowSlug,
6027
6311
  runId,
6312
+ versionId: metadata.versionId,
6028
6313
  originalRunId: metadata.originalRunId,
6029
6314
  resumedSteps: metadata.resumedSteps,
6030
6315
  pendingSteps: metadata.pendingSteps
@@ -6327,20 +6612,17 @@ class PostgresBackend extends Backend {
6327
6612
  ]);
6328
6613
  }
6329
6614
  async getWorkflowVersion(workflowSlug, versionId) {
6330
- const result = await this.db.getPool().query(`
6331
- SELECT * FROM ${this.db.getSchema()}.workflow_versions
6332
- WHERE workflow_slug = $1 AND version_id = $2
6333
- `, [workflowSlug, versionId]);
6334
- if (result.rows.length === 0)
6615
+ const row = await this.db.getWorkflowVersion(workflowSlug, versionId);
6616
+ if (!row)
6335
6617
  return null;
6336
- const row = result.rows[0];
6337
6618
  return {
6338
6619
  workflowSlug: row.workflow_slug,
6339
6620
  versionId: row.version_id,
6621
+ versionNumber: parseInt(row.version_number.toString(), 10),
6340
6622
  createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
6341
6623
  stepManifest: row.step_manifest,
6342
6624
  totalSteps: row.total_steps,
6343
- git: row.git_commit ? {
6625
+ git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
6344
6626
  commit: row.git_commit,
6345
6627
  dirty: row.git_dirty,
6346
6628
  branch: row.git_branch
@@ -6348,22 +6630,17 @@ class PostgresBackend extends Backend {
6348
6630
  };
6349
6631
  }
6350
6632
  async getCurrentWorkflowVersion(workflowSlug) {
6351
- const result = await this.db.getPool().query(`
6352
- SELECT * FROM ${this.db.getSchema()}.workflow_versions
6353
- WHERE workflow_slug = $1
6354
- ORDER BY created_at DESC
6355
- LIMIT 1
6356
- `, [workflowSlug]);
6357
- if (result.rows.length === 0)
6633
+ const row = await this.db.getCurrentWorkflowVersion(workflowSlug);
6634
+ if (!row)
6358
6635
  return null;
6359
- const row = result.rows[0];
6360
6636
  return {
6361
6637
  workflowSlug: row.workflow_slug,
6362
6638
  versionId: row.version_id,
6639
+ versionNumber: parseInt(row.version_number.toString(), 10),
6363
6640
  createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
6364
6641
  stepManifest: row.step_manifest,
6365
6642
  totalSteps: row.total_steps,
6366
- git: row.git_commit ? {
6643
+ git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
6367
6644
  commit: row.git_commit,
6368
6645
  dirty: row.git_dirty,
6369
6646
  branch: row.git_branch
@@ -6372,19 +6649,15 @@ class PostgresBackend extends Backend {
6372
6649
  }
6373
6650
  async listWorkflowVersions(workflowSlug, options) {
6374
6651
  const limit = options?.limit ?? 100;
6375
- const result = await this.db.getPool().query(`
6376
- SELECT * FROM ${this.db.getSchema()}.workflow_versions
6377
- WHERE workflow_slug = $1
6378
- ORDER BY created_at DESC
6379
- LIMIT $2
6380
- `, [workflowSlug, limit]);
6381
- return result.rows.map((row) => ({
6652
+ const rows = await this.db.listWorkflowVersions(workflowSlug, limit);
6653
+ return rows.map((row) => ({
6382
6654
  workflowSlug: row.workflow_slug,
6383
6655
  versionId: row.version_id,
6656
+ versionNumber: parseInt(row.version_number.toString(), 10),
6384
6657
  createdAt: Math.floor(new Date(row.created_at).getTime() * 1000),
6385
6658
  stepManifest: row.step_manifest,
6386
6659
  totalSteps: row.total_steps,
6387
- git: row.git_commit ? {
6660
+ git: row.git_commit && row.git_dirty !== null && row.git_branch !== null ? {
6388
6661
  commit: row.git_commit,
6389
6662
  dirty: row.git_dirty,
6390
6663
  branch: row.git_branch
@@ -6399,7 +6672,7 @@ class PostgresBackend extends Backend {
6399
6672
  const startUs = options?.startUs ?? now - 24 * 60 * 60 * 1000 * 1000;
6400
6673
  const endUs = options?.endUs ?? now;
6401
6674
  let stepQuery = `
6402
- SELECT event_data
6675
+ SELECT event_data, event_id
6403
6676
  FROM ${this.db.getSchema()}.step_events
6404
6677
  WHERE timestamp_us >= $1 AND timestamp_us <= $2
6405
6678
  `;
@@ -6423,7 +6696,7 @@ class PostgresBackend extends Backend {
6423
6696
  }
6424
6697
  stepQuery += ` ORDER BY timestamp_us ASC`;
6425
6698
  let workflowQuery = `
6426
- SELECT event_data
6699
+ SELECT event_data, event_id
6427
6700
  FROM ${this.db.getSchema()}.workflow_events
6428
6701
  WHERE timestamp_us >= $1 AND timestamp_us <= $2
6429
6702
  `;
@@ -6445,8 +6718,8 @@ class PostgresBackend extends Backend {
6445
6718
  this.db.getPool().query(stepQuery, stepParams),
6446
6719
  options?.stepId ? Promise.resolve({ rows: [] }) : this.db.getPool().query(workflowQuery, workflowParams)
6447
6720
  ]);
6448
- const stepEvents = stepResult.rows.map((row) => row.event_data);
6449
- const workflowEvents = workflowResult.rows.map((row) => row.event_data);
6721
+ const stepEvents = stepResult.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
6722
+ const workflowEvents = workflowResult.rows.map((row) => ({ ...row.event_data, eventId: row.event_id }));
6450
6723
  return { stepEvents, workflowEvents };
6451
6724
  }
6452
6725
  async getErrorAnalysis(options) {
@@ -6793,4 +7066,4 @@ export {
6793
7066
  PostgresBackend
6794
7067
  };
6795
7068
 
6796
- //# debugId=D60A61AD3A02516564756E2164756E21
7069
+ //# debugId=53B1DE663ECDB0B364756E2164756E21