@sixb/sqlite 0.1.12 → 0.1.13
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/auth-storage/access-tokens.d.ts +0 -1
- package/dist/auth-storage/access-tokens.d.ts.map +1 -1
- package/dist/auth-storage/auth-storage.d.ts.map +1 -1
- package/dist/auth-storage/device-authorizations.d.ts.map +1 -1
- package/dist/auth-storage/rows.d.ts +6 -3
- package/dist/auth-storage/rows.d.ts.map +1 -1
- package/dist/auth-storage/sessions.d.ts +8 -1
- package/dist/auth-storage/sessions.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/file-upload-session-storage.d.ts +6 -0
- package/dist/file-upload-session-storage.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +388 -78
- package/dist/index.js.map +18 -17
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/storage.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +0 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +2 -1
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/workflow-intervention-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/auth-storage/access-tokens.ts +11 -18
- package/src/auth-storage/auth-storage.ts +5 -7
- package/src/auth-storage/device-authorizations.ts +3 -5
- package/src/auth-storage/rows.ts +17 -7
- package/src/auth-storage/sessions.ts +89 -4
- package/src/auth-storage/shared.ts +9 -3
- package/src/file-upload-session-storage.ts +136 -0
- package/src/index.ts +5 -0
- package/src/migrations/046-workflow-intervention-principals.sql +15 -0
- package/src/migrations/047-ontology-commit-attribution.sql +67 -0
- package/src/migrations/048-file-upload-sessions.sql +35 -0
- package/src/migrations/049-native-sessions.sql +12 -0
- package/src/migrations.ts +12 -0
- package/src/objects/query-compiler.ts +59 -4
- package/src/objects/reader.ts +4 -0
- package/src/objects/storage.ts +1 -0
- package/src/ontology-storage/materializations.ts +16 -59
- package/src/ontology-storage/shared.ts +7 -3
- package/src/workflow-intervention-storage.ts +9 -9
package/dist/index.js
CHANGED
|
@@ -4230,6 +4230,109 @@ var _045_agent_thread_sandbox_state_default = `ALTER TABLE agent_threads ADD COL
|
|
|
4230
4230
|
CHECK (sandbox_state IS NULL OR (json_valid(sandbox_state) AND json_type(sandbox_state) = 'object'));
|
|
4231
4231
|
`;
|
|
4232
4232
|
|
|
4233
|
+
// src/migrations/046-workflow-intervention-principals.sql
|
|
4234
|
+
var _046_workflow_intervention_principals_default = `-- Intervention actors were stored as { principalType, principalId }. Rewrite them to the
|
|
4235
|
+
-- canonical Principal shape { type, id } used by every other stored principal.
|
|
4236
|
+
UPDATE workflow_interventions
|
|
4237
|
+
SET submitted_by = json_object(
|
|
4238
|
+
'type', json_extract(submitted_by, '$.principalType'),
|
|
4239
|
+
'id', json_extract(submitted_by, '$.principalId')
|
|
4240
|
+
)
|
|
4241
|
+
WHERE json_extract(submitted_by, '$.principalType') IS NOT NULL;
|
|
4242
|
+
|
|
4243
|
+
UPDATE workflow_interventions
|
|
4244
|
+
SET cancelled_by = json_object(
|
|
4245
|
+
'type', json_extract(cancelled_by, '$.principalType'),
|
|
4246
|
+
'id', json_extract(cancelled_by, '$.principalId')
|
|
4247
|
+
)
|
|
4248
|
+
WHERE json_extract(cancelled_by, '$.principalType') IS NOT NULL;
|
|
4249
|
+
`;
|
|
4250
|
+
|
|
4251
|
+
// src/migrations/047-ontology-commit-attribution.sql
|
|
4252
|
+
var _047_ontology_commit_attribution_default = `-- Commits and their events name who requested the write and what ran it, replacing the
|
|
4253
|
+
-- authority-only \`actor\`. Both are copied from the commit's execution, which stays canonical and
|
|
4254
|
+
-- is immutable, so the backfill is exact. SQLite cannot add a NOT NULL column without a default;
|
|
4255
|
+
-- every insert supplies \`executor\`, and the UPDATE below replaces the placeholder on every row.
|
|
4256
|
+
ALTER TABLE ontology_commits ADD COLUMN requested_by TEXT
|
|
4257
|
+
CHECK (requested_by IS NULL OR json_valid(requested_by));
|
|
4258
|
+
ALTER TABLE ontology_commits ADD COLUMN executor TEXT NOT NULL DEFAULT '{}'
|
|
4259
|
+
CHECK (json_valid(executor));
|
|
4260
|
+
|
|
4261
|
+
UPDATE ontology_commits SET
|
|
4262
|
+
requested_by = (
|
|
4263
|
+
SELECT CASE
|
|
4264
|
+
WHEN e.requested_by_user_id IS NOT NULL
|
|
4265
|
+
THEN json_object('id', e.requested_by_user_id, 'type', 'user')
|
|
4266
|
+
WHEN e.requested_by_service_account_id IS NOT NULL
|
|
4267
|
+
THEN json_object('id', e.requested_by_service_account_id, 'type', 'serviceAccount')
|
|
4268
|
+
END
|
|
4269
|
+
FROM executions e
|
|
4270
|
+
WHERE e.project_id = ontology_commits.project_id AND e.id = ontology_commits.execution_id
|
|
4271
|
+
),
|
|
4272
|
+
executor = (
|
|
4273
|
+
SELECT CASE e.executor_kind
|
|
4274
|
+
WHEN 'request' THEN json_object('requestId', e.executor_id, 'type', 'request')
|
|
4275
|
+
WHEN 'agent' THEN json_object('runId', e.executor_id, 'type', 'agent')
|
|
4276
|
+
WHEN 'kernel' THEN json_object(
|
|
4277
|
+
'operation',
|
|
4278
|
+
CASE e.authority_kernel_operation
|
|
4279
|
+
WHEN 'ontology.recover'
|
|
4280
|
+
THEN json_object('recoveryId', e.executor_id, 'type', 'ontology.recover')
|
|
4281
|
+
ELSE json_object('indexingId', e.executor_id, 'type', 'ontology.indexVectors')
|
|
4282
|
+
END,
|
|
4283
|
+
'type', 'kernel'
|
|
4284
|
+
)
|
|
4285
|
+
ELSE json_object(
|
|
4286
|
+
'id', e.authority_primitive_id,
|
|
4287
|
+
'kind', e.executor_kind,
|
|
4288
|
+
'runId', e.executor_id,
|
|
4289
|
+
'type', 'primitive'
|
|
4290
|
+
)
|
|
4291
|
+
END
|
|
4292
|
+
FROM executions e
|
|
4293
|
+
WHERE e.project_id = ontology_commits.project_id AND e.id = ontology_commits.execution_id
|
|
4294
|
+
);
|
|
4295
|
+
|
|
4296
|
+
-- Events not yet published would otherwise reach consumers in the retired shape.
|
|
4297
|
+
UPDATE ontology_outbox SET envelope = (
|
|
4298
|
+
SELECT json_remove(
|
|
4299
|
+
CASE
|
|
4300
|
+
WHEN c.requested_by IS NULL
|
|
4301
|
+
THEN json_set(ontology_outbox.envelope, '$.executor', json(c.executor))
|
|
4302
|
+
ELSE json_set(
|
|
4303
|
+
ontology_outbox.envelope,
|
|
4304
|
+
'$.executor', json(c.executor),
|
|
4305
|
+
'$.requestedBy', json(c.requested_by)
|
|
4306
|
+
)
|
|
4307
|
+
END,
|
|
4308
|
+
'$.actor'
|
|
4309
|
+
)
|
|
4310
|
+
FROM ontology_commits c
|
|
4311
|
+
WHERE c.project_id = ontology_outbox.project_id AND c.id = ontology_outbox.commit_id
|
|
4312
|
+
)
|
|
4313
|
+
WHERE EXISTS (
|
|
4314
|
+
SELECT 1 FROM ontology_commits c
|
|
4315
|
+
WHERE c.project_id = ontology_outbox.project_id AND c.id = ontology_outbox.commit_id
|
|
4316
|
+
);
|
|
4317
|
+
|
|
4318
|
+
ALTER TABLE ontology_commits DROP COLUMN actor;
|
|
4319
|
+
`;
|
|
4320
|
+
|
|
4321
|
+
// src/migrations/049-native-sessions.sql
|
|
4322
|
+
var _049_native_sessions_default = `-- Native clients, such as the CLI, hold their session as bearer tokens: a
|
|
4323
|
+
-- short-lived access token, whose hash is \`token_hash\`, and a rotating refresh token. Browser
|
|
4324
|
+
-- sessions leave these columns NULL; \`refresh_token_hash IS NULL\` is what marks a cookie session.
|
|
4325
|
+
ALTER TABLE auth_sessions ADD COLUMN client_name TEXT;
|
|
4326
|
+
ALTER TABLE auth_sessions ADD COLUMN access_expires_at TEXT;
|
|
4327
|
+
ALTER TABLE auth_sessions ADD COLUMN refresh_token_hash TEXT;
|
|
4328
|
+
ALTER TABLE auth_sessions ADD COLUMN previous_refresh_token_hash TEXT;
|
|
4329
|
+
ALTER TABLE auth_sessions ADD COLUMN refreshed_at TEXT;
|
|
4330
|
+
|
|
4331
|
+
-- The device flow now starts a session instead of issuing a personal access token.
|
|
4332
|
+
ALTER TABLE auth_device_authorizations DROP COLUMN token_name;
|
|
4333
|
+
ALTER TABLE auth_device_authorizations DROP COLUMN token_expires_at;
|
|
4334
|
+
`;
|
|
4335
|
+
|
|
4233
4336
|
// src/migrations/037-execution-requester-groups.sql
|
|
4234
4337
|
var _037_execution_requester_groups_default = `ALTER TABLE executions ADD COLUMN requester_group_ids TEXT NOT NULL DEFAULT '[]';
|
|
4235
4338
|
|
|
@@ -4312,6 +4415,44 @@ CREATE INDEX idx_connector_attempts_expiry
|
|
|
4312
4415
|
ON connector_authorization_attempts (project_id, connector_id, expires_at);
|
|
4313
4416
|
`;
|
|
4314
4417
|
|
|
4418
|
+
// src/migrations/048-file-upload-sessions.sql
|
|
4419
|
+
var _048_file_upload_sessions_default = `-- Durable staged-upload sessions, so an upload survives restarts and spans API replicas.
|
|
4420
|
+
-- Timestamps are ISO-8601 UTC text and compare lexicographically.
|
|
4421
|
+
CREATE TABLE file_upload_sessions (
|
|
4422
|
+
id TEXT PRIMARY KEY CHECK (length(trim(id)) > 0),
|
|
4423
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
4424
|
+
owner_principal_type TEXT NOT NULL
|
|
4425
|
+
CHECK (owner_principal_type IN ('user', 'serviceAccount', 'system')),
|
|
4426
|
+
owner_principal_id TEXT NOT NULL CHECK (length(owner_principal_id) > 0),
|
|
4427
|
+
strategy TEXT NOT NULL CHECK (strategy IN ('server', 'direct-put', 'multipart')),
|
|
4428
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'aborted')),
|
|
4429
|
+
file_name TEXT,
|
|
4430
|
+
media_type TEXT,
|
|
4431
|
+
logical_path TEXT,
|
|
4432
|
+
expected_size_bytes INTEGER CHECK (expected_size_bytes IS NULL OR expected_size_bytes >= 0),
|
|
4433
|
+
expected_digest TEXT,
|
|
4434
|
+
provider_upload TEXT CHECK (provider_upload IS NULL OR json_type(provider_upload) = 'object'),
|
|
4435
|
+
signed_parts TEXT NOT NULL CHECK (json_type(signed_parts) = 'array'),
|
|
4436
|
+
file_ref TEXT CHECK (file_ref IS NULL OR json_type(file_ref) = 'object'),
|
|
4437
|
+
created_at TEXT NOT NULL,
|
|
4438
|
+
expires_at TEXT NOT NULL,
|
|
4439
|
+
completed_at TEXT,
|
|
4440
|
+
aborted_at TEXT,
|
|
4441
|
+
-- Derived by core (fileUploadSessionReapAt); NULL while an abandoned upload awaits its abort.
|
|
4442
|
+
reap_at TEXT,
|
|
4443
|
+
CHECK ((status = 'completed') = (completed_at IS NOT NULL)),
|
|
4444
|
+
CHECK ((status = 'aborted') = (aborted_at IS NOT NULL))
|
|
4445
|
+
);
|
|
4446
|
+
|
|
4447
|
+
CREATE INDEX idx_file_upload_sessions_reap
|
|
4448
|
+
ON file_upload_sessions (reap_at)
|
|
4449
|
+
WHERE reap_at IS NOT NULL;
|
|
4450
|
+
|
|
4451
|
+
CREATE INDEX idx_file_upload_sessions_abandoned
|
|
4452
|
+
ON file_upload_sessions (project_id, expires_at)
|
|
4453
|
+
WHERE status = 'pending' AND provider_upload IS NOT NULL;
|
|
4454
|
+
`;
|
|
4455
|
+
|
|
4315
4456
|
// src/migrations.ts
|
|
4316
4457
|
var MIGRATIONS_TABLE_SQL = `
|
|
4317
4458
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -4391,7 +4532,11 @@ var sqliteStorageMigrations = defineMigrations({
|
|
|
4391
4532
|
sqliteSql("042-vector-profiles", _042_vector_profiles_default),
|
|
4392
4533
|
sqliteSql("043-vector-indexing", _043_vector_indexing_default),
|
|
4393
4534
|
sqliteSql("044-vector-batching", _044_vector_batching_default),
|
|
4394
|
-
sqliteSql("045-agent-thread-sandbox-state", _045_agent_thread_sandbox_state_default)
|
|
4535
|
+
sqliteSql("045-agent-thread-sandbox-state", _045_agent_thread_sandbox_state_default),
|
|
4536
|
+
sqliteSql("046-workflow-intervention-principals", _046_workflow_intervention_principals_default),
|
|
4537
|
+
sqliteSql("047-ontology-commit-attribution", _047_ontology_commit_attribution_default),
|
|
4538
|
+
sqliteSql("048-file-upload-sessions", _048_file_upload_sessions_default),
|
|
4539
|
+
sqliteSql("049-native-sessions", _049_native_sessions_default)
|
|
4395
4540
|
]
|
|
4396
4541
|
});
|
|
4397
4542
|
function sqliteStoragePath(basePath) {
|
|
@@ -7345,7 +7490,14 @@ function rowToSessionRecord(row) {
|
|
|
7345
7490
|
revokedAt: row.revoked_at ? new Date(row.revoked_at) : undefined,
|
|
7346
7491
|
lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : undefined,
|
|
7347
7492
|
userAgent: row.user_agent ?? undefined,
|
|
7348
|
-
ipAddress: row.ip_address ?? undefined
|
|
7493
|
+
ipAddress: row.ip_address ?? undefined,
|
|
7494
|
+
bearer: row.refresh_token_hash !== null && row.client_name !== null && row.access_expires_at !== null ? {
|
|
7495
|
+
clientName: row.client_name,
|
|
7496
|
+
accessExpiresAt: new Date(row.access_expires_at),
|
|
7497
|
+
refreshTokenHash: row.refresh_token_hash,
|
|
7498
|
+
previousRefreshTokenHash: row.previous_refresh_token_hash ?? undefined,
|
|
7499
|
+
refreshedAt: row.refreshed_at ? new Date(row.refreshed_at) : undefined
|
|
7500
|
+
} : undefined
|
|
7349
7501
|
};
|
|
7350
7502
|
}
|
|
7351
7503
|
function rowToAccessTokenRecord(row) {
|
|
@@ -7354,8 +7506,7 @@ function rowToAccessTokenRecord(row) {
|
|
|
7354
7506
|
projectId: row.project_id,
|
|
7355
7507
|
name: row.name,
|
|
7356
7508
|
kind: row.kind,
|
|
7357
|
-
|
|
7358
|
-
subjectId: row.subject_id,
|
|
7509
|
+
subject: { type: row.subject_type, id: row.subject_id },
|
|
7359
7510
|
tokenHash: row.token_hash,
|
|
7360
7511
|
groupIds: parseOptionalStringArray(row.group_ids),
|
|
7361
7512
|
createdByPrincipal: row.created_by_principal_type && row.created_by_principal_id ? {
|
|
@@ -7436,8 +7587,6 @@ function rowToDeviceAuthorizationRecord(row) {
|
|
|
7436
7587
|
deviceCodeHash: row.device_code_hash,
|
|
7437
7588
|
userCode: row.user_code,
|
|
7438
7589
|
clientName: row.client_name,
|
|
7439
|
-
tokenName: row.token_name,
|
|
7440
|
-
tokenExpiresAt: new Date(row.token_expires_at),
|
|
7441
7590
|
status: row.status,
|
|
7442
7591
|
approvedUserId: row.approved_user_id ?? undefined,
|
|
7443
7592
|
approvedSessionId: row.approved_session_id ?? undefined,
|
|
@@ -7668,9 +7817,12 @@ function createSession(db, input) {
|
|
|
7668
7817
|
expires_at,
|
|
7669
7818
|
absolute_expires_at,
|
|
7670
7819
|
user_agent,
|
|
7671
|
-
ip_address
|
|
7672
|
-
|
|
7673
|
-
|
|
7820
|
+
ip_address,
|
|
7821
|
+
client_name,
|
|
7822
|
+
access_expires_at,
|
|
7823
|
+
refresh_token_hash
|
|
7824
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7825
|
+
`).run(projectId, id, userId, strategyId, audience, 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);
|
|
7674
7826
|
const session = getSessionById(db, { projectId, id });
|
|
7675
7827
|
if (!session) {
|
|
7676
7828
|
throw new AuthStorageError("missing_session", `[Sixb] Failed to load session '${id}' for project '${projectId}'.`);
|
|
@@ -7818,10 +7970,10 @@ function createAuthAccessToken(db, input) {
|
|
|
7818
7970
|
const id = assertNonEmpty(input.id, "Access token id");
|
|
7819
7971
|
const projectId = assertNonEmpty(input.projectId, "Project id");
|
|
7820
7972
|
const name = assertNonEmpty(input.name, "Access token name");
|
|
7821
|
-
const subjectId = assertNonEmpty(input.
|
|
7973
|
+
const subjectId = assertNonEmpty(input.subject.id, "Access token subject id");
|
|
7822
7974
|
const tokenHash = assertNonEmpty(input.tokenHash, "Access token hash");
|
|
7823
7975
|
assertKindMatchesSubject(input);
|
|
7824
|
-
assertSubjectExists(db, projectId, input.
|
|
7976
|
+
assertSubjectExists(db, projectId, input.subject.type, subjectId);
|
|
7825
7977
|
const groupIds = input.groupIds === undefined ? undefined : normalizeGroupIds(input.groupIds);
|
|
7826
7978
|
try {
|
|
7827
7979
|
db.query(`
|
|
@@ -7840,7 +7992,7 @@ function createAuthAccessToken(db, input) {
|
|
|
7840
7992
|
created_at,
|
|
7841
7993
|
expires_at
|
|
7842
7994
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7843
|
-
`).run(projectId, id, name, input.kind, input.
|
|
7995
|
+
`).run(projectId, id, name, input.kind, input.subject.type, subjectId, tokenHash, serializeOptionalStringArray(groupIds), input.createdByPrincipal?.type ?? null, input.createdByPrincipal?.id ?? null, input.createdBySessionId ?? null, toIso(input.createdAt), toIso(input.expiresAt));
|
|
7844
7996
|
} catch (error) {
|
|
7845
7997
|
mapUniqueConstraintError(error, "duplicate_access_token", `[Sixb] Access token '${id}' already exists for project '${projectId}'.`);
|
|
7846
7998
|
}
|
|
@@ -7871,13 +8023,9 @@ class SqliteAuthAccessTokenStore {
|
|
|
7871
8023
|
whereClauses.push("kind = ?");
|
|
7872
8024
|
args.push(input.kind);
|
|
7873
8025
|
}
|
|
7874
|
-
if (input.
|
|
7875
|
-
whereClauses.push("subject_type = ?");
|
|
7876
|
-
args.push(input.
|
|
7877
|
-
}
|
|
7878
|
-
if (input.subjectId) {
|
|
7879
|
-
whereClauses.push("subject_id = ?");
|
|
7880
|
-
args.push(input.subjectId);
|
|
8026
|
+
if (input.subject) {
|
|
8027
|
+
whereClauses.push("subject_type = ?", "subject_id = ?");
|
|
8028
|
+
args.push(input.subject.type, input.subject.id);
|
|
7881
8029
|
}
|
|
7882
8030
|
if (!input.includeRevoked) {
|
|
7883
8031
|
whereClauses.push("revoked_at IS NULL");
|
|
@@ -7961,10 +8109,10 @@ function assertSubjectExists(db, projectId, subjectType, subjectId) {
|
|
|
7961
8109
|
throw new AuthStorageError2("missing_service_account", `[Sixb] Service account '${subjectId}' not found for project '${projectId}'.`);
|
|
7962
8110
|
}
|
|
7963
8111
|
function assertKindMatchesSubject(input) {
|
|
7964
|
-
if (input.kind === "personal" && input.
|
|
8112
|
+
if (input.kind === "personal" && input.subject.type === "user" || input.kind === "serviceAccount" && input.subject.type === "serviceAccount") {
|
|
7965
8113
|
return;
|
|
7966
8114
|
}
|
|
7967
|
-
throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.
|
|
8115
|
+
throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subject.type}'.`);
|
|
7968
8116
|
}
|
|
7969
8117
|
|
|
7970
8118
|
// src/auth-storage/device-authorizations.ts
|
|
@@ -7984,10 +8132,10 @@ class SqliteAuthDeviceAuthorizationStore {
|
|
|
7984
8132
|
try {
|
|
7985
8133
|
this.db.query(`
|
|
7986
8134
|
INSERT INTO auth_device_authorizations (
|
|
7987
|
-
project_id, id, device_code_hash, user_code, client_name,
|
|
7988
|
-
|
|
7989
|
-
) VALUES (?, ?, ?, ?, ?,
|
|
7990
|
-
`).run(assertNonEmpty(input.projectId, "Project id"), assertNonEmpty(input.id, "Device authorization id"), assertNonEmpty(input.deviceCodeHash, "Device code hash"), assertNonEmpty(input.userCode, "User code"), assertNonEmpty(input.clientName, "Client name"),
|
|
8135
|
+
project_id, id, device_code_hash, user_code, client_name, status, created_at,
|
|
8136
|
+
expires_at
|
|
8137
|
+
) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)
|
|
8138
|
+
`).run(assertNonEmpty(input.projectId, "Project id"), assertNonEmpty(input.id, "Device authorization id"), assertNonEmpty(input.deviceCodeHash, "Device code hash"), assertNonEmpty(input.userCode, "User code"), assertNonEmpty(input.clientName, "Client name"), toIso(input.createdAt), toIso(input.expiresAt));
|
|
7991
8139
|
} catch (error) {
|
|
7992
8140
|
mapUniqueConstraintError(error, "duplicate_device_authorization", `[Sixb] Device authorization '${input.id}' already exists for project '${input.projectId}'.`);
|
|
7993
8141
|
}
|
|
@@ -8653,11 +8801,48 @@ class SqliteAuthSessionStore {
|
|
|
8653
8801
|
}
|
|
8654
8802
|
async findValidByTokenHash(params) {
|
|
8655
8803
|
const row = getSessionRowById(this.db, params);
|
|
8656
|
-
if (!row || row.
|
|
8804
|
+
if (!row || row.refresh_token_hash !== null || row.audience !== params.audience || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
|
|
8657
8805
|
return null;
|
|
8658
8806
|
}
|
|
8659
8807
|
return rowToSessionRecord(row);
|
|
8660
8808
|
}
|
|
8809
|
+
async findValidByAccessTokenHash(params) {
|
|
8810
|
+
const row = getSessionRowById(this.db, params);
|
|
8811
|
+
if (!row || row.access_expires_at === null || row.token_hash !== params.tokenHash || new Date(row.access_expires_at) <= params.now || !isLiveSessionRow(row, params.now)) {
|
|
8812
|
+
return null;
|
|
8813
|
+
}
|
|
8814
|
+
return rowToSessionRecord(row);
|
|
8815
|
+
}
|
|
8816
|
+
async rotateRefreshToken(params) {
|
|
8817
|
+
return runImmediateTransaction(this.db, () => {
|
|
8818
|
+
const row = getSessionRowById(this.db, params);
|
|
8819
|
+
if (!row?.refresh_token_hash || !isLiveSessionRow(row, params.now)) {
|
|
8820
|
+
return { status: "invalid" };
|
|
8821
|
+
}
|
|
8822
|
+
const replacedRecently = row.previous_refresh_token_hash === params.refreshTokenHash && row.refreshed_at !== null && params.now.getTime() - new Date(row.refreshed_at).getTime() <= params.reuseGraceMs;
|
|
8823
|
+
if (row.refresh_token_hash !== params.refreshTokenHash && !replacedRecently) {
|
|
8824
|
+
if (row.previous_refresh_token_hash !== params.refreshTokenHash) {
|
|
8825
|
+
return { status: "invalid" };
|
|
8826
|
+
}
|
|
8827
|
+
this.db.query("UPDATE auth_sessions SET revoked_at = ? WHERE project_id = ? AND id = ?").run(toIso(params.now), params.projectId, params.id);
|
|
8828
|
+
return { status: "reused" };
|
|
8829
|
+
}
|
|
8830
|
+
const expiresAt = toIso(params.next.expiresAt);
|
|
8831
|
+
this.db.query(`
|
|
8832
|
+
UPDATE auth_sessions
|
|
8833
|
+
SET token_hash = ?,
|
|
8834
|
+
access_expires_at = ?,
|
|
8835
|
+
previous_refresh_token_hash = refresh_token_hash,
|
|
8836
|
+
refresh_token_hash = ?,
|
|
8837
|
+
refreshed_at = ?,
|
|
8838
|
+
last_seen_at = ?,
|
|
8839
|
+
expires_at = MAX(expires_at, MIN(?, COALESCE(absolute_expires_at, ?)))
|
|
8840
|
+
WHERE project_id = ? AND id = ?
|
|
8841
|
+
`).run(params.next.tokenHash, toIso(params.next.accessExpiresAt), params.next.refreshTokenHash, toIso(params.now), toIso(params.now), expiresAt, expiresAt, params.projectId, params.id);
|
|
8842
|
+
const session = getSessionById(this.db, params);
|
|
8843
|
+
return session ? { status: "rotated", session } : { status: "invalid" };
|
|
8844
|
+
});
|
|
8845
|
+
}
|
|
8661
8846
|
async renewIfValid(params) {
|
|
8662
8847
|
return runImmediateTransaction(this.db, () => {
|
|
8663
8848
|
const now = toIso(params.now);
|
|
@@ -8673,6 +8858,7 @@ class SqliteAuthSessionStore {
|
|
|
8673
8858
|
AND id = ?
|
|
8674
8859
|
AND audience = ?
|
|
8675
8860
|
AND token_hash = ?
|
|
8861
|
+
AND refresh_token_hash IS NULL
|
|
8676
8862
|
AND revoked_at IS NULL
|
|
8677
8863
|
AND expires_at > ?
|
|
8678
8864
|
AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
|
|
@@ -8718,6 +8904,9 @@ class SqliteAuthSessionStore {
|
|
|
8718
8904
|
});
|
|
8719
8905
|
}
|
|
8720
8906
|
}
|
|
8907
|
+
function isLiveSessionRow(row, now) {
|
|
8908
|
+
return row.revoked_at === null && new Date(row.expires_at) > now && (row.absolute_expires_at === null || new Date(row.absolute_expires_at) > now);
|
|
8909
|
+
}
|
|
8721
8910
|
|
|
8722
8911
|
// src/auth-storage/users.ts
|
|
8723
8912
|
import { AuthStorageError as AuthStorageError10 } from "@sixb/core/storage";
|
|
@@ -8888,7 +9077,7 @@ class SqliteAuthStorage {
|
|
|
8888
9077
|
throw new AuthStorageError11("missing_device_authorization", `[Sixb] Device authorization '${input.id}' not found for project '${input.projectId}'.`);
|
|
8889
9078
|
}
|
|
8890
9079
|
assertCompletableDeviceAuthorization(authorization, input);
|
|
8891
|
-
const
|
|
9080
|
+
const session = createSession(this.db, input.session);
|
|
8892
9081
|
this.db.query(`
|
|
8893
9082
|
UPDATE auth_device_authorizations
|
|
8894
9083
|
SET status = 'consumed', consumed_at = ?
|
|
@@ -8900,7 +9089,7 @@ class SqliteAuthStorage {
|
|
|
8900
9089
|
status: "consumed",
|
|
8901
9090
|
consumedAt: new Date(input.completedAt)
|
|
8902
9091
|
},
|
|
8903
|
-
|
|
9092
|
+
session
|
|
8904
9093
|
};
|
|
8905
9094
|
});
|
|
8906
9095
|
}
|
|
@@ -9341,7 +9530,7 @@ function assertCompletableDeviceAuthorization(authorization, input) {
|
|
|
9341
9530
|
if (authorization.status === "denied") {
|
|
9342
9531
|
throw new AuthStorageError11("device_authorization_denied", "[Sixb] Device authorization was denied.");
|
|
9343
9532
|
}
|
|
9344
|
-
if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.
|
|
9533
|
+
if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.session.projectId !== input.projectId || input.session.userId !== authorization.approvedUserId) {
|
|
9345
9534
|
throw new AuthStorageError11("invalid_device_authorization", "[Sixb] Device authorization is invalid.");
|
|
9346
9535
|
}
|
|
9347
9536
|
}
|
|
@@ -9920,6 +10109,100 @@ function isDuplicateExecutionError(error) {
|
|
|
9920
10109
|
return error instanceof Error && error.message.includes("UNIQUE constraint failed: executions.project_id, executions.id");
|
|
9921
10110
|
}
|
|
9922
10111
|
|
|
10112
|
+
// src/file-upload-session-storage.ts
|
|
10113
|
+
import {
|
|
10114
|
+
DurableFileUploadSessions,
|
|
10115
|
+
fileUploadSessionReapAt,
|
|
10116
|
+
parseFileUploadSessionRow
|
|
10117
|
+
} from "@sixb/core/internal/file-upload-session-storage-provider";
|
|
10118
|
+
class SqliteFileUploadSessionStorage extends DurableFileUploadSessions {
|
|
10119
|
+
constructor(connection) {
|
|
10120
|
+
super(new SqliteFileUploadSessionBackend(connection.db));
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
|
|
10124
|
+
class SqliteFileUploadSessionBackend {
|
|
10125
|
+
db;
|
|
10126
|
+
persistence;
|
|
10127
|
+
constructor(db) {
|
|
10128
|
+
this.db = db;
|
|
10129
|
+
this.persistence = new SqliteFileUploadSessionPersistence(db);
|
|
10130
|
+
}
|
|
10131
|
+
read(run) {
|
|
10132
|
+
return run(this.persistence);
|
|
10133
|
+
}
|
|
10134
|
+
transaction(run) {
|
|
10135
|
+
return runImmediateTransactionAsync(this.db, () => run(this.persistence));
|
|
10136
|
+
}
|
|
10137
|
+
}
|
|
10138
|
+
|
|
10139
|
+
class SqliteFileUploadSessionPersistence {
|
|
10140
|
+
db;
|
|
10141
|
+
constructor(db) {
|
|
10142
|
+
this.db = db;
|
|
10143
|
+
}
|
|
10144
|
+
async now() {
|
|
10145
|
+
const row = this.db.query("SELECT strftime('%Y-%m-%dT%H:%M:%fZ', 'now') AS now").get();
|
|
10146
|
+
return new Date(row.now);
|
|
10147
|
+
}
|
|
10148
|
+
async insert(session) {
|
|
10149
|
+
try {
|
|
10150
|
+
this.db.query(`INSERT INTO file_upload_sessions (
|
|
10151
|
+
id, project_id, owner_principal_type, owner_principal_id, strategy, status, file_name,
|
|
10152
|
+
media_type, logical_path, expected_size_bytes, expected_digest, provider_upload, signed_parts, file_ref,
|
|
10153
|
+
created_at, expires_at, completed_at, aborted_at, reap_at
|
|
10154
|
+
) 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));
|
|
10155
|
+
return true;
|
|
10156
|
+
} catch (error) {
|
|
10157
|
+
if (isUniqueConstraintError2(error))
|
|
10158
|
+
return false;
|
|
10159
|
+
throw error;
|
|
10160
|
+
}
|
|
10161
|
+
}
|
|
10162
|
+
async get(uploadId) {
|
|
10163
|
+
const row = this.db.query(`${SELECT_SESSION} WHERE id = ?`).get(uploadId);
|
|
10164
|
+
return row ? parseFileUploadSessionRow(row) : null;
|
|
10165
|
+
}
|
|
10166
|
+
async update(session) {
|
|
10167
|
+
this.db.query(`UPDATE file_upload_sessions
|
|
10168
|
+
SET status = ?, provider_upload = ?, signed_parts = ?, file_ref = ?, created_at = ?,
|
|
10169
|
+
expires_at = ?, completed_at = ?, aborted_at = ?, reap_at = ?
|
|
10170
|
+
WHERE id = ?`).run(session.status, ...mutableColumns(session), session.id);
|
|
10171
|
+
}
|
|
10172
|
+
async listAbandoned(input) {
|
|
10173
|
+
const rows = this.db.query(`${SELECT_SESSION}
|
|
10174
|
+
WHERE project_id = ? AND status = 'pending' AND provider_upload IS NOT NULL
|
|
10175
|
+
AND expires_at <= ?
|
|
10176
|
+
ORDER BY expires_at, id
|
|
10177
|
+
LIMIT ?`).all(input.projectId, input.now.toISOString(), input.limit);
|
|
10178
|
+
return rows.map((row) => parseFileUploadSessionRow(row));
|
|
10179
|
+
}
|
|
10180
|
+
async deleteReapable(now) {
|
|
10181
|
+
return this.db.query("DELETE FROM file_upload_sessions WHERE reap_at IS NOT NULL AND reap_at <= ?").run(now.toISOString()).changes;
|
|
10182
|
+
}
|
|
10183
|
+
}
|
|
10184
|
+
var SELECT_SESSION = `
|
|
10185
|
+
SELECT id, project_id AS projectId, owner_principal_type AS ownerPrincipalType,
|
|
10186
|
+
owner_principal_id AS ownerPrincipalId, strategy, status,
|
|
10187
|
+
file_name AS fileName, media_type AS mediaType, logical_path AS logicalPath,
|
|
10188
|
+
expected_size_bytes AS expectedSizeBytes, expected_digest AS expectedDigest,
|
|
10189
|
+
provider_upload AS providerUpload, signed_parts AS signedParts, file_ref AS fileRef,
|
|
10190
|
+
created_at AS createdAt, expires_at AS expiresAt, completed_at AS completedAt,
|
|
10191
|
+
aborted_at AS abortedAt
|
|
10192
|
+
FROM file_upload_sessions`;
|
|
10193
|
+
function mutableColumns(session) {
|
|
10194
|
+
return [
|
|
10195
|
+
session.providerUpload === undefined ? null : JSON.stringify(session.providerUpload),
|
|
10196
|
+
JSON.stringify(session.signedParts),
|
|
10197
|
+
session.fileRef === undefined ? null : JSON.stringify(session.fileRef),
|
|
10198
|
+
session.createdAt.toISOString(),
|
|
10199
|
+
session.expiresAt.toISOString(),
|
|
10200
|
+
session.completedAt?.toISOString() ?? null,
|
|
10201
|
+
session.abortedAt?.toISOString() ?? null,
|
|
10202
|
+
fileUploadSessionReapAt(session)?.toISOString() ?? null
|
|
10203
|
+
];
|
|
10204
|
+
}
|
|
10205
|
+
|
|
9923
10206
|
// src/objects/storage.ts
|
|
9924
10207
|
import { hasVectorProfile as hasVectorProfile3 } from "@sixb/core/internal/query";
|
|
9925
10208
|
|
|
@@ -10554,9 +10837,9 @@ function compilePredicate(predicate) {
|
|
|
10554
10837
|
return negatePredicate(item);
|
|
10555
10838
|
}
|
|
10556
10839
|
case "eq":
|
|
10557
|
-
return compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
|
|
10840
|
+
return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, [predicate.value]) : compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
|
|
10558
10841
|
case "neq":
|
|
10559
|
-
return compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
|
|
10842
|
+
return predicate.scalarKind === "userRef" ? negatePredicate(compileUserRefInPredicate(predicate.propertyId, [predicate.value])) : compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
|
|
10560
10843
|
case "lt":
|
|
10561
10844
|
case "lte":
|
|
10562
10845
|
case "gt":
|
|
@@ -10568,16 +10851,52 @@ function compilePredicate(predicate) {
|
|
|
10568
10851
|
};
|
|
10569
10852
|
}
|
|
10570
10853
|
case "in":
|
|
10571
|
-
return compileInPredicate(predicate.propertyId, predicate.values);
|
|
10854
|
+
return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, predicate.values) : compileInPredicate(predicate.propertyId, predicate.values);
|
|
10572
10855
|
case "exists": {
|
|
10573
10856
|
const sql = `${jsonTypeExpression()} IS NOT NULL`;
|
|
10574
10857
|
const item = { sql, args: [jsonPath(predicate.propertyId)] };
|
|
10575
10858
|
return predicate.value ? item : negatePredicate(item);
|
|
10576
10859
|
}
|
|
10577
10860
|
case "contains":
|
|
10578
|
-
return compileContainsPredicate(predicate.propertyId, predicate.value);
|
|
10861
|
+
return predicate.scalarKind === "userRef" ? compileUserRefContainsPredicate(predicate.propertyId, predicate.value) : compileContainsPredicate(predicate.propertyId, predicate.value);
|
|
10579
10862
|
}
|
|
10580
10863
|
}
|
|
10864
|
+
function compileUserRefInPredicate(propertyId, values) {
|
|
10865
|
+
const path = jsonPath(propertyId);
|
|
10866
|
+
const ids = values.flatMap((value) => {
|
|
10867
|
+
const id = userRefId(value);
|
|
10868
|
+
return id === undefined ? [] : [id];
|
|
10869
|
+
});
|
|
10870
|
+
const clauses = [];
|
|
10871
|
+
const args = [];
|
|
10872
|
+
if (values.includes(null)) {
|
|
10873
|
+
clauses.push(`${jsonTypeExpression()} = 'null'`);
|
|
10874
|
+
args.push(path);
|
|
10875
|
+
}
|
|
10876
|
+
if (ids.length > 0) {
|
|
10877
|
+
clauses.push(`(${jsonValueExpression()} = 'user' AND ${jsonValueExpression()} IN (${ids.map(() => "?").join(", ")}))`);
|
|
10878
|
+
args.push(`${path}.type`, `${path}.id`, ...ids);
|
|
10879
|
+
}
|
|
10880
|
+
if (clauses.length === 0)
|
|
10881
|
+
return { sql: "0 = 1", args: [] };
|
|
10882
|
+
return { sql: `(${clauses.join(" OR ")})`, args };
|
|
10883
|
+
}
|
|
10884
|
+
function compileUserRefContainsPredicate(propertyId, value) {
|
|
10885
|
+
const id = userRefId(value);
|
|
10886
|
+
if (id === undefined)
|
|
10887
|
+
return { sql: "0 = 1", args: [] };
|
|
10888
|
+
const path = jsonPath(propertyId);
|
|
10889
|
+
return {
|
|
10890
|
+
sql: `(${jsonTypeExpression()} = 'array' AND EXISTS (SELECT 1 FROM json_each(properties, ?) AS item WHERE item.type = 'object' AND json_extract(item.value, '$.type') = 'user' AND json_extract(item.value, '$.id') = ?))`,
|
|
10891
|
+
args: [path, path, id]
|
|
10892
|
+
};
|
|
10893
|
+
}
|
|
10894
|
+
function userRefId(value) {
|
|
10895
|
+
if (typeof value !== "object" || value === null)
|
|
10896
|
+
return;
|
|
10897
|
+
const { type, id } = value;
|
|
10898
|
+
return type === "user" && typeof id === "string" ? id : undefined;
|
|
10899
|
+
}
|
|
10581
10900
|
function negatePredicate(predicate) {
|
|
10582
10901
|
return {
|
|
10583
10902
|
sql: `(NOT COALESCE((${predicate.sql}), 0))`,
|
|
@@ -11308,6 +11627,9 @@ function sqliteFacetValue(valueType, value) {
|
|
|
11308
11627
|
return false;
|
|
11309
11628
|
if (valueType === "null")
|
|
11310
11629
|
return null;
|
|
11630
|
+
if ((valueType === "object" || valueType === "array") && typeof value === "string") {
|
|
11631
|
+
return JSON.parse(value);
|
|
11632
|
+
}
|
|
11311
11633
|
return value;
|
|
11312
11634
|
}
|
|
11313
11635
|
function existsProbeQuery(query) {
|
|
@@ -11744,7 +12066,8 @@ var SQLITE_OBJECT_QUERY_CAPABILITIES = {
|
|
|
11744
12066
|
double: { equality: true, ordering: true },
|
|
11745
12067
|
decimal: { equality: true },
|
|
11746
12068
|
date: { equality: true, ordering: true },
|
|
11747
|
-
timestamp: { equality: true, ordering: true }
|
|
12069
|
+
timestamp: { equality: true, ordering: true },
|
|
12070
|
+
userRef: { equality: true }
|
|
11748
12071
|
},
|
|
11749
12072
|
limits: {
|
|
11750
12073
|
totalCount: true,
|
|
@@ -11938,7 +12261,10 @@ function commitRecord(row) {
|
|
|
11938
12261
|
requestHash: row.request_hash,
|
|
11939
12262
|
executionId: row.execution_id,
|
|
11940
12263
|
origin: parseJson2(row.origin),
|
|
11941
|
-
...row.
|
|
12264
|
+
...row.requested_by === null ? {} : {
|
|
12265
|
+
requestedBy: parseJson2(row.requested_by)
|
|
12266
|
+
},
|
|
12267
|
+
executor: parseJson2(row.executor),
|
|
11942
12268
|
ontologyRevision: row.ontology_revision,
|
|
11943
12269
|
...row.projection_revision === null ? {} : { projectionRevision: row.projection_revision },
|
|
11944
12270
|
...row.ownership_hash === null ? {} : { ownershipHash: row.ownership_hash },
|
|
@@ -12092,6 +12418,9 @@ import {
|
|
|
12092
12418
|
telemetryPointSortKey as telemetryPointSortKey2
|
|
12093
12419
|
} from "@sixb/core/internal/materialization";
|
|
12094
12420
|
import {
|
|
12421
|
+
assertExpectedLinkRevision,
|
|
12422
|
+
assertExpectedLinkScopeRevision,
|
|
12423
|
+
assertExpectedObjectRevision,
|
|
12095
12424
|
assertMaterializationFinalizationCorrelation,
|
|
12096
12425
|
assertMaterializationHeader,
|
|
12097
12426
|
assertMaterializationLaneCompletion,
|
|
@@ -13587,15 +13916,15 @@ class SqliteOntologyMaterializationStorage {
|
|
|
13587
13916
|
const reader = new SqliteMaterializationStateReader(this.db, input.commit.projectId);
|
|
13588
13917
|
for (const expected of input.expected.sources)
|
|
13589
13918
|
this.assertSource(expected, input.commit.projectId);
|
|
13590
|
-
for (const expected of input.expected.objects)
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13919
|
+
for (const expected of input.expected.objects) {
|
|
13920
|
+
assertExpectedObjectRevision(reader.effectiveObjectRevision(expected.ref), expected);
|
|
13921
|
+
}
|
|
13922
|
+
for (const expected of input.expected.links) {
|
|
13923
|
+
assertExpectedLinkRevision(reader.effectiveLinkLastCommit(expected.ref), expected);
|
|
13924
|
+
}
|
|
13594
13925
|
const linkScopeRevisions = reader.linkScopeRevisions(input.expected.linkScopes);
|
|
13595
13926
|
for (const [index, expected] of input.expected.linkScopes.entries()) {
|
|
13596
|
-
|
|
13597
|
-
throw new MaterializationConflictError6("effective-state", `Expected link scope changed for ${expected.source.objectTypeId}:${expected.source.primaryId}.${expected.linkId}.`);
|
|
13598
|
-
}
|
|
13927
|
+
assertExpectedLinkScopeRevision(linkScopeRevisions[index]?.fingerprint, expected);
|
|
13599
13928
|
}
|
|
13600
13929
|
for (const expected of input.expected.points) {
|
|
13601
13930
|
const point = reader.exactPoint(expected.series, expected.at);
|
|
@@ -13828,30 +14157,6 @@ class SqliteOntologyMaterializationStorage {
|
|
|
13828
14157
|
throw new MaterializationConflictError6("projection-fence", `Source '${expected.source.projectionId}' changed.`);
|
|
13829
14158
|
}
|
|
13830
14159
|
}
|
|
13831
|
-
assertObject(reader, expected) {
|
|
13832
|
-
const row = reader.effectiveObjectRevision(expected.ref);
|
|
13833
|
-
if (!expected.exists) {
|
|
13834
|
-
if (row) {
|
|
13835
|
-
throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} to be absent.`);
|
|
13836
|
-
}
|
|
13837
|
-
return;
|
|
13838
|
-
}
|
|
13839
|
-
if (!row || row.version !== expected.version || row.lastCommitId !== expected.lastCommitId) {
|
|
13840
|
-
throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} changed.`);
|
|
13841
|
-
}
|
|
13842
|
-
}
|
|
13843
|
-
assertLink(reader, expected) {
|
|
13844
|
-
const lastCommitId = reader.effectiveLinkLastCommit(expected.ref);
|
|
13845
|
-
if (!expected.exists) {
|
|
13846
|
-
if (lastCommitId !== undefined) {
|
|
13847
|
-
throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} to be absent.`);
|
|
13848
|
-
}
|
|
13849
|
-
return;
|
|
13850
|
-
}
|
|
13851
|
-
if (lastCommitId === undefined || lastCommitId !== expected.lastCommitId) {
|
|
13852
|
-
throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} changed.`);
|
|
13853
|
-
}
|
|
13854
|
-
}
|
|
13855
14160
|
async assertFinalization(session, input) {
|
|
13856
14161
|
const { commit } = session.header;
|
|
13857
14162
|
const { result } = input.finalization;
|
|
@@ -13988,11 +14293,13 @@ class SqliteOntologyMaterializationStorage {
|
|
|
13988
14293
|
this.db.query(`
|
|
13989
14294
|
INSERT INTO ontology_commits (
|
|
13990
14295
|
project_id, id, idempotency_key, request_hash, execution_id,
|
|
13991
|
-
origin_kind, origin_run_id, origin_batch_ordinal, origin,
|
|
14296
|
+
origin_kind, origin_run_id, origin_batch_ordinal, origin, requested_by, executor,
|
|
13992
14297
|
ontology_revision, projection_revision, ownership_hash,
|
|
13993
14298
|
intent, result, committed_at
|
|
13994
|
-
) VALUES (
|
|
13995
|
-
|
|
14299
|
+
) VALUES (
|
|
14300
|
+
?, ?, ?, ?, ?, ?, ?, ?, json(?), json(?), json(?), ?, ?, ?, json(?), json(?), ?
|
|
14301
|
+
)
|
|
14302
|
+
`).run(commit.projectId, commit.id, commit.idempotencyKey, commit.requestHash, commit.executionId, origin.kind, origin.runId, origin.batchOrdinal, canonicalJson(commit.origin), commit.requestedBy === undefined ? null : canonicalJson(commit.requestedBy), canonicalJson(commit.executor), commit.ontologyRevision, commit.projectionRevision ?? null, commit.ownershipHash ?? null, canonicalJson(commit.intent), canonicalJson(input.finalization.result), commit.committedAt);
|
|
13996
14303
|
} catch (error) {
|
|
13997
14304
|
if (isSqliteConstraintError(error)) {
|
|
13998
14305
|
throw new MaterializationConflictError6("idempotency", "Ontology commit identity already exists.");
|
|
@@ -16620,7 +16927,7 @@ class SqliteWorkflowInterventionStorage {
|
|
|
16620
16927
|
submitted_by = ?,
|
|
16621
16928
|
response = ?
|
|
16622
16929
|
WHERE project_id = ? AND id = ?
|
|
16623
|
-
`).run("submitted", (input.submittedAt ?? new Date).toISOString(),
|
|
16930
|
+
`).run("submitted", (input.submittedAt ?? new Date).toISOString(), serializePrincipal(input.submittedBy), serializeRecord(input.response), existing.project_id, existing.id);
|
|
16624
16931
|
return this.requireIntervention(input.projectId, input.id);
|
|
16625
16932
|
})();
|
|
16626
16933
|
}
|
|
@@ -16634,7 +16941,7 @@ class SqliteWorkflowInterventionStorage {
|
|
|
16634
16941
|
cancelled_at = ?,
|
|
16635
16942
|
cancelled_by = ?
|
|
16636
16943
|
WHERE project_id = ? AND id = ?
|
|
16637
|
-
`).run("cancelled", (input.cancelledAt ?? new Date).toISOString(),
|
|
16944
|
+
`).run("cancelled", (input.cancelledAt ?? new Date).toISOString(), serializePrincipal(input.cancelledBy), existing.project_id, existing.id);
|
|
16638
16945
|
return this.requireIntervention(input.projectId, input.id);
|
|
16639
16946
|
})();
|
|
16640
16947
|
}
|
|
@@ -16756,10 +17063,10 @@ function serializeRecord(value) {
|
|
|
16756
17063
|
function parseRecord(value) {
|
|
16757
17064
|
return JSON.parse(value);
|
|
16758
17065
|
}
|
|
16759
|
-
function
|
|
16760
|
-
return
|
|
17066
|
+
function serializePrincipal(principal) {
|
|
17067
|
+
return principal ? JSON.stringify(principal) : null;
|
|
16761
17068
|
}
|
|
16762
|
-
function
|
|
17069
|
+
function parsePrincipal(value) {
|
|
16763
17070
|
return value ? JSON.parse(value) : undefined;
|
|
16764
17071
|
}
|
|
16765
17072
|
function rowToWorkflowInterventionRecord(row) {
|
|
@@ -16779,10 +17086,10 @@ function rowToWorkflowInterventionRecord(row) {
|
|
|
16779
17086
|
requestedAt: new Date(row.requested_at),
|
|
16780
17087
|
expiresAt: row.expires_at ? new Date(row.expires_at) : undefined,
|
|
16781
17088
|
submittedAt: row.submitted_at ? new Date(row.submitted_at) : undefined,
|
|
16782
|
-
submittedBy:
|
|
17089
|
+
submittedBy: parsePrincipal(row.submitted_by),
|
|
16783
17090
|
response: row.response ? parseRecord(row.response) : undefined,
|
|
16784
17091
|
cancelledAt: row.cancelled_at ? new Date(row.cancelled_at) : undefined,
|
|
16785
|
-
cancelledBy:
|
|
17092
|
+
cancelledBy: parsePrincipal(row.cancelled_by),
|
|
16786
17093
|
expiredAt: row.expired_at ? new Date(row.expired_at) : undefined
|
|
16787
17094
|
};
|
|
16788
17095
|
}
|
|
@@ -17445,6 +17752,7 @@ class SqliteStorage {
|
|
|
17445
17752
|
shareGrants;
|
|
17446
17753
|
shareSessions;
|
|
17447
17754
|
connectorConnections;
|
|
17755
|
+
fileUploadSessions;
|
|
17448
17756
|
migrators;
|
|
17449
17757
|
connection;
|
|
17450
17758
|
readConnection;
|
|
@@ -17495,6 +17803,7 @@ class SqliteStorage {
|
|
|
17495
17803
|
this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope);
|
|
17496
17804
|
this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope);
|
|
17497
17805
|
this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope);
|
|
17806
|
+
this.fileUploadSessions = createOperationScopedFacade(stores.fileUploadSessions, scope);
|
|
17498
17807
|
this.migrators = options.path ? createSqliteStorageMigrators(options.path) : [];
|
|
17499
17808
|
registerSqliteStorageTestingAdapter(this, (durationMs) => stores.connectorConnections.advanceTimeForTesting(durationMs));
|
|
17500
17809
|
}
|
|
@@ -17619,7 +17928,8 @@ function createSqliteStores(connection, options) {
|
|
|
17619
17928
|
rules: new SqliteRulesStorage({ connection }),
|
|
17620
17929
|
shareGrants,
|
|
17621
17930
|
shareSessions,
|
|
17622
|
-
connectorConnections: new SqliteConnectorConnectionStorage(connection)
|
|
17931
|
+
connectorConnections: new SqliteConnectorConnectionStorage(connection),
|
|
17932
|
+
fileUploadSessions: new SqliteFileUploadSessionStorage(connection)
|
|
17623
17933
|
};
|
|
17624
17934
|
}
|
|
17625
17935
|
export {
|
|
@@ -17627,4 +17937,4 @@ export {
|
|
|
17627
17937
|
migrateSqliteStorage
|
|
17628
17938
|
};
|
|
17629
17939
|
|
|
17630
|
-
//# debugId=
|
|
17940
|
+
//# debugId=A346535172FAF7A764756E2164756E21
|