create-safest-tools 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +71 -0
  3. package/bin/create-safest-tools.mjs +12 -0
  4. package/package.json +34 -0
  5. package/src/cli.mjs +128 -0
  6. package/src/config.mjs +151 -0
  7. package/src/scaffold.mjs +30 -0
  8. package/template/LICENSE +201 -0
  9. package/template/README.md +35 -0
  10. package/template/console/README.md +28 -0
  11. package/template/console/analytics/AnalyticsWorkspace.tsx +55 -0
  12. package/template/console/analytics/controller.ts +133 -0
  13. package/template/console/analytics/events.ts +33 -0
  14. package/template/console/analytics/store.ts +33 -0
  15. package/template/console/analytics/types.ts +38 -0
  16. package/template/console/appeals/AppealWorkspace.tsx +73 -0
  17. package/template/console/appeals/controller.ts +125 -0
  18. package/template/console/appeals/events.ts +33 -0
  19. package/template/console/appeals/store.ts +35 -0
  20. package/template/console/appeals/types.ts +37 -0
  21. package/template/console/assistant/AssistantWorkspace.tsx +133 -0
  22. package/template/console/assistant/types.ts +34 -0
  23. package/template/console/auth/AccountJourney.tsx +69 -0
  24. package/template/console/auth/InvitationAcceptance.tsx +145 -0
  25. package/template/console/auth/OAuthButtons.tsx +78 -0
  26. package/template/console/auth/OperatorLogin.tsx +110 -0
  27. package/template/console/auth/PasswordRecovery.tsx +132 -0
  28. package/template/console/auth/account-route.ts +15 -0
  29. package/template/console/auth/browser-navigation.ts +7 -0
  30. package/template/console/auth/events.ts +15 -0
  31. package/template/console/command/CommandCentre.tsx +119 -0
  32. package/template/console/command/controller.ts +267 -0
  33. package/template/console/command/events.ts +19 -0
  34. package/template/console/command/store.ts +36 -0
  35. package/template/console/command/types.ts +61 -0
  36. package/template/console/components/AnalystIdentity.tsx +25 -0
  37. package/template/console/components/PageHeader.tsx +27 -0
  38. package/template/console/configuration/ConfigurationDialog.tsx +200 -0
  39. package/template/console/configuration/ConfigurationWorkspace.tsx +66 -0
  40. package/template/console/configuration/FormBuilder.tsx +143 -0
  41. package/template/console/configuration/api.ts +40 -0
  42. package/template/console/configuration/events.ts +14 -0
  43. package/template/console/configuration/types.ts +79 -0
  44. package/template/console/lib/format.ts +49 -0
  45. package/template/console/lib/http.ts +96 -0
  46. package/template/console/main.tsx +225 -0
  47. package/template/console/operations/OperationsWorkspace.tsx +126 -0
  48. package/template/console/operations/controller.ts +237 -0
  49. package/template/console/operations/events.ts +37 -0
  50. package/template/console/operations/store.ts +32 -0
  51. package/template/console/operations/types.ts +107 -0
  52. package/template/console/people/PeopleWorkspace.tsx +81 -0
  53. package/template/console/people/types.ts +25 -0
  54. package/template/console/profile/ProfileWorkspace.tsx +136 -0
  55. package/template/console/profile/events.ts +9 -0
  56. package/template/console/profile/types.ts +6 -0
  57. package/template/console/quality/QualityWorkspace.tsx +87 -0
  58. package/template/console/quality/controller.ts +154 -0
  59. package/template/console/quality/events.ts +34 -0
  60. package/template/console/quality/store.ts +36 -0
  61. package/template/console/quality/types.ts +70 -0
  62. package/template/console/queues/QueueEditor.tsx +173 -0
  63. package/template/console/queues/QueueWorkspace.tsx +109 -0
  64. package/template/console/queues/controller.ts +194 -0
  65. package/template/console/queues/events.ts +34 -0
  66. package/template/console/queues/store.ts +37 -0
  67. package/template/console/queues/types.ts +102 -0
  68. package/template/console/registry/RegistryDialog.tsx +198 -0
  69. package/template/console/registry/RegistryWorkspace.tsx +108 -0
  70. package/template/console/registry/events.ts +14 -0
  71. package/template/console/registry/types.ts +52 -0
  72. package/template/console/reports/ReportDrawer.tsx +159 -0
  73. package/template/console/reports/ReportWorkspace.tsx +90 -0
  74. package/template/console/reports/controller.ts +517 -0
  75. package/template/console/reports/events.ts +42 -0
  76. package/template/console/reports/store.ts +39 -0
  77. package/template/console/reports/types.ts +230 -0
  78. package/template/console/settings/BrandEditor.tsx +126 -0
  79. package/template/console/settings/ChannelDialog.tsx +241 -0
  80. package/template/console/settings/SettingsWorkspace.tsx +155 -0
  81. package/template/console/settings/events.ts +19 -0
  82. package/template/console/settings/handoff.ts +22 -0
  83. package/template/console/settings/types.ts +93 -0
  84. package/template/console/shell/WorkspaceShell.tsx +160 -0
  85. package/template/console/shell/controller.ts +182 -0
  86. package/template/console/shell/events.ts +25 -0
  87. package/template/console/shell/navigation.ts +61 -0
  88. package/template/console/shell/store.ts +56 -0
  89. package/template/console/shell/types.ts +86 -0
  90. package/template/console/workflows/CreateWorkflowDialog.tsx +87 -0
  91. package/template/console/workflows/WorkflowCanvas.tsx +42 -0
  92. package/template/console/workflows/WorkflowDialogs.tsx +6 -0
  93. package/template/console/workflows/WorkflowStudio.tsx +331 -0
  94. package/template/console/workflows/WorkflowWorkspace.tsx +82 -0
  95. package/template/console/workflows/events.ts +17 -0
  96. package/template/console/workflows/graph.ts +156 -0
  97. package/template/console/workflows/templates.ts +70 -0
  98. package/template/console/workflows/types.ts +201 -0
  99. package/template/gitignore.template +18 -0
  100. package/template/migrations/0001_reports_foundation.sql +444 -0
  101. package/template/migrations/0002_human_report_loop.sql +65 -0
  102. package/template/migrations/0003_delivery_reliability.sql +18 -0
  103. package/template/migrations/0004_public_intake.sql +14 -0
  104. package/template/migrations/0005_operations_visibility.sql +24 -0
  105. package/template/migrations/0006_ai_governance.sql +198 -0
  106. package/template/migrations/0007_ai_release_gates.sql +6 -0
  107. package/template/migrations/0008_retention_analytics_exports.sql +52 -0
  108. package/template/migrations/0009_retention_derived_copies.sql +14 -0
  109. package/template/migrations/0010_ai_quality_controls.sql +26 -0
  110. package/template/migrations/0011_analyst_presence.sql +28 -0
  111. package/template/migrations/0012_queue_policies.sql +87 -0
  112. package/template/migrations/0013_routing_agents.sql +63 -0
  113. package/template/migrations/0014_webhook_enrichments.sql +122 -0
  114. package/template/migrations/0015_queue_owned_ai.sql +55 -0
  115. package/template/migrations/0016_operator_accounts.sql +67 -0
  116. package/template/migrations/0017_operator_profiles_and_recovery.sql +33 -0
  117. package/template/migrations/0018_platform_configuration.sql +382 -0
  118. package/template/migrations/0019_workflow_authoring_runtime.sql +372 -0
  119. package/template/migrations/0020_tasks_findings_assistant_budgets.sql +427 -0
  120. package/template/migrations/0021_abuse_evidence_operations.sql +324 -0
  121. package/template/migrations/0022_workflow_dispatch_operations.sql +42 -0
  122. package/template/migrations/0023_component_connection_execution.sql +75 -0
  123. package/template/migrations/0024_access_runtime_integrity.sql +72 -0
  124. package/template/migrations/0025_installation_timezone.sql +11 -0
  125. package/template/migrations/0026_ai_and_egress_execution_controls.sql +49 -0
  126. package/template/migrations/0027_prompt_and_ai_registry.sql +37 -0
  127. package/template/migrations/0028_step_attempt_ai_provenance.sql +13 -0
  128. package/template/migrations/0029_evidence_fetch_transport.sql +5 -0
  129. package/template/migrations/0030_evidence_dlq_incidents.sql +45 -0
  130. package/template/migrations/0031_shadow_quality_integrity.sql +7 -0
  131. package/template/migrations/0032_action_delivery_outbox.sql +55 -0
  132. package/template/migrations/0033_configuration_and_assistant_drafts.sql +43 -0
  133. package/template/migrations/0034_installation_integrations.sql +31 -0
  134. package/template/migrations/0035_workspace_governance.sql +21 -0
  135. package/template/migrations/0036_published_routing_baseline.sql +15 -0
  136. package/template/migrations/0037_builtin_phishing_specialist.sql +71 -0
  137. package/template/migrations/0038_remove_deprecated_enrichment_runtime.sql +228 -0
  138. package/template/migrations/0039_secure_reporting_channels.sql +45 -0
  139. package/template/migrations/0040_notification_only_reporting.sql +24 -0
  140. package/template/migrations/0041_better_auth_credentials.sql +17 -0
  141. package/template/package.json +47 -0
  142. package/template/public/_headers +27 -0
  143. package/template/public/app-icon-192.png +0 -0
  144. package/template/public/app-icon-512.png +0 -0
  145. package/template/public/brand-icon.svg +7 -0
  146. package/template/public/brand-tokens.css +80 -0
  147. package/template/public/console/auth-shell.js +19340 -0
  148. package/template/public/customer-brand.js +58 -0
  149. package/template/public/embed/embed.css +139 -0
  150. package/template/public/embed/embed.js +408 -0
  151. package/template/public/embed/index.html +91 -0
  152. package/template/public/favicon.svg +7 -0
  153. package/template/public/fonts/Manrope-Variable.ttf +0 -0
  154. package/template/public/fonts/Newsreader-Italic-Variable.ttf +0 -0
  155. package/template/public/fonts/Newsreader-Variable.ttf +0 -0
  156. package/template/public/index.html +123 -0
  157. package/template/public/logo-primary.svg +7 -0
  158. package/template/public/logo-reversed.svg +7 -0
  159. package/template/public/manifest.webmanifest +21 -0
  160. package/template/public/public-report.js +184 -0
  161. package/template/public/report/index.html +39 -0
  162. package/template/public/report/public-report.css +20 -0
  163. package/template/public/social-card.png +0 -0
  164. package/template/public/styles.css +1521 -0
  165. package/template/public/widget.css +80 -0
  166. package/template/public/widget.js +220 -0
  167. package/template/reports.config.example.json +38 -0
  168. package/template/reports.schema.json +89 -0
  169. package/template/scripts/reports-auth-onboarding.mjs +180 -0
  170. package/template/scripts/reports-backup.mjs +276 -0
  171. package/template/scripts/reports-cloudflare-preflight.mjs +152 -0
  172. package/template/scripts/reports-deploy.mjs +173 -0
  173. package/template/scripts/reports-plan.mjs +226 -0
  174. package/template/scripts/reports-restore.mjs +180 -0
  175. package/template/scripts/reports-secrets.mjs +73 -0
  176. package/template/scripts/reports-uninstall-plan.mjs +32 -0
  177. package/template/src/agent-executor.ts +330 -0
  178. package/template/src/ai-observability.ts +163 -0
  179. package/template/src/ai-registry-validation.ts +244 -0
  180. package/template/src/ai-registry.ts +292 -0
  181. package/template/src/api-cursor.ts +84 -0
  182. package/template/src/assistant.ts +554 -0
  183. package/template/src/audit.ts +39 -0
  184. package/template/src/backup-service.ts +269 -0
  185. package/template/src/budget-control.ts +127 -0
  186. package/template/src/component-executor.ts +845 -0
  187. package/template/src/configuration-registry.ts +550 -0
  188. package/template/src/connection-egress.ts +430 -0
  189. package/template/src/connection-oauth.ts +368 -0
  190. package/template/src/evidence-service.ts +335 -0
  191. package/template/src/human-tasks.ts +316 -0
  192. package/template/src/index.ts +4114 -0
  193. package/template/src/installation-admin.ts +301 -0
  194. package/template/src/intake-abuse.ts +156 -0
  195. package/template/src/platform-registry-validation.ts +367 -0
  196. package/template/src/platform-registry.ts +753 -0
  197. package/template/src/report-admin.ts +342 -0
  198. package/template/src/report-ai-quality.ts +390 -0
  199. package/template/src/report-ai-validation.ts +80 -0
  200. package/template/src/report-ai.ts +857 -0
  201. package/template/src/report-auth.ts +292 -0
  202. package/template/src/report-better-auth.ts +583 -0
  203. package/template/src/report-context-schema.ts +132 -0
  204. package/template/src/report-context.ts +126 -0
  205. package/template/src/report-crypto.ts +142 -0
  206. package/template/src/report-delivery.ts +579 -0
  207. package/template/src/report-form-validation.ts +51 -0
  208. package/template/src/report-governance.ts +510 -0
  209. package/template/src/report-http.ts +90 -0
  210. package/template/src/report-operations.ts +685 -0
  211. package/template/src/report-operator-accounts.ts +810 -0
  212. package/template/src/report-presence.ts +398 -0
  213. package/template/src/report-queue-validation.ts +309 -0
  214. package/template/src/report-queues.ts +478 -0
  215. package/template/src/report-repository.ts +972 -0
  216. package/template/src/report-router-agent.ts +328 -0
  217. package/template/src/report-router-validation.ts +81 -0
  218. package/template/src/report-routing.ts +178 -0
  219. package/template/src/report-turnstile.ts +142 -0
  220. package/template/src/report-types.ts +224 -0
  221. package/template/src/report-validation.ts +279 -0
  222. package/template/src/report-workflow-validation.ts +119 -0
  223. package/template/src/report-workflow.ts +886 -0
  224. package/template/src/shadow-quality.ts +278 -0
  225. package/template/src/workflow-actions.ts +782 -0
  226. package/template/src/workflow-compiler.ts +230 -0
  227. package/template/src/workflow-dynamic-runtime.ts +613 -0
  228. package/template/src/workflow-effects.ts +316 -0
  229. package/template/src/workflow-expressions.ts +191 -0
  230. package/template/src/workflow-platform-types.ts +121 -0
  231. package/template/src/workflow-platform-validation.ts +540 -0
  232. package/template/src/workflow-repository.ts +916 -0
  233. package/template/src/workflow-runs.ts +686 -0
  234. package/template/src/workflow-simulator.ts +211 -0
  235. package/template/src/workspace-branding.ts +128 -0
  236. package/template/src/workspace-governance.ts +279 -0
  237. package/template/tsconfig.console.json +23 -0
  238. package/template/tsconfig.json +22 -0
  239. package/template/vite.console.config.ts +20 -0
  240. package/template/worker-configuration.d.ts +65 -0
@@ -0,0 +1,67 @@
1
+ PRAGMA foreign_keys = ON;
2
+
3
+ CREATE TABLE operator_users (
4
+ id TEXT PRIMARY KEY,
5
+ email TEXT NOT NULL COLLATE NOCASE UNIQUE,
6
+ display_name TEXT NOT NULL,
7
+ avatar_url TEXT,
8
+ roles_json TEXT NOT NULL,
9
+ status TEXT NOT NULL DEFAULT 'active'
10
+ CHECK (status IN ('active', 'suspended')),
11
+ password_hash TEXT,
12
+ password_salt TEXT,
13
+ password_iterations INTEGER,
14
+ invited_by TEXT,
15
+ accepted_at TEXT,
16
+ last_login_at TEXT,
17
+ created_at TEXT NOT NULL,
18
+ updated_at TEXT NOT NULL
19
+ );
20
+
21
+ CREATE INDEX operator_users_status_idx
22
+ ON operator_users(status, email, id);
23
+
24
+ CREATE TABLE operator_invitations (
25
+ id TEXT PRIMARY KEY,
26
+ email TEXT NOT NULL COLLATE NOCASE,
27
+ role TEXT NOT NULL
28
+ CHECK (role IN ('administrator', 'reviewer', 'appeal_reviewer', 'auditor')),
29
+ token_hash TEXT NOT NULL UNIQUE,
30
+ status TEXT NOT NULL DEFAULT 'pending'
31
+ CHECK (status IN ('pending', 'accepted', 'revoked')),
32
+ invited_by TEXT NOT NULL,
33
+ accepted_by TEXT REFERENCES operator_users(id),
34
+ expires_at TEXT NOT NULL,
35
+ accepted_at TEXT,
36
+ revoked_at TEXT,
37
+ created_at TEXT NOT NULL
38
+ );
39
+
40
+ CREATE UNIQUE INDEX operator_invitations_pending_email_idx
41
+ ON operator_invitations(email)
42
+ WHERE status = 'pending';
43
+ CREATE INDEX operator_invitations_status_idx
44
+ ON operator_invitations(status, expires_at, created_at DESC, id);
45
+
46
+ CREATE TABLE operator_sessions (
47
+ id TEXT PRIMARY KEY,
48
+ user_id TEXT NOT NULL REFERENCES operator_users(id) ON DELETE CASCADE,
49
+ token_hash TEXT NOT NULL UNIQUE,
50
+ csrf_hash TEXT NOT NULL,
51
+ expires_at TEXT NOT NULL,
52
+ last_seen_at TEXT NOT NULL,
53
+ revoked_at TEXT,
54
+ created_at TEXT NOT NULL
55
+ );
56
+
57
+ CREATE INDEX operator_sessions_user_idx
58
+ ON operator_sessions(user_id, revoked_at, expires_at DESC, id);
59
+ CREATE INDEX operator_sessions_expiry_idx
60
+ ON operator_sessions(revoked_at, expires_at, id);
61
+
62
+ CREATE TABLE operator_login_limits (
63
+ key_hash TEXT PRIMARY KEY,
64
+ attempt_count INTEGER NOT NULL CHECK (attempt_count >= 0),
65
+ window_started_at TEXT NOT NULL,
66
+ updated_at TEXT NOT NULL
67
+ );
@@ -0,0 +1,33 @@
1
+ PRAGMA foreign_keys = ON;
2
+
3
+ ALTER TABLE operator_users ADD COLUMN avatar_object_key TEXT;
4
+ ALTER TABLE operator_users ADD COLUMN avatar_uploaded_at TEXT;
5
+
6
+ CREATE TABLE operator_password_resets (
7
+ id TEXT PRIMARY KEY,
8
+ user_id TEXT NOT NULL REFERENCES operator_users(id) ON DELETE CASCADE,
9
+ token_hash TEXT NOT NULL UNIQUE,
10
+ status TEXT NOT NULL DEFAULT 'pending'
11
+ CHECK (status IN ('pending', 'used', 'revoked')),
12
+ delivery_status TEXT NOT NULL DEFAULT 'pending'
13
+ CHECK (delivery_status IN ('pending', 'delivered', 'failed', 'unavailable', 'manual')),
14
+ requested_by TEXT NOT NULL,
15
+ expires_at TEXT NOT NULL,
16
+ delivered_at TEXT,
17
+ used_at TEXT,
18
+ revoked_at TEXT,
19
+ created_at TEXT NOT NULL,
20
+ updated_at TEXT NOT NULL
21
+ );
22
+
23
+ CREATE INDEX operator_password_resets_user_idx
24
+ ON operator_password_resets(user_id, status, expires_at DESC, id);
25
+ CREATE INDEX operator_password_resets_expiry_idx
26
+ ON operator_password_resets(status, expires_at, id);
27
+
28
+ CREATE TABLE operator_password_reset_limits (
29
+ key_hash TEXT PRIMARY KEY,
30
+ attempt_count INTEGER NOT NULL CHECK (attempt_count >= 0),
31
+ window_started_at TEXT NOT NULL,
32
+ updated_at TEXT NOT NULL
33
+ );
@@ -0,0 +1,382 @@
1
+ PRAGMA foreign_keys = ON;
2
+
3
+ CREATE TABLE installation_features (
4
+ installation_id TEXT NOT NULL REFERENCES installations(id) ON DELETE CASCADE,
5
+ feature_key TEXT NOT NULL,
6
+ state TEXT NOT NULL CHECK (state IN ('unavailable', 'disabled', 'setup_required', 'ready', 'degraded', 'paused')),
7
+ capability_json TEXT NOT NULL DEFAULT '{}',
8
+ checked_at TEXT NOT NULL,
9
+ error_code TEXT,
10
+ revision INTEGER NOT NULL DEFAULT 1 CHECK (revision >= 1),
11
+ PRIMARY KEY (installation_id, feature_key)
12
+ );
13
+
14
+ CREATE INDEX installation_features_state_idx
15
+ ON installation_features(installation_id, state, feature_key);
16
+
17
+ CREATE TABLE service_identities (
18
+ id TEXT PRIMARY KEY,
19
+ installation_id TEXT NOT NULL REFERENCES installations(id) ON DELETE CASCADE,
20
+ identity_key TEXT NOT NULL,
21
+ display_name TEXT NOT NULL,
22
+ identity_kind TEXT NOT NULL CHECK (identity_kind IN (
23
+ 'integration', 'workflow_runtime', 'assistant', 'specialist_agent', 'delivery', 'maintenance'
24
+ )),
25
+ status TEXT NOT NULL CHECK (status IN ('active', 'paused', 'revoked')),
26
+ scopes_json TEXT NOT NULL DEFAULT '[]',
27
+ key_hash TEXT,
28
+ binding_reference TEXT,
29
+ created_at TEXT NOT NULL,
30
+ rotated_at TEXT,
31
+ revoked_at TEXT,
32
+ UNIQUE (installation_id, identity_key),
33
+ CHECK (key_hash IS NULL OR binding_reference IS NULL)
34
+ );
35
+
36
+ CREATE TABLE role_bindings (
37
+ id TEXT PRIMARY KEY,
38
+ installation_id TEXT NOT NULL REFERENCES installations(id) ON DELETE CASCADE,
39
+ principal_type TEXT NOT NULL CHECK (principal_type IN ('operator', 'service_identity')),
40
+ principal_id TEXT NOT NULL,
41
+ role TEXT NOT NULL CHECK (role IN (
42
+ 'owner', 'administrator', 'workflow_author', 'reviewer', 'appeal_reviewer',
43
+ 'operations', 'auditor', 'quality_reviewer'
44
+ )),
45
+ queue_scope_json TEXT NOT NULL DEFAULT '[]',
46
+ field_scope_json TEXT NOT NULL DEFAULT '{}',
47
+ created_by TEXT NOT NULL,
48
+ created_at TEXT NOT NULL,
49
+ revoked_at TEXT
50
+ );
51
+
52
+ CREATE INDEX role_bindings_principal_idx
53
+ ON role_bindings(installation_id, principal_type, principal_id, revoked_at, role);
54
+
55
+ CREATE TABLE connection_definitions (
56
+ id TEXT PRIMARY KEY,
57
+ installation_id TEXT NOT NULL REFERENCES installations(id) ON DELETE CASCADE,
58
+ connection_key TEXT NOT NULL,
59
+ name TEXT NOT NULL,
60
+ description TEXT NOT NULL DEFAULT '',
61
+ kind TEXT NOT NULL CHECK (kind IN (
62
+ 'webhook', 'external_api', 'customer_worker', 'ai_provider', 'notification', 'email'
63
+ )),
64
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'paused', 'archived')),
65
+ active_version_id TEXT,
66
+ created_by TEXT NOT NULL,
67
+ created_at TEXT NOT NULL,
68
+ updated_at TEXT NOT NULL,
69
+ UNIQUE (installation_id, connection_key)
70
+ );
71
+
72
+ CREATE INDEX connection_definitions_admin_idx
73
+ ON connection_definitions(installation_id, status, kind, name, id);
74
+
75
+ CREATE TABLE connection_versions (
76
+ id TEXT PRIMARY KEY,
77
+ connection_id TEXT NOT NULL REFERENCES connection_definitions(id) ON DELETE CASCADE,
78
+ version INTEGER NOT NULL CHECK (version >= 1),
79
+ base_url TEXT,
80
+ service_binding_name TEXT,
81
+ allowed_hosts_json TEXT NOT NULL DEFAULT '[]',
82
+ allowed_methods_json TEXT NOT NULL DEFAULT '["POST"]',
83
+ allowed_path_prefixes_json TEXT NOT NULL DEFAULT '["/"]',
84
+ redirect_policy_json TEXT NOT NULL DEFAULT '{"follow":false,"maximum":0}',
85
+ request_limit_bytes INTEGER NOT NULL DEFAULT 65536 CHECK (request_limit_bytes BETWEEN 1 AND 1048576),
86
+ response_limit_bytes INTEGER NOT NULL DEFAULT 262144 CHECK (response_limit_bytes BETWEEN 1 AND 5242880),
87
+ response_content_types_json TEXT NOT NULL DEFAULT '["application/json"]',
88
+ timeout_ms INTEGER NOT NULL DEFAULT 5000 CHECK (timeout_ms BETWEEN 100 AND 120000),
89
+ concurrency_limit INTEGER NOT NULL DEFAULT 8 CHECK (concurrency_limit BETWEEN 1 AND 1000),
90
+ requests_per_window INTEGER NOT NULL DEFAULT 60 CHECK (requests_per_window BETWEEN 1 AND 1000000),
91
+ window_seconds INTEGER NOT NULL DEFAULT 60 CHECK (window_seconds BETWEEN 1 AND 86400),
92
+ credential_strategy TEXT NOT NULL DEFAULT 'none' CHECK (credential_strategy IN (
93
+ 'none', 'static_header', 'bearer', 'hmac', 'oauth2_client_credentials',
94
+ 'oauth2_authorization_code', 'mutual_tls', 'service_binding'
95
+ )),
96
+ secret_reference TEXT,
97
+ signing_strategy_json TEXT NOT NULL DEFAULT '{}',
98
+ oauth_configuration_json TEXT NOT NULL DEFAULT '{}',
99
+ published_at TEXT NOT NULL,
100
+ retired_at TEXT,
101
+ created_by TEXT NOT NULL,
102
+ created_at TEXT NOT NULL,
103
+ UNIQUE (connection_id, version),
104
+ CHECK ((base_url IS NOT NULL) != (service_binding_name IS NOT NULL))
105
+ );
106
+
107
+ CREATE INDEX connection_versions_lookup_idx
108
+ ON connection_versions(connection_id, version DESC, id);
109
+
110
+ CREATE TABLE connection_health (
111
+ connection_version_id TEXT PRIMARY KEY REFERENCES connection_versions(id) ON DELETE CASCADE,
112
+ state TEXT NOT NULL DEFAULT 'unknown' CHECK (state IN ('unknown', 'healthy', 'degraded', 'open_circuit', 'paused')),
113
+ consecutive_failures INTEGER NOT NULL DEFAULT 0 CHECK (consecutive_failures >= 0),
114
+ opened_at TEXT,
115
+ next_probe_at TEXT,
116
+ last_success_at TEXT,
117
+ last_error_code TEXT,
118
+ revision INTEGER NOT NULL DEFAULT 1 CHECK (revision >= 1),
119
+ updated_at TEXT NOT NULL
120
+ );
121
+
122
+ CREATE INDEX connection_health_probe_idx
123
+ ON connection_health(state, next_probe_at, connection_version_id);
124
+
125
+ CREATE TABLE connection_credentials (
126
+ id TEXT PRIMARY KEY,
127
+ connection_version_id TEXT NOT NULL REFERENCES connection_versions(id) ON DELETE CASCADE,
128
+ strategy TEXT NOT NULL CHECK (strategy IN (
129
+ 'static_header', 'bearer', 'hmac', 'oauth2_client_credentials',
130
+ 'oauth2_authorization_code', 'mutual_tls', 'service_binding'
131
+ )),
132
+ secret_reference TEXT,
133
+ encrypted_access_token TEXT,
134
+ encrypted_refresh_token TEXT,
135
+ token_type TEXT,
136
+ granted_scopes_json TEXT NOT NULL DEFAULT '[]',
137
+ expires_at TEXT,
138
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'active', 'refresh_failed', 'revoked')),
139
+ last_refresh_at TEXT,
140
+ last_error_code TEXT,
141
+ created_at TEXT NOT NULL,
142
+ updated_at TEXT NOT NULL,
143
+ UNIQUE (connection_version_id)
144
+ );
145
+
146
+ CREATE INDEX connection_credentials_refresh_idx
147
+ ON connection_credentials(status, expires_at, id);
148
+
149
+ CREATE TABLE connection_oauth_states (
150
+ id TEXT PRIMARY KEY,
151
+ connection_id TEXT NOT NULL REFERENCES connection_definitions(id) ON DELETE CASCADE,
152
+ actor_id TEXT NOT NULL,
153
+ operator_session_id TEXT,
154
+ state_hash TEXT NOT NULL UNIQUE,
155
+ pkce_verifier_ciphertext TEXT,
156
+ redirect_uri TEXT NOT NULL,
157
+ requested_scopes_json TEXT NOT NULL DEFAULT '[]',
158
+ expires_at TEXT NOT NULL,
159
+ consumed_at TEXT,
160
+ created_at TEXT NOT NULL
161
+ );
162
+
163
+ CREATE INDEX connection_oauth_states_expiry_idx
164
+ ON connection_oauth_states(expires_at, consumed_at, id);
165
+
166
+ CREATE TABLE component_definitions (
167
+ id TEXT PRIMARY KEY,
168
+ installation_id TEXT NOT NULL REFERENCES installations(id) ON DELETE CASCADE,
169
+ component_key TEXT NOT NULL,
170
+ name TEXT NOT NULL,
171
+ description TEXT NOT NULL DEFAULT '',
172
+ component_kind TEXT NOT NULL CHECK (component_kind IN (
173
+ 'built_in', 'webhook_enrichment', 'api_enrichment', 'workers_ai',
174
+ 'specialist_agent', 'action', 'message'
175
+ )),
176
+ effect_class TEXT NOT NULL CHECK (effect_class IN ('read_only', 'side_effecting')),
177
+ owner_kind TEXT NOT NULL DEFAULT 'customer' CHECK (owner_kind IN ('safest', 'customer')),
178
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'paused', 'deprecated', 'archived')),
179
+ active_version_id TEXT,
180
+ created_by TEXT NOT NULL,
181
+ created_at TEXT NOT NULL,
182
+ updated_at TEXT NOT NULL,
183
+ UNIQUE (installation_id, component_key)
184
+ );
185
+
186
+ CREATE INDEX component_definitions_admin_idx
187
+ ON component_definitions(installation_id, status, component_kind, effect_class, name, id);
188
+
189
+ CREATE TABLE component_versions (
190
+ id TEXT PRIMARY KEY,
191
+ definition_id TEXT NOT NULL REFERENCES component_definitions(id) ON DELETE CASCADE,
192
+ version INTEGER NOT NULL CHECK (version >= 1),
193
+ implementation_kind TEXT NOT NULL CHECK (implementation_kind IN (
194
+ 'built_in', 'webhook', 'external_api', 'workers_ai', 'specialist_agent', 'message_template'
195
+ )),
196
+ implementation_reference TEXT NOT NULL,
197
+ input_schema_json TEXT NOT NULL,
198
+ output_schema_json TEXT NOT NULL,
199
+ allowed_input_fields_json TEXT NOT NULL DEFAULT '[]',
200
+ data_classifications_json TEXT NOT NULL DEFAULT '[]',
201
+ connection_version_id TEXT REFERENCES connection_versions(id),
202
+ risk_class TEXT NOT NULL DEFAULT 'low' CHECK (risk_class IN ('low', 'medium', 'high', 'critical')),
203
+ timeout_policy_json TEXT NOT NULL,
204
+ retry_policy_json TEXT NOT NULL,
205
+ cache_policy_json TEXT NOT NULL DEFAULT '{"enabled":false}',
206
+ concurrency_policy_json TEXT NOT NULL DEFAULT '{}',
207
+ budget_policy_json TEXT NOT NULL DEFAULT '{}',
208
+ approval_policy_json TEXT NOT NULL DEFAULT '{}',
209
+ tool_manifest_json TEXT NOT NULL DEFAULT '[]',
210
+ compatibility_json TEXT NOT NULL DEFAULT '{}',
211
+ package_digest TEXT,
212
+ signature_metadata_json TEXT,
213
+ published_at TEXT NOT NULL,
214
+ retired_at TEXT,
215
+ created_by TEXT NOT NULL,
216
+ created_at TEXT NOT NULL,
217
+ UNIQUE (definition_id, version)
218
+ );
219
+
220
+ CREATE INDEX component_versions_lookup_idx
221
+ ON component_versions(definition_id, version DESC, id);
222
+ CREATE INDEX component_versions_connection_idx
223
+ ON component_versions(connection_version_id, definition_id, id);
224
+
225
+ CREATE TABLE component_fixtures (
226
+ id TEXT PRIMARY KEY,
227
+ component_version_id TEXT NOT NULL REFERENCES component_versions(id) ON DELETE CASCADE,
228
+ name TEXT NOT NULL,
229
+ input_json TEXT NOT NULL,
230
+ expected_json TEXT NOT NULL,
231
+ expected_status TEXT NOT NULL DEFAULT 'succeeded' CHECK (expected_status IN ('succeeded', 'failed', 'timed_out')),
232
+ created_by TEXT NOT NULL,
233
+ created_at TEXT NOT NULL,
234
+ UNIQUE (component_version_id, name)
235
+ );
236
+
237
+ CREATE TABLE component_test_runs (
238
+ id TEXT PRIMARY KEY,
239
+ component_version_id TEXT NOT NULL REFERENCES component_versions(id) ON DELETE CASCADE,
240
+ fixture_id TEXT REFERENCES component_fixtures(id) ON DELETE SET NULL,
241
+ status TEXT NOT NULL CHECK (status IN ('running', 'passed', 'failed')),
242
+ output_json TEXT,
243
+ error_code TEXT,
244
+ started_by TEXT NOT NULL,
245
+ started_at TEXT NOT NULL,
246
+ finished_at TEXT
247
+ );
248
+
249
+ CREATE INDEX component_test_runs_version_idx
250
+ ON component_test_runs(component_version_id, started_at DESC, id DESC);
251
+
252
+ INSERT INTO connection_definitions (
253
+ id, installation_id, connection_key, name, description, kind, status,
254
+ active_version_id, created_by, created_at, updated_at
255
+ )
256
+ SELECT
257
+ 'legacy-enrichment-connection:' || d.id,
258
+ d.installation_id,
259
+ 'legacy-' || d.enrichment_key,
260
+ d.name || ' connection',
261
+ 'Migrated from webhook enrichment ' || d.enrichment_key,
262
+ 'webhook',
263
+ CASE d.status WHEN 'paused' THEN 'paused' WHEN 'archived' THEN 'archived' ELSE 'active' END,
264
+ 'legacy-enrichment-connection-version:' || d.active_version_id,
265
+ d.created_by,
266
+ d.created_at,
267
+ d.updated_at
268
+ FROM enrichment_definitions d;
269
+
270
+ INSERT INTO connection_versions (
271
+ id, connection_id, version, base_url, service_binding_name,
272
+ allowed_hosts_json, allowed_methods_json, allowed_path_prefixes_json,
273
+ redirect_policy_json, request_limit_bytes, response_limit_bytes,
274
+ response_content_types_json, timeout_ms, concurrency_limit,
275
+ requests_per_window, window_seconds, credential_strategy, secret_reference,
276
+ signing_strategy_json, oauth_configuration_json, published_at, retired_at,
277
+ created_by, created_at
278
+ )
279
+ SELECT
280
+ 'legacy-enrichment-connection-version:' || v.id,
281
+ 'legacy-enrichment-connection:' || v.definition_id,
282
+ v.version,
283
+ v.webhook_url,
284
+ NULL,
285
+ json_array(json_extract(v.webhook_url, '$.host')),
286
+ '["POST"]',
287
+ '["/"]',
288
+ '{"follow":false,"maximum":0}',
289
+ 65536,
290
+ 262144,
291
+ '["application/json"]',
292
+ v.timeout_ms,
293
+ 8,
294
+ 60,
295
+ 60,
296
+ 'hmac',
297
+ v.secret_binding,
298
+ '{"kind":"safest_hmac_v1"}',
299
+ '{}',
300
+ v.published_at,
301
+ NULL,
302
+ v.created_by,
303
+ v.created_at
304
+ FROM enrichment_definition_versions v;
305
+
306
+ UPDATE connection_versions
307
+ SET allowed_hosts_json = json_array(
308
+ substr(
309
+ base_url,
310
+ instr(base_url, '://') + 3,
311
+ CASE
312
+ WHEN instr(substr(base_url, instr(base_url, '://') + 3), '/') = 0
313
+ THEN length(base_url)
314
+ ELSE instr(substr(base_url, instr(base_url, '://') + 3), '/') - 1
315
+ END
316
+ )
317
+ )
318
+ WHERE id LIKE 'legacy-enrichment-connection-version:%';
319
+
320
+ INSERT INTO connection_health (
321
+ connection_version_id, state, consecutive_failures, revision, updated_at
322
+ )
323
+ SELECT
324
+ 'legacy-enrichment-connection-version:' || v.id,
325
+ 'unknown',
326
+ 0,
327
+ 1,
328
+ v.created_at
329
+ FROM enrichment_definition_versions v;
330
+
331
+ INSERT INTO component_definitions (
332
+ id, installation_id, component_key, name, description, component_kind,
333
+ effect_class, owner_kind, status, active_version_id, created_by, created_at, updated_at
334
+ )
335
+ SELECT
336
+ d.id,
337
+ d.installation_id,
338
+ d.enrichment_key,
339
+ d.name,
340
+ d.description,
341
+ 'webhook_enrichment',
342
+ 'read_only',
343
+ 'customer',
344
+ CASE d.status WHEN 'paused' THEN 'paused' WHEN 'archived' THEN 'archived' ELSE 'active' END,
345
+ d.active_version_id,
346
+ d.created_by,
347
+ d.created_at,
348
+ d.updated_at
349
+ FROM enrichment_definitions d;
350
+
351
+ INSERT INTO component_versions (
352
+ id, definition_id, version, implementation_kind, implementation_reference,
353
+ input_schema_json, output_schema_json, allowed_input_fields_json,
354
+ data_classifications_json, connection_version_id, risk_class,
355
+ timeout_policy_json, retry_policy_json, cache_policy_json,
356
+ concurrency_policy_json, budget_policy_json, approval_policy_json,
357
+ tool_manifest_json, compatibility_json, published_at, created_by, created_at
358
+ )
359
+ SELECT
360
+ v.id,
361
+ v.definition_id,
362
+ v.version,
363
+ 'webhook',
364
+ v.webhook_url,
365
+ json_object('type', 'object', 'properties', json(v.input_fields_json)),
366
+ v.output_schema_json,
367
+ v.input_fields_json,
368
+ '["report_operational"]',
369
+ 'legacy-enrichment-connection-version:' || v.id,
370
+ 'low',
371
+ json_object('timeout_ms', v.timeout_ms),
372
+ json_object('maximum_attempts', v.max_attempts, 'backoff', 'exponential'),
373
+ json_object('enabled', CASE WHEN v.ttl_seconds > 0 THEN json('true') ELSE json('false') END, 'ttl_seconds', v.ttl_seconds),
374
+ '{"maximum_concurrency":8}',
375
+ '{}',
376
+ '{}',
377
+ '[]',
378
+ '{"legacy_enrichment":true}',
379
+ v.published_at,
380
+ v.created_by,
381
+ v.created_at
382
+ FROM enrichment_definition_versions v;