@sixb/sqlite 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/action-run-storage.d.ts.map +1 -1
  2. package/dist/agents/rows.d.ts +0 -1
  3. package/dist/agents/rows.d.ts.map +1 -1
  4. package/dist/agents/runs.d.ts.map +1 -1
  5. package/dist/ai-cost-storage.d.ts.map +1 -1
  6. package/dist/ai-usage-storage.d.ts.map +1 -1
  7. package/dist/execution-storage.d.ts +3 -2
  8. package/dist/execution-storage.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1567 -430
  12. package/dist/index.js.map +25 -19
  13. package/dist/migrations.d.ts.map +1 -1
  14. package/dist/objects/index.d.ts +3 -0
  15. package/dist/objects/index.d.ts.map +1 -0
  16. package/dist/{object-query-compiler.d.ts → objects/query-compiler.d.ts} +16 -1
  17. package/dist/objects/query-compiler.d.ts.map +1 -0
  18. package/dist/objects/read-scope.d.ts +17 -0
  19. package/dist/objects/read-scope.d.ts.map +1 -0
  20. package/dist/objects/reader.d.ts +51 -0
  21. package/dist/objects/reader.d.ts.map +1 -0
  22. package/dist/objects/rows.d.ts +33 -0
  23. package/dist/objects/rows.d.ts.map +1 -0
  24. package/dist/objects/selected-reader.d.ts +9 -0
  25. package/dist/objects/selected-reader.d.ts.map +1 -0
  26. package/dist/{object-storage.d.ts → objects/storage.d.ts} +12 -9
  27. package/dist/objects/storage.d.ts.map +1 -0
  28. package/dist/pipeline-run-storage.d.ts.map +1 -1
  29. package/dist/share-grant-storage.d.ts +20 -0
  30. package/dist/share-grant-storage.d.ts.map +1 -0
  31. package/dist/share-session-storage.d.ts +19 -0
  32. package/dist/share-session-storage.d.ts.map +1 -0
  33. package/dist/storage-errors.d.ts +1 -0
  34. package/dist/storage-errors.d.ts.map +1 -1
  35. package/dist/sync-run-storage.d.ts.map +1 -1
  36. package/dist/transactions.d.ts +8 -0
  37. package/dist/transactions.d.ts.map +1 -1
  38. package/dist/workflow-run-storage.d.ts.map +1 -1
  39. package/package.json +4 -4
  40. package/src/action-run-storage.ts +6 -7
  41. package/src/agents/rows.ts +0 -2
  42. package/src/agents/runs.ts +3 -7
  43. package/src/ai-cost-groups.ts +3 -0
  44. package/src/ai-cost-storage.ts +11 -2
  45. package/src/ai-usage-storage.ts +1 -2
  46. package/src/execution-storage.ts +28 -7
  47. package/src/index.ts +22 -5
  48. package/src/migrations/035-share-grants.sql +66 -0
  49. package/src/migrations/036-share-sessions.sql +226 -0
  50. package/src/migrations/037-execution-requester-groups.sql +24 -0
  51. package/src/migrations.ts +9 -0
  52. package/src/objects/index.ts +2 -0
  53. package/src/{object-query-compiler.ts → objects/query-compiler.ts} +104 -54
  54. package/src/objects/read-scope.ts +316 -0
  55. package/src/objects/reader.ts +526 -0
  56. package/src/objects/rows.ts +123 -0
  57. package/src/objects/selected-reader.ts +119 -0
  58. package/src/objects/storage.ts +296 -0
  59. package/src/pipeline-run-storage.ts +2 -5
  60. package/src/share-grant-storage.ts +252 -0
  61. package/src/share-session-storage.ts +189 -0
  62. package/src/storage-errors.ts +4 -0
  63. package/src/sync-run-storage.ts +2 -5
  64. package/src/transactions.ts +32 -0
  65. package/src/workflow-run-storage.ts +1 -6
  66. package/dist/object-query-compiler.d.ts.map +0 -1
  67. package/dist/object-storage.d.ts.map +0 -1
  68. package/src/object-storage.ts +0 -709
@@ -3,24 +3,29 @@ import {
3
3
  type ExecutionStorageRow,
4
4
  executionRecordFromStorageRow,
5
5
  executionRecordToStorageRow,
6
- normalizeExecutionRecord,
7
- validateExecutionRecordReferences,
6
+ prepareExecutionRecord,
8
7
  } from "@sixb/core/internal/execution-storage"
9
- import type { CreateExecutionInput, ExecutionRecord, ExecutionStorage } from "@sixb/core/storage"
8
+ import type {
9
+ CreateExecutionInput,
10
+ ExecutionRecord,
11
+ ExecutionStorage,
12
+ ShareSessionStorage,
13
+ } from "@sixb/core/storage"
10
14
  import { ExecutionStorageError } from "@sixb/core/storage"
11
15
  import type { SqliteAuthStorage } from "./auth-storage"
12
16
 
13
17
  export class SqliteExecutionStorage implements ExecutionStorage {
14
18
  constructor(
15
19
  private readonly db: Database,
16
- private readonly auth: SqliteAuthStorage
20
+ private readonly auth: SqliteAuthStorage,
21
+ private readonly shareSessions: Pick<ShareSessionStorage, "getById">
17
22
  ) {}
18
23
 
19
24
  async create(input: CreateExecutionInput): Promise<ExecutionRecord> {
20
- const record = normalizeExecutionRecord(input)
21
- await validateExecutionRecordReferences(record, {
25
+ const record = await prepareExecutionRecord(input, {
22
26
  auth: this.auth,
23
27
  getExecution: (params) => this.getById(params),
28
+ getShareSession: (params) => this.shareSessions.getById(params),
24
29
  })
25
30
  const row = executionRecordToStorageRow(record)
26
31
 
@@ -37,6 +42,7 @@ export class SqliteExecutionStorage implements ExecutionStorage {
37
42
  source_id,
38
43
  requested_by_user_id,
39
44
  requested_by_service_account_id,
45
+ requester_group_ids,
40
46
  correlation_id,
41
47
  parent_execution_id,
42
48
  authority_kind,
@@ -47,8 +53,11 @@ export class SqliteExecutionStorage implements ExecutionStorage {
47
53
  authority_primitive_kind,
48
54
  authority_primitive_id,
49
55
  authority_kernel_operation,
56
+ authority_delegation_kind,
57
+ authority_delegation_id,
58
+ authority_delegation_session_id,
50
59
  created_at
51
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
60
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
52
61
  `
53
62
  )
54
63
  .run(
@@ -60,6 +69,7 @@ export class SqliteExecutionStorage implements ExecutionStorage {
60
69
  row.sourceId,
61
70
  row.requestedByUserId,
62
71
  row.requestedByServiceAccountId,
72
+ JSON.stringify(row.requesterGroupIds),
63
73
  row.correlationId,
64
74
  row.parentExecutionId,
65
75
  row.authorityKind,
@@ -70,6 +80,9 @@ export class SqliteExecutionStorage implements ExecutionStorage {
70
80
  row.authorityPrimitiveKind,
71
81
  row.authorityPrimitiveId,
72
82
  row.authorityKernelOperation,
83
+ row.authorityDelegationKind,
84
+ row.authorityDelegationId,
85
+ row.authorityDelegationSessionId,
73
86
  row.createdAt.toISOString()
74
87
  )
75
88
  } catch (error) {
@@ -114,6 +127,7 @@ function toStorageRow(row: SqliteExecutionRow): ExecutionStorageRow {
114
127
  sourceId: row.source_id,
115
128
  requestedByUserId: row.requested_by_user_id,
116
129
  requestedByServiceAccountId: row.requested_by_service_account_id,
130
+ requesterGroupIds: JSON.parse(row.requester_group_ids),
117
131
  correlationId: row.correlation_id,
118
132
  parentExecutionId: row.parent_execution_id,
119
133
  authorityKind: row.authority_kind,
@@ -124,6 +138,9 @@ function toStorageRow(row: SqliteExecutionRow): ExecutionStorageRow {
124
138
  authorityPrimitiveKind: row.authority_primitive_kind,
125
139
  authorityPrimitiveId: row.authority_primitive_id,
126
140
  authorityKernelOperation: row.authority_kernel_operation,
141
+ authorityDelegationKind: row.authority_delegation_kind,
142
+ authorityDelegationId: row.authority_delegation_id,
143
+ authorityDelegationSessionId: row.authority_delegation_session_id,
127
144
  createdAt: new Date(row.created_at),
128
145
  }
129
146
  }
@@ -144,6 +161,7 @@ interface SqliteExecutionRow {
144
161
  readonly source_id: string
145
162
  readonly requested_by_user_id: string | null
146
163
  readonly requested_by_service_account_id: string | null
164
+ readonly requester_group_ids: string
147
165
  readonly correlation_id: string
148
166
  readonly parent_execution_id: string | null
149
167
  readonly authority_kind: ExecutionStorageRow["authorityKind"]
@@ -154,5 +172,8 @@ interface SqliteExecutionRow {
154
172
  readonly authority_primitive_kind: ExecutionStorageRow["authorityPrimitiveKind"]
155
173
  readonly authority_primitive_id: string | null
156
174
  readonly authority_kernel_operation: ExecutionStorageRow["authorityKernelOperation"]
175
+ readonly authority_delegation_kind: ExecutionStorageRow["authorityDelegationKind"]
176
+ readonly authority_delegation_id: string | null
177
+ readonly authority_delegation_session_id: string | null
157
178
  readonly created_at: string
158
179
  }
package/src/index.ts CHANGED
@@ -10,9 +10,14 @@ import type {
10
10
  StorageTransactionOptions,
11
11
  } from "@sixb/core"
12
12
  import { ProviderMaterializationTransactionLifecycle } from "@sixb/core/internal/ontology-storage-provider"
13
+ import {
14
+ createTransactionStorageProxy,
15
+ throwNestedStorageTransaction,
16
+ } from "@sixb/core/internal/storage"
13
17
  import {
14
18
  createAgentOperationScope,
15
19
  createAuthOperationScope,
20
+ createObjectOperationScope,
16
21
  createOntologyOperationScope,
17
22
  createOperationScopedFacade,
18
23
  createStorageOperationScope,
@@ -22,9 +27,9 @@ import {
22
27
  type AiCostStorage,
23
28
  type AiLimitStorage,
24
29
  type AiUsageStorage,
25
- createTransactionStorageProxy,
30
+ type ShareGrantStorage,
31
+ type ShareSessionStorage,
26
32
  StorageTransactionError,
27
- throwNestedStorageTransaction,
28
33
  } from "@sixb/core/storage"
29
34
  import { SqliteActionRunStorage } from "./action-run-storage"
30
35
  import { SqliteAgentStorage } from "./agents"
@@ -39,11 +44,13 @@ import {
39
44
  installFreshSqliteSchema,
40
45
  sqliteStoragePath,
41
46
  } from "./migrations"
42
- import { SqliteObjectStorage } from "./object-storage"
47
+ import { SqliteObjectStorage } from "./objects"
43
48
  import { SqliteOntologyStorage, type SqliteOntologyTransactionContext } from "./ontology-storage"
44
49
  import { SqlitePipelineRunStorage } from "./pipeline-run-storage"
45
50
  import { SqliteProjectionRunStorage } from "./projection-run-storage"
46
51
  import { SqliteRulesStorage } from "./rules-storage"
52
+ import { SqliteShareGrantStorage } from "./share-grant-storage"
53
+ import { SqliteShareSessionStorage } from "./share-session-storage"
47
54
  import { SqliteSyncRunStorage } from "./sync-run-storage"
48
55
  import { registerSqliteStorageTestingAdapter } from "./testing"
49
56
  import { SqliteTimeseriesStorage } from "./timeseries-storage"
@@ -96,6 +103,8 @@ export class SqliteStorage implements MigrationCapableStorage {
96
103
  readonly timeseries: Storage["timeseries"]
97
104
  readonly webhookRuns: SqliteWebhookRunStorage
98
105
  readonly rules: SqliteRulesStorage
106
+ readonly shareGrants: ShareGrantStorage
107
+ readonly shareSessions: ShareSessionStorage
99
108
  readonly connectorConnections: SqliteConnectorConnectionStorage
100
109
  readonly migrators: readonly StorageMigrator[]
101
110
 
@@ -143,7 +152,7 @@ export class SqliteStorage implements MigrationCapableStorage {
143
152
  const readTimeseries = path
144
153
  ? new SqliteTimeseriesStorage({ connection: this.readConnection })
145
154
  : stores.timeseries
146
- this.objects = createOperationScopedFacade(readObjects, readScope)
155
+ this.objects = createObjectOperationScope(readObjects, readScope)
147
156
  this.ontology = createOntologyOperationScope(stores.ontology, ontologyScope)
148
157
  this.auth = createAuthOperationScope(stores.auth, scope)
149
158
  this.executions = createOperationScopedFacade(stores.executions, scope)
@@ -160,6 +169,8 @@ export class SqliteStorage implements MigrationCapableStorage {
160
169
  this.workflowInterventions = createOperationScopedFacade(stores.workflowInterventions, scope)
161
170
  this.webhookRuns = createOperationScopedFacade(stores.webhookRuns, scope)
162
171
  this.rules = createOperationScopedFacade(stores.rules, scope)
172
+ this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope)
173
+ this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope)
163
174
  this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope)
164
175
  this.migrators = options.path ? createSqliteStorageMigrators(options.path) : []
165
176
  registerSqliteStorageTestingAdapter(this, (durationMs) =>
@@ -294,7 +305,9 @@ function createSqliteStores(
294
305
  }
295
306
  ): SqliteStoreSet {
296
307
  const auth = new SqliteAuthStorage({ connection })
297
- const executions = new SqliteExecutionStorage(connection.db, auth)
308
+ const shareGrants = new SqliteShareGrantStorage({ connection })
309
+ const shareSessions = new SqliteShareSessionStorage({ connection })
310
+ const executions = new SqliteExecutionStorage(connection.db, auth, shareSessions)
298
311
  return {
299
312
  objects: new SqliteObjectStorage({ connection }),
300
313
  ontology: new SqliteOntologyStorage({
@@ -317,6 +330,8 @@ function createSqliteStores(
317
330
  workflowInterventions: new SqliteWorkflowInterventionStorage({ connection }),
318
331
  webhookRuns: new SqliteWebhookRunStorage({ connection, executions }),
319
332
  rules: new SqliteRulesStorage({ connection }),
333
+ shareGrants,
334
+ shareSessions,
320
335
  connectorConnections: new SqliteConnectorConnectionStorage(connection),
321
336
  }
322
337
  }
@@ -339,6 +354,8 @@ interface SqliteStoreSet {
339
354
  readonly timeseries: SqliteTimeseriesStorage
340
355
  readonly webhookRuns: SqliteWebhookRunStorage
341
356
  readonly rules: SqliteRulesStorage
357
+ readonly shareGrants: SqliteShareGrantStorage
358
+ readonly shareSessions: SqliteShareSessionStorage
342
359
  readonly connectorConnections: SqliteConnectorConnectionStorage
343
360
  }
344
361
 
@@ -0,0 +1,66 @@
1
+ CREATE TABLE share_grants (
2
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
3
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
4
+ definition_id TEXT NOT NULL CHECK (length(trim(definition_id)) > 0),
5
+ target_object_type_id TEXT NOT NULL CHECK (length(trim(target_object_type_id)) > 0),
6
+ target_primary_id TEXT NOT NULL CHECK (length(trim(target_primary_id)) > 0),
7
+ issued_by_type TEXT NOT NULL CHECK (issued_by_type IN ('user', 'serviceAccount')),
8
+ issued_by_id TEXT NOT NULL CHECK (length(trim(issued_by_id)) > 0),
9
+ authority_version INTEGER NOT NULL CHECK (authority_version > 0),
10
+ authority_snapshot TEXT NOT NULL CHECK (
11
+ json_valid(authority_snapshot)
12
+ AND json_type(authority_snapshot) = 'object'
13
+ AND json_type(authority_snapshot, '$.version') = 'integer'
14
+ AND json_extract(authority_snapshot, '$.version') = authority_version
15
+ AND json_type(authority_snapshot, '$.access') = 'object'
16
+ ),
17
+ authority_digest TEXT NOT NULL CHECK (
18
+ length(authority_digest) = 64
19
+ AND authority_digest = lower(authority_digest)
20
+ AND authority_digest NOT GLOB '*[^0-9a-f]*'
21
+ ),
22
+ token_hash TEXT NOT NULL CHECK (
23
+ length(token_hash) = 64
24
+ AND token_hash = lower(token_hash)
25
+ AND token_hash NOT GLOB '*[^0-9a-f]*'
26
+ ),
27
+ destination_path TEXT NOT NULL CHECK (
28
+ substr(destination_path, 1, 1) = '/'
29
+ AND instr(destination_path, '?') = 0
30
+ AND instr(destination_path, '#') = 0
31
+ AND instr(destination_path, char(92)) = 0
32
+ ),
33
+ created_at TEXT NOT NULL,
34
+ expires_at TEXT NOT NULL,
35
+ revoked_at TEXT,
36
+ revoked_by_type TEXT CHECK (
37
+ revoked_by_type IS NULL OR revoked_by_type IN ('user', 'serviceAccount', 'system')
38
+ ),
39
+ revoked_by_id TEXT CHECK (revoked_by_id IS NULL OR length(trim(revoked_by_id)) > 0),
40
+ PRIMARY KEY (project_id, id),
41
+ UNIQUE (project_id, token_hash),
42
+ CHECK (expires_at > created_at),
43
+ CHECK (revoked_at IS NULL OR revoked_at >= created_at),
44
+ CHECK (
45
+ (revoked_at IS NULL AND revoked_by_type IS NULL AND revoked_by_id IS NULL)
46
+ OR
47
+ (revoked_at IS NOT NULL AND revoked_by_type IS NOT NULL AND revoked_by_id IS NOT NULL)
48
+ )
49
+ );
50
+
51
+ CREATE INDEX idx_share_grants_target
52
+ ON share_grants (
53
+ project_id,
54
+ definition_id,
55
+ target_object_type_id,
56
+ target_primary_id,
57
+ created_at DESC,
58
+ id DESC
59
+ );
60
+
61
+ CREATE INDEX idx_share_grants_project_created
62
+ ON share_grants (project_id, created_at DESC, id DESC);
63
+
64
+ CREATE INDEX idx_share_grants_expiry
65
+ ON share_grants (project_id, expires_at)
66
+ WHERE revoked_at IS NULL;
@@ -0,0 +1,226 @@
1
+ -- Shared sessions and their execution provenance.
2
+ CREATE TABLE share_sessions (
3
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
4
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
5
+ grant_id TEXT NOT NULL CHECK (length(trim(grant_id)) > 0),
6
+ token_hash TEXT NOT NULL CHECK (
7
+ length(token_hash) = 64
8
+ AND token_hash = lower(token_hash)
9
+ AND token_hash NOT GLOB '*[^0-9a-f]*'
10
+ ),
11
+ created_at TEXT NOT NULL,
12
+ expires_at TEXT NOT NULL,
13
+ absolute_expires_at TEXT NOT NULL,
14
+ revoked_at TEXT,
15
+ PRIMARY KEY (project_id, id),
16
+ UNIQUE (project_id, id, grant_id),
17
+ UNIQUE (project_id, token_hash),
18
+ FOREIGN KEY (project_id, grant_id)
19
+ REFERENCES share_grants (project_id, id),
20
+ CHECK (expires_at > created_at),
21
+ CHECK (absolute_expires_at > created_at),
22
+ CHECK (expires_at <= absolute_expires_at),
23
+ CHECK (revoked_at IS NULL OR revoked_at >= created_at)
24
+ );
25
+
26
+ CREATE INDEX idx_share_sessions_grant
27
+ ON share_sessions (project_id, grant_id, created_at DESC, id DESC);
28
+
29
+ CREATE INDEX idx_share_sessions_expiry
30
+ ON share_sessions (project_id, expires_at)
31
+ WHERE revoked_at IS NULL;
32
+
33
+ -- Persist shared-session provenance on request executions without fabricating a principal.
34
+ CREATE TABLE executions_v2 (
35
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
36
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
37
+ executor_kind TEXT NOT NULL CHECK (
38
+ executor_kind IN (
39
+ 'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
40
+ 'agent', 'kernel'
41
+ )
42
+ ),
43
+ executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
44
+ source_kind TEXT NOT NULL CHECK (
45
+ source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution')
46
+ ),
47
+ source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
48
+ requested_by_user_id TEXT,
49
+ requested_by_service_account_id TEXT,
50
+ correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
51
+ parent_execution_id TEXT,
52
+ authority_kind TEXT NOT NULL CHECK (
53
+ authority_kind IN ('principal', 'trustedPrimitive', 'delegated', 'kernel', 'disabled')
54
+ ),
55
+ authority_user_id TEXT,
56
+ authority_service_account_id TEXT,
57
+ authority_session_id TEXT,
58
+ authority_access_token_id TEXT,
59
+ authority_primitive_kind TEXT CHECK (
60
+ authority_primitive_kind IS NULL
61
+ OR authority_primitive_kind IN (
62
+ 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
63
+ )
64
+ ),
65
+ authority_primitive_id TEXT,
66
+ authority_kernel_operation TEXT CHECK (
67
+ authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
68
+ ),
69
+ authority_delegation_kind TEXT CHECK (
70
+ authority_delegation_kind IS NULL OR authority_delegation_kind = 'share'
71
+ ),
72
+ authority_delegation_id TEXT,
73
+ authority_delegation_session_id TEXT,
74
+ created_at TEXT NOT NULL,
75
+ PRIMARY KEY (project_id, id),
76
+ FOREIGN KEY (project_id, parent_execution_id) REFERENCES executions (project_id, id),
77
+ FOREIGN KEY (project_id, requested_by_user_id) REFERENCES auth_users (project_id, id),
78
+ FOREIGN KEY (project_id, requested_by_service_account_id)
79
+ REFERENCES auth_service_accounts (project_id, id),
80
+ FOREIGN KEY (project_id, authority_user_id) REFERENCES auth_users (project_id, id),
81
+ FOREIGN KEY (project_id, authority_service_account_id)
82
+ REFERENCES auth_service_accounts (project_id, id),
83
+ FOREIGN KEY (project_id, authority_session_id) REFERENCES auth_sessions (project_id, id),
84
+ FOREIGN KEY (project_id, authority_access_token_id)
85
+ REFERENCES auth_access_tokens (project_id, id),
86
+ FOREIGN KEY (
87
+ project_id, authority_delegation_session_id, authority_delegation_id
88
+ ) REFERENCES share_sessions (project_id, id, grant_id),
89
+ CHECK ((requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1),
90
+ CHECK (
91
+ (source_kind = 'execution' AND parent_execution_id = source_id)
92
+ OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
93
+ ),
94
+ CHECK (
95
+ (
96
+ authority_kind = 'principal'
97
+ AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
98
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
99
+ AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
100
+ AND authority_primitive_kind IS NULL
101
+ AND authority_primitive_id IS NULL
102
+ AND authority_kernel_operation IS NULL
103
+ AND authority_delegation_kind IS NULL
104
+ AND authority_delegation_id IS NULL
105
+ AND authority_delegation_session_id IS NULL
106
+ )
107
+ OR (
108
+ authority_kind = 'trustedPrimitive'
109
+ AND authority_user_id IS NULL
110
+ AND authority_service_account_id IS NULL
111
+ AND authority_session_id IS NULL
112
+ AND authority_access_token_id IS NULL
113
+ AND authority_primitive_kind IS NOT NULL
114
+ AND authority_primitive_id IS NOT NULL
115
+ AND length(trim(authority_primitive_id)) > 0
116
+ AND authority_kernel_operation IS NULL
117
+ AND authority_delegation_kind IS NULL
118
+ AND authority_delegation_id IS NULL
119
+ AND authority_delegation_session_id IS NULL
120
+ )
121
+ OR (
122
+ authority_kind = 'delegated'
123
+ AND authority_user_id IS NULL
124
+ AND authority_service_account_id IS NULL
125
+ AND authority_session_id IS NULL
126
+ AND authority_access_token_id IS NULL
127
+ AND authority_primitive_kind IS NULL
128
+ AND authority_primitive_id IS NULL
129
+ AND authority_kernel_operation IS NULL
130
+ AND authority_delegation_kind IS NOT NULL
131
+ AND authority_delegation_kind = 'share'
132
+ AND authority_delegation_id IS NOT NULL
133
+ AND length(trim(authority_delegation_id)) > 0
134
+ AND authority_delegation_session_id IS NOT NULL
135
+ AND length(trim(authority_delegation_session_id)) > 0
136
+ )
137
+ OR (
138
+ authority_kind = 'kernel'
139
+ AND authority_user_id IS NULL
140
+ AND authority_service_account_id IS NULL
141
+ AND authority_session_id IS NULL
142
+ AND authority_access_token_id IS NULL
143
+ AND authority_primitive_kind IS NULL
144
+ AND authority_primitive_id IS NULL
145
+ AND authority_kernel_operation IS NOT NULL
146
+ AND authority_delegation_kind IS NULL
147
+ AND authority_delegation_id IS NULL
148
+ AND authority_delegation_session_id IS NULL
149
+ )
150
+ OR (
151
+ authority_kind = 'disabled'
152
+ AND authority_user_id IS NULL
153
+ AND authority_service_account_id IS NULL
154
+ AND authority_session_id IS NULL
155
+ AND authority_access_token_id IS NULL
156
+ AND authority_primitive_kind IS NULL
157
+ AND authority_primitive_id IS NULL
158
+ AND authority_kernel_operation IS NULL
159
+ AND authority_delegation_kind IS NULL
160
+ AND authority_delegation_id IS NULL
161
+ AND authority_delegation_session_id IS NULL
162
+ )
163
+ ),
164
+ CHECK (
165
+ (
166
+ executor_kind = 'request'
167
+ AND source_kind = 'http'
168
+ AND executor_id = source_id
169
+ AND (
170
+ (
171
+ authority_kind = 'principal'
172
+ AND requested_by_user_id IS authority_user_id
173
+ AND requested_by_service_account_id IS authority_service_account_id
174
+ )
175
+ OR (
176
+ authority_kind IN ('delegated', 'disabled')
177
+ AND requested_by_user_id IS NULL
178
+ AND requested_by_service_account_id IS NULL
179
+ )
180
+ )
181
+ )
182
+ OR (
183
+ executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
184
+ AND authority_kind = 'trustedPrimitive'
185
+ AND executor_kind = authority_primitive_kind
186
+ )
187
+ OR (
188
+ executor_kind = 'agent'
189
+ AND source_kind = 'execution'
190
+ AND (
191
+ (
192
+ authority_kind = 'principal'
193
+ AND authority_service_account_id IS NOT NULL
194
+ AND authority_session_id IS NULL
195
+ AND authority_access_token_id IS NULL
196
+ )
197
+ OR (
198
+ authority_kind = 'principal'
199
+ AND authority_user_id IS NOT NULL
200
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) = 1
201
+ )
202
+ OR authority_kind = 'disabled'
203
+ )
204
+ )
205
+ OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
206
+ )
207
+ );
208
+
209
+ INSERT INTO executions_v2 (
210
+ project_id, id, executor_kind, executor_id, source_kind, source_id,
211
+ requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id,
212
+ authority_kind, authority_user_id, authority_service_account_id, authority_session_id,
213
+ authority_access_token_id, authority_primitive_kind, authority_primitive_id,
214
+ authority_kernel_operation, authority_delegation_kind, authority_delegation_id,
215
+ authority_delegation_session_id, created_at
216
+ )
217
+ SELECT
218
+ project_id, id, executor_kind, executor_id, source_kind, source_id,
219
+ requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id,
220
+ authority_kind, authority_user_id, authority_service_account_id, authority_session_id,
221
+ authority_access_token_id, authority_primitive_kind, authority_primitive_id,
222
+ authority_kernel_operation, NULL, NULL, NULL, created_at
223
+ FROM executions;
224
+
225
+ DROP TABLE executions;
226
+ ALTER TABLE executions_v2 RENAME TO executions;
@@ -0,0 +1,24 @@
1
+ ALTER TABLE executions ADD COLUMN requester_group_ids TEXT NOT NULL DEFAULT '[]';
2
+
3
+ -- Preserve each admitted snapshot, including an intentionally empty one. Executions without
4
+ -- their own historical snapshot inherit from their parent; historical roots remain unknown/empty.
5
+ WITH RECURSIVE attribution(project_id, id, groups) AS (
6
+ SELECT e.project_id, e.id, COALESCE(w.requester_group_ids, a.requester_group_ids, '[]')
7
+ FROM executions e
8
+ LEFT JOIN workflow_runs w ON w.project_id = e.project_id AND w.execution_id = e.id
9
+ LEFT JOIN agent_runs a ON a.project_id = e.project_id AND a.execution_id = e.id
10
+ WHERE e.parent_execution_id IS NULL
11
+ UNION ALL
12
+ SELECT e.project_id, e.id, COALESCE(w.requester_group_ids, a.requester_group_ids, p.groups)
13
+ FROM executions e
14
+ JOIN attribution p ON p.project_id = e.project_id AND p.id = e.parent_execution_id
15
+ LEFT JOIN workflow_runs w ON w.project_id = e.project_id AND w.execution_id = e.id
16
+ LEFT JOIN agent_runs a ON a.project_id = e.project_id AND a.execution_id = e.id
17
+ )
18
+ UPDATE executions SET requester_group_ids = (
19
+ SELECT groups FROM attribution
20
+ WHERE attribution.project_id = executions.project_id AND attribution.id = executions.id
21
+ );
22
+
23
+ ALTER TABLE workflow_runs DROP COLUMN requester_group_ids;
24
+ ALTER TABLE agent_runs DROP COLUMN requester_group_ids;
package/src/migrations.ts CHANGED
@@ -88,6 +88,8 @@ import retireAgentDefinitionsSql from "./migrations/033-retire-agent-definitions
88
88
  import deviceAuthorizationsSql from "./migrations/034-device-authorizations.sql" with {
89
89
  type: "text",
90
90
  }
91
+ import shareGrantsSql from "./migrations/035-share-grants.sql" with { type: "text" }
92
+ import shareSessionsSql from "./migrations/036-share-sessions.sql" with { type: "text" }
91
93
 
92
94
  const MIGRATIONS_TABLE_SQL = `
93
95
  CREATE TABLE IF NOT EXISTS sixb_migrations (
@@ -177,6 +179,9 @@ export const sqliteStorageMigrations = defineMigrations({
177
179
  sqliteSql("032-conversation-run-spec", conversationRunSpecSql),
178
180
  sqliteSql("033-retire-agent-definitions", retireAgentDefinitionsSql),
179
181
  sqliteSql("034-device-authorizations", deviceAuthorizationsSql),
182
+ sqliteSql("035-share-grants", shareGrantsSql),
183
+ sqliteSql("036-share-sessions", shareSessionsSql),
184
+ sqliteSql("037-execution-requester-groups", executionRequesterGroupsSql),
180
185
  ],
181
186
  })
182
187
 
@@ -392,3 +397,7 @@ function rollbackQuietly(db: Database): void {
392
397
  // Ignore rollback errors so the original migration failure is preserved.
393
398
  }
394
399
  }
400
+
401
+ import executionRequesterGroupsSql from "./migrations/037-execution-requester-groups.sql" with {
402
+ type: "text",
403
+ }
@@ -0,0 +1,2 @@
1
+ export type { SqliteObjectStorageOptions } from "./storage"
2
+ export { SqliteObjectStorage } from "./storage"