@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.
- package/README.md +32 -0
- package/dist/agents/rows.d.ts +2 -0
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/threads.d.ts +2 -1
- package/dist/agents/threads.d.ts.map +1 -1
- package/dist/auth-storage/access-tokens.d.ts +0 -1
- package/dist/auth-storage/access-tokens.d.ts.map +1 -1
- package/dist/auth-storage/auth-storage.d.ts.map +1 -1
- package/dist/auth-storage/device-authorizations.d.ts.map +1 -1
- package/dist/auth-storage/rows.d.ts +6 -3
- package/dist/auth-storage/rows.d.ts.map +1 -1
- package/dist/auth-storage/sessions.d.ts +8 -1
- package/dist/auth-storage/sessions.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/file-upload-session-storage.d.ts +6 -0
- package/dist/file-upload-session-storage.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1062 -137
- package/dist/index.js.map +28 -23
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/query-compiler.d.ts +9 -2
- package/dist/objects/query-compiler.d.ts.map +1 -1
- package/dist/objects/read-scope.d.ts +3 -0
- package/dist/objects/read-scope.d.ts.map +1 -1
- package/dist/objects/reader.d.ts +1 -0
- package/dist/objects/reader.d.ts.map +1 -1
- package/dist/objects/rows.d.ts +1 -0
- package/dist/objects/rows.d.ts.map +1 -1
- package/dist/objects/storage.d.ts.map +1 -1
- package/dist/objects/vector-extension.d.ts +4 -0
- package/dist/objects/vector-extension.d.ts.map +1 -0
- package/dist/ontology-storage/index.d.ts +4 -0
- package/dist/ontology-storage/index.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +1 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +2 -1
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/vector-indexing.d.ts +20 -0
- package/dist/ontology-storage/vector-indexing.d.ts.map +1 -0
- package/dist/ontology-storage/vectors.d.ts +16 -0
- package/dist/ontology-storage/vectors.d.ts.map +1 -0
- package/dist/vector-encoding.d.ts +3 -0
- package/dist/vector-encoding.d.ts.map +1 -0
- package/dist/workflow-intervention-storage.d.ts.map +1 -1
- package/package.json +8 -4
- package/src/agents/rows.ts +12 -0
- package/src/agents/threads.ts +41 -2
- package/src/ai-cost-storage.ts +4 -0
- package/src/auth-storage/access-tokens.ts +11 -18
- package/src/auth-storage/auth-storage.ts +5 -7
- package/src/auth-storage/device-authorizations.ts +3 -5
- package/src/auth-storage/rows.ts +17 -7
- package/src/auth-storage/sessions.ts +89 -4
- package/src/auth-storage/shared.ts +9 -3
- package/src/file-upload-session-storage.ts +136 -0
- package/src/index.ts +5 -0
- package/src/migrations/041-agent-thread-workspaces.sql +2 -0
- package/src/migrations/042-vector-profiles.sql +21 -0
- package/src/migrations/043-vector-indexing.sql +197 -0
- package/src/migrations/044-vector-batching.sql +3 -0
- package/src/migrations/045-agent-thread-sandbox-state.sql +2 -0
- package/src/migrations/046-workflow-intervention-principals.sql +15 -0
- package/src/migrations/047-ontology-commit-attribution.sql +67 -0
- package/src/migrations/048-file-upload-sessions.sql +35 -0
- package/src/migrations/049-native-sessions.sql +12 -0
- package/src/migrations.ts +26 -0
- package/src/objects/query-compiler.ts +164 -11
- package/src/objects/read-scope.ts +34 -31
- package/src/objects/reader.ts +29 -1
- package/src/objects/rows.ts +5 -1
- package/src/objects/storage.ts +13 -1
- package/src/objects/vector-extension.ts +26 -0
- package/src/ontology-storage/index.ts +16 -0
- package/src/ontology-storage/materializations.ts +29 -59
- package/src/ontology-storage/shared.ts +7 -3
- package/src/ontology-storage/vector-indexing.ts +196 -0
- package/src/ontology-storage/vectors.ts +182 -0
- package/src/vector-encoding.ts +9 -0
- 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
|
-
|
|
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
|
-
|
|
7405
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
7607
|
-
whereClauses.push("subject_type = ?");
|
|
7608
|
-
args.push(input.
|
|
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.
|
|
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.
|
|
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,
|
|
7720
|
-
|
|
7721
|
-
) VALUES (?, ?, ?, ?, ?,
|
|
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"),
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
13592
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 :
|
|
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 :
|
|
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
|
|
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 :
|
|
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
|
|
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 :
|
|
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(),
|
|
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(),
|
|
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
|
|
16145
|
-
return
|
|
17066
|
+
function serializePrincipal(principal) {
|
|
17067
|
+
return principal ? JSON.stringify(principal) : null;
|
|
16146
17068
|
}
|
|
16147
|
-
function
|
|
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:
|
|
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:
|
|
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
|
|
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 :
|
|
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 :
|
|
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:
|
|
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=
|
|
17940
|
+
//# debugId=A346535172FAF7A764756E2164756E21
|