@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,980 @@
1
+ -- deployment-mode: rolling
2
+ -- Expand-only normalized Capabilities Platform state. The v1 catalog,
3
+ -- capability installations, workspace packs, and pack installations remain
4
+ -- authoritative during shadow-read/backfill and are not dropped or renamed.
5
+
6
+ SET LOCAL lock_timeout = '5s';
7
+ SET LOCAL statement_timeout = '10min';
8
+
9
+ CREATE TABLE "capability_plugins" (
10
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
11
+ "plugin_key" text NOT NULL,
12
+ "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
13
+ "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE,
14
+ "name" text NOT NULL,
15
+ "description" text,
16
+ "category" text NOT NULL,
17
+ "tags" jsonb NOT NULL DEFAULT '[]'::jsonb,
18
+ "provenance" text NOT NULL,
19
+ "created_at" timestamptz NOT NULL DEFAULT now(),
20
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
21
+ CONSTRAINT "capability_plugins_scope_chk" CHECK (
22
+ ("account_id" IS NULL AND "workspace_id" IS NULL)
23
+ OR ("account_id" IS NOT NULL AND "workspace_id" IS NOT NULL)
24
+ ),
25
+ CONSTRAINT "capability_plugins_key_chk" CHECK (
26
+ length("plugin_key") BETWEEN 1 AND 200
27
+ AND "plugin_key" = lower(btrim("plugin_key"))
28
+ AND "plugin_key" ~ '^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$'
29
+ ),
30
+ CONSTRAINT "capability_plugins_text_chk" CHECK (
31
+ length(btrim("name")) BETWEEN 1 AND 200
32
+ AND length("category") BETWEEN 1 AND 96
33
+ AND ("description" IS NULL OR length("description") <= 4000)
34
+ ),
35
+ CONSTRAINT "capability_plugins_tags_chk" CHECK (
36
+ jsonb_typeof("tags") = 'array'
37
+ AND jsonb_array_length("tags") <= 64
38
+ AND octet_length(convert_to("tags"::text, 'UTF8')) <= 8192
39
+ ),
40
+ CONSTRAINT "capability_plugins_provenance_chk" CHECK (
41
+ "provenance" IN ('platform', 'deployment', 'registry', 'workspace')
42
+ )
43
+ );
44
+
45
+ CREATE UNIQUE INDEX "capability_plugins_global_key_idx"
46
+ ON "capability_plugins" ("plugin_key") WHERE "workspace_id" IS NULL;
47
+ CREATE UNIQUE INDEX "capability_plugins_workspace_key_idx"
48
+ ON "capability_plugins" ("workspace_id", "plugin_key");
49
+ CREATE INDEX "capability_plugins_scope_idx"
50
+ ON "capability_plugins" ("workspace_id", "category");
51
+
52
+ CREATE TABLE "capability_plugin_versions" (
53
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
54
+ "plugin_id" uuid NOT NULL REFERENCES "capability_plugins"("id") ON DELETE CASCADE,
55
+ "version" text NOT NULL,
56
+ "manifest_digest" text NOT NULL,
57
+ "manifest" jsonb NOT NULL DEFAULT '{}'::jsonb,
58
+ "status" text NOT NULL DEFAULT 'published',
59
+ "import_batch_id" uuid REFERENCES "import_batches"("id") ON DELETE SET NULL,
60
+ "created_at" timestamptz NOT NULL DEFAULT now(),
61
+ CONSTRAINT "capability_plugin_versions_version_chk" CHECK (
62
+ length("version") BETWEEN 1 AND 96
63
+ AND "version" !~ '[[:cntrl:]]'
64
+ ),
65
+ CONSTRAINT "capability_plugin_versions_digest_chk" CHECK (
66
+ "manifest_digest" ~ '^[0-9a-f]{64}$'
67
+ ),
68
+ CONSTRAINT "capability_plugin_versions_manifest_chk" CHECK (
69
+ jsonb_typeof("manifest") = 'object'
70
+ AND octet_length(convert_to("manifest"::text, 'UTF8')) <= 1048576
71
+ ),
72
+ CONSTRAINT "capability_plugin_versions_status_chk" CHECK (
73
+ "status" IN ('published', 'stale', 'withdrawn')
74
+ ),
75
+ CONSTRAINT "capability_plugin_versions_plugin_version_uq" UNIQUE ("plugin_id", "version"),
76
+ CONSTRAINT "capability_plugin_versions_plugin_digest_uq" UNIQUE ("plugin_id", "manifest_digest"),
77
+ CONSTRAINT "capability_plugin_versions_plugin_identity_uq" UNIQUE ("plugin_id", "id")
78
+ );
79
+
80
+ CREATE TABLE "capability_facets" (
81
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
82
+ "plugin_version_id" uuid NOT NULL
83
+ REFERENCES "capability_plugin_versions"("id") ON DELETE CASCADE,
84
+ "facet_key" text NOT NULL,
85
+ "kind" text NOT NULL,
86
+ "activation_mode" text NOT NULL,
87
+ "required" boolean NOT NULL DEFAULT true,
88
+ "created_at" timestamptz NOT NULL DEFAULT now(),
89
+ CONSTRAINT "capability_facets_key_chk" CHECK (
90
+ length("facet_key") BETWEEN 1 AND 200
91
+ AND "facet_key" = lower(btrim("facet_key"))
92
+ AND "facet_key" ~ '^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$'
93
+ ),
94
+ CONSTRAINT "capability_facets_kind_chk" CHECK (
95
+ "kind" IN ('integration', 'mcp', 'api', 'skill')
96
+ ),
97
+ CONSTRAINT "capability_facets_activation_chk" CHECK (
98
+ "activation_mode" IN ('platform_available', 'runtime_baseline', 'workspace_managed')
99
+ ),
100
+ CONSTRAINT "capability_facets_version_key_uq" UNIQUE ("plugin_version_id", "facet_key")
101
+ );
102
+
103
+ CREATE INDEX "capability_facets_version_kind_idx"
104
+ ON "capability_facets" ("plugin_version_id", "kind");
105
+
106
+ CREATE TABLE "capability_integration_facets" (
107
+ "facet_id" uuid PRIMARY KEY REFERENCES "capability_facets"("id") ON DELETE CASCADE,
108
+ "provider_domain" text NOT NULL,
109
+ "connection_kinds" jsonb NOT NULL DEFAULT '[]'::jsonb,
110
+ "ownership" text NOT NULL,
111
+ "required_scopes" jsonb NOT NULL DEFAULT '[]'::jsonb,
112
+ "resource_selection" text NOT NULL DEFAULT 'none',
113
+ CONSTRAINT "capability_integration_facets_domain_chk" CHECK (
114
+ length("provider_domain") BETWEEN 1 AND 253
115
+ AND "provider_domain" = lower(btrim("provider_domain"))
116
+ AND "provider_domain" !~ '[/@[:space:]]'
117
+ ),
118
+ CONSTRAINT "capability_integration_facets_connections_chk" CHECK (
119
+ jsonb_typeof("connection_kinds") = 'array'
120
+ AND jsonb_array_length("connection_kinds") <= 16
121
+ AND octet_length(convert_to("connection_kinds"::text, 'UTF8')) <= 4096
122
+ ),
123
+ CONSTRAINT "capability_integration_facets_ownership_chk" CHECK (
124
+ "ownership" IN ('workspace', 'subject', 'either')
125
+ ),
126
+ CONSTRAINT "capability_integration_facets_scopes_chk" CHECK (
127
+ jsonb_typeof("required_scopes") = 'array'
128
+ AND jsonb_array_length("required_scopes") <= 256
129
+ AND octet_length(convert_to("required_scopes"::text, 'UTF8')) <= 32768
130
+ ),
131
+ CONSTRAINT "capability_integration_facets_resource_chk" CHECK (
132
+ "resource_selection" IN ('none', 'optional', 'required')
133
+ )
134
+ );
135
+
136
+ CREATE TABLE "capability_mcp_facets" (
137
+ "facet_id" uuid PRIMARY KEY REFERENCES "capability_facets"("id") ON DELETE CASCADE,
138
+ "server_id" text NOT NULL,
139
+ "endpoint_url" text NOT NULL,
140
+ "transport" text NOT NULL,
141
+ "auth_kind" text NOT NULL,
142
+ "integration_facet_id" uuid REFERENCES "capability_integration_facets"("facet_id")
143
+ ON DELETE RESTRICT,
144
+ "allowed_tools" jsonb NOT NULL DEFAULT '[]'::jsonb,
145
+ CONSTRAINT "capability_mcp_facets_server_chk" CHECK (
146
+ length("server_id") BETWEEN 1 AND 128
147
+ AND "server_id" ~ '^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$'
148
+ ),
149
+ CONSTRAINT "capability_mcp_facets_url_chk" CHECK (
150
+ length("endpoint_url") BETWEEN 1 AND 2048
151
+ AND "endpoint_url" ~ '^https://'
152
+ AND "endpoint_url" !~ '[[:cntrl:][:space:]]'
153
+ ),
154
+ CONSTRAINT "capability_mcp_facets_transport_chk" CHECK (
155
+ "transport" IN ('streamable_http', 'sse')
156
+ ),
157
+ CONSTRAINT "capability_mcp_facets_auth_chk" CHECK (
158
+ "auth_kind" IN ('oauth2', 'api_key', 'none', 'unknown')
159
+ ),
160
+ CONSTRAINT "capability_mcp_facets_tools_chk" CHECK (
161
+ jsonb_typeof("allowed_tools") = 'array'
162
+ AND jsonb_array_length("allowed_tools") <= 1024
163
+ AND octet_length(convert_to("allowed_tools"::text, 'UTF8')) <= 131072
164
+ )
165
+ );
166
+
167
+ CREATE INDEX "capability_mcp_facets_server_idx" ON "capability_mcp_facets" ("server_id");
168
+
169
+ CREATE TABLE "capability_api_facets" (
170
+ "facet_id" uuid PRIMARY KEY REFERENCES "capability_facets"("id") ON DELETE CASCADE,
171
+ "protocol" text NOT NULL,
172
+ "base_url" text NOT NULL,
173
+ "spec_source_url" text,
174
+ "auth_scheme" jsonb NOT NULL DEFAULT '{}'::jsonb,
175
+ "integration_facet_id" uuid REFERENCES "capability_integration_facets"("facet_id")
176
+ ON DELETE RESTRICT,
177
+ CONSTRAINT "capability_api_facets_protocol_chk" CHECK (
178
+ "protocol" IN ('openapi', 'graphql')
179
+ ),
180
+ CONSTRAINT "capability_api_facets_base_url_chk" CHECK (
181
+ length("base_url") BETWEEN 1 AND 2048
182
+ AND "base_url" ~ '^https://'
183
+ AND "base_url" !~ '[[:cntrl:][:space:]]'
184
+ ),
185
+ CONSTRAINT "capability_api_facets_source_url_chk" CHECK (
186
+ "spec_source_url" IS NULL OR (
187
+ length("spec_source_url") BETWEEN 1 AND 2048
188
+ AND "spec_source_url" ~ '^https://'
189
+ AND "spec_source_url" !~ '[[:cntrl:][:space:]]'
190
+ )
191
+ ),
192
+ CONSTRAINT "capability_api_facets_auth_chk" CHECK (
193
+ jsonb_typeof("auth_scheme") = 'object'
194
+ AND octet_length(convert_to("auth_scheme"::text, 'UTF8')) <= 32768
195
+ )
196
+ );
197
+
198
+ CREATE TABLE "capability_skill_facets" (
199
+ "facet_id" uuid PRIMARY KEY REFERENCES "capability_facets"("id") ON DELETE CASCADE,
200
+ "capability_id" text NOT NULL,
201
+ "name" text NOT NULL,
202
+ "description" text NOT NULL,
203
+ "source_url" text NOT NULL,
204
+ "source_commit" text NOT NULL,
205
+ "source_path" text NOT NULL,
206
+ "content_sha256" text NOT NULL,
207
+ "file_count" integer NOT NULL,
208
+ "total_bytes" integer NOT NULL,
209
+ "license" text,
210
+ CONSTRAINT "capability_skill_facets_capability_id_chk" CHECK (
211
+ length("capability_id") BETWEEN 1 AND 512
212
+ AND "capability_id" !~ '[[:cntrl:]]'
213
+ ),
214
+ CONSTRAINT "capability_skill_facets_name_chk" CHECK (
215
+ length("name") BETWEEN 1 AND 64
216
+ AND "name" ~ '^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$'
217
+ ),
218
+ CONSTRAINT "capability_skill_facets_description_chk" CHECK (
219
+ length("description") BETWEEN 1 AND 2048
220
+ AND "description" !~ '[\r\n]'
221
+ ),
222
+ CONSTRAINT "capability_skill_facets_source_chk" CHECK (
223
+ length("source_url") BETWEEN 1 AND 2048
224
+ AND "source_url" ~ '^https://'
225
+ AND "source_url" !~ '[[:cntrl:][:space:]]'
226
+ AND "source_commit" ~ '^[0-9a-f]{40,64}$'
227
+ AND length("source_path") BETWEEN 1 AND 1024
228
+ AND "source_path" !~ '(^/|/$|//|\\|(^|/)\.\.?(/|$)|[[:cntrl:]])'
229
+ ),
230
+ CONSTRAINT "capability_skill_facets_content_chk" CHECK (
231
+ "content_sha256" ~ '^[0-9a-f]{64}$'
232
+ AND "file_count" BETWEEN 1 AND 128
233
+ AND "total_bytes" BETWEEN 1 AND 1048576
234
+ ),
235
+ CONSTRAINT "capability_skill_facets_license_chk" CHECK (
236
+ "license" IS NULL OR length("license") BETWEEN 1 AND 128
237
+ )
238
+ );
239
+
240
+ CREATE INDEX "capability_skill_facets_content_idx"
241
+ ON "capability_skill_facets" ("content_sha256");
242
+
243
+ CREATE TABLE "capability_skill_files" (
244
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
245
+ "skill_facet_id" uuid NOT NULL REFERENCES "capability_skill_facets"("facet_id")
246
+ ON DELETE CASCADE,
247
+ "path" text NOT NULL,
248
+ "content" text NOT NULL,
249
+ "byte_size" integer NOT NULL,
250
+ "content_sha256" text NOT NULL,
251
+ CONSTRAINT "capability_skill_files_path_chk" CHECK (
252
+ length("path") BETWEEN 1 AND 1024
253
+ AND "path" !~ '(^/|/$|//|\\|(^|/)\.\.?(/|$)|[[:cntrl:]])'
254
+ ),
255
+ CONSTRAINT "capability_skill_files_content_chk" CHECK (
256
+ "byte_size" BETWEEN 0 AND 262144
257
+ AND "byte_size" = octet_length(convert_to("content", 'UTF8'))
258
+ AND "content_sha256" ~ '^[0-9a-f]{64}$'
259
+ AND "content_sha256" = encode(sha256(convert_to("content", 'UTF8')), 'hex')
260
+ ),
261
+ CONSTRAINT "capability_skill_files_skill_path_uq" UNIQUE ("skill_facet_id", "path")
262
+ );
263
+
264
+ CREATE TABLE "capability_plugin_installations" (
265
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
266
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
267
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
268
+ "plugin_id" uuid NOT NULL REFERENCES "capability_plugins"("id") ON DELETE RESTRICT,
269
+ "plugin_version_id" uuid NOT NULL,
270
+ "status" text NOT NULL DEFAULT 'active',
271
+ "version" integer NOT NULL DEFAULT 1,
272
+ "installed_by_subject_id" text NOT NULL,
273
+ "installed_at" timestamptz NOT NULL DEFAULT now(),
274
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
275
+ CONSTRAINT "capability_plugin_installations_plugin_version_fk"
276
+ FOREIGN KEY ("plugin_id", "plugin_version_id")
277
+ REFERENCES "capability_plugin_versions"("plugin_id", "id") ON DELETE RESTRICT,
278
+ CONSTRAINT "capability_plugin_installations_status_chk" CHECK (
279
+ "status" IN ('active', 'disabled', 'needs_attention')
280
+ ),
281
+ CONSTRAINT "capability_plugin_installations_version_chk" CHECK ("version" > 0),
282
+ CONSTRAINT "capability_plugin_installations_actor_chk" CHECK (
283
+ length(btrim("installed_by_subject_id")) BETWEEN 1 AND 1024
284
+ ),
285
+ CONSTRAINT "capability_plugin_installations_workspace_plugin_uq"
286
+ UNIQUE ("workspace_id", "plugin_id")
287
+ );
288
+
289
+ CREATE INDEX "capability_plugin_installations_workspace_status_idx"
290
+ ON "capability_plugin_installations" ("workspace_id", "status");
291
+
292
+ CREATE TABLE "capability_facet_installations" (
293
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
294
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
295
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
296
+ "plugin_installation_id" uuid NOT NULL
297
+ REFERENCES "capability_plugin_installations"("id") ON DELETE CASCADE,
298
+ "facet_id" uuid NOT NULL REFERENCES "capability_facets"("id") ON DELETE RESTRICT,
299
+ "connection_id" uuid REFERENCES "connections"("id") ON DELETE RESTRICT,
300
+ "status" text NOT NULL DEFAULT 'active',
301
+ "config" jsonb NOT NULL DEFAULT '{}'::jsonb,
302
+ "version" integer NOT NULL DEFAULT 1,
303
+ "attention_code" text,
304
+ "created_at" timestamptz NOT NULL DEFAULT now(),
305
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
306
+ CONSTRAINT "capability_facet_installations_status_chk" CHECK (
307
+ "status" IN ('active', 'disabled', 'needs_attention')
308
+ ),
309
+ CONSTRAINT "capability_facet_installations_config_chk" CHECK (
310
+ jsonb_typeof("config") = 'object'
311
+ AND octet_length(convert_to("config"::text, 'UTF8')) <= 131072
312
+ ),
313
+ CONSTRAINT "capability_facet_installations_version_chk" CHECK ("version" > 0),
314
+ CONSTRAINT "capability_facet_installations_attention_chk" CHECK (
315
+ ("status" = 'needs_attention') = ("attention_code" IS NOT NULL)
316
+ AND ("attention_code" IS NULL OR length("attention_code") BETWEEN 1 AND 120)
317
+ ),
318
+ CONSTRAINT "capability_facet_installations_installation_facet_uq"
319
+ UNIQUE ("plugin_installation_id", "facet_id")
320
+ );
321
+
322
+ CREATE INDEX "capability_facet_installations_workspace_status_idx"
323
+ ON "capability_facet_installations" ("workspace_id", "status");
324
+
325
+ CREATE TABLE "capability_component_owners" (
326
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
327
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
328
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
329
+ "facet_installation_id" uuid NOT NULL
330
+ REFERENCES "capability_facet_installations"("id") ON DELETE CASCADE,
331
+ "owner_kind" text NOT NULL,
332
+ "owner_id" text NOT NULL,
333
+ "removable" boolean NOT NULL DEFAULT true,
334
+ "created_at" timestamptz NOT NULL DEFAULT now(),
335
+ CONSTRAINT "capability_component_owners_kind_chk" CHECK (
336
+ "owner_kind" IN ('direct', 'plugin', 'pack', 'migration')
337
+ ),
338
+ CONSTRAINT "capability_component_owners_id_chk" CHECK (
339
+ length("owner_id") BETWEEN 1 AND 512 AND "owner_id" !~ '[[:cntrl:]]'
340
+ ),
341
+ CONSTRAINT "capability_component_owners_unique_uq"
342
+ UNIQUE ("facet_installation_id", "owner_kind", "owner_id")
343
+ );
344
+
345
+ CREATE INDEX "capability_component_owners_workspace_owner_idx"
346
+ ON "capability_component_owners" ("workspace_id", "owner_kind", "owner_id");
347
+
348
+ CREATE TABLE "integration_spec_revisions" (
349
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
350
+ "api_facet_id" uuid NOT NULL REFERENCES "capability_api_facets"("facet_id")
351
+ ON DELETE CASCADE,
352
+ "revision" integer NOT NULL,
353
+ "protocol" text NOT NULL,
354
+ "source_url" text,
355
+ "spec_digest" text NOT NULL,
356
+ "spec" jsonb NOT NULL,
357
+ "status" text NOT NULL DEFAULT 'active',
358
+ "fetched_at" timestamptz NOT NULL DEFAULT now(),
359
+ CONSTRAINT "integration_spec_revisions_revision_chk" CHECK ("revision" > 0),
360
+ CONSTRAINT "integration_spec_revisions_protocol_chk" CHECK (
361
+ "protocol" IN ('openapi', 'graphql')
362
+ ),
363
+ CONSTRAINT "integration_spec_revisions_source_chk" CHECK (
364
+ "source_url" IS NULL OR (
365
+ length("source_url") BETWEEN 1 AND 2048
366
+ AND "source_url" ~ '^https://'
367
+ AND "source_url" !~ '[[:cntrl:][:space:]]'
368
+ )
369
+ ),
370
+ CONSTRAINT "integration_spec_revisions_spec_chk" CHECK (
371
+ "spec_digest" ~ '^[0-9a-f]{64}$'
372
+ AND jsonb_typeof("spec") = 'object'
373
+ AND octet_length(convert_to("spec"::text, 'UTF8')) <= 4194304
374
+ ),
375
+ CONSTRAINT "integration_spec_revisions_status_chk" CHECK (
376
+ "status" IN ('active', 'stale', 'invalid')
377
+ ),
378
+ CONSTRAINT "integration_spec_revisions_facet_revision_uq"
379
+ UNIQUE ("api_facet_id", "revision"),
380
+ CONSTRAINT "integration_spec_revisions_facet_digest_uq"
381
+ UNIQUE ("api_facet_id", "spec_digest")
382
+ );
383
+
384
+ CREATE TABLE "integration_tools" (
385
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
386
+ "facet_id" uuid NOT NULL REFERENCES "capability_facets"("id") ON DELETE CASCADE,
387
+ "tool_key" text NOT NULL,
388
+ "name" text NOT NULL,
389
+ "description" text,
390
+ "input_schema" jsonb NOT NULL DEFAULT '{}'::jsonb,
391
+ "output_schema" jsonb,
392
+ "effect" text NOT NULL DEFAULT 'read',
393
+ "active" boolean NOT NULL DEFAULT true,
394
+ "created_at" timestamptz NOT NULL DEFAULT now(),
395
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
396
+ CONSTRAINT "integration_tools_key_chk" CHECK (
397
+ length("tool_key") BETWEEN 1 AND 200
398
+ AND "tool_key" ~ '^[A-Za-z0-9](?:[A-Za-z0-9._/-]*[A-Za-z0-9])?$'
399
+ ),
400
+ CONSTRAINT "integration_tools_text_chk" CHECK (
401
+ length("name") BETWEEN 1 AND 200
402
+ AND ("description" IS NULL OR length("description") <= 4000)
403
+ ),
404
+ CONSTRAINT "integration_tools_schema_chk" CHECK (
405
+ jsonb_typeof("input_schema") = 'object'
406
+ AND ("output_schema" IS NULL OR jsonb_typeof("output_schema") = 'object')
407
+ AND octet_length(convert_to("input_schema"::text, 'UTF8')) <= 262144
408
+ AND ("output_schema" IS NULL OR octet_length(convert_to("output_schema"::text, 'UTF8')) <= 262144)
409
+ ),
410
+ CONSTRAINT "integration_tools_effect_chk" CHECK (
411
+ "effect" IN ('read', 'write', 'destructive')
412
+ ),
413
+ CONSTRAINT "integration_tools_facet_tool_uq" UNIQUE ("facet_id", "tool_key")
414
+ );
415
+
416
+ CREATE TABLE "integration_feature_facets" (
417
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
418
+ "integration_facet_id" uuid NOT NULL
419
+ REFERENCES "capability_integration_facets"("facet_id") ON DELETE CASCADE,
420
+ "feature_key" text NOT NULL,
421
+ "kind" text NOT NULL,
422
+ "config_schema" jsonb NOT NULL DEFAULT '{}'::jsonb,
423
+ "capabilities" jsonb NOT NULL DEFAULT '{}'::jsonb,
424
+ "created_at" timestamptz NOT NULL DEFAULT now(),
425
+ CONSTRAINT "integration_feature_facets_key_chk" CHECK (
426
+ length("feature_key") BETWEEN 1 AND 200
427
+ AND "feature_key" = lower(btrim("feature_key"))
428
+ AND "feature_key" ~ '^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$'
429
+ ),
430
+ CONSTRAINT "integration_feature_facets_kind_chk" CHECK (
431
+ "kind" IN ('tools', 'knowledge_source', 'inbound_trigger', 'delivery_destination', 'identity_link')
432
+ ),
433
+ CONSTRAINT "integration_feature_facets_schema_chk" CHECK (
434
+ jsonb_typeof("config_schema") = 'object'
435
+ AND jsonb_typeof("capabilities") = 'object'
436
+ AND octet_length(convert_to("config_schema"::text, 'UTF8')) <= 131072
437
+ AND octet_length(convert_to("capabilities"::text, 'UTF8')) <= 131072
438
+ ),
439
+ CONSTRAINT "integration_feature_facets_integration_feature_uq"
440
+ UNIQUE ("integration_facet_id", "feature_key")
441
+ );
442
+
443
+ CREATE INDEX "integration_feature_facets_integration_kind_idx"
444
+ ON "integration_feature_facets" ("integration_facet_id", "kind");
445
+
446
+ CREATE TABLE "integration_feature_bindings" (
447
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
448
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
449
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
450
+ "feature_facet_id" uuid NOT NULL REFERENCES "integration_feature_facets"("id")
451
+ ON DELETE RESTRICT,
452
+ "integration_facet_installation_id" uuid NOT NULL
453
+ REFERENCES "capability_facet_installations"("id") ON DELETE CASCADE,
454
+ "binding_key" text NOT NULL,
455
+ "display_name" text NOT NULL,
456
+ "runtime_key" text,
457
+ "connection_id" uuid REFERENCES "connections"("id") ON DELETE RESTRICT,
458
+ "status" text NOT NULL DEFAULT 'active',
459
+ "config" jsonb NOT NULL DEFAULT '{}'::jsonb,
460
+ "cursor" jsonb NOT NULL DEFAULT '{}'::jsonb,
461
+ "version" integer NOT NULL DEFAULT 1,
462
+ "last_success_at" timestamptz,
463
+ "last_error_code" text,
464
+ "created_by_subject_id" text NOT NULL,
465
+ "created_at" timestamptz NOT NULL DEFAULT now(),
466
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
467
+ CONSTRAINT "integration_feature_bindings_identity_chk" CHECK (
468
+ length("binding_key") BETWEEN 1 AND 128
469
+ AND "binding_key" = lower(btrim("binding_key"))
470
+ AND "binding_key" ~ '^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$'
471
+ AND length(btrim("display_name")) BETWEEN 1 AND 200
472
+ AND length(btrim("created_by_subject_id")) BETWEEN 1 AND 1024
473
+ ),
474
+ CONSTRAINT "integration_feature_bindings_runtime_chk" CHECK (
475
+ "runtime_key" IS NULL OR (
476
+ length("runtime_key") BETWEEN 1 AND 128
477
+ AND "runtime_key" ~ '^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$'
478
+ )
479
+ ),
480
+ CONSTRAINT "integration_feature_bindings_status_chk" CHECK (
481
+ "status" IN ('active', 'paused', 'needs_attention', 'disabled')
482
+ ),
483
+ CONSTRAINT "integration_feature_bindings_state_chk" CHECK (
484
+ jsonb_typeof("config") = 'object'
485
+ AND jsonb_typeof("cursor") = 'object'
486
+ AND octet_length(convert_to("config"::text, 'UTF8')) <= 131072
487
+ AND octet_length(convert_to("cursor"::text, 'UTF8')) <= 131072
488
+ AND "version" > 0
489
+ AND ("last_error_code" IS NULL OR length("last_error_code") BETWEEN 1 AND 120)
490
+ ),
491
+ CONSTRAINT "integration_feature_bindings_installation_feature_key_uq"
492
+ UNIQUE (
493
+ "workspace_id", "integration_facet_installation_id", "feature_facet_id", "binding_key"
494
+ )
495
+ );
496
+
497
+ CREATE INDEX "integration_feature_bindings_workspace_status_idx"
498
+ ON "integration_feature_bindings" ("workspace_id", "status");
499
+ CREATE UNIQUE INDEX "integration_feature_bindings_workspace_runtime_uq"
500
+ ON "integration_feature_bindings" ("workspace_id", "runtime_key")
501
+ WHERE "runtime_key" IS NOT NULL;
502
+
503
+ CREATE TABLE "integration_feature_binding_owners" (
504
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
505
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
506
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
507
+ "binding_id" uuid NOT NULL REFERENCES "integration_feature_bindings"("id")
508
+ ON DELETE CASCADE,
509
+ "owner_kind" text NOT NULL,
510
+ "owner_id" text NOT NULL,
511
+ "removable" boolean NOT NULL DEFAULT true,
512
+ "created_at" timestamptz NOT NULL DEFAULT now(),
513
+ CONSTRAINT "integration_feature_binding_owners_kind_chk" CHECK (
514
+ "owner_kind" IN ('direct', 'plugin', 'pack', 'migration')
515
+ ),
516
+ CONSTRAINT "integration_feature_binding_owners_id_chk" CHECK (
517
+ length("owner_id") BETWEEN 1 AND 512 AND "owner_id" !~ '[[:cntrl:]]'
518
+ ),
519
+ CONSTRAINT "integration_feature_binding_owners_unique_uq"
520
+ UNIQUE ("binding_id", "owner_kind", "owner_id")
521
+ );
522
+
523
+ CREATE INDEX "integration_feature_binding_owners_workspace_owner_idx"
524
+ ON "integration_feature_binding_owners" ("workspace_id", "owner_kind", "owner_id");
525
+
526
+ CREATE TABLE "capability_operations" (
527
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
528
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
529
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
530
+ "idempotency_key" text NOT NULL,
531
+ "request_digest" text NOT NULL,
532
+ "kind" text NOT NULL,
533
+ "target_kind" text NOT NULL,
534
+ "target_id" text NOT NULL,
535
+ "status" text NOT NULL DEFAULT 'pending',
536
+ "phase" text NOT NULL DEFAULT 'admitted',
537
+ "version" integer NOT NULL DEFAULT 1,
538
+ "result" jsonb,
539
+ "error_code" text,
540
+ "created_by_subject_id" text NOT NULL,
541
+ "created_at" timestamptz NOT NULL DEFAULT now(),
542
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
543
+ "completed_at" timestamptz,
544
+ CONSTRAINT "capability_operations_idempotency_chk" CHECK (
545
+ length("idempotency_key") BETWEEN 1 AND 200
546
+ AND "request_digest" ~ '^[0-9a-f]{64}$'
547
+ ),
548
+ CONSTRAINT "capability_operations_kind_chk" CHECK (
549
+ "kind" IN ('install', 'connect', 'configure', 'update', 'repair', 'disconnect', 'uninstall')
550
+ ),
551
+ CONSTRAINT "capability_operations_target_chk" CHECK (
552
+ "target_kind" IN ('plugin', 'integration', 'skill', 'pack', 'facet_binding')
553
+ AND length("target_id") BETWEEN 1 AND 512
554
+ ),
555
+ CONSTRAINT "capability_operations_status_chk" CHECK (
556
+ "status" IN ('pending', 'running', 'completed', 'failed', 'outcome_unknown')
557
+ ),
558
+ CONSTRAINT "capability_operations_state_chk" CHECK (
559
+ length("phase") BETWEEN 1 AND 120
560
+ AND "version" > 0
561
+ AND ("result" IS NULL OR (
562
+ jsonb_typeof("result") = 'object'
563
+ AND octet_length(convert_to("result"::text, 'UTF8')) <= 131072
564
+ ))
565
+ AND ("error_code" IS NULL OR length("error_code") BETWEEN 1 AND 120)
566
+ AND length(btrim("created_by_subject_id")) BETWEEN 1 AND 1024
567
+ AND (("status" IN ('completed', 'failed')) = ("completed_at" IS NOT NULL))
568
+ ),
569
+ CONSTRAINT "capability_operations_workspace_idempotency_uq"
570
+ UNIQUE ("workspace_id", "idempotency_key")
571
+ );
572
+
573
+ CREATE INDEX "capability_operations_workspace_status_idx"
574
+ ON "capability_operations" ("workspace_id", "status", "updated_at");
575
+
576
+ CREATE OR REPLACE FUNCTION capability_v2_reject_immutable_update()
577
+ RETURNS trigger
578
+ LANGUAGE plpgsql
579
+ AS $$
580
+ BEGIN
581
+ RAISE EXCEPTION '% rows are immutable', TG_TABLE_NAME USING ERRCODE = '55000';
582
+ END;
583
+ $$;
584
+
585
+ CREATE TRIGGER capability_facets_immutable
586
+ BEFORE UPDATE ON "capability_facets"
587
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
588
+ CREATE TRIGGER capability_integration_facets_immutable
589
+ BEFORE UPDATE ON "capability_integration_facets"
590
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
591
+ CREATE TRIGGER capability_mcp_facets_immutable
592
+ BEFORE UPDATE ON "capability_mcp_facets"
593
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
594
+ CREATE TRIGGER capability_api_facets_immutable
595
+ BEFORE UPDATE ON "capability_api_facets"
596
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
597
+ CREATE TRIGGER capability_skill_facets_immutable
598
+ BEFORE UPDATE ON "capability_skill_facets"
599
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
600
+ CREATE TRIGGER capability_skill_files_immutable
601
+ BEFORE UPDATE ON "capability_skill_files"
602
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
603
+ CREATE TRIGGER integration_spec_revisions_immutable
604
+ BEFORE UPDATE ON "integration_spec_revisions"
605
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_reject_immutable_update();
606
+
607
+ CREATE OR REPLACE FUNCTION capability_plugin_versions_restrict_update()
608
+ RETURNS trigger
609
+ LANGUAGE plpgsql
610
+ AS $$
611
+ BEGIN
612
+ IF NEW."plugin_id" IS DISTINCT FROM OLD."plugin_id"
613
+ OR NEW."version" IS DISTINCT FROM OLD."version"
614
+ OR NEW."manifest_digest" IS DISTINCT FROM OLD."manifest_digest"
615
+ OR NEW."manifest" IS DISTINCT FROM OLD."manifest"
616
+ OR NEW."import_batch_id" IS DISTINCT FROM OLD."import_batch_id"
617
+ OR NEW."created_at" IS DISTINCT FROM OLD."created_at"
618
+ THEN
619
+ RAISE EXCEPTION 'published capability plugin version identity is immutable'
620
+ USING ERRCODE = '55000';
621
+ END IF;
622
+ RETURN NEW;
623
+ END;
624
+ $$;
625
+
626
+ CREATE TRIGGER capability_plugin_versions_restrict_update
627
+ BEFORE UPDATE ON "capability_plugin_versions"
628
+ FOR EACH ROW EXECUTE FUNCTION capability_plugin_versions_restrict_update();
629
+
630
+ CREATE OR REPLACE FUNCTION capability_v2_validate_plugin_installation()
631
+ RETURNS trigger
632
+ LANGUAGE plpgsql
633
+ AS $$
634
+ BEGIN
635
+ IF NOT EXISTS (
636
+ SELECT 1
637
+ FROM "capability_plugins" p
638
+ JOIN "capability_plugin_versions" v
639
+ ON v."plugin_id" = p."id" AND v."id" = NEW."plugin_version_id"
640
+ WHERE p."id" = NEW."plugin_id"
641
+ AND (
642
+ p."workspace_id" IS NULL
643
+ OR (
644
+ p."account_id" = NEW."account_id"
645
+ AND p."workspace_id" = NEW."workspace_id"
646
+ )
647
+ )
648
+ ) THEN
649
+ RAISE EXCEPTION 'plugin installation version or tenant does not match its plugin'
650
+ USING ERRCODE = '23514';
651
+ END IF;
652
+ RETURN NEW;
653
+ END;
654
+ $$;
655
+
656
+ CREATE TRIGGER capability_plugin_installations_validate
657
+ BEFORE INSERT OR UPDATE ON "capability_plugin_installations"
658
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_validate_plugin_installation();
659
+
660
+ CREATE OR REPLACE FUNCTION capability_v2_validate_facet_installation()
661
+ RETURNS trigger
662
+ LANGUAGE plpgsql
663
+ AS $$
664
+ BEGIN
665
+ IF NOT EXISTS (
666
+ SELECT 1
667
+ FROM "capability_plugin_installations" i
668
+ JOIN "capability_facets" f ON f."id" = NEW."facet_id"
669
+ WHERE i."id" = NEW."plugin_installation_id"
670
+ AND i."account_id" = NEW."account_id"
671
+ AND i."workspace_id" = NEW."workspace_id"
672
+ AND f."plugin_version_id" = i."plugin_version_id"
673
+ ) THEN
674
+ RAISE EXCEPTION 'facet installation does not match its plugin installation or tenant'
675
+ USING ERRCODE = '23514';
676
+ END IF;
677
+ IF NEW."connection_id" IS NOT NULL AND NOT EXISTS (
678
+ SELECT 1 FROM "connections" c
679
+ WHERE c."id" = NEW."connection_id"
680
+ AND c."account_id" = NEW."account_id"
681
+ AND c."workspace_id" = NEW."workspace_id"
682
+ ) THEN
683
+ RAISE EXCEPTION 'facet installation connection belongs to another tenant'
684
+ USING ERRCODE = '23514';
685
+ END IF;
686
+ RETURN NEW;
687
+ END;
688
+ $$;
689
+
690
+ CREATE TRIGGER capability_facet_installations_validate
691
+ BEFORE INSERT OR UPDATE ON "capability_facet_installations"
692
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_validate_facet_installation();
693
+
694
+ CREATE OR REPLACE FUNCTION capability_v2_validate_component_owner()
695
+ RETURNS trigger
696
+ LANGUAGE plpgsql
697
+ AS $$
698
+ BEGIN
699
+ IF NOT EXISTS (
700
+ SELECT 1 FROM "capability_facet_installations" i
701
+ WHERE i."id" = NEW."facet_installation_id"
702
+ AND i."account_id" = NEW."account_id"
703
+ AND i."workspace_id" = NEW."workspace_id"
704
+ ) THEN
705
+ RAISE EXCEPTION 'component owner does not match its facet installation tenant'
706
+ USING ERRCODE = '23514';
707
+ END IF;
708
+ RETURN NEW;
709
+ END;
710
+ $$;
711
+
712
+ CREATE TRIGGER capability_component_owners_validate
713
+ BEFORE INSERT OR UPDATE ON "capability_component_owners"
714
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_validate_component_owner();
715
+
716
+ CREATE OR REPLACE FUNCTION capability_v2_validate_feature_binding()
717
+ RETURNS trigger
718
+ LANGUAGE plpgsql
719
+ AS $$
720
+ BEGIN
721
+ IF NOT EXISTS (
722
+ SELECT 1
723
+ FROM "integration_feature_facets" f
724
+ JOIN "capability_facet_installations" i
725
+ ON i."id" = NEW."integration_facet_installation_id"
726
+ AND i."facet_id" = f."integration_facet_id"
727
+ WHERE f."id" = NEW."feature_facet_id"
728
+ AND i."account_id" = NEW."account_id"
729
+ AND i."workspace_id" = NEW."workspace_id"
730
+ ) THEN
731
+ RAISE EXCEPTION 'feature binding does not match its integration installation or tenant'
732
+ USING ERRCODE = '23514';
733
+ END IF;
734
+ IF NEW."connection_id" IS NOT NULL AND NOT EXISTS (
735
+ SELECT 1 FROM "connections" c
736
+ WHERE c."id" = NEW."connection_id"
737
+ AND c."account_id" = NEW."account_id"
738
+ AND c."workspace_id" = NEW."workspace_id"
739
+ ) THEN
740
+ RAISE EXCEPTION 'feature binding connection belongs to another tenant'
741
+ USING ERRCODE = '23514';
742
+ END IF;
743
+ RETURN NEW;
744
+ END;
745
+ $$;
746
+
747
+ CREATE TRIGGER integration_feature_bindings_validate
748
+ BEFORE INSERT OR UPDATE ON "integration_feature_bindings"
749
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_validate_feature_binding();
750
+
751
+ CREATE OR REPLACE FUNCTION capability_v2_validate_feature_binding_owner()
752
+ RETURNS trigger
753
+ LANGUAGE plpgsql
754
+ AS $$
755
+ BEGIN
756
+ IF NOT EXISTS (
757
+ SELECT 1 FROM "integration_feature_bindings" b
758
+ WHERE b."id" = NEW."binding_id"
759
+ AND b."account_id" = NEW."account_id"
760
+ AND b."workspace_id" = NEW."workspace_id"
761
+ ) THEN
762
+ RAISE EXCEPTION 'feature binding owner does not match its binding tenant'
763
+ USING ERRCODE = '23514';
764
+ END IF;
765
+ RETURN NEW;
766
+ END;
767
+ $$;
768
+
769
+ CREATE TRIGGER integration_feature_binding_owners_validate
770
+ BEFORE INSERT OR UPDATE ON "integration_feature_binding_owners"
771
+ FOR EACH ROW EXECUTE FUNCTION capability_v2_validate_feature_binding_owner();
772
+
773
+ ALTER TABLE "capability_plugins" ENABLE ROW LEVEL SECURITY;
774
+ ALTER TABLE "capability_plugins" FORCE ROW LEVEL SECURITY;
775
+ ALTER TABLE "capability_plugin_versions" ENABLE ROW LEVEL SECURITY;
776
+ ALTER TABLE "capability_plugin_versions" FORCE ROW LEVEL SECURITY;
777
+ ALTER TABLE "capability_facets" ENABLE ROW LEVEL SECURITY;
778
+ ALTER TABLE "capability_facets" FORCE ROW LEVEL SECURITY;
779
+ ALTER TABLE "capability_integration_facets" ENABLE ROW LEVEL SECURITY;
780
+ ALTER TABLE "capability_integration_facets" FORCE ROW LEVEL SECURITY;
781
+ ALTER TABLE "capability_mcp_facets" ENABLE ROW LEVEL SECURITY;
782
+ ALTER TABLE "capability_mcp_facets" FORCE ROW LEVEL SECURITY;
783
+ ALTER TABLE "capability_api_facets" ENABLE ROW LEVEL SECURITY;
784
+ ALTER TABLE "capability_api_facets" FORCE ROW LEVEL SECURITY;
785
+ ALTER TABLE "capability_skill_facets" ENABLE ROW LEVEL SECURITY;
786
+ ALTER TABLE "capability_skill_facets" FORCE ROW LEVEL SECURITY;
787
+ ALTER TABLE "capability_skill_files" ENABLE ROW LEVEL SECURITY;
788
+ ALTER TABLE "capability_skill_files" FORCE ROW LEVEL SECURITY;
789
+ ALTER TABLE "capability_plugin_installations" ENABLE ROW LEVEL SECURITY;
790
+ ALTER TABLE "capability_plugin_installations" FORCE ROW LEVEL SECURITY;
791
+ ALTER TABLE "capability_facet_installations" ENABLE ROW LEVEL SECURITY;
792
+ ALTER TABLE "capability_facet_installations" FORCE ROW LEVEL SECURITY;
793
+ ALTER TABLE "capability_component_owners" ENABLE ROW LEVEL SECURITY;
794
+ ALTER TABLE "capability_component_owners" FORCE ROW LEVEL SECURITY;
795
+ ALTER TABLE "integration_spec_revisions" ENABLE ROW LEVEL SECURITY;
796
+ ALTER TABLE "integration_spec_revisions" FORCE ROW LEVEL SECURITY;
797
+ ALTER TABLE "integration_tools" ENABLE ROW LEVEL SECURITY;
798
+ ALTER TABLE "integration_tools" FORCE ROW LEVEL SECURITY;
799
+ ALTER TABLE "integration_feature_facets" ENABLE ROW LEVEL SECURITY;
800
+ ALTER TABLE "integration_feature_facets" FORCE ROW LEVEL SECURITY;
801
+ ALTER TABLE "integration_feature_bindings" ENABLE ROW LEVEL SECURITY;
802
+ ALTER TABLE "integration_feature_bindings" FORCE ROW LEVEL SECURITY;
803
+ ALTER TABLE "integration_feature_binding_owners" ENABLE ROW LEVEL SECURITY;
804
+ ALTER TABLE "integration_feature_binding_owners" FORCE ROW LEVEL SECURITY;
805
+ ALTER TABLE "capability_operations" ENABLE ROW LEVEL SECURITY;
806
+ ALTER TABLE "capability_operations" FORCE ROW LEVEL SECURITY;
807
+
808
+ CREATE POLICY workspace_or_global_visibility ON "capability_plugins"
809
+ USING (
810
+ "workspace_id" IS NULL
811
+ OR opengeni_private.workspace_rls_visible("account_id", "workspace_id")
812
+ )
813
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
814
+
815
+ CREATE POLICY parent_plugin_visibility ON "capability_plugin_versions"
816
+ USING (EXISTS (
817
+ SELECT 1 FROM "capability_plugins" p WHERE p."id" = "plugin_id"
818
+ ))
819
+ WITH CHECK (EXISTS (
820
+ SELECT 1 FROM "capability_plugins" p
821
+ WHERE p."id" = "plugin_id"
822
+ AND p."workspace_id" IS NOT NULL
823
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
824
+ ));
825
+
826
+ CREATE POLICY parent_plugin_visibility ON "capability_facets"
827
+ USING (EXISTS (
828
+ SELECT 1 FROM "capability_plugin_versions" v WHERE v."id" = "plugin_version_id"
829
+ ))
830
+ WITH CHECK (EXISTS (
831
+ SELECT 1
832
+ FROM "capability_plugin_versions" v
833
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
834
+ WHERE v."id" = "plugin_version_id"
835
+ AND p."workspace_id" IS NOT NULL
836
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
837
+ ));
838
+
839
+ CREATE POLICY parent_facet_visibility ON "capability_integration_facets"
840
+ USING (EXISTS (SELECT 1 FROM "capability_facets" f WHERE f."id" = "facet_id"))
841
+ WITH CHECK (EXISTS (
842
+ SELECT 1
843
+ FROM "capability_facets" f
844
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
845
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
846
+ WHERE f."id" = "facet_id"
847
+ AND p."workspace_id" IS NOT NULL
848
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
849
+ ));
850
+ CREATE POLICY parent_facet_visibility ON "capability_mcp_facets"
851
+ USING (EXISTS (SELECT 1 FROM "capability_facets" f WHERE f."id" = "facet_id"))
852
+ WITH CHECK (EXISTS (
853
+ SELECT 1
854
+ FROM "capability_facets" f
855
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
856
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
857
+ WHERE f."id" = "facet_id"
858
+ AND p."workspace_id" IS NOT NULL
859
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
860
+ ));
861
+ CREATE POLICY parent_facet_visibility ON "capability_api_facets"
862
+ USING (EXISTS (SELECT 1 FROM "capability_facets" f WHERE f."id" = "facet_id"))
863
+ WITH CHECK (EXISTS (
864
+ SELECT 1
865
+ FROM "capability_facets" f
866
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
867
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
868
+ WHERE f."id" = "facet_id"
869
+ AND p."workspace_id" IS NOT NULL
870
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
871
+ ));
872
+ CREATE POLICY parent_facet_visibility ON "capability_skill_facets"
873
+ USING (EXISTS (SELECT 1 FROM "capability_facets" f WHERE f."id" = "facet_id"))
874
+ WITH CHECK (EXISTS (
875
+ SELECT 1
876
+ FROM "capability_facets" f
877
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
878
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
879
+ WHERE f."id" = "facet_id"
880
+ AND p."workspace_id" IS NOT NULL
881
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
882
+ ));
883
+ CREATE POLICY parent_skill_visibility ON "capability_skill_files"
884
+ USING (EXISTS (
885
+ SELECT 1 FROM "capability_skill_facets" s WHERE s."facet_id" = "skill_facet_id"
886
+ ))
887
+ WITH CHECK (EXISTS (
888
+ SELECT 1
889
+ FROM "capability_skill_facets" s
890
+ JOIN "capability_facets" f ON f."id" = s."facet_id"
891
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
892
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
893
+ WHERE s."facet_id" = "skill_facet_id"
894
+ AND p."workspace_id" IS NOT NULL
895
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
896
+ ));
897
+ CREATE POLICY parent_api_visibility ON "integration_spec_revisions"
898
+ USING (EXISTS (
899
+ SELECT 1 FROM "capability_api_facets" a WHERE a."facet_id" = "api_facet_id"
900
+ ))
901
+ WITH CHECK (EXISTS (
902
+ SELECT 1
903
+ FROM "capability_api_facets" a
904
+ JOIN "capability_facets" f ON f."id" = a."facet_id"
905
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
906
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
907
+ WHERE a."facet_id" = "api_facet_id"
908
+ AND p."workspace_id" IS NOT NULL
909
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
910
+ ));
911
+ CREATE POLICY parent_facet_visibility ON "integration_tools"
912
+ USING (EXISTS (SELECT 1 FROM "capability_facets" f WHERE f."id" = "facet_id"))
913
+ WITH CHECK (EXISTS (
914
+ SELECT 1
915
+ FROM "capability_facets" f
916
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
917
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
918
+ WHERE f."id" = "facet_id"
919
+ AND p."workspace_id" IS NOT NULL
920
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
921
+ ));
922
+ CREATE POLICY parent_integration_visibility ON "integration_feature_facets"
923
+ USING (EXISTS (
924
+ SELECT 1 FROM "capability_integration_facets" i
925
+ WHERE i."facet_id" = "integration_facet_id"
926
+ ))
927
+ WITH CHECK (EXISTS (
928
+ SELECT 1
929
+ FROM "capability_integration_facets" i
930
+ JOIN "capability_facets" f ON f."id" = i."facet_id"
931
+ JOIN "capability_plugin_versions" v ON v."id" = f."plugin_version_id"
932
+ JOIN "capability_plugins" p ON p."id" = v."plugin_id"
933
+ WHERE i."facet_id" = "integration_facet_id"
934
+ AND p."workspace_id" IS NOT NULL
935
+ AND opengeni_private.workspace_rls_visible(p."account_id", p."workspace_id")
936
+ ));
937
+
938
+ CREATE POLICY workspace_isolation ON "capability_plugin_installations"
939
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
940
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
941
+ CREATE POLICY workspace_isolation ON "capability_facet_installations"
942
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
943
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
944
+ CREATE POLICY workspace_isolation ON "capability_component_owners"
945
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
946
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
947
+ CREATE POLICY workspace_isolation ON "integration_feature_bindings"
948
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
949
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
950
+ CREATE POLICY workspace_isolation ON "integration_feature_binding_owners"
951
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
952
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
953
+ CREATE POLICY workspace_isolation ON "capability_operations"
954
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
955
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
956
+
957
+ DO $$
958
+ BEGIN
959
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
960
+ GRANT SELECT, INSERT, UPDATE, DELETE ON
961
+ "capability_plugins",
962
+ "capability_plugin_versions",
963
+ "capability_facets",
964
+ "capability_integration_facets",
965
+ "capability_mcp_facets",
966
+ "capability_api_facets",
967
+ "capability_skill_facets",
968
+ "capability_skill_files",
969
+ "capability_plugin_installations",
970
+ "capability_facet_installations",
971
+ "capability_component_owners",
972
+ "integration_spec_revisions",
973
+ "integration_tools",
974
+ "integration_feature_facets",
975
+ "integration_feature_bindings",
976
+ "integration_feature_binding_owners",
977
+ "capability_operations"
978
+ TO opengeni_app;
979
+ END IF;
980
+ END $$;