@opengeni/core 1.0.1 → 2.1.0-canary.0

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 (99) hide show
  1. package/dist/access/index.d.ts +37 -0
  2. package/dist/application/new-session-drafts.d.ts +8 -1
  3. package/dist/application/session-commands.d.ts +18 -11
  4. package/dist/application/session-tenancy.d.ts +18 -0
  5. package/dist/application/user-resource-grants.d.ts +20 -0
  6. package/dist/{chunk-6WKPWE5S.js → chunk-H7X52RI2.js} +27 -18
  7. package/dist/chunk-H7X52RI2.js.map +1 -0
  8. package/dist/{chunk-JJU6I5XD.js → chunk-VCZFFEPB.js} +21 -9
  9. package/dist/chunk-VCZFFEPB.js.map +1 -0
  10. package/dist/{chunk-NYPMQ7NO.js → chunk-ZYCNLYGH.js} +29 -27
  11. package/dist/chunk-ZYCNLYGH.js.map +1 -0
  12. package/dist/dependencies.d.ts +12 -1
  13. package/dist/domain/automations.d.ts +51 -0
  14. package/dist/domain/company-brain-governed-writes.d.ts +70 -0
  15. package/dist/domain/company-profile-agent-admin.d.ts +24 -0
  16. package/dist/domain/connection-authority.d.ts +97 -0
  17. package/dist/domain/connection-authority.js +169 -0
  18. package/dist/domain/connection-authority.js.map +1 -0
  19. package/dist/domain/editable-artifacts/service.d.ts +1 -2
  20. package/dist/domain/environments.d.ts +1 -1
  21. package/dist/domain/github-repository-bindings.d.ts +117 -0
  22. package/dist/domain/governed-learning-activation.d.ts +16 -0
  23. package/dist/domain/governed-learning-evaluator.d.ts +6 -0
  24. package/dist/domain/governed-learning-slack-publication.d.ts +45 -0
  25. package/dist/domain/memory-slack-delivery.d.ts +1 -4
  26. package/dist/domain/organization-membership-lifecycle.d.ts +1 -0
  27. package/dist/domain/packs.d.ts +5 -1
  28. package/dist/domain/personal-connection-delegations.d.ts +34 -2
  29. package/dist/domain/pr-review.d.ts +149 -0
  30. package/dist/domain/remember.d.ts +69 -0
  31. package/dist/domain/resources.d.ts +22 -1
  32. package/dist/domain/scheduled-tasks.d.ts +43 -2
  33. package/dist/domain/session-tool-policy.d.ts +1 -1
  34. package/dist/domain/sessions.d.ts +40 -6
  35. package/dist/editable-artifact-live/application.d.ts +10 -2
  36. package/dist/editable-artifact-live/ports.d.ts +0 -1
  37. package/dist/editable-artifact-live/server.d.ts +0 -1
  38. package/dist/editable-artifact-live/ticket.d.ts +0 -1
  39. package/dist/editable-artifact-live/types.d.ts +5 -2
  40. package/dist/editable-artifact-live.js +2 -2
  41. package/dist/editable-artifacts.js +2 -4
  42. package/dist/index.d.ts +13 -1
  43. package/dist/index.js +4827 -1164
  44. package/dist/index.js.map +1 -1
  45. package/dist/rigs/index.d.ts +22 -5
  46. package/dist/sandbox/fleet.d.ts +34 -6
  47. package/dist/sandbox/routing.d.ts +15 -1
  48. package/dist/sandbox/runtime-settings.d.ts +39 -0
  49. package/package.json +16 -11
  50. package/src/access/index.ts +151 -31
  51. package/src/application/new-session-drafts.ts +24 -2
  52. package/src/application/session-commands.ts +305 -71
  53. package/src/application/session-tenancy.ts +321 -0
  54. package/src/application/user-resource-grants.ts +140 -0
  55. package/src/billing/limits.ts +25 -15
  56. package/src/dependencies.ts +12 -1
  57. package/src/domain/automations.ts +196 -0
  58. package/src/domain/capabilities.ts +7 -1
  59. package/src/domain/company-brain-governed-writes.ts +330 -0
  60. package/src/domain/company-profile-agent-admin.ts +55 -0
  61. package/src/domain/connection-authority.ts +329 -0
  62. package/src/domain/editable-artifacts/agent-application.ts +17 -9
  63. package/src/domain/editable-artifacts/service.ts +12 -1
  64. package/src/domain/editable-artifacts/snapshot-compaction.ts +9 -5
  65. package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +10 -8
  66. package/src/domain/editable-artifacts/snapshot-verifier.ts +10 -3
  67. package/src/domain/environments.ts +16 -3
  68. package/src/domain/github-repository-bindings.ts +295 -0
  69. package/src/domain/governed-learning-activation.ts +44 -0
  70. package/src/domain/governed-learning-evaluator.ts +49 -0
  71. package/src/domain/governed-learning-slack-publication.ts +157 -0
  72. package/src/domain/insights.ts +9 -0
  73. package/src/domain/memory-slack-delivery.ts +0 -30
  74. package/src/domain/organization-membership-lifecycle.ts +9 -0
  75. package/src/domain/packs.ts +106 -3
  76. package/src/domain/personal-connection-delegations.ts +532 -51
  77. package/src/domain/pr-review.ts +671 -0
  78. package/src/domain/remember.ts +549 -0
  79. package/src/domain/resources.ts +131 -4
  80. package/src/domain/scheduled-tasks.ts +497 -76
  81. package/src/domain/session-tool-policy.ts +12 -9
  82. package/src/domain/sessions.ts +613 -166
  83. package/src/editable-artifact-live/application.ts +21 -3
  84. package/src/editable-artifact-live/ports.ts +0 -1
  85. package/src/editable-artifact-live/server.ts +13 -7
  86. package/src/editable-artifact-live/ticket.ts +1 -5
  87. package/src/editable-artifact-live/types.ts +6 -2
  88. package/src/editable-artifact-live/wire.ts +0 -10
  89. package/src/index.ts +13 -1
  90. package/src/rigs/index.ts +165 -48
  91. package/src/sandbox/fleet.ts +376 -30
  92. package/src/sandbox/routing.ts +91 -29
  93. package/src/sandbox/runtime-settings.ts +274 -0
  94. package/src/session-authorization.ts +17 -49
  95. package/dist/chunk-6WKPWE5S.js.map +0 -1
  96. package/dist/chunk-JJU6I5XD.js.map +0 -1
  97. package/dist/chunk-NYPMQ7NO.js.map +0 -1
  98. package/dist/domain/durable-learning-slack-publication.d.ts +0 -72
  99. package/src/domain/durable-learning-slack-publication.ts +0 -202
@@ -0,0 +1,329 @@
1
+ import type {
2
+ ConnectionKind,
3
+ ConnectionStatus,
4
+ SessionTenancyVisibility,
5
+ UserResourceDelegation,
6
+ UserResourceGrantMode,
7
+ UserResourceGrantStatus,
8
+ } from "@opengeni/contracts";
9
+ import {
10
+ ConnectionAuthorityEnvelope,
11
+ ConnectionUseAttribution,
12
+ ConnectionUseAuthoritySnapshot,
13
+ type ConnectionUseAuthorizationResult,
14
+ type ConnectionAuthoritySelectionSource,
15
+ type ConnectionUseDenialReason,
16
+ type ConnectionUseSelectionSource,
17
+ } from "@opengeni/contracts/connection-authority";
18
+
19
+ export type ConnectionAuthorityCandidate = {
20
+ id: string;
21
+ organizationId: string;
22
+ workspaceId: string;
23
+ generation: number;
24
+ status: ConnectionStatus;
25
+ providerDomain: string;
26
+ kind: ConnectionKind;
27
+ subjectId: string | null;
28
+ ownerOrganizationMembershipId: string | null;
29
+ };
30
+
31
+ export type UserConnectionAuthorityCandidate = {
32
+ id: string;
33
+ organizationId: string;
34
+ resourceKind: "connection";
35
+ resourceId: string;
36
+ originWorkspaceId: string;
37
+ ownerSubjectId: string;
38
+ ownerOrganizationMembershipId: string;
39
+ ownerMembershipAuthorizationRevision: number;
40
+ generation: number;
41
+ status: "active" | "retained" | "revoked";
42
+ };
43
+
44
+ export class ConnectionAuthorityInvariantError extends Error {
45
+ constructor(readonly code: string) {
46
+ super(`connection authority invariant failed: ${code}`);
47
+ this.name = "ConnectionAuthorityInvariantError";
48
+ }
49
+ }
50
+
51
+ export function captureConnectionUseAuthority(input: {
52
+ organizationId: string;
53
+ targetWorkspaceId: string;
54
+ targetSessionId: string;
55
+ targetSessionVisibility: SessionTenancyVisibility;
56
+ targetSessionAuthorityEpoch: number;
57
+ acceptedWork:
58
+ | { kind: "turn"; turnId: string }
59
+ | {
60
+ kind: "scheduled_task";
61
+ taskId: string;
62
+ taskAuthorityRevision: number;
63
+ runId: string;
64
+ };
65
+ connection: ConnectionAuthorityCandidate;
66
+ authority?: unknown;
67
+ authorityWasOmitted?: boolean;
68
+ userAuthority?: UserConnectionAuthorityCandidate | null;
69
+ selectionSources: ConnectionUseSelectionSource[];
70
+ }): ConnectionUseAuthoritySnapshot {
71
+ const authority = ConnectionAuthorityEnvelope.parse(input.authority ?? {});
72
+ const connection = input.connection;
73
+ if (connection.organizationId !== input.organizationId) {
74
+ throw new ConnectionAuthorityInvariantError("tenant_mismatch");
75
+ }
76
+ if (connection.status !== "active") {
77
+ throw new ConnectionAuthorityInvariantError("connection_status_inactive");
78
+ }
79
+
80
+ let authoritySource: ConnectionAuthoritySelectionSource;
81
+ let userDelegation: UserResourceDelegation | null = null;
82
+ if (authority.scope === "workspace") {
83
+ if (connection.subjectId !== null || connection.ownerOrganizationMembershipId !== null) {
84
+ throw new ConnectionAuthorityInvariantError("workspace_borrowed_personal_connection");
85
+ }
86
+ if (connection.workspaceId !== input.targetWorkspaceId) {
87
+ throw new ConnectionAuthorityInvariantError("workspace_connection_scope_mismatch");
88
+ }
89
+ authoritySource = input.authorityWasOmitted
90
+ ? "legacy_workspace_omission"
91
+ : "explicit_workspace";
92
+ } else {
93
+ const delegation = authority.userDelegation;
94
+ const resourceAuthority = input.userAuthority;
95
+ if (!delegation || !resourceAuthority) {
96
+ throw new ConnectionAuthorityInvariantError("user_authority_missing");
97
+ }
98
+ if (!connection.subjectId || !connection.ownerOrganizationMembershipId) {
99
+ throw new ConnectionAuthorityInvariantError("personal_owner_missing");
100
+ }
101
+ if (
102
+ resourceAuthority.id !== delegation.authorityId ||
103
+ resourceAuthority.organizationId !== input.organizationId ||
104
+ resourceAuthority.resourceKind !== "connection" ||
105
+ resourceAuthority.resourceId !== connection.id ||
106
+ resourceAuthority.originWorkspaceId !== connection.workspaceId ||
107
+ resourceAuthority.ownerSubjectId !== connection.subjectId ||
108
+ resourceAuthority.ownerOrganizationMembershipId !==
109
+ connection.ownerOrganizationMembershipId ||
110
+ resourceAuthority.generation !== delegation.authorityGeneration ||
111
+ resourceAuthority.status !== "active"
112
+ ) {
113
+ throw new ConnectionAuthorityInvariantError("user_authority_mismatch");
114
+ }
115
+ userDelegation = delegation;
116
+ authoritySource = "user_delegation";
117
+ }
118
+
119
+ return ConnectionUseAuthoritySnapshot.parse({
120
+ organizationId: input.organizationId,
121
+ originWorkspaceId: connection.workspaceId,
122
+ targetWorkspaceId: input.targetWorkspaceId,
123
+ targetSessionId: input.targetSessionId,
124
+ targetSessionVisibility: input.targetSessionVisibility,
125
+ targetSessionAuthorityEpoch: input.targetSessionAuthorityEpoch,
126
+ acceptedWork: input.acceptedWork,
127
+ connectionId: connection.id,
128
+ connectionGeneration: connection.generation,
129
+ connectionStatus: "active",
130
+ providerDomain: connection.providerDomain.toLowerCase(),
131
+ connectionKind: connection.kind,
132
+ scope: authority.scope,
133
+ ownerSubjectId: connection.subjectId,
134
+ ownerOrganizationMembershipId: connection.ownerOrganizationMembershipId,
135
+ ownerMembershipAuthorizationRevision:
136
+ authority.scope === "user" ? input.userAuthority!.ownerMembershipAuthorizationRevision : null,
137
+ authoritySource,
138
+ selectionSources: input.selectionSources,
139
+ userDelegation,
140
+ });
141
+ }
142
+
143
+ export type LiveConnectionUseState = {
144
+ organizationId: string;
145
+ targetWorkspaceId: string;
146
+ targetWorkspaceAccessActive: boolean;
147
+ session: {
148
+ id: string;
149
+ organizationId: string;
150
+ workspaceId: string;
151
+ visibility: SessionTenancyVisibility;
152
+ authorityEpoch: number;
153
+ active: boolean;
154
+ };
155
+ connection: ConnectionAuthorityCandidate | null;
156
+ ownerMembership: {
157
+ id: string;
158
+ organizationId: string;
159
+ subjectId: string;
160
+ status: "provisioning" | "active" | "suspended" | "revoked";
161
+ authorizationRevision: number;
162
+ } | null;
163
+ userAuthority: UserConnectionAuthorityCandidate | null;
164
+ grant: {
165
+ id: string;
166
+ authorityId: string;
167
+ organizationId: string;
168
+ workspaceId: string;
169
+ sessionId: string | null;
170
+ action: string;
171
+ mode: UserResourceGrantMode;
172
+ context: SessionTenancyVisibility;
173
+ authorityEpoch: number | null;
174
+ generation: number;
175
+ status: UserResourceGrantStatus;
176
+ expiresAt: string | null;
177
+ consumed: boolean;
178
+ } | null;
179
+ };
180
+
181
+ function denied(reason: ConnectionUseDenialReason): ConnectionUseAuthorizationResult {
182
+ return { status: "denied", reason };
183
+ }
184
+
185
+ /**
186
+ * Revalidates every mutable fence immediately before provider use. Callers must
187
+ * resolve the live state in one DB authority boundary; this pure function does
188
+ * not cache, refresh, decrypt, or invoke a provider.
189
+ */
190
+ export function revalidateConnectionUseAuthority(input: {
191
+ snapshot: ConnectionUseAuthoritySnapshot;
192
+ live: LiveConnectionUseState;
193
+ now?: Date;
194
+ }): ConnectionUseAuthorizationResult {
195
+ const snapshot = ConnectionUseAuthoritySnapshot.parse(input.snapshot);
196
+ const live = input.live;
197
+ const now = input.now ?? new Date();
198
+ if (
199
+ live.organizationId !== snapshot.organizationId ||
200
+ live.targetWorkspaceId !== snapshot.targetWorkspaceId
201
+ ) {
202
+ return denied("tenant_mismatch");
203
+ }
204
+ if (!live.targetWorkspaceAccessActive) return denied("workspace_access_inactive");
205
+ if (!live.session.active) return denied("session_inactive");
206
+ if (
207
+ live.session.id !== snapshot.targetSessionId ||
208
+ live.session.organizationId !== snapshot.organizationId ||
209
+ live.session.workspaceId !== snapshot.targetWorkspaceId
210
+ ) {
211
+ return denied("session_identity_changed");
212
+ }
213
+ if (live.session.visibility !== snapshot.targetSessionVisibility) {
214
+ return denied("session_visibility_changed");
215
+ }
216
+ if (live.session.authorityEpoch !== snapshot.targetSessionAuthorityEpoch) {
217
+ return denied("session_authority_epoch_changed");
218
+ }
219
+ const connection = live.connection;
220
+ if (!connection) return denied("connection_missing");
221
+ if (
222
+ connection.id !== snapshot.connectionId ||
223
+ connection.organizationId !== snapshot.organizationId ||
224
+ connection.workspaceId !== snapshot.originWorkspaceId ||
225
+ connection.providerDomain.toLowerCase() !== snapshot.providerDomain ||
226
+ connection.kind !== snapshot.connectionKind
227
+ ) {
228
+ return denied("connection_identity_changed");
229
+ }
230
+ if (connection.generation !== snapshot.connectionGeneration) {
231
+ return denied("connection_generation_changed");
232
+ }
233
+ if (connection.status !== "active") return denied("connection_status_inactive");
234
+ if (
235
+ connection.subjectId !== snapshot.ownerSubjectId ||
236
+ connection.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
237
+ ) {
238
+ return denied("connection_owner_changed");
239
+ }
240
+
241
+ if (snapshot.scope === "workspace") {
242
+ if (connection.subjectId !== null || connection.workspaceId !== snapshot.targetWorkspaceId) {
243
+ return denied("connection_owner_changed");
244
+ }
245
+ return {
246
+ status: "authorized",
247
+ attribution: ConnectionUseAttribution.parse({
248
+ organizationId: snapshot.organizationId,
249
+ workspaceId: snapshot.targetWorkspaceId,
250
+ sessionId: snapshot.targetSessionId,
251
+ connectionId: snapshot.connectionId,
252
+ connectionGeneration: snapshot.connectionGeneration,
253
+ scope: "workspace",
254
+ ownerSubjectId: null,
255
+ authorityId: null,
256
+ grantId: null,
257
+ }),
258
+ };
259
+ }
260
+
261
+ const delegation = snapshot.userDelegation!;
262
+ const membership = live.ownerMembership;
263
+ if (
264
+ !membership ||
265
+ membership.status !== "active" ||
266
+ membership.id !== snapshot.ownerOrganizationMembershipId ||
267
+ membership.organizationId !== snapshot.organizationId ||
268
+ membership.subjectId !== snapshot.ownerSubjectId ||
269
+ membership.authorizationRevision !== snapshot.ownerMembershipAuthorizationRevision
270
+ ) {
271
+ return denied("owner_membership_inactive");
272
+ }
273
+ const authority = live.userAuthority;
274
+ if (!authority) return denied("authority_missing");
275
+ if (
276
+ authority.id !== delegation.authorityId ||
277
+ authority.organizationId !== snapshot.organizationId ||
278
+ authority.resourceKind !== "connection" ||
279
+ authority.resourceId !== snapshot.connectionId ||
280
+ authority.originWorkspaceId !== snapshot.originWorkspaceId ||
281
+ authority.ownerSubjectId !== snapshot.ownerSubjectId ||
282
+ authority.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
283
+ ) {
284
+ return denied("authority_identity_changed");
285
+ }
286
+ if (authority.generation !== delegation.authorityGeneration) {
287
+ return denied("authority_generation_changed");
288
+ }
289
+ if (authority.status !== "active") return denied("authority_status_inactive");
290
+
291
+ const grant = live.grant;
292
+ if (!grant) return denied("grant_missing");
293
+ if (
294
+ grant.id !== delegation.grantId ||
295
+ grant.authorityId !== delegation.authorityId ||
296
+ grant.organizationId !== snapshot.organizationId ||
297
+ grant.workspaceId !== snapshot.targetWorkspaceId ||
298
+ grant.sessionId !== delegation.sessionId ||
299
+ grant.action !== "connection.use" ||
300
+ grant.mode !== delegation.mode ||
301
+ grant.context !== snapshot.targetSessionVisibility ||
302
+ grant.authorityEpoch !== delegation.authorityEpoch
303
+ ) {
304
+ return denied("grant_identity_changed");
305
+ }
306
+ if (grant.generation !== delegation.grantGeneration) {
307
+ return denied("grant_generation_changed");
308
+ }
309
+ if (grant.status !== "active") return denied("grant_status_inactive");
310
+ if (grant.expiresAt !== null && Date.parse(grant.expiresAt) <= now.getTime()) {
311
+ return denied("grant_expired");
312
+ }
313
+ if (grant.mode === "once" && grant.consumed) return denied("grant_already_consumed");
314
+
315
+ return {
316
+ status: "authorized",
317
+ attribution: ConnectionUseAttribution.parse({
318
+ organizationId: snapshot.organizationId,
319
+ workspaceId: snapshot.targetWorkspaceId,
320
+ sessionId: snapshot.targetSessionId,
321
+ connectionId: snapshot.connectionId,
322
+ connectionGeneration: snapshot.connectionGeneration,
323
+ scope: "user",
324
+ ownerSubjectId: snapshot.ownerSubjectId,
325
+ authorityId: delegation.authorityId,
326
+ grantId: delegation.grantId,
327
+ }),
328
+ };
329
+ }
@@ -1,14 +1,12 @@
1
1
  import { createHash } from "node:crypto";
2
2
 
3
- import {
4
- COMMITTED_TRANSACTION_PROTOCOL_VERSION,
5
- EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION,
6
- } from "@opengeni/contracts/editable-artifact-versions";
7
3
  import {
8
4
  DOCUMENT_ARTIFACT_COMMAND_VERSION,
5
+ EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
9
6
  EDITABLE_ARTIFACT_INTENT_VERSION,
10
7
  PRESENTATION_ARTIFACT_COMMAND_VERSION,
11
8
  SPREADSHEET_ARTIFACT_COMMAND_VERSION,
9
+ currentEditableArtifactCompatibility,
12
10
  decodeEditableArtifactMutationIntent,
13
11
  decodeDocumentArtifactQueryResponse,
14
12
  decodePresentationArtifactQueryResponse,
@@ -364,8 +362,9 @@ export class EditableArtifactAgentApplication {
364
362
  }
365
363
  const authored = hashEditableArtifactMutationIntent({
366
364
  envelopeVersion: EDITABLE_ARTIFACT_INTENT_VERSION,
367
- protocolVersion: COMMITTED_TRANSACTION_PROTOCOL_VERSION,
368
- modelSchemaVersion: EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION,
365
+ protocolVersion: EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
366
+ modelSchemaVersion: currentEditableArtifactCompatibility(input.batch.modality)
367
+ .modelSchemaVersion,
369
368
  commandProtocolVersion: commandProtocolVersion(input.batch.modality),
370
369
  artifactId,
371
370
  clientTransactionId,
@@ -564,12 +563,21 @@ function agentContext(input: EditableArtifactAgentContext): EditableArtifactAgen
564
563
 
565
564
  function encodeCommands(batch: EditableArtifactAgentCommandBatch): Uint8Array {
566
565
  if (batch.modality === "spreadsheet") {
567
- return encodeSpreadsheetArtifactCommandBatch({ version: 1, commands: batch.commands });
566
+ return encodeSpreadsheetArtifactCommandBatch({
567
+ version: SPREADSHEET_ARTIFACT_COMMAND_VERSION,
568
+ commands: batch.commands,
569
+ });
568
570
  }
569
571
  if (batch.modality === "document") {
570
- return encodeDocumentArtifactCommandBatch({ version: 1, commands: batch.commands });
572
+ return encodeDocumentArtifactCommandBatch({
573
+ version: DOCUMENT_ARTIFACT_COMMAND_VERSION,
574
+ commands: batch.commands,
575
+ });
571
576
  }
572
- return encodePresentationArtifactCommandBatch({ version: 1, commands: batch.commands });
577
+ return encodePresentationArtifactCommandBatch({
578
+ version: PRESENTATION_ARTIFACT_COMMAND_VERSION,
579
+ commands: batch.commands,
580
+ });
573
581
  }
574
582
 
575
583
  function encodeQuery(request: EditableArtifactAgentQuery): Uint8Array {
@@ -28,9 +28,11 @@ import { hashEditableArtifactCreateRequest, hashEditableArtifactImportRequest }
28
28
  import {
29
29
  EDITABLE_ARTIFACT_COMMAND_MAX_BYTES,
30
30
  EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
31
+ EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
31
32
  EDITABLE_ARTIFACT_INTENT_MAX_UNDO_TARGETS,
32
33
  EDITABLE_ARTIFACT_INTENT_VERSION,
33
34
  EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES,
35
+ EDITABLE_ARTIFACT_CODEC_REGISTRY,
34
36
  } from "@opengeni/contracts/editable-artifacts";
35
37
  import {
36
38
  COMMITTED_TRANSACTION_PROTOCOL_VERSION,
@@ -111,7 +113,6 @@ export const EDITABLE_ARTIFACT_MAX_COMMAND_BYTES_PER_TRANSACTION =
111
113
  EDITABLE_ARTIFACT_COMMAND_MAX_BYTES;
112
114
  export const EDITABLE_ARTIFACT_MAX_INTENT_BYTES_PER_TRANSACTION =
113
115
  EDITABLE_ARTIFACT_INTENT_MAX_BYTES;
114
- export const EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION = 1;
115
116
  export const EDITABLE_ARTIFACT_MAX_OPERATION_BYTES_PER_TRANSACTION =
116
117
  MAX_COMMITTED_TRANSACTION_BYTES;
117
118
  /** Canonical OGACO envelope bound. Kept as an alias for existing consumers. */
@@ -2266,6 +2267,10 @@ function validateSnapshotRequest(
2266
2267
  assertNonnegativeSafeInteger(rawCoveredHeadSequence, "snapshot covered head sequence");
2267
2268
  const stateHash = editableArtifactStateHash(rawStateHash);
2268
2269
  assertPositiveSafeInteger(rawModelSchemaVersion, "snapshot model schema version");
2270
+ const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[rawModality];
2271
+ if (rawModelSchemaVersion !== currentCodec.modelSchemaVersion) {
2272
+ throw new TypeError("Snapshot model schema version is unsupported");
2273
+ }
2269
2274
  assertBoundedKernelVersion(rawKernelVersion);
2270
2275
  assertIsoTimestamp(rawVerifiedAt, "snapshot verified timestamp");
2271
2276
  const common = {
@@ -2294,6 +2299,12 @@ function validateSnapshotRequest(
2294
2299
  }
2295
2300
  assertPositiveSafeInteger(rawOperationProtocolVersion, "snapshot operation protocol version");
2296
2301
  assertPositiveSafeInteger(rawCrdtStateVersion, "snapshot CRDT state version");
2302
+ if (
2303
+ rawOperationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
2304
+ rawCrdtStateVersion !== currentCodec.snapshotVersion
2305
+ ) {
2306
+ throw new TypeError("Spreadsheet snapshot version is unsupported");
2307
+ }
2297
2308
  return Object.freeze({
2298
2309
  ...common,
2299
2310
  modality: "spreadsheet",
@@ -1,4 +1,6 @@
1
1
  import { type BoundedImmutableObjectWritePort, BoundedObjectWriteError } from "@opengeni/storage";
2
+ import { EDITABLE_ARTIFACT_CODEC_REGISTRY } from "@opengeni/contracts/editable-artifacts";
3
+ import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
2
4
 
3
5
  import type { EditableArtifactCompactionPort, EditableArtifactKernelState } from "./ports";
4
6
  import {
@@ -177,6 +179,7 @@ function validateGenerated(
177
179
  scope: EditableArtifactScope,
178
180
  artifactId: EditableArtifactId,
179
181
  ): void {
182
+ const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[value.modality];
180
183
  if (
181
184
  value.scope.accountId !== scope.accountId ||
182
185
  value.scope.workspaceId !== scope.workspaceId ||
@@ -207,11 +210,12 @@ function validateGenerated(
207
210
  throw new EditableArtifactSnapshotVerificationError("limit_exceeded");
208
211
  }
209
212
  editableArtifactContentHash(value.canonicalContentHash);
210
- const versions =
211
- value.modality === "spreadsheet"
212
- ? [value.modelSchemaVersion, value.operationProtocolVersion, value.crdtStateVersion]
213
- : [value.modelSchemaVersion];
214
- if (versions.some((version) => !Number.isSafeInteger(version) || version <= 0)) {
213
+ if (
214
+ value.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
215
+ (value.modality === "spreadsheet" &&
216
+ (value.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
217
+ value.crdtStateVersion !== currentCodec.snapshotVersion))
218
+ ) {
215
219
  throw new EditableArtifactSnapshotVerificationError("version_mismatch");
216
220
  }
217
221
  try {
@@ -1,4 +1,6 @@
1
1
  import { type BoundedImmutableObjectWritePort, BoundedObjectWriteError } from "@opengeni/storage";
2
+ import { EDITABLE_ARTIFACT_CODEC_REGISTRY } from "@opengeni/contracts/editable-artifacts";
3
+ import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
2
4
  import type { EditableArtifactGenesisPort } from "./ports";
3
5
  import {
4
6
  MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES,
@@ -173,6 +175,7 @@ function validateGeneratedGenesis(
173
175
  artifactId: EditableArtifactId,
174
176
  modality: EditableArtifactModality,
175
177
  ): void {
178
+ const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[value.modality];
176
179
  if (
177
180
  value.scope.accountId !== scope.accountId ||
178
181
  value.scope.workspaceId !== scope.workspaceId ||
@@ -198,14 +201,13 @@ function validateGeneratedGenesis(
198
201
  }
199
202
  editableArtifactContentHash(value.canonicalContentHash);
200
203
  editableArtifactStateHash(value.stateHash);
201
- const versions =
202
- value.modality === "spreadsheet"
203
- ? [value.modelSchemaVersion, value.operationProtocolVersion, value.crdtStateVersion]
204
- : [value.modelSchemaVersion];
205
- for (const version of versions) {
206
- if (!Number.isSafeInteger(version) || version <= 0) {
207
- throw new EditableArtifactSnapshotVerificationError("version_mismatch");
208
- }
204
+ if (
205
+ value.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
206
+ (value.modality === "spreadsheet" &&
207
+ (value.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
208
+ value.crdtStateVersion !== currentCodec.snapshotVersion))
209
+ ) {
210
+ throw new EditableArtifactSnapshotVerificationError("version_mismatch");
209
211
  }
210
212
  try {
211
213
  assertBoundedKernelVersion(value.kernelVersion);
@@ -7,7 +7,11 @@ import {
7
7
  } from "@opengeni/storage";
8
8
  import type { EditableArtifactSnapshotVerifierPort } from "./ports";
9
9
  import { decodeEditableArtifactSerializedCommit } from "@opengeni/contracts/editable-artifact-serialized-commit";
10
- import { EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES } from "@opengeni/contracts/editable-artifacts";
10
+ import {
11
+ EDITABLE_ARTIFACT_CODEC_REGISTRY,
12
+ EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES,
13
+ } from "@opengeni/contracts/editable-artifacts";
14
+ import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
11
15
  import {
12
16
  causalFrontiersEqual,
13
17
  editableArtifactCausalFrontier,
@@ -520,6 +524,7 @@ function validateKernelResult(
520
524
  >
521
525
  | undefined,
522
526
  ): void {
527
+ const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[snapshot.modality];
523
528
  if (
524
529
  result.canonicalReencodeVerified !== true ||
525
530
  result.modality !== snapshot.modality ||
@@ -542,8 +547,8 @@ function validateKernelResult(
542
547
  throw new EditableArtifactSnapshotVerificationError("state_hash_mismatch");
543
548
  }
544
549
  if (
545
- result.modelSchemaVersion !== snapshot.modelSchemaVersion ||
546
- result.kernelVersion !== snapshot.kernelVersion
550
+ snapshot.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
551
+ result.modelSchemaVersion !== snapshot.modelSchemaVersion
547
552
  ) {
548
553
  throw new EditableArtifactSnapshotVerificationError("version_mismatch");
549
554
  }
@@ -559,6 +564,8 @@ function validateKernelResult(
559
564
  throw new EditableArtifactSnapshotVerificationError("frontier_mismatch");
560
565
  }
561
566
  if (
567
+ snapshot.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
568
+ snapshot.crdtStateVersion !== currentCodec.snapshotVersion ||
562
569
  result.operationProtocolVersion !== snapshot.operationProtocolVersion ||
563
570
  result.crdtStateVersion !== snapshot.crdtStateVersion
564
571
  ) {
@@ -69,10 +69,18 @@ export const requireEnvironmentEncryption = requireVariableSetEncryption;
69
69
 
70
70
  export async function requireVariableSetForApi(
71
71
  db: Database,
72
- workspaceId: string,
72
+ grant: AccessGrant,
73
73
  variableSetId: string,
74
74
  ): Promise<VariableSet> {
75
- const variableSet = await getVariableSet(db, workspaceId, variableSetId);
75
+ const variableSet = await getVariableSet(
76
+ db,
77
+ {
78
+ accountId: grant.accountId,
79
+ workspaceId: grant.workspaceId,
80
+ subjectId: grant.subjectId,
81
+ },
82
+ variableSetId,
83
+ );
76
84
  if (!variableSet) {
77
85
  throw new HTTPException(404, { message: "variableSet not found" });
78
86
  }
@@ -97,9 +105,14 @@ export async function validateVariableSetAttachment(
97
105
  ): Promise<VariableSet> {
98
106
  requireVariableSetEncryption(deps.settings);
99
107
  if (!options.preauthorized) {
108
+ requirePermission(grant, "variable-sets:attach");
100
109
  requirePermission(grant, "variable-sets:use");
101
110
  }
102
- const variableSet = await getVariableSet(deps.db, workspaceId, variableSetId);
111
+ const variableSet = await getVariableSet(
112
+ deps.db,
113
+ { accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
114
+ variableSetId,
115
+ );
103
116
  if (!variableSet) {
104
117
  throw new HTTPException(422, { message: "unknown variableSetId" });
105
118
  }