@sixb/sqlite 0.1.11 → 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.
Files changed (80) hide show
  1. package/README.md +32 -0
  2. package/dist/agents/rows.d.ts +2 -0
  3. package/dist/agents/rows.d.ts.map +1 -1
  4. package/dist/agents/threads.d.ts +2 -1
  5. package/dist/agents/threads.d.ts.map +1 -1
  6. package/dist/auth-storage/access-tokens.d.ts +0 -1
  7. package/dist/auth-storage/access-tokens.d.ts.map +1 -1
  8. package/dist/auth-storage/auth-storage.d.ts.map +1 -1
  9. package/dist/auth-storage/device-authorizations.d.ts.map +1 -1
  10. package/dist/auth-storage/rows.d.ts +6 -3
  11. package/dist/auth-storage/rows.d.ts.map +1 -1
  12. package/dist/auth-storage/sessions.d.ts +8 -1
  13. package/dist/auth-storage/sessions.d.ts.map +1 -1
  14. package/dist/auth-storage/shared.d.ts.map +1 -1
  15. package/dist/file-upload-session-storage.d.ts +6 -0
  16. package/dist/file-upload-session-storage.d.ts.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1062 -137
  20. package/dist/index.js.map +28 -23
  21. package/dist/migrations.d.ts.map +1 -1
  22. package/dist/objects/query-compiler.d.ts +9 -2
  23. package/dist/objects/query-compiler.d.ts.map +1 -1
  24. package/dist/objects/read-scope.d.ts +3 -0
  25. package/dist/objects/read-scope.d.ts.map +1 -1
  26. package/dist/objects/reader.d.ts +1 -0
  27. package/dist/objects/reader.d.ts.map +1 -1
  28. package/dist/objects/rows.d.ts +1 -0
  29. package/dist/objects/rows.d.ts.map +1 -1
  30. package/dist/objects/storage.d.ts.map +1 -1
  31. package/dist/objects/vector-extension.d.ts +4 -0
  32. package/dist/objects/vector-extension.d.ts.map +1 -0
  33. package/dist/ontology-storage/index.d.ts +4 -0
  34. package/dist/ontology-storage/index.d.ts.map +1 -1
  35. package/dist/ontology-storage/materializations.d.ts +1 -2
  36. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  37. package/dist/ontology-storage/shared.d.ts +2 -1
  38. package/dist/ontology-storage/shared.d.ts.map +1 -1
  39. package/dist/ontology-storage/vector-indexing.d.ts +20 -0
  40. package/dist/ontology-storage/vector-indexing.d.ts.map +1 -0
  41. package/dist/ontology-storage/vectors.d.ts +16 -0
  42. package/dist/ontology-storage/vectors.d.ts.map +1 -0
  43. package/dist/vector-encoding.d.ts +3 -0
  44. package/dist/vector-encoding.d.ts.map +1 -0
  45. package/dist/workflow-intervention-storage.d.ts.map +1 -1
  46. package/package.json +8 -4
  47. package/src/agents/rows.ts +12 -0
  48. package/src/agents/threads.ts +41 -2
  49. package/src/ai-cost-storage.ts +4 -0
  50. package/src/auth-storage/access-tokens.ts +11 -18
  51. package/src/auth-storage/auth-storage.ts +5 -7
  52. package/src/auth-storage/device-authorizations.ts +3 -5
  53. package/src/auth-storage/rows.ts +17 -7
  54. package/src/auth-storage/sessions.ts +89 -4
  55. package/src/auth-storage/shared.ts +9 -3
  56. package/src/file-upload-session-storage.ts +136 -0
  57. package/src/index.ts +5 -0
  58. package/src/migrations/041-agent-thread-workspaces.sql +2 -0
  59. package/src/migrations/042-vector-profiles.sql +21 -0
  60. package/src/migrations/043-vector-indexing.sql +197 -0
  61. package/src/migrations/044-vector-batching.sql +3 -0
  62. package/src/migrations/045-agent-thread-sandbox-state.sql +2 -0
  63. package/src/migrations/046-workflow-intervention-principals.sql +15 -0
  64. package/src/migrations/047-ontology-commit-attribution.sql +67 -0
  65. package/src/migrations/048-file-upload-sessions.sql +35 -0
  66. package/src/migrations/049-native-sessions.sql +12 -0
  67. package/src/migrations.ts +26 -0
  68. package/src/objects/query-compiler.ts +164 -11
  69. package/src/objects/read-scope.ts +34 -31
  70. package/src/objects/reader.ts +29 -1
  71. package/src/objects/rows.ts +5 -1
  72. package/src/objects/storage.ts +13 -1
  73. package/src/objects/vector-extension.ts +26 -0
  74. package/src/ontology-storage/index.ts +16 -0
  75. package/src/ontology-storage/materializations.ts +29 -59
  76. package/src/ontology-storage/shared.ts +7 -3
  77. package/src/ontology-storage/vector-indexing.ts +196 -0
  78. package/src/ontology-storage/vectors.ts +182 -0
  79. package/src/vector-encoding.ts +9 -0
  80. package/src/workflow-intervention-storage.ts +9 -9
package/dist/index.js CHANGED
@@ -3990,6 +3990,349 @@ CREATE INDEX idx_ontology_outbox_publication_order
3990
3990
  WHERE published_at IS NULL;
3991
3991
  `;
3992
3992
 
3993
+ // src/migrations/041-agent-thread-workspaces.sql
3994
+ var _041_agent_thread_workspaces_default = `ALTER TABLE agent_threads ADD COLUMN sandbox_params TEXT
3995
+ CHECK (sandbox_params IS NULL OR (json_valid(sandbox_params) AND json_type(sandbox_params) = 'object'));
3996
+ `;
3997
+
3998
+ // src/migrations/042-vector-profiles.sql
3999
+ var _042_vector_profiles_default = `CREATE TABLE object_vectors (
4000
+ project_id TEXT NOT NULL,
4001
+ object_type_id TEXT NOT NULL,
4002
+ primary_id TEXT NOT NULL,
4003
+ profile TEXT NOT NULL CHECK (length(trim(profile)) > 0),
4004
+ configuration TEXT NOT NULL,
4005
+ source TEXT NOT NULL CHECK (
4006
+ json_valid(source) AND json_type(source) = 'array' AND json_array_length(source) > 0
4007
+ ),
4008
+ source_fingerprint TEXT NOT NULL,
4009
+ embedding BLOB NOT NULL CHECK (
4010
+ typeof(embedding) = 'blob' AND length(embedding) BETWEEN 4 AND 64000
4011
+ AND length(embedding) % 4 = 0
4012
+ ),
4013
+ last_commit_id TEXT NOT NULL,
4014
+ PRIMARY KEY (project_id, object_type_id, primary_id, profile),
4015
+ FOREIGN KEY (project_id, object_type_id, primary_id)
4016
+ REFERENCES objects (project_id, object_type_id, primary_id) ON DELETE CASCADE,
4017
+ FOREIGN KEY (project_id, last_commit_id)
4018
+ REFERENCES ontology_commits (project_id, id) DEFERRABLE INITIALLY DEFERRED
4019
+ );
4020
+ `;
4021
+
4022
+ // src/migrations/043-vector-indexing.sql
4023
+ var _043_vector_indexing_default = `CREATE TABLE object_vector_indexing (
4024
+ project_id TEXT NOT NULL,
4025
+ id TEXT NOT NULL,
4026
+ object_type_id TEXT NOT NULL,
4027
+ primary_id TEXT NOT NULL,
4028
+ profile TEXT NOT NULL,
4029
+ request TEXT NOT NULL,
4030
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'ready', 'failed')),
4031
+ available_at TEXT NOT NULL,
4032
+ dispatch_at TEXT NOT NULL,
4033
+ values_json TEXT,
4034
+ error TEXT,
4035
+ PRIMARY KEY (project_id, id),
4036
+ UNIQUE (project_id, object_type_id, primary_id, profile)
4037
+ );
4038
+ CREATE INDEX object_vector_indexing_due ON object_vector_indexing (project_id, dispatch_at, id)
4039
+ WHERE status <> 'failed';
4040
+
4041
+ CREATE TABLE executions_v2 (
4042
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
4043
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
4044
+ executor_kind TEXT NOT NULL CHECK (
4045
+ executor_kind IN (
4046
+ 'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
4047
+ 'agent', 'kernel'
4048
+ )
4049
+ ),
4050
+ executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
4051
+ source_kind TEXT NOT NULL CHECK (
4052
+ source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution', 'ontologyCommit')
4053
+ ),
4054
+ source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
4055
+ requested_by_user_id TEXT,
4056
+ requested_by_service_account_id TEXT,
4057
+ correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
4058
+ parent_execution_id TEXT,
4059
+ authority_kind TEXT NOT NULL CHECK (
4060
+ authority_kind IN ('principal', 'trustedPrimitive', 'delegated', 'kernel', 'disabled')
4061
+ ),
4062
+ authority_user_id TEXT,
4063
+ authority_service_account_id TEXT,
4064
+ authority_session_id TEXT,
4065
+ authority_access_token_id TEXT,
4066
+ authority_primitive_kind TEXT CHECK (
4067
+ authority_primitive_kind IS NULL
4068
+ OR authority_primitive_kind IN (
4069
+ 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
4070
+ )
4071
+ ),
4072
+ authority_primitive_id TEXT,
4073
+ authority_kernel_operation TEXT CHECK (
4074
+ authority_kernel_operation IS NULL OR authority_kernel_operation IN ('ontology.recover', 'ontology.indexVectors')
4075
+ ),
4076
+ authority_delegation_kind TEXT CHECK (
4077
+ authority_delegation_kind IS NULL OR authority_delegation_kind = 'share'
4078
+ ),
4079
+ authority_delegation_id TEXT,
4080
+ authority_delegation_session_id TEXT,
4081
+ requester_group_ids TEXT NOT NULL DEFAULT '[]',
4082
+ created_at TEXT NOT NULL,
4083
+ PRIMARY KEY (project_id, id),
4084
+ FOREIGN KEY (project_id, parent_execution_id) REFERENCES executions (project_id, id),
4085
+ FOREIGN KEY (project_id, requested_by_user_id) REFERENCES auth_users (project_id, id),
4086
+ FOREIGN KEY (project_id, requested_by_service_account_id)
4087
+ REFERENCES auth_service_accounts (project_id, id),
4088
+ FOREIGN KEY (project_id, authority_user_id) REFERENCES auth_users (project_id, id),
4089
+ FOREIGN KEY (project_id, authority_service_account_id)
4090
+ REFERENCES auth_service_accounts (project_id, id),
4091
+ FOREIGN KEY (project_id, authority_session_id) REFERENCES auth_sessions (project_id, id),
4092
+ FOREIGN KEY (project_id, authority_access_token_id)
4093
+ REFERENCES auth_access_tokens (project_id, id),
4094
+ FOREIGN KEY (
4095
+ project_id, authority_delegation_session_id, authority_delegation_id
4096
+ ) REFERENCES share_sessions (project_id, id, grant_id),
4097
+ CHECK ((requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1),
4098
+ CHECK (
4099
+ (source_kind = 'execution' AND parent_execution_id = source_id)
4100
+ OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
4101
+ ),
4102
+ CHECK (
4103
+ (
4104
+ authority_kind = 'principal'
4105
+ AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
4106
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
4107
+ AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
4108
+ AND authority_primitive_kind IS NULL
4109
+ AND authority_primitive_id IS NULL
4110
+ AND authority_kernel_operation IS NULL
4111
+ AND authority_delegation_kind IS NULL
4112
+ AND authority_delegation_id IS NULL
4113
+ AND authority_delegation_session_id IS NULL
4114
+ )
4115
+ OR (
4116
+ authority_kind = 'trustedPrimitive'
4117
+ AND authority_user_id IS NULL
4118
+ AND authority_service_account_id IS NULL
4119
+ AND authority_session_id IS NULL
4120
+ AND authority_access_token_id IS NULL
4121
+ AND authority_primitive_kind IS NOT NULL
4122
+ AND authority_primitive_id IS NOT NULL
4123
+ AND length(trim(authority_primitive_id)) > 0
4124
+ AND authority_kernel_operation IS NULL
4125
+ AND authority_delegation_kind IS NULL
4126
+ AND authority_delegation_id IS NULL
4127
+ AND authority_delegation_session_id IS NULL
4128
+ )
4129
+ OR (
4130
+ authority_kind = 'delegated'
4131
+ AND authority_user_id IS NULL
4132
+ AND authority_service_account_id IS NULL
4133
+ AND authority_session_id IS NULL
4134
+ AND authority_access_token_id IS NULL
4135
+ AND authority_primitive_kind IS NULL
4136
+ AND authority_primitive_id IS NULL
4137
+ AND authority_kernel_operation IS NULL
4138
+ AND authority_delegation_kind IS NOT NULL
4139
+ AND authority_delegation_kind = 'share'
4140
+ AND authority_delegation_id IS NOT NULL
4141
+ AND length(trim(authority_delegation_id)) > 0
4142
+ AND authority_delegation_session_id IS NOT NULL
4143
+ AND length(trim(authority_delegation_session_id)) > 0
4144
+ )
4145
+ OR (
4146
+ authority_kind = 'kernel'
4147
+ AND authority_user_id IS NULL
4148
+ AND authority_service_account_id IS NULL
4149
+ AND authority_session_id IS NULL
4150
+ AND authority_access_token_id IS NULL
4151
+ AND authority_primitive_kind IS NULL
4152
+ AND authority_primitive_id IS NULL
4153
+ AND authority_kernel_operation IS NOT NULL
4154
+ AND authority_delegation_kind IS NULL
4155
+ AND authority_delegation_id IS NULL
4156
+ AND authority_delegation_session_id IS NULL
4157
+ )
4158
+ OR (
4159
+ authority_kind = 'disabled'
4160
+ AND authority_user_id IS NULL
4161
+ AND authority_service_account_id IS NULL
4162
+ AND authority_session_id IS NULL
4163
+ AND authority_access_token_id IS NULL
4164
+ AND authority_primitive_kind IS NULL
4165
+ AND authority_primitive_id IS NULL
4166
+ AND authority_kernel_operation IS NULL
4167
+ AND authority_delegation_kind IS NULL
4168
+ AND authority_delegation_id IS NULL
4169
+ AND authority_delegation_session_id IS NULL
4170
+ )
4171
+ ),
4172
+ CHECK (
4173
+ (
4174
+ executor_kind = 'request'
4175
+ AND source_kind = 'http'
4176
+ AND executor_id = source_id
4177
+ AND (
4178
+ (
4179
+ authority_kind = 'principal'
4180
+ AND requested_by_user_id IS authority_user_id
4181
+ AND requested_by_service_account_id IS authority_service_account_id
4182
+ )
4183
+ OR (
4184
+ authority_kind IN ('delegated', 'disabled')
4185
+ AND requested_by_user_id IS NULL
4186
+ AND requested_by_service_account_id IS NULL
4187
+ )
4188
+ )
4189
+ )
4190
+ OR (
4191
+ executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
4192
+ AND authority_kind = 'trustedPrimitive'
4193
+ AND executor_kind = authority_primitive_kind
4194
+ )
4195
+ OR (
4196
+ executor_kind = 'agent'
4197
+ AND source_kind = 'execution'
4198
+ AND (
4199
+ (
4200
+ authority_kind = 'principal'
4201
+ AND authority_service_account_id IS NOT NULL
4202
+ AND authority_session_id IS NULL
4203
+ AND authority_access_token_id IS NULL
4204
+ )
4205
+ OR (
4206
+ authority_kind = 'principal'
4207
+ AND authority_user_id IS NOT NULL
4208
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) = 1
4209
+ )
4210
+ OR authority_kind = 'disabled'
4211
+ )
4212
+ )
4213
+ OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
4214
+ )
4215
+ );
4216
+
4217
+ INSERT INTO executions_v2 (project_id, id, executor_kind, executor_id, source_kind, source_id, requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id, authority_kind, authority_user_id, authority_service_account_id, authority_session_id, authority_access_token_id, authority_primitive_kind, authority_primitive_id, authority_kernel_operation, authority_delegation_kind, authority_delegation_id, authority_delegation_session_id, requester_group_ids, created_at) SELECT project_id, id, executor_kind, executor_id, source_kind, source_id, requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id, authority_kind, authority_user_id, authority_service_account_id, authority_session_id, authority_access_token_id, authority_primitive_kind, authority_primitive_id, authority_kernel_operation, authority_delegation_kind, authority_delegation_id, authority_delegation_session_id, requester_group_ids, created_at FROM executions;
4218
+ DROP TABLE executions;
4219
+ ALTER TABLE executions_v2 RENAME TO executions;
4220
+ `;
4221
+
4222
+ // src/migrations/044-vector-batching.sql
4223
+ var _044_vector_batching_default = `ALTER TABLE object_vector_indexing ADD COLUMN batch_id TEXT;
4224
+ CREATE INDEX object_vector_indexing_batch ON object_vector_indexing (project_id, batch_id, id)
4225
+ WHERE batch_id IS NOT NULL;
4226
+ `;
4227
+
4228
+ // src/migrations/045-agent-thread-sandbox-state.sql
4229
+ var _045_agent_thread_sandbox_state_default = `ALTER TABLE agent_threads ADD COLUMN sandbox_state TEXT
4230
+ CHECK (sandbox_state IS NULL OR (json_valid(sandbox_state) AND json_type(sandbox_state) = 'object'));
4231
+ `;
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
+
3993
4336
  // src/migrations/037-execution-requester-groups.sql
3994
4337
  var _037_execution_requester_groups_default = `ALTER TABLE executions ADD COLUMN requester_group_ids TEXT NOT NULL DEFAULT '[]';
3995
4338
 
@@ -4072,6 +4415,44 @@ CREATE INDEX idx_connector_attempts_expiry
4072
4415
  ON connector_authorization_attempts (project_id, connector_id, expires_at);
4073
4416
  `;
4074
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
+
4075
4456
  // src/migrations.ts
4076
4457
  var MIGRATIONS_TABLE_SQL = `
4077
4458
  CREATE TABLE IF NOT EXISTS sixb_migrations (
@@ -4146,7 +4527,16 @@ var sqliteStorageMigrations = defineMigrations({
4146
4527
  sqliteSql("037-execution-requester-groups", _037_execution_requester_groups_default),
4147
4528
  sqliteSql("038-projection-source-roots", _038_projection_source_roots_default),
4148
4529
  sqliteSql("039-connector-optional-pkce", _039_connector_optional_pkce_default),
4149
- sqliteSql("040-outbox-publication-order", _040_outbox_publication_order_default)
4530
+ sqliteSql("040-outbox-publication-order", _040_outbox_publication_order_default),
4531
+ sqliteSql("041-agent-thread-workspaces", _041_agent_thread_workspaces_default),
4532
+ sqliteSql("042-vector-profiles", _042_vector_profiles_default),
4533
+ sqliteSql("043-vector-indexing", _043_vector_indexing_default),
4534
+ sqliteSql("044-vector-batching", _044_vector_batching_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)
4150
4540
  ]
4151
4541
  });
4152
4542
  function sqliteStoragePath(basePath) {
@@ -4831,6 +5221,7 @@ import {
4831
5221
  } from "@sixb/core/storage";
4832
5222
 
4833
5223
  // src/agents/rows.ts
5224
+ import { snapshotAgentThreadSandboxParams } from "@sixb/core/internal/agent-run-storage-provider";
4834
5225
  import { parseSixbFailure } from "@sixb/core/internal/errors";
4835
5226
  import {
4836
5227
  AGENT_RUN_FAILURE_CODES,
@@ -4842,6 +5233,10 @@ function rowToThreadRecord(row) {
4842
5233
  projectId: row.project_id,
4843
5234
  ownerPrincipal: { type: row.owner_principal_type, id: row.owner_principal_id },
4844
5235
  title: row.title ?? undefined,
5236
+ ...row.sandbox_state == null ? {} : {
5237
+ sandboxState: JSON.parse(row.sandbox_state)
5238
+ },
5239
+ ...row.sandbox_params == null ? {} : { sandboxParams: snapshotAgentThreadSandboxParams(JSON.parse(row.sandbox_params)) },
4845
5240
  status: row.status,
4846
5241
  activeRunId: row.active_run_id,
4847
5242
  lastMessageAt: row.last_message_at ? new Date(row.last_message_at) : undefined,
@@ -5541,6 +5936,10 @@ class SqliteAgentRunStore {
5541
5936
  }
5542
5937
 
5543
5938
  // src/agents/threads.ts
5939
+ import {
5940
+ snapshotAgentThreadSandboxParams as snapshotAgentThreadSandboxParams2,
5941
+ transitionAgentThreadSandbox
5942
+ } from "@sixb/core/internal/agent-run-storage-provider";
5544
5943
  import {
5545
5944
  AgentStorageError as AgentStorageError4
5546
5945
  } from "@sixb/core/storage";
@@ -5549,7 +5948,17 @@ class SqliteAgentThreadStore {
5549
5948
  constructor(db) {
5550
5949
  this.db = db;
5551
5950
  }
5951
+ async transitionSandbox(input) {
5952
+ return this.db.transaction(() => {
5953
+ const run = input.action === "recreate" ? null : this.db.query("SELECT * FROM agent_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.runId);
5954
+ const thread = this.requireThread(input.projectId, input.id);
5955
+ const state = transitionAgentThreadSandbox(thread, run ? rowToRunRecord(run) : null, input);
5956
+ this.db.query("UPDATE agent_threads SET sandbox_state = ? WHERE project_id = ? AND id = ?").run(JSON.stringify(state), input.projectId, input.id);
5957
+ return state;
5958
+ }).immediate();
5959
+ }
5552
5960
  async create(input) {
5961
+ const sandboxParams = input.sandboxParams === undefined ? null : JSON.stringify(snapshotAgentThreadSandboxParams2(input.sandboxParams));
5553
5962
  const createdAt = input.createdAt ?? new Date;
5554
5963
  const updatedAt = input.updatedAt ?? createdAt;
5555
5964
  try {
@@ -5560,14 +5969,15 @@ class SqliteAgentThreadStore {
5560
5969
  owner_principal_type,
5561
5970
  owner_principal_id,
5562
5971
  title,
5972
+ sandbox_params,
5563
5973
  status,
5564
5974
  active_run_id,
5565
5975
  last_message_at,
5566
5976
  message_count,
5567
5977
  created_at,
5568
5978
  updated_at
5569
- ) VALUES (?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
5570
- `).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
5979
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
5980
+ `).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, sandboxParams, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
5571
5981
  } catch (error) {
5572
5982
  if (isUniqueConstraintError2(error)) {
5573
5983
  throw new AgentStorageError4("duplicate_id", `[SixbSqlite] Agent thread '${input.id}' already exists for project '${input.projectId}'.`);
@@ -6188,6 +6598,8 @@ var SQLITE_ACCOUNTING_OVERVIEW_SQL = `
6188
6598
  CAST(COUNT(*) AS TEXT) AS model_call_count,
6189
6599
  CAST(SUM(CASE WHEN reporting_status <> 'unavailable' THEN 1 ELSE 0 END) AS TEXT)
6190
6600
  AS reported_usage_call_count,
6601
+ CAST(SUM(CASE WHEN input_tokens IS NOT NULL AND output_tokens IS NOT NULL THEN 1 ELSE 0 END) AS TEXT)
6602
+ AS complete_usage_call_count,
6191
6603
  CAST(COUNT(input_tokens) AS TEXT) AS input_tokens_count,
6192
6604
  CAST(SUM(input_tokens) AS TEXT) AS input_tokens_sum,
6193
6605
  CAST(COUNT(output_tokens) AS TEXT) AS output_tokens_count,
@@ -6240,6 +6652,7 @@ function aggregateFragmentFromRow(row) {
6240
6652
  modelCallCount: row.model_call_count,
6241
6653
  usage: {
6242
6654
  reportedCallCount: row.reported_usage_call_count,
6655
+ completeCallCount: row.complete_usage_call_count,
6243
6656
  inputTokens: meterFragment(row.input_tokens_count, row.input_tokens_sum),
6244
6657
  outputTokens: meterFragment(row.output_tokens_count, row.output_tokens_sum),
6245
6658
  uncachedInputTokens: meterFragment(row.uncached_input_tokens_count, row.uncached_input_tokens_sum),
@@ -7077,7 +7490,14 @@ function rowToSessionRecord(row) {
7077
7490
  revokedAt: row.revoked_at ? new Date(row.revoked_at) : undefined,
7078
7491
  lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : undefined,
7079
7492
  userAgent: row.user_agent ?? undefined,
7080
- 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
7081
7501
  };
7082
7502
  }
7083
7503
  function rowToAccessTokenRecord(row) {
@@ -7086,8 +7506,7 @@ function rowToAccessTokenRecord(row) {
7086
7506
  projectId: row.project_id,
7087
7507
  name: row.name,
7088
7508
  kind: row.kind,
7089
- subjectType: row.subject_type,
7090
- subjectId: row.subject_id,
7509
+ subject: { type: row.subject_type, id: row.subject_id },
7091
7510
  tokenHash: row.token_hash,
7092
7511
  groupIds: parseOptionalStringArray(row.group_ids),
7093
7512
  createdByPrincipal: row.created_by_principal_type && row.created_by_principal_id ? {
@@ -7168,8 +7587,6 @@ function rowToDeviceAuthorizationRecord(row) {
7168
7587
  deviceCodeHash: row.device_code_hash,
7169
7588
  userCode: row.user_code,
7170
7589
  clientName: row.client_name,
7171
- tokenName: row.token_name,
7172
- tokenExpiresAt: new Date(row.token_expires_at),
7173
7590
  status: row.status,
7174
7591
  approvedUserId: row.approved_user_id ?? undefined,
7175
7592
  approvedSessionId: row.approved_session_id ?? undefined,
@@ -7400,9 +7817,12 @@ function createSession(db, input) {
7400
7817
  expires_at,
7401
7818
  absolute_expires_at,
7402
7819
  user_agent,
7403
- ip_address
7404
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7405
- `).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);
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);
7406
7826
  const session = getSessionById(db, { projectId, id });
7407
7827
  if (!session) {
7408
7828
  throw new AuthStorageError("missing_session", `[Sixb] Failed to load session '${id}' for project '${projectId}'.`);
@@ -7550,10 +7970,10 @@ function createAuthAccessToken(db, input) {
7550
7970
  const id = assertNonEmpty(input.id, "Access token id");
7551
7971
  const projectId = assertNonEmpty(input.projectId, "Project id");
7552
7972
  const name = assertNonEmpty(input.name, "Access token name");
7553
- const subjectId = assertNonEmpty(input.subjectId, "Access token subject id");
7973
+ const subjectId = assertNonEmpty(input.subject.id, "Access token subject id");
7554
7974
  const tokenHash = assertNonEmpty(input.tokenHash, "Access token hash");
7555
7975
  assertKindMatchesSubject(input);
7556
- assertSubjectExists(db, projectId, input.subjectType, subjectId);
7976
+ assertSubjectExists(db, projectId, input.subject.type, subjectId);
7557
7977
  const groupIds = input.groupIds === undefined ? undefined : normalizeGroupIds(input.groupIds);
7558
7978
  try {
7559
7979
  db.query(`
@@ -7572,7 +7992,7 @@ function createAuthAccessToken(db, input) {
7572
7992
  created_at,
7573
7993
  expires_at
7574
7994
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7575
- `).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));
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));
7576
7996
  } catch (error) {
7577
7997
  mapUniqueConstraintError(error, "duplicate_access_token", `[Sixb] Access token '${id}' already exists for project '${projectId}'.`);
7578
7998
  }
@@ -7603,13 +8023,9 @@ class SqliteAuthAccessTokenStore {
7603
8023
  whereClauses.push("kind = ?");
7604
8024
  args.push(input.kind);
7605
8025
  }
7606
- if (input.subjectType) {
7607
- whereClauses.push("subject_type = ?");
7608
- args.push(input.subjectType);
7609
- }
7610
- if (input.subjectId) {
7611
- whereClauses.push("subject_id = ?");
7612
- args.push(input.subjectId);
8026
+ if (input.subject) {
8027
+ whereClauses.push("subject_type = ?", "subject_id = ?");
8028
+ args.push(input.subject.type, input.subject.id);
7613
8029
  }
7614
8030
  if (!input.includeRevoked) {
7615
8031
  whereClauses.push("revoked_at IS NULL");
@@ -7693,10 +8109,10 @@ function assertSubjectExists(db, projectId, subjectType, subjectId) {
7693
8109
  throw new AuthStorageError2("missing_service_account", `[Sixb] Service account '${subjectId}' not found for project '${projectId}'.`);
7694
8110
  }
7695
8111
  function assertKindMatchesSubject(input) {
7696
- if (input.kind === "personal" && input.subjectType === "user" || input.kind === "serviceAccount" && input.subjectType === "serviceAccount") {
8112
+ if (input.kind === "personal" && input.subject.type === "user" || input.kind === "serviceAccount" && input.subject.type === "serviceAccount") {
7697
8113
  return;
7698
8114
  }
7699
- throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subjectType}'.`);
8115
+ throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subject.type}'.`);
7700
8116
  }
7701
8117
 
7702
8118
  // src/auth-storage/device-authorizations.ts
@@ -7716,10 +8132,10 @@ class SqliteAuthDeviceAuthorizationStore {
7716
8132
  try {
7717
8133
  this.db.query(`
7718
8134
  INSERT INTO auth_device_authorizations (
7719
- project_id, id, device_code_hash, user_code, client_name, token_name,
7720
- token_expires_at, status, created_at, expires_at
7721
- ) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
7722
- `).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));
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));
7723
8139
  } catch (error) {
7724
8140
  mapUniqueConstraintError(error, "duplicate_device_authorization", `[Sixb] Device authorization '${input.id}' already exists for project '${input.projectId}'.`);
7725
8141
  }
@@ -8385,11 +8801,48 @@ class SqliteAuthSessionStore {
8385
8801
  }
8386
8802
  async findValidByTokenHash(params) {
8387
8803
  const row = getSessionRowById(this.db, params);
8388
- 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) {
8804
+ if (!row || row.refresh_token_hash !== null || row.audience !== params.audience || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
8805
+ return null;
8806
+ }
8807
+ return rowToSessionRecord(row);
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)) {
8389
8812
  return null;
8390
8813
  }
8391
8814
  return rowToSessionRecord(row);
8392
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
+ }
8393
8846
  async renewIfValid(params) {
8394
8847
  return runImmediateTransaction(this.db, () => {
8395
8848
  const now = toIso(params.now);
@@ -8405,6 +8858,7 @@ class SqliteAuthSessionStore {
8405
8858
  AND id = ?
8406
8859
  AND audience = ?
8407
8860
  AND token_hash = ?
8861
+ AND refresh_token_hash IS NULL
8408
8862
  AND revoked_at IS NULL
8409
8863
  AND expires_at > ?
8410
8864
  AND (absolute_expires_at IS NULL OR absolute_expires_at > ?)
@@ -8450,6 +8904,9 @@ class SqliteAuthSessionStore {
8450
8904
  });
8451
8905
  }
8452
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
+ }
8453
8910
 
8454
8911
  // src/auth-storage/users.ts
8455
8912
  import { AuthStorageError as AuthStorageError10 } from "@sixb/core/storage";
@@ -8620,7 +9077,7 @@ class SqliteAuthStorage {
8620
9077
  throw new AuthStorageError11("missing_device_authorization", `[Sixb] Device authorization '${input.id}' not found for project '${input.projectId}'.`);
8621
9078
  }
8622
9079
  assertCompletableDeviceAuthorization(authorization, input);
8623
- const accessToken = createAuthAccessToken(this.db, input.accessToken);
9080
+ const session = createSession(this.db, input.session);
8624
9081
  this.db.query(`
8625
9082
  UPDATE auth_device_authorizations
8626
9083
  SET status = 'consumed', consumed_at = ?
@@ -8632,7 +9089,7 @@ class SqliteAuthStorage {
8632
9089
  status: "consumed",
8633
9090
  consumedAt: new Date(input.completedAt)
8634
9091
  },
8635
- accessToken
9092
+ session
8636
9093
  };
8637
9094
  });
8638
9095
  }
@@ -9073,7 +9530,7 @@ function assertCompletableDeviceAuthorization(authorization, input) {
9073
9530
  if (authorization.status === "denied") {
9074
9531
  throw new AuthStorageError11("device_authorization_denied", "[Sixb] Device authorization was denied.");
9075
9532
  }
9076
- 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) {
9533
+ if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.session.projectId !== input.projectId || input.session.userId !== authorization.approvedUserId) {
9077
9534
  throw new AuthStorageError11("invalid_device_authorization", "[Sixb] Device authorization is invalid.");
9078
9535
  }
9079
9536
  }
@@ -9652,13 +10109,131 @@ function isDuplicateExecutionError(error) {
9652
10109
  return error instanceof Error && error.message.includes("UNIQUE constraint failed: executions.project_id, executions.id");
9653
10110
  }
9654
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
+
10206
+ // src/objects/storage.ts
10207
+ import { hasVectorProfile as hasVectorProfile3 } from "@sixb/core/internal/query";
10208
+
9655
10209
  // src/objects/query-compiler.ts
9656
10210
  import {
9657
10211
  ObjectQueryExecutionError
9658
10212
  } from "@sixb/core";
10213
+ import {
10214
+ hasVectorProfile,
10215
+ isVectorProfileQuery,
10216
+ normalizeVector,
10217
+ vectorSearchCandidateLimit
10218
+ } from "@sixb/core/internal/query";
10219
+
10220
+ // src/vector-encoding.ts
10221
+ function encodeSqliteVector(values) {
10222
+ const bytes = new Uint8Array(values.length * 4);
10223
+ const view = new DataView(bytes.buffer);
10224
+ for (let index = 0;index < values.length; index++) {
10225
+ view.setFloat32(index * 4, values[index], true);
10226
+ }
10227
+ return bytes;
10228
+ }
10229
+
10230
+ // src/objects/query-compiler.ts
9659
10231
  var PAGE_TOKEN_PREFIX = "keyset:";
9660
10232
  var DEFAULT_EXPANSION_FANOUT = 1000;
9661
10233
  function compileObjectQuery(projectId, query, options = {}) {
10234
+ if (hasVectorProfile(query) && !isVectorProfileQuery(query)) {
10235
+ throw new ObjectQueryExecutionError("unsupported_vector_composition", "Vector search supports one profile with filters before ranking and limit/project after.");
10236
+ }
9662
10237
  const source = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE;
9663
10238
  const ctx = { probeLimit: options.includeTotal === false, source };
9664
10239
  return source.wrapQuery(compileObjectQueryInternal(projectId, query, ctx));
@@ -9697,8 +10272,59 @@ function compileObjectQueryInternal(projectId, query, ctx) {
9697
10272
  case "expand":
9698
10273
  return compileExpand(projectId, query.input, query.expansions, ctx);
9699
10274
  case "vector":
9700
- throw new Error(`[Sixb] SQLite object storage does not support query node '${query.kind}'`);
9701
- }
10275
+ return compileVector(projectId, query, ctx);
10276
+ }
10277
+ }
10278
+ function compileVector(projectId, query, ctx) {
10279
+ if (typeof query.vector === "string" || !isVectorProfileQuery(query) || !query.configuration || !Number.isSafeInteger(query.k) || query.k < 1 || query.k > 1000 || query.vector.length < 1 || query.vector.length > 16000) {
10280
+ throw new ObjectQueryExecutionError("invalid_vector_query", "A validated named vector profile is required.");
10281
+ }
10282
+ const input = compileObjectQueryInternal(projectId, query.input, exactContext(ctx));
10283
+ const permissions = ctx.source.objectPropertyPermissionsTable;
10284
+ const permissionJoin = permissions ? `CROSS JOIN (
10285
+ SELECT project_id, object_type_id, primary_id, json_group_array(property_id) AS property_ids
10286
+ FROM ${permissions}
10287
+ GROUP BY project_id, object_type_id, primary_id
10288
+ ) AS vector_permissions ON vector_permissions.project_id = vectors.project_id
10289
+ AND vector_permissions.object_type_id = vectors.object_type_id
10290
+ AND vector_permissions.primary_id = vectors.primary_id` : "";
10291
+ const authorized = permissions ? `AND NOT EXISTS (
10292
+ SELECT 1 FROM json_each(vectors.source) AS required
10293
+ WHERE required.value NOT IN (SELECT value FROM json_each(vector_permissions.property_ids))
10294
+ )` : "";
10295
+ const candidates = `FROM (${input.sql}) AS input
10296
+ CROSS JOIN object_vectors AS vectors ON vectors.project_id = input.project_id
10297
+ AND vectors.object_type_id = input.object_type_id AND vectors.primary_id = input.primary_id
10298
+ ${permissionJoin}
10299
+ WHERE vectors.profile = ? AND vectors.configuration = ?
10300
+ AND length(vectors.embedding) / 4 = ? ${authorized}`;
10301
+ const candidateArgs = [...input.args, query.profile, query.configuration, query.vector.length];
10302
+ const limit = vectorSearchCandidateLimit(query.vector.length);
10303
+ const values = normalizeVector(query.vector, query.vector.length);
10304
+ const order = compileOrder([
10305
+ { kind: "column", column: "_vector_score", direction: "desc" },
10306
+ ...identityOrderFields().map((field) => ({ ...field, binary: true }))
10307
+ ]);
10308
+ const sql = `SELECT * FROM (SELECT input.*, max(-1, min(1, 1 - vec_distance_cosine(vectors.embedding, ?))) AS _vector_score
10309
+ ${candidates}) AS ranked ORDER BY ${order.sql} LIMIT ?`;
10310
+ const args = [encodeSqliteVector(values), ...candidateArgs, query.k];
10311
+ return {
10312
+ sql,
10313
+ args,
10314
+ totalSql: `SELECT COUNT(*) AS total FROM (SELECT 1 ${candidates} LIMIT ?) AS eligible`,
10315
+ totalArgs: [...candidateArgs, query.k],
10316
+ order,
10317
+ vectorProbe: {
10318
+ sql: `SELECT COUNT(*) AS total FROM (SELECT 1 ${candidates} LIMIT ?) AS candidates`,
10319
+ args: [...candidateArgs, limit + 1],
10320
+ limit
10321
+ },
10322
+ hasMore: () => false,
10323
+ trimRows: identityRows,
10324
+ nextPageToken: () => {
10325
+ return;
10326
+ }
10327
+ };
9702
10328
  }
9703
10329
  function compileStart(projectId, query, ctx) {
9704
10330
  if (query.includeSubtypes === true) {
@@ -9788,6 +10414,7 @@ function compileWhere(projectId, inputQuery, predicate, ctx) {
9788
10414
  WHERE ${predicate.sql}
9789
10415
  `,
9790
10416
  totalArgs: [...input.args, ...predicate.args],
10417
+ vectorProbe: input.vectorProbe,
9791
10418
  order: input.order,
9792
10419
  hasMore: () => false,
9793
10420
  trimRows: identityRows,
@@ -9818,7 +10445,7 @@ function compileSort(projectId, inputQuery, fields, ctx) {
9818
10445
  input.created_at,
9819
10446
  input.updated_at,
9820
10447
  input.version,
9821
- input.last_commit_id
10448
+ input.last_commit_id${input.vectorProbe ? ", input._vector_score" : ""}
9822
10449
  FROM (${input.sql}) AS input
9823
10450
  ORDER BY ${order.sql}
9824
10451
  `,
@@ -9849,6 +10476,7 @@ function compileLimit(projectId, inputQuery, rawLimit, ctx) {
9849
10476
  FROM (${input.sql}) AS input
9850
10477
  `,
9851
10478
  totalArgs: input.args,
10479
+ vectorProbe: input.vectorProbe,
9852
10480
  order: input.order,
9853
10481
  hasMore: (rowCount, total) => total === undefined ? ctx.probeLimit && rowCount > limit : limit < total,
9854
10482
  trimRows: ctx.probeLimit ? (rows) => rows.slice(0, limit) : identityRows,
@@ -9877,6 +10505,7 @@ function compilePage(projectId, inputQuery, rawPageSize, pageToken, ctx) {
9877
10505
  FROM (${input.sql}) AS input
9878
10506
  `,
9879
10507
  totalArgs: input.args,
10508
+ vectorProbe: input.vectorProbe,
9880
10509
  order: input.order,
9881
10510
  hasMore: (rowCount) => rowCount > pageSize,
9882
10511
  trimRows: (rows) => rows.slice(0, pageSize),
@@ -9953,6 +10582,7 @@ function compileExpand(projectId, inputQuery, expansions, ctx) {
9953
10582
  args: [...expand.args, ...input.args, ...inputOrder.args],
9954
10583
  totalSql: input.totalSql,
9955
10584
  totalArgs: input.totalArgs,
10585
+ vectorProbe: input.vectorProbe,
9956
10586
  order: input.order,
9957
10587
  hasMoreProbe: input.hasMoreProbe,
9958
10588
  hasMore: input.hasMore,
@@ -10123,13 +10753,14 @@ function compileProject(projectId, inputQuery, properties, ctx) {
10123
10753
  input.created_at,
10124
10754
  input.updated_at,
10125
10755
  input.version,
10126
- input.last_commit_id
10756
+ input.last_commit_id${input.vectorProbe ? ", input._vector_score" : ""}
10127
10757
  FROM (${input.sql}) AS input
10128
10758
  ORDER BY ${inputOrder.sql}
10129
10759
  `,
10130
10760
  args: [...projection.args, ...input.args, ...inputOrder.args],
10131
10761
  totalSql: input.totalSql,
10132
10762
  totalArgs: input.totalArgs,
10763
+ vectorProbe: input.vectorProbe,
10133
10764
  order: outputOrder,
10134
10765
  hasMoreProbe: input.hasMoreProbe,
10135
10766
  hasMore: input.hasMore,
@@ -10206,9 +10837,9 @@ function compilePredicate(predicate) {
10206
10837
  return negatePredicate(item);
10207
10838
  }
10208
10839
  case "eq":
10209
- return compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
10840
+ return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, [predicate.value]) : compileEqualityPredicate(predicate.propertyId, "eq", predicate.value);
10210
10841
  case "neq":
10211
- return compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
10842
+ return predicate.scalarKind === "userRef" ? negatePredicate(compileUserRefInPredicate(predicate.propertyId, [predicate.value])) : compileEqualityPredicate(predicate.propertyId, "neq", predicate.value);
10212
10843
  case "lt":
10213
10844
  case "lte":
10214
10845
  case "gt":
@@ -10220,16 +10851,52 @@ function compilePredicate(predicate) {
10220
10851
  };
10221
10852
  }
10222
10853
  case "in":
10223
- return compileInPredicate(predicate.propertyId, predicate.values);
10854
+ return predicate.scalarKind === "userRef" ? compileUserRefInPredicate(predicate.propertyId, predicate.values) : compileInPredicate(predicate.propertyId, predicate.values);
10224
10855
  case "exists": {
10225
10856
  const sql = `${jsonTypeExpression()} IS NOT NULL`;
10226
10857
  const item = { sql, args: [jsonPath(predicate.propertyId)] };
10227
10858
  return predicate.value ? item : negatePredicate(item);
10228
10859
  }
10229
10860
  case "contains":
10230
- return compileContainsPredicate(predicate.propertyId, predicate.value);
10861
+ return predicate.scalarKind === "userRef" ? compileUserRefContainsPredicate(predicate.propertyId, predicate.value) : compileContainsPredicate(predicate.propertyId, predicate.value);
10231
10862
  }
10232
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
+ }
10233
10900
  function negatePredicate(predicate) {
10234
10901
  return {
10235
10902
  sql: `(NOT COALESCE((${predicate.sql}), 0))`,
@@ -10324,7 +10991,7 @@ function compileOrder(fields, qualifier, propertyColumn = "properties") {
10324
10991
  const args = [];
10325
10992
  for (const field of fields) {
10326
10993
  if (field.kind === "column") {
10327
- clauses.push(`${columnExpression(field.column, qualifier)} ${field.direction.toUpperCase()}`);
10994
+ clauses.push(`${columnExpression(field.column, qualifier)}${field.binary ? " COLLATE BINARY" : ""} ${field.direction.toUpperCase()}`);
10328
10995
  continue;
10329
10996
  }
10330
10997
  const direction = field.direction === "desc" ? "DESC" : "ASC";
@@ -10510,6 +11177,8 @@ function isPlainObject(value) {
10510
11177
  }
10511
11178
 
10512
11179
  // src/objects/reader.ts
11180
+ import { ObjectQueryExecutionError as ObjectQueryExecutionError3 } from "@sixb/core";
11181
+ import { hasVectorProfile as hasVectorProfile2 } from "@sixb/core/internal/query";
10513
11182
  import { linkBatchKey, objectBatchKey } from "@sixb/core/storage";
10514
11183
 
10515
11184
  // src/objects/rows.ts
@@ -10526,7 +11195,10 @@ function rowToObject(row) {
10526
11195
  };
10527
11196
  }
10528
11197
  function queryRowToObject(row) {
10529
- const base = rowToObject(row);
11198
+ const base = {
11199
+ ...rowToObject(row),
11200
+ ...row._vector_score === undefined ? {} : { score: row._vector_score }
11201
+ };
10530
11202
  const links = reviveExpandedLinks(parseExpandColumn(row._expand));
10531
11203
  return links ? { ...base, links } : base;
10532
11204
  }
@@ -10589,6 +11261,25 @@ function isPlainObject2(value) {
10589
11261
  return typeof value === "object" && value !== null && !Array.isArray(value);
10590
11262
  }
10591
11263
 
11264
+ // src/objects/vector-extension.ts
11265
+ import { ObjectQueryExecutionError as ObjectQueryExecutionError2 } from "@sixb/core";
11266
+ import { load } from "sqlite-vec";
11267
+ var loaded = new WeakSet;
11268
+ function ensureSqliteVectorSearch(db) {
11269
+ if (loaded.has(db))
11270
+ return;
11271
+ const options = db.query("PRAGMA compile_options").all();
11272
+ if (options.some((option) => option.compile_options === "OMIT_LOAD_EXTENSION")) {
11273
+ throw new ObjectQueryExecutionError2("vector_extension_missing", "SQLite vector search requires extension support. On macOS install SQLite (brew install sqlite), then call Database.setCustomSQLite with its library path before opening any database.");
11274
+ }
11275
+ try {
11276
+ load(db);
11277
+ loaded.add(db);
11278
+ } catch (cause) {
11279
+ throw new Error("[SixbSqlite] Could not load sqlite-vec for vector search. Check that its native package supports your platform.", { cause });
11280
+ }
11281
+ }
11282
+
10592
11283
  // src/objects/reader.ts
10593
11284
  class SqliteObjectReader {
10594
11285
  db;
@@ -10597,7 +11288,21 @@ class SqliteObjectReader {
10597
11288
  this.db = db;
10598
11289
  this.source = source;
10599
11290
  }
11291
+ assertVectorSearch(params) {
11292
+ if (!hasVectorProfile2(params.query))
11293
+ return;
11294
+ const compiled = compileObjectQuery(params.projectId, params.query, { source: this.source });
11295
+ if (!compiled.vectorProbe)
11296
+ return;
11297
+ ensureSqliteVectorSearch(this.db);
11298
+ const probe = compiled.vectorProbe;
11299
+ const row = this.db.query(probe.sql).get(...probe.args);
11300
+ if (Number(row?.total ?? 0) > probe.limit) {
11301
+ throw new ObjectQueryExecutionError3("vector_work_limit_exceeded", `Exact vector search supports at most ${probe.limit} eligible vectors at this dimension. Narrow the query filters.`);
11302
+ }
11303
+ }
10600
11304
  queryObjects(params) {
11305
+ this.assertVectorSearch(params);
10601
11306
  const source = this.source;
10602
11307
  const compiled = compileObjectQuery(params.projectId, params.query, {
10603
11308
  includeTotal: params.includeTotal,
@@ -10615,6 +11320,7 @@ class SqliteObjectReader {
10615
11320
  };
10616
11321
  }
10617
11322
  countObjects(params) {
11323
+ this.assertVectorSearch(params);
10618
11324
  const source = this.source;
10619
11325
  return {
10620
11326
  count: readTotal(this.db, compileObjectQuery(params.projectId, stripOuterRowShape(params.query), {
@@ -10623,6 +11329,7 @@ class SqliteObjectReader {
10623
11329
  };
10624
11330
  }
10625
11331
  existsObjects(params) {
11332
+ this.assertVectorSearch(params);
10626
11333
  const source = this.source;
10627
11334
  const compiled = compileObjectQuery(params.projectId, existsProbeQuery(params.query), {
10628
11335
  source
@@ -10630,6 +11337,7 @@ class SqliteObjectReader {
10630
11337
  return { exists: this.db.query(compiled.sql).get(...compiled.args) !== null };
10631
11338
  }
10632
11339
  facetObjects(params) {
11340
+ this.assertVectorSearch(params);
10633
11341
  const source = this.source;
10634
11342
  const compiled = compileObjectQuery(params.projectId, stripOuterRowShape(params.query), {
10635
11343
  source
@@ -10919,6 +11627,9 @@ function sqliteFacetValue(valueType, value) {
10919
11627
  return false;
10920
11628
  if (valueType === "null")
10921
11629
  return null;
11630
+ if ((valueType === "object" || valueType === "array") && typeof value === "string") {
11631
+ return JSON.parse(value);
11632
+ }
10922
11633
  return value;
10923
11634
  }
10924
11635
  function existsProbeQuery(query) {
@@ -10966,6 +11677,7 @@ ${sql}`,
10966
11677
  wrapQuery: (query) => ({
10967
11678
  ...query,
10968
11679
  ...wrapStatement(query.sql, query.args),
11680
+ vectorProbe: query.vectorProbe ? { ...query.vectorProbe, ...wrapStatement(query.vectorProbe.sql, query.vectorProbe.args) } : undefined,
10969
11681
  totalSql: `${compiled.sql}
10970
11682
  ${query.totalSql}`,
10971
11683
  totalArgs: [...compiled.args, ...query.totalArgs],
@@ -11052,16 +11764,16 @@ function compileSelectedReadScopeCte(scopeJson, projectId) {
11052
11764
 
11053
11765
  SELECT edge.project_id, selection.node_id, edge.target_type_id, edge.target_id
11054
11766
  FROM _sixb_scope_reachable AS parent
11055
- JOIN _sixb_scope_link_selections AS selection
11767
+ CROSS JOIN _sixb_scope_link_selections AS selection
11056
11768
  ON selection.parent_node_id = parent.node_id
11057
11769
  AND selection.source_object_type_id = parent.object_type_id
11058
- JOIN links AS edge
11770
+ CROSS JOIN links AS edge
11059
11771
  ON edge.project_id = parent.project_id
11060
11772
  AND edge.source_type_id = parent.object_type_id
11061
11773
  AND edge.source_id = parent.primary_id
11062
11774
  AND edge.link_id = selection.link_id
11063
11775
  AND edge.target_type_id = selection.target_object_type_id
11064
- JOIN objects AS target
11776
+ CROSS JOIN objects AS target
11065
11777
  ON target.project_id = edge.project_id
11066
11778
  AND target.object_type_id = edge.target_type_id
11067
11779
  AND target.primary_id = edge.target_id
@@ -11082,32 +11794,29 @@ function compileSelectedReadScopeCte(scopeJson, projectId) {
11082
11794
  SELECT DISTINCT project_id, object_type_id, primary_id
11083
11795
  FROM _sixb_scope_reachable
11084
11796
  ),
11797
+ _sixb_scope_object_grants AS (
11798
+ SELECT reachable.project_id, reachable.object_type_id, reachable.primary_id,
11799
+ json_group_array(DISTINCT selected_property.value) FILTER (WHERE selected_property.value IS NOT NULL) AS property_ids
11800
+ FROM _sixb_scope_reachable AS reachable
11801
+ LEFT JOIN _sixb_scope_object_selections AS selection
11802
+ ON selection.node_id = reachable.node_id
11803
+ AND selection.object_type_id = reachable.object_type_id
11804
+ LEFT JOIN json_each(selection.property_ids) AS selected_property ON true
11805
+ GROUP BY reachable.project_id, reachable.object_type_id, reachable.primary_id
11806
+ ),
11085
11807
  _sixb_scope_objects AS (
11086
- SELECT
11087
- stored.project_id,
11088
- stored.object_type_id,
11089
- stored.primary_id,
11090
- COALESCE(
11091
- (
11092
- SELECT json_group_object(property.key, ${sqliteJsonEachValue("property")})
11093
- FROM json_each(stored.properties) AS property
11094
- JOIN _sixb_scope_object_permissions AS permission
11095
- ON permission.project_id = stored.project_id
11096
- AND permission.object_type_id = stored.object_type_id
11097
- AND permission.primary_id = stored.primary_id
11098
- AND permission.property_id = property.key
11099
- ),
11100
- json('{}')
11101
- ) AS properties,
11102
- stored.created_at,
11103
- stored.updated_at,
11104
- stored.version,
11105
- stored.last_commit_id
11106
- FROM objects AS stored
11107
- JOIN _sixb_scope_object_ids AS visible
11108
- ON visible.project_id = stored.project_id
11109
- AND visible.object_type_id = stored.object_type_id
11110
- AND visible.primary_id = stored.primary_id
11808
+ SELECT stored.project_id, stored.object_type_id, stored.primary_id,
11809
+ COALESCE((
11810
+ SELECT json_group_object(property.key, ${sqliteJsonEachValue("property")})
11811
+ FROM json_each(stored.properties) AS property
11812
+ WHERE property.key IN (SELECT value FROM json_each(grants.property_ids))
11813
+ ), json('{}')) AS properties,
11814
+ stored.created_at, stored.updated_at, stored.version, stored.last_commit_id
11815
+ FROM _sixb_scope_object_grants AS grants
11816
+ CROSS JOIN objects AS stored
11817
+ ON stored.project_id = grants.project_id
11818
+ AND stored.object_type_id = grants.object_type_id
11819
+ AND stored.primary_id = grants.primary_id
11111
11820
  ),
11112
11821
  _sixb_scope_reached_links(
11113
11822
  project_id,
@@ -11133,16 +11842,16 @@ function compileSelectedReadScopeCte(scopeJson, projectId) {
11133
11842
  edge.target_id,
11134
11843
  selection.property_ids
11135
11844
  FROM _sixb_scope_reachable AS parent
11136
- JOIN _sixb_scope_link_selections AS selection
11845
+ CROSS JOIN _sixb_scope_link_selections AS selection
11137
11846
  ON selection.parent_node_id = parent.node_id
11138
11847
  AND selection.source_object_type_id = parent.object_type_id
11139
- JOIN links AS edge
11848
+ CROSS JOIN links AS edge
11140
11849
  ON edge.project_id = parent.project_id
11141
11850
  AND edge.source_type_id = parent.object_type_id
11142
11851
  AND edge.source_id = parent.primary_id
11143
11852
  AND edge.link_id = selection.link_id
11144
11853
  AND edge.target_type_id = selection.target_object_type_id
11145
- JOIN objects AS target
11854
+ CROSS JOIN objects AS target
11146
11855
  ON target.project_id = edge.project_id
11147
11856
  AND target.object_type_id = edge.target_type_id
11148
11857
  AND target.primary_id = edge.target_id
@@ -11314,6 +12023,7 @@ var SQLITE_OBJECT_QUERY_CAPABILITIES = {
11314
12023
  refs: true,
11315
12024
  filter: true,
11316
12025
  text: true,
12026
+ vector: true,
11317
12027
  sort: true,
11318
12028
  limit: true,
11319
12029
  page: true,
@@ -11356,7 +12066,8 @@ var SQLITE_OBJECT_QUERY_CAPABILITIES = {
11356
12066
  double: { equality: true, ordering: true },
11357
12067
  decimal: { equality: true },
11358
12068
  date: { equality: true, ordering: true },
11359
- timestamp: { equality: true, ordering: true }
12069
+ timestamp: { equality: true, ordering: true },
12070
+ userRef: { equality: true }
11360
12071
  },
11361
12072
  limits: {
11362
12073
  totalCount: true,
@@ -11366,7 +12077,7 @@ var SQLITE_OBJECT_QUERY_CAPABILITIES = {
11366
12077
  "SQLite object query pushdown supports start/refs/filter/text/sort/limit/page/traverse/set/project/expand over JSON properties and object links.",
11367
12078
  "expand hydrates linked objects in-database (top-N per parent via row_number() + json_group_array); core resolves each expansion's cardinality before pushdown, and a mixed/unresolved one stays on the fallback.",
11368
12079
  "Ordered decimal predicates and sorting use the bounded core fallback because SQLite has no native exact decimal type; canonical decimal equality remains pushdown-safe.",
11369
- "Relevance sorting, vector search, and unresolved start.includeSubtypes remain planner fallback or rejection cases."
12080
+ "Relevance sorting and unresolved start.includeSubtypes remain planner fallback or rejection cases."
11370
12081
  ]
11371
12082
  };
11372
12083
 
@@ -11389,15 +12100,23 @@ class SqliteObjectStorage {
11389
12100
  return createSqliteSelectedReader(this.db, params, () => this.queryCapabilities());
11390
12101
  }
11391
12102
  async queryObjects(params) {
12103
+ if (hasVectorProfile3(params.query))
12104
+ return runDeferredReadTransaction(this.db, () => this.reader.queryObjects(params));
11392
12105
  return this.reader.queryObjects(params);
11393
12106
  }
11394
12107
  async countObjects(params) {
12108
+ if (hasVectorProfile3(params.query))
12109
+ return runDeferredReadTransaction(this.db, () => this.reader.countObjects(params));
11395
12110
  return this.reader.countObjects(params);
11396
12111
  }
11397
12112
  async existsObjects(params) {
12113
+ if (hasVectorProfile3(params.query))
12114
+ return runDeferredReadTransaction(this.db, () => this.reader.existsObjects(params));
11398
12115
  return this.reader.existsObjects(params);
11399
12116
  }
11400
12117
  async facetObjects(params) {
12118
+ if (hasVectorProfile3(params.query))
12119
+ return runDeferredReadTransaction(this.db, () => this.reader.facetObjects(params));
11401
12120
  return this.reader.facetObjects(params);
11402
12121
  }
11403
12122
  async getByPrimaryId(params) {
@@ -11542,7 +12261,10 @@ function commitRecord(row) {
11542
12261
  requestHash: row.request_hash,
11543
12262
  executionId: row.execution_id,
11544
12263
  origin: parseJson2(row.origin),
11545
- ...row.actor === null ? {} : { actor: parseJson2(row.actor) },
12264
+ ...row.requested_by === null ? {} : {
12265
+ requestedBy: parseJson2(row.requested_by)
12266
+ },
12267
+ executor: parseJson2(row.executor),
11546
12268
  ontologyRevision: row.ontology_revision,
11547
12269
  ...row.projection_revision === null ? {} : { projectionRevision: row.projection_revision },
11548
12270
  ...row.ownership_hash === null ? {} : { ownershipHash: row.ownership_hash },
@@ -11689,12 +12411,16 @@ import {
11689
12411
  linkRefSortKey,
11690
12412
  linkScopeSortKey as linkScopeSortKey2,
11691
12413
  MaterializationConflictError as MaterializationConflictError6,
12414
+ MaterializationValidationError as MaterializationValidationError2,
11692
12415
  objectRefKey as objectRefKey3,
11693
12416
  objectRefSortKey,
11694
12417
  telemetryPointKey as telemetryPointKey2,
11695
12418
  telemetryPointSortKey as telemetryPointSortKey2
11696
12419
  } from "@sixb/core/internal/materialization";
11697
12420
  import {
12421
+ assertExpectedLinkRevision,
12422
+ assertExpectedLinkScopeRevision,
12423
+ assertExpectedObjectRevision,
11698
12424
  assertMaterializationFinalizationCorrelation,
11699
12425
  assertMaterializationHeader,
11700
12426
  assertMaterializationLaneCompletion,
@@ -13176,6 +13902,12 @@ class SqliteOntologyMaterializationStorage {
13176
13902
  this.sessions = new SqliteMaterializationSessions(db, context);
13177
13903
  this.writer = new SqliteMaterializationWriter(db);
13178
13904
  }
13905
+ assertVectorSession(session, projectId, commitId) {
13906
+ const active = this.sessions.require(session);
13907
+ if (active.header.commit.projectId !== projectId || commitId !== undefined && active.header.commit.id !== commitId) {
13908
+ throw new MaterializationValidationError2("Vector mutation does not belong to this materialization session.");
13909
+ }
13910
+ }
13179
13911
  async begin(input) {
13180
13912
  assertMaterializationHeader(input);
13181
13913
  const session = this.sessions.create(input);
@@ -13184,15 +13916,15 @@ class SqliteOntologyMaterializationStorage {
13184
13916
  const reader = new SqliteMaterializationStateReader(this.db, input.commit.projectId);
13185
13917
  for (const expected of input.expected.sources)
13186
13918
  this.assertSource(expected, input.commit.projectId);
13187
- for (const expected of input.expected.objects)
13188
- this.assertObject(reader, expected);
13189
- for (const expected of input.expected.links)
13190
- this.assertLink(reader, expected);
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
+ }
13191
13925
  const linkScopeRevisions = reader.linkScopeRevisions(input.expected.linkScopes);
13192
13926
  for (const [index, expected] of input.expected.linkScopes.entries()) {
13193
- if (linkScopeRevisions[index]?.fingerprint !== expected.fingerprint) {
13194
- throw new MaterializationConflictError6("effective-state", `Expected link scope changed for ${expected.source.objectTypeId}:${expected.source.primaryId}.${expected.linkId}.`);
13195
- }
13927
+ assertExpectedLinkScopeRevision(linkScopeRevisions[index]?.fingerprint, expected);
13196
13928
  }
13197
13929
  for (const expected of input.expected.points) {
13198
13930
  const point = reader.exactPoint(expected.series, expected.at);
@@ -13425,30 +14157,6 @@ class SqliteOntologyMaterializationStorage {
13425
14157
  throw new MaterializationConflictError6("projection-fence", `Source '${expected.source.projectionId}' changed.`);
13426
14158
  }
13427
14159
  }
13428
- assertObject(reader, expected) {
13429
- const row = reader.effectiveObjectRevision(expected.ref);
13430
- if (!expected.exists) {
13431
- if (row) {
13432
- throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} to be absent.`);
13433
- }
13434
- return;
13435
- }
13436
- if (!row || row.version !== expected.version || row.lastCommitId !== expected.lastCommitId) {
13437
- throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} changed.`);
13438
- }
13439
- }
13440
- assertLink(reader, expected) {
13441
- const lastCommitId = reader.effectiveLinkLastCommit(expected.ref);
13442
- if (!expected.exists) {
13443
- if (lastCommitId !== undefined) {
13444
- throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} to be absent.`);
13445
- }
13446
- return;
13447
- }
13448
- if (lastCommitId === undefined || lastCommitId !== expected.lastCommitId) {
13449
- throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} changed.`);
13450
- }
13451
- }
13452
14160
  async assertFinalization(session, input) {
13453
14161
  const { commit } = session.header;
13454
14162
  const { result } = input.finalization;
@@ -13585,11 +14293,13 @@ class SqliteOntologyMaterializationStorage {
13585
14293
  this.db.query(`
13586
14294
  INSERT INTO ontology_commits (
13587
14295
  project_id, id, idempotency_key, request_hash, execution_id,
13588
- origin_kind, origin_run_id, origin_batch_ordinal, origin, actor,
14296
+ origin_kind, origin_run_id, origin_batch_ordinal, origin, requested_by, executor,
13589
14297
  ontology_revision, projection_revision, ownership_hash,
13590
14298
  intent, result, committed_at
13591
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, json(?), json(?), ?, ?, ?, json(?), json(?), ?)
13592
- `).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);
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);
13593
14303
  } catch (error) {
13594
14304
  if (isSqliteConstraintError(error)) {
13595
14305
  throw new MaterializationConflictError6("idempotency", "Ontology commit identity already exists.");
@@ -13613,7 +14323,7 @@ class SqliteOntologyMaterializationStorage {
13613
14323
  import { serializeSixbFailure as serializeSixbFailure2 } from "@sixb/core/internal/errors";
13614
14324
  import {
13615
14325
  MaterializationConflictError as MaterializationConflictError7,
13616
- MaterializationValidationError as MaterializationValidationError2
14326
+ MaterializationValidationError as MaterializationValidationError3
13617
14327
  } from "@sixb/core/internal/materialization";
13618
14328
  import { ONTOLOGY_OUTBOX_FAILURE_CODES as ONTOLOGY_OUTBOX_FAILURE_CODES2 } from "@sixb/core/storage";
13619
14329
  class SqliteOntologyOutboxStorage {
@@ -13631,7 +14341,7 @@ class SqliteOntologyOutboxStorage {
13631
14341
  const leaseExpiry = assertTimestamp(input.leaseExpiresAt, "Ontology outbox lease expiry");
13632
14342
  assertNonblank(input.leaseId, "Ontology outbox lease id");
13633
14343
  if (leaseExpiry <= now) {
13634
- throw new MaterializationValidationError2("Ontology outbox lease expiry must be later than the claim time.");
14344
+ throw new MaterializationValidationError3("Ontology outbox lease expiry must be later than the claim time.");
13635
14345
  }
13636
14346
  const eligible = this.db.query(`SELECT CAST(rowid AS TEXT) AS rowId
13637
14347
  FROM ontology_outbox INDEXED BY idx_ontology_outbox_claim
@@ -13756,7 +14466,7 @@ function validateLeaseIds(ids) {
13756
14466
  for (const id of ids) {
13757
14467
  assertNonblank(id, "Ontology outbox event id");
13758
14468
  if (seen.has(id)) {
13759
- throw new MaterializationValidationError2(`Ontology outbox lease batch repeats event '${id}'.`);
14469
+ throw new MaterializationValidationError3(`Ontology outbox lease batch repeats event '${id}'.`);
13760
14470
  }
13761
14471
  seen.add(id);
13762
14472
  }
@@ -13771,7 +14481,7 @@ function leaseConflict() {
13771
14481
  }
13772
14482
 
13773
14483
  // src/ontology-storage/sources.ts
13774
- import { MaterializationValidationError as MaterializationValidationError3 } from "@sixb/core/internal/materialization";
14484
+ import { MaterializationValidationError as MaterializationValidationError4 } from "@sixb/core/internal/materialization";
13775
14485
  import {
13776
14486
  assertSourceBeginInput as assertBeginInput,
13777
14487
  assertSourceExecutionIdentity as assertExecutionIdentity,
@@ -13911,7 +14621,7 @@ class SqliteOntologySourceStorage {
13911
14621
  throw sourceConflict(`Source materialization '${input.materializationId}' cannot transition from '${manifest.status}' to 'ready'.`);
13912
14622
  }
13913
14623
  if (input.readyAt < manifest.created_at) {
13914
- throw new MaterializationValidationError3("Source readyAt cannot precede source createdAt.");
14624
+ throw new MaterializationValidationError4("Source readyAt cannot precede source createdAt.");
13915
14625
  }
13916
14626
  this.assertReadyState(manifest, input.rootCount, input.assertionCount);
13917
14627
  const result = this.db.query(`
@@ -13994,7 +14704,7 @@ class SqliteOntologySourceStorage {
13994
14704
  }
13995
14705
  transitionToAbandoned(manifest, abandonedAt) {
13996
14706
  if (abandonedAt < manifest.created_at || manifest.ready_at !== null && abandonedAt < manifest.ready_at) {
13997
- throw new MaterializationValidationError3("Source abandonedAt cannot precede source creation or readiness.");
14707
+ throw new MaterializationValidationError4("Source abandonedAt cannot precede source creation or readiness.");
13998
14708
  }
13999
14709
  const changed = this.db.query(`
14000
14710
  UPDATE ontology_sources
@@ -14019,7 +14729,7 @@ class SqliteOntologySourceStorage {
14019
14729
  WHERE project_id = ? AND source_id = ? AND materialization_id = ?
14020
14730
  `).get(manifest.project_id, manifest.source_id, manifest.materialization_id, manifest.project_id, manifest.source_id, manifest.materialization_id);
14021
14731
  if (counts.assertions !== assertionCount || counts.roots !== rootCount || counts.ordinals !== rootCount || rootCount > 0 && (counts.min_ordinal !== 0 || counts.max_ordinal !== rootCount - 1)) {
14022
- throw new MaterializationValidationError3("Source ready counts do not match the staged roots and assertions.");
14732
+ throw new MaterializationValidationError4("Source ready counts do not match the staged roots and assertions.");
14023
14733
  }
14024
14734
  assertSourceRootCoverage(this.db, manifest);
14025
14735
  const invalid = this.db.query(manifest.projection_kind === "link" ? `
@@ -14047,7 +14757,7 @@ class SqliteOntologySourceStorage {
14047
14757
  LIMIT 1
14048
14758
  `).get(manifest.project_id, manifest.source_id, manifest.materialization_id);
14049
14759
  if (invalid) {
14050
- throw new MaterializationValidationError3(manifest.projection_kind === "link" ? "Link projection roots must contain exactly their matching link assertion." : "Object projection roots must contain exactly their matching object assertion plus links sourced from that root.");
14760
+ throw new MaterializationValidationError4(manifest.projection_kind === "link" ? "Link projection roots must contain exactly their matching link assertion." : "Object projection roots must contain exactly their matching object assertion plus links sourced from that root.");
14051
14761
  }
14052
14762
  }
14053
14763
  findStageRows(input, rows) {
@@ -14153,16 +14863,228 @@ class SqliteOntologySourceStorage {
14153
14863
  }
14154
14864
  }
14155
14865
 
14866
+ // src/ontology-storage/vector-indexing.ts
14867
+ import { parseSixbFailure as parseSixbFailure3 } from "@sixb/core/internal/errors";
14868
+ import {
14869
+ VECTOR_INDEXING_FAILURE_CODES
14870
+ } from "@sixb/core/storage";
14871
+
14872
+ class SqliteVectorIndexingStorage {
14873
+ db;
14874
+ run;
14875
+ assertSession;
14876
+ constructor(db, run, assertSession) {
14877
+ this.db = db;
14878
+ this.run = run;
14879
+ this.assertSession = assertSession;
14880
+ }
14881
+ async schedule(input) {
14882
+ this.assertSession(input.session, input.projectId);
14883
+ for (const ref of input.deleted)
14884
+ this.db.query(`DELETE FROM object_vector_indexing WHERE project_id = ? AND object_type_id = ? AND primary_id = ?`).run(input.projectId, ref.objectTypeId, ref.primaryId);
14885
+ const insert = this.db.query(`INSERT INTO object_vector_indexing (project_id, id, object_type_id, primary_id, profile, batch_id, request, status, available_at, dispatch_at)
14886
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
14887
+ ON CONFLICT (project_id, object_type_id, primary_id, profile) DO UPDATE SET id = excluded.id, batch_id = excluded.batch_id, request = excluded.request, status = 'pending', available_at = excluded.available_at, dispatch_at = excluded.dispatch_at, values_json = NULL, error = NULL`);
14888
+ for (const { batchId, ...request } of input.requests)
14889
+ insert.run(input.projectId, request.id, request.ref.objectTypeId, request.ref.primaryId, request.profile, batchId ?? null, JSON.stringify(request), input.availableAt, input.availableAt);
14890
+ }
14891
+ async complete(input) {
14892
+ this.assertSession(input.session, input.projectId);
14893
+ const remove = this.db.query(`DELETE FROM object_vector_indexing WHERE project_id = ? AND object_type_id = ? AND primary_id = ? AND profile = ? AND json_extract(request, '$.configuration') = ? AND json_extract(request, '$.sourceFingerprint') = ?`);
14894
+ for (const entry of input.entries) {
14895
+ remove.run(input.projectId, entry.ref.objectTypeId, entry.ref.primaryId, entry.profile, entry.configuration, entry.sourceFingerprint);
14896
+ }
14897
+ }
14898
+ async dispatched(input) {
14899
+ await this.run(() => {
14900
+ const update = this.db.query(`UPDATE object_vector_indexing SET dispatch_at = ? WHERE project_id = ? AND id = ?`);
14901
+ for (const id of input.ids)
14902
+ update.run(input.nextDispatchAt, input.projectId, id);
14903
+ });
14904
+ }
14905
+ async get(input) {
14906
+ return this.run(() => {
14907
+ const row = this.db.query(`SELECT batch_id, request, status, available_at, values_json, error FROM object_vector_indexing WHERE project_id = ? AND id = ?`).get(input.projectId, input.id);
14908
+ return row ? decode(row) : null;
14909
+ });
14910
+ }
14911
+ async getBatch(input) {
14912
+ return this.run(() => this.db.query(`
14913
+ SELECT batch_id, request, status, available_at, values_json, error FROM object_vector_indexing
14914
+ WHERE project_id = ? AND batch_id = ? ORDER BY id`).all(input.projectId, input.batchId).map(decode));
14915
+ }
14916
+ async getBatchMember(input) {
14917
+ return this.run(() => {
14918
+ const row = this.db.query(`
14919
+ SELECT batch_id, request, status, available_at, values_json, error
14920
+ FROM object_vector_indexing WHERE project_id = ? AND object_type_id = ?
14921
+ AND primary_id = ? AND profile = ? AND batch_id = ?`).get(input.projectId, input.ref.objectTypeId, input.ref.primaryId, input.profile, input.batchId);
14922
+ return row ? decode(row) : null;
14923
+ });
14924
+ }
14925
+ async updateBatch(input) {
14926
+ return this.run(() => this.db.transaction(() => {
14927
+ const status = this.db.query("SELECT status FROM object_vector_indexing WHERE project_id = ? AND id = ?");
14928
+ if (input.requireAll && input.updates.some((update) => status.get(input.projectId, update.id)?.status !== update.expectedStatus))
14929
+ return false;
14930
+ const updateRow = this.db.query(`UPDATE object_vector_indexing
14931
+ SET status = ?, available_at = ?, values_json = COALESCE(?, values_json), error = ?
14932
+ WHERE project_id = ? AND id = ? AND status = ?`);
14933
+ for (const update of input.updates)
14934
+ updateRow.run(update.status, update.availableAt, update.values ? JSON.stringify(update.values) : null, update.error ? JSON.stringify(update.error) : null, input.projectId, update.id, update.expectedStatus);
14935
+ return true;
14936
+ })());
14937
+ }
14938
+ async listDue(input) {
14939
+ return this.run(() => this.db.query(`SELECT batch_id, request, status, available_at, NULL AS values_json, error FROM object_vector_indexing WHERE project_id = ? AND status <> 'failed' AND dispatch_at <= ? ORDER BY dispatch_at, id LIMIT ?`).all(input.projectId, input.now, input.limit).map(decode));
14940
+ }
14941
+ async update(input) {
14942
+ return this.run(() => this.db.query(`UPDATE object_vector_indexing SET status = ?, available_at = ?, values_json = COALESCE(?, values_json), error = ? WHERE project_id = ? AND id = ? AND status = ?`).run(input.status, input.availableAt, input.values ? JSON.stringify(input.values) : null, input.error ? JSON.stringify(input.error) : null, input.projectId, input.id, input.expectedStatus).changes === 1);
14943
+ }
14944
+ async remove(input) {
14945
+ await this.run(() => {
14946
+ this.db.query(`DELETE FROM object_vector_indexing WHERE project_id = ? AND id = ?`).run(input.projectId, input.id);
14947
+ });
14948
+ }
14949
+ }
14950
+ function decode(row) {
14951
+ const request = JSON.parse(row.request);
14952
+ return {
14953
+ ...request,
14954
+ ...row.batch_id ? { batchId: row.batch_id } : {},
14955
+ status: row.status,
14956
+ availableAt: row.available_at,
14957
+ ...row.values_json ? { values: JSON.parse(row.values_json) } : {},
14958
+ ...row.error ? {
14959
+ error: parseSixbFailure3(row.error, VECTOR_INDEXING_FAILURE_CODES)
14960
+ } : {}
14961
+ };
14962
+ }
14963
+
14964
+ // src/ontology-storage/vectors.ts
14965
+ import { MaterializationConflictError as MaterializationConflictError8 } from "@sixb/core/internal/materialization";
14966
+ class SqliteOntologyVectorStorage {
14967
+ db;
14968
+ runRootOperation;
14969
+ assertSession;
14970
+ constructor(db, runRootOperation, assertSession) {
14971
+ this.db = db;
14972
+ this.runRootOperation = runRootOperation;
14973
+ this.assertSession = assertSession;
14974
+ }
14975
+ async list(input) {
14976
+ return this.runRootOperation(() => {
14977
+ const rows = this.db.query(`
14978
+ SELECT profile, configuration, source, source_fingerprint, last_commit_id
14979
+ FROM object_vectors
14980
+ WHERE project_id = ? AND object_type_id = ? AND primary_id = ?
14981
+ ORDER BY profile
14982
+ `).all(input.projectId, input.ref.objectTypeId, input.ref.primaryId);
14983
+ return rows.map((row) => ({
14984
+ ref: { ...input.ref },
14985
+ profile: row.profile,
14986
+ configuration: row.configuration,
14987
+ source: JSON.parse(row.source),
14988
+ sourceFingerprint: row.source_fingerprint,
14989
+ lastCommitId: row.last_commit_id
14990
+ }));
14991
+ });
14992
+ }
14993
+ async listBatch(input) {
14994
+ if (!input.refs.length)
14995
+ return [];
14996
+ return this.runRootOperation(() => {
14997
+ const rows = this.db.query(`
14998
+ WITH requested AS (
14999
+ SELECT DISTINCT json_extract(value, '$.objectTypeId') AS object_type_id,
15000
+ json_extract(value, '$.primaryId') AS primary_id FROM json_each(?)
15001
+ )
15002
+ SELECT stored.object_type_id, stored.primary_id, stored.profile, stored.configuration,
15003
+ stored.source, stored.source_fingerprint, stored.last_commit_id
15004
+ FROM requested CROSS JOIN object_vectors AS stored
15005
+ WHERE stored.project_id = ? AND stored.object_type_id = requested.object_type_id
15006
+ AND stored.primary_id = requested.primary_id
15007
+ ORDER BY stored.object_type_id, stored.primary_id, stored.profile
15008
+ `).all(JSON.stringify(input.refs), input.projectId);
15009
+ return rows.map((row) => ({
15010
+ ref: { objectTypeId: row.object_type_id, primaryId: row.primary_id },
15011
+ profile: row.profile,
15012
+ configuration: row.configuration,
15013
+ source: JSON.parse(row.source),
15014
+ sourceFingerprint: row.source_fingerprint,
15015
+ lastCommitId: row.last_commit_id
15016
+ }));
15017
+ });
15018
+ }
15019
+ async removeBatch(input) {
15020
+ this.assertSession(input.session, input.projectId);
15021
+ if (!input.entries.length)
15022
+ return;
15023
+ const { changes } = this.db.query(`
15024
+ DELETE FROM object_vectors WHERE rowid IN (
15025
+ SELECT stored.rowid FROM json_each(?) AS requested CROSS JOIN object_vectors AS stored
15026
+ WHERE stored.project_id = ? AND stored.object_type_id = json_extract(requested.value, '$.ref.objectTypeId')
15027
+ AND stored.primary_id = json_extract(requested.value, '$.ref.primaryId')
15028
+ AND stored.profile = json_extract(requested.value, '$.profile')
15029
+ AND stored.last_commit_id = json_extract(requested.value, '$.expectedCommitId')
15030
+ )
15031
+ `).run(JSON.stringify(input.entries), input.projectId);
15032
+ if (changes !== input.entries.length)
15033
+ throw vectorConflict();
15034
+ }
15035
+ async write(input) {
15036
+ const { value } = input;
15037
+ this.assertSession(input.session, input.projectId, value.lastCommitId);
15038
+ const embedding = encodeSqliteVector(value.values);
15039
+ const changes = input.expectedCommitId === null ? this.db.query(`
15040
+ INSERT INTO object_vectors (
15041
+ project_id, object_type_id, primary_id, profile,
15042
+ configuration, source, source_fingerprint, embedding, last_commit_id
15043
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
15044
+ ON CONFLICT (project_id, object_type_id, primary_id, profile) DO NOTHING
15045
+ `).run(input.projectId, value.ref.objectTypeId, value.ref.primaryId, value.profile, value.configuration, JSON.stringify(value.source), value.sourceFingerprint, embedding, value.lastCommitId).changes : this.db.query(`
15046
+ UPDATE object_vectors
15047
+ SET configuration = ?, source = ?, source_fingerprint = ?, embedding = ?, last_commit_id = ?
15048
+ WHERE project_id = ? AND object_type_id = ? AND primary_id = ?
15049
+ AND profile = ? AND last_commit_id = ?
15050
+ `).run(value.configuration, JSON.stringify(value.source), value.sourceFingerprint, embedding, value.lastCommitId, input.projectId, value.ref.objectTypeId, value.ref.primaryId, value.profile, input.expectedCommitId).changes;
15051
+ if (changes !== 1)
15052
+ throw vectorConflict();
15053
+ }
15054
+ async writeBatch(input) {
15055
+ for (const entry of input.entries) {
15056
+ await this.write({ session: input.session, projectId: input.projectId, ...entry });
15057
+ }
15058
+ }
15059
+ async remove(input) {
15060
+ this.assertSession(input.session, input.projectId);
15061
+ const { changes } = this.db.query(`
15062
+ DELETE FROM object_vectors
15063
+ WHERE project_id = ? AND object_type_id = ? AND primary_id = ?
15064
+ AND profile = ? AND last_commit_id = ?
15065
+ `).run(input.projectId, input.ref.objectTypeId, input.ref.primaryId, input.profile, input.expectedCommitId);
15066
+ if (changes !== 1)
15067
+ throw vectorConflict();
15068
+ }
15069
+ }
15070
+ function vectorConflict() {
15071
+ return new MaterializationConflictError8("effective-state", "Vector changed since it was prepared.");
15072
+ }
15073
+
14156
15074
  // src/ontology-storage/index.ts
14157
15075
  class SqliteOntologyStorage {
14158
15076
  commits;
14159
15077
  sources;
14160
15078
  materializations;
15079
+ vectorIndexing;
15080
+ vectors;
14161
15081
  outbox;
14162
15082
  constructor(input) {
14163
15083
  this.commits = new SqliteOntologyCommitStorage(input.db, input.runRootOperation);
14164
15084
  this.sources = new SqliteOntologySourceStorage(input.db, input.runRootOperation);
14165
15085
  this.materializations = new SqliteOntologyMaterializationStorage(input.db, input.transactionContext);
15086
+ this.vectorIndexing = new SqliteVectorIndexingStorage(input.db, input.runRootOperation, (session, projectId) => this.materializations.assertVectorSession(session, projectId));
15087
+ this.vectors = new SqliteOntologyVectorStorage(input.db, input.runRootOperation, (session, projectId, commitId) => this.materializations.assertVectorSession(session, projectId, commitId));
14166
15088
  this.outbox = new SqliteOntologyOutboxStorage(input.db, input.runRootOperation);
14167
15089
  }
14168
15090
  deactivateSessions() {
@@ -14171,7 +15093,7 @@ class SqliteOntologyStorage {
14171
15093
  }
14172
15094
 
14173
15095
  // src/pipeline-run-storage.ts
14174
- import { parseSixbFailure as parseSixbFailure3, serializeSixbFailure as serializeSixbFailure3 } from "@sixb/core/internal/errors";
15096
+ import { parseSixbFailure as parseSixbFailure4, serializeSixbFailure as serializeSixbFailure3 } from "@sixb/core/internal/errors";
14175
15097
  import { assertPipelineRunExecution } from "@sixb/core/internal/pipeline-run-storage-provider";
14176
15098
  import { canRequeuePipelineRunAfterEnqueueFailure } from "@sixb/core/internal/storage";
14177
15099
  import { PIPELINE_RUN_FAILURE_CODES, PipelineRunError } from "@sixb/core/storage";
@@ -14493,7 +15415,7 @@ function rowToPipelineRunRecord(row) {
14493
15415
  datasetId: row.output_dataset_id,
14494
15416
  versionId: row.output_version_id
14495
15417
  } : undefined,
14496
- error: row.error === null ? undefined : parseSixbFailure3(row.error, PIPELINE_RUN_FAILURE_CODES)
15418
+ error: row.error === null ? undefined : parseSixbFailure4(row.error, PIPELINE_RUN_FAILURE_CODES)
14497
15419
  };
14498
15420
  }
14499
15421
  function rowToPipelineStepRunRecord(row) {
@@ -14514,7 +15436,7 @@ function rowToPipelineStepRunRecord(row) {
14514
15436
  versionId: row.output_version_id
14515
15437
  } : undefined,
14516
15438
  rowsWritten: row.rows_written ?? undefined,
14517
- error: row.error === null ? undefined : parseSixbFailure3(row.error, PIPELINE_RUN_FAILURE_CODES)
15439
+ error: row.error === null ? undefined : parseSixbFailure4(row.error, PIPELINE_RUN_FAILURE_CODES)
14518
15440
  };
14519
15441
  }
14520
15442
  function assertOptionalNonNegativeInteger(value, fieldName) {
@@ -15459,7 +16381,7 @@ function invalidRecord2(message) {
15459
16381
  }
15460
16382
 
15461
16383
  // src/sync-run-storage.ts
15462
- import { parseSixbFailure as parseSixbFailure4, serializeSixbFailure as serializeSixbFailure5 } from "@sixb/core/internal/errors";
16384
+ import { parseSixbFailure as parseSixbFailure5, serializeSixbFailure as serializeSixbFailure5 } from "@sixb/core/internal/errors";
15463
16385
  import { canRequeueSyncRunAfterEnqueueFailure } from "@sixb/core/internal/storage";
15464
16386
  import { assertSyncRunExecution } from "@sixb/core/internal/sync-run-storage-provider";
15465
16387
  import { SYNC_RUN_FAILURE_CODES, SyncRunError } from "@sixb/core/storage";
@@ -15662,7 +16584,7 @@ function rowToSyncRunRecord(row) {
15662
16584
  } : undefined,
15663
16585
  expectedLatestVersionId: row.expected_latest_version_id ?? undefined,
15664
16586
  commitMessage: row.commit_message ?? undefined,
15665
- error: row.error === null ? undefined : parseSixbFailure4(row.error, SYNC_RUN_FAILURE_CODES),
16587
+ error: row.error === null ? undefined : parseSixbFailure5(row.error, SYNC_RUN_FAILURE_CODES),
15666
16588
  checkpoint: parseCheckpoint(row.checkpoint)
15667
16589
  };
15668
16590
  }
@@ -15803,7 +16725,7 @@ class SqliteTimeseriesStorage {
15803
16725
  }
15804
16726
 
15805
16727
  // src/webhook-run-storage.ts
15806
- import { parseSixbFailure as parseSixbFailure5, serializeSixbFailure as serializeSixbFailure6 } from "@sixb/core/internal/errors";
16728
+ import { parseSixbFailure as parseSixbFailure6, serializeSixbFailure as serializeSixbFailure6 } from "@sixb/core/internal/errors";
15807
16729
  import { assertWebhookRunExecution } from "@sixb/core/internal/webhook-run-storage-provider";
15808
16730
  import { canRetryWebhookRun, WEBHOOK_RUN_FAILURE_CODES, WebhookRunError } from "@sixb/core/storage";
15809
16731
  class SqliteWebhookRunStorage {
@@ -15949,7 +16871,7 @@ function rowToWebhookRunRecord(row) {
15949
16871
  requestBodySha256: row.request_body_sha256,
15950
16872
  responseStatus: row.response_status ?? undefined,
15951
16873
  idempotencyKey: row.idempotency_key ?? undefined,
15952
- error: row.error === null ? undefined : parseSixbFailure5(row.error, WEBHOOK_RUN_FAILURE_CODES)
16874
+ error: row.error === null ? undefined : parseSixbFailure6(row.error, WEBHOOK_RUN_FAILURE_CODES)
15953
16875
  };
15954
16876
  }
15955
16877
 
@@ -16005,7 +16927,7 @@ class SqliteWorkflowInterventionStorage {
16005
16927
  submitted_by = ?,
16006
16928
  response = ?
16007
16929
  WHERE project_id = ? AND id = ?
16008
- `).run("submitted", (input.submittedAt ?? new Date).toISOString(), serializeActor(input.submittedBy), serializeRecord(input.response), existing.project_id, existing.id);
16930
+ `).run("submitted", (input.submittedAt ?? new Date).toISOString(), serializePrincipal(input.submittedBy), serializeRecord(input.response), existing.project_id, existing.id);
16009
16931
  return this.requireIntervention(input.projectId, input.id);
16010
16932
  })();
16011
16933
  }
@@ -16019,7 +16941,7 @@ class SqliteWorkflowInterventionStorage {
16019
16941
  cancelled_at = ?,
16020
16942
  cancelled_by = ?
16021
16943
  WHERE project_id = ? AND id = ?
16022
- `).run("cancelled", (input.cancelledAt ?? new Date).toISOString(), serializeActor(input.cancelledBy), existing.project_id, existing.id);
16944
+ `).run("cancelled", (input.cancelledAt ?? new Date).toISOString(), serializePrincipal(input.cancelledBy), existing.project_id, existing.id);
16023
16945
  return this.requireIntervention(input.projectId, input.id);
16024
16946
  })();
16025
16947
  }
@@ -16141,10 +17063,10 @@ function serializeRecord(value) {
16141
17063
  function parseRecord(value) {
16142
17064
  return JSON.parse(value);
16143
17065
  }
16144
- function serializeActor(actor) {
16145
- return actor ? JSON.stringify(actor) : null;
17066
+ function serializePrincipal(principal) {
17067
+ return principal ? JSON.stringify(principal) : null;
16146
17068
  }
16147
- function parseActor(value) {
17069
+ function parsePrincipal(value) {
16148
17070
  return value ? JSON.parse(value) : undefined;
16149
17071
  }
16150
17072
  function rowToWorkflowInterventionRecord(row) {
@@ -16164,10 +17086,10 @@ function rowToWorkflowInterventionRecord(row) {
16164
17086
  requestedAt: new Date(row.requested_at),
16165
17087
  expiresAt: row.expires_at ? new Date(row.expires_at) : undefined,
16166
17088
  submittedAt: row.submitted_at ? new Date(row.submitted_at) : undefined,
16167
- submittedBy: parseActor(row.submitted_by),
17089
+ submittedBy: parsePrincipal(row.submitted_by),
16168
17090
  response: row.response ? parseRecord(row.response) : undefined,
16169
17091
  cancelledAt: row.cancelled_at ? new Date(row.cancelled_at) : undefined,
16170
- cancelledBy: parseActor(row.cancelled_by),
17092
+ cancelledBy: parsePrincipal(row.cancelled_by),
16171
17093
  expiredAt: row.expired_at ? new Date(row.expired_at) : undefined
16172
17094
  };
16173
17095
  }
@@ -16178,7 +17100,7 @@ function assertNonNegativeInteger(value, fieldName) {
16178
17100
  }
16179
17101
 
16180
17102
  // src/workflow-run-storage.ts
16181
- import { parseSixbFailure as parseSixbFailure6, serializeSixbFailure as serializeSixbFailure7 } from "@sixb/core/internal/errors";
17103
+ import { parseSixbFailure as parseSixbFailure7, serializeSixbFailure as serializeSixbFailure7 } from "@sixb/core/internal/errors";
16182
17104
  import {
16183
17105
  assertWorkflowAgentNodeRunExecution,
16184
17106
  assertWorkflowRunExecution
@@ -16736,7 +17658,7 @@ function rowToWorkflowRunRecord(row) {
16736
17658
  queuedAt: row.queued_at ? new Date(row.queued_at) : undefined,
16737
17659
  startedAt: new Date(row.started_at),
16738
17660
  finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
16739
- error: row.error === null ? undefined : parseSixbFailure6(row.error, WORKFLOW_RUN_FAILURE_CODES),
17661
+ error: row.error === null ? undefined : parseSixbFailure7(row.error, WORKFLOW_RUN_FAILURE_CODES),
16740
17662
  attempt: row.attempt,
16741
17663
  ...row.execution_token && row.execution_queue_lease_expires_at ? {
16742
17664
  execution: {
@@ -16761,7 +17683,7 @@ function rowToWorkflowNodeRunRecord(row) {
16761
17683
  startedAt: new Date(row.started_at),
16762
17684
  finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
16763
17685
  output: row.output ? parseRecord2(row.output) : undefined,
16764
- error: row.error === null ? undefined : parseSixbFailure6(row.error, WORKFLOW_RUN_FAILURE_CODES)
17686
+ error: row.error === null ? undefined : parseSixbFailure7(row.error, WORKFLOW_RUN_FAILURE_CODES)
16765
17687
  };
16766
17688
  }
16767
17689
  function assertNonNegativeInteger2(value, fieldName) {
@@ -16789,7 +17711,7 @@ function rowToWorkflowAgentNodeRunRecord(row) {
16789
17711
  ...row.finish_reason ? { finishReason: row.finish_reason } : {},
16790
17712
  ...row.trace ? { trace: JSON.parse(row.trace) } : {},
16791
17713
  ...row.diagnostics ? { diagnostics: JSON.parse(row.diagnostics) } : {},
16792
- ...row.error ? { error: parseSixbFailure6(row.error, AGENT_RUN_FAILURE_CODES3) } : {},
17714
+ ...row.error ? { error: parseSixbFailure7(row.error, AGENT_RUN_FAILURE_CODES3) } : {},
16793
17715
  attempt: row.attempt,
16794
17716
  ...row.execution_token && row.execution_queue_lease_expires_at ? {
16795
17717
  execution: {
@@ -16830,6 +17752,7 @@ class SqliteStorage {
16830
17752
  shareGrants;
16831
17753
  shareSessions;
16832
17754
  connectorConnections;
17755
+ fileUploadSessions;
16833
17756
  migrators;
16834
17757
  connection;
16835
17758
  readConnection;
@@ -16880,6 +17803,7 @@ class SqliteStorage {
16880
17803
  this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope);
16881
17804
  this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope);
16882
17805
  this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope);
17806
+ this.fileUploadSessions = createOperationScopedFacade(stores.fileUploadSessions, scope);
16883
17807
  this.migrators = options.path ? createSqliteStorageMigrators(options.path) : [];
16884
17808
  registerSqliteStorageTestingAdapter(this, (durationMs) => stores.connectorConnections.advanceTimeForTesting(durationMs));
16885
17809
  }
@@ -17004,7 +17928,8 @@ function createSqliteStores(connection, options) {
17004
17928
  rules: new SqliteRulesStorage({ connection }),
17005
17929
  shareGrants,
17006
17930
  shareSessions,
17007
- connectorConnections: new SqliteConnectorConnectionStorage(connection)
17931
+ connectorConnections: new SqliteConnectorConnectionStorage(connection),
17932
+ fileUploadSessions: new SqliteFileUploadSessionStorage(connection)
17008
17933
  };
17009
17934
  }
17010
17935
  export {
@@ -17012,4 +17937,4 @@ export {
17012
17937
  migrateSqliteStorage
17013
17938
  };
17014
17939
 
17015
- //# debugId=6BCAC863183D761764756E2164756E21
17940
+ //# debugId=A346535172FAF7A764756E2164756E21