@sixb/sqlite 0.1.12 → 0.1.14

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.
Files changed (44) hide show
  1. package/dist/auth-storage/access-tokens.d.ts +0 -1
  2. package/dist/auth-storage/access-tokens.d.ts.map +1 -1
  3. package/dist/auth-storage/auth-storage.d.ts +2 -1
  4. package/dist/auth-storage/auth-storage.d.ts.map +1 -1
  5. package/dist/auth-storage/device-authorizations.d.ts.map +1 -1
  6. package/dist/auth-storage/rows.d.ts +7 -4
  7. package/dist/auth-storage/rows.d.ts.map +1 -1
  8. package/dist/auth-storage/sessions.d.ts +8 -1
  9. package/dist/auth-storage/sessions.d.ts.map +1 -1
  10. package/dist/auth-storage/shared.d.ts.map +1 -1
  11. package/dist/file-upload-session-storage.d.ts +6 -0
  12. package/dist/file-upload-session-storage.d.ts.map +1 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +441 -123
  16. package/dist/index.js.map +18 -17
  17. package/dist/migrations.d.ts.map +1 -1
  18. package/dist/objects/storage.d.ts.map +1 -1
  19. package/dist/ontology-storage/materializations.d.ts +0 -2
  20. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  21. package/dist/ontology-storage/shared.d.ts +2 -1
  22. package/dist/ontology-storage/shared.d.ts.map +1 -1
  23. package/dist/workflow-intervention-storage.d.ts.map +1 -1
  24. package/package.json +3 -3
  25. package/src/auth-storage/access-tokens.ts +11 -18
  26. package/src/auth-storage/auth-storage.ts +49 -86
  27. package/src/auth-storage/device-authorizations.ts +3 -5
  28. package/src/auth-storage/rows.ts +18 -8
  29. package/src/auth-storage/sessions.ts +89 -4
  30. package/src/auth-storage/shared.ts +9 -3
  31. package/src/file-upload-session-storage.ts +136 -0
  32. package/src/index.ts +5 -0
  33. package/src/migrations/046-workflow-intervention-principals.sql +15 -0
  34. package/src/migrations/047-ontology-commit-attribution.sql +67 -0
  35. package/src/migrations/048-file-upload-sessions.sql +35 -0
  36. package/src/migrations/049-native-sessions.sql +12 -0
  37. package/src/migrations/050-directory-group-memberships.sql +21 -0
  38. package/src/migrations.ts +16 -0
  39. package/src/objects/query-compiler.ts +59 -4
  40. package/src/objects/reader.ts +4 -0
  41. package/src/objects/storage.ts +1 -0
  42. package/src/ontology-storage/materializations.ts +16 -59
  43. package/src/ontology-storage/shared.ts +7 -3
  44. package/src/workflow-intervention-storage.ts +9 -9
package/dist/index.js CHANGED
@@ -4230,6 +4230,133 @@ 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
+
4336
+ // src/migrations/050-directory-group-memberships.sql
4337
+ var _050_directory_group_memberships_default = `-- A membership the identity provider owns is recorded with source 'directory' and synced to the
4338
+ -- provider's groups on every sign-in. Service accounts never sign in, so their table is unchanged.
4339
+ -- SQLite cannot change a CHECK constraint in place, so the table is rebuilt.
4340
+ CREATE TABLE auth_group_memberships_next (
4341
+ project_id TEXT NOT NULL,
4342
+ user_id TEXT NOT NULL,
4343
+ group_id TEXT NOT NULL,
4344
+ source TEXT NOT NULL CHECK (source IN ('invitation', 'manual', 'agent', 'directory')),
4345
+ created_at TEXT NOT NULL,
4346
+ PRIMARY KEY (project_id, user_id, group_id)
4347
+ );
4348
+
4349
+ INSERT INTO auth_group_memberships_next (project_id, user_id, group_id, source, created_at)
4350
+ SELECT project_id, user_id, group_id, source, created_at
4351
+ FROM auth_group_memberships;
4352
+
4353
+ DROP TABLE auth_group_memberships;
4354
+ ALTER TABLE auth_group_memberships_next RENAME TO auth_group_memberships;
4355
+
4356
+ CREATE INDEX idx_auth_group_memberships_group
4357
+ ON auth_group_memberships(project_id, group_id);
4358
+ `;
4359
+
4233
4360
  // src/migrations/037-execution-requester-groups.sql
4234
4361
  var _037_execution_requester_groups_default = `ALTER TABLE executions ADD COLUMN requester_group_ids TEXT NOT NULL DEFAULT '[]';
4235
4362
 
@@ -4312,6 +4439,44 @@ CREATE INDEX idx_connector_attempts_expiry
4312
4439
  ON connector_authorization_attempts (project_id, connector_id, expires_at);
4313
4440
  `;
4314
4441
 
4442
+ // src/migrations/048-file-upload-sessions.sql
4443
+ var _048_file_upload_sessions_default = `-- Durable staged-upload sessions, so an upload survives restarts and spans API replicas.
4444
+ -- Timestamps are ISO-8601 UTC text and compare lexicographically.
4445
+ CREATE TABLE file_upload_sessions (
4446
+ id TEXT PRIMARY KEY CHECK (length(trim(id)) > 0),
4447
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
4448
+ owner_principal_type TEXT NOT NULL
4449
+ CHECK (owner_principal_type IN ('user', 'serviceAccount', 'system')),
4450
+ owner_principal_id TEXT NOT NULL CHECK (length(owner_principal_id) > 0),
4451
+ strategy TEXT NOT NULL CHECK (strategy IN ('server', 'direct-put', 'multipart')),
4452
+ status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'aborted')),
4453
+ file_name TEXT,
4454
+ media_type TEXT,
4455
+ logical_path TEXT,
4456
+ expected_size_bytes INTEGER CHECK (expected_size_bytes IS NULL OR expected_size_bytes >= 0),
4457
+ expected_digest TEXT,
4458
+ provider_upload TEXT CHECK (provider_upload IS NULL OR json_type(provider_upload) = 'object'),
4459
+ signed_parts TEXT NOT NULL CHECK (json_type(signed_parts) = 'array'),
4460
+ file_ref TEXT CHECK (file_ref IS NULL OR json_type(file_ref) = 'object'),
4461
+ created_at TEXT NOT NULL,
4462
+ expires_at TEXT NOT NULL,
4463
+ completed_at TEXT,
4464
+ aborted_at TEXT,
4465
+ -- Derived by core (fileUploadSessionReapAt); NULL while an abandoned upload awaits its abort.
4466
+ reap_at TEXT,
4467
+ CHECK ((status = 'completed') = (completed_at IS NOT NULL)),
4468
+ CHECK ((status = 'aborted') = (aborted_at IS NOT NULL))
4469
+ );
4470
+
4471
+ CREATE INDEX idx_file_upload_sessions_reap
4472
+ ON file_upload_sessions (reap_at)
4473
+ WHERE reap_at IS NOT NULL;
4474
+
4475
+ CREATE INDEX idx_file_upload_sessions_abandoned
4476
+ ON file_upload_sessions (project_id, expires_at)
4477
+ WHERE status = 'pending' AND provider_upload IS NOT NULL;
4478
+ `;
4479
+
4315
4480
  // src/migrations.ts
4316
4481
  var MIGRATIONS_TABLE_SQL = `
4317
4482
  CREATE TABLE IF NOT EXISTS sixb_migrations (
@@ -4391,7 +4556,12 @@ var sqliteStorageMigrations = defineMigrations({
4391
4556
  sqliteSql("042-vector-profiles", _042_vector_profiles_default),
4392
4557
  sqliteSql("043-vector-indexing", _043_vector_indexing_default),
4393
4558
  sqliteSql("044-vector-batching", _044_vector_batching_default),
4394
- sqliteSql("045-agent-thread-sandbox-state", _045_agent_thread_sandbox_state_default)
4559
+ sqliteSql("045-agent-thread-sandbox-state", _045_agent_thread_sandbox_state_default),
4560
+ sqliteSql("046-workflow-intervention-principals", _046_workflow_intervention_principals_default),
4561
+ sqliteSql("047-ontology-commit-attribution", _047_ontology_commit_attribution_default),
4562
+ sqliteSql("048-file-upload-sessions", _048_file_upload_sessions_default),
4563
+ sqliteSql("049-native-sessions", _049_native_sessions_default),
4564
+ sqliteSql("050-directory-group-memberships", _050_directory_group_memberships_default)
4395
4565
  ]
4396
4566
  });
4397
4567
  function sqliteStoragePath(basePath) {
@@ -7345,7 +7515,14 @@ function rowToSessionRecord(row) {
7345
7515
  revokedAt: row.revoked_at ? new Date(row.revoked_at) : undefined,
7346
7516
  lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : undefined,
7347
7517
  userAgent: row.user_agent ?? undefined,
7348
- ipAddress: row.ip_address ?? undefined
7518
+ ipAddress: row.ip_address ?? undefined,
7519
+ bearer: row.refresh_token_hash !== null && row.client_name !== null && row.access_expires_at !== null ? {
7520
+ clientName: row.client_name,
7521
+ accessExpiresAt: new Date(row.access_expires_at),
7522
+ refreshTokenHash: row.refresh_token_hash,
7523
+ previousRefreshTokenHash: row.previous_refresh_token_hash ?? undefined,
7524
+ refreshedAt: row.refreshed_at ? new Date(row.refreshed_at) : undefined
7525
+ } : undefined
7349
7526
  };
7350
7527
  }
7351
7528
  function rowToAccessTokenRecord(row) {
@@ -7354,8 +7531,7 @@ function rowToAccessTokenRecord(row) {
7354
7531
  projectId: row.project_id,
7355
7532
  name: row.name,
7356
7533
  kind: row.kind,
7357
- subjectType: row.subject_type,
7358
- subjectId: row.subject_id,
7534
+ subject: { type: row.subject_type, id: row.subject_id },
7359
7535
  tokenHash: row.token_hash,
7360
7536
  groupIds: parseOptionalStringArray(row.group_ids),
7361
7537
  createdByPrincipal: row.created_by_principal_type && row.created_by_principal_id ? {
@@ -7436,8 +7612,6 @@ function rowToDeviceAuthorizationRecord(row) {
7436
7612
  deviceCodeHash: row.device_code_hash,
7437
7613
  userCode: row.user_code,
7438
7614
  clientName: row.client_name,
7439
- tokenName: row.token_name,
7440
- tokenExpiresAt: new Date(row.token_expires_at),
7441
7615
  status: row.status,
7442
7616
  approvedUserId: row.approved_user_id ?? undefined,
7443
7617
  approvedSessionId: row.approved_session_id ?? undefined,
@@ -7668,9 +7842,12 @@ function createSession(db, input) {
7668
7842
  expires_at,
7669
7843
  absolute_expires_at,
7670
7844
  user_agent,
7671
- ip_address
7672
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7673
- `).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);
7845
+ ip_address,
7846
+ client_name,
7847
+ access_expires_at,
7848
+ refresh_token_hash
7849
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7850
+ `).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
7851
  const session = getSessionById(db, { projectId, id });
7675
7852
  if (!session) {
7676
7853
  throw new AuthStorageError("missing_session", `[Sixb] Failed to load session '${id}' for project '${projectId}'.`);
@@ -7818,10 +7995,10 @@ function createAuthAccessToken(db, input) {
7818
7995
  const id = assertNonEmpty(input.id, "Access token id");
7819
7996
  const projectId = assertNonEmpty(input.projectId, "Project id");
7820
7997
  const name = assertNonEmpty(input.name, "Access token name");
7821
- const subjectId = assertNonEmpty(input.subjectId, "Access token subject id");
7998
+ const subjectId = assertNonEmpty(input.subject.id, "Access token subject id");
7822
7999
  const tokenHash = assertNonEmpty(input.tokenHash, "Access token hash");
7823
8000
  assertKindMatchesSubject(input);
7824
- assertSubjectExists(db, projectId, input.subjectType, subjectId);
8001
+ assertSubjectExists(db, projectId, input.subject.type, subjectId);
7825
8002
  const groupIds = input.groupIds === undefined ? undefined : normalizeGroupIds(input.groupIds);
7826
8003
  try {
7827
8004
  db.query(`
@@ -7840,7 +8017,7 @@ function createAuthAccessToken(db, input) {
7840
8017
  created_at,
7841
8018
  expires_at
7842
8019
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7843
- `).run(projectId, id, name, input.kind, input.subjectType, subjectId, tokenHash, serializeOptionalStringArray(groupIds), input.createdByPrincipal?.type ?? null, input.createdByPrincipal?.id ?? null, input.createdBySessionId ?? null, toIso(input.createdAt), toIso(input.expiresAt));
8020
+ `).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
8021
  } catch (error) {
7845
8022
  mapUniqueConstraintError(error, "duplicate_access_token", `[Sixb] Access token '${id}' already exists for project '${projectId}'.`);
7846
8023
  }
@@ -7871,13 +8048,9 @@ class SqliteAuthAccessTokenStore {
7871
8048
  whereClauses.push("kind = ?");
7872
8049
  args.push(input.kind);
7873
8050
  }
7874
- if (input.subjectType) {
7875
- whereClauses.push("subject_type = ?");
7876
- args.push(input.subjectType);
7877
- }
7878
- if (input.subjectId) {
7879
- whereClauses.push("subject_id = ?");
7880
- args.push(input.subjectId);
8051
+ if (input.subject) {
8052
+ whereClauses.push("subject_type = ?", "subject_id = ?");
8053
+ args.push(input.subject.type, input.subject.id);
7881
8054
  }
7882
8055
  if (!input.includeRevoked) {
7883
8056
  whereClauses.push("revoked_at IS NULL");
@@ -7961,10 +8134,10 @@ function assertSubjectExists(db, projectId, subjectType, subjectId) {
7961
8134
  throw new AuthStorageError2("missing_service_account", `[Sixb] Service account '${subjectId}' not found for project '${projectId}'.`);
7962
8135
  }
7963
8136
  function assertKindMatchesSubject(input) {
7964
- if (input.kind === "personal" && input.subjectType === "user" || input.kind === "serviceAccount" && input.subjectType === "serviceAccount") {
8137
+ if (input.kind === "personal" && input.subject.type === "user" || input.kind === "serviceAccount" && input.subject.type === "serviceAccount") {
7965
8138
  return;
7966
8139
  }
7967
- throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subjectType}'.`);
8140
+ throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subject.type}'.`);
7968
8141
  }
7969
8142
 
7970
8143
  // src/auth-storage/device-authorizations.ts
@@ -7984,10 +8157,10 @@ class SqliteAuthDeviceAuthorizationStore {
7984
8157
  try {
7985
8158
  this.db.query(`
7986
8159
  INSERT INTO auth_device_authorizations (
7987
- project_id, id, device_code_hash, user_code, client_name, token_name,
7988
- token_expires_at, status, created_at, expires_at
7989
- ) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
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"), assertNonEmpty(input.tokenName, "Token name"), toIso(input.tokenExpiresAt), toIso(input.createdAt), toIso(input.expiresAt));
8160
+ project_id, id, device_code_hash, user_code, client_name, status, created_at,
8161
+ expires_at
8162
+ ) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)
8163
+ `).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
8164
  } catch (error) {
7992
8165
  mapUniqueConstraintError(error, "duplicate_device_authorization", `[Sixb] Device authorization '${input.id}' already exists for project '${input.projectId}'.`);
7993
8166
  }
@@ -8653,11 +8826,48 @@ class SqliteAuthSessionStore {
8653
8826
  }
8654
8827
  async findValidByTokenHash(params) {
8655
8828
  const row = getSessionRowById(this.db, params);
8656
- if (!row || row.audience !== params.audience || row.token_hash !== params.tokenHash || row.revoked_at || new Date(row.expires_at) <= params.now || row.absolute_expires_at !== null && new Date(row.absolute_expires_at) <= params.now) {
8829
+ if (!row || row.refresh_token_hash !== null || row.audience !== params.audience || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
8657
8830
  return null;
8658
8831
  }
8659
8832
  return rowToSessionRecord(row);
8660
8833
  }
8834
+ async findValidByAccessTokenHash(params) {
8835
+ const row = getSessionRowById(this.db, params);
8836
+ if (!row || row.access_expires_at === null || row.token_hash !== params.tokenHash || new Date(row.access_expires_at) <= params.now || !isLiveSessionRow(row, params.now)) {
8837
+ return null;
8838
+ }
8839
+ return rowToSessionRecord(row);
8840
+ }
8841
+ async rotateRefreshToken(params) {
8842
+ return runImmediateTransaction(this.db, () => {
8843
+ const row = getSessionRowById(this.db, params);
8844
+ if (!row?.refresh_token_hash || !isLiveSessionRow(row, params.now)) {
8845
+ return { status: "invalid" };
8846
+ }
8847
+ const replacedRecently = row.previous_refresh_token_hash === params.refreshTokenHash && row.refreshed_at !== null && params.now.getTime() - new Date(row.refreshed_at).getTime() <= params.reuseGraceMs;
8848
+ if (row.refresh_token_hash !== params.refreshTokenHash && !replacedRecently) {
8849
+ if (row.previous_refresh_token_hash !== params.refreshTokenHash) {
8850
+ return { status: "invalid" };
8851
+ }
8852
+ this.db.query("UPDATE auth_sessions SET revoked_at = ? WHERE project_id = ? AND id = ?").run(toIso(params.now), params.projectId, params.id);
8853
+ return { status: "reused" };
8854
+ }
8855
+ const expiresAt = toIso(params.next.expiresAt);
8856
+ this.db.query(`
8857
+ UPDATE auth_sessions
8858
+ SET token_hash = ?,
8859
+ access_expires_at = ?,
8860
+ previous_refresh_token_hash = refresh_token_hash,
8861
+ refresh_token_hash = ?,
8862
+ refreshed_at = ?,
8863
+ last_seen_at = ?,
8864
+ expires_at = MAX(expires_at, MIN(?, COALESCE(absolute_expires_at, ?)))
8865
+ WHERE project_id = ? AND id = ?
8866
+ `).run(params.next.tokenHash, toIso(params.next.accessExpiresAt), params.next.refreshTokenHash, toIso(params.now), toIso(params.now), expiresAt, expiresAt, params.projectId, params.id);
8867
+ const session = getSessionById(this.db, params);
8868
+ return session ? { status: "rotated", session } : { status: "invalid" };
8869
+ });
8870
+ }
8661
8871
  async renewIfValid(params) {
8662
8872
  return runImmediateTransaction(this.db, () => {
8663
8873
  const now = toIso(params.now);
@@ -8673,6 +8883,7 @@ class SqliteAuthSessionStore {
8673
8883
  AND id = ?
8674
8884
  AND audience = ?
8675
8885
  AND token_hash = ?
8886
+ AND refresh_token_hash IS NULL
8676
8887
  AND revoked_at IS NULL
8677
8888
  AND expires_at > ?
8678
8889
  AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
@@ -8718,6 +8929,9 @@ class SqliteAuthSessionStore {
8718
8929
  });
8719
8930
  }
8720
8931
  }
8932
+ function isLiveSessionRow(row, now) {
8933
+ return row.revoked_at === null && new Date(row.expires_at) > now && (row.absolute_expires_at === null || new Date(row.absolute_expires_at) > now);
8934
+ }
8721
8935
 
8722
8936
  // src/auth-storage/users.ts
8723
8937
  import { AuthStorageError as AuthStorageError10 } from "@sixb/core/storage";
@@ -8888,7 +9102,7 @@ class SqliteAuthStorage {
8888
9102
  throw new AuthStorageError11("missing_device_authorization", `[Sixb] Device authorization '${input.id}' not found for project '${input.projectId}'.`);
8889
9103
  }
8890
9104
  assertCompletableDeviceAuthorization(authorization, input);
8891
- const accessToken = createAuthAccessToken(this.db, input.accessToken);
9105
+ const session = createSession(this.db, input.session);
8892
9106
  this.db.query(`
8893
9107
  UPDATE auth_device_authorizations
8894
9108
  SET status = 'consumed', consumed_at = ?
@@ -8900,7 +9114,7 @@ class SqliteAuthStorage {
8900
9114
  status: "consumed",
8901
9115
  consumedAt: new Date(input.completedAt)
8902
9116
  },
8903
- accessToken
9117
+ session
8904
9118
  };
8905
9119
  });
8906
9120
  }
@@ -8946,17 +9160,6 @@ class SqliteAuthStorage {
8946
9160
  error: new AuthStorageError11("user_creation_not_allowed", `[Sixb] Magic link '${input.magicLinkId}' cannot create a user for project '${projectId}'.`)
8947
9161
  };
8948
9162
  }
8949
- if (shouldCreateUser && !activeInvitation && input.allowUserCreationWithoutInvitation && input.requireNoActiveUsersForUserCreation && hasActiveUsers(this.db, projectId)) {
8950
- consumeMagicLink(this.db, {
8951
- projectId,
8952
- id: input.magicLinkId,
8953
- tokenHash: input.tokenHash,
8954
- consumedAt: completedAt
8955
- });
8956
- return {
8957
- error: new AuthStorageError11("user_creation_not_allowed", `[Sixb] Magic link '${input.magicLinkId}' cannot create a user for project '${projectId}'.`)
8958
- };
8959
- }
8960
9163
  validateCompleteSessionInput(this.db, projectId, input.session);
8961
9164
  assertSignInSessionAudience(projectId, input.session.audience, magicLink.audience);
8962
9165
  let newUserId;
@@ -8986,8 +9189,9 @@ class SqliteAuthStorage {
8986
9189
  projectId,
8987
9190
  user
8988
9191
  });
8989
- const groupMemberships = this.applyManualGroups({
9192
+ const groupMemberships = this.applyGroups({
8990
9193
  completedAt,
9194
+ source: "manual",
8991
9195
  existing: invitation.groupMemberships,
8992
9196
  groupIds: manualGroupIds,
8993
9197
  projectId,
@@ -9041,36 +9245,18 @@ class SqliteAuthStorage {
9041
9245
  error: new AuthStorageError11("missing_user", `[Sixb] User '${identity.user_id}' not found for linked OIDC identity.`)
9042
9246
  };
9043
9247
  }
9044
- if (!identity && userRow && (!input.autoLinkByVerifiedEmail || !input.emailVerified)) {
9045
- this.consumeOidcAttempt(input, completedAt, projectId);
9046
- return {
9047
- error: new AuthStorageError11("email_link_not_allowed", `[Sixb] OIDC identity cannot auto-link to user '${userRow.id}' for project '${projectId}'.`)
9048
- };
9049
- }
9050
9248
  if (userRow?.status === "suspended") {
9051
9249
  this.consumeOidcAttempt(input, completedAt, projectId);
9052
9250
  return {
9053
9251
  error: new AuthStorageError11("suspended_user", `[Sixb] User '${userRow.id}' is suspended for project '${projectId}'.`)
9054
9252
  };
9055
9253
  }
9056
- if (shouldCreateUser && !input.emailVerified) {
9057
- this.consumeOidcAttempt(input, completedAt, projectId);
9058
- return {
9059
- error: new AuthStorageError11("user_creation_not_allowed", `[Sixb] OIDC authorization attempt '${input.oidcAuthorizationAttemptId}' cannot create a user for project '${projectId}'.`)
9060
- };
9061
- }
9062
9254
  if (shouldCreateUser && !activeInvitation && !input.allowUserCreationWithoutInvitation) {
9063
9255
  this.consumeOidcAttempt(input, completedAt, projectId);
9064
9256
  return {
9065
9257
  error: new AuthStorageError11("user_creation_not_allowed", `[Sixb] OIDC authorization attempt '${input.oidcAuthorizationAttemptId}' cannot create a user for project '${projectId}'.`)
9066
9258
  };
9067
9259
  }
9068
- if (shouldCreateUser && !activeInvitation && input.allowUserCreationWithoutInvitation && input.requireNoActiveUsersForUserCreation && hasActiveUsers(this.db, projectId)) {
9069
- this.consumeOidcAttempt(input, completedAt, projectId);
9070
- return {
9071
- error: new AuthStorageError11("user_creation_not_allowed", `[Sixb] OIDC authorization attempt '${input.oidcAuthorizationAttemptId}' cannot create a user for project '${projectId}'.`)
9072
- };
9073
- }
9074
9260
  validateCompleteSessionInput(this.db, projectId, input.session);
9075
9261
  assertSignInSessionAudience(projectId, input.session.audience, attempt.audience);
9076
9262
  let newUserId;
@@ -9108,10 +9294,17 @@ class SqliteAuthStorage {
9108
9294
  projectId,
9109
9295
  user
9110
9296
  });
9111
- const groupMemberships = this.applyManualGroups({
9297
+ const groupMemberships = this.syncDirectoryGroups({
9112
9298
  completedAt,
9113
- existing: invitation.groupMemberships,
9114
- groupIds: manualGroupIds,
9299
+ existing: this.applyGroups({
9300
+ completedAt,
9301
+ source: "manual",
9302
+ existing: invitation.groupMemberships,
9303
+ groupIds: manualGroupIds,
9304
+ projectId,
9305
+ userId: user.id
9306
+ }),
9307
+ groupIds: input.directoryGroupIds,
9115
9308
  projectId,
9116
9309
  userId: user.id
9117
9310
  });
@@ -9251,19 +9444,33 @@ class SqliteAuthStorage {
9251
9444
  }));
9252
9445
  return { invitation, groupMemberships };
9253
9446
  }
9254
- applyManualGroups(input) {
9447
+ applyGroups(input) {
9255
9448
  const groupMemberships = [...input.existing];
9256
9449
  for (const groupId of input.groupIds) {
9257
9450
  groupMemberships.push(upsertGroupMembership(this.db, {
9258
9451
  projectId: input.projectId,
9259
9452
  userId: input.userId,
9260
9453
  groupId,
9261
- source: "manual",
9454
+ source: input.source,
9262
9455
  createdAt: input.completedAt
9263
9456
  }));
9264
9457
  }
9265
9458
  return groupMemberships;
9266
9459
  }
9460
+ syncDirectoryGroups(input) {
9461
+ if (!input.groupIds) {
9462
+ return input.existing;
9463
+ }
9464
+ const groupIds = normalizeGroupIds(input.groupIds);
9465
+ this.db.query(`
9466
+ DELETE FROM auth_group_memberships
9467
+ WHERE project_id = ?
9468
+ AND user_id = ?
9469
+ AND source = 'directory'
9470
+ AND group_id NOT IN (${groupIds.map(() => "?").join(", ")})
9471
+ `).run(input.projectId, input.userId, ...groupIds);
9472
+ return this.applyGroups({ ...input, groupIds, source: "directory" });
9473
+ }
9267
9474
  createSignInSession(input) {
9268
9475
  return createSession(this.db, {
9269
9476
  id: input.session.id,
@@ -9315,16 +9522,6 @@ class SqliteAuthStorage {
9315
9522
  });
9316
9523
  }
9317
9524
  }
9318
- function hasActiveUsers(db, projectId) {
9319
- const row = db.query(`
9320
- SELECT 1 AS active
9321
- FROM auth_users
9322
- WHERE project_id = ?
9323
- AND status = 'active'
9324
- LIMIT 1
9325
- `).get(projectId);
9326
- return row !== null;
9327
- }
9328
9525
  function assertSignInSessionAudience(projectId, sessionAudience, storedAudience) {
9329
9526
  if (sessionAudience === storedAudience) {
9330
9527
  return;
@@ -9341,7 +9538,7 @@ function assertCompletableDeviceAuthorization(authorization, input) {
9341
9538
  if (authorization.status === "denied") {
9342
9539
  throw new AuthStorageError11("device_authorization_denied", "[Sixb] Device authorization was denied.");
9343
9540
  }
9344
- if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.accessToken.projectId !== input.projectId || input.accessToken.subjectType !== "user" || input.accessToken.subjectId !== authorization.approvedUserId || input.accessToken.createdBySessionId !== authorization.approvedSessionId) {
9541
+ if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.session.projectId !== input.projectId || input.session.userId !== authorization.approvedUserId) {
9345
9542
  throw new AuthStorageError11("invalid_device_authorization", "[Sixb] Device authorization is invalid.");
9346
9543
  }
9347
9544
  }
@@ -9920,6 +10117,100 @@ function isDuplicateExecutionError(error) {
9920
10117
  return error instanceof Error && error.message.includes("UNIQUE constraint failed: executions.project_id, executions.id");
9921
10118
  }
9922
10119
 
10120
+ // src/file-upload-session-storage.ts
10121
+ import {
10122
+ DurableFileUploadSessions,
10123
+ fileUploadSessionReapAt,
10124
+ parseFileUploadSessionRow
10125
+ } from "@sixb/core/internal/file-upload-session-storage-provider";
10126
+ class SqliteFileUploadSessionStorage extends DurableFileUploadSessions {
10127
+ constructor(connection) {
10128
+ super(new SqliteFileUploadSessionBackend(connection.db));
10129
+ }
10130
+ }
10131
+
10132
+ class SqliteFileUploadSessionBackend {
10133
+ db;
10134
+ persistence;
10135
+ constructor(db) {
10136
+ this.db = db;
10137
+ this.persistence = new SqliteFileUploadSessionPersistence(db);
10138
+ }
10139
+ read(run) {
10140
+ return run(this.persistence);
10141
+ }
10142
+ transaction(run) {
10143
+ return runImmediateTransactionAsync(this.db, () => run(this.persistence));
10144
+ }
10145
+ }
10146
+
10147
+ class SqliteFileUploadSessionPersistence {
10148
+ db;
10149
+ constructor(db) {
10150
+ this.db = db;
10151
+ }
10152
+ async now() {
10153
+ const row = this.db.query("SELECT strftime('%Y-%m-%dT%H:%M:%fZ', 'now') AS now").get();
10154
+ return new Date(row.now);
10155
+ }
10156
+ async insert(session) {
10157
+ try {
10158
+ this.db.query(`INSERT INTO file_upload_sessions (
10159
+ id, project_id, owner_principal_type, owner_principal_id, strategy, status, file_name,
10160
+ media_type, logical_path, expected_size_bytes, expected_digest, provider_upload, signed_parts, file_ref,
10161
+ created_at, expires_at, completed_at, aborted_at, reap_at
10162
+ ) 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));
10163
+ return true;
10164
+ } catch (error) {
10165
+ if (isUniqueConstraintError2(error))
10166
+ return false;
10167
+ throw error;
10168
+ }
10169
+ }
10170
+ async get(uploadId) {
10171
+ const row = this.db.query(`${SELECT_SESSION} WHERE id = ?`).get(uploadId);
10172
+ return row ? parseFileUploadSessionRow(row) : null;
10173
+ }
10174
+ async update(session) {
10175
+ this.db.query(`UPDATE file_upload_sessions
10176
+ SET status = ?, provider_upload = ?, signed_parts = ?, file_ref = ?, created_at = ?,
10177
+ expires_at = ?, completed_at = ?, aborted_at = ?, reap_at = ?
10178
+ WHERE id = ?`).run(session.status, ...mutableColumns(session), session.id);
10179
+ }
10180
+ async listAbandoned(input) {
10181
+ const rows = this.db.query(`${SELECT_SESSION}
10182
+ WHERE project_id = ? AND status = 'pending' AND provider_upload IS NOT NULL
10183
+ AND expires_at <= ?
10184
+ ORDER BY expires_at, id
10185
+ LIMIT ?`).all(input.projectId, input.now.toISOString(), input.limit);
10186
+ return rows.map((row) => parseFileUploadSessionRow(row));
10187
+ }
10188
+ async deleteReapable(now) {
10189
+ return this.db.query("DELETE FROM file_upload_sessions WHERE reap_at IS NOT NULL AND reap_at <= ?").run(now.toISOString()).changes;
10190
+ }
10191
+ }
10192
+ var SELECT_SESSION = `
10193
+ SELECT id, project_id AS projectId, owner_principal_type AS ownerPrincipalType,
10194
+ owner_principal_id AS ownerPrincipalId, strategy, status,
10195
+ file_name AS fileName, media_type AS mediaType, logical_path AS logicalPath,
10196
+ expected_size_bytes AS expectedSizeBytes, expected_digest AS expectedDigest,
10197
+ provider_upload AS providerUpload, signed_parts AS signedParts, file_ref AS fileRef,
10198
+ created_at AS createdAt, expires_at AS expiresAt, completed_at AS completedAt,
10199
+ aborted_at AS abortedAt
10200
+ FROM file_upload_sessions`;
10201
+ function mutableColumns(session) {
10202
+ return [
10203
+ session.providerUpload === undefined ? null : JSON.stringify(session.providerUpload),
10204
+ JSON.stringify(session.signedParts),
10205
+ session.fileRef === undefined ? null : JSON.stringify(session.fileRef),
10206
+ session.createdAt.toISOString(),
10207
+ session.expiresAt.toISOString(),
10208
+ session.completedAt?.toISOString() ?? null,
10209
+ session.abortedAt?.toISOString() ?? null,
10210
+ fileUploadSessionReapAt(session)?.toISOString() ?? null
10211
+ ];
10212
+ }
10213
+
9923
10214
  // src/objects/storage.ts
9924
10215
  import { hasVectorProfile as hasVectorProfile3 } from "@sixb/core/internal/query";
9925
10216
 
@@ -10554,9 +10845,9 @@ function compilePredicate(predicate) {
10554
10845
  return negatePredicate(item);
10555
10846
  }
10556
10847
  case "eq":
10557
- return compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
10848
+ return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, [predicate.value]) : compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
10558
10849
  case "neq":
10559
- return compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
10850
+ return predicate.scalarKind === "userRef" ? negatePredicate(compileUserRefInPredicate(predicate.propertyId, [predicate.value])) : compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
10560
10851
  case "lt":
10561
10852
  case "lte":
10562
10853
  case "gt":
@@ -10568,16 +10859,52 @@ function compilePredicate(predicate) {
10568
10859
  };
10569
10860
  }
10570
10861
  case "in":
10571
- return compileInPredicate(predicate.propertyId, predicate.values);
10862
+ return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, predicate.values) : compileInPredicate(predicate.propertyId, predicate.values);
10572
10863
  case "exists": {
10573
10864
  const sql = `${jsonTypeExpression()} IS NOT NULL`;
10574
10865
  const item = { sql, args: [jsonPath(predicate.propertyId)] };
10575
10866
  return predicate.value ? item : negatePredicate(item);
10576
10867
  }
10577
10868
  case "contains":
10578
- return compileContainsPredicate(predicate.propertyId, predicate.value);
10869
+ return predicate.scalarKind === "userRef" ? compileUserRefContainsPredicate(predicate.propertyId, predicate.value) : compileContainsPredicate(predicate.propertyId, predicate.value);
10579
10870
  }
10580
10871
  }
10872
+ function compileUserRefInPredicate(propertyId, values) {
10873
+ const path = jsonPath(propertyId);
10874
+ const ids = values.flatMap((value) => {
10875
+ const id = userRefId(value);
10876
+ return id === undefined ? [] : [id];
10877
+ });
10878
+ const clauses = [];
10879
+ const args = [];
10880
+ if (values.includes(null)) {
10881
+ clauses.push(`${jsonTypeExpression()} = 'null'`);
10882
+ args.push(path);
10883
+ }
10884
+ if (ids.length > 0) {
10885
+ clauses.push(`(${jsonValueExpression()} = 'user' AND ${jsonValueExpression()} IN (${ids.map(() => "?").join(", ")}))`);
10886
+ args.push(`${path}.type`, `${path}.id`, ...ids);
10887
+ }
10888
+ if (clauses.length === 0)
10889
+ return { sql: "0 = 1", args: [] };
10890
+ return { sql: `(${clauses.join(" OR ")})`, args };
10891
+ }
10892
+ function compileUserRefContainsPredicate(propertyId, value) {
10893
+ const id = userRefId(value);
10894
+ if (id === undefined)
10895
+ return { sql: "0 = 1", args: [] };
10896
+ const path = jsonPath(propertyId);
10897
+ return {
10898
+ 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') = ?))`,
10899
+ args: [path, path, id]
10900
+ };
10901
+ }
10902
+ function userRefId(value) {
10903
+ if (typeof value !== "object" || value === null)
10904
+ return;
10905
+ const { type, id } = value;
10906
+ return type === "user" && typeof id === "string" ? id : undefined;
10907
+ }
10581
10908
  function negatePredicate(predicate) {
10582
10909
  return {
10583
10910
  sql: `(NOT COALESCE((${predicate.sql}), 0))`,
@@ -11308,6 +11635,9 @@ function sqliteFacetValue(valueType, value) {
11308
11635
  return false;
11309
11636
  if (valueType === "null")
11310
11637
  return null;
11638
+ if ((valueType === "object" || valueType === "array") && typeof value === "string") {
11639
+ return JSON.parse(value);
11640
+ }
11311
11641
  return value;
11312
11642
  }
11313
11643
  function existsProbeQuery(query) {
@@ -11744,7 +12074,8 @@ var SQLITE_OBJECT_QUERY_CAPABILITIES = {
11744
12074
  double: { equality: true, ordering: true },
11745
12075
  decimal: { equality: true },
11746
12076
  date: { equality: true, ordering: true },
11747
- timestamp: { equality: true, ordering: true }
12077
+ timestamp: { equality: true, ordering: true },
12078
+ userRef: { equality: true }
11748
12079
  },
11749
12080
  limits: {
11750
12081
  totalCount: true,
@@ -11938,7 +12269,10 @@ function commitRecord(row) {
11938
12269
  requestHash: row.request_hash,
11939
12270
  executionId: row.execution_id,
11940
12271
  origin: parseJson2(row.origin),
11941
- ...row.actor === null ? {} : { actor: parseJson2(row.actor) },
12272
+ ...row.requested_by === null ? {} : {
12273
+ requestedBy: parseJson2(row.requested_by)
12274
+ },
12275
+ executor: parseJson2(row.executor),
11942
12276
  ontologyRevision: row.ontology_revision,
11943
12277
  ...row.projection_revision === null ? {} : { projectionRevision: row.projection_revision },
11944
12278
  ...row.ownership_hash === null ? {} : { ownershipHash: row.ownership_hash },
@@ -12092,6 +12426,9 @@ import {
12092
12426
  telemetryPointSortKey as telemetryPointSortKey2
12093
12427
  } from "@sixb/core/internal/materialization";
12094
12428
  import {
12429
+ assertExpectedLinkRevision,
12430
+ assertExpectedLinkScopeRevision,
12431
+ assertExpectedObjectRevision,
12095
12432
  assertMaterializationFinalizationCorrelation,
12096
12433
  assertMaterializationHeader,
12097
12434
  assertMaterializationLaneCompletion,
@@ -13587,15 +13924,15 @@ class SqliteOntologyMaterializationStorage {
13587
13924
  const reader = new SqliteMaterializationStateReader(this.db, input.commit.projectId);
13588
13925
  for (const expected of input.expected.sources)
13589
13926
  this.assertSource(expected, input.commit.projectId);
13590
- for (const expected of input.expected.objects)
13591
- this.assertObject(reader, expected);
13592
- for (const expected of input.expected.links)
13593
- this.assertLink(reader, expected);
13927
+ for (const expected of input.expected.objects) {
13928
+ assertExpectedObjectRevision(reader.effectiveObjectRevision(expected.ref), expected);
13929
+ }
13930
+ for (const expected of input.expected.links) {
13931
+ assertExpectedLinkRevision(reader.effectiveLinkLastCommit(expected.ref), expected);
13932
+ }
13594
13933
  const linkScopeRevisions = reader.linkScopeRevisions(input.expected.linkScopes);
13595
13934
  for (const [index, expected] of input.expected.linkScopes.entries()) {
13596
- if (linkScopeRevisions[index]?.fingerprint !== expected.fingerprint) {
13597
- throw new MaterializationConflictError6("effective-state", `Expected link scope changed for ${expected.source.objectTypeId}:${expected.source.primaryId}.${expected.linkId}.`);
13598
- }
13935
+ assertExpectedLinkScopeRevision(linkScopeRevisions[index]?.fingerprint, expected);
13599
13936
  }
13600
13937
  for (const expected of input.expected.points) {
13601
13938
  const point = reader.exactPoint(expected.series, expected.at);
@@ -13828,30 +14165,6 @@ class SqliteOntologyMaterializationStorage {
13828
14165
  throw new MaterializationConflictError6("projection-fence", `Source '${expected.source.projectionId}' changed.`);
13829
14166
  }
13830
14167
  }
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
14168
  async assertFinalization(session, input) {
13856
14169
  const { commit } = session.header;
13857
14170
  const { result } = input.finalization;
@@ -13988,11 +14301,13 @@ class SqliteOntologyMaterializationStorage {
13988
14301
  this.db.query(`
13989
14302
  INSERT INTO ontology_commits (
13990
14303
  project_id, id, idempotency_key, request_hash, execution_id,
13991
- origin_kind, origin_run_id, origin_batch_ordinal, origin, actor,
14304
+ origin_kind, origin_run_id, origin_batch_ordinal, origin, requested_by, executor,
13992
14305
  ontology_revision, projection_revision, ownership_hash,
13993
14306
  intent, result, committed_at
13994
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, json(?), json(?), ?, ?, ?, json(?), json(?), ?)
13995
- `).run(commit.projectId, commit.id, commit.idempotencyKey, commit.requestHash, commit.executionId, origin.kind, origin.runId, origin.batchOrdinal, canonicalJson(commit.origin), commit.actor === undefined ? null : canonicalJson(commit.actor), commit.ontologyRevision, commit.projectionRevision ?? null, commit.ownershipHash ?? null, canonicalJson(commit.intent), canonicalJson(input.finalization.result), commit.committedAt);
14307
+ ) VALUES (
14308
+ ?, ?, ?, ?, ?, ?, ?, ?, json(?), json(?), json(?), ?, ?, ?, json(?), json(?), ?
14309
+ )
14310
+ `).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
14311
  } catch (error) {
13997
14312
  if (isSqliteConstraintError(error)) {
13998
14313
  throw new MaterializationConflictError6("idempotency", "Ontology commit identity already exists.");
@@ -16620,7 +16935,7 @@ class SqliteWorkflowInterventionStorage {
16620
16935
  submitted_by = ?,
16621
16936
  response = ?
16622
16937
  WHERE project_id = ? AND id = ?
16623
- `).run("submitted", (input.submittedAt ?? new Date).toISOString(), serializeActor(input.submittedBy), serializeRecord(input.response), existing.project_id, existing.id);
16938
+ `).run("submitted", (input.submittedAt ?? new Date).toISOString(), serializePrincipal(input.submittedBy), serializeRecord(input.response), existing.project_id, existing.id);
16624
16939
  return this.requireIntervention(input.projectId, input.id);
16625
16940
  })();
16626
16941
  }
@@ -16634,7 +16949,7 @@ class SqliteWorkflowInterventionStorage {
16634
16949
  cancelled_at = ?,
16635
16950
  cancelled_by = ?
16636
16951
  WHERE project_id = ? AND id = ?
16637
- `).run("cancelled", (input.cancelledAt ?? new Date).toISOString(), serializeActor(input.cancelledBy), existing.project_id, existing.id);
16952
+ `).run("cancelled", (input.cancelledAt ?? new Date).toISOString(), serializePrincipal(input.cancelledBy), existing.project_id, existing.id);
16638
16953
  return this.requireIntervention(input.projectId, input.id);
16639
16954
  })();
16640
16955
  }
@@ -16756,10 +17071,10 @@ function serializeRecord(value) {
16756
17071
  function parseRecord(value) {
16757
17072
  return JSON.parse(value);
16758
17073
  }
16759
- function serializeActor(actor) {
16760
- return actor ? JSON.stringify(actor) : null;
17074
+ function serializePrincipal(principal) {
17075
+ return principal ? JSON.stringify(principal) : null;
16761
17076
  }
16762
- function parseActor(value) {
17077
+ function parsePrincipal(value) {
16763
17078
  return value ? JSON.parse(value) : undefined;
16764
17079
  }
16765
17080
  function rowToWorkflowInterventionRecord(row) {
@@ -16779,10 +17094,10 @@ function rowToWorkflowInterventionRecord(row) {
16779
17094
  requestedAt: new Date(row.requested_at),
16780
17095
  expiresAt: row.expires_at ? new Date(row.expires_at) : undefined,
16781
17096
  submittedAt: row.submitted_at ? new Date(row.submitted_at) : undefined,
16782
- submittedBy: parseActor(row.submitted_by),
17097
+ submittedBy: parsePrincipal(row.submitted_by),
16783
17098
  response: row.response ? parseRecord(row.response) : undefined,
16784
17099
  cancelledAt: row.cancelled_at ? new Date(row.cancelled_at) : undefined,
16785
- cancelledBy: parseActor(row.cancelled_by),
17100
+ cancelledBy: parsePrincipal(row.cancelled_by),
16786
17101
  expiredAt: row.expired_at ? new Date(row.expired_at) : undefined
16787
17102
  };
16788
17103
  }
@@ -17445,6 +17760,7 @@ class SqliteStorage {
17445
17760
  shareGrants;
17446
17761
  shareSessions;
17447
17762
  connectorConnections;
17763
+ fileUploadSessions;
17448
17764
  migrators;
17449
17765
  connection;
17450
17766
  readConnection;
@@ -17495,6 +17811,7 @@ class SqliteStorage {
17495
17811
  this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope);
17496
17812
  this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope);
17497
17813
  this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope);
17814
+ this.fileUploadSessions = createOperationScopedFacade(stores.fileUploadSessions, scope);
17498
17815
  this.migrators = options.path ? createSqliteStorageMigrators(options.path) : [];
17499
17816
  registerSqliteStorageTestingAdapter(this, (durationMs) => stores.connectorConnections.advanceTimeForTesting(durationMs));
17500
17817
  }
@@ -17619,7 +17936,8 @@ function createSqliteStores(connection, options) {
17619
17936
  rules: new SqliteRulesStorage({ connection }),
17620
17937
  shareGrants,
17621
17938
  shareSessions,
17622
- connectorConnections: new SqliteConnectorConnectionStorage(connection)
17939
+ connectorConnections: new SqliteConnectorConnectionStorage(connection),
17940
+ fileUploadSessions: new SqliteFileUploadSessionStorage(connection)
17623
17941
  };
17624
17942
  }
17625
17943
  export {
@@ -17627,4 +17945,4 @@ export {
17627
17945
  migrateSqliteStorage
17628
17946
  };
17629
17947
 
17630
- //# debugId=23F5EFFEE42C282464756E2164756E21
17948
+ //# debugId=9F25188860B63C3464756E2164756E21