@sixb/sqlite 0.1.17 → 0.1.19
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/action-run-storage.d.ts +4 -9
- package/dist/action-run-storage.d.ts.map +1 -1
- package/dist/index.js +248 -284
- package/dist/index.js.map +4 -4
- package/dist/migrations.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/action-run-storage.ts +104 -442
- package/src/migrations/060-terminal-action-runs.sql +149 -0
- package/src/migrations.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -25,12 +25,8 @@ import {
|
|
|
25
25
|
serializeActionRunFailure
|
|
26
26
|
} from "@sixb/core/internal/action-run-storage";
|
|
27
27
|
import { assertActionRunExecution } from "@sixb/core/internal/action-run-storage-provider";
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
canRequeueActionRunAfterEnqueueFailure,
|
|
31
|
-
finishActionRunPhase
|
|
32
|
-
} from "@sixb/core/internal/storage";
|
|
33
|
-
import { ActionRunError, isTerminalActionRun } from "@sixb/core/storage";
|
|
28
|
+
import { normalizeRecordActionRunInput, resolveActionRunEffects } from "@sixb/core/internal/storage";
|
|
29
|
+
import { ActionRunError } from "@sixb/core/storage";
|
|
34
30
|
|
|
35
31
|
// src/migrations.ts
|
|
36
32
|
import { Database } from "bun:sqlite";
|
|
@@ -4994,6 +4990,158 @@ CREATE INDEX idx_ontology_sources_drained
|
|
|
4994
4990
|
WHERE status = 'superseded' AND root_count = 0;
|
|
4995
4991
|
`;
|
|
4996
4992
|
|
|
4993
|
+
// src/migrations/060-terminal-action-runs.sql
|
|
4994
|
+
var _060_terminal_action_runs_default = `-- Actions run in the request that asks for them and record their run once, when it ends. No run
|
|
4995
|
+
-- is queued, running, or cancelled any more, and every run has started and finished. SQLite cannot
|
|
4996
|
+
-- alter a CHECK constraint, so the table is rebuilt.
|
|
4997
|
+
CREATE TABLE action_runs_v2 (
|
|
4998
|
+
project_id TEXT NOT NULL,
|
|
4999
|
+
id TEXT NOT NULL,
|
|
5000
|
+
execution_id TEXT NOT NULL,
|
|
5001
|
+
action_id TEXT NOT NULL,
|
|
5002
|
+
subject_kind TEXT NOT NULL CHECK (subject_kind IN ('none', 'object')),
|
|
5003
|
+
object_type_id TEXT,
|
|
5004
|
+
primary_id TEXT,
|
|
5005
|
+
status TEXT NOT NULL CHECK (status IN ('succeeded', 'failed')),
|
|
5006
|
+
phase TEXT NOT NULL CHECK (phase IN ('validation', 'writeback', 'edits', 'commit', 'effects')),
|
|
5007
|
+
started_at TEXT NOT NULL,
|
|
5008
|
+
finished_at TEXT NOT NULL,
|
|
5009
|
+
params TEXT NOT NULL,
|
|
5010
|
+
idempotency_key TEXT NOT NULL,
|
|
5011
|
+
writeback_status TEXT CHECK (writeback_status IS NULL OR writeback_status IN ('succeeded', 'failed')),
|
|
5012
|
+
writeback_completed_at TEXT,
|
|
5013
|
+
writeback_result TEXT,
|
|
5014
|
+
writeback_error TEXT CHECK (writeback_error IS NULL OR json_valid(writeback_error)),
|
|
5015
|
+
effects_status TEXT CHECK (effects_status IS NULL OR effects_status IN ('succeeded', 'failed')),
|
|
5016
|
+
effects_completed_at TEXT,
|
|
5017
|
+
effects_error TEXT CHECK (effects_error IS NULL OR json_valid(effects_error)),
|
|
5018
|
+
error TEXT CHECK (error IS NULL OR json_valid(error)),
|
|
5019
|
+
CHECK (
|
|
5020
|
+
(subject_kind = 'none' AND object_type_id IS NULL AND primary_id IS NULL)
|
|
5021
|
+
OR (subject_kind = 'object' AND object_type_id IS NOT NULL AND primary_id IS NOT NULL)
|
|
5022
|
+
),
|
|
5023
|
+
CHECK ((status = 'failed') = (error IS NOT NULL)),
|
|
5024
|
+
PRIMARY KEY (project_id, id),
|
|
5025
|
+
UNIQUE (project_id, execution_id)
|
|
5026
|
+
);
|
|
5027
|
+
|
|
5028
|
+
INSERT INTO action_runs_v2 (
|
|
5029
|
+
project_id, id, execution_id, action_id, subject_kind, object_type_id, primary_id, status,
|
|
5030
|
+
phase, started_at, finished_at, params, idempotency_key, writeback_status,
|
|
5031
|
+
writeback_completed_at, writeback_result, writeback_error, effects_status,
|
|
5032
|
+
effects_completed_at, effects_error, error
|
|
5033
|
+
)
|
|
5034
|
+
SELECT
|
|
5035
|
+
project_id, id, execution_id, action_id, subject_kind, object_type_id, primary_id,
|
|
5036
|
+
migrated_status, migrated_phase,
|
|
5037
|
+
-- A run starts when it was queued at the latest.
|
|
5038
|
+
COALESCE(started_at, queued_at),
|
|
5039
|
+
migrated_finished_at,
|
|
5040
|
+
params, idempotency_key, writeback_status,
|
|
5041
|
+
CASE
|
|
5042
|
+
WHEN writeback_status IS NULL THEN NULL
|
|
5043
|
+
ELSE COALESCE(writeback_completed_at, migrated_finished_at)
|
|
5044
|
+
END,
|
|
5045
|
+
writeback_result, writeback_error,
|
|
5046
|
+
CASE WHEN effects_abandoned THEN 'failed' ELSE effects_status END,
|
|
5047
|
+
CASE
|
|
5048
|
+
WHEN effects_abandoned THEN migrated_at
|
|
5049
|
+
WHEN effects_status IS NULL THEN NULL
|
|
5050
|
+
ELSE COALESCE(effects_completed_at, migrated_finished_at)
|
|
5051
|
+
END,
|
|
5052
|
+
CASE
|
|
5053
|
+
WHEN effects_abandoned THEN json_object(
|
|
5054
|
+
'code', 'internal.unexpected',
|
|
5055
|
+
'message', 'Abandoned: Actions now run synchronously; these effects never finished.',
|
|
5056
|
+
'retryable', json('false'),
|
|
5057
|
+
'at', migrated_at,
|
|
5058
|
+
'details', json_object('actionId', action_id, 'runId', id, 'phase', 'effects')
|
|
5059
|
+
)
|
|
5060
|
+
ELSE effects_error
|
|
5061
|
+
END,
|
|
5062
|
+
-- A failure names the phase its run ended in.
|
|
5063
|
+
CASE
|
|
5064
|
+
WHEN migrated_error IS NULL THEN NULL
|
|
5065
|
+
WHEN json_extract(migrated_error, '$.details.phase') IS migrated_phase THEN migrated_error
|
|
5066
|
+
ELSE json_set(migrated_error, '$.details.phase', migrated_phase)
|
|
5067
|
+
END
|
|
5068
|
+
FROM (
|
|
5069
|
+
SELECT
|
|
5070
|
+
*,
|
|
5071
|
+
CASE
|
|
5072
|
+
WHEN status = 'succeeded' OR edits_committed THEN 'succeeded'
|
|
5073
|
+
ELSE 'failed'
|
|
5074
|
+
END AS migrated_status,
|
|
5075
|
+
CASE
|
|
5076
|
+
WHEN edits_committed THEN CASE WHEN phase = 'effects' THEN 'effects' ELSE 'commit' END
|
|
5077
|
+
-- The phases \`request\`, \`enqueue\`, and \`cancelled\` are gone: a run that stopped in one of
|
|
5078
|
+
-- them never got past validation.
|
|
5079
|
+
WHEN phase IN ('validation', 'writeback', 'edits', 'commit', 'effects') THEN phase
|
|
5080
|
+
ELSE 'validation'
|
|
5081
|
+
END AS migrated_phase,
|
|
5082
|
+
CASE
|
|
5083
|
+
WHEN edits_committed THEN committed_at
|
|
5084
|
+
WHEN status IN ('queued', 'running') THEN migrated_at
|
|
5085
|
+
ELSE COALESCE(finished_at, migrated_at)
|
|
5086
|
+
END AS migrated_finished_at,
|
|
5087
|
+
edits_committed AND phase = 'effects' AND effects_status IS NULL AS effects_abandoned,
|
|
5088
|
+
CASE
|
|
5089
|
+
WHEN edits_committed THEN NULL
|
|
5090
|
+
WHEN status IN ('queued', 'running') THEN json_object(
|
|
5091
|
+
'code', 'internal.unexpected',
|
|
5092
|
+
'message', 'Abandoned: Actions now run synchronously; this run never finished.',
|
|
5093
|
+
'retryable', json('false'),
|
|
5094
|
+
'at', migrated_at,
|
|
5095
|
+
'details', json_object('actionId', action_id, 'runId', id)
|
|
5096
|
+
)
|
|
5097
|
+
-- Every failed run carries a failure. One recorded before failures were kept explains
|
|
5098
|
+
-- itself.
|
|
5099
|
+
WHEN status IN ('failed', 'cancelled') AND error IS NULL THEN json_object(
|
|
5100
|
+
'code', 'internal.unexpected',
|
|
5101
|
+
'message', 'This run failed before Sixb recorded why.',
|
|
5102
|
+
'retryable', json('false'),
|
|
5103
|
+
'at', COALESCE(finished_at, migrated_at),
|
|
5104
|
+
'details', json_object('actionId', action_id, 'runId', id)
|
|
5105
|
+
)
|
|
5106
|
+
-- An enqueue failure, which no run can meet any more, reads as the unexpected error it
|
|
5107
|
+
-- now is.
|
|
5108
|
+
WHEN json_extract(error, '$.code') = 'queue.enqueue_failed'
|
|
5109
|
+
THEN json_set(error, '$.code', 'internal.unexpected', '$.retryable', json('false'))
|
|
5110
|
+
ELSE error
|
|
5111
|
+
END AS migrated_error
|
|
5112
|
+
FROM (
|
|
5113
|
+
SELECT
|
|
5114
|
+
run.*,
|
|
5115
|
+
committed.committed_at,
|
|
5116
|
+
strftime('%Y-%m-%dT%H:%M:%fZ', 'now') AS migrated_at,
|
|
5117
|
+
-- A run left running after its edits committed, as a crash between the commit and the end
|
|
5118
|
+
-- of the run left it, succeeded: its edits and their outbox facts are in the commit. A run
|
|
5119
|
+
-- that stopped during its effects keeps that phase, and records effects that never ended.
|
|
5120
|
+
-- Any other run left queued or running never finished, and nothing will resume it. A
|
|
5121
|
+
-- cancelled run failed, and keeps the failure it recorded.
|
|
5122
|
+
run.status IN ('queued', 'running') AND committed.committed_at IS NOT NULL
|
|
5123
|
+
AS edits_committed
|
|
5124
|
+
FROM action_runs AS run
|
|
5125
|
+
LEFT JOIN ontology_commits AS committed
|
|
5126
|
+
ON committed.origin_kind = 'action'
|
|
5127
|
+
AND committed.project_id = run.project_id
|
|
5128
|
+
AND committed.origin_run_id = run.id
|
|
5129
|
+
)
|
|
5130
|
+
);
|
|
5131
|
+
|
|
5132
|
+
DROP TABLE action_runs;
|
|
5133
|
+
ALTER TABLE action_runs_v2 RENAME TO action_runs;
|
|
5134
|
+
|
|
5135
|
+
CREATE INDEX idx_action_runs_project_started
|
|
5136
|
+
ON action_runs(project_id, started_at DESC);
|
|
5137
|
+
CREATE INDEX idx_action_runs_project_action_started
|
|
5138
|
+
ON action_runs(project_id, action_id, started_at DESC);
|
|
5139
|
+
CREATE INDEX idx_action_runs_project_object_started
|
|
5140
|
+
ON action_runs(project_id, object_type_id, primary_id, started_at DESC);
|
|
5141
|
+
CREATE INDEX idx_action_runs_project_status_started
|
|
5142
|
+
ON action_runs(project_id, status, started_at DESC);
|
|
5143
|
+
`;
|
|
5144
|
+
|
|
4997
5145
|
// src/migrations.ts
|
|
4998
5146
|
var MIGRATIONS_TABLE_SQL = `
|
|
4999
5147
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -5100,7 +5248,8 @@ var sqliteStorageMigrations = defineMigrations({
|
|
|
5100
5248
|
sqliteSql("056-audio-transcription", _056_audio_transcription_default),
|
|
5101
5249
|
sqliteSql("057-reranking-model-kind", _057_reranking_model_kind_default),
|
|
5102
5250
|
sqliteSql("058-file-download-grants", _058_file_download_grants_default),
|
|
5103
|
-
sqliteSql("059-drained-source-versions", _059_drained_source_versions_default)
|
|
5251
|
+
sqliteSql("059-drained-source-versions", _059_drained_source_versions_default),
|
|
5252
|
+
sqliteSql("060-terminal-action-runs", _060_terminal_action_runs_default)
|
|
5104
5253
|
]
|
|
5105
5254
|
});
|
|
5106
5255
|
function sqliteStoragePath(basePath) {
|
|
@@ -5437,174 +5586,50 @@ class SqliteActionRunStorage {
|
|
|
5437
5586
|
installFreshSqliteSchema(this.db);
|
|
5438
5587
|
}
|
|
5439
5588
|
}
|
|
5440
|
-
async
|
|
5441
|
-
const
|
|
5442
|
-
if (!row) {
|
|
5443
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.runId}' not found for project '${input.projectId}'.`);
|
|
5444
|
-
}
|
|
5445
|
-
if (row.action_id !== input.actionId) {
|
|
5446
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.runId}' does not belong to action '${input.actionId}'.`);
|
|
5447
|
-
}
|
|
5448
|
-
if (row.status !== "running") {
|
|
5449
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.runId}' cannot materialize from status '${row.status}'.`);
|
|
5450
|
-
}
|
|
5451
|
-
const record = await this.getById({ projectId: input.projectId, id: input.runId });
|
|
5452
|
-
if (!record) {
|
|
5453
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.runId}' disappeared while locking materialization.`);
|
|
5454
|
-
}
|
|
5455
|
-
return record;
|
|
5456
|
-
}
|
|
5457
|
-
async queue(input) {
|
|
5458
|
-
const queuedAt = input.queuedAt ?? new Date;
|
|
5589
|
+
async record(input) {
|
|
5590
|
+
const record = normalizeRecordActionRunInput(input);
|
|
5459
5591
|
await assertActionRunExecution({
|
|
5460
5592
|
executions: this.executions,
|
|
5461
|
-
projectId:
|
|
5462
|
-
executionId:
|
|
5463
|
-
runId:
|
|
5464
|
-
actionId:
|
|
5593
|
+
projectId: record.projectId,
|
|
5594
|
+
executionId: record.executionId,
|
|
5595
|
+
runId: record.id,
|
|
5596
|
+
actionId: record.actionId
|
|
5465
5597
|
});
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?,
|
|
5493
|
-
NULL, NULL, NULL, NULL,
|
|
5494
|
-
NULL, NULL, NULL,
|
|
5495
|
-
NULL
|
|
5496
|
-
)
|
|
5497
|
-
`).run(input.projectId, input.id, input.executionId, input.actionId, input.subject.kind, input.subject.kind === "object" ? input.subject.objectTypeId : null, input.subject.kind === "object" ? input.subject.primaryId : null, "queued", "request", queuedAt.toISOString(), JSON.stringify(input.params), input.idempotencyKey);
|
|
5498
|
-
} catch (error) {
|
|
5499
|
-
if (isUniqueConstraintError(error)) {
|
|
5500
|
-
return this.requeueAfterEnqueueFailure(input, queuedAt);
|
|
5501
|
-
}
|
|
5502
|
-
throw error;
|
|
5503
|
-
}
|
|
5504
|
-
const record = await this.getById({ projectId: input.projectId, id: input.id });
|
|
5505
|
-
if (!record) {
|
|
5506
|
-
throw new ActionRunError(`[SixbSqlite] Failed to load action run '${input.id}' for project '${input.projectId}'.`);
|
|
5598
|
+
const inserted = this.db.query(`
|
|
5599
|
+
INSERT INTO action_runs (
|
|
5600
|
+
project_id,
|
|
5601
|
+
id,
|
|
5602
|
+
execution_id,
|
|
5603
|
+
action_id,
|
|
5604
|
+
subject_kind,
|
|
5605
|
+
object_type_id,
|
|
5606
|
+
primary_id,
|
|
5607
|
+
status,
|
|
5608
|
+
phase,
|
|
5609
|
+
started_at,
|
|
5610
|
+
finished_at,
|
|
5611
|
+
params,
|
|
5612
|
+
idempotency_key,
|
|
5613
|
+
writeback_status,
|
|
5614
|
+
writeback_completed_at,
|
|
5615
|
+
writeback_result,
|
|
5616
|
+
writeback_error,
|
|
5617
|
+
error
|
|
5618
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5619
|
+
ON CONFLICT DO NOTHING
|
|
5620
|
+
`).run(record.projectId, record.id, record.executionId, record.actionId, record.subject.kind, record.subject.kind === "object" ? record.subject.objectTypeId : null, record.subject.kind === "object" ? record.subject.primaryId : null, record.status, record.phase, record.startedAt.toISOString(), record.finishedAt.toISOString(), JSON.stringify(record.params), record.idempotencyKey, record.writeback?.status ?? null, record.writeback?.completedAt.toISOString() ?? null, record.writeback?.status === "succeeded" ? JSON.stringify(record.writeback.result) : null, record.writeback?.status === "failed" ? serializeActionRunFailure(record.writeback.error, "writeback") : null, record.status === "failed" ? serializeActionRunFailure(record.error) : null);
|
|
5621
|
+
if (inserted.changes === 0) {
|
|
5622
|
+
const conflict = this.selectRow(record.projectId, record.id);
|
|
5623
|
+
throw new ActionRunError(conflict ? `[SixbSqlite] Action run '${record.id}' is already recorded for project '${record.projectId}'.` : `[SixbSqlite] Execution '${record.executionId}' already belongs to another Action run.`);
|
|
5507
5624
|
}
|
|
5508
|
-
return record;
|
|
5509
|
-
}
|
|
5510
|
-
async requeueAfterEnqueueFailure(input, queuedAt) {
|
|
5511
|
-
return this.db.transaction(() => {
|
|
5512
|
-
const existing = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5513
|
-
if (!existing || !canRequeueActionRunAfterEnqueueFailure(rowToActionRunRecord(existing), input)) {
|
|
5514
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
5515
|
-
}
|
|
5516
|
-
this.db.query(`
|
|
5517
|
-
UPDATE action_runs
|
|
5518
|
-
SET
|
|
5519
|
-
status = ?,
|
|
5520
|
-
phase = ?,
|
|
5521
|
-
queued_at = ?,
|
|
5522
|
-
started_at = NULL,
|
|
5523
|
-
finished_at = NULL,
|
|
5524
|
-
writeback_status = NULL,
|
|
5525
|
-
writeback_completed_at = NULL,
|
|
5526
|
-
writeback_result = NULL,
|
|
5527
|
-
writeback_error = NULL,
|
|
5528
|
-
effects_status = NULL,
|
|
5529
|
-
effects_completed_at = NULL,
|
|
5530
|
-
effects_error = NULL,
|
|
5531
|
-
error = NULL
|
|
5532
|
-
WHERE project_id = ? AND id = ?
|
|
5533
|
-
`).run("queued", "request", queuedAt.toISOString(), input.projectId, input.id);
|
|
5534
|
-
const updated = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5535
|
-
return rowToActionRunRecord(updated);
|
|
5536
|
-
})();
|
|
5537
|
-
}
|
|
5538
|
-
async start(input) {
|
|
5539
|
-
return this.db.transaction(() => {
|
|
5540
|
-
const existing = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5541
|
-
if (!existing) {
|
|
5542
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' not found for project '${input.projectId}'.`);
|
|
5543
|
-
}
|
|
5544
|
-
if (existing.status !== "queued") {
|
|
5545
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' cannot start from status '${existing.status}'.`);
|
|
5546
|
-
}
|
|
5547
|
-
this.db.query(`
|
|
5548
|
-
UPDATE action_runs
|
|
5549
|
-
SET
|
|
5550
|
-
status = ?,
|
|
5551
|
-
phase = ?,
|
|
5552
|
-
started_at = ?,
|
|
5553
|
-
error = NULL
|
|
5554
|
-
WHERE project_id = ? AND id = ?
|
|
5555
|
-
`).run("running", input.phase ?? "validation", (input.startedAt ?? new Date).toISOString(), input.projectId, input.id);
|
|
5556
|
-
const updated = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5557
|
-
return rowToActionRunRecord(updated);
|
|
5558
|
-
})();
|
|
5559
|
-
}
|
|
5560
|
-
async enterPhase(input) {
|
|
5561
|
-
return this.db.transaction(() => {
|
|
5562
|
-
this.requireRunningRun(input.projectId, input.id, "transition phase");
|
|
5563
|
-
this.db.query(`
|
|
5564
|
-
UPDATE action_runs
|
|
5565
|
-
SET phase = ?
|
|
5566
|
-
WHERE project_id = ? AND id = ?
|
|
5567
|
-
`).run(input.phase, input.projectId, input.id);
|
|
5568
|
-
const updated = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5569
|
-
return rowToActionRunRecord(updated);
|
|
5570
|
-
})();
|
|
5571
|
-
}
|
|
5572
|
-
async recordWriteback(input) {
|
|
5573
|
-
return this.db.transaction(() => {
|
|
5574
|
-
const existing = this.requireRunningRun(input.projectId, input.id, "record writeback");
|
|
5575
|
-
const nextWriteback = toWritebackRecord(input, new Date(input.completedAt ?? new Date));
|
|
5576
|
-
const currentWriteback = toActionRunWritebackRecord(existing);
|
|
5577
|
-
if (currentWriteback) {
|
|
5578
|
-
if (actionRunPhaseRecordsEqual(currentWriteback, nextWriteback)) {
|
|
5579
|
-
return rowToActionRunRecord(existing);
|
|
5580
|
-
}
|
|
5581
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' already has a different writeback record.`);
|
|
5582
|
-
}
|
|
5583
|
-
this.db.query(`
|
|
5584
|
-
UPDATE action_runs
|
|
5585
|
-
SET
|
|
5586
|
-
phase = ?,
|
|
5587
|
-
writeback_status = ?,
|
|
5588
|
-
writeback_completed_at = ?,
|
|
5589
|
-
writeback_result = ?,
|
|
5590
|
-
writeback_error = ?
|
|
5591
|
-
WHERE project_id = ? AND id = ?
|
|
5592
|
-
`).run("writeback", input.status, nextWriteback.completedAt.toISOString(), input.status === "succeeded" ? serializeJsonValue(input.result) : null, input.status === "failed" ? serializeActionRunFailure(input.error, "writeback") : null, input.projectId, input.id);
|
|
5593
|
-
const updated = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5594
|
-
return rowToActionRunRecord(updated);
|
|
5595
|
-
})();
|
|
5625
|
+
return rowToActionRunRecord(this.requireRow(record.projectId, record.id));
|
|
5596
5626
|
}
|
|
5597
5627
|
async recordEffects(input) {
|
|
5598
5628
|
return this.db.transaction(() => {
|
|
5599
|
-
const existing = this.
|
|
5600
|
-
const
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
if (actionRunPhaseRecordsEqual(currentEffects, nextEffects)) {
|
|
5604
|
-
return rowToActionRunRecord(existing);
|
|
5605
|
-
}
|
|
5606
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' already has a different effects record.`);
|
|
5607
|
-
}
|
|
5629
|
+
const existing = this.selectRow(input.projectId, input.id);
|
|
5630
|
+
const { run, effects } = resolveActionRunEffects(existing ? rowToActionRunRecord(existing) : null, input);
|
|
5631
|
+
if (!effects)
|
|
5632
|
+
return run;
|
|
5608
5633
|
this.db.query(`
|
|
5609
5634
|
UPDATE action_runs
|
|
5610
5635
|
SET
|
|
@@ -5613,32 +5638,8 @@ class SqliteActionRunStorage {
|
|
|
5613
5638
|
effects_completed_at = ?,
|
|
5614
5639
|
effects_error = ?
|
|
5615
5640
|
WHERE project_id = ? AND id = ?
|
|
5616
|
-
`).run("effects",
|
|
5617
|
-
|
|
5618
|
-
return rowToActionRunRecord(updated);
|
|
5619
|
-
})();
|
|
5620
|
-
}
|
|
5621
|
-
async finish(input) {
|
|
5622
|
-
return this.db.transaction(() => {
|
|
5623
|
-
const existing = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5624
|
-
if (!existing) {
|
|
5625
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' not found for project '${input.projectId}'.`);
|
|
5626
|
-
}
|
|
5627
|
-
if (isTerminalActionRun({ status: existing.status })) {
|
|
5628
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${input.id}' cannot finish from terminal status '${existing.status}'.`);
|
|
5629
|
-
}
|
|
5630
|
-
const phase = finishActionRunPhase(input, existing.phase);
|
|
5631
|
-
this.db.query(`
|
|
5632
|
-
UPDATE action_runs
|
|
5633
|
-
SET
|
|
5634
|
-
status = ?,
|
|
5635
|
-
phase = ?,
|
|
5636
|
-
finished_at = ?,
|
|
5637
|
-
error = ?
|
|
5638
|
-
WHERE project_id = ? AND id = ?
|
|
5639
|
-
`).run(input.status, phase, (input.finishedAt ?? new Date).toISOString(), input.status === "succeeded" ? null : serializeActionRunFailure(input.error), input.projectId, input.id);
|
|
5640
|
-
const updated = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
5641
|
-
return rowToActionRunRecord(updated);
|
|
5641
|
+
`).run("effects", effects.status, effects.completedAt.toISOString(), effects.status === "failed" ? serializeActionRunFailure(effects.error, "effects") : null, input.projectId, input.id);
|
|
5642
|
+
return rowToActionRunRecord(this.requireRow(input.projectId, input.id));
|
|
5642
5643
|
})();
|
|
5643
5644
|
}
|
|
5644
5645
|
async getById(params) {
|
|
@@ -5699,11 +5700,11 @@ class SqliteActionRunStorage {
|
|
|
5699
5700
|
args.push(...input.statuses);
|
|
5700
5701
|
}
|
|
5701
5702
|
if (input.startedAfter) {
|
|
5702
|
-
whereClauses.push("
|
|
5703
|
+
whereClauses.push("started_at >= ?");
|
|
5703
5704
|
args.push(input.startedAfter.toISOString());
|
|
5704
5705
|
}
|
|
5705
5706
|
if (input.startedBefore) {
|
|
5706
|
-
whereClauses.push("
|
|
5707
|
+
whereClauses.push("started_at <= ?");
|
|
5707
5708
|
args.push(input.startedBefore.toISOString());
|
|
5708
5709
|
}
|
|
5709
5710
|
const where = `WHERE ${whereClauses.join(" AND ")}`;
|
|
@@ -5714,7 +5715,7 @@ class SqliteActionRunStorage {
|
|
|
5714
5715
|
let query = `
|
|
5715
5716
|
SELECT * FROM action_runs
|
|
5716
5717
|
${where}
|
|
5717
|
-
ORDER BY
|
|
5718
|
+
ORDER BY started_at ${order}, id ${order}
|
|
5718
5719
|
`;
|
|
5719
5720
|
const queryArgs = [...args];
|
|
5720
5721
|
if (limit !== undefined) {
|
|
@@ -5735,31 +5736,22 @@ class SqliteActionRunStorage {
|
|
|
5735
5736
|
close() {
|
|
5736
5737
|
closeSqliteStoreConnection(this.connection);
|
|
5737
5738
|
}
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
if (
|
|
5744
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${id}'
|
|
5739
|
+
selectRow(projectId, id) {
|
|
5740
|
+
return this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(projectId, id);
|
|
5741
|
+
}
|
|
5742
|
+
requireRow(projectId, id) {
|
|
5743
|
+
const row = this.selectRow(projectId, id);
|
|
5744
|
+
if (!row) {
|
|
5745
|
+
throw new ActionRunError(`[SixbSqlite] Action run '${id}' disappeared from project '${projectId}' while recording it.`);
|
|
5745
5746
|
}
|
|
5746
|
-
return
|
|
5747
|
+
return row;
|
|
5747
5748
|
}
|
|
5748
5749
|
}
|
|
5749
|
-
function serializeJsonValue(value) {
|
|
5750
|
-
return JSON.stringify(value);
|
|
5751
|
-
}
|
|
5752
|
-
function toActionRunFailure(row) {
|
|
5753
|
-
return row.error === null ? undefined : parseActionRunFailure(row.error);
|
|
5754
|
-
}
|
|
5755
|
-
function parsePhaseFailure(value, expectedPhase) {
|
|
5756
|
-
return parseActionRunFailure(value, expectedPhase);
|
|
5757
|
-
}
|
|
5758
5750
|
function toActionRunWritebackRecord(row) {
|
|
5759
5751
|
if (!row.writeback_status) {
|
|
5760
5752
|
return;
|
|
5761
5753
|
}
|
|
5762
|
-
const completedAt =
|
|
5754
|
+
const completedAt = new Date(row.writeback_completed_at ?? row.finished_at);
|
|
5763
5755
|
if (row.writeback_status === "succeeded") {
|
|
5764
5756
|
return {
|
|
5765
5757
|
status: "succeeded",
|
|
@@ -5770,14 +5762,14 @@ function toActionRunWritebackRecord(row) {
|
|
|
5770
5762
|
return {
|
|
5771
5763
|
status: "failed",
|
|
5772
5764
|
completedAt,
|
|
5773
|
-
error:
|
|
5765
|
+
error: parseActionRunFailure(row.writeback_error, "writeback")
|
|
5774
5766
|
};
|
|
5775
5767
|
}
|
|
5776
5768
|
function toActionRunEffectsRecord(row) {
|
|
5777
5769
|
if (!row.effects_status) {
|
|
5778
5770
|
return;
|
|
5779
5771
|
}
|
|
5780
|
-
const completedAt =
|
|
5772
|
+
const completedAt = new Date(row.effects_completed_at ?? row.finished_at);
|
|
5781
5773
|
if (row.effects_status === "succeeded") {
|
|
5782
5774
|
return {
|
|
5783
5775
|
status: "succeeded",
|
|
@@ -5787,54 +5779,29 @@ function toActionRunEffectsRecord(row) {
|
|
|
5787
5779
|
return {
|
|
5788
5780
|
status: "failed",
|
|
5789
5781
|
completedAt,
|
|
5790
|
-
error:
|
|
5791
|
-
};
|
|
5792
|
-
}
|
|
5793
|
-
function toWritebackRecord(input, completedAt) {
|
|
5794
|
-
if (input.status === "succeeded") {
|
|
5795
|
-
return {
|
|
5796
|
-
status: "succeeded",
|
|
5797
|
-
completedAt,
|
|
5798
|
-
result: input.result
|
|
5799
|
-
};
|
|
5800
|
-
}
|
|
5801
|
-
return {
|
|
5802
|
-
status: "failed",
|
|
5803
|
-
completedAt,
|
|
5804
|
-
error: input.error
|
|
5805
|
-
};
|
|
5806
|
-
}
|
|
5807
|
-
function toEffectsRecord(input, completedAt) {
|
|
5808
|
-
if (input.status === "succeeded") {
|
|
5809
|
-
return {
|
|
5810
|
-
status: "succeeded",
|
|
5811
|
-
completedAt
|
|
5812
|
-
};
|
|
5813
|
-
}
|
|
5814
|
-
return {
|
|
5815
|
-
status: "failed",
|
|
5816
|
-
completedAt,
|
|
5817
|
-
error: input.error
|
|
5782
|
+
error: parseActionRunFailure(row.effects_error, "effects")
|
|
5818
5783
|
};
|
|
5819
5784
|
}
|
|
5820
5785
|
function rowToActionRunRecord(row) {
|
|
5821
|
-
|
|
5786
|
+
const writeback = toActionRunWritebackRecord(row);
|
|
5787
|
+
const effects = toActionRunEffectsRecord(row);
|
|
5788
|
+
const fields = {
|
|
5822
5789
|
id: row.id,
|
|
5823
5790
|
projectId: row.project_id,
|
|
5824
5791
|
executionId: row.execution_id,
|
|
5825
5792
|
actionId: row.action_id,
|
|
5826
5793
|
subject: rowToActionSubject(row),
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
startedAt: row.started_at ? new Date(row.started_at) : undefined,
|
|
5831
|
-
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
5794
|
+
phase: row.phase,
|
|
5795
|
+
startedAt: new Date(row.started_at),
|
|
5796
|
+
finishedAt: new Date(row.finished_at),
|
|
5832
5797
|
params: JSON.parse(row.params),
|
|
5833
5798
|
idempotencyKey: row.idempotency_key,
|
|
5834
|
-
writeback:
|
|
5835
|
-
effects:
|
|
5836
|
-
error: toActionRunFailure(row)
|
|
5799
|
+
...writeback === undefined ? {} : { writeback },
|
|
5800
|
+
...effects === undefined ? {} : { effects }
|
|
5837
5801
|
};
|
|
5802
|
+
if (row.status === "succeeded")
|
|
5803
|
+
return { ...fields, status: "succeeded" };
|
|
5804
|
+
return { ...fields, status: "failed", error: parseActionRunFailure(row.error) };
|
|
5838
5805
|
}
|
|
5839
5806
|
function rowToActionSubject(row) {
|
|
5840
5807
|
if (row.subject_kind === "none") {
|
|
@@ -5849,9 +5816,6 @@ function rowToActionSubject(row) {
|
|
|
5849
5816
|
primaryId: row.primary_id
|
|
5850
5817
|
};
|
|
5851
5818
|
}
|
|
5852
|
-
function isUniqueConstraintError(error) {
|
|
5853
|
-
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
5854
|
-
}
|
|
5855
5819
|
|
|
5856
5820
|
// src/agents/checkpoints.ts
|
|
5857
5821
|
import {
|
|
@@ -6105,7 +6069,7 @@ import {
|
|
|
6105
6069
|
} from "@sixb/core/storage";
|
|
6106
6070
|
|
|
6107
6071
|
// src/storage-errors.ts
|
|
6108
|
-
function
|
|
6072
|
+
function isUniqueConstraintError(error) {
|
|
6109
6073
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
6110
6074
|
}
|
|
6111
6075
|
function isForeignKeyConstraintError(error) {
|
|
@@ -6151,7 +6115,7 @@ class SqliteAgentMessageStore {
|
|
|
6151
6115
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6152
6116
|
`).run(input.projectId, input.id, input.threadId, input.runId, input.role, input.authorPrincipal?.type ?? null, input.authorPrincipal?.id ?? null, seqRow.next, JSON.stringify(input.parts), input.metadata === undefined ? null : JSON.stringify(input.metadata), AGENT_MESSAGE_CONTENT_VERSION, createdAt.toISOString(), input.completedAt ? input.completedAt.toISOString() : null);
|
|
6153
6117
|
} catch (error) {
|
|
6154
|
-
if (
|
|
6118
|
+
if (isUniqueConstraintError(error)) {
|
|
6155
6119
|
throw new AgentStorageError2("duplicate_id", `[SixbSqlite] Agent message '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6156
6120
|
}
|
|
6157
6121
|
throw error;
|
|
@@ -6340,7 +6304,7 @@ class SqliteAgentRunStore {
|
|
|
6340
6304
|
) VALUES (?, ?, ?, 'conversation', ?, ?, ?, 'queued', 0, ?)
|
|
6341
6305
|
`).run(input.projectId, input.id, input.executionId, input.threadId, input.triggerMessageId, JSON.stringify(input.spec), createdAt.toISOString());
|
|
6342
6306
|
} catch (error) {
|
|
6343
|
-
if (
|
|
6307
|
+
if (isUniqueConstraintError(error)) {
|
|
6344
6308
|
throw new AgentStorageError3("duplicate_id", `[SixbSqlite] Agent run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6345
6309
|
}
|
|
6346
6310
|
throw error;
|
|
@@ -6395,7 +6359,7 @@ class SqliteAgentRunStore {
|
|
|
6395
6359
|
) VALUES (?, ?, ?, 'subagent', ?, ?, ?, 'queued', 0, ?)
|
|
6396
6360
|
`).run(input.projectId, input.id, input.executionId, input.parentRunId, input.spawnKey, JSON.stringify(input.spec), (input.createdAt ?? new Date).toISOString());
|
|
6397
6361
|
} catch (error) {
|
|
6398
|
-
if (
|
|
6362
|
+
if (isUniqueConstraintError(error)) {
|
|
6399
6363
|
throw new AgentStorageError3("duplicate_id", `[SixbSqlite] Subagent run '${input.id}' conflicts with an existing durable spawn.`);
|
|
6400
6364
|
}
|
|
6401
6365
|
throw error;
|
|
@@ -6624,7 +6588,7 @@ class SqliteAgentThreadStore {
|
|
|
6624
6588
|
) VALUES (?, ?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
|
|
6625
6589
|
`).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, sandboxParams, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
|
|
6626
6590
|
} catch (error) {
|
|
6627
|
-
if (
|
|
6591
|
+
if (isUniqueConstraintError(error)) {
|
|
6628
6592
|
throw new AgentStorageError4("duplicate_id", `[SixbSqlite] Agent thread '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6629
6593
|
}
|
|
6630
6594
|
throw error;
|
|
@@ -6827,7 +6791,7 @@ class SqliteAiUsageStorage {
|
|
|
6827
6791
|
try {
|
|
6828
6792
|
this.insertRecord(record);
|
|
6829
6793
|
} catch (error) {
|
|
6830
|
-
if (!
|
|
6794
|
+
if (!isUniqueConstraintError(error))
|
|
6831
6795
|
throw error;
|
|
6832
6796
|
const concurrent = this.findByIdempotencyKey(record);
|
|
6833
6797
|
if (concurrent)
|
|
@@ -7035,7 +6999,7 @@ class SqliteAiCostStorage {
|
|
|
7035
6999
|
try {
|
|
7036
7000
|
this.insertCost(record);
|
|
7037
7001
|
} catch (error) {
|
|
7038
|
-
if (!
|
|
7002
|
+
if (!isUniqueConstraintError(error))
|
|
7039
7003
|
throw error;
|
|
7040
7004
|
if (!this.findCost(record.projectId, record.usageRecordId))
|
|
7041
7005
|
throw error;
|
|
@@ -8613,7 +8577,7 @@ function revokeActiveMagicLinksForEmail(db, params) {
|
|
|
8613
8577
|
}));
|
|
8614
8578
|
}
|
|
8615
8579
|
function mapUniqueConstraintError(error, code, message) {
|
|
8616
|
-
if (
|
|
8580
|
+
if (isUniqueConstraintError(error)) {
|
|
8617
8581
|
throw new AuthStorageError(code, message);
|
|
8618
8582
|
}
|
|
8619
8583
|
throw error;
|
|
@@ -10233,7 +10197,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10233
10197
|
`).run(record.projectId, record.connectorId, record.id, record.slot, record.initiatedByExecutionId, record.stateHash, record.codeVerifier === undefined ? null : json(record.codeVerifier), record.redirectUri, record.connectionRunId ?? null, record.returnTo ?? null, record.callbackBindingHash ?? null, record.reauthorizationId ?? null, record.reauthorizationRevision ?? null, record.reauthorizationConnectionIds ? json(record.reauthorizationConnectionIds) : null, iso(record.createdAt), iso(record.expiresAt));
|
|
10234
10198
|
return true;
|
|
10235
10199
|
} catch (error) {
|
|
10236
|
-
if (
|
|
10200
|
+
if (isUniqueConstraintError(error))
|
|
10237
10201
|
return false;
|
|
10238
10202
|
throw error;
|
|
10239
10203
|
}
|
|
@@ -10259,7 +10223,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10259
10223
|
this.insertRun(record);
|
|
10260
10224
|
return true;
|
|
10261
10225
|
} catch (error) {
|
|
10262
|
-
if (
|
|
10226
|
+
if (isUniqueConstraintError(error))
|
|
10263
10227
|
return false;
|
|
10264
10228
|
throw error;
|
|
10265
10229
|
}
|
|
@@ -10293,7 +10257,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10293
10257
|
this.insertAuthorizationRow(record);
|
|
10294
10258
|
return true;
|
|
10295
10259
|
} catch (error) {
|
|
10296
|
-
if (
|
|
10260
|
+
if (isUniqueConstraintError(error))
|
|
10297
10261
|
return false;
|
|
10298
10262
|
throw error;
|
|
10299
10263
|
}
|
|
@@ -10324,7 +10288,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10324
10288
|
`).run(record.projectId, record.connectorId, record.id, record.authorizationId, record.slot, json(record.account), record.account.id, record.status, optionalIso(record.disconnectedAt), iso(record.createdAt), iso(record.updatedAt));
|
|
10325
10289
|
return true;
|
|
10326
10290
|
} catch (error) {
|
|
10327
|
-
if (
|
|
10291
|
+
if (isUniqueConstraintError(error))
|
|
10328
10292
|
return false;
|
|
10329
10293
|
throw error;
|
|
10330
10294
|
}
|
|
@@ -10837,7 +10801,7 @@ class SqliteFileUploadSessionPersistence {
|
|
|
10837
10801
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(session.id, session.projectId, session.principal.type, session.principal.id, session.strategy, session.status, session.fileName ?? null, session.mediaType ?? null, session.logicalPath ?? null, session.expectedSizeBytes ?? null, session.expectedDigest ?? null, ...mutableColumns(session));
|
|
10838
10802
|
return true;
|
|
10839
10803
|
} catch (error) {
|
|
10840
|
-
if (
|
|
10804
|
+
if (isUniqueConstraintError(error))
|
|
10841
10805
|
return false;
|
|
10842
10806
|
throw error;
|
|
10843
10807
|
}
|
|
@@ -16392,7 +16356,7 @@ class SqlitePipelineRunStorage {
|
|
|
16392
16356
|
) VALUES (?, ?, ?, ?, ?, ?, NULL)
|
|
16393
16357
|
`).run(input.projectId, input.id, input.executionId, input.pipelineId, "queued", queuedAt.toISOString());
|
|
16394
16358
|
} catch (error) {
|
|
16395
|
-
if (
|
|
16359
|
+
if (isUniqueConstraintError(error)) {
|
|
16396
16360
|
return this.requeueAfterEnqueueFailure(input, queuedAt);
|
|
16397
16361
|
}
|
|
16398
16362
|
throw error;
|
|
@@ -16489,7 +16453,7 @@ class SqlitePipelineRunStorage {
|
|
|
16489
16453
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
16490
16454
|
`).run(input.projectId, input.id, input.pipelineRunId, input.pipelineId, input.stepId, input.datasetId, input.mode, "running", startedAt.toISOString(), serializeDatasetVersionRefs(input.inputs));
|
|
16491
16455
|
} catch (error) {
|
|
16492
|
-
if (
|
|
16456
|
+
if (isUniqueConstraintError(error)) {
|
|
16493
16457
|
throw new PipelineRunError(`[SixbSqlite] Pipeline step run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
16494
16458
|
}
|
|
16495
16459
|
throw error;
|
|
@@ -16757,7 +16721,7 @@ class SqliteProjectionRunStorage {
|
|
|
16757
16721
|
try {
|
|
16758
16722
|
this.insertQueued(record);
|
|
16759
16723
|
} catch (error) {
|
|
16760
|
-
if (
|
|
16724
|
+
if (isUniqueConstraintError2(error))
|
|
16761
16725
|
throw duplicateProjectionRun(input);
|
|
16762
16726
|
throw error;
|
|
16763
16727
|
}
|
|
@@ -17146,7 +17110,7 @@ function databaseSafeInteger(value, fieldName) {
|
|
|
17146
17110
|
}
|
|
17147
17111
|
return value;
|
|
17148
17112
|
}
|
|
17149
|
-
function
|
|
17113
|
+
function isUniqueConstraintError2(error) {
|
|
17150
17114
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
17151
17115
|
}
|
|
17152
17116
|
function duplicateProjectionRun(input) {
|
|
@@ -17422,7 +17386,7 @@ class SqliteShareGrantStorage {
|
|
|
17422
17386
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
17423
17387
|
`).run(record.projectId, record.id, record.definitionId, record.target.objectTypeId, record.target.primaryId, record.issuedBy.type, record.issuedBy.id, record.authoritySnapshot.version, JSON.stringify(record.authoritySnapshot), record.authorityDigest, record.tokenHash, record.destinationPath, record.createdAt.toISOString(), record.expiresAt.toISOString());
|
|
17424
17388
|
} catch (error) {
|
|
17425
|
-
if (
|
|
17389
|
+
if (isUniqueConstraintError(error)) {
|
|
17426
17390
|
throw new ShareGrantStorageError("duplicate", `[SixbSqlite] Share grant '${record.id}' conflicts with an existing record.`, { cause: error });
|
|
17427
17391
|
}
|
|
17428
17392
|
throw error;
|
|
@@ -17571,7 +17535,7 @@ class SqliteShareSessionStorage {
|
|
|
17571
17535
|
throw invalidRecord2(`Share session '${record.id}' disappeared after create.`);
|
|
17572
17536
|
return rowToRecord2(row);
|
|
17573
17537
|
} catch (error) {
|
|
17574
|
-
if (
|
|
17538
|
+
if (isUniqueConstraintError(error)) {
|
|
17575
17539
|
throw new ShareSessionStorageError("duplicate", `[SixbSqlite] Share session '${record.id}' conflicts with an existing record.`, { cause: error });
|
|
17576
17540
|
}
|
|
17577
17541
|
if (isForeignKeyConstraintError(error)) {
|
|
@@ -17688,7 +17652,7 @@ class SqliteSyncRunStorage {
|
|
|
17688
17652
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)
|
|
17689
17653
|
`).run(input.projectId, input.id, input.executionId, input.syncId, input.datasetId, input.mode, "queued", queuedAt.toISOString(), input.expectedLatestVersionId ?? null, input.commitMessage ?? null);
|
|
17690
17654
|
} catch (error) {
|
|
17691
|
-
if (
|
|
17655
|
+
if (isUniqueConstraintError3(error)) {
|
|
17692
17656
|
return this.requeueAfterEnqueueFailure(input, queuedAt);
|
|
17693
17657
|
}
|
|
17694
17658
|
throw error;
|
|
@@ -17853,7 +17817,7 @@ function rowToSyncRunRecord(row) {
|
|
|
17853
17817
|
checkpoint: parseCheckpoint(row.checkpoint)
|
|
17854
17818
|
};
|
|
17855
17819
|
}
|
|
17856
|
-
function
|
|
17820
|
+
function isUniqueConstraintError3(error) {
|
|
17857
17821
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
17858
17822
|
}
|
|
17859
17823
|
|
|
@@ -18019,7 +17983,7 @@ class SqliteWebhookRunStorage {
|
|
|
18019
17983
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18020
17984
|
`).run(input.projectId, input.id, input.executionId, input.connectorId, input.webhookId, "running", input.method, input.route, startedAt.toISOString(), input.requestBodyBytes, input.requestBodySha256, input.idempotencyKey ?? null);
|
|
18021
17985
|
} catch (error) {
|
|
18022
|
-
if (
|
|
17986
|
+
if (isUniqueConstraintError(error)) {
|
|
18023
17987
|
throw new WebhookRunError(`[SixbSqlite] Webhook run '${input.id}' or delivery key already exists for project '${input.projectId}'.`, "duplicate_run");
|
|
18024
17988
|
}
|
|
18025
17989
|
throw error;
|
|
@@ -18172,7 +18136,7 @@ class SqliteWorkflowInterventionStorage {
|
|
|
18172
18136
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18173
18137
|
`).run(input.projectId, input.id, input.workflowId, input.workflowRunId, input.nodeRunId, input.nodeIndex, input.nodeId, input.nodeKey, input.interventionId, serializeRecord(input.input), serializeRecord(input.defaultResponse), "pending", (input.requestedAt ?? new Date).toISOString(), input.expiresAt?.toISOString() ?? null);
|
|
18174
18138
|
} catch (error) {
|
|
18175
|
-
if (
|
|
18139
|
+
if (isUniqueConstraintError(error)) {
|
|
18176
18140
|
throw new WorkflowInterventionError(`[SixbSqlite] Workflow intervention '${input.id}' already exists for project '${input.projectId}'.`);
|
|
18177
18141
|
}
|
|
18178
18142
|
throw error;
|
|
@@ -18413,7 +18377,7 @@ class SqliteWorkflowRunStorage {
|
|
|
18413
18377
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18414
18378
|
`).run(input.projectId, input.id, input.executionId, input.workflowId, "queued", serializeRecord2(input.input), queuedAt.toISOString(), queuedAt.toISOString(), 0);
|
|
18415
18379
|
} catch (error) {
|
|
18416
|
-
if (
|
|
18380
|
+
if (isUniqueConstraintError(error)) {
|
|
18417
18381
|
throw new WorkflowRunError(`[SixbSqlite] Workflow run '${input.id}' or execution '${input.executionId}' is already linked for project '${input.projectId}'.`);
|
|
18418
18382
|
}
|
|
18419
18383
|
throw error;
|
|
@@ -18639,7 +18603,7 @@ class SqliteWorkflowAgentNodeRunStorage {
|
|
|
18639
18603
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
18640
18604
|
`).run(input.projectId, input.nodeRunId, input.executionId, input.actorId, "queued", input.prompt, 0, (input.createdAt ?? new Date).toISOString());
|
|
18641
18605
|
} catch (error) {
|
|
18642
|
-
if (
|
|
18606
|
+
if (isUniqueConstraintError(error)) {
|
|
18643
18607
|
throw new WorkflowRunError(`[SixbSqlite] Agent execution already exists for workflow node run '${input.nodeRunId}'.`);
|
|
18644
18608
|
}
|
|
18645
18609
|
throw error;
|
|
@@ -18788,7 +18752,7 @@ class SqliteWorkflowNodeRunStorage {
|
|
|
18788
18752
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18789
18753
|
`).run(input.projectId, input.id, input.workflowRunId, input.workflowId, input.nodeIndex, input.nodeType, input.nodeId, input.nodeKey, "running", serializeRecord2(input.input), startedAt.toISOString());
|
|
18790
18754
|
} catch (error) {
|
|
18791
|
-
if (
|
|
18755
|
+
if (isUniqueConstraintError(error)) {
|
|
18792
18756
|
throw new WorkflowRunError(`[SixbSqlite] Workflow node run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
18793
18757
|
}
|
|
18794
18758
|
throw error;
|
|
@@ -19206,4 +19170,4 @@ export {
|
|
|
19206
19170
|
migrateSqliteStorage
|
|
19207
19171
|
};
|
|
19208
19172
|
|
|
19209
|
-
//# debugId=
|
|
19173
|
+
//# debugId=682E7F57F0A7280864756E2164756E21
|