@opengeni/db 0.28.1 → 0.31.1

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 (187) hide show
  1. package/dist/attached-browser-devices.d.ts +42 -0
  2. package/dist/attempt-tool-catalogs.d.ts +16 -0
  3. package/dist/browser-auth.d.ts +91 -0
  4. package/dist/browser-identities.d.ts +128 -0
  5. package/dist/browser-sessions.d.ts +272 -0
  6. package/dist/browser-state-artifacts.d.ts +17 -0
  7. package/dist/capability-components.d.ts +37 -0
  8. package/dist/capability-integrations.d.ts +192 -0
  9. package/dist/chunk-F5FT7BEZ.js +3535 -0
  10. package/dist/chunk-F5FT7BEZ.js.map +1 -0
  11. package/dist/chunk-ISI2TIUG.js +639 -0
  12. package/dist/chunk-ISI2TIUG.js.map +1 -0
  13. package/dist/chunk-MWDVXQOL.js +11639 -0
  14. package/dist/chunk-MWDVXQOL.js.map +1 -0
  15. package/dist/chunk-NBE6CHRI.js +955 -0
  16. package/dist/chunk-NBE6CHRI.js.map +1 -0
  17. package/dist/{chunk-DBS5HPEW.js → chunk-YHZXQ7HP.js} +760 -11
  18. package/dist/chunk-YHZXQ7HP.js.map +1 -0
  19. package/dist/codemode-operations.d.ts +117 -0
  20. package/dist/codex-token-resolver.d.ts +2 -2
  21. package/dist/company-profile-schema.d.ts +798 -0
  22. package/dist/company-profile.d.ts +268 -0
  23. package/dist/computer-sessions.d.ts +109 -0
  24. package/dist/connection-token-resolver.d.ts +9 -4
  25. package/dist/database.d.ts +52 -3
  26. package/dist/editable-artifact-durable-export.d.ts +153 -0
  27. package/dist/editable-artifact-durable-export.js +788 -0
  28. package/dist/editable-artifact-durable-export.js.map +1 -0
  29. package/dist/editable-artifact-materialization.d.ts +123 -0
  30. package/dist/editable-artifacts-schema.d.ts +4152 -0
  31. package/dist/editable-artifacts.d.ts +610 -0
  32. package/dist/editable-artifacts.js +26 -0
  33. package/dist/editable-artifacts.js.map +1 -0
  34. package/dist/environment-crypto.d.ts +8 -4
  35. package/dist/generated-images.d.ts +139 -0
  36. package/dist/index.d.ts +958 -126
  37. package/dist/index.js +31204 -12172
  38. package/dist/index.js.map +1 -1
  39. package/dist/insights.d.ts +51 -4
  40. package/dist/integration-bindings.d.ts +70 -0
  41. package/dist/integration-features.d.ts +99 -0
  42. package/dist/interaction-revisions.d.ts +3 -0
  43. package/dist/interaction-schema.d.ts +5372 -0
  44. package/dist/knowledge-source-sync-schema.d.ts +1679 -0
  45. package/dist/knowledge-source-sync.d.ts +274 -0
  46. package/dist/lossless-columns.d.ts +58 -0
  47. package/dist/lossless-json.d.ts +39 -0
  48. package/dist/memory-domain.d.ts +3 -6
  49. package/dist/memory-governance.d.ts +2 -2
  50. package/dist/memory-slack-delivery.d.ts +101 -0
  51. package/dist/new-session-drafts.d.ts +2 -2
  52. package/dist/pack-components.d.ts +76 -0
  53. package/dist/pack-installations.d.ts +86 -0
  54. package/dist/persistence-errors.d.ts +7 -14
  55. package/dist/plugin-packages.d.ts +126 -0
  56. package/dist/preference-registry.d.ts +1 -1
  57. package/dist/provision-roles.d.ts +9 -1
  58. package/dist/provision-roles.js +1 -1
  59. package/dist/runtime-posture.d.ts +18 -6
  60. package/dist/schema.d.ts +19122 -8731
  61. package/dist/schema.js +173 -1
  62. package/dist/scoped-knowledge.d.ts +97 -1
  63. package/dist/session-control.d.ts +4 -4
  64. package/dist/session-queue-commands.d.ts +19 -11
  65. package/dist/session-realtime-context.d.ts +2 -2
  66. package/dist/session-realtime-ledger.d.ts +4 -4
  67. package/dist/session-realtime-mirror.d.ts +2 -2
  68. package/dist/session-realtime-state.d.ts +1 -1
  69. package/dist/session-realtime-terminal.d.ts +8 -1
  70. package/dist/session-realtime.d.ts +7 -7
  71. package/dist/session-tool-call-settlement.d.ts +1 -1
  72. package/dist/slack-user-link-access.d.ts +54 -0
  73. package/dist/transcription-recordings-schema.d.ts +44 -6
  74. package/dist/transcription-recordings.d.ts +3 -3
  75. package/dist/turn-initiator.d.ts +2 -2
  76. package/dist/video-generation.d.ts +216 -0
  77. package/dist/video-generation.js +66 -0
  78. package/dist/video-generation.js.map +1 -0
  79. package/dist/workspace-artifacts.d.ts +1 -1
  80. package/dist/workspace-instruction-policies.d.ts +1 -1
  81. package/dist/workspace-learning-policy-schema.d.ts +932 -0
  82. package/dist/workspace-learning-policy.d.ts +161 -0
  83. package/drizzle/0065_enrollment_credential_generation.sql +10 -0
  84. package/drizzle/0140_retained_screenshot_artifacts.sql +192 -0
  85. package/drizzle/0176_lossless_canonical_json.sql +975 -0
  86. package/drizzle/0177_session_events_workspace_turn_type_index.sql +5 -0
  87. package/drizzle/0178_permissioned_secret_reads.sql +14 -0
  88. package/drizzle/0179_slack_private_shortcut_delivery_gate.sql +85 -0
  89. package/drizzle/0180_retained_screenshot_lifecycle_fences.sql +273 -0
  90. package/drizzle/0181_connected_machine_removal.sql +52 -0
  91. package/drizzle/0182_connected_machine_remove_session_default.sql +77 -0
  92. package/drizzle/0183_model_call_provider_cost_estimates.sql +39 -0
  93. package/drizzle/0184_sandbox_drain_teardown_fence.sql +682 -0
  94. package/drizzle/0185_temporal_schedule_cleanup_outbox.sql +168 -0
  95. package/drizzle/0186_sandbox_capture_provider_contract.sql +400 -0
  96. package/drizzle/0187_generated_image_artifacts.sql +173 -0
  97. package/drizzle/0188_image_generation_retention_failure.sql +25 -0
  98. package/drizzle/0189_retained_session_image_formats.sql +13 -0
  99. package/drizzle/0190_timeline_annotations.sql +31 -0
  100. package/drizzle/0191_editable_artifact_engine.sql +3853 -0
  101. package/drizzle/0192_editable_artifact_live_tickets.sql +338 -0
  102. package/drizzle/0193_editable_artifact_authorization.sql +190 -0
  103. package/drizzle/0194_editable_artifact_durable_exports.sql +160 -0
  104. package/drizzle/0195_editable_artifact_import_authorization.sql +203 -0
  105. package/drizzle/0196_rig_provider_images.sql +152 -0
  106. package/drizzle/0197_knowledge_source_sync_schedules.sql +523 -0
  107. package/drizzle/0198_memory_slack_publication_delivery.sql +393 -0
  108. package/drizzle/0199_workspace_learning_policy.sql +980 -0
  109. package/drizzle/0201_company_profile_authority.sql +849 -0
  110. package/drizzle/0202_document_index_checkpoints.sql +85 -0
  111. package/drizzle/0203_durable_video_generation.sql +353 -0
  112. package/drizzle/0204_video_generation_funding.sql +44 -0
  113. package/drizzle/0205_attempt_tool_catalogs.sql +230 -0
  114. package/drizzle/0206_browser_sessions.sql +646 -0
  115. package/drizzle/0207_browser_identities.sql +379 -0
  116. package/drizzle/0208_attached_browser_devices.sql +165 -0
  117. package/drizzle/0209_computer_sessions.sql +575 -0
  118. package/drizzle/0210_browser_auth_network_interventions.sql +441 -0
  119. package/drizzle/0211_editable_artifact_session_links.sql +58 -0
  120. package/drizzle/0212_slack_installation_bindings.sql +348 -0
  121. package/drizzle/0213_slack_user_link_access_requests.sql +177 -0
  122. package/drizzle/0214_session_activity_commit_gate.sql +262 -0
  123. package/drizzle/0215_capabilities_platform.sql +980 -0
  124. package/drizzle/0216_pack_component_ownership.sql +235 -0
  125. package/drizzle/0217_capability_definition_delete_authority.sql +32 -0
  126. package/package.json +18 -5
  127. package/src/attached-browser-devices.ts +371 -0
  128. package/src/attempt-tool-catalogs.ts +131 -0
  129. package/src/browser-auth.ts +1896 -0
  130. package/src/browser-identities.ts +1168 -0
  131. package/src/browser-sessions.ts +2005 -0
  132. package/src/browser-state-artifacts.ts +59 -0
  133. package/src/capability-components.ts +166 -0
  134. package/src/capability-integrations.ts +1663 -0
  135. package/src/codemode-operations.ts +674 -0
  136. package/src/company-profile-schema.ts +143 -0
  137. package/src/company-profile.ts +968 -0
  138. package/src/computer-sessions.ts +1130 -0
  139. package/src/connection-token-resolver.ts +270 -25
  140. package/src/database.ts +434 -24
  141. package/src/editable-artifact-durable-export.ts +1201 -0
  142. package/src/editable-artifact-materialization.ts +893 -0
  143. package/src/editable-artifacts-schema.ts +879 -0
  144. package/src/editable-artifacts.ts +5404 -0
  145. package/src/environment-crypto.ts +22 -9
  146. package/src/generated-images.ts +740 -0
  147. package/src/index.ts +10117 -2730
  148. package/src/insights.ts +160 -13
  149. package/src/integration-bindings.ts +455 -0
  150. package/src/integration-features.ts +859 -0
  151. package/src/interaction-revisions.ts +40 -0
  152. package/src/interaction-schema.ts +1303 -0
  153. package/src/knowledge-source-sync-schema.ts +192 -0
  154. package/src/knowledge-source-sync.ts +1922 -0
  155. package/src/lossless-columns.ts +35 -0
  156. package/src/lossless-json.ts +322 -0
  157. package/src/memory-domain.ts +5 -44
  158. package/src/memory-slack-delivery.ts +801 -0
  159. package/src/pack-components.ts +954 -0
  160. package/src/pack-installations.ts +929 -0
  161. package/src/persistence-errors.ts +26 -34
  162. package/src/plugin-packages.ts +1186 -0
  163. package/src/provision-roles.ts +302 -1
  164. package/src/runtime-posture-cli.ts +9 -0
  165. package/src/runtime-posture.ts +514 -5
  166. package/src/schema.ts +5177 -2957
  167. package/src/scoped-knowledge-schema.ts +1 -1
  168. package/src/scoped-knowledge.ts +655 -3
  169. package/src/session-control.ts +133 -81
  170. package/src/session-queue-commands.ts +511 -247
  171. package/src/session-realtime-context.ts +20 -7
  172. package/src/session-realtime-ledger.ts +32 -10
  173. package/src/session-realtime-mirror.ts +4 -2
  174. package/src/session-realtime-terminal.ts +89 -21
  175. package/src/session-realtime.ts +10 -9
  176. package/src/session-tool-call-settlement.ts +38 -15
  177. package/src/slack-user-link-access.ts +702 -0
  178. package/src/transcription-recordings-schema.ts +5 -2
  179. package/src/transcription-recordings.ts +70 -40
  180. package/src/video-generation.ts +1452 -0
  181. package/src/workspace-learning-policy-schema.ts +139 -0
  182. package/src/workspace-learning-policy.ts +595 -0
  183. package/dist/chunk-DBS5HPEW.js.map +0 -1
  184. package/dist/chunk-HT5T62CC.js +0 -6803
  185. package/dist/chunk-HT5T62CC.js.map +0 -1
  186. package/dist/event-payload-sanitizer.d.ts +0 -32
  187. package/src/event-payload-sanitizer.ts +0 -377
@@ -0,0 +1,161 @@
1
+ import { WorkspaceLearningPolicySnapshot, type WorkspaceLearningPolicyActivationEvent, type WorkspaceLearningPolicyActivationType, type WorkspaceLearningPolicyHead, type WorkspaceLearningPolicyRevision, type WorkspaceLearningSourceOverrideInput } from "@opengeni/contracts";
2
+ import type { Database } from "./database.js";
3
+ export declare class WorkspaceLearningPolicyConflictError extends Error {
4
+ readonly currentHead: WorkspaceLearningPolicyHead | null;
5
+ readonly name = "WorkspaceLearningPolicyConflictError";
6
+ readonly code = "WORKSPACE_LEARNING_POLICY_CONFLICT";
7
+ constructor(currentHead: WorkspaceLearningPolicyHead | null);
8
+ }
9
+ export declare class WorkspaceLearningPolicyOperationReuseError extends Error {
10
+ readonly name = "WorkspaceLearningPolicyOperationReuseError";
11
+ readonly code = "WORKSPACE_LEARNING_POLICY_OPERATION_REUSED";
12
+ constructor();
13
+ }
14
+ export declare class WorkspaceLearningPolicyNotFoundError extends Error {
15
+ readonly name = "WorkspaceLearningPolicyNotFoundError";
16
+ constructor(message?: string);
17
+ }
18
+ export declare class WorkspaceLearningPolicyInvalidOperationError extends Error {
19
+ readonly name = "WorkspaceLearningPolicyInvalidOperationError";
20
+ }
21
+ export declare class WorkspaceLearningPolicyAuthorityError extends Error {
22
+ readonly name = "WorkspaceLearningPolicyAuthorityError";
23
+ }
24
+ export type WorkspaceLearningPolicyAttemptClaims = {
25
+ accountId: string;
26
+ workspaceId: string;
27
+ sessionId: string;
28
+ turnId: string;
29
+ attemptId: string;
30
+ executionGeneration: number;
31
+ };
32
+ export declare function createWorkspaceLearningPolicyRevision(db: Database, input: {
33
+ operationId?: string;
34
+ accountId: string;
35
+ workspaceId: string;
36
+ workspaceMode: "off" | "suggest" | "automatic";
37
+ sourceOverrides?: WorkspaceLearningSourceOverrideInput[];
38
+ supersedesRevisionId?: string | null;
39
+ actorSubjectId: string;
40
+ principalKind: string | undefined;
41
+ }): Promise<WorkspaceLearningPolicyRevision>;
42
+ declare function changeActiveWorkspaceLearningPolicy(db: Database, input: {
43
+ operationId?: string;
44
+ accountId: string;
45
+ workspaceId: string;
46
+ targetRevisionId: string;
47
+ expectedCurrentRevisionId: string | null;
48
+ expectedActivationVersion: number;
49
+ actorSubjectId: string;
50
+ principalKind: string | undefined;
51
+ reason: string;
52
+ type: WorkspaceLearningPolicyActivationType;
53
+ }): Promise<{
54
+ head: {
55
+ accountId: string;
56
+ workspaceId: string;
57
+ revisionId: string;
58
+ revision: number;
59
+ policyHash: string;
60
+ activationVersion: number;
61
+ activatedAt: string;
62
+ };
63
+ event: {
64
+ id: string;
65
+ operationId: string;
66
+ accountId: string;
67
+ workspaceId: string;
68
+ type: "activate" | "rollback";
69
+ activationVersion: number;
70
+ oldRevision: {
71
+ id: string;
72
+ revision: number;
73
+ policyHash: string;
74
+ } | null;
75
+ newRevision: {
76
+ id: string;
77
+ revision: number;
78
+ policyHash: string;
79
+ };
80
+ actorSubjectId: string;
81
+ reason: string;
82
+ createdAt: string;
83
+ };
84
+ }>;
85
+ export declare function activateWorkspaceLearningPolicyRevision(db: Database, input: Omit<Parameters<typeof changeActiveWorkspaceLearningPolicy>[1], "type" | "targetRevisionId"> & {
86
+ revisionId: string;
87
+ }): Promise<{
88
+ head: {
89
+ accountId: string;
90
+ workspaceId: string;
91
+ revisionId: string;
92
+ revision: number;
93
+ policyHash: string;
94
+ activationVersion: number;
95
+ activatedAt: string;
96
+ };
97
+ event: {
98
+ id: string;
99
+ operationId: string;
100
+ accountId: string;
101
+ workspaceId: string;
102
+ type: "activate" | "rollback";
103
+ activationVersion: number;
104
+ oldRevision: {
105
+ id: string;
106
+ revision: number;
107
+ policyHash: string;
108
+ } | null;
109
+ newRevision: {
110
+ id: string;
111
+ revision: number;
112
+ policyHash: string;
113
+ };
114
+ actorSubjectId: string;
115
+ reason: string;
116
+ createdAt: string;
117
+ };
118
+ }>;
119
+ export declare function rollbackWorkspaceLearningPolicyRevision(db: Database, input: Omit<Parameters<typeof changeActiveWorkspaceLearningPolicy>[1], "type">): Promise<{
120
+ head: {
121
+ accountId: string;
122
+ workspaceId: string;
123
+ revisionId: string;
124
+ revision: number;
125
+ policyHash: string;
126
+ activationVersion: number;
127
+ activatedAt: string;
128
+ };
129
+ event: {
130
+ id: string;
131
+ operationId: string;
132
+ accountId: string;
133
+ workspaceId: string;
134
+ type: "activate" | "rollback";
135
+ activationVersion: number;
136
+ oldRevision: {
137
+ id: string;
138
+ revision: number;
139
+ policyHash: string;
140
+ } | null;
141
+ newRevision: {
142
+ id: string;
143
+ revision: number;
144
+ policyHash: string;
145
+ };
146
+ actorSubjectId: string;
147
+ reason: string;
148
+ createdAt: string;
149
+ };
150
+ }>;
151
+ export declare function listWorkspaceLearningPolicyHistory(db: Database, input: {
152
+ accountId: string;
153
+ workspaceId: string;
154
+ limit?: number;
155
+ }): Promise<{
156
+ head: WorkspaceLearningPolicyHead | null;
157
+ revisions: WorkspaceLearningPolicyRevision[];
158
+ events: WorkspaceLearningPolicyActivationEvent[];
159
+ }>;
160
+ export declare function getOrCreateWorkspaceLearningPolicySnapshot(db: Database, claims: WorkspaceLearningPolicyAttemptClaims): Promise<WorkspaceLearningPolicySnapshot>;
161
+ export {};
@@ -0,0 +1,10 @@
1
+ -- deployment-mode: rolling
2
+ -- Enrollment credential-generation fence.
3
+ --
4
+ -- Schema-first/backward-compatible rollout: every pre-existing enrollment is
5
+ -- generation 1, matching legacy signed bearers that did not carry an explicit
6
+ -- generation claim. New binaries atomically increment this column whenever the
7
+ -- same machine identity is enrolled again and require the signed claim to match.
8
+
9
+ ALTER TABLE "enrollments"
10
+ ADD COLUMN IF NOT EXISTS "credential_generation" integer NOT NULL DEFAULT 1;
@@ -0,0 +1,192 @@
1
+ -- deployment-mode: rolling
2
+ -- Retain computer screenshots as deterministic, tenant-owned files while
3
+ -- keeping provider object locations server-private. Pending/ready bytes are
4
+ -- quota-accounted, and one bounded SECURITY DEFINER claim seam drives stale
5
+ -- settlement reconciliation plus expiry/orphan cleanup across FORCE-RLS rows.
6
+
7
+ CREATE UNIQUE INDEX IF NOT EXISTS "files_workspace_id_uq"
8
+ ON "files" ("workspace_id", "id");
9
+
10
+ CREATE TABLE "workspace_screenshot_quotas" (
11
+ "workspace_id" uuid PRIMARY KEY,
12
+ "account_id" uuid NOT NULL,
13
+ "reserved_bytes" bigint NOT NULL DEFAULT 0,
14
+ "ready_bytes" bigint NOT NULL DEFAULT 0,
15
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
16
+ CONSTRAINT "workspace_screenshot_quotas_workspace_account_fk"
17
+ FOREIGN KEY ("workspace_id", "account_id")
18
+ REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
19
+ CONSTRAINT "workspace_screenshot_quotas_nonnegative_chk"
20
+ CHECK ("reserved_bytes" >= 0 AND "ready_bytes" >= 0)
21
+ );
22
+
23
+ CREATE TABLE "retained_screenshot_artifacts" (
24
+ "artifact_id" uuid PRIMARY KEY,
25
+ "account_id" uuid NOT NULL,
26
+ "workspace_id" uuid NOT NULL,
27
+ "session_id" uuid NOT NULL,
28
+ "turn_id" uuid NOT NULL,
29
+ "attempt_id" uuid NOT NULL,
30
+ "settlement_key" text NOT NULL,
31
+ "tool_call_id" text NOT NULL,
32
+ "tool_output_id" text NOT NULL,
33
+ "status" text NOT NULL DEFAULT 'pending',
34
+ "media_type" text NOT NULL,
35
+ "size_bytes" bigint NOT NULL,
36
+ "sha256" text NOT NULL,
37
+ "width" integer NOT NULL,
38
+ "height" integer NOT NULL,
39
+ "retention_expires_at" timestamptz NOT NULL,
40
+ "ready_at" timestamptz,
41
+ "cleanup_reason" text,
42
+ "last_error" text,
43
+ "created_at" timestamptz NOT NULL DEFAULT now(),
44
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
45
+ CONSTRAINT "retained_screenshot_artifacts_workspace_account_fk"
46
+ FOREIGN KEY ("workspace_id", "account_id")
47
+ REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
48
+ CONSTRAINT "retained_screenshot_artifacts_workspace_session_fk"
49
+ FOREIGN KEY ("workspace_id", "session_id")
50
+ REFERENCES "sessions"("workspace_id", "id") ON DELETE CASCADE,
51
+ CONSTRAINT "retained_screenshot_artifacts_workspace_turn_fk"
52
+ FOREIGN KEY ("workspace_id", "turn_id")
53
+ REFERENCES "session_turns"("workspace_id", "id") ON DELETE CASCADE,
54
+ CONSTRAINT "retained_screenshot_artifacts_workspace_attempt_fk"
55
+ FOREIGN KEY ("workspace_id", "attempt_id")
56
+ REFERENCES "session_turn_attempts"("workspace_id", "id") ON DELETE RESTRICT,
57
+ CONSTRAINT "retained_screenshot_artifacts_workspace_file_fk"
58
+ FOREIGN KEY ("workspace_id", "artifact_id")
59
+ REFERENCES "files"("workspace_id", "id") ON DELETE CASCADE,
60
+ CONSTRAINT "retained_screenshot_artifacts_settlement_key_uq"
61
+ UNIQUE ("settlement_key"),
62
+ CONSTRAINT "retained_screenshot_artifacts_status_chk"
63
+ CHECK ("status" IN ('pending', 'reconciling', 'ready', 'cleanup_pending', 'failed', 'expired', 'deleted')),
64
+ CONSTRAINT "retained_screenshot_artifacts_media_type_chk"
65
+ CHECK ("media_type" = 'image/png'),
66
+ CONSTRAINT "retained_screenshot_artifacts_size_chk"
67
+ CHECK ("size_bytes" > 0 AND "size_bytes" <= 33554432),
68
+ CONSTRAINT "retained_screenshot_artifacts_sha256_chk"
69
+ CHECK ("sha256" ~ '^[0-9a-f]{64}$'),
70
+ CONSTRAINT "retained_screenshot_artifacts_dimensions_chk"
71
+ CHECK (
72
+ "width" BETWEEN 1 AND 16384
73
+ AND "height" BETWEEN 1 AND 16384
74
+ AND ("width"::bigint * "height"::bigint) <= 67108864
75
+ ),
76
+ CONSTRAINT "retained_screenshot_artifacts_ready_shape_chk"
77
+ CHECK (
78
+ ("status" = 'ready' AND "ready_at" IS NOT NULL)
79
+ OR ("status" IN ('pending', 'reconciling') AND "ready_at" IS NULL)
80
+ OR "status" IN ('cleanup_pending', 'failed', 'expired', 'deleted')
81
+ ),
82
+ CONSTRAINT "retained_screenshot_artifacts_terminal_cleanup_chk"
83
+ CHECK (
84
+ ("status" IN ('cleanup_pending', 'failed', 'expired', 'deleted'))
85
+ OR "cleanup_reason" IS NULL
86
+ )
87
+ );
88
+
89
+ CREATE INDEX "retained_screenshot_artifacts_session_created_idx"
90
+ ON "retained_screenshot_artifacts" ("workspace_id", "session_id", "created_at", "artifact_id");
91
+ CREATE INDEX "retained_screenshot_artifacts_ready_expiry_idx"
92
+ ON "retained_screenshot_artifacts" ("retention_expires_at", "artifact_id")
93
+ WHERE "status" = 'ready';
94
+ CREATE INDEX "retained_screenshot_artifacts_pending_reconcile_idx"
95
+ ON "retained_screenshot_artifacts" ("updated_at", "artifact_id")
96
+ WHERE "status" IN ('pending', 'reconciling', 'cleanup_pending');
97
+
98
+ ALTER TABLE "workspace_screenshot_quotas" ENABLE ROW LEVEL SECURITY;
99
+ ALTER TABLE "workspace_screenshot_quotas" FORCE ROW LEVEL SECURITY;
100
+ CREATE POLICY "workspace_isolation" ON "workspace_screenshot_quotas"
101
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
102
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
103
+
104
+ ALTER TABLE "retained_screenshot_artifacts" ENABLE ROW LEVEL SECURITY;
105
+ ALTER TABLE "retained_screenshot_artifacts" FORCE ROW LEVEL SECURITY;
106
+ CREATE POLICY "workspace_isolation" ON "retained_screenshot_artifacts"
107
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
108
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
109
+
110
+ CREATE OR REPLACE FUNCTION opengeni_private.claim_retained_screenshot_maintenance(
111
+ p_pending_grace_ms bigint,
112
+ p_claim_timeout_ms bigint,
113
+ p_limit integer
114
+ )
115
+ RETURNS TABLE (
116
+ action text,
117
+ artifact_id uuid,
118
+ account_id uuid,
119
+ workspace_id uuid,
120
+ session_id uuid,
121
+ object_key text,
122
+ media_type text,
123
+ size_bytes bigint,
124
+ sha256 text,
125
+ width integer,
126
+ height integer,
127
+ retention_expires_at timestamptz,
128
+ cleanup_reason text
129
+ )
130
+ LANGUAGE sql
131
+ SECURITY DEFINER
132
+ AS $$
133
+ WITH candidates AS (
134
+ SELECT A.artifact_id,
135
+ CASE
136
+ WHEN A.status IN ('pending', 'reconciling') THEN 'reconcile'
137
+ ELSE 'delete'
138
+ END AS action,
139
+ CASE
140
+ WHEN A.status = 'ready' THEN 'expired'
141
+ WHEN A.status IN ('pending', 'reconciling') THEN A.cleanup_reason
142
+ ELSE coalesce(A.cleanup_reason, 'orphaned')
143
+ END AS cleanup_reason
144
+ FROM retained_screenshot_artifacts A
145
+ WHERE
146
+ (A.status = 'ready' AND A.retention_expires_at <= clock_timestamp())
147
+ OR (
148
+ A.status = 'pending'
149
+ AND A.updated_at <= clock_timestamp() - (
150
+ greatest(p_pending_grace_ms, 0)::double precision * interval '1 millisecond'
151
+ )
152
+ )
153
+ OR (
154
+ A.status IN ('reconciling', 'cleanup_pending')
155
+ AND A.updated_at <= clock_timestamp() - (
156
+ greatest(p_claim_timeout_ms, 0)::double precision * interval '1 millisecond'
157
+ )
158
+ )
159
+ ORDER BY A.retention_expires_at, A.artifact_id
160
+ LIMIT least(greatest(p_limit, 0), 1000)
161
+ FOR UPDATE SKIP LOCKED
162
+ ), claimed AS (
163
+ UPDATE retained_screenshot_artifacts A
164
+ SET
165
+ status = CASE WHEN C.action = 'reconcile' THEN 'reconciling' ELSE 'cleanup_pending' END,
166
+ cleanup_reason = C.cleanup_reason,
167
+ updated_at = clock_timestamp()
168
+ FROM candidates C
169
+ WHERE A.artifact_id = C.artifact_id
170
+ RETURNING A.*, C.action
171
+ )
172
+ SELECT C.action, C.artifact_id, C.account_id, C.workspace_id, C.session_id,
173
+ F.object_key, C.media_type, C.size_bytes, C.sha256, C.width, C.height,
174
+ C.retention_expires_at, C.cleanup_reason
175
+ FROM claimed C
176
+ JOIN files F
177
+ ON F.workspace_id = C.workspace_id
178
+ AND F.id = C.artifact_id;
179
+ $$;
180
+
181
+ REVOKE ALL ON FUNCTION opengeni_private.claim_retained_screenshot_maintenance(bigint, bigint, integer)
182
+ FROM PUBLIC;
183
+
184
+ DO $$
185
+ BEGIN
186
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
187
+ GRANT SELECT, INSERT, UPDATE, DELETE ON "workspace_screenshot_quotas" TO opengeni_app;
188
+ GRANT SELECT, INSERT, UPDATE, DELETE ON "retained_screenshot_artifacts" TO opengeni_app;
189
+ GRANT EXECUTE ON FUNCTION opengeni_private.claim_retained_screenshot_maintenance(bigint, bigint, integer)
190
+ TO opengeni_app;
191
+ END IF;
192
+ END $$;