@sixb/sqlite 0.1.18 → 0.1.20
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/agents/agent-storage.d.ts.map +1 -1
- package/dist/ai-limit-storage.d.ts.map +1 -1
- package/dist/ai-usage-storage.d.ts.map +1 -1
- package/dist/auth-storage/auth-storage.d.ts.map +1 -1
- package/dist/auth-storage/magic-links.d.ts.map +1 -1
- package/dist/auth-storage/oidc-attempts.d.ts.map +1 -1
- package/dist/auth-storage/rows.d.ts +0 -3
- package/dist/auth-storage/rows.d.ts.map +1 -1
- package/dist/auth-storage/sessions.d.ts +0 -10
- package/dist/auth-storage/sessions.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +0 -2
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +301 -398
- package/dist/index.js.map +27 -27
- package/dist/migrations.d.ts +2 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/storage.d.ts.map +1 -1
- package/dist/pipeline-run-storage.d.ts.map +1 -1
- package/dist/projection-run-storage.d.ts.map +1 -1
- package/dist/rules-storage.d.ts.map +1 -1
- package/dist/share-grant-storage.d.ts.map +1 -1
- package/dist/share-session-storage.d.ts.map +1 -1
- package/dist/sync-run-storage.d.ts.map +1 -1
- package/dist/timeseries-storage.d.ts.map +1 -1
- package/dist/transactions.d.ts +0 -1
- package/dist/transactions.d.ts.map +1 -1
- package/dist/webhook-run-storage.d.ts.map +1 -1
- package/dist/workflow-intervention-storage.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/action-run-storage.ts +104 -447
- package/src/agents/agent-storage.ts +0 -5
- package/src/ai-limit-storage.ts +0 -2
- package/src/ai-usage-storage.ts +0 -4
- package/src/auth-storage/auth-storage.ts +0 -23
- package/src/auth-storage/magic-links.ts +1 -6
- package/src/auth-storage/oidc-attempts.ts +1 -6
- package/src/auth-storage/rows.ts +0 -6
- package/src/auth-storage/sessions.ts +1 -49
- package/src/auth-storage/shared.ts +3 -20
- package/src/index.ts +1 -10
- package/src/migrations/060-terminal-action-runs.sql +149 -0
- package/src/migrations/061-drop-auth-audience.sql +16 -0
- package/src/migrations.ts +24 -0
- package/src/objects/storage.ts +0 -5
- package/src/pipeline-run-storage.ts +0 -5
- package/src/projection-run-storage.ts +0 -5
- package/src/rules-storage.ts +0 -5
- package/src/share-grant-storage.ts +0 -2
- package/src/share-session-storage.ts +0 -2
- package/src/sync-run-storage.ts +0 -5
- package/src/timeseries-storage.ts +0 -5
- package/src/transactions.ts +8 -8
- package/src/webhook-run-storage.ts +0 -3
- package/src/workflow-intervention-storage.ts +0 -5
- package/src/workflow-run-storage.ts +0 -5
package/dist/index.js
CHANGED
|
@@ -25,12 +25,13 @@ 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
|
-
|
|
31
|
-
|
|
32
|
-
} from "
|
|
33
|
-
import {
|
|
28
|
+
import { normalizeRecordActionRunInput, resolveActionRunEffects } from "@sixb/core/internal/storage";
|
|
29
|
+
import { ActionRunError } from "@sixb/core/storage";
|
|
30
|
+
|
|
31
|
+
// src/transactions.ts
|
|
32
|
+
import { Database as SqliteDatabase } from "bun:sqlite";
|
|
33
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
34
|
+
import { dirname as dirname2 } from "path";
|
|
34
35
|
|
|
35
36
|
// src/migrations.ts
|
|
36
37
|
import { Database } from "bun:sqlite";
|
|
@@ -4994,6 +4995,177 @@ CREATE INDEX idx_ontology_sources_drained
|
|
|
4994
4995
|
WHERE status = 'superseded' AND root_count = 0;
|
|
4995
4996
|
`;
|
|
4996
4997
|
|
|
4998
|
+
// src/migrations/060-terminal-action-runs.sql
|
|
4999
|
+
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
|
|
5000
|
+
-- is queued, running, or cancelled any more, and every run has started and finished. SQLite cannot
|
|
5001
|
+
-- alter a CHECK constraint, so the table is rebuilt.
|
|
5002
|
+
CREATE TABLE action_runs_v2 (
|
|
5003
|
+
project_id TEXT NOT NULL,
|
|
5004
|
+
id TEXT NOT NULL,
|
|
5005
|
+
execution_id TEXT NOT NULL,
|
|
5006
|
+
action_id TEXT NOT NULL,
|
|
5007
|
+
subject_kind TEXT NOT NULL CHECK (subject_kind IN ('none', 'object')),
|
|
5008
|
+
object_type_id TEXT,
|
|
5009
|
+
primary_id TEXT,
|
|
5010
|
+
status TEXT NOT NULL CHECK (status IN ('succeeded', 'failed')),
|
|
5011
|
+
phase TEXT NOT NULL CHECK (phase IN ('validation', 'writeback', 'edits', 'commit', 'effects')),
|
|
5012
|
+
started_at TEXT NOT NULL,
|
|
5013
|
+
finished_at TEXT NOT NULL,
|
|
5014
|
+
params TEXT NOT NULL,
|
|
5015
|
+
idempotency_key TEXT NOT NULL,
|
|
5016
|
+
writeback_status TEXT CHECK (writeback_status IS NULL OR writeback_status IN ('succeeded', 'failed')),
|
|
5017
|
+
writeback_completed_at TEXT,
|
|
5018
|
+
writeback_result TEXT,
|
|
5019
|
+
writeback_error TEXT CHECK (writeback_error IS NULL OR json_valid(writeback_error)),
|
|
5020
|
+
effects_status TEXT CHECK (effects_status IS NULL OR effects_status IN ('succeeded', 'failed')),
|
|
5021
|
+
effects_completed_at TEXT,
|
|
5022
|
+
effects_error TEXT CHECK (effects_error IS NULL OR json_valid(effects_error)),
|
|
5023
|
+
error TEXT CHECK (error IS NULL OR json_valid(error)),
|
|
5024
|
+
CHECK (
|
|
5025
|
+
(subject_kind = 'none' AND object_type_id IS NULL AND primary_id IS NULL)
|
|
5026
|
+
OR (subject_kind = 'object' AND object_type_id IS NOT NULL AND primary_id IS NOT NULL)
|
|
5027
|
+
),
|
|
5028
|
+
CHECK ((status = 'failed') = (error IS NOT NULL)),
|
|
5029
|
+
PRIMARY KEY (project_id, id),
|
|
5030
|
+
UNIQUE (project_id, execution_id)
|
|
5031
|
+
);
|
|
5032
|
+
|
|
5033
|
+
INSERT INTO action_runs_v2 (
|
|
5034
|
+
project_id, id, execution_id, action_id, subject_kind, object_type_id, primary_id, status,
|
|
5035
|
+
phase, started_at, finished_at, params, idempotency_key, writeback_status,
|
|
5036
|
+
writeback_completed_at, writeback_result, writeback_error, effects_status,
|
|
5037
|
+
effects_completed_at, effects_error, error
|
|
5038
|
+
)
|
|
5039
|
+
SELECT
|
|
5040
|
+
project_id, id, execution_id, action_id, subject_kind, object_type_id, primary_id,
|
|
5041
|
+
migrated_status, migrated_phase,
|
|
5042
|
+
-- A run starts when it was queued at the latest.
|
|
5043
|
+
COALESCE(started_at, queued_at),
|
|
5044
|
+
migrated_finished_at,
|
|
5045
|
+
params, idempotency_key, writeback_status,
|
|
5046
|
+
CASE
|
|
5047
|
+
WHEN writeback_status IS NULL THEN NULL
|
|
5048
|
+
ELSE COALESCE(writeback_completed_at, migrated_finished_at)
|
|
5049
|
+
END,
|
|
5050
|
+
writeback_result, writeback_error,
|
|
5051
|
+
CASE WHEN effects_abandoned THEN 'failed' ELSE effects_status END,
|
|
5052
|
+
CASE
|
|
5053
|
+
WHEN effects_abandoned THEN migrated_at
|
|
5054
|
+
WHEN effects_status IS NULL THEN NULL
|
|
5055
|
+
ELSE COALESCE(effects_completed_at, migrated_finished_at)
|
|
5056
|
+
END,
|
|
5057
|
+
CASE
|
|
5058
|
+
WHEN effects_abandoned THEN json_object(
|
|
5059
|
+
'code', 'internal.unexpected',
|
|
5060
|
+
'message', 'Abandoned: Actions now run synchronously; these effects never finished.',
|
|
5061
|
+
'retryable', json('false'),
|
|
5062
|
+
'at', migrated_at,
|
|
5063
|
+
'details', json_object('actionId', action_id, 'runId', id, 'phase', 'effects')
|
|
5064
|
+
)
|
|
5065
|
+
ELSE effects_error
|
|
5066
|
+
END,
|
|
5067
|
+
-- A failure names the phase its run ended in.
|
|
5068
|
+
CASE
|
|
5069
|
+
WHEN migrated_error IS NULL THEN NULL
|
|
5070
|
+
WHEN json_extract(migrated_error, '$.details.phase') IS migrated_phase THEN migrated_error
|
|
5071
|
+
ELSE json_set(migrated_error, '$.details.phase', migrated_phase)
|
|
5072
|
+
END
|
|
5073
|
+
FROM (
|
|
5074
|
+
SELECT
|
|
5075
|
+
*,
|
|
5076
|
+
CASE
|
|
5077
|
+
WHEN status = 'succeeded' OR edits_committed THEN 'succeeded'
|
|
5078
|
+
ELSE 'failed'
|
|
5079
|
+
END AS migrated_status,
|
|
5080
|
+
CASE
|
|
5081
|
+
WHEN edits_committed THEN CASE WHEN phase = 'effects' THEN 'effects' ELSE 'commit' END
|
|
5082
|
+
-- The phases \`request\`, \`enqueue\`, and \`cancelled\` are gone: a run that stopped in one of
|
|
5083
|
+
-- them never got past validation.
|
|
5084
|
+
WHEN phase IN ('validation', 'writeback', 'edits', 'commit', 'effects') THEN phase
|
|
5085
|
+
ELSE 'validation'
|
|
5086
|
+
END AS migrated_phase,
|
|
5087
|
+
CASE
|
|
5088
|
+
WHEN edits_committed THEN committed_at
|
|
5089
|
+
WHEN status IN ('queued', 'running') THEN migrated_at
|
|
5090
|
+
ELSE COALESCE(finished_at, migrated_at)
|
|
5091
|
+
END AS migrated_finished_at,
|
|
5092
|
+
edits_committed AND phase = 'effects' AND effects_status IS NULL AS effects_abandoned,
|
|
5093
|
+
CASE
|
|
5094
|
+
WHEN edits_committed THEN NULL
|
|
5095
|
+
WHEN status IN ('queued', 'running') THEN json_object(
|
|
5096
|
+
'code', 'internal.unexpected',
|
|
5097
|
+
'message', 'Abandoned: Actions now run synchronously; this run never finished.',
|
|
5098
|
+
'retryable', json('false'),
|
|
5099
|
+
'at', migrated_at,
|
|
5100
|
+
'details', json_object('actionId', action_id, 'runId', id)
|
|
5101
|
+
)
|
|
5102
|
+
-- Every failed run carries a failure. One recorded before failures were kept explains
|
|
5103
|
+
-- itself.
|
|
5104
|
+
WHEN status IN ('failed', 'cancelled') AND error IS NULL THEN json_object(
|
|
5105
|
+
'code', 'internal.unexpected',
|
|
5106
|
+
'message', 'This run failed before Sixb recorded why.',
|
|
5107
|
+
'retryable', json('false'),
|
|
5108
|
+
'at', COALESCE(finished_at, migrated_at),
|
|
5109
|
+
'details', json_object('actionId', action_id, 'runId', id)
|
|
5110
|
+
)
|
|
5111
|
+
-- An enqueue failure, which no run can meet any more, reads as the unexpected error it
|
|
5112
|
+
-- now is.
|
|
5113
|
+
WHEN json_extract(error, '$.code') = 'queue.enqueue_failed'
|
|
5114
|
+
THEN json_set(error, '$.code', 'internal.unexpected', '$.retryable', json('false'))
|
|
5115
|
+
ELSE error
|
|
5116
|
+
END AS migrated_error
|
|
5117
|
+
FROM (
|
|
5118
|
+
SELECT
|
|
5119
|
+
run.*,
|
|
5120
|
+
committed.committed_at,
|
|
5121
|
+
strftime('%Y-%m-%dT%H:%M:%fZ', 'now') AS migrated_at,
|
|
5122
|
+
-- A run left running after its edits committed, as a crash between the commit and the end
|
|
5123
|
+
-- of the run left it, succeeded: its edits and their outbox facts are in the commit. A run
|
|
5124
|
+
-- that stopped during its effects keeps that phase, and records effects that never ended.
|
|
5125
|
+
-- Any other run left queued or running never finished, and nothing will resume it. A
|
|
5126
|
+
-- cancelled run failed, and keeps the failure it recorded.
|
|
5127
|
+
run.status IN ('queued', 'running') AND committed.committed_at IS NOT NULL
|
|
5128
|
+
AS edits_committed
|
|
5129
|
+
FROM action_runs AS run
|
|
5130
|
+
LEFT JOIN ontology_commits AS committed
|
|
5131
|
+
ON committed.origin_kind = 'action'
|
|
5132
|
+
AND committed.project_id = run.project_id
|
|
5133
|
+
AND committed.origin_run_id = run.id
|
|
5134
|
+
)
|
|
5135
|
+
);
|
|
5136
|
+
|
|
5137
|
+
DROP TABLE action_runs;
|
|
5138
|
+
ALTER TABLE action_runs_v2 RENAME TO action_runs;
|
|
5139
|
+
|
|
5140
|
+
CREATE INDEX idx_action_runs_project_started
|
|
5141
|
+
ON action_runs(project_id, started_at DESC);
|
|
5142
|
+
CREATE INDEX idx_action_runs_project_action_started
|
|
5143
|
+
ON action_runs(project_id, action_id, started_at DESC);
|
|
5144
|
+
CREATE INDEX idx_action_runs_project_object_started
|
|
5145
|
+
ON action_runs(project_id, object_type_id, primary_id, started_at DESC);
|
|
5146
|
+
CREATE INDEX idx_action_runs_project_status_started
|
|
5147
|
+
ON action_runs(project_id, status, started_at DESC);
|
|
5148
|
+
`;
|
|
5149
|
+
|
|
5150
|
+
// src/migrations/061-drop-auth-audience.sql
|
|
5151
|
+
var _061_drop_auth_audience_default = `-- A project has one browser app, so sessions, magic links and sign-in attempts no longer name the
|
|
5152
|
+
-- one they belong to. Atlas's browser sessions end here: their cookie is no longer read. Native
|
|
5153
|
+
-- sessions carried Atlas's name only because the column needed a value, so they stay.
|
|
5154
|
+
UPDATE auth_sessions
|
|
5155
|
+
SET revoked_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
5156
|
+
WHERE audience = 'atlas'
|
|
5157
|
+
AND refresh_token_hash IS NULL
|
|
5158
|
+
AND revoked_at IS NULL;
|
|
5159
|
+
|
|
5160
|
+
DROP INDEX idx_auth_sessions_user_active;
|
|
5161
|
+
ALTER TABLE auth_sessions DROP COLUMN audience;
|
|
5162
|
+
CREATE INDEX idx_auth_sessions_user_active
|
|
5163
|
+
ON auth_sessions(project_id, user_id, revoked_at, expires_at);
|
|
5164
|
+
|
|
5165
|
+
ALTER TABLE auth_magic_links DROP COLUMN audience;
|
|
5166
|
+
ALTER TABLE auth_oidc_authorization_attempts DROP COLUMN audience;
|
|
5167
|
+
`;
|
|
5168
|
+
|
|
4997
5169
|
// src/migrations.ts
|
|
4998
5170
|
var MIGRATIONS_TABLE_SQL = `
|
|
4999
5171
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -5100,7 +5272,9 @@ var sqliteStorageMigrations = defineMigrations({
|
|
|
5100
5272
|
sqliteSql("056-audio-transcription", _056_audio_transcription_default),
|
|
5101
5273
|
sqliteSql("057-reranking-model-kind", _057_reranking_model_kind_default),
|
|
5102
5274
|
sqliteSql("058-file-download-grants", _058_file_download_grants_default),
|
|
5103
|
-
sqliteSql("059-drained-source-versions", _059_drained_source_versions_default)
|
|
5275
|
+
sqliteSql("059-drained-source-versions", _059_drained_source_versions_default),
|
|
5276
|
+
sqliteSql("060-terminal-action-runs", _060_terminal_action_runs_default),
|
|
5277
|
+
sqliteSql("061-drop-auth-audience", _061_drop_auth_audience_default)
|
|
5104
5278
|
]
|
|
5105
5279
|
});
|
|
5106
5280
|
function sqliteStoragePath(basePath) {
|
|
@@ -5114,6 +5288,20 @@ function sqliteSql(id, sqlText) {
|
|
|
5114
5288
|
function sqliteStep(id, up, options = {}) {
|
|
5115
5289
|
return step(id, up, options);
|
|
5116
5290
|
}
|
|
5291
|
+
var freshSchema;
|
|
5292
|
+
function freshSqliteDatabase() {
|
|
5293
|
+
if (!freshSchema) {
|
|
5294
|
+
const template = new Database(":memory:");
|
|
5295
|
+
try {
|
|
5296
|
+
template.run("PRAGMA foreign_keys = ON");
|
|
5297
|
+
installFreshSqliteSchema(template);
|
|
5298
|
+
freshSchema = template.serialize();
|
|
5299
|
+
} finally {
|
|
5300
|
+
template.close();
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
return Database.deserialize(freshSchema);
|
|
5304
|
+
}
|
|
5117
5305
|
function installFreshSqliteSchema(db) {
|
|
5118
5306
|
for (const migration of sqliteStorageMigrations.steps) {
|
|
5119
5307
|
const installed = migration.up(db);
|
|
@@ -5331,28 +5519,20 @@ function rollbackQuietly(db) {
|
|
|
5331
5519
|
}
|
|
5332
5520
|
|
|
5333
5521
|
// src/transactions.ts
|
|
5334
|
-
import { Database as SqliteDatabase } from "bun:sqlite";
|
|
5335
|
-
import { mkdirSync as mkdirSync2 } from "fs";
|
|
5336
|
-
import { dirname as dirname2 } from "path";
|
|
5337
5522
|
function openSqliteStoreConnection(options = {}) {
|
|
5338
5523
|
if (options.connection) {
|
|
5339
5524
|
return {
|
|
5340
5525
|
db: options.connection.db,
|
|
5341
|
-
ownsConnection: false
|
|
5342
|
-
installFreshSchema: false
|
|
5526
|
+
ownsConnection: false
|
|
5343
5527
|
};
|
|
5344
5528
|
}
|
|
5345
5529
|
const path = options.path ?? ":memory:";
|
|
5346
5530
|
if (path !== ":memory:" && !options.readonly)
|
|
5347
5531
|
mkdirSync2(dirname2(path), { recursive: true });
|
|
5348
|
-
const db = new SqliteDatabase(path, options.readonly ? { readonly: true } : undefined);
|
|
5532
|
+
const db = path === ":memory:" && !options.readonly ? freshSqliteDatabase() : new SqliteDatabase(path, options.readonly ? { readonly: true } : undefined);
|
|
5349
5533
|
db.run("PRAGMA foreign_keys = ON");
|
|
5350
5534
|
db.run("PRAGMA busy_timeout = 5000");
|
|
5351
|
-
return {
|
|
5352
|
-
db,
|
|
5353
|
-
ownsConnection: true,
|
|
5354
|
-
installFreshSchema: path === ":memory:" && !options.readonly
|
|
5355
|
-
};
|
|
5535
|
+
return { db, ownsConnection: true };
|
|
5356
5536
|
}
|
|
5357
5537
|
function closeSqliteStoreConnection(connection) {
|
|
5358
5538
|
if (connection.ownsConnection) {
|
|
@@ -5433,178 +5613,51 @@ class SqliteActionRunStorage {
|
|
|
5433
5613
|
this.connection = openSqliteStoreConnection(options);
|
|
5434
5614
|
this.db = this.connection.db;
|
|
5435
5615
|
this.executions = options.executions;
|
|
5436
|
-
if (this.connection.installFreshSchema) {
|
|
5437
|
-
installFreshSqliteSchema(this.db);
|
|
5438
|
-
}
|
|
5439
|
-
}
|
|
5440
|
-
async lockForMaterialization(input) {
|
|
5441
|
-
const row = this.db.query(`SELECT action_id, status FROM action_runs WHERE project_id = ? AND id = ?`).get(input.projectId, input.runId);
|
|
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
5616
|
}
|
|
5457
|
-
async
|
|
5458
|
-
const
|
|
5617
|
+
async record(input) {
|
|
5618
|
+
const record = normalizeRecordActionRunInput(input);
|
|
5459
5619
|
await assertActionRunExecution({
|
|
5460
5620
|
executions: this.executions,
|
|
5461
|
-
projectId:
|
|
5462
|
-
executionId:
|
|
5463
|
-
runId:
|
|
5464
|
-
actionId:
|
|
5621
|
+
projectId: record.projectId,
|
|
5622
|
+
executionId: record.executionId,
|
|
5623
|
+
runId: record.id,
|
|
5624
|
+
actionId: record.actionId
|
|
5465
5625
|
});
|
|
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}'.`);
|
|
5626
|
+
const inserted = this.db.query(`
|
|
5627
|
+
INSERT INTO action_runs (
|
|
5628
|
+
project_id,
|
|
5629
|
+
id,
|
|
5630
|
+
execution_id,
|
|
5631
|
+
action_id,
|
|
5632
|
+
subject_kind,
|
|
5633
|
+
object_type_id,
|
|
5634
|
+
primary_id,
|
|
5635
|
+
status,
|
|
5636
|
+
phase,
|
|
5637
|
+
started_at,
|
|
5638
|
+
finished_at,
|
|
5639
|
+
params,
|
|
5640
|
+
idempotency_key,
|
|
5641
|
+
writeback_status,
|
|
5642
|
+
writeback_completed_at,
|
|
5643
|
+
writeback_result,
|
|
5644
|
+
writeback_error,
|
|
5645
|
+
error
|
|
5646
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5647
|
+
ON CONFLICT DO NOTHING
|
|
5648
|
+
`).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);
|
|
5649
|
+
if (inserted.changes === 0) {
|
|
5650
|
+
const conflict = this.selectRow(record.projectId, record.id);
|
|
5651
|
+
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
5652
|
}
|
|
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
|
-
})();
|
|
5653
|
+
return rowToActionRunRecord(this.requireRow(record.projectId, record.id));
|
|
5596
5654
|
}
|
|
5597
5655
|
async recordEffects(input) {
|
|
5598
5656
|
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
|
-
}
|
|
5657
|
+
const existing = this.selectRow(input.projectId, input.id);
|
|
5658
|
+
const { run, effects } = resolveActionRunEffects(existing ? rowToActionRunRecord(existing) : null, input);
|
|
5659
|
+
if (!effects)
|
|
5660
|
+
return run;
|
|
5608
5661
|
this.db.query(`
|
|
5609
5662
|
UPDATE action_runs
|
|
5610
5663
|
SET
|
|
@@ -5613,32 +5666,8 @@ class SqliteActionRunStorage {
|
|
|
5613
5666
|
effects_completed_at = ?,
|
|
5614
5667
|
effects_error = ?
|
|
5615
5668
|
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);
|
|
5669
|
+
`).run("effects", effects.status, effects.completedAt.toISOString(), effects.status === "failed" ? serializeActionRunFailure(effects.error, "effects") : null, input.projectId, input.id);
|
|
5670
|
+
return rowToActionRunRecord(this.requireRow(input.projectId, input.id));
|
|
5642
5671
|
})();
|
|
5643
5672
|
}
|
|
5644
5673
|
async getById(params) {
|
|
@@ -5699,11 +5728,11 @@ class SqliteActionRunStorage {
|
|
|
5699
5728
|
args.push(...input.statuses);
|
|
5700
5729
|
}
|
|
5701
5730
|
if (input.startedAfter) {
|
|
5702
|
-
whereClauses.push("
|
|
5731
|
+
whereClauses.push("started_at >= ?");
|
|
5703
5732
|
args.push(input.startedAfter.toISOString());
|
|
5704
5733
|
}
|
|
5705
5734
|
if (input.startedBefore) {
|
|
5706
|
-
whereClauses.push("
|
|
5735
|
+
whereClauses.push("started_at <= ?");
|
|
5707
5736
|
args.push(input.startedBefore.toISOString());
|
|
5708
5737
|
}
|
|
5709
5738
|
const where = `WHERE ${whereClauses.join(" AND ")}`;
|
|
@@ -5714,7 +5743,7 @@ class SqliteActionRunStorage {
|
|
|
5714
5743
|
let query = `
|
|
5715
5744
|
SELECT * FROM action_runs
|
|
5716
5745
|
${where}
|
|
5717
|
-
ORDER BY
|
|
5746
|
+
ORDER BY started_at ${order}, id ${order}
|
|
5718
5747
|
`;
|
|
5719
5748
|
const queryArgs = [...args];
|
|
5720
5749
|
if (limit !== undefined) {
|
|
@@ -5735,31 +5764,22 @@ class SqliteActionRunStorage {
|
|
|
5735
5764
|
close() {
|
|
5736
5765
|
closeSqliteStoreConnection(this.connection);
|
|
5737
5766
|
}
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
if (
|
|
5744
|
-
throw new ActionRunError(`[SixbSqlite] Action run '${id}'
|
|
5767
|
+
selectRow(projectId, id) {
|
|
5768
|
+
return this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(projectId, id);
|
|
5769
|
+
}
|
|
5770
|
+
requireRow(projectId, id) {
|
|
5771
|
+
const row = this.selectRow(projectId, id);
|
|
5772
|
+
if (!row) {
|
|
5773
|
+
throw new ActionRunError(`[SixbSqlite] Action run '${id}' disappeared from project '${projectId}' while recording it.`);
|
|
5745
5774
|
}
|
|
5746
|
-
return
|
|
5775
|
+
return row;
|
|
5747
5776
|
}
|
|
5748
5777
|
}
|
|
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
5778
|
function toActionRunWritebackRecord(row) {
|
|
5759
5779
|
if (!row.writeback_status) {
|
|
5760
5780
|
return;
|
|
5761
5781
|
}
|
|
5762
|
-
const completedAt =
|
|
5782
|
+
const completedAt = new Date(row.writeback_completed_at ?? row.finished_at);
|
|
5763
5783
|
if (row.writeback_status === "succeeded") {
|
|
5764
5784
|
return {
|
|
5765
5785
|
status: "succeeded",
|
|
@@ -5770,14 +5790,14 @@ function toActionRunWritebackRecord(row) {
|
|
|
5770
5790
|
return {
|
|
5771
5791
|
status: "failed",
|
|
5772
5792
|
completedAt,
|
|
5773
|
-
error:
|
|
5793
|
+
error: parseActionRunFailure(row.writeback_error, "writeback")
|
|
5774
5794
|
};
|
|
5775
5795
|
}
|
|
5776
5796
|
function toActionRunEffectsRecord(row) {
|
|
5777
5797
|
if (!row.effects_status) {
|
|
5778
5798
|
return;
|
|
5779
5799
|
}
|
|
5780
|
-
const completedAt =
|
|
5800
|
+
const completedAt = new Date(row.effects_completed_at ?? row.finished_at);
|
|
5781
5801
|
if (row.effects_status === "succeeded") {
|
|
5782
5802
|
return {
|
|
5783
5803
|
status: "succeeded",
|
|
@@ -5787,54 +5807,29 @@ function toActionRunEffectsRecord(row) {
|
|
|
5787
5807
|
return {
|
|
5788
5808
|
status: "failed",
|
|
5789
5809
|
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
|
|
5810
|
+
error: parseActionRunFailure(row.effects_error, "effects")
|
|
5818
5811
|
};
|
|
5819
5812
|
}
|
|
5820
5813
|
function rowToActionRunRecord(row) {
|
|
5821
|
-
|
|
5814
|
+
const writeback = toActionRunWritebackRecord(row);
|
|
5815
|
+
const effects = toActionRunEffectsRecord(row);
|
|
5816
|
+
const fields = {
|
|
5822
5817
|
id: row.id,
|
|
5823
5818
|
projectId: row.project_id,
|
|
5824
5819
|
executionId: row.execution_id,
|
|
5825
5820
|
actionId: row.action_id,
|
|
5826
5821
|
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,
|
|
5822
|
+
phase: row.phase,
|
|
5823
|
+
startedAt: new Date(row.started_at),
|
|
5824
|
+
finishedAt: new Date(row.finished_at),
|
|
5832
5825
|
params: JSON.parse(row.params),
|
|
5833
5826
|
idempotencyKey: row.idempotency_key,
|
|
5834
|
-
writeback:
|
|
5835
|
-
effects:
|
|
5836
|
-
error: toActionRunFailure(row)
|
|
5827
|
+
...writeback === undefined ? {} : { writeback },
|
|
5828
|
+
...effects === undefined ? {} : { effects }
|
|
5837
5829
|
};
|
|
5830
|
+
if (row.status === "succeeded")
|
|
5831
|
+
return { ...fields, status: "succeeded" };
|
|
5832
|
+
return { ...fields, status: "failed", error: parseActionRunFailure(row.error) };
|
|
5838
5833
|
}
|
|
5839
5834
|
function rowToActionSubject(row) {
|
|
5840
5835
|
if (row.subject_kind === "none") {
|
|
@@ -5849,9 +5844,6 @@ function rowToActionSubject(row) {
|
|
|
5849
5844
|
primaryId: row.primary_id
|
|
5850
5845
|
};
|
|
5851
5846
|
}
|
|
5852
|
-
function isUniqueConstraintError(error) {
|
|
5853
|
-
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
5854
|
-
}
|
|
5855
5847
|
|
|
5856
5848
|
// src/agents/checkpoints.ts
|
|
5857
5849
|
import {
|
|
@@ -6105,7 +6097,7 @@ import {
|
|
|
6105
6097
|
} from "@sixb/core/storage";
|
|
6106
6098
|
|
|
6107
6099
|
// src/storage-errors.ts
|
|
6108
|
-
function
|
|
6100
|
+
function isUniqueConstraintError(error) {
|
|
6109
6101
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
6110
6102
|
}
|
|
6111
6103
|
function isForeignKeyConstraintError(error) {
|
|
@@ -6151,7 +6143,7 @@ class SqliteAgentMessageStore {
|
|
|
6151
6143
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6152
6144
|
`).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
6145
|
} catch (error) {
|
|
6154
|
-
if (
|
|
6146
|
+
if (isUniqueConstraintError(error)) {
|
|
6155
6147
|
throw new AgentStorageError2("duplicate_id", `[SixbSqlite] Agent message '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6156
6148
|
}
|
|
6157
6149
|
throw error;
|
|
@@ -6340,7 +6332,7 @@ class SqliteAgentRunStore {
|
|
|
6340
6332
|
) VALUES (?, ?, ?, 'conversation', ?, ?, ?, 'queued', 0, ?)
|
|
6341
6333
|
`).run(input.projectId, input.id, input.executionId, input.threadId, input.triggerMessageId, JSON.stringify(input.spec), createdAt.toISOString());
|
|
6342
6334
|
} catch (error) {
|
|
6343
|
-
if (
|
|
6335
|
+
if (isUniqueConstraintError(error)) {
|
|
6344
6336
|
throw new AgentStorageError3("duplicate_id", `[SixbSqlite] Agent run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6345
6337
|
}
|
|
6346
6338
|
throw error;
|
|
@@ -6395,7 +6387,7 @@ class SqliteAgentRunStore {
|
|
|
6395
6387
|
) VALUES (?, ?, ?, 'subagent', ?, ?, ?, 'queued', 0, ?)
|
|
6396
6388
|
`).run(input.projectId, input.id, input.executionId, input.parentRunId, input.spawnKey, JSON.stringify(input.spec), (input.createdAt ?? new Date).toISOString());
|
|
6397
6389
|
} catch (error) {
|
|
6398
|
-
if (
|
|
6390
|
+
if (isUniqueConstraintError(error)) {
|
|
6399
6391
|
throw new AgentStorageError3("duplicate_id", `[SixbSqlite] Subagent run '${input.id}' conflicts with an existing durable spawn.`);
|
|
6400
6392
|
}
|
|
6401
6393
|
throw error;
|
|
@@ -6624,7 +6616,7 @@ class SqliteAgentThreadStore {
|
|
|
6624
6616
|
) VALUES (?, ?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
|
|
6625
6617
|
`).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, sandboxParams, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
|
|
6626
6618
|
} catch (error) {
|
|
6627
|
-
if (
|
|
6619
|
+
if (isUniqueConstraintError(error)) {
|
|
6628
6620
|
throw new AgentStorageError4("duplicate_id", `[SixbSqlite] Agent thread '${input.id}' already exists for project '${input.projectId}'.`);
|
|
6629
6621
|
}
|
|
6630
6622
|
throw error;
|
|
@@ -6679,9 +6671,6 @@ class SqliteAgentStorage {
|
|
|
6679
6671
|
connection;
|
|
6680
6672
|
constructor(options) {
|
|
6681
6673
|
this.connection = openSqliteStoreConnection(options);
|
|
6682
|
-
if (this.connection.installFreshSchema) {
|
|
6683
|
-
installFreshSqliteSchema(this.connection.db);
|
|
6684
|
-
}
|
|
6685
6674
|
this.threads = new SqliteAgentThreadStore(this.connection.db);
|
|
6686
6675
|
this.runs = new SqliteAgentRunStore(this.connection.db, options.executions);
|
|
6687
6676
|
this.messages = new SqliteAgentMessageStore(this.connection.db);
|
|
@@ -6813,9 +6802,6 @@ class SqliteAiUsageStorage {
|
|
|
6813
6802
|
connection;
|
|
6814
6803
|
constructor(options = {}) {
|
|
6815
6804
|
this.connection = openSqliteStoreConnection(options);
|
|
6816
|
-
if (this.connection.installFreshSchema) {
|
|
6817
|
-
installFreshSqliteSchema(this.connection.db);
|
|
6818
|
-
}
|
|
6819
6805
|
}
|
|
6820
6806
|
async recordModelCall(input) {
|
|
6821
6807
|
const record = normalizeAiModelCallRecord(input);
|
|
@@ -6827,7 +6813,7 @@ class SqliteAiUsageStorage {
|
|
|
6827
6813
|
try {
|
|
6828
6814
|
this.insertRecord(record);
|
|
6829
6815
|
} catch (error) {
|
|
6830
|
-
if (!
|
|
6816
|
+
if (!isUniqueConstraintError(error))
|
|
6831
6817
|
throw error;
|
|
6832
6818
|
const concurrent = this.findByIdempotencyKey(record);
|
|
6833
6819
|
if (concurrent)
|
|
@@ -7035,7 +7021,7 @@ class SqliteAiCostStorage {
|
|
|
7035
7021
|
try {
|
|
7036
7022
|
this.insertCost(record);
|
|
7037
7023
|
} catch (error) {
|
|
7038
|
-
if (!
|
|
7024
|
+
if (!isUniqueConstraintError(error))
|
|
7039
7025
|
throw error;
|
|
7040
7026
|
if (!this.findCost(record.projectId, record.usageRecordId))
|
|
7041
7027
|
throw error;
|
|
@@ -7547,8 +7533,6 @@ class SqliteAiLimitStorage {
|
|
|
7547
7533
|
connection;
|
|
7548
7534
|
constructor(options = {}) {
|
|
7549
7535
|
this.connection = openSqliteStoreConnection(options);
|
|
7550
|
-
if (this.connection.installFreshSchema)
|
|
7551
|
-
installFreshSqliteSchema(this.connection.db);
|
|
7552
7536
|
}
|
|
7553
7537
|
async createPolicy(input) {
|
|
7554
7538
|
const policy = normalizeCreateAiLimitPolicy(input);
|
|
@@ -8142,7 +8126,6 @@ function rowToSessionRecord(row) {
|
|
|
8142
8126
|
projectId: row.project_id,
|
|
8143
8127
|
userId: row.user_id,
|
|
8144
8128
|
strategyId: row.strategy_id,
|
|
8145
|
-
audience: row.audience,
|
|
8146
8129
|
tokenHash: row.token_hash,
|
|
8147
8130
|
createdAt: new Date(row.created_at),
|
|
8148
8131
|
expiresAt: new Date(row.expires_at),
|
|
@@ -8215,7 +8198,6 @@ function rowToMagicLinkRecord(row) {
|
|
|
8215
8198
|
id: row.id,
|
|
8216
8199
|
projectId: row.project_id,
|
|
8217
8200
|
strategyId: row.strategy_id,
|
|
8218
|
-
audience: row.audience,
|
|
8219
8201
|
email: row.email,
|
|
8220
8202
|
tokenHash: row.token_hash,
|
|
8221
8203
|
returnTo: row.return_to ?? undefined,
|
|
@@ -8230,7 +8212,6 @@ function rowToOidcAuthorizationAttemptRecord(row) {
|
|
|
8230
8212
|
id: row.id,
|
|
8231
8213
|
projectId: row.project_id,
|
|
8232
8214
|
strategyId: row.strategy_id,
|
|
8233
|
-
audience: row.audience,
|
|
8234
8215
|
stateHash: row.state_hash,
|
|
8235
8216
|
nonceHash: row.nonce_hash,
|
|
8236
8217
|
codeVerifier: row.code_verifier,
|
|
@@ -8448,7 +8429,6 @@ function consumeOidcAttempt(db, params) {
|
|
|
8448
8429
|
}
|
|
8449
8430
|
function validateCompleteSessionInput(db, projectId, session) {
|
|
8450
8431
|
const sessionId = assertNonEmpty(session.id, "Session id");
|
|
8451
|
-
assertNonEmpty(session.audience, "Session audience");
|
|
8452
8432
|
assertNonEmpty(session.tokenHash, "Session token hash");
|
|
8453
8433
|
assertSessionIdAvailable(db, projectId, sessionId);
|
|
8454
8434
|
}
|
|
@@ -8462,7 +8442,6 @@ function createSession(db, input) {
|
|
|
8462
8442
|
const projectId = assertNonEmpty(input.projectId, "Project id");
|
|
8463
8443
|
const userId = assertNonEmpty(input.userId, "User id");
|
|
8464
8444
|
const strategyId = assertNonEmpty(input.strategyId, "Strategy id");
|
|
8465
|
-
const audience = assertNonEmpty(input.audience, "Session audience");
|
|
8466
8445
|
const tokenHash = assertNonEmpty(input.tokenHash, "Session token hash");
|
|
8467
8446
|
assertSessionIdAvailable(db, projectId, id);
|
|
8468
8447
|
db.query(`
|
|
@@ -8471,7 +8450,6 @@ function createSession(db, input) {
|
|
|
8471
8450
|
id,
|
|
8472
8451
|
user_id,
|
|
8473
8452
|
strategy_id,
|
|
8474
|
-
audience,
|
|
8475
8453
|
token_hash,
|
|
8476
8454
|
created_at,
|
|
8477
8455
|
expires_at,
|
|
@@ -8481,8 +8459,8 @@ function createSession(db, input) {
|
|
|
8481
8459
|
client_name,
|
|
8482
8460
|
access_expires_at,
|
|
8483
8461
|
refresh_token_hash
|
|
8484
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
8485
|
-
`).run(projectId, id, userId, strategyId,
|
|
8462
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8463
|
+
`).run(projectId, id, userId, strategyId, tokenHash, toIso(input.createdAt), toIso(input.expiresAt), input.absoluteExpiresAt ? toIso(input.absoluteExpiresAt) : null, input.userAgent ?? null, input.ipAddress ?? null, input.bearer ? assertNonEmpty(input.bearer.clientName, "Session client name") : null, input.bearer ? toIso(input.bearer.accessExpiresAt) : null, input.bearer ? assertNonEmpty(input.bearer.refreshTokenHash, "Refresh token hash") : null);
|
|
8486
8464
|
const session = getSessionById(db, { projectId, id });
|
|
8487
8465
|
if (!session) {
|
|
8488
8466
|
throw new AuthStorageError("missing_session", `[Sixb] Failed to load session '${id}' for project '${projectId}'.`);
|
|
@@ -8491,30 +8469,25 @@ function createSession(db, input) {
|
|
|
8491
8469
|
}
|
|
8492
8470
|
function revokeActiveSessionsForUser(db, params) {
|
|
8493
8471
|
const revokedAt = toIso(params.revokedAt);
|
|
8494
|
-
const audienceCondition = params.audience === undefined ? "" : "AND audience = ?";
|
|
8495
|
-
const selectArgs = params.audience === undefined ? [params.projectId, params.userId, revokedAt, revokedAt] : [params.projectId, params.userId, params.audience, revokedAt, revokedAt];
|
|
8496
|
-
const updateArgs = params.audience === undefined ? [revokedAt, params.projectId, params.userId, revokedAt, revokedAt] : [revokedAt, params.projectId, params.userId, params.audience, revokedAt, revokedAt];
|
|
8497
8472
|
const rows = db.query(`
|
|
8498
8473
|
SELECT *
|
|
8499
8474
|
FROM auth_sessions
|
|
8500
8475
|
WHERE project_id = ?
|
|
8501
8476
|
AND user_id = ?
|
|
8502
|
-
${audienceCondition}
|
|
8503
8477
|
AND revoked_at IS NULL
|
|
8504
8478
|
AND expires_at > ?
|
|
8505
8479
|
AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
|
|
8506
8480
|
ORDER BY created_at ASC, id ASC
|
|
8507
|
-
`).all(
|
|
8481
|
+
`).all(params.projectId, params.userId, revokedAt, revokedAt);
|
|
8508
8482
|
db.query(`
|
|
8509
8483
|
UPDATE auth_sessions
|
|
8510
8484
|
SET revoked_at = ?
|
|
8511
8485
|
WHERE project_id = ?
|
|
8512
8486
|
AND user_id = ?
|
|
8513
|
-
${audienceCondition}
|
|
8514
8487
|
AND revoked_at IS NULL
|
|
8515
8488
|
AND expires_at > ?
|
|
8516
8489
|
AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
|
|
8517
|
-
`).run(
|
|
8490
|
+
`).run(revokedAt, params.projectId, params.userId, revokedAt, revokedAt);
|
|
8518
8491
|
return rows.map((row) => rowToSessionRecord({
|
|
8519
8492
|
...row,
|
|
8520
8493
|
revoked_at: revokedAt
|
|
@@ -8613,7 +8586,7 @@ function revokeActiveMagicLinksForEmail(db, params) {
|
|
|
8613
8586
|
}));
|
|
8614
8587
|
}
|
|
8615
8588
|
function mapUniqueConstraintError(error, code, message) {
|
|
8616
|
-
if (
|
|
8589
|
+
if (isUniqueConstraintError(error)) {
|
|
8617
8590
|
throw new AuthStorageError(code, message);
|
|
8618
8591
|
}
|
|
8619
8592
|
throw error;
|
|
@@ -9092,7 +9065,6 @@ class SqliteAuthInvitationStore {
|
|
|
9092
9065
|
}
|
|
9093
9066
|
|
|
9094
9067
|
// src/auth-storage/magic-links.ts
|
|
9095
|
-
import { resolveAuthSessionAudience } from "@sixb/core";
|
|
9096
9068
|
import { AuthStorageError as AuthStorageError5 } from "@sixb/core/storage";
|
|
9097
9069
|
class SqliteAuthMagicLinkStore {
|
|
9098
9070
|
db;
|
|
@@ -9104,7 +9076,6 @@ class SqliteAuthMagicLinkStore {
|
|
|
9104
9076
|
const id = assertNonEmpty(input.id, "Magic link id");
|
|
9105
9077
|
const projectId = assertNonEmpty(input.projectId, "Project id");
|
|
9106
9078
|
const strategyId = assertNonEmpty(input.strategyId, "Strategy id");
|
|
9107
|
-
const audience = resolveAuthSessionAudience(input.audience);
|
|
9108
9079
|
const email = normalizeEmail(input.email);
|
|
9109
9080
|
const tokenHash = assertNonEmpty(input.tokenHash, "Magic link token hash");
|
|
9110
9081
|
if (getMagicLinkRowById(this.db, { projectId, id })) {
|
|
@@ -9121,14 +9092,13 @@ class SqliteAuthMagicLinkStore {
|
|
|
9121
9092
|
project_id,
|
|
9122
9093
|
id,
|
|
9123
9094
|
strategy_id,
|
|
9124
|
-
audience,
|
|
9125
9095
|
email,
|
|
9126
9096
|
token_hash,
|
|
9127
9097
|
return_to,
|
|
9128
9098
|
created_at,
|
|
9129
9099
|
expires_at
|
|
9130
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?,
|
|
9131
|
-
`).run(projectId, id, strategyId,
|
|
9100
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
9101
|
+
`).run(projectId, id, strategyId, email, tokenHash, input.returnTo ?? null, toIso(input.createdAt), toIso(input.expiresAt));
|
|
9132
9102
|
} catch (error) {
|
|
9133
9103
|
mapUniqueConstraintError(error, "duplicate_magic_link", `[Sixb] Magic link '${id}' already exists for project '${projectId}'.`);
|
|
9134
9104
|
}
|
|
@@ -9136,7 +9106,6 @@ class SqliteAuthMagicLinkStore {
|
|
|
9136
9106
|
id,
|
|
9137
9107
|
projectId,
|
|
9138
9108
|
strategyId,
|
|
9139
|
-
audience,
|
|
9140
9109
|
email,
|
|
9141
9110
|
tokenHash,
|
|
9142
9111
|
returnTo: input.returnTo,
|
|
@@ -9171,7 +9140,6 @@ class SqliteAuthMagicLinkStore {
|
|
|
9171
9140
|
}
|
|
9172
9141
|
|
|
9173
9142
|
// src/auth-storage/oidc-attempts.ts
|
|
9174
|
-
import { resolveAuthSessionAudience as resolveAuthSessionAudience2 } from "@sixb/core";
|
|
9175
9143
|
import { AuthStorageError as AuthStorageError6 } from "@sixb/core/storage";
|
|
9176
9144
|
class SqliteAuthOidcAuthorizationAttemptStore {
|
|
9177
9145
|
db;
|
|
@@ -9183,7 +9151,6 @@ class SqliteAuthOidcAuthorizationAttemptStore {
|
|
|
9183
9151
|
const id = assertNonEmpty(input.id, "OIDC authorization attempt id");
|
|
9184
9152
|
const projectId = assertNonEmpty(input.projectId, "Project id");
|
|
9185
9153
|
const strategyId = assertNonEmpty(input.strategyId, "Strategy id");
|
|
9186
|
-
const audience = resolveAuthSessionAudience2(input.audience);
|
|
9187
9154
|
const stateHash = assertNonEmpty(input.stateHash, "OIDC state hash");
|
|
9188
9155
|
const nonceHash = assertNonEmpty(input.nonceHash, "OIDC nonce hash");
|
|
9189
9156
|
const codeVerifier = assertNonEmpty(input.codeVerifier, "OIDC code verifier");
|
|
@@ -9196,15 +9163,14 @@ class SqliteAuthOidcAuthorizationAttemptStore {
|
|
|
9196
9163
|
project_id,
|
|
9197
9164
|
id,
|
|
9198
9165
|
strategy_id,
|
|
9199
|
-
audience,
|
|
9200
9166
|
state_hash,
|
|
9201
9167
|
nonce_hash,
|
|
9202
9168
|
code_verifier,
|
|
9203
9169
|
return_to,
|
|
9204
9170
|
created_at,
|
|
9205
9171
|
expires_at
|
|
9206
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
|
|
9207
|
-
`).run(projectId, id, strategyId,
|
|
9172
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
9173
|
+
`).run(projectId, id, strategyId, stateHash, nonceHash, codeVerifier, input.returnTo ?? null, toIso(input.createdAt), toIso(input.expiresAt));
|
|
9208
9174
|
} catch (error) {
|
|
9209
9175
|
mapUniqueConstraintError(error, "duplicate_oidc_attempt", `[Sixb] OIDC authorization attempt '${id}' already exists for project '${projectId}'.`);
|
|
9210
9176
|
}
|
|
@@ -9212,7 +9178,6 @@ class SqliteAuthOidcAuthorizationAttemptStore {
|
|
|
9212
9178
|
id,
|
|
9213
9179
|
projectId,
|
|
9214
9180
|
strategyId,
|
|
9215
|
-
audience,
|
|
9216
9181
|
stateHash,
|
|
9217
9182
|
nonceHash,
|
|
9218
9183
|
codeVerifier,
|
|
@@ -9431,21 +9396,6 @@ class SqliteAuthSessionStore {
|
|
|
9431
9396
|
async getById(params) {
|
|
9432
9397
|
return getSessionById(this.db, params);
|
|
9433
9398
|
}
|
|
9434
|
-
async getActiveByUserId(params) {
|
|
9435
|
-
const row = this.db.query(`
|
|
9436
|
-
SELECT *
|
|
9437
|
-
FROM auth_sessions
|
|
9438
|
-
WHERE project_id = ?
|
|
9439
|
-
AND user_id = ?
|
|
9440
|
-
AND audience = ?
|
|
9441
|
-
AND revoked_at IS NULL
|
|
9442
|
-
AND expires_at > ?
|
|
9443
|
-
AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
|
|
9444
|
-
ORDER BY created_at DESC, id DESC
|
|
9445
|
-
LIMIT 1
|
|
9446
|
-
`).get(params.projectId, params.userId, params.audience, toIso(params.now), toIso(params.now));
|
|
9447
|
-
return row ? rowToSessionRecord(row) : null;
|
|
9448
|
-
}
|
|
9449
9399
|
async listActiveByUserId(params) {
|
|
9450
9400
|
const rows = this.db.query(`
|
|
9451
9401
|
SELECT *
|
|
@@ -9461,7 +9411,7 @@ class SqliteAuthSessionStore {
|
|
|
9461
9411
|
}
|
|
9462
9412
|
async findValidByTokenHash(params) {
|
|
9463
9413
|
const row = getSessionRowById(this.db, params);
|
|
9464
|
-
if (!row || row.refresh_token_hash !== null || row.
|
|
9414
|
+
if (!row || row.refresh_token_hash !== null || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
|
|
9465
9415
|
return null;
|
|
9466
9416
|
}
|
|
9467
9417
|
return rowToSessionRecord(row);
|
|
@@ -9516,13 +9466,12 @@ class SqliteAuthSessionStore {
|
|
|
9516
9466
|
last_seen_at = ?
|
|
9517
9467
|
WHERE project_id = ?
|
|
9518
9468
|
AND id = ?
|
|
9519
|
-
AND audience = ?
|
|
9520
9469
|
AND token_hash = ?
|
|
9521
9470
|
AND refresh_token_hash IS NULL
|
|
9522
9471
|
AND revoked_at IS NULL
|
|
9523
9472
|
AND expires_at > ?
|
|
9524
9473
|
AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
|
|
9525
|
-
`).run(expiresAt, expiresAt, now, params.projectId, params.id, params.
|
|
9474
|
+
`).run(expiresAt, expiresAt, now, params.projectId, params.id, params.tokenHash, now, now);
|
|
9526
9475
|
return result.changes === 0 ? null : getSessionById(this.db, params);
|
|
9527
9476
|
});
|
|
9528
9477
|
}
|
|
@@ -9715,9 +9664,6 @@ class SqliteAuthStorage {
|
|
|
9715
9664
|
constructor(options = {}) {
|
|
9716
9665
|
this.connection = openSqliteStoreConnection(options);
|
|
9717
9666
|
this.db = this.connection.db;
|
|
9718
|
-
if (this.connection.installFreshSchema) {
|
|
9719
|
-
installFreshSqliteSchema(this.db);
|
|
9720
|
-
}
|
|
9721
9667
|
this.users = new SqliteAuthUserStore(this.db);
|
|
9722
9668
|
this.identities = new SqliteAuthUserIdentityStore(this.db);
|
|
9723
9669
|
this.serviceAccounts = new SqliteAuthServiceAccountStore(this.db);
|
|
@@ -9796,7 +9742,6 @@ class SqliteAuthStorage {
|
|
|
9796
9742
|
};
|
|
9797
9743
|
}
|
|
9798
9744
|
validateCompleteSessionInput(this.db, projectId, input.session);
|
|
9799
|
-
assertSignInSessionAudience(projectId, input.session.audience, magicLink.audience);
|
|
9800
9745
|
let newUserId;
|
|
9801
9746
|
if (shouldCreateUser) {
|
|
9802
9747
|
newUserId = assertNonEmpty(input.newUserId, "User id");
|
|
@@ -9893,7 +9838,6 @@ class SqliteAuthStorage {
|
|
|
9893
9838
|
};
|
|
9894
9839
|
}
|
|
9895
9840
|
validateCompleteSessionInput(this.db, projectId, input.session);
|
|
9896
|
-
assertSignInSessionAudience(projectId, input.session.audience, attempt.audience);
|
|
9897
9841
|
let newUserId;
|
|
9898
9842
|
if (shouldCreateUser) {
|
|
9899
9843
|
newUserId = assertNonEmpty(input.newUserId, "User id");
|
|
@@ -10112,7 +10056,6 @@ class SqliteAuthStorage {
|
|
|
10112
10056
|
projectId: input.projectId,
|
|
10113
10057
|
userId: input.userId,
|
|
10114
10058
|
strategyId: input.strategyId,
|
|
10115
|
-
audience: input.session.audience,
|
|
10116
10059
|
tokenHash: input.session.tokenHash,
|
|
10117
10060
|
createdAt: input.session.createdAt,
|
|
10118
10061
|
expiresAt: input.session.expiresAt,
|
|
@@ -10157,12 +10100,6 @@ class SqliteAuthStorage {
|
|
|
10157
10100
|
});
|
|
10158
10101
|
}
|
|
10159
10102
|
}
|
|
10160
|
-
function assertSignInSessionAudience(projectId, sessionAudience, storedAudience) {
|
|
10161
|
-
if (sessionAudience === storedAudience) {
|
|
10162
|
-
return;
|
|
10163
|
-
}
|
|
10164
|
-
throw new AuthStorageError11("invalid_input", `[Sixb] Sign-in session audience '${sessionAudience}' does not match stored auth audience '${storedAudience}' for project '${projectId}'.`);
|
|
10165
|
-
}
|
|
10166
10103
|
function assertCompletableDeviceAuthorization(authorization, input) {
|
|
10167
10104
|
if (authorization.deviceCodeHash !== input.deviceCodeHash) {
|
|
10168
10105
|
throw new AuthStorageError11("invalid_device_authorization", "[Sixb] Invalid device authorization.");
|
|
@@ -10233,7 +10170,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10233
10170
|
`).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
10171
|
return true;
|
|
10235
10172
|
} catch (error) {
|
|
10236
|
-
if (
|
|
10173
|
+
if (isUniqueConstraintError(error))
|
|
10237
10174
|
return false;
|
|
10238
10175
|
throw error;
|
|
10239
10176
|
}
|
|
@@ -10259,7 +10196,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10259
10196
|
this.insertRun(record);
|
|
10260
10197
|
return true;
|
|
10261
10198
|
} catch (error) {
|
|
10262
|
-
if (
|
|
10199
|
+
if (isUniqueConstraintError(error))
|
|
10263
10200
|
return false;
|
|
10264
10201
|
throw error;
|
|
10265
10202
|
}
|
|
@@ -10293,7 +10230,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10293
10230
|
this.insertAuthorizationRow(record);
|
|
10294
10231
|
return true;
|
|
10295
10232
|
} catch (error) {
|
|
10296
|
-
if (
|
|
10233
|
+
if (isUniqueConstraintError(error))
|
|
10297
10234
|
return false;
|
|
10298
10235
|
throw error;
|
|
10299
10236
|
}
|
|
@@ -10324,7 +10261,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10324
10261
|
`).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
10262
|
return true;
|
|
10326
10263
|
} catch (error) {
|
|
10327
|
-
if (
|
|
10264
|
+
if (isUniqueConstraintError(error))
|
|
10328
10265
|
return false;
|
|
10329
10266
|
throw error;
|
|
10330
10267
|
}
|
|
@@ -10837,7 +10774,7 @@ class SqliteFileUploadSessionPersistence {
|
|
|
10837
10774
|
) 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
10775
|
return true;
|
|
10839
10776
|
} catch (error) {
|
|
10840
|
-
if (
|
|
10777
|
+
if (isUniqueConstraintError(error))
|
|
10841
10778
|
return false;
|
|
10842
10779
|
throw error;
|
|
10843
10780
|
}
|
|
@@ -12821,9 +12758,6 @@ class SqliteObjectStorage {
|
|
|
12821
12758
|
this.connection = openSqliteStoreConnection(options);
|
|
12822
12759
|
this.db = this.connection.db;
|
|
12823
12760
|
this.reader = new SqliteObjectReader(this.db, DEFAULT_OBJECT_QUERY_SOURCE);
|
|
12824
|
-
if (this.connection.installFreshSchema) {
|
|
12825
|
-
installFreshSqliteSchema(this.db);
|
|
12826
|
-
}
|
|
12827
12761
|
}
|
|
12828
12762
|
queryCapabilities() {
|
|
12829
12763
|
return SQLITE_OBJECT_QUERY_CAPABILITIES;
|
|
@@ -16366,9 +16300,6 @@ class SqlitePipelineRunStorage {
|
|
|
16366
16300
|
this.connection = openSqliteStoreConnection(options);
|
|
16367
16301
|
this.db = this.connection.db;
|
|
16368
16302
|
this.executions = options.executions;
|
|
16369
|
-
if (this.connection.installFreshSchema) {
|
|
16370
|
-
installFreshSqliteSchema(this.db);
|
|
16371
|
-
}
|
|
16372
16303
|
}
|
|
16373
16304
|
async queue(input) {
|
|
16374
16305
|
const queuedAt = input.queuedAt ?? new Date;
|
|
@@ -16392,7 +16323,7 @@ class SqlitePipelineRunStorage {
|
|
|
16392
16323
|
) VALUES (?, ?, ?, ?, ?, ?, NULL)
|
|
16393
16324
|
`).run(input.projectId, input.id, input.executionId, input.pipelineId, "queued", queuedAt.toISOString());
|
|
16394
16325
|
} catch (error) {
|
|
16395
|
-
if (
|
|
16326
|
+
if (isUniqueConstraintError(error)) {
|
|
16396
16327
|
return this.requeueAfterEnqueueFailure(input, queuedAt);
|
|
16397
16328
|
}
|
|
16398
16329
|
throw error;
|
|
@@ -16489,7 +16420,7 @@ class SqlitePipelineRunStorage {
|
|
|
16489
16420
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
16490
16421
|
`).run(input.projectId, input.id, input.pipelineRunId, input.pipelineId, input.stepId, input.datasetId, input.mode, "running", startedAt.toISOString(), serializeDatasetVersionRefs(input.inputs));
|
|
16491
16422
|
} catch (error) {
|
|
16492
|
-
if (
|
|
16423
|
+
if (isUniqueConstraintError(error)) {
|
|
16493
16424
|
throw new PipelineRunError(`[SixbSqlite] Pipeline step run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
16494
16425
|
}
|
|
16495
16426
|
throw error;
|
|
@@ -16714,9 +16645,6 @@ class SqliteProjectionRunStorage {
|
|
|
16714
16645
|
this.connection = openSqliteStoreConnection(options);
|
|
16715
16646
|
this.db = this.connection.db;
|
|
16716
16647
|
this.executions = options.executions;
|
|
16717
|
-
if (this.connection.installFreshSchema) {
|
|
16718
|
-
installFreshSqliteSchema(this.db);
|
|
16719
|
-
}
|
|
16720
16648
|
}
|
|
16721
16649
|
async queue(input) {
|
|
16722
16650
|
assertProjectionRunQueueInput(input);
|
|
@@ -16757,7 +16685,7 @@ class SqliteProjectionRunStorage {
|
|
|
16757
16685
|
try {
|
|
16758
16686
|
this.insertQueued(record);
|
|
16759
16687
|
} catch (error) {
|
|
16760
|
-
if (
|
|
16688
|
+
if (isUniqueConstraintError2(error))
|
|
16761
16689
|
throw duplicateProjectionRun(input);
|
|
16762
16690
|
throw error;
|
|
16763
16691
|
}
|
|
@@ -17146,7 +17074,7 @@ function databaseSafeInteger(value, fieldName) {
|
|
|
17146
17074
|
}
|
|
17147
17075
|
return value;
|
|
17148
17076
|
}
|
|
17149
|
-
function
|
|
17077
|
+
function isUniqueConstraintError2(error) {
|
|
17150
17078
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
17151
17079
|
}
|
|
17152
17080
|
function duplicateProjectionRun(input) {
|
|
@@ -17160,9 +17088,6 @@ class SqliteRulesStorage {
|
|
|
17160
17088
|
constructor(options = {}) {
|
|
17161
17089
|
this.connection = openSqliteStoreConnection(options);
|
|
17162
17090
|
this.db = this.connection.db;
|
|
17163
|
-
if (this.connection.installFreshSchema) {
|
|
17164
|
-
installFreshSqliteSchema(this.db);
|
|
17165
|
-
}
|
|
17166
17091
|
}
|
|
17167
17092
|
async getActive(params) {
|
|
17168
17093
|
const row = this.db.query(`
|
|
@@ -17408,8 +17333,6 @@ class SqliteShareGrantStorage {
|
|
|
17408
17333
|
constructor(options = {}) {
|
|
17409
17334
|
this.connection = openSqliteStoreConnection(options);
|
|
17410
17335
|
this.db = this.connection.db;
|
|
17411
|
-
if (this.connection.installFreshSchema)
|
|
17412
|
-
installFreshSqliteSchema(this.db);
|
|
17413
17336
|
}
|
|
17414
17337
|
async create(input) {
|
|
17415
17338
|
const record = normalizeShareGrantCreate(input);
|
|
@@ -17422,7 +17345,7 @@ class SqliteShareGrantStorage {
|
|
|
17422
17345
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
17423
17346
|
`).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
17347
|
} catch (error) {
|
|
17425
|
-
if (
|
|
17348
|
+
if (isUniqueConstraintError(error)) {
|
|
17426
17349
|
throw new ShareGrantStorageError("duplicate", `[SixbSqlite] Share grant '${record.id}' conflicts with an existing record.`, { cause: error });
|
|
17427
17350
|
}
|
|
17428
17351
|
throw error;
|
|
@@ -17554,8 +17477,6 @@ class SqliteShareSessionStorage {
|
|
|
17554
17477
|
constructor(options = {}) {
|
|
17555
17478
|
this.connection = openSqliteStoreConnection(options);
|
|
17556
17479
|
this.db = this.connection.db;
|
|
17557
|
-
if (this.connection.installFreshSchema)
|
|
17558
|
-
installFreshSqliteSchema(this.db);
|
|
17559
17480
|
}
|
|
17560
17481
|
async create(input) {
|
|
17561
17482
|
const record = normalizeShareSessionCreate(input);
|
|
@@ -17571,7 +17492,7 @@ class SqliteShareSessionStorage {
|
|
|
17571
17492
|
throw invalidRecord2(`Share session '${record.id}' disappeared after create.`);
|
|
17572
17493
|
return rowToRecord2(row);
|
|
17573
17494
|
} catch (error) {
|
|
17574
|
-
if (
|
|
17495
|
+
if (isUniqueConstraintError(error)) {
|
|
17575
17496
|
throw new ShareSessionStorageError("duplicate", `[SixbSqlite] Share session '${record.id}' conflicts with an existing record.`, { cause: error });
|
|
17576
17497
|
}
|
|
17577
17498
|
if (isForeignKeyConstraintError(error)) {
|
|
@@ -17658,9 +17579,6 @@ class SqliteSyncRunStorage {
|
|
|
17658
17579
|
this.connection = openSqliteStoreConnection(options);
|
|
17659
17580
|
this.db = this.connection.db;
|
|
17660
17581
|
this.executions = options.executions;
|
|
17661
|
-
if (this.connection.installFreshSchema) {
|
|
17662
|
-
installFreshSqliteSchema(this.db);
|
|
17663
|
-
}
|
|
17664
17582
|
}
|
|
17665
17583
|
async queue(input) {
|
|
17666
17584
|
const queuedAt = input.queuedAt ?? new Date;
|
|
@@ -17688,7 +17606,7 @@ class SqliteSyncRunStorage {
|
|
|
17688
17606
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)
|
|
17689
17607
|
`).run(input.projectId, input.id, input.executionId, input.syncId, input.datasetId, input.mode, "queued", queuedAt.toISOString(), input.expectedLatestVersionId ?? null, input.commitMessage ?? null);
|
|
17690
17608
|
} catch (error) {
|
|
17691
|
-
if (
|
|
17609
|
+
if (isUniqueConstraintError3(error)) {
|
|
17692
17610
|
return this.requeueAfterEnqueueFailure(input, queuedAt);
|
|
17693
17611
|
}
|
|
17694
17612
|
throw error;
|
|
@@ -17853,7 +17771,7 @@ function rowToSyncRunRecord(row) {
|
|
|
17853
17771
|
checkpoint: parseCheckpoint(row.checkpoint)
|
|
17854
17772
|
};
|
|
17855
17773
|
}
|
|
17856
|
-
function
|
|
17774
|
+
function isUniqueConstraintError3(error) {
|
|
17857
17775
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed");
|
|
17858
17776
|
}
|
|
17859
17777
|
|
|
@@ -17870,9 +17788,6 @@ class SqliteTimeseriesStorage {
|
|
|
17870
17788
|
constructor(options = {}) {
|
|
17871
17789
|
this.connection = openSqliteStoreConnection(options);
|
|
17872
17790
|
this.db = this.connection.db;
|
|
17873
|
-
if (this.connection.installFreshSchema) {
|
|
17874
|
-
installFreshSqliteSchema(this.db);
|
|
17875
|
-
}
|
|
17876
17791
|
}
|
|
17877
17792
|
async getHistory(params) {
|
|
17878
17793
|
let query = `
|
|
@@ -17999,8 +17914,6 @@ class SqliteWebhookRunStorage {
|
|
|
17999
17914
|
this.connection = openSqliteStoreConnection(options);
|
|
18000
17915
|
this.db = this.connection.db;
|
|
18001
17916
|
this.executions = options.executions;
|
|
18002
|
-
if (this.connection.installFreshSchema)
|
|
18003
|
-
installFreshSqliteSchema(this.db);
|
|
18004
17917
|
}
|
|
18005
17918
|
async start(input) {
|
|
18006
17919
|
const startedAt = input.startedAt ?? new Date;
|
|
@@ -18019,7 +17932,7 @@ class SqliteWebhookRunStorage {
|
|
|
18019
17932
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18020
17933
|
`).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
17934
|
} catch (error) {
|
|
18022
|
-
if (
|
|
17935
|
+
if (isUniqueConstraintError(error)) {
|
|
18023
17936
|
throw new WebhookRunError(`[SixbSqlite] Webhook run '${input.id}' or delivery key already exists for project '${input.projectId}'.`, "duplicate_run");
|
|
18024
17937
|
}
|
|
18025
17938
|
throw error;
|
|
@@ -18146,9 +18059,6 @@ class SqliteWorkflowInterventionStorage {
|
|
|
18146
18059
|
constructor(options = {}) {
|
|
18147
18060
|
this.connection = openSqliteStoreConnection(options);
|
|
18148
18061
|
this.db = this.connection.db;
|
|
18149
|
-
if (this.connection.installFreshSchema) {
|
|
18150
|
-
installFreshSqliteSchema(this.db);
|
|
18151
|
-
}
|
|
18152
18062
|
}
|
|
18153
18063
|
async create(input) {
|
|
18154
18064
|
assertNonNegativeInteger(input.nodeIndex, "nodeIndex");
|
|
@@ -18172,7 +18082,7 @@ class SqliteWorkflowInterventionStorage {
|
|
|
18172
18082
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18173
18083
|
`).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
18084
|
} catch (error) {
|
|
18175
|
-
if (
|
|
18085
|
+
if (isUniqueConstraintError(error)) {
|
|
18176
18086
|
throw new WorkflowInterventionError(`[SixbSqlite] Workflow intervention '${input.id}' already exists for project '${input.projectId}'.`);
|
|
18177
18087
|
}
|
|
18178
18088
|
throw error;
|
|
@@ -18383,9 +18293,6 @@ class SqliteWorkflowRunStorage {
|
|
|
18383
18293
|
this.connection = openSqliteStoreConnection(options);
|
|
18384
18294
|
this.db = this.connection.db;
|
|
18385
18295
|
this.executions = options.executions;
|
|
18386
|
-
if (this.connection.installFreshSchema) {
|
|
18387
|
-
installFreshSqliteSchema(this.db);
|
|
18388
|
-
}
|
|
18389
18296
|
this.nodes = new SqliteWorkflowNodeRunStorage(this.db);
|
|
18390
18297
|
this.agentNodes = new SqliteWorkflowAgentNodeRunStorage(this.db, this.executions);
|
|
18391
18298
|
}
|
|
@@ -18413,7 +18320,7 @@ class SqliteWorkflowRunStorage {
|
|
|
18413
18320
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18414
18321
|
`).run(input.projectId, input.id, input.executionId, input.workflowId, "queued", serializeRecord2(input.input), queuedAt.toISOString(), queuedAt.toISOString(), 0);
|
|
18415
18322
|
} catch (error) {
|
|
18416
|
-
if (
|
|
18323
|
+
if (isUniqueConstraintError(error)) {
|
|
18417
18324
|
throw new WorkflowRunError(`[SixbSqlite] Workflow run '${input.id}' or execution '${input.executionId}' is already linked for project '${input.projectId}'.`);
|
|
18418
18325
|
}
|
|
18419
18326
|
throw error;
|
|
@@ -18639,7 +18546,7 @@ class SqliteWorkflowAgentNodeRunStorage {
|
|
|
18639
18546
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
18640
18547
|
`).run(input.projectId, input.nodeRunId, input.executionId, input.actorId, "queued", input.prompt, 0, (input.createdAt ?? new Date).toISOString());
|
|
18641
18548
|
} catch (error) {
|
|
18642
|
-
if (
|
|
18549
|
+
if (isUniqueConstraintError(error)) {
|
|
18643
18550
|
throw new WorkflowRunError(`[SixbSqlite] Agent execution already exists for workflow node run '${input.nodeRunId}'.`);
|
|
18644
18551
|
}
|
|
18645
18552
|
throw error;
|
|
@@ -18788,7 +18695,7 @@ class SqliteWorkflowNodeRunStorage {
|
|
|
18788
18695
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18789
18696
|
`).run(input.projectId, input.id, input.workflowRunId, input.workflowId, input.nodeIndex, input.nodeType, input.nodeId, input.nodeKey, "running", serializeRecord2(input.input), startedAt.toISOString());
|
|
18790
18697
|
} catch (error) {
|
|
18791
|
-
if (
|
|
18698
|
+
if (isUniqueConstraintError(error)) {
|
|
18792
18699
|
throw new WorkflowRunError(`[SixbSqlite] Workflow node run '${input.id}' already exists for project '${input.projectId}'.`);
|
|
18793
18700
|
}
|
|
18794
18701
|
throw error;
|
|
@@ -19031,9 +18938,6 @@ class SqliteStorage {
|
|
|
19031
18938
|
} else {
|
|
19032
18939
|
this.readConnection = this.connection;
|
|
19033
18940
|
}
|
|
19034
|
-
if (this.connection.installFreshSchema) {
|
|
19035
|
-
installFreshSqliteSchema(this.connection.db);
|
|
19036
|
-
}
|
|
19037
18941
|
const stores = createSqliteStores(this.connection, {
|
|
19038
18942
|
runOntologyOperation: async (run) => run(),
|
|
19039
18943
|
transactionContext: null
|
|
@@ -19126,8 +19030,7 @@ class SqliteStorage {
|
|
|
19126
19030
|
return {
|
|
19127
19031
|
...createSqliteStores({
|
|
19128
19032
|
db: this.connection.db,
|
|
19129
|
-
ownsConnection: false
|
|
19130
|
-
installFreshSchema: false
|
|
19033
|
+
ownsConnection: false
|
|
19131
19034
|
}, {
|
|
19132
19035
|
runOntologyOperation: async (run) => run(),
|
|
19133
19036
|
transactionContext
|
|
@@ -19206,4 +19109,4 @@ export {
|
|
|
19206
19109
|
migrateSqliteStorage
|
|
19207
19110
|
};
|
|
19208
19111
|
|
|
19209
|
-
//# debugId=
|
|
19112
|
+
//# debugId=7AEE546F2916C86164756E2164756E21
|