@sixb/sqlite 0.1.20 → 0.1.21
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 -0
- package/dist/action-run-storage.d.ts.map +1 -1
- package/dist/activity-storage.d.ts +20 -0
- package/dist/activity-storage.d.ts.map +1 -0
- package/dist/agents/threads.d.ts +4 -0
- package/dist/agents/threads.d.ts.map +1 -1
- package/dist/artifact-storage.d.ts +22 -0
- package/dist/artifact-storage.d.ts.map +1 -0
- package/dist/auth-storage/sessions.d.ts +2 -1
- package/dist/auth-storage/sessions.d.ts.map +1 -1
- package/dist/execution-storage.d.ts +2 -1
- package/dist/execution-storage.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +880 -14
- package/dist/index.js.map +14 -12
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/sources.d.ts +2 -1
- package/dist/ontology-storage/sources.d.ts.map +1 -1
- package/dist/share-grant-storage.d.ts +2 -1
- package/dist/share-grant-storage.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts +4 -0
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/action-run-storage.ts +27 -0
- package/src/activity-storage.ts +588 -0
- package/src/agents/threads.ts +27 -0
- package/src/artifact-storage.ts +356 -0
- package/src/auth-storage/sessions.ts +27 -0
- package/src/execution-storage.ts +56 -0
- package/src/index.ts +10 -0
- package/src/migrations/062-artifacts.sql +71 -0
- package/src/migrations/063-drop-output-diagnostics.sql +19 -0
- package/src/migrations/064-activity.sql +61 -0
- package/src/migrations/065-activity-timeline.sql +19 -0
- package/src/migrations/066-activity-interactions.sql +20 -0
- package/src/migrations.ts +14 -0
- package/src/ontology-storage/sources.ts +41 -0
- package/src/share-grant-storage.ts +25 -0
- package/src/workflow-run-storage.ts +27 -0
package/dist/index.js
CHANGED
|
@@ -5166,6 +5166,211 @@ ALTER TABLE auth_magic_links DROP COLUMN audience;
|
|
|
5166
5166
|
ALTER TABLE auth_oidc_authorization_attempts DROP COLUMN audience;
|
|
5167
5167
|
`;
|
|
5168
5168
|
|
|
5169
|
+
// src/migrations/062-artifacts.sql
|
|
5170
|
+
var _062_artifacts_default = `-- Artifacts: versioned documents, sheets, decks, and files. An artifact's kind never
|
|
5171
|
+
-- changes. Versions take \`next_version\`, which only grows, so a number is never reused after its
|
|
5172
|
+
-- version is deleted. Timestamps are ISO-8601 UTC text and compare lexicographically.
|
|
5173
|
+
CREATE TABLE artifacts (
|
|
5174
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
5175
|
+
id TEXT NOT NULL CHECK (length(trim(id)) > 0),
|
|
5176
|
+
kind TEXT NOT NULL CHECK (kind IN ('document', 'sheet', 'slides', 'file')),
|
|
5177
|
+
title TEXT NOT NULL CHECK (length(trim(title)) > 0),
|
|
5178
|
+
owner_principal_type TEXT NOT NULL
|
|
5179
|
+
CHECK (owner_principal_type IN ('user', 'serviceAccount', 'system')),
|
|
5180
|
+
owner_principal_id TEXT NOT NULL CHECK (length(owner_principal_id) > 0),
|
|
5181
|
+
latest_version INTEGER NOT NULL CHECK (latest_version > 0),
|
|
5182
|
+
next_version INTEGER NOT NULL CHECK (next_version > latest_version),
|
|
5183
|
+
created_at TEXT NOT NULL,
|
|
5184
|
+
updated_at TEXT NOT NULL,
|
|
5185
|
+
PRIMARY KEY (project_id, id)
|
|
5186
|
+
);
|
|
5187
|
+
|
|
5188
|
+
CREATE INDEX idx_artifacts_project_updated ON artifacts (project_id, updated_at DESC, id);
|
|
5189
|
+
CREATE INDEX idx_artifacts_owner_updated
|
|
5190
|
+
ON artifacts (project_id, owner_principal_type, owner_principal_id, updated_at DESC, id);
|
|
5191
|
+
|
|
5192
|
+
-- \`refs\`, not \`references\`: that word is reserved in SQL.
|
|
5193
|
+
CREATE TABLE artifact_versions (
|
|
5194
|
+
project_id TEXT NOT NULL,
|
|
5195
|
+
artifact_id TEXT NOT NULL,
|
|
5196
|
+
version INTEGER NOT NULL CHECK (version > 0),
|
|
5197
|
+
title TEXT NOT NULL CHECK (length(trim(title)) > 0),
|
|
5198
|
+
entry TEXT NOT NULL CHECK (length(entry) > 0),
|
|
5199
|
+
files TEXT NOT NULL CHECK (json_type(files) = 'array'),
|
|
5200
|
+
outline TEXT NOT NULL CHECK (json_type(outline) = 'object'),
|
|
5201
|
+
refs TEXT NOT NULL CHECK (json_type(refs) = 'array'),
|
|
5202
|
+
author_principal_type TEXT NOT NULL
|
|
5203
|
+
CHECK (author_principal_type IN ('user', 'serviceAccount', 'system')),
|
|
5204
|
+
author_principal_id TEXT NOT NULL CHECK (length(author_principal_id) > 0),
|
|
5205
|
+
origin_thread_id TEXT,
|
|
5206
|
+
origin_run_id TEXT,
|
|
5207
|
+
created_at TEXT NOT NULL,
|
|
5208
|
+
PRIMARY KEY (project_id, artifact_id, version),
|
|
5209
|
+
FOREIGN KEY (project_id, artifact_id) REFERENCES artifacts (project_id, id) ON DELETE CASCADE,
|
|
5210
|
+
CHECK ((origin_thread_id IS NULL) = (origin_run_id IS NULL))
|
|
5211
|
+
);
|
|
5212
|
+
|
|
5213
|
+
CREATE INDEX idx_artifact_versions_origin_run
|
|
5214
|
+
ON artifact_versions (project_id, origin_run_id) WHERE origin_run_id IS NOT NULL;
|
|
5215
|
+
CREATE INDEX idx_artifact_versions_origin_thread
|
|
5216
|
+
ON artifact_versions (project_id, origin_thread_id, artifact_id) WHERE origin_thread_id IS NOT NULL;
|
|
5217
|
+
|
|
5218
|
+
-- Short-lived links that a sandboxed frame loads a deck's files through. Only the SHA-256 of each
|
|
5219
|
+
-- link's token is stored. \`targets\` is what the frame may show from other artifacts, decided for
|
|
5220
|
+
-- its reader when the link was issued: a JSON array of { address, artifactId, version }.
|
|
5221
|
+
CREATE TABLE artifact_frame_grants (
|
|
5222
|
+
project_id TEXT NOT NULL,
|
|
5223
|
+
token_hash TEXT NOT NULL CHECK (
|
|
5224
|
+
length(token_hash) = 64
|
|
5225
|
+
AND token_hash = lower(token_hash)
|
|
5226
|
+
AND token_hash NOT GLOB '*[^0-9a-f]*'
|
|
5227
|
+
),
|
|
5228
|
+
artifact_id TEXT NOT NULL,
|
|
5229
|
+
version INTEGER NOT NULL CHECK (version > 0),
|
|
5230
|
+
targets TEXT NOT NULL CHECK (json_type(targets) = 'array'),
|
|
5231
|
+
created_at TEXT NOT NULL,
|
|
5232
|
+
expires_at TEXT NOT NULL,
|
|
5233
|
+
PRIMARY KEY (project_id, token_hash),
|
|
5234
|
+
FOREIGN KEY (project_id, artifact_id) REFERENCES artifacts (project_id, id) ON DELETE CASCADE,
|
|
5235
|
+
CHECK (expires_at > created_at)
|
|
5236
|
+
);
|
|
5237
|
+
|
|
5238
|
+
CREATE INDEX idx_artifact_frame_grants_expiry ON artifact_frame_grants (project_id, expires_at);
|
|
5239
|
+
-- Deleting an artifact cascades here.
|
|
5240
|
+
CREATE INDEX idx_artifact_frame_grants_artifact ON artifact_frame_grants (project_id, artifact_id);
|
|
5241
|
+
`;
|
|
5242
|
+
|
|
5243
|
+
// src/migrations/063-drop-output-diagnostics.sql
|
|
5244
|
+
var _063_drop_output_diagnostics_default = `-- The Agent delivers files by publishing artifacts, so a run no longer collects an output
|
|
5245
|
+
-- directory or reports on it. Stored \`output_*\` diagnostics go; a run left with none stores none.
|
|
5246
|
+
UPDATE agent_runs
|
|
5247
|
+
SET diagnostics = (
|
|
5248
|
+
SELECT CASE WHEN count(*) = 0 THEN NULL ELSE json_group_array(json(value)) END
|
|
5249
|
+
FROM (
|
|
5250
|
+
SELECT value
|
|
5251
|
+
FROM json_each(agent_runs.diagnostics)
|
|
5252
|
+
WHERE json_extract(value, '$.code') NOT LIKE 'output\\_%' ESCAPE '\\'
|
|
5253
|
+
ORDER BY key
|
|
5254
|
+
)
|
|
5255
|
+
)
|
|
5256
|
+
WHERE diagnostics IS NOT NULL
|
|
5257
|
+
AND json_valid(diagnostics)
|
|
5258
|
+
AND EXISTS (
|
|
5259
|
+
SELECT 1
|
|
5260
|
+
FROM json_each(agent_runs.diagnostics)
|
|
5261
|
+
WHERE json_extract(value, '$.code') LIKE 'output\\_%' ESCAPE '\\'
|
|
5262
|
+
);
|
|
5263
|
+
`;
|
|
5264
|
+
|
|
5265
|
+
// src/migrations/064-activity.sql
|
|
5266
|
+
var _064_activity_default = `-- App activity: one source per verified session, the visits it opened, and their page views.
|
|
5267
|
+
-- Foreground activity moves a visit's \`last_seen_at\` and stores no row, unless it opens a visit.
|
|
5268
|
+
-- A session id names an \`auth_sessions\` row for a user and a \`share_sessions\` row for a share; it
|
|
5269
|
+
-- is not a secret, and no foreign key holds it, so history outlives its sessions. Timestamps are
|
|
5270
|
+
-- ISO-8601 UTC text and compare lexicographically.
|
|
5271
|
+
CREATE TABLE activity_sources (
|
|
5272
|
+
project_id TEXT NOT NULL,
|
|
5273
|
+
actor_type TEXT NOT NULL CHECK (actor_type IN ('user', 'share')),
|
|
5274
|
+
session_id TEXT NOT NULL CHECK (length(session_id) > 0),
|
|
5275
|
+
visit_id TEXT NOT NULL,
|
|
5276
|
+
last_seen_at TEXT NOT NULL,
|
|
5277
|
+
sequence INTEGER NOT NULL CHECK (sequence >= 0),
|
|
5278
|
+
window_start TEXT NOT NULL,
|
|
5279
|
+
window_count INTEGER NOT NULL CHECK (window_count >= 0),
|
|
5280
|
+
PRIMARY KEY (project_id, actor_type, session_id)
|
|
5281
|
+
);
|
|
5282
|
+
|
|
5283
|
+
CREATE TABLE activity_visits (
|
|
5284
|
+
project_id TEXT NOT NULL,
|
|
5285
|
+
id TEXT NOT NULL,
|
|
5286
|
+
actor_type TEXT NOT NULL CHECK (actor_type IN ('user', 'share')),
|
|
5287
|
+
user_id TEXT,
|
|
5288
|
+
grant_id TEXT,
|
|
5289
|
+
session_id TEXT NOT NULL CHECK (length(session_id) > 0),
|
|
5290
|
+
started_at TEXT NOT NULL,
|
|
5291
|
+
last_seen_at TEXT NOT NULL CHECK (last_seen_at >= started_at),
|
|
5292
|
+
page_views INTEGER NOT NULL CHECK (page_views >= 0),
|
|
5293
|
+
attribution TEXT CHECK (attribution IS NULL OR json_type(attribution) = 'object'),
|
|
5294
|
+
PRIMARY KEY (project_id, id),
|
|
5295
|
+
CHECK (
|
|
5296
|
+
(actor_type = 'user' AND user_id IS NOT NULL AND grant_id IS NULL)
|
|
5297
|
+
OR (actor_type = 'share' AND user_id IS NULL AND grant_id IS NOT NULL)
|
|
5298
|
+
)
|
|
5299
|
+
);
|
|
5300
|
+
|
|
5301
|
+
-- A period reads the visits it overlaps. A visit lasts less than a day, so they started in
|
|
5302
|
+
-- \`[from - 1 day, to)\`: both period indexes bound \`started_at\` on both sides. \`last_seen_at\` is
|
|
5303
|
+
-- left out of every index, so the update each batch makes touches none of them. The user index
|
|
5304
|
+
-- also serves deleting one user's history.
|
|
5305
|
+
CREATE INDEX idx_activity_visits_started
|
|
5306
|
+
ON activity_visits (project_id, started_at, id);
|
|
5307
|
+
CREATE INDEX idx_activity_visits_user
|
|
5308
|
+
ON activity_visits (project_id, user_id, started_at, id);
|
|
5309
|
+
-- A session's visits, to join them with the session and the executions it authorized.
|
|
5310
|
+
CREATE INDEX idx_activity_visits_session
|
|
5311
|
+
ON activity_visits (project_id, actor_type, session_id);
|
|
5312
|
+
|
|
5313
|
+
CREATE TABLE activity_page_views (
|
|
5314
|
+
project_id TEXT NOT NULL,
|
|
5315
|
+
visit_id TEXT NOT NULL,
|
|
5316
|
+
sequence INTEGER NOT NULL CHECK (sequence > 0),
|
|
5317
|
+
id TEXT NOT NULL,
|
|
5318
|
+
route TEXT NOT NULL,
|
|
5319
|
+
received_at TEXT NOT NULL,
|
|
5320
|
+
attribution TEXT CHECK (attribution IS NULL OR json_type(attribution) = 'object'),
|
|
5321
|
+
PRIMARY KEY (project_id, visit_id, sequence),
|
|
5322
|
+
FOREIGN KEY (project_id, visit_id) REFERENCES activity_visits (project_id, id) ON DELETE CASCADE
|
|
5323
|
+
);
|
|
5324
|
+
|
|
5325
|
+
-- Finds a retried page view by the id its browser chose.
|
|
5326
|
+
CREATE INDEX idx_activity_page_views_id ON activity_page_views (project_id, id);
|
|
5327
|
+
`;
|
|
5328
|
+
|
|
5329
|
+
// src/migrations/065-activity-timeline.sql
|
|
5330
|
+
var _065_activity_timeline_default = `-- A visit's timeline reads what its session started: the roots it authorized in a window, then
|
|
5331
|
+
-- everything they caused. A signed-in session is the credential of its roots, a shared link's
|
|
5332
|
+
-- session their delegation; a child names its parent. Agent executions copy their parent's
|
|
5333
|
+
-- session: the root indexes hold only executions without a parent, so they never see those, and
|
|
5334
|
+
-- end with \`id\` so the root read's order needs no sort.
|
|
5335
|
+
CREATE INDEX idx_executions_session_roots
|
|
5336
|
+
ON executions (project_id, authority_session_id, created_at, id)
|
|
5337
|
+
WHERE authority_session_id IS NOT NULL AND parent_execution_id IS NULL;
|
|
5338
|
+
CREATE INDEX idx_executions_delegation_roots
|
|
5339
|
+
ON executions (project_id, authority_delegation_session_id, created_at, id)
|
|
5340
|
+
WHERE authority_delegation_session_id IS NOT NULL AND parent_execution_id IS NULL;
|
|
5341
|
+
CREATE INDEX idx_executions_parent
|
|
5342
|
+
ON executions (project_id, parent_execution_id)
|
|
5343
|
+
WHERE parent_execution_id IS NOT NULL;
|
|
5344
|
+
|
|
5345
|
+
-- A user's connection history lists all their sessions, revoked and expired ones too, newest
|
|
5346
|
+
-- first.
|
|
5347
|
+
CREATE INDEX idx_auth_sessions_user_created
|
|
5348
|
+
ON auth_sessions (project_id, user_id, created_at, id);
|
|
5349
|
+
`;
|
|
5350
|
+
|
|
5351
|
+
// src/migrations/066-activity-interactions.sql
|
|
5352
|
+
var _066_activity_interactions_default = `-- Interactions an app marks, such as a button: their name and route, never a value. They share
|
|
5353
|
+
-- the visit's sequence with its page views, so a visit reads both in the order they happened, and
|
|
5354
|
+
-- cascade with the visit, which counts them as it counts its page views.
|
|
5355
|
+
ALTER TABLE activity_visits
|
|
5356
|
+
ADD COLUMN interactions INTEGER NOT NULL DEFAULT 0 CHECK (interactions >= 0);
|
|
5357
|
+
|
|
5358
|
+
CREATE TABLE activity_interactions (
|
|
5359
|
+
project_id TEXT NOT NULL,
|
|
5360
|
+
visit_id TEXT NOT NULL,
|
|
5361
|
+
sequence INTEGER NOT NULL CHECK (sequence > 0),
|
|
5362
|
+
id TEXT NOT NULL,
|
|
5363
|
+
name TEXT NOT NULL CHECK (length(name) BETWEEN 1 AND 100),
|
|
5364
|
+
route TEXT NOT NULL,
|
|
5365
|
+
received_at TEXT NOT NULL,
|
|
5366
|
+
PRIMARY KEY (project_id, visit_id, sequence),
|
|
5367
|
+
FOREIGN KEY (project_id, visit_id) REFERENCES activity_visits (project_id, id) ON DELETE CASCADE
|
|
5368
|
+
);
|
|
5369
|
+
|
|
5370
|
+
-- Finds a retried interaction by the id its browser chose.
|
|
5371
|
+
CREATE INDEX idx_activity_interactions_id ON activity_interactions (project_id, id);
|
|
5372
|
+
`;
|
|
5373
|
+
|
|
5169
5374
|
// src/migrations.ts
|
|
5170
5375
|
var MIGRATIONS_TABLE_SQL = `
|
|
5171
5376
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -5274,7 +5479,12 @@ var sqliteStorageMigrations = defineMigrations({
|
|
|
5274
5479
|
sqliteSql("058-file-download-grants", _058_file_download_grants_default),
|
|
5275
5480
|
sqliteSql("059-drained-source-versions", _059_drained_source_versions_default),
|
|
5276
5481
|
sqliteSql("060-terminal-action-runs", _060_terminal_action_runs_default),
|
|
5277
|
-
sqliteSql("061-drop-auth-audience", _061_drop_auth_audience_default)
|
|
5482
|
+
sqliteSql("061-drop-auth-audience", _061_drop_auth_audience_default),
|
|
5483
|
+
sqliteSql("062-artifacts", _062_artifacts_default),
|
|
5484
|
+
sqliteSql("063-drop-output-diagnostics", _063_drop_output_diagnostics_default),
|
|
5485
|
+
sqliteSql("064-activity", _064_activity_default),
|
|
5486
|
+
sqliteSql("065-activity-timeline", _065_activity_timeline_default),
|
|
5487
|
+
sqliteSql("066-activity-interactions", _066_activity_interactions_default)
|
|
5278
5488
|
]
|
|
5279
5489
|
});
|
|
5280
5490
|
function sqliteStoragePath(basePath) {
|
|
@@ -5674,6 +5884,23 @@ class SqliteActionRunStorage {
|
|
|
5674
5884
|
const row = this.db.query("SELECT * FROM action_runs WHERE project_id = ? AND id = ?").get(params.projectId, params.id);
|
|
5675
5885
|
return row ? rowToActionRunRecord(row) : null;
|
|
5676
5886
|
}
|
|
5887
|
+
async getByExecutionIds(params) {
|
|
5888
|
+
const executionIds = [...new Set(params.executionIds)];
|
|
5889
|
+
if (executionIds.length === 0) {
|
|
5890
|
+
return [];
|
|
5891
|
+
}
|
|
5892
|
+
const rows = this.db.query(`
|
|
5893
|
+
SELECT *
|
|
5894
|
+
FROM action_runs
|
|
5895
|
+
WHERE project_id = ?
|
|
5896
|
+
AND execution_id IN (SELECT value FROM json_each(?))
|
|
5897
|
+
`).all(params.projectId, JSON.stringify(executionIds));
|
|
5898
|
+
const byExecution = new Map(rows.map((row) => [row.execution_id, row]));
|
|
5899
|
+
return executionIds.flatMap((executionId) => {
|
|
5900
|
+
const row = byExecution.get(executionId);
|
|
5901
|
+
return row ? [rowToActionRunRecord(row)] : [];
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5677
5904
|
async list(input) {
|
|
5678
5905
|
if (input.statuses && input.statuses.length === 0 || input.actionIds?.length === 0) {
|
|
5679
5906
|
return {
|
|
@@ -5845,6 +6072,342 @@ function rowToActionSubject(row) {
|
|
|
5845
6072
|
};
|
|
5846
6073
|
}
|
|
5847
6074
|
|
|
6075
|
+
// src/activity-storage.ts
|
|
6076
|
+
import {
|
|
6077
|
+
ACTIVITY_MAX_VISIT_MS,
|
|
6078
|
+
activityActor,
|
|
6079
|
+
activityCalendarDays,
|
|
6080
|
+
parseActivityAttribution,
|
|
6081
|
+
planActivityAppend,
|
|
6082
|
+
serializeActivityAttribution,
|
|
6083
|
+
validateActivityAppend
|
|
6084
|
+
} from "@sixb/core/internal/storage";
|
|
6085
|
+
var VISIT_COLUMNS = `
|
|
6086
|
+
v.id, v.actor_type, v.user_id, v.grant_id, v.started_at, v.last_seen_at, v.page_views,
|
|
6087
|
+
v.interactions, v.attribution
|
|
6088
|
+
`;
|
|
6089
|
+
var NO_CURSOR = { at: "9999-12-31T23:59:59.999Z", id: "" };
|
|
6090
|
+
|
|
6091
|
+
class SqliteActivityStorage {
|
|
6092
|
+
db;
|
|
6093
|
+
constructor(connection) {
|
|
6094
|
+
this.db = connection.db;
|
|
6095
|
+
}
|
|
6096
|
+
async append(input) {
|
|
6097
|
+
validateActivityAppend(input);
|
|
6098
|
+
return runImmediateTransaction(this.db, () => {
|
|
6099
|
+
const plan = planActivityAppend(input, this.source(input), this.storedEvents(input));
|
|
6100
|
+
if (plan.status !== "append") {
|
|
6101
|
+
return { status: plan.status === "duplicate" ? "accepted" : "throttled", accepted: 0 };
|
|
6102
|
+
}
|
|
6103
|
+
const { state } = plan;
|
|
6104
|
+
const lastSeenAt = iso(state.lastSeenAt);
|
|
6105
|
+
if (plan.newVisit) {
|
|
6106
|
+
this.run(`
|
|
6107
|
+
INSERT INTO activity_visits (
|
|
6108
|
+
project_id, id, actor_type, user_id, grant_id, session_id,
|
|
6109
|
+
started_at, last_seen_at, page_views, interactions, attribution
|
|
6110
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6111
|
+
`, input.projectId, state.visitId, input.actor.type, input.actor.type === "user" ? input.actor.userId : null, input.actor.type === "share" ? input.actor.grantId : null, input.sessionId, lastSeenAt, lastSeenAt, plan.pageViews.length, plan.interactions.length, plan.newVisit.attribution === null ? null : serializeActivityAttribution(plan.newVisit.attribution));
|
|
6112
|
+
} else {
|
|
6113
|
+
this.run(`
|
|
6114
|
+
UPDATE activity_visits
|
|
6115
|
+
SET
|
|
6116
|
+
last_seen_at = ?,
|
|
6117
|
+
page_views = page_views + ?,
|
|
6118
|
+
interactions = interactions + ?
|
|
6119
|
+
WHERE project_id = ? AND id = ?
|
|
6120
|
+
`, lastSeenAt, plan.pageViews.length, plan.interactions.length, input.projectId, state.visitId);
|
|
6121
|
+
}
|
|
6122
|
+
for (const pageView of plan.pageViews) {
|
|
6123
|
+
this.run(`
|
|
6124
|
+
INSERT INTO activity_page_views (
|
|
6125
|
+
project_id, visit_id, sequence, id, route, received_at, attribution
|
|
6126
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6127
|
+
`, input.projectId, pageView.visitId, pageView.sequence, pageView.id, pageView.route, pageView.receivedAt.toISOString(), serializeActivityAttribution(pageView.attribution));
|
|
6128
|
+
}
|
|
6129
|
+
for (const interaction of plan.interactions) {
|
|
6130
|
+
this.run(`
|
|
6131
|
+
INSERT INTO activity_interactions (
|
|
6132
|
+
project_id, visit_id, sequence, id, name, route, received_at
|
|
6133
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6134
|
+
`, input.projectId, interaction.visitId, interaction.sequence, interaction.id, interaction.name, interaction.route, interaction.receivedAt.toISOString());
|
|
6135
|
+
}
|
|
6136
|
+
this.run(`
|
|
6137
|
+
INSERT INTO activity_sources (
|
|
6138
|
+
project_id, actor_type, session_id, visit_id, last_seen_at, sequence,
|
|
6139
|
+
window_start, window_count
|
|
6140
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
6141
|
+
ON CONFLICT (project_id, actor_type, session_id) DO UPDATE SET
|
|
6142
|
+
visit_id = excluded.visit_id,
|
|
6143
|
+
last_seen_at = excluded.last_seen_at,
|
|
6144
|
+
sequence = excluded.sequence,
|
|
6145
|
+
window_start = excluded.window_start,
|
|
6146
|
+
window_count = excluded.window_count
|
|
6147
|
+
`, input.projectId, input.actor.type, input.sessionId, state.visitId, lastSeenAt, state.sequence, iso(state.windowStart), state.windowCount);
|
|
6148
|
+
return { status: "accepted", accepted: plan.accepted };
|
|
6149
|
+
});
|
|
6150
|
+
}
|
|
6151
|
+
async list(input) {
|
|
6152
|
+
const period = overlapping(input);
|
|
6153
|
+
const before = cursorOf(input.before);
|
|
6154
|
+
const rows = this.all(`
|
|
6155
|
+
SELECT ${VISIT_COLUMNS}
|
|
6156
|
+
FROM activity_visits v
|
|
6157
|
+
WHERE ${period.where}
|
|
6158
|
+
AND (v.last_seen_at < ? OR (v.last_seen_at = ? AND v.id < ?))
|
|
6159
|
+
ORDER BY v.last_seen_at DESC, v.id DESC
|
|
6160
|
+
LIMIT ?
|
|
6161
|
+
`, ...period.params, before.at, before.at, before.id, input.limit + 1);
|
|
6162
|
+
return {
|
|
6163
|
+
visits: rows.slice(0, input.limit).map(visitFromRow),
|
|
6164
|
+
hasMore: rows.length > input.limit
|
|
6165
|
+
};
|
|
6166
|
+
}
|
|
6167
|
+
async users(input) {
|
|
6168
|
+
const period = overlapping(input);
|
|
6169
|
+
const before = cursorOf(input.before);
|
|
6170
|
+
const rows = this.all(`
|
|
6171
|
+
SELECT
|
|
6172
|
+
v.user_id,
|
|
6173
|
+
MAX(v.last_seen_at) AS last_seen_at,
|
|
6174
|
+
COUNT(DISTINCT v.id) AS visits,
|
|
6175
|
+
COUNT(p.id) AS page_views
|
|
6176
|
+
FROM activity_visits v
|
|
6177
|
+
LEFT JOIN activity_page_views p
|
|
6178
|
+
ON p.project_id = v.project_id
|
|
6179
|
+
AND p.visit_id = v.id
|
|
6180
|
+
AND p.received_at >= ?
|
|
6181
|
+
AND p.received_at < ?
|
|
6182
|
+
WHERE ${period.where} AND v.actor_type = 'user'
|
|
6183
|
+
GROUP BY v.user_id
|
|
6184
|
+
HAVING MAX(v.last_seen_at) < ? OR (MAX(v.last_seen_at) = ? AND v.user_id < ?)
|
|
6185
|
+
ORDER BY last_seen_at DESC, v.user_id DESC
|
|
6186
|
+
LIMIT ?
|
|
6187
|
+
`, input.from.toISOString(), input.to.toISOString(), ...period.params, before.at, before.at, before.id, input.limit + 1);
|
|
6188
|
+
return {
|
|
6189
|
+
users: rows.slice(0, input.limit).map((row) => ({
|
|
6190
|
+
userId: row.user_id,
|
|
6191
|
+
lastSeenAt: new Date(row.last_seen_at),
|
|
6192
|
+
visits: Number(row.visits),
|
|
6193
|
+
pageViews: Number(row.page_views)
|
|
6194
|
+
})),
|
|
6195
|
+
hasMore: rows.length > input.limit
|
|
6196
|
+
};
|
|
6197
|
+
}
|
|
6198
|
+
async summarize(input) {
|
|
6199
|
+
const period = overlapping(input);
|
|
6200
|
+
const [row] = this.all(`
|
|
6201
|
+
SELECT
|
|
6202
|
+
COUNT(DISTINCT v.user_id) AS users,
|
|
6203
|
+
COUNT(DISTINCT v.id) AS visits,
|
|
6204
|
+
COUNT(DISTINCT CASE WHEN v.actor_type = 'share' THEN v.id END) AS shared_visits,
|
|
6205
|
+
COUNT(p.id) AS page_views
|
|
6206
|
+
FROM activity_visits v
|
|
6207
|
+
LEFT JOIN activity_page_views p
|
|
6208
|
+
ON p.project_id = v.project_id
|
|
6209
|
+
AND p.visit_id = v.id
|
|
6210
|
+
AND p.received_at >= ?
|
|
6211
|
+
AND p.received_at < ?
|
|
6212
|
+
WHERE ${period.where}
|
|
6213
|
+
`, input.from.toISOString(), input.to.toISOString(), ...period.params);
|
|
6214
|
+
return {
|
|
6215
|
+
users: Number(row?.users ?? 0),
|
|
6216
|
+
visits: Number(row?.visits ?? 0),
|
|
6217
|
+
sharedVisits: Number(row?.shared_visits ?? 0),
|
|
6218
|
+
pageViews: Number(row?.page_views ?? 0)
|
|
6219
|
+
};
|
|
6220
|
+
}
|
|
6221
|
+
async calendar(input) {
|
|
6222
|
+
const period = overlapping(input);
|
|
6223
|
+
const visits = this.all(`
|
|
6224
|
+
SELECT v.started_at, v.last_seen_at
|
|
6225
|
+
FROM activity_visits v
|
|
6226
|
+
WHERE ${period.where}
|
|
6227
|
+
`, ...period.params);
|
|
6228
|
+
const days = this.all(`
|
|
6229
|
+
SELECT substr(p.received_at, 1, 10) AS day, COUNT(*) AS page_views
|
|
6230
|
+
FROM activity_visits v
|
|
6231
|
+
JOIN activity_page_views p ON p.project_id = v.project_id AND p.visit_id = v.id
|
|
6232
|
+
WHERE ${period.where}
|
|
6233
|
+
AND p.received_at >= ?
|
|
6234
|
+
AND p.received_at < ?
|
|
6235
|
+
GROUP BY day
|
|
6236
|
+
`, ...period.params, input.from.toISOString(), input.to.toISOString());
|
|
6237
|
+
return activityCalendarDays(input, visits.map((visit) => ({
|
|
6238
|
+
startedAt: new Date(visit.started_at),
|
|
6239
|
+
lastSeenAt: new Date(visit.last_seen_at)
|
|
6240
|
+
})), new Map(days.map((row) => [row.day, Number(row.page_views)])));
|
|
6241
|
+
}
|
|
6242
|
+
async read(input) {
|
|
6243
|
+
const [visit] = this.all(`
|
|
6244
|
+
SELECT ${VISIT_COLUMNS}, v.session_id
|
|
6245
|
+
FROM activity_visits v
|
|
6246
|
+
WHERE v.project_id = ? AND v.id = ?
|
|
6247
|
+
`, input.projectId, input.id);
|
|
6248
|
+
if (!visit) {
|
|
6249
|
+
return null;
|
|
6250
|
+
}
|
|
6251
|
+
const rows = this.all(`
|
|
6252
|
+
SELECT id, visit_id, sequence, route, NULL AS name, received_at
|
|
6253
|
+
FROM activity_page_views
|
|
6254
|
+
WHERE project_id = ? AND visit_id = ?
|
|
6255
|
+
UNION ALL
|
|
6256
|
+
SELECT id, visit_id, sequence, route, name, received_at
|
|
6257
|
+
FROM activity_interactions
|
|
6258
|
+
WHERE project_id = ? AND visit_id = ?
|
|
6259
|
+
ORDER BY sequence
|
|
6260
|
+
LIMIT ?
|
|
6261
|
+
`, input.projectId, input.id, input.projectId, input.id, input.limit + 1);
|
|
6262
|
+
const pageViews = [];
|
|
6263
|
+
const interactions = [];
|
|
6264
|
+
for (const row of rows.slice(0, input.limit)) {
|
|
6265
|
+
if (row.name === null) {
|
|
6266
|
+
pageViews.push(pageViewFromRow(row));
|
|
6267
|
+
} else {
|
|
6268
|
+
interactions.push({ ...pageViewFromRow(row), name: row.name });
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
6271
|
+
return {
|
|
6272
|
+
visit: visitFromRow(visit),
|
|
6273
|
+
sessionId: visit.session_id,
|
|
6274
|
+
pageViews,
|
|
6275
|
+
interactions,
|
|
6276
|
+
hasMore: rows.length > input.limit
|
|
6277
|
+
};
|
|
6278
|
+
}
|
|
6279
|
+
async sessionVisits(input) {
|
|
6280
|
+
if (input.sessionIds.length === 0) {
|
|
6281
|
+
return [];
|
|
6282
|
+
}
|
|
6283
|
+
const rows = this.all(`
|
|
6284
|
+
SELECT *
|
|
6285
|
+
FROM (
|
|
6286
|
+
SELECT
|
|
6287
|
+
${VISIT_COLUMNS},
|
|
6288
|
+
v.session_id,
|
|
6289
|
+
ROW_NUMBER() OVER (
|
|
6290
|
+
PARTITION BY v.session_id ORDER BY v.started_at DESC, v.id DESC
|
|
6291
|
+
) AS position,
|
|
6292
|
+
COUNT(*) OVER (PARTITION BY v.session_id) AS total
|
|
6293
|
+
FROM activity_visits v
|
|
6294
|
+
WHERE v.project_id = ?
|
|
6295
|
+
AND v.actor_type = 'user'
|
|
6296
|
+
AND v.session_id IN (SELECT value FROM json_each(?))
|
|
6297
|
+
AND v.user_id = ?
|
|
6298
|
+
)
|
|
6299
|
+
WHERE position <= ?
|
|
6300
|
+
ORDER BY session_id, position
|
|
6301
|
+
`, input.projectId, JSON.stringify(input.sessionIds), input.userId, input.limit);
|
|
6302
|
+
const bySession = new Map;
|
|
6303
|
+
for (const row of rows) {
|
|
6304
|
+
const session = bySession.get(row.session_id) ?? { visits: Number(row.total), latest: [] };
|
|
6305
|
+
session.latest.push(visitFromRow(row));
|
|
6306
|
+
bySession.set(row.session_id, session);
|
|
6307
|
+
}
|
|
6308
|
+
return [...bySession].map(([sessionId, session]) => ({ sessionId, ...session }));
|
|
6309
|
+
}
|
|
6310
|
+
source(input) {
|
|
6311
|
+
const [row] = this.all(`
|
|
6312
|
+
SELECT
|
|
6313
|
+
s.visit_id, v.started_at AS visit_started_at, s.last_seen_at, s.sequence,
|
|
6314
|
+
s.window_start, s.window_count
|
|
6315
|
+
FROM activity_sources s
|
|
6316
|
+
LEFT JOIN activity_visits v ON v.project_id = s.project_id AND v.id = s.visit_id
|
|
6317
|
+
WHERE s.project_id = ? AND s.actor_type = ? AND s.session_id = ?
|
|
6318
|
+
`, input.projectId, input.actor.type, input.sessionId);
|
|
6319
|
+
if (!row) {
|
|
6320
|
+
return;
|
|
6321
|
+
}
|
|
6322
|
+
return {
|
|
6323
|
+
visitId: row.visit_id,
|
|
6324
|
+
visitStartedAt: row.visit_started_at === null ? null : Date.parse(row.visit_started_at),
|
|
6325
|
+
lastSeenAt: Date.parse(row.last_seen_at),
|
|
6326
|
+
sequence: Number(row.sequence),
|
|
6327
|
+
windowStart: Date.parse(row.window_start),
|
|
6328
|
+
windowCount: Number(row.window_count)
|
|
6329
|
+
};
|
|
6330
|
+
}
|
|
6331
|
+
storedEvents(input) {
|
|
6332
|
+
const ids = JSON.stringify(input.events.map((event) => event.id));
|
|
6333
|
+
const rows = this.all(`
|
|
6334
|
+
SELECT p.id, p.route, NULL AS name, p.attribution
|
|
6335
|
+
FROM activity_page_views p
|
|
6336
|
+
JOIN activity_visits v ON v.project_id = p.project_id AND v.id = p.visit_id
|
|
6337
|
+
WHERE p.project_id = ?
|
|
6338
|
+
AND p.id IN (SELECT value FROM json_each(?))
|
|
6339
|
+
AND v.actor_type = ?
|
|
6340
|
+
AND v.session_id = ?
|
|
6341
|
+
UNION ALL
|
|
6342
|
+
SELECT i.id, i.route, i.name, NULL AS attribution
|
|
6343
|
+
FROM activity_interactions i
|
|
6344
|
+
JOIN activity_visits v ON v.project_id = i.project_id AND v.id = i.visit_id
|
|
6345
|
+
WHERE i.project_id = ?
|
|
6346
|
+
AND i.id IN (SELECT value FROM json_each(?))
|
|
6347
|
+
AND v.actor_type = ?
|
|
6348
|
+
AND v.session_id = ?
|
|
6349
|
+
`, input.projectId, ids, input.actor.type, input.sessionId, input.projectId, ids, input.actor.type, input.sessionId);
|
|
6350
|
+
return rows.map((row) => {
|
|
6351
|
+
if (row.name !== null) {
|
|
6352
|
+
return { id: row.id, route: row.route, name: row.name };
|
|
6353
|
+
}
|
|
6354
|
+
const attribution = parseActivityAttribution(row.attribution);
|
|
6355
|
+
return { id: row.id, route: row.route, ...attribution ? { attribution } : {} };
|
|
6356
|
+
});
|
|
6357
|
+
}
|
|
6358
|
+
run(sql, ...params) {
|
|
6359
|
+
this.db.query(sql).run(...params);
|
|
6360
|
+
}
|
|
6361
|
+
all(sql, ...params) {
|
|
6362
|
+
return this.db.query(sql).all(...params);
|
|
6363
|
+
}
|
|
6364
|
+
}
|
|
6365
|
+
function overlapping(input) {
|
|
6366
|
+
const conditions = [
|
|
6367
|
+
"v.project_id = ?",
|
|
6368
|
+
"v.started_at >= ?",
|
|
6369
|
+
"v.started_at < ?",
|
|
6370
|
+
"v.last_seen_at >= ?"
|
|
6371
|
+
];
|
|
6372
|
+
const params = [
|
|
6373
|
+
input.projectId,
|
|
6374
|
+
new Date(input.from.getTime() - ACTIVITY_MAX_VISIT_MS).toISOString(),
|
|
6375
|
+
input.to.toISOString(),
|
|
6376
|
+
input.from.toISOString()
|
|
6377
|
+
];
|
|
6378
|
+
if (input.userId !== undefined) {
|
|
6379
|
+
conditions.push("v.user_id = ?");
|
|
6380
|
+
params.push(input.userId);
|
|
6381
|
+
}
|
|
6382
|
+
return { where: conditions.join(" AND "), params };
|
|
6383
|
+
}
|
|
6384
|
+
function cursorOf(cursor) {
|
|
6385
|
+
return cursor ? { at: cursor.at.toISOString(), id: cursor.id } : NO_CURSOR;
|
|
6386
|
+
}
|
|
6387
|
+
function visitFromRow(row) {
|
|
6388
|
+
return {
|
|
6389
|
+
id: row.id,
|
|
6390
|
+
actor: activityActor(row.actor_type, row.user_id, row.grant_id),
|
|
6391
|
+
attribution: parseActivityAttribution(row.attribution),
|
|
6392
|
+
startedAt: new Date(row.started_at),
|
|
6393
|
+
lastSeenAt: new Date(row.last_seen_at),
|
|
6394
|
+
pageViews: Number(row.page_views),
|
|
6395
|
+
interactions: Number(row.interactions)
|
|
6396
|
+
};
|
|
6397
|
+
}
|
|
6398
|
+
function pageViewFromRow(row) {
|
|
6399
|
+
return {
|
|
6400
|
+
id: row.id,
|
|
6401
|
+
visitId: row.visit_id,
|
|
6402
|
+
sequence: Number(row.sequence),
|
|
6403
|
+
route: row.route,
|
|
6404
|
+
receivedAt: new Date(row.received_at)
|
|
6405
|
+
};
|
|
6406
|
+
}
|
|
6407
|
+
function iso(epochMs) {
|
|
6408
|
+
return new Date(epochMs).toISOString();
|
|
6409
|
+
}
|
|
6410
|
+
|
|
5848
6411
|
// src/agents/checkpoints.ts
|
|
5849
6412
|
import {
|
|
5850
6413
|
agentContextCheckpointMatchesCreateInput,
|
|
@@ -6627,6 +7190,23 @@ class SqliteAgentThreadStore {
|
|
|
6627
7190
|
const row = this.db.query("SELECT * FROM agent_threads WHERE project_id = ? AND id = ?").get(params.projectId, params.id);
|
|
6628
7191
|
return row ? rowToThreadRecord(row) : null;
|
|
6629
7192
|
}
|
|
7193
|
+
async getByIds(params) {
|
|
7194
|
+
const ids = [...new Set(params.ids)];
|
|
7195
|
+
if (ids.length === 0) {
|
|
7196
|
+
return [];
|
|
7197
|
+
}
|
|
7198
|
+
const rows = this.db.query(`
|
|
7199
|
+
SELECT *
|
|
7200
|
+
FROM agent_threads
|
|
7201
|
+
WHERE project_id = ?
|
|
7202
|
+
AND id IN (SELECT value FROM json_each(?))
|
|
7203
|
+
`).all(params.projectId, JSON.stringify(ids));
|
|
7204
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
7205
|
+
return ids.flatMap((id) => {
|
|
7206
|
+
const row = byId.get(id);
|
|
7207
|
+
return row ? [rowToThreadRecord(row)] : [];
|
|
7208
|
+
});
|
|
7209
|
+
}
|
|
6630
7210
|
async list(input) {
|
|
6631
7211
|
if (input.statuses !== undefined && input.statuses.length === 0) {
|
|
6632
7212
|
return { threads: [], hasMore: false, total: 0 };
|
|
@@ -8065,6 +8645,185 @@ function isConstraintError(error) {
|
|
|
8065
8645
|
return error instanceof Error && /constraint/i.test(error.message);
|
|
8066
8646
|
}
|
|
8067
8647
|
|
|
8648
|
+
// src/artifact-storage.ts
|
|
8649
|
+
import {
|
|
8650
|
+
artifactStorageErrors,
|
|
8651
|
+
parseArtifactFrameGrantRow,
|
|
8652
|
+
parseArtifactRow,
|
|
8653
|
+
parseArtifactVersionRow
|
|
8654
|
+
} from "@sixb/core/internal/storage";
|
|
8655
|
+
var ARTIFACT_COLUMNS = `
|
|
8656
|
+
project_id AS projectId, id, kind, title,
|
|
8657
|
+
owner_principal_type AS ownerPrincipalType, owner_principal_id AS ownerPrincipalId,
|
|
8658
|
+
latest_version AS latestVersion, created_at AS createdAt, updated_at AS updatedAt
|
|
8659
|
+
`;
|
|
8660
|
+
var VERSION_COLUMNS = `
|
|
8661
|
+
project_id AS projectId, artifact_id AS artifactId, version, title, entry, files, outline, refs,
|
|
8662
|
+
author_principal_type AS authorPrincipalType, author_principal_id AS authorPrincipalId,
|
|
8663
|
+
origin_thread_id AS originThreadId, origin_run_id AS originRunId, created_at AS createdAt
|
|
8664
|
+
`;
|
|
8665
|
+
var FRAME_GRANT_COLUMNS = `
|
|
8666
|
+
project_id AS projectId, token_hash AS tokenHash, artifact_id AS artifactId, version, targets,
|
|
8667
|
+
created_at AS createdAt, expires_at AS expiresAt
|
|
8668
|
+
`;
|
|
8669
|
+
|
|
8670
|
+
class SqliteArtifactStorage {
|
|
8671
|
+
db;
|
|
8672
|
+
constructor(connection) {
|
|
8673
|
+
this.db = connection.db;
|
|
8674
|
+
}
|
|
8675
|
+
async create(input) {
|
|
8676
|
+
return runImmediateTransaction(this.db, () => {
|
|
8677
|
+
const createdAt = input.version.createdAt.toISOString();
|
|
8678
|
+
const artifact = this.db.query(`INSERT INTO artifacts (
|
|
8679
|
+
project_id, id, kind, title, owner_principal_type, owner_principal_id,
|
|
8680
|
+
latest_version, next_version, created_at, updated_at
|
|
8681
|
+
) VALUES (?, ?, ?, ?, ?, ?, 1, 2, ?, ?)
|
|
8682
|
+
ON CONFLICT (project_id, id) DO NOTHING
|
|
8683
|
+
RETURNING ${ARTIFACT_COLUMNS}`).get(input.projectId, input.id, input.kind, input.version.title, input.owner.type, input.owner.id, createdAt, createdAt);
|
|
8684
|
+
if (!artifact)
|
|
8685
|
+
throw artifactStorageErrors.exists(input.id);
|
|
8686
|
+
return {
|
|
8687
|
+
artifact: parseArtifactRow(artifact),
|
|
8688
|
+
version: this.insertVersion(input.projectId, input.id, 1, input.version)
|
|
8689
|
+
};
|
|
8690
|
+
});
|
|
8691
|
+
}
|
|
8692
|
+
async publish(input) {
|
|
8693
|
+
return runImmediateTransaction(this.db, () => {
|
|
8694
|
+
const current = this.db.query("SELECT kind, next_version AS nextVersion FROM artifacts WHERE project_id = ? AND id = ?").get(input.projectId, input.artifactId);
|
|
8695
|
+
if (!current)
|
|
8696
|
+
throw artifactStorageErrors.notFound(input.artifactId);
|
|
8697
|
+
if (current.kind !== input.kind) {
|
|
8698
|
+
throw artifactStorageErrors.kindMismatch(input.artifactId, current.kind, input.kind);
|
|
8699
|
+
}
|
|
8700
|
+
const version = this.insertVersion(input.projectId, input.artifactId, current.nextVersion, input.version);
|
|
8701
|
+
const artifact = this.db.query(`UPDATE artifacts
|
|
8702
|
+
SET title = ?, latest_version = ?, next_version = ?, updated_at = ?
|
|
8703
|
+
WHERE project_id = ? AND id = ?
|
|
8704
|
+
RETURNING ${ARTIFACT_COLUMNS}`).get(input.version.title, version.version, version.version + 1, input.version.createdAt.toISOString(), input.projectId, input.artifactId);
|
|
8705
|
+
return { artifact: parseArtifactRow(artifact), version };
|
|
8706
|
+
});
|
|
8707
|
+
}
|
|
8708
|
+
async get(input) {
|
|
8709
|
+
const row = this.db.query(`SELECT ${ARTIFACT_COLUMNS} FROM artifacts WHERE project_id = ? AND id = ?`).get(input.projectId, input.id);
|
|
8710
|
+
return row ? parseArtifactRow(row) : null;
|
|
8711
|
+
}
|
|
8712
|
+
async list(input) {
|
|
8713
|
+
const where = ["a.project_id = ?"];
|
|
8714
|
+
const params = [input.projectId];
|
|
8715
|
+
if (input.owner) {
|
|
8716
|
+
where.push("a.owner_principal_type = ? AND a.owner_principal_id = ?");
|
|
8717
|
+
params.push(input.owner.type, input.owner.id);
|
|
8718
|
+
}
|
|
8719
|
+
if (input.originThreadId !== undefined) {
|
|
8720
|
+
where.push(`EXISTS (
|
|
8721
|
+
SELECT 1 FROM artifact_versions v
|
|
8722
|
+
WHERE v.project_id = a.project_id AND v.artifact_id = a.id AND v.origin_thread_id = ?
|
|
8723
|
+
)`);
|
|
8724
|
+
params.push(input.originThreadId);
|
|
8725
|
+
}
|
|
8726
|
+
if (input.kind !== undefined) {
|
|
8727
|
+
where.push("a.kind = ?");
|
|
8728
|
+
params.push(input.kind);
|
|
8729
|
+
}
|
|
8730
|
+
const clause = where.join(" AND ");
|
|
8731
|
+
const { total } = this.db.query(`SELECT COUNT(*) AS total FROM artifacts a WHERE ${clause}`).get(...params);
|
|
8732
|
+
const offset = input.offset ?? 0;
|
|
8733
|
+
const rows = this.db.query(`SELECT ${ARTIFACT_COLUMNS} FROM artifacts a WHERE ${clause}
|
|
8734
|
+
ORDER BY a.updated_at DESC, a.id ASC LIMIT ? OFFSET ?`).all(...params, input.limit ?? -1, offset);
|
|
8735
|
+
return {
|
|
8736
|
+
artifacts: rows.map(parseArtifactRow),
|
|
8737
|
+
hasMore: offset + rows.length < total,
|
|
8738
|
+
total
|
|
8739
|
+
};
|
|
8740
|
+
}
|
|
8741
|
+
async getVersion(input) {
|
|
8742
|
+
const row = this.db.query(`SELECT ${VERSION_COLUMNS} FROM artifact_versions
|
|
8743
|
+
WHERE project_id = ? AND artifact_id = ? AND version = ?`).get(input.projectId, input.artifactId, input.version);
|
|
8744
|
+
return row ? parseArtifactVersionRow(row) : null;
|
|
8745
|
+
}
|
|
8746
|
+
async listVersions(input) {
|
|
8747
|
+
const { total } = this.db.query("SELECT COUNT(*) AS total FROM artifact_versions WHERE project_id = ? AND artifact_id = ?").get(input.projectId, input.artifactId);
|
|
8748
|
+
const offset = input.offset ?? 0;
|
|
8749
|
+
const rows = this.db.query(`SELECT ${VERSION_COLUMNS} FROM artifact_versions
|
|
8750
|
+
WHERE project_id = ? AND artifact_id = ?
|
|
8751
|
+
ORDER BY version DESC LIMIT ? OFFSET ?`).all(input.projectId, input.artifactId, input.limit ?? -1, offset);
|
|
8752
|
+
return {
|
|
8753
|
+
versions: rows.map(parseArtifactVersionRow),
|
|
8754
|
+
hasMore: offset + rows.length < total,
|
|
8755
|
+
total
|
|
8756
|
+
};
|
|
8757
|
+
}
|
|
8758
|
+
async listReferencingVersions(input) {
|
|
8759
|
+
const prefix = `artifact:${input.artifactId}`;
|
|
8760
|
+
const rows = this.db.query(`SELECT ${VERSION_COLUMNS} FROM artifact_versions v
|
|
8761
|
+
WHERE (project_id, artifact_id, version) IN (
|
|
8762
|
+
SELECT project_id, id, latest_version FROM artifacts WHERE project_id = ?
|
|
8763
|
+
) AND EXISTS (
|
|
8764
|
+
SELECT 1 FROM json_each(v.refs) r
|
|
8765
|
+
WHERE substr(json_extract(r.value, '$.address'), 1, ?) = ?
|
|
8766
|
+
AND substr(json_extract(r.value, '$.address'), ? + 1, 1) IN ('', '@', '/', '#')
|
|
8767
|
+
)
|
|
8768
|
+
ORDER BY artifact_id`).all(input.projectId, prefix.length, prefix, prefix.length);
|
|
8769
|
+
return rows.map(parseArtifactVersionRow);
|
|
8770
|
+
}
|
|
8771
|
+
async createFrameGrant(record) {
|
|
8772
|
+
runImmediateTransaction(this.db, () => {
|
|
8773
|
+
const exists = this.db.query("SELECT 1 FROM artifacts WHERE project_id = ? AND id = ?").get(record.projectId, record.artifactId);
|
|
8774
|
+
if (!exists)
|
|
8775
|
+
throw artifactStorageErrors.notFound(record.artifactId);
|
|
8776
|
+
this.db.query(`INSERT INTO artifact_frame_grants
|
|
8777
|
+
(project_id, token_hash, artifact_id, version, targets, created_at, expires_at)
|
|
8778
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(record.projectId, record.tokenHash, record.artifactId, record.version, JSON.stringify(record.targets), record.createdAt.toISOString(), record.expiresAt.toISOString());
|
|
8779
|
+
});
|
|
8780
|
+
}
|
|
8781
|
+
async findFrameGrant(input) {
|
|
8782
|
+
const row = this.db.query(`SELECT ${FRAME_GRANT_COLUMNS} FROM artifact_frame_grants
|
|
8783
|
+
WHERE project_id = ? AND token_hash = ?`).get(input.projectId, input.tokenHash);
|
|
8784
|
+
return row ? parseArtifactFrameGrantRow(row) : null;
|
|
8785
|
+
}
|
|
8786
|
+
async deleteExpiredFrameGrants(input) {
|
|
8787
|
+
return this.db.query(`DELETE FROM artifact_frame_grants WHERE rowid IN (
|
|
8788
|
+
SELECT rowid FROM artifact_frame_grants
|
|
8789
|
+
WHERE project_id = ? AND expires_at < ?
|
|
8790
|
+
ORDER BY expires_at LIMIT ?
|
|
8791
|
+
)`).run(input.projectId, input.expiredBefore.toISOString(), input.limit).changes;
|
|
8792
|
+
}
|
|
8793
|
+
async delete(input) {
|
|
8794
|
+
return this.db.query("DELETE FROM artifacts WHERE project_id = ? AND id = ?").run(input.projectId, input.id).changes > 0;
|
|
8795
|
+
}
|
|
8796
|
+
async deleteVersionsByOrigin(input) {
|
|
8797
|
+
return runImmediateTransaction(this.db, () => {
|
|
8798
|
+
const affected = this.db.query(`SELECT DISTINCT artifact_id AS artifactId FROM artifact_versions
|
|
8799
|
+
WHERE project_id = ? AND origin_run_id = ?`).all(input.projectId, input.runId);
|
|
8800
|
+
const deleted = this.db.query("DELETE FROM artifact_versions WHERE project_id = ? AND origin_run_id = ?").run(input.projectId, input.runId).changes;
|
|
8801
|
+
for (const { artifactId } of affected) {
|
|
8802
|
+
this.repointLatest(input.projectId, artifactId);
|
|
8803
|
+
}
|
|
8804
|
+
return deleted;
|
|
8805
|
+
});
|
|
8806
|
+
}
|
|
8807
|
+
repointLatest(projectId, artifactId) {
|
|
8808
|
+
const latest = this.db.query(`SELECT version, title, created_at AS createdAt FROM artifact_versions
|
|
8809
|
+
WHERE project_id = ? AND artifact_id = ? ORDER BY version DESC LIMIT 1`).get(projectId, artifactId);
|
|
8810
|
+
if (!latest) {
|
|
8811
|
+
this.db.query("DELETE FROM artifacts WHERE project_id = ? AND id = ?").run(projectId, artifactId);
|
|
8812
|
+
return;
|
|
8813
|
+
}
|
|
8814
|
+
this.db.query(`UPDATE artifacts SET title = ?, latest_version = ?, updated_at = ?
|
|
8815
|
+
WHERE project_id = ? AND id = ?`).run(latest.title, latest.version, latest.createdAt, projectId, artifactId);
|
|
8816
|
+
}
|
|
8817
|
+
insertVersion(projectId, artifactId, version, input) {
|
|
8818
|
+
const row = this.db.query(`INSERT INTO artifact_versions (
|
|
8819
|
+
project_id, artifact_id, version, title, entry, files, outline, refs,
|
|
8820
|
+
author_principal_type, author_principal_id, origin_thread_id, origin_run_id, created_at
|
|
8821
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8822
|
+
RETURNING ${VERSION_COLUMNS}`).get(projectId, artifactId, version, input.title, input.entry, JSON.stringify(input.files), JSON.stringify(input.outline), JSON.stringify(input.references), input.author.type, input.author.id, input.origin?.threadId ?? null, input.origin?.runId ?? null, input.createdAt.toISOString());
|
|
8823
|
+
return parseArtifactVersionRow(row);
|
|
8824
|
+
}
|
|
8825
|
+
}
|
|
8826
|
+
|
|
8068
8827
|
// src/auth-storage/auth-storage.ts
|
|
8069
8828
|
import { AuthStorageError as AuthStorageError11 } from "@sixb/core/storage";
|
|
8070
8829
|
|
|
@@ -9409,6 +10168,19 @@ class SqliteAuthSessionStore {
|
|
|
9409
10168
|
`).all(params.projectId, params.userId, toIso(params.now), toIso(params.now));
|
|
9410
10169
|
return rows.map(rowToSessionRecord);
|
|
9411
10170
|
}
|
|
10171
|
+
async listByUserId(params) {
|
|
10172
|
+
const rows = this.db.query(`
|
|
10173
|
+
SELECT *
|
|
10174
|
+
FROM auth_sessions
|
|
10175
|
+
WHERE project_id = ? AND user_id = ? AND created_at <= ?
|
|
10176
|
+
ORDER BY created_at DESC, id DESC
|
|
10177
|
+
LIMIT ? OFFSET ?
|
|
10178
|
+
`).all(params.projectId, params.userId, params.before ? toIso(params.before.createdAt) : "9999-12-31T23:59:59.999Z", params.limit + 1, params.before?.skip ?? 0);
|
|
10179
|
+
return {
|
|
10180
|
+
sessions: rows.slice(0, params.limit).map(rowToSessionRecord),
|
|
10181
|
+
hasMore: rows.length > params.limit
|
|
10182
|
+
};
|
|
10183
|
+
}
|
|
9412
10184
|
async findValidByTokenHash(params) {
|
|
9413
10185
|
const row = getSessionRowById(this.db, params);
|
|
9414
10186
|
if (!row || row.refresh_token_hash !== null || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
|
|
@@ -10167,7 +10939,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10167
10939
|
callback_binding_hash, reauthorization_id, reauthorization_revision,
|
|
10168
10940
|
reauthorization_connection_ids, created_at, expires_at
|
|
10169
10941
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
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,
|
|
10942
|
+
`).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, iso2(record.createdAt), iso2(record.expiresAt));
|
|
10171
10943
|
return true;
|
|
10172
10944
|
} catch (error) {
|
|
10173
10945
|
if (isUniqueConstraintError(error))
|
|
@@ -10258,7 +11030,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10258
11030
|
project_id, connector_id, id, authorization_id, slot, account,
|
|
10259
11031
|
account_id, status, disconnected_at, created_at, updated_at
|
|
10260
11032
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10261
|
-
`).run(record.projectId, record.connectorId, record.id, record.authorizationId, record.slot, json(record.account), record.account.id, record.status, optionalIso(record.disconnectedAt),
|
|
11033
|
+
`).run(record.projectId, record.connectorId, record.id, record.authorizationId, record.slot, json(record.account), record.account.id, record.status, optionalIso(record.disconnectedAt), iso2(record.createdAt), iso2(record.updatedAt));
|
|
10262
11034
|
return true;
|
|
10263
11035
|
} catch (error) {
|
|
10264
11036
|
if (isUniqueConstraintError(error))
|
|
@@ -10310,7 +11082,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10310
11082
|
SET authorization_id = ?, slot = ?, account = ?, account_id = ?,
|
|
10311
11083
|
status = ?, disconnected_at = ?, updated_at = ?
|
|
10312
11084
|
WHERE project_id = ? AND connector_id = ? AND id = ?
|
|
10313
|
-
`).run(record.authorizationId, record.slot, json(record.account), record.account.id, record.status, optionalIso(record.disconnectedAt),
|
|
11085
|
+
`).run(record.authorizationId, record.slot, json(record.account), record.account.id, record.status, optionalIso(record.disconnectedAt), iso2(record.updatedAt), record.projectId, record.connectorId, record.id);
|
|
10314
11086
|
assertChanged(result.changes, "connector connection", record.id);
|
|
10315
11087
|
}
|
|
10316
11088
|
insertRun(record) {
|
|
@@ -10322,7 +11094,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10322
11094
|
expires_at, authorization_id, cleanup_authorization_id, connections, error,
|
|
10323
11095
|
created_at, updated_at, finished_at
|
|
10324
11096
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10325
|
-
`).run(record.projectId, record.connectorId, record.id, ...values.slice(0, -2),
|
|
11097
|
+
`).run(record.projectId, record.connectorId, record.id, ...values.slice(0, -2), iso2(record.createdAt), ...values.slice(-2));
|
|
10326
11098
|
}
|
|
10327
11099
|
insertAuthorizationRow(record) {
|
|
10328
11100
|
const values = authorizationValues(record);
|
|
@@ -10334,7 +11106,7 @@ class SqliteConnectorConnectionPersistence {
|
|
|
10334
11106
|
mutation_expected_connection_ids, staged_credentials, staged_credential_expires_at,
|
|
10335
11107
|
staged_scopes, created_at, updated_at
|
|
10336
11108
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10337
|
-
`).run(record.projectId, record.connectorId, record.id, ...values.slice(0, -1),
|
|
11109
|
+
`).run(record.projectId, record.connectorId, record.id, ...values.slice(0, -1), iso2(record.createdAt), ...values.slice(-1));
|
|
10338
11110
|
}
|
|
10339
11111
|
getById(table, id) {
|
|
10340
11112
|
if (this.scope.connectorId) {
|
|
@@ -10371,13 +11143,13 @@ function authorizationAttemptFromRow(row) {
|
|
|
10371
11143
|
function runValues(record) {
|
|
10372
11144
|
const waitingFor = record.status === "waiting" ? record.waitingFor : null;
|
|
10373
11145
|
const processingId = record.status === "running" ? record.processingId : null;
|
|
10374
|
-
const callbackStartedAt = record.status === "running" ?
|
|
10375
|
-
const expiresAt = record.status === "waiting" || record.status === "running" ?
|
|
11146
|
+
const callbackStartedAt = record.status === "running" ? iso2(record.callbackStartedAt) : null;
|
|
11147
|
+
const expiresAt = record.status === "waiting" || record.status === "running" ? iso2(record.expiresAt) : null;
|
|
10376
11148
|
const authorizationId = "authorizationId" in record ? record.authorizationId ?? null : null;
|
|
10377
11149
|
const cleanupAuthorizationId = record.status === "succeeded" ? record.cleanupAuthorizationId ?? null : null;
|
|
10378
11150
|
const connections = record.status === "succeeded" ? json(record.connections) : null;
|
|
10379
11151
|
const error = record.status === "failed" ? json(record.error) : null;
|
|
10380
|
-
const finishedAt = record.status === "succeeded" || record.status === "failed" || record.status === "cancelled" || record.status === "expired" ?
|
|
11152
|
+
const finishedAt = record.status === "succeeded" || record.status === "failed" || record.status === "cancelled" || record.status === "expired" ? iso2(record.finishedAt) : null;
|
|
10381
11153
|
return [
|
|
10382
11154
|
record.kind,
|
|
10383
11155
|
record.slot,
|
|
@@ -10391,7 +11163,7 @@ function runValues(record) {
|
|
|
10391
11163
|
cleanupAuthorizationId,
|
|
10392
11164
|
connections,
|
|
10393
11165
|
error,
|
|
10394
|
-
|
|
11166
|
+
iso2(record.updatedAt),
|
|
10395
11167
|
finishedAt
|
|
10396
11168
|
];
|
|
10397
11169
|
}
|
|
@@ -10494,7 +11266,7 @@ function authorizationValues(record) {
|
|
|
10494
11266
|
staged ? json(staged.credentials) : null,
|
|
10495
11267
|
optionalIso(staged?.credentialExpiresAt),
|
|
10496
11268
|
staged ? json(staged.scopes) : null,
|
|
10497
|
-
|
|
11269
|
+
iso2(record.updatedAt)
|
|
10498
11270
|
];
|
|
10499
11271
|
}
|
|
10500
11272
|
function authorizationFromRow(row) {
|
|
@@ -10569,7 +11341,7 @@ function json(value) {
|
|
|
10569
11341
|
function parseJson(value) {
|
|
10570
11342
|
return JSON.parse(value);
|
|
10571
11343
|
}
|
|
10572
|
-
function
|
|
11344
|
+
function iso2(value) {
|
|
10573
11345
|
return value.toISOString();
|
|
10574
11346
|
}
|
|
10575
11347
|
function optionalIso(value) {
|
|
@@ -10591,6 +11363,7 @@ function assertChanged(changes, label, id) {
|
|
|
10591
11363
|
|
|
10592
11364
|
// src/execution-storage.ts
|
|
10593
11365
|
import {
|
|
11366
|
+
compareExecutionCreation,
|
|
10594
11367
|
executionRecordFromStorageRow,
|
|
10595
11368
|
executionRecordToStorageRow,
|
|
10596
11369
|
prepareExecutionRecord
|
|
@@ -10657,6 +11430,39 @@ class SqliteExecutionStorage {
|
|
|
10657
11430
|
`).get(params.projectId, params.id);
|
|
10658
11431
|
return row ? sqliteExecutionRecord(row) : null;
|
|
10659
11432
|
}
|
|
11433
|
+
async listBySession(input) {
|
|
11434
|
+
const sessionColumn = input.session.type === "user" ? "authority_session_id" : "authority_delegation_session_id";
|
|
11435
|
+
const rows = this.db.query(`
|
|
11436
|
+
WITH RECURSIVE tree AS (
|
|
11437
|
+
SELECT roots.*, 0 AS depth
|
|
11438
|
+
FROM (
|
|
11439
|
+
SELECT *
|
|
11440
|
+
FROM executions
|
|
11441
|
+
WHERE project_id = ?
|
|
11442
|
+
AND ${sessionColumn} = ?
|
|
11443
|
+
AND parent_execution_id IS NULL
|
|
11444
|
+
AND created_at >= ?
|
|
11445
|
+
AND created_at < ?
|
|
11446
|
+
ORDER BY created_at, id
|
|
11447
|
+
LIMIT ?
|
|
11448
|
+
) roots
|
|
11449
|
+
UNION ALL
|
|
11450
|
+
SELECT child.*, tree.depth + 1
|
|
11451
|
+
FROM tree
|
|
11452
|
+
CROSS JOIN executions child
|
|
11453
|
+
ON child.project_id = tree.project_id
|
|
11454
|
+
AND child.parent_execution_id = tree.id
|
|
11455
|
+
ORDER BY depth, created_at, id
|
|
11456
|
+
LIMIT ?
|
|
11457
|
+
)
|
|
11458
|
+
SELECT * FROM tree
|
|
11459
|
+
`).all(input.projectId, input.session.id, input.from.toISOString(), input.to.toISOString(), input.limit + 1, input.limit + 1);
|
|
11460
|
+
const kept = rows.slice(0, input.limit).map(sqliteExecutionRecord);
|
|
11461
|
+
return {
|
|
11462
|
+
executions: kept.sort(compareExecutionCreation),
|
|
11463
|
+
truncated: rows.length > input.limit
|
|
11464
|
+
};
|
|
11465
|
+
}
|
|
10660
11466
|
}
|
|
10661
11467
|
function sqliteExecutionRecord(row) {
|
|
10662
11468
|
return executionRecordFromStorageRow(toStorageRow(row));
|
|
@@ -15792,6 +16598,26 @@ class SqliteOntologySourceStorage {
|
|
|
15792
16598
|
return row ? sourceRecord(row) : null;
|
|
15793
16599
|
});
|
|
15794
16600
|
}
|
|
16601
|
+
async listActive(input) {
|
|
16602
|
+
return this.runRootOperation(() => {
|
|
16603
|
+
assertNonblank(input.projectId, "Source project id");
|
|
16604
|
+
const rows = this.db.query(`
|
|
16605
|
+
SELECT source_id, dataset_id, dataset_version_id, dataset_version_created_at,
|
|
16606
|
+
projection_revision
|
|
16607
|
+
FROM ontology_sources
|
|
16608
|
+
WHERE project_id = ? AND status = 'active'
|
|
16609
|
+
`).all(input.projectId);
|
|
16610
|
+
return rows.map((row) => ({
|
|
16611
|
+
source: { projectionId: row.source_id },
|
|
16612
|
+
datasetVersion: {
|
|
16613
|
+
datasetId: row.dataset_id,
|
|
16614
|
+
versionId: row.dataset_version_id,
|
|
16615
|
+
createdAt: row.dataset_version_created_at
|
|
16616
|
+
},
|
|
16617
|
+
projectionRevision: row.projection_revision
|
|
16618
|
+
}));
|
|
16619
|
+
});
|
|
16620
|
+
}
|
|
15795
16621
|
async adopt(input) {
|
|
15796
16622
|
return this.runRootOperation(() => {
|
|
15797
16623
|
assertProjectAndSource(input);
|
|
@@ -17356,6 +18182,23 @@ class SqliteShareGrantStorage {
|
|
|
17356
18182
|
const normalized = normalizeGetShareGrantByIdInput(input);
|
|
17357
18183
|
return this.getRow(normalized.projectId, normalized.id);
|
|
17358
18184
|
}
|
|
18185
|
+
async getByIds(input) {
|
|
18186
|
+
const ids = [...new Set(input.ids)];
|
|
18187
|
+
if (ids.length === 0) {
|
|
18188
|
+
return [];
|
|
18189
|
+
}
|
|
18190
|
+
const rows = this.db.query(`
|
|
18191
|
+
SELECT *
|
|
18192
|
+
FROM share_grants
|
|
18193
|
+
WHERE project_id = ?
|
|
18194
|
+
AND id IN (SELECT value FROM json_each(?))
|
|
18195
|
+
`).all(input.projectId, JSON.stringify(ids));
|
|
18196
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
18197
|
+
return ids.flatMap((id) => {
|
|
18198
|
+
const row = byId.get(id);
|
|
18199
|
+
return row ? [rowToRecord(row)] : [];
|
|
18200
|
+
});
|
|
18201
|
+
}
|
|
17359
18202
|
async list(input) {
|
|
17360
18203
|
const normalized = normalizeListShareGrantsInput(input);
|
|
17361
18204
|
const where = ["project_id = ?"];
|
|
@@ -18442,6 +19285,23 @@ class SqliteWorkflowRunStorage {
|
|
|
18442
19285
|
const row = this.db.query("SELECT * FROM workflow_runs WHERE project_id = ? AND id = ?").get(params.projectId, params.id);
|
|
18443
19286
|
return row ? rowToWorkflowRunRecord(row) : null;
|
|
18444
19287
|
}
|
|
19288
|
+
async getByExecutionIds(params) {
|
|
19289
|
+
const executionIds = [...new Set(params.executionIds)];
|
|
19290
|
+
if (executionIds.length === 0) {
|
|
19291
|
+
return [];
|
|
19292
|
+
}
|
|
19293
|
+
const rows = this.db.query(`
|
|
19294
|
+
SELECT *
|
|
19295
|
+
FROM workflow_runs
|
|
19296
|
+
WHERE project_id = ?
|
|
19297
|
+
AND execution_id IN (SELECT value FROM json_each(?))
|
|
19298
|
+
`).all(params.projectId, JSON.stringify(executionIds));
|
|
19299
|
+
const byExecution = new Map(rows.map((row) => [row.execution_id, row]));
|
|
19300
|
+
return executionIds.flatMap((executionId) => {
|
|
19301
|
+
const row = byExecution.get(executionId);
|
|
19302
|
+
return row ? [rowToWorkflowRunRecord(row)] : [];
|
|
19303
|
+
});
|
|
19304
|
+
}
|
|
18445
19305
|
async list(input) {
|
|
18446
19306
|
if (hasEmptyStatuses(input) || input.workflowIds?.length === 0) {
|
|
18447
19307
|
return {
|
|
@@ -18907,6 +19767,7 @@ class SqliteStorage {
|
|
|
18907
19767
|
auth;
|
|
18908
19768
|
executions;
|
|
18909
19769
|
agents;
|
|
19770
|
+
artifacts;
|
|
18910
19771
|
aiUsage;
|
|
18911
19772
|
aiCosts;
|
|
18912
19773
|
aiLimits;
|
|
@@ -18924,6 +19785,7 @@ class SqliteStorage {
|
|
|
18924
19785
|
connectorConnections;
|
|
18925
19786
|
fileUploadSessions;
|
|
18926
19787
|
fileDownloadGrants;
|
|
19788
|
+
activity;
|
|
18927
19789
|
migrators;
|
|
18928
19790
|
connection;
|
|
18929
19791
|
readConnection;
|
|
@@ -18956,6 +19818,7 @@ class SqliteStorage {
|
|
|
18956
19818
|
this.auth = createAuthOperationScope(stores.auth, scope);
|
|
18957
19819
|
this.executions = createOperationScopedFacade(stores.executions, scope);
|
|
18958
19820
|
this.agents = createAgentOperationScope(stores.agents, scope);
|
|
19821
|
+
this.artifacts = createOperationScopedFacade(stores.artifacts, scope);
|
|
18959
19822
|
this.aiUsage = createOperationScopedFacade(stores.aiUsage, scope);
|
|
18960
19823
|
this.aiCosts = createOperationScopedFacade(stores.aiCosts, scope);
|
|
18961
19824
|
this.aiLimits = createOperationScopedFacade(stores.aiLimits, scope);
|
|
@@ -18973,6 +19836,7 @@ class SqliteStorage {
|
|
|
18973
19836
|
this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope);
|
|
18974
19837
|
this.fileUploadSessions = createOperationScopedFacade(stores.fileUploadSessions, scope);
|
|
18975
19838
|
this.fileDownloadGrants = createOperationScopedFacade(stores.fileDownloadGrants, scope);
|
|
19839
|
+
this.activity = createOperationScopedFacade(stores.activity, scope);
|
|
18976
19840
|
this.migrators = options.path ? createSqliteStorageMigrators(options.path) : [];
|
|
18977
19841
|
registerSqliteStorageTestingAdapter(this, {
|
|
18978
19842
|
advanceConnectorConnectionTime: (durationMs) => stores.connectorConnections.advanceTimeForTesting(durationMs),
|
|
@@ -19085,6 +19949,7 @@ function createSqliteStores(connection, options) {
|
|
|
19085
19949
|
auth,
|
|
19086
19950
|
executions,
|
|
19087
19951
|
agents: new SqliteAgentStorage({ connection, executions }),
|
|
19952
|
+
artifacts: new SqliteArtifactStorage(connection),
|
|
19088
19953
|
aiUsage: new SqliteAiUsageStorage({ connection }),
|
|
19089
19954
|
aiCosts: new SqliteAiCostStorage(connection),
|
|
19090
19955
|
aiLimits: new SqliteAiLimitStorage({ connection }),
|
|
@@ -19101,7 +19966,8 @@ function createSqliteStores(connection, options) {
|
|
|
19101
19966
|
shareSessions,
|
|
19102
19967
|
connectorConnections: new SqliteConnectorConnectionStorage(connection),
|
|
19103
19968
|
fileUploadSessions: new SqliteFileUploadSessionStorage(connection),
|
|
19104
|
-
fileDownloadGrants: new SqliteFileDownloadGrantStorage(connection)
|
|
19969
|
+
fileDownloadGrants: new SqliteFileDownloadGrantStorage(connection),
|
|
19970
|
+
activity: new SqliteActivityStorage(connection)
|
|
19105
19971
|
};
|
|
19106
19972
|
}
|
|
19107
19973
|
export {
|
|
@@ -19109,4 +19975,4 @@ export {
|
|
|
19109
19975
|
migrateSqliteStorage
|
|
19110
19976
|
};
|
|
19111
19977
|
|
|
19112
|
-
//# debugId=
|
|
19978
|
+
//# debugId=B9F8223963B8B3F664756E2164756E21
|