@opengeni/db 3.5.2-canary.0 → 3.6.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.
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-NRGUX3M5.js → chunk-2NT476HD.js} +2 -2
- package/dist/{chunk-PERPE2UY.js → chunk-744DFC65.js} +31 -1
- package/dist/chunk-744DFC65.js.map +1 -0
- package/dist/{chunk-FJHEWYV5.js → chunk-CDMMSUWJ.js} +3 -3
- package/dist/{chunk-TRCYF26N.js → chunk-G3732M3T.js} +2 -2
- package/dist/{chunk-ORKVXHL2.js → chunk-IW6O6G7R.js} +2 -2
- package/dist/{chunk-Y44FKTYU.js → chunk-Q5YUGQVK.js} +3 -3
- package/dist/{chunk-U7NKCX5E.js → chunk-UGDVSQ6U.js} +2 -2
- package/dist/{chunk-6NYKC5DD.js → chunk-UJ2EW3QI.js} +4729 -4583
- package/dist/chunk-UJ2EW3QI.js.map +1 -0
- package/dist/{chunk-X6T2P3L3.js → chunk-WW7AJ5IC.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +2112 -1436
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +5 -4
- package/dist/schema.d.ts +7 -6
- package/dist/schema.js +7 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/dist/work-claims-schema.d.ts +975 -0
- package/dist/work-claims.d.ts +83 -0
- package/drizzle/0365_permission_scoped_work_claims.sql +1306 -0
- package/drizzle/0366_session_discovery_title_search_index.sql +5 -0
- package/drizzle/0367_session_discovery_goal_search_index.sql +5 -0
- package/drizzle/0368_session_discovery_claim_search_index.sql +6 -0
- package/package.json +6 -6
- package/src/index.ts +1051 -330
- package/src/provision-roles.ts +18 -0
- package/src/runtime-posture.ts +12 -0
- package/src/schema.ts +1 -0
- package/src/work-claims-schema.ts +148 -0
- package/src/work-claims.ts +200 -0
- package/dist/chunk-6NYKC5DD.js.map +0 -1
- package/dist/chunk-PERPE2UY.js.map +0 -1
- /package/dist/{chunk-NRGUX3M5.js.map → chunk-2NT476HD.js.map} +0 -0
- /package/dist/{chunk-FJHEWYV5.js.map → chunk-CDMMSUWJ.js.map} +0 -0
- /package/dist/{chunk-TRCYF26N.js.map → chunk-G3732M3T.js.map} +0 -0
- /package/dist/{chunk-ORKVXHL2.js.map → chunk-IW6O6G7R.js.map} +0 -0
- /package/dist/{chunk-Y44FKTYU.js.map → chunk-Q5YUGQVK.js.map} +0 -0
- /package/dist/{chunk-U7NKCX5E.js.map → chunk-UGDVSQ6U.js.map} +0 -0
- /package/dist/{chunk-X6T2P3L3.js.map → chunk-WW7AJ5IC.js.map} +0 -0
package/src/provision-roles.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
RUNTIME_READ_INSERT_UPDATE_TABLES,
|
|
7
7
|
RUNTIME_READ_ONLY_TABLES,
|
|
8
8
|
RUNTIME_READ_UPDATE_TABLES,
|
|
9
|
+
WORK_CLAIM_CAPABILITY_ROUTINES,
|
|
9
10
|
} from "./runtime-posture";
|
|
10
11
|
import {
|
|
11
12
|
classifyRoleRelationships,
|
|
@@ -482,6 +483,7 @@ async function grantAppRoleIfSchemaExists(
|
|
|
482
483
|
const runtimeReadUpdateTables = `ARRAY[${RUNTIME_READ_UPDATE_TABLES.map(literal).join(", ")}]`;
|
|
483
484
|
const runtimeReadInsertTables = `ARRAY[${RUNTIME_READ_INSERT_TABLES.map(literal).join(", ")}]`;
|
|
484
485
|
const runtimeReadInsertUpdateTables = `ARRAY[${RUNTIME_READ_INSERT_UPDATE_TABLES.map(literal).join(", ")}]`;
|
|
486
|
+
const workClaimCapabilityRoutines = `ARRAY[${WORK_CLAIM_CAPABILITY_ROUTINES.map(literal).join(", ")}]`;
|
|
485
487
|
const organizationMembershipLifecycleRoutines = `ARRAY[${[
|
|
486
488
|
"list_self_organization_memberships(text)",
|
|
487
489
|
"list_self_organization_invitations(text)",
|
|
@@ -997,6 +999,22 @@ BEGIN
|
|
|
997
999
|
${literal(role)}
|
|
998
1000
|
);
|
|
999
1001
|
END IF;
|
|
1002
|
+
-- Migration 0365 creates the advisory work-claim mutation capabilities
|
|
1003
|
+
-- before a custom runtime role may exist. Re-converge their exact grants
|
|
1004
|
+
-- for migrate-then-provision installs without exposing claim history or
|
|
1005
|
+
-- the write-capability ledger to direct runtime DML.
|
|
1006
|
+
FOREACH routine_signature IN ARRAY ${workClaimCapabilityRoutines} LOOP
|
|
1007
|
+
IF to_regprocedure(format('%I.%s', ${literal(schema)}, routine_signature)) IS NOT NULL THEN
|
|
1008
|
+
EXECUTE format(
|
|
1009
|
+
'REVOKE ALL ON FUNCTION %I.%s FROM PUBLIC',
|
|
1010
|
+
${literal(schema)}, routine_signature
|
|
1011
|
+
);
|
|
1012
|
+
EXECUTE format(
|
|
1013
|
+
'GRANT EXECUTE ON FUNCTION %I.%s TO %I',
|
|
1014
|
+
${literal(schema)}, routine_signature, ${literal(role)}
|
|
1015
|
+
);
|
|
1016
|
+
END IF;
|
|
1017
|
+
END LOOP;
|
|
1000
1018
|
IF to_regprocedure(
|
|
1001
1019
|
format(
|
|
1002
1020
|
'%I.workspace_instruction_policy_get_or_create_snapshot(uuid,uuid,uuid,uuid,uuid,integer)',
|
package/src/runtime-posture.ts
CHANGED
|
@@ -377,6 +377,10 @@ const TASK_NOTE_CAPABILITY_ROUTINES = [
|
|
|
377
377
|
"replace_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, integer, text, text, integer, text)",
|
|
378
378
|
"resolve_task_note_knowledge_promotion_source(uuid, uuid, uuid, uuid, uuid, integer, uuid, integer, text, text, text)",
|
|
379
379
|
] as const;
|
|
380
|
+
export const WORK_CLAIM_CAPABILITY_ROUTINES = [
|
|
381
|
+
"upsert_session_work_claim_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, integer, text, text, text, text, text, text, text)",
|
|
382
|
+
"release_session_work_claim_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, integer, text)",
|
|
383
|
+
] as const;
|
|
380
384
|
const COMPANY_BRAIN_CONTEXT_SELECTION_ROUTINE =
|
|
381
385
|
"company_brain_context_get_or_create_selection(uuid, uuid, uuid, uuid, uuid, integer)";
|
|
382
386
|
const COMPANY_BRAIN_CONTEXT_INSPECTION_ROUTINE =
|
|
@@ -500,6 +504,7 @@ const SESSION_AUTHORITY_ROUTINES = new Set<string>([
|
|
|
500
504
|
...PRIVATE_SESSION_CREATE_CAPABILITY_ROUTINES,
|
|
501
505
|
TRANSITION_SESSION_VISIBILITY_ROUTINE,
|
|
502
506
|
...TASK_NOTE_CAPABILITY_ROUTINES,
|
|
507
|
+
...WORK_CLAIM_CAPABILITY_ROUTINES,
|
|
503
508
|
COMPANY_BRAIN_CONTEXT_SELECTION_ROUTINE,
|
|
504
509
|
COMPANY_BRAIN_CONTEXT_INSPECTION_ROUTINE,
|
|
505
510
|
]);
|
|
@@ -557,6 +562,7 @@ export const RUNTIME_TARGET_SCHEMA_CAPABILITY_ROUTINES = [
|
|
|
557
562
|
...MANAGED_AUTH_SESSION_SET_ROUTINES,
|
|
558
563
|
...ORGANIZATION_RECOVERY_ROUTINES,
|
|
559
564
|
...TASK_NOTE_CAPABILITY_ROUTINES,
|
|
565
|
+
...WORK_CLAIM_CAPABILITY_ROUTINES,
|
|
560
566
|
SESSION_PRIVATE_ACTOR_VISIBLE_ROUTINE,
|
|
561
567
|
SESSION_REFERENCE_VISIBLE_ROUTINE,
|
|
562
568
|
SESSION_VISIBILITY_LIFECYCLE_CAPABILITY_ROUTINE,
|
|
@@ -868,6 +874,9 @@ export const FORCE_RLS_TABLES = [
|
|
|
868
874
|
"session_turns",
|
|
869
875
|
"session_variable_set_attachments",
|
|
870
876
|
"session_visibility_write_capabilities",
|
|
877
|
+
"session_work_claim_revisions",
|
|
878
|
+
"session_work_claim_write_capabilities",
|
|
879
|
+
"session_work_claims",
|
|
871
880
|
"session_workflow_wake_outbox",
|
|
872
881
|
"sessions",
|
|
873
882
|
"site_auth_connections",
|
|
@@ -1136,6 +1145,7 @@ export const RUNTIME_READ_ONLY_TABLES = [
|
|
|
1136
1145
|
"preference_registry_events",
|
|
1137
1146
|
"preference_registry_snapshots",
|
|
1138
1147
|
"session_tenancy_activations",
|
|
1148
|
+
"session_work_claims",
|
|
1139
1149
|
"slack_installation_bindings",
|
|
1140
1150
|
"slack_task_policy_activation_events",
|
|
1141
1151
|
"slack_task_policy_heads",
|
|
@@ -1330,6 +1340,8 @@ export const PROTECTED_NO_DIRECT_DML_TABLES = [
|
|
|
1330
1340
|
"session_tenancy_greenfield_activation_evidence",
|
|
1331
1341
|
"session_variable_set_attachments",
|
|
1332
1342
|
"session_visibility_write_capabilities",
|
|
1343
|
+
"session_work_claim_revisions",
|
|
1344
|
+
"session_work_claim_write_capabilities",
|
|
1333
1345
|
"task_note_events",
|
|
1334
1346
|
"task_note_knowledge_promotion_capabilities",
|
|
1335
1347
|
"task_note_replacement_receipts",
|
package/src/schema.ts
CHANGED
|
@@ -12483,6 +12483,7 @@ export * from "./preference-registry-schema";
|
|
|
12483
12483
|
export * from "./memory-governance-schema";
|
|
12484
12484
|
export * from "./scoped-knowledge-schema";
|
|
12485
12485
|
export * from "./task-notes-schema";
|
|
12486
|
+
export * from "./work-claims-schema";
|
|
12486
12487
|
export * from "./company-brain-context-selection-schema";
|
|
12487
12488
|
export * from "./governed-learning-evaluator-schema";
|
|
12488
12489
|
export * from "./governed-learning-activation-schema";
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
customType,
|
|
4
|
+
index,
|
|
5
|
+
integer,
|
|
6
|
+
pgTable,
|
|
7
|
+
primaryKey,
|
|
8
|
+
text,
|
|
9
|
+
timestamp,
|
|
10
|
+
uniqueIndex,
|
|
11
|
+
uuid,
|
|
12
|
+
} from "drizzle-orm/pg-core";
|
|
13
|
+
|
|
14
|
+
const xid8 = customType<{ data: string; driverData: string }>({
|
|
15
|
+
dataType: () => "xid8",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Exact lifecycle-only mutation, immutable revisions, FORCE RLS, and runtime
|
|
19
|
+
// grants are owned by the work-claim migration. The application role receives
|
|
20
|
+
// SELECT on the compact head plus EXECUTE on exact-attempt mutation routines,
|
|
21
|
+
// never direct DML authority.
|
|
22
|
+
export const sessionWorkClaims = pgTable(
|
|
23
|
+
"session_work_claims",
|
|
24
|
+
{
|
|
25
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
26
|
+
accountId: uuid("account_id").notNull(),
|
|
27
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
28
|
+
sessionId: uuid("session_id").notNull(),
|
|
29
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
30
|
+
subjectNamespace: text("subject_namespace").notNull(),
|
|
31
|
+
subjectType: text("subject_type").notNull(),
|
|
32
|
+
canonicalKey: text("canonical_key").notNull(),
|
|
33
|
+
subjectDigest: text("subject_digest").notNull(),
|
|
34
|
+
displayLabel: text("display_label"),
|
|
35
|
+
role: text("role").notNull(),
|
|
36
|
+
state: text("state").notNull().default("active"),
|
|
37
|
+
revision: integer("revision").notNull().default(1),
|
|
38
|
+
provenance: text("provenance").notNull(),
|
|
39
|
+
versionKind: text("version_kind"),
|
|
40
|
+
versionValue: text("version_value"),
|
|
41
|
+
observedAt: timestamp("observed_at", { withTimezone: true }).notNull(),
|
|
42
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
43
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
44
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
45
|
+
},
|
|
46
|
+
(table) => ({
|
|
47
|
+
workspaceIdentity: uniqueIndex("session_work_claims_workspace_id_uq").on(
|
|
48
|
+
table.workspaceId,
|
|
49
|
+
table.id,
|
|
50
|
+
),
|
|
51
|
+
activeIdentity: uniqueIndex("session_work_claims_active_identity_uq")
|
|
52
|
+
.on(
|
|
53
|
+
table.workspaceId,
|
|
54
|
+
table.sessionId,
|
|
55
|
+
table.subjectNamespace,
|
|
56
|
+
table.subjectType,
|
|
57
|
+
table.subjectDigest,
|
|
58
|
+
table.role,
|
|
59
|
+
)
|
|
60
|
+
.where(sql`${table.state} = 'active'`),
|
|
61
|
+
sessionState: index("session_work_claims_session_state_idx").on(
|
|
62
|
+
table.workspaceId,
|
|
63
|
+
table.sessionId,
|
|
64
|
+
table.state,
|
|
65
|
+
table.updatedAt,
|
|
66
|
+
table.id,
|
|
67
|
+
),
|
|
68
|
+
subjectState: index("session_work_claims_subject_state_idx").on(
|
|
69
|
+
table.workspaceId,
|
|
70
|
+
table.subjectNamespace,
|
|
71
|
+
table.subjectType,
|
|
72
|
+
table.subjectDigest,
|
|
73
|
+
table.state,
|
|
74
|
+
table.updatedAt,
|
|
75
|
+
table.id,
|
|
76
|
+
),
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export const sessionWorkClaimRevisions = pgTable(
|
|
81
|
+
"session_work_claim_revisions",
|
|
82
|
+
{
|
|
83
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
84
|
+
accountId: uuid("account_id").notNull(),
|
|
85
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
86
|
+
claimId: uuid("claim_id").notNull(),
|
|
87
|
+
sessionId: uuid("session_id").notNull(),
|
|
88
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
89
|
+
operationId: uuid("operation_id").notNull(),
|
|
90
|
+
inputHash: text("input_hash").notNull(),
|
|
91
|
+
mutationKind: text("mutation_kind").notNull(),
|
|
92
|
+
priorRevision: integer("prior_revision"),
|
|
93
|
+
resultingRevision: integer("resulting_revision").notNull(),
|
|
94
|
+
subjectNamespace: text("subject_namespace").notNull(),
|
|
95
|
+
subjectType: text("subject_type").notNull(),
|
|
96
|
+
canonicalKey: text("canonical_key").notNull(),
|
|
97
|
+
subjectDigest: text("subject_digest").notNull(),
|
|
98
|
+
displayLabel: text("display_label"),
|
|
99
|
+
role: text("role").notNull(),
|
|
100
|
+
state: text("state").notNull(),
|
|
101
|
+
provenance: text("provenance").notNull(),
|
|
102
|
+
versionKind: text("version_kind"),
|
|
103
|
+
versionValue: text("version_value"),
|
|
104
|
+
observedAt: timestamp("observed_at", { withTimezone: true }).notNull(),
|
|
105
|
+
claimCreatedAt: timestamp("claim_created_at", { withTimezone: true }).notNull(),
|
|
106
|
+
claimUpdatedAt: timestamp("claim_updated_at", { withTimezone: true }).notNull(),
|
|
107
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
108
|
+
actorKind: text("actor_kind").notNull(),
|
|
109
|
+
actorSubjectId: text("actor_subject_id").notNull(),
|
|
110
|
+
actorSessionId: uuid("actor_session_id"),
|
|
111
|
+
actorTurnId: uuid("actor_turn_id"),
|
|
112
|
+
actorAttemptId: uuid("actor_attempt_id"),
|
|
113
|
+
actorExecutionGeneration: integer("actor_execution_generation"),
|
|
114
|
+
reason: text("reason"),
|
|
115
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
116
|
+
},
|
|
117
|
+
(table) => ({
|
|
118
|
+
operation: uniqueIndex("session_work_claim_revisions_workspace_operation_uq").on(
|
|
119
|
+
table.workspaceId,
|
|
120
|
+
table.operationId,
|
|
121
|
+
),
|
|
122
|
+
claimRevision: uniqueIndex("session_work_claim_revisions_claim_revision_uq").on(
|
|
123
|
+
table.workspaceId,
|
|
124
|
+
table.claimId,
|
|
125
|
+
table.resultingRevision,
|
|
126
|
+
),
|
|
127
|
+
sessionTimeline: index("session_work_claim_revisions_session_timeline_idx").on(
|
|
128
|
+
table.workspaceId,
|
|
129
|
+
table.sessionId,
|
|
130
|
+
table.createdAt,
|
|
131
|
+
table.id,
|
|
132
|
+
),
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
export const sessionWorkClaimWriteCapabilities = pgTable(
|
|
137
|
+
"session_work_claim_write_capabilities",
|
|
138
|
+
{
|
|
139
|
+
backendPid: integer("backend_pid").notNull(),
|
|
140
|
+
transactionId: xid8("transaction_id").notNull(),
|
|
141
|
+
capabilityId: uuid("capability_id").notNull(),
|
|
142
|
+
},
|
|
143
|
+
(table) => ({
|
|
144
|
+
identity: primaryKey({
|
|
145
|
+
columns: [table.backendPid, table.transactionId, table.capabilityId],
|
|
146
|
+
}),
|
|
147
|
+
}),
|
|
148
|
+
);
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WorkClaim,
|
|
3
|
+
WorkClaimCanonicalKey,
|
|
4
|
+
WorkClaimDisplayLabel,
|
|
5
|
+
WorkClaimMutationKind,
|
|
6
|
+
WorkClaimMutationResult,
|
|
7
|
+
WorkClaimNamespace,
|
|
8
|
+
WorkClaimReleaseReason,
|
|
9
|
+
WorkClaimRole,
|
|
10
|
+
WorkClaimSubjectType,
|
|
11
|
+
WorkClaimVersionKind,
|
|
12
|
+
WorkClaimVersionValue,
|
|
13
|
+
normalizeWorkClaimCanonicalKey,
|
|
14
|
+
normalizeWorkClaimDisplayLabel,
|
|
15
|
+
normalizeWorkClaimNamespace,
|
|
16
|
+
type WorkClaimRole as WorkClaimRoleType,
|
|
17
|
+
type WorkClaimSubjectType as WorkClaimSubjectTypeType,
|
|
18
|
+
type WorkClaimVersionKind as WorkClaimVersionKindType,
|
|
19
|
+
} from "@opengeni/contracts";
|
|
20
|
+
import { sql } from "drizzle-orm";
|
|
21
|
+
import type { Database } from "./database";
|
|
22
|
+
import { rawRows, withSessionActivityRlsContext } from "./database";
|
|
23
|
+
|
|
24
|
+
export type WorkClaimAttemptClaims = {
|
|
25
|
+
accountId: string;
|
|
26
|
+
workspaceId: string;
|
|
27
|
+
sessionId: string;
|
|
28
|
+
turnId: string;
|
|
29
|
+
attemptId: string;
|
|
30
|
+
executionGeneration: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type UpsertWorkClaimInput = WorkClaimAttemptClaims & {
|
|
34
|
+
operationId: string;
|
|
35
|
+
expectedRevision: number;
|
|
36
|
+
subjectNamespace: string;
|
|
37
|
+
subjectType: WorkClaimSubjectTypeType;
|
|
38
|
+
canonicalKey: string;
|
|
39
|
+
displayLabel?: string | null;
|
|
40
|
+
role: WorkClaimRoleType;
|
|
41
|
+
version?: {
|
|
42
|
+
kind: WorkClaimVersionKindType;
|
|
43
|
+
value: string;
|
|
44
|
+
} | null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type ReleaseWorkClaimInput = WorkClaimAttemptClaims & {
|
|
48
|
+
operationId: string;
|
|
49
|
+
claimId: string;
|
|
50
|
+
expectedRevision: number;
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type WorkClaimMutationRow = {
|
|
55
|
+
claim_id: string;
|
|
56
|
+
session_id: string;
|
|
57
|
+
root_session_id: string;
|
|
58
|
+
subject_namespace: string;
|
|
59
|
+
subject_type: string;
|
|
60
|
+
canonical_key: string;
|
|
61
|
+
display_label: string | null;
|
|
62
|
+
role: string;
|
|
63
|
+
state: string;
|
|
64
|
+
revision: number;
|
|
65
|
+
provenance: string;
|
|
66
|
+
version_kind: string | null;
|
|
67
|
+
version_value: string | null;
|
|
68
|
+
observed_at: Date | string;
|
|
69
|
+
created_at: Date | string;
|
|
70
|
+
updated_at: Date | string;
|
|
71
|
+
settled_at: Date | string | null;
|
|
72
|
+
mutation_kind: string;
|
|
73
|
+
replayed: boolean;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function iso(value: Date | string): string {
|
|
77
|
+
return (value instanceof Date ? value : new Date(value)).toISOString();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function assertAttemptClaims(claims: WorkClaimAttemptClaims): void {
|
|
81
|
+
if (!Number.isSafeInteger(claims.executionGeneration) || claims.executionGeneration < 1) {
|
|
82
|
+
throw new Error("Work claims require a positive exact execution generation");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function mutationResultFromRow(row: WorkClaimMutationRow) {
|
|
87
|
+
const version =
|
|
88
|
+
row.version_kind === null || row.version_value === null
|
|
89
|
+
? null
|
|
90
|
+
: {
|
|
91
|
+
kind: WorkClaimVersionKind.parse(row.version_kind),
|
|
92
|
+
value: WorkClaimVersionValue.parse(row.version_value),
|
|
93
|
+
};
|
|
94
|
+
return WorkClaimMutationResult.parse({
|
|
95
|
+
claim: WorkClaim.parse({
|
|
96
|
+
id: row.claim_id,
|
|
97
|
+
sessionId: row.session_id,
|
|
98
|
+
rootSessionId: row.root_session_id,
|
|
99
|
+
subject: {
|
|
100
|
+
namespace: row.subject_namespace,
|
|
101
|
+
type: row.subject_type,
|
|
102
|
+
canonicalKey: row.canonical_key,
|
|
103
|
+
displayLabel: row.display_label,
|
|
104
|
+
},
|
|
105
|
+
role: row.role,
|
|
106
|
+
state: row.state,
|
|
107
|
+
revision: Number(row.revision),
|
|
108
|
+
provenance: row.provenance,
|
|
109
|
+
version,
|
|
110
|
+
observedAt: iso(row.observed_at),
|
|
111
|
+
createdAt: iso(row.created_at),
|
|
112
|
+
updatedAt: iso(row.updated_at),
|
|
113
|
+
settledAt: row.settled_at === null ? null : iso(row.settled_at),
|
|
114
|
+
}),
|
|
115
|
+
mutation: WorkClaimMutationKind.parse(row.mutation_kind),
|
|
116
|
+
replayed: row.replayed,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function upsertWorkClaim(db: Database, input: UpsertWorkClaimInput) {
|
|
121
|
+
assertAttemptClaims(input);
|
|
122
|
+
if (!Number.isSafeInteger(input.expectedRevision) || input.expectedRevision < 0) {
|
|
123
|
+
throw new Error("Work claim expectedRevision must be a non-negative safe integer");
|
|
124
|
+
}
|
|
125
|
+
const subjectNamespace = WorkClaimNamespace.parse(
|
|
126
|
+
normalizeWorkClaimNamespace(input.subjectNamespace),
|
|
127
|
+
);
|
|
128
|
+
const subjectType = WorkClaimSubjectType.parse(input.subjectType);
|
|
129
|
+
const canonicalKey = WorkClaimCanonicalKey.parse(
|
|
130
|
+
normalizeWorkClaimCanonicalKey(input.canonicalKey),
|
|
131
|
+
);
|
|
132
|
+
const role = WorkClaimRole.parse(input.role);
|
|
133
|
+
const displayLabel =
|
|
134
|
+
input.displayLabel === undefined || input.displayLabel === null
|
|
135
|
+
? null
|
|
136
|
+
: WorkClaimDisplayLabel.parse(normalizeWorkClaimDisplayLabel(input.displayLabel));
|
|
137
|
+
const version = input.version
|
|
138
|
+
? {
|
|
139
|
+
kind: WorkClaimVersionKind.parse(input.version.kind),
|
|
140
|
+
value: WorkClaimVersionValue.parse(normalizeWorkClaimCanonicalKey(input.version.value)),
|
|
141
|
+
}
|
|
142
|
+
: null;
|
|
143
|
+
const rows = await withSessionActivityRlsContext(
|
|
144
|
+
db,
|
|
145
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
146
|
+
async (tx) =>
|
|
147
|
+
await rawRows<WorkClaimMutationRow>(
|
|
148
|
+
tx,
|
|
149
|
+
sql`SELECT * FROM upsert_session_work_claim_for_attempt(
|
|
150
|
+
${input.accountId}::uuid,
|
|
151
|
+
${input.workspaceId}::uuid,
|
|
152
|
+
${input.sessionId}::uuid,
|
|
153
|
+
${input.turnId}::uuid,
|
|
154
|
+
${input.attemptId}::uuid,
|
|
155
|
+
${input.executionGeneration}::integer,
|
|
156
|
+
${input.operationId}::uuid,
|
|
157
|
+
${input.expectedRevision}::integer,
|
|
158
|
+
${subjectNamespace}::text,
|
|
159
|
+
${subjectType}::text,
|
|
160
|
+
${canonicalKey}::text,
|
|
161
|
+
${displayLabel}::text,
|
|
162
|
+
${role}::text,
|
|
163
|
+
${version?.kind ?? null}::text,
|
|
164
|
+
${version?.value ?? null}::text
|
|
165
|
+
)`,
|
|
166
|
+
),
|
|
167
|
+
);
|
|
168
|
+
if (rows.length !== 1) throw new Error("Work claim upsert returned no durable receipt");
|
|
169
|
+
return mutationResultFromRow(rows[0]!);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function releaseWorkClaim(db: Database, input: ReleaseWorkClaimInput) {
|
|
173
|
+
assertAttemptClaims(input);
|
|
174
|
+
if (!Number.isSafeInteger(input.expectedRevision) || input.expectedRevision < 1) {
|
|
175
|
+
throw new Error("Work claim release requires a positive expectedRevision");
|
|
176
|
+
}
|
|
177
|
+
const reason = WorkClaimReleaseReason.parse(input.reason);
|
|
178
|
+
const rows = await withSessionActivityRlsContext(
|
|
179
|
+
db,
|
|
180
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
181
|
+
async (tx) =>
|
|
182
|
+
await rawRows<WorkClaimMutationRow>(
|
|
183
|
+
tx,
|
|
184
|
+
sql`SELECT * FROM release_session_work_claim_for_attempt(
|
|
185
|
+
${input.accountId}::uuid,
|
|
186
|
+
${input.workspaceId}::uuid,
|
|
187
|
+
${input.sessionId}::uuid,
|
|
188
|
+
${input.turnId}::uuid,
|
|
189
|
+
${input.attemptId}::uuid,
|
|
190
|
+
${input.executionGeneration}::integer,
|
|
191
|
+
${input.operationId}::uuid,
|
|
192
|
+
${input.claimId}::uuid,
|
|
193
|
+
${input.expectedRevision}::integer,
|
|
194
|
+
${reason}::text
|
|
195
|
+
)`,
|
|
196
|
+
),
|
|
197
|
+
);
|
|
198
|
+
if (rows.length !== 1) throw new Error("Work claim release returned no durable receipt");
|
|
199
|
+
return mutationResultFromRow(rows[0]!);
|
|
200
|
+
}
|