open-managed-agents 0.1.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 (197) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +248 -0
  3. package/bin/oma.mjs +499 -0
  4. package/dist/scripts/alpha-openai-compatible-fixture.mjs +134 -0
  5. package/dist/scripts/alpha-smoke-models.mjs +92 -0
  6. package/dist/scripts/alpha-smoke.mjs +581 -0
  7. package/dist/scripts/oma-doctor.js +230 -0
  8. package/dist/scripts/oma-models.js +299 -0
  9. package/dist/scripts/oma-workspaces.js +133 -0
  10. package/dist/src/control-plane/admin/auth.js +43 -0
  11. package/dist/src/control-plane/admin/routes.js +76 -0
  12. package/dist/src/control-plane/admin/service.js +102 -0
  13. package/dist/src/control-plane/admission.js +90 -0
  14. package/dist/src/control-plane/agents/routes.js +63 -0
  15. package/dist/src/control-plane/agents/service.js +687 -0
  16. package/dist/src/control-plane/agents/store.js +391 -0
  17. package/dist/src/control-plane/agents/types.js +1 -0
  18. package/dist/src/control-plane/api-constants.js +3 -0
  19. package/dist/src/control-plane/app.js +907 -0
  20. package/dist/src/control-plane/console/auth.js +68 -0
  21. package/dist/src/control-plane/console/static.js +112 -0
  22. package/dist/src/control-plane/deployment-runtime-config.js +328 -0
  23. package/dist/src/control-plane/deployment-runtime-event-coordinator.js +25 -0
  24. package/dist/src/control-plane/deployment-runtime-turn-guard.js +14 -0
  25. package/dist/src/control-plane/deployment-session-coordinator.js +25 -0
  26. package/dist/src/control-plane/deployment-session-output-coordinator.js +27 -0
  27. package/dist/src/control-plane/deployment-storage.js +354 -0
  28. package/dist/src/control-plane/egress/image.js +48 -0
  29. package/dist/src/control-plane/egress/policy.js +571 -0
  30. package/dist/src/control-plane/egress/presets.js +77 -0
  31. package/dist/src/control-plane/egress/proxy.js +72 -0
  32. package/dist/src/control-plane/egress/ssrf.js +106 -0
  33. package/dist/src/control-plane/egress/utils/debug.js +14 -0
  34. package/dist/src/control-plane/egress/vendor/http-proxy.js +335 -0
  35. package/dist/src/control-plane/egress/vendor/mitm-ca.js +226 -0
  36. package/dist/src/control-plane/egress/vendor/mitm-leaf.js +124 -0
  37. package/dist/src/control-plane/egress/vendor/parent-proxy.js +438 -0
  38. package/dist/src/control-plane/egress/vendor/request-filter.js +105 -0
  39. package/dist/src/control-plane/egress/vendor/sandbox-config.js +1 -0
  40. package/dist/src/control-plane/egress/vendor/tls-terminate-proxy.js +269 -0
  41. package/dist/src/control-plane/environments/routes.js +54 -0
  42. package/dist/src/control-plane/environments/service.js +112 -0
  43. package/dist/src/control-plane/environments/store.js +132 -0
  44. package/dist/src/control-plane/environments/types.js +1 -0
  45. package/dist/src/control-plane/errors.js +81 -0
  46. package/dist/src/control-plane/events/broadcaster.js +217 -0
  47. package/dist/src/control-plane/events/constants.js +2 -0
  48. package/dist/src/control-plane/events/persist.js +39 -0
  49. package/dist/src/control-plane/events/request.js +190 -0
  50. package/dist/src/control-plane/events/routes.js +159 -0
  51. package/dist/src/control-plane/events/runtime-helpers.js +134 -0
  52. package/dist/src/control-plane/events/service.js +1985 -0
  53. package/dist/src/control-plane/events/session-guards.js +29 -0
  54. package/dist/src/control-plane/events/sse.js +6 -0
  55. package/dist/src/control-plane/events/store.js +772 -0
  56. package/dist/src/control-plane/events/tool-persistence.js +102 -0
  57. package/dist/src/control-plane/events/types.js +21 -0
  58. package/dist/src/control-plane/files/routes.js +121 -0
  59. package/dist/src/control-plane/files/service.js +65 -0
  60. package/dist/src/control-plane/files/store-common.js +87 -0
  61. package/dist/src/control-plane/files/store-local.js +488 -0
  62. package/dist/src/control-plane/files/store-memory.js +270 -0
  63. package/dist/src/control-plane/files/store.js +2 -0
  64. package/dist/src/control-plane/files/types.js +7 -0
  65. package/dist/src/control-plane/http.js +25 -0
  66. package/dist/src/control-plane/ids.js +43 -0
  67. package/dist/src/control-plane/logging.js +263 -0
  68. package/dist/src/control-plane/models/auth-storage-backend.js +238 -0
  69. package/dist/src/control-plane/models/catalog.js +78 -0
  70. package/dist/src/control-plane/models/config-security.js +376 -0
  71. package/dist/src/control-plane/models/deployment-config.js +93 -0
  72. package/dist/src/control-plane/models/routes.js +32 -0
  73. package/dist/src/control-plane/models/service.js +138 -0
  74. package/dist/src/control-plane/observability/instruments.js +65 -0
  75. package/dist/src/control-plane/observability/metrics.js +125 -0
  76. package/dist/src/control-plane/observability/routes.js +95 -0
  77. package/dist/src/control-plane/openapi/document.js +282 -0
  78. package/dist/src/control-plane/openapi/routes.js +78 -0
  79. package/dist/src/control-plane/request-idempotency.js +85 -0
  80. package/dist/src/control-plane/secrets/envelope.js +132 -0
  81. package/dist/src/control-plane/secrets/master-key.js +44 -0
  82. package/dist/src/control-plane/secrets/routes.js +20 -0
  83. package/dist/src/control-plane/secrets/service.js +71 -0
  84. package/dist/src/control-plane/secrets/store.js +212 -0
  85. package/dist/src/control-plane/secrets/types.js +3 -0
  86. package/dist/src/control-plane/sessions/pi/custom-tools.js +146 -0
  87. package/dist/src/control-plane/sessions/pi/mcp/bridge.js +527 -0
  88. package/dist/src/control-plane/sessions/pi/mcp/client.js +157 -0
  89. package/dist/src/control-plane/sessions/pi/mcp/credential.js +28 -0
  90. package/dist/src/control-plane/sessions/pi/mcp/fetch.js +69 -0
  91. package/dist/src/control-plane/sessions/pi/mcp/probe.js +202 -0
  92. package/dist/src/control-plane/sessions/pi/mcp/runtime.js +13 -0
  93. package/dist/src/control-plane/sessions/pi/runner.js +1104 -0
  94. package/dist/src/control-plane/sessions/pi/sandbox/cma-glob.js +388 -0
  95. package/dist/src/control-plane/sessions/pi/sandbox/cma-grep.js +124 -0
  96. package/dist/src/control-plane/sessions/pi/sandbox/docker-egress.js +347 -0
  97. package/dist/src/control-plane/sessions/pi/sandbox/docker.js +1589 -0
  98. package/dist/src/control-plane/sessions/pi/sandbox/glob.js +48 -0
  99. package/dist/src/control-plane/sessions/pi/sandbox/image.js +7 -0
  100. package/dist/src/control-plane/sessions/pi/sandbox/microsandbox.js +1677 -0
  101. package/dist/src/control-plane/sessions/pi/sandbox/provider.js +561 -0
  102. package/dist/src/control-plane/sessions/pi/sandbox/selection.js +168 -0
  103. package/dist/src/control-plane/sessions/pi/span-normalizer.js +82 -0
  104. package/dist/src/control-plane/sessions/pi/tool-permissions.js +392 -0
  105. package/dist/src/control-plane/sessions/pi/translator.js +100 -0
  106. package/dist/src/control-plane/sessions/request.js +164 -0
  107. package/dist/src/control-plane/sessions/resources.js +63 -0
  108. package/dist/src/control-plane/sessions/routes.js +88 -0
  109. package/dist/src/control-plane/sessions/serialize.js +24 -0
  110. package/dist/src/control-plane/sessions/service.js +733 -0
  111. package/dist/src/control-plane/sessions/store.js +538 -0
  112. package/dist/src/control-plane/sessions/types.js +1 -0
  113. package/dist/src/control-plane/skills/archive.js +169 -0
  114. package/dist/src/control-plane/skills/routes.js +41 -0
  115. package/dist/src/control-plane/skills/service.js +29 -0
  116. package/dist/src/control-plane/skills/store.js +233 -0
  117. package/dist/src/control-plane/skills/types.js +5 -0
  118. package/dist/src/control-plane/sqlite-transaction.js +15 -0
  119. package/dist/src/control-plane/vaults/mcp-oauth-validate.js +165 -0
  120. package/dist/src/control-plane/vaults/oauth-refresh-ticker.js +43 -0
  121. package/dist/src/control-plane/vaults/oauth-refresh.js +448 -0
  122. package/dist/src/control-plane/vaults/routes.js +66 -0
  123. package/dist/src/control-plane/vaults/service.js +553 -0
  124. package/dist/src/control-plane/vaults/store.js +691 -0
  125. package/dist/src/control-plane/vaults/types.js +1 -0
  126. package/dist/src/control-plane/wake-loop.js +65 -0
  127. package/dist/src/control-plane/wiring.js +92 -0
  128. package/dist/src/control-plane/workspace.js +4 -0
  129. package/dist/src/control-plane/workspaces/store.js +158 -0
  130. package/dist/src/egress-proxy-main.js +103 -0
  131. package/dist/src/main.js +124 -0
  132. package/dist/src/types/agents.js +1 -0
  133. package/dist/src/types/common.js +1 -0
  134. package/dist/src/types/environments.js +1 -0
  135. package/dist/src/types/events.js +121 -0
  136. package/dist/src/types/files.js +1 -0
  137. package/dist/src/types/json.js +19 -0
  138. package/dist/src/types/sessions.js +1 -0
  139. package/dist/ui/managed-agents-console/README.md +52 -0
  140. package/dist/ui/managed-agents-console/docs/agents.md +23 -0
  141. package/dist/ui/managed-agents-console/docs/console.md +23 -0
  142. package/dist/ui/managed-agents-console/docs/dreams.md +5 -0
  143. package/dist/ui/managed-agents-console/docs/environments.md +27 -0
  144. package/dist/ui/managed-agents-console/docs/events.md +19 -0
  145. package/dist/ui/managed-agents-console/docs/files.md +17 -0
  146. package/dist/ui/managed-agents-console/docs/github.md +11 -0
  147. package/dist/ui/managed-agents-console/docs/integrations.md +19 -0
  148. package/dist/ui/managed-agents-console/docs/memory.md +11 -0
  149. package/dist/ui/managed-agents-console/docs/migration.md +17 -0
  150. package/dist/ui/managed-agents-console/docs/multiagent.md +11 -0
  151. package/dist/ui/managed-agents-console/docs/outcomes.md +11 -0
  152. package/dist/ui/managed-agents-console/docs/overview.md +41 -0
  153. package/dist/ui/managed-agents-console/docs/permissions.md +24 -0
  154. package/dist/ui/managed-agents-console/docs/quickstart.md +51 -0
  155. package/dist/ui/managed-agents-console/docs/reference.md +27 -0
  156. package/dist/ui/managed-agents-console/docs/sandbox-reference.md +19 -0
  157. package/dist/ui/managed-agents-console/docs/sandbox-security.md +15 -0
  158. package/dist/ui/managed-agents-console/docs/scheduled-deployments.md +5 -0
  159. package/dist/ui/managed-agents-console/docs/self-hosted-sandboxes.md +15 -0
  160. package/dist/ui/managed-agents-console/docs/session-operations.md +21 -0
  161. package/dist/ui/managed-agents-console/docs/sessions.md +21 -0
  162. package/dist/ui/managed-agents-console/docs/skills.md +15 -0
  163. package/dist/ui/managed-agents-console/docs/tools.md +23 -0
  164. package/dist/ui/managed-agents-console/docs/vaults.md +19 -0
  165. package/dist/ui/managed-agents-console/docs/webhooks.md +11 -0
  166. package/dist/ui/managed-agents-console/index.html +47 -0
  167. package/dist/ui/managed-agents-console/serve.mjs +116 -0
  168. package/dist/ui/managed-agents-console/src/agents-files.jsx +273 -0
  169. package/dist/ui/managed-agents-console/src/api.js +1043 -0
  170. package/dist/ui/managed-agents-console/src/app.jsx +633 -0
  171. package/dist/ui/managed-agents-console/src/auth.jsx +215 -0
  172. package/dist/ui/managed-agents-console/src/console.css +733 -0
  173. package/dist/ui/managed-agents-console/src/data.js +188 -0
  174. package/dist/ui/managed-agents-console/src/detail.jsx +719 -0
  175. package/dist/ui/managed-agents-console/src/docs.jsx +200 -0
  176. package/dist/ui/managed-agents-console/src/environments.jsx +365 -0
  177. package/dist/ui/managed-agents-console/src/forms.jsx +494 -0
  178. package/dist/ui/managed-agents-console/src/icons.jsx +48 -0
  179. package/dist/ui/managed-agents-console/src/skills.jsx +21 -0
  180. package/dist/ui/managed-agents-console/src/sse.js +185 -0
  181. package/dist/ui/managed-agents-console/src/states.jsx +90 -0
  182. package/dist/ui/managed-agents-console/src/tweaks-panel.jsx +541 -0
  183. package/dist/ui/managed-agents-console/src/ui.jsx +190 -0
  184. package/dist/ui/managed-agents-console/src/vaults-data.js +89 -0
  185. package/dist/ui/managed-agents-console/src/vaults.jsx +171 -0
  186. package/dist/ui/managed-agents-console/vendor/babel.min.js +4 -0
  187. package/dist/ui/managed-agents-console/vendor/react-dom.production.min.js +267 -0
  188. package/dist/ui/managed-agents-console/vendor/react.production.min.js +31 -0
  189. package/dist/ui/openapi-docs/VENDOR.md +27 -0
  190. package/dist/ui/openapi-docs/index.html +16 -0
  191. package/dist/ui/openapi-docs/swagger-initializer.js +14 -0
  192. package/dist/ui/openapi-docs/vendor/LICENSE +202 -0
  193. package/dist/ui/openapi-docs/vendor/NOTICE +2 -0
  194. package/dist/ui/openapi-docs/vendor/swagger-ui-bundle.js +2 -0
  195. package/dist/ui/openapi-docs/vendor/swagger-ui-standalone-preset.js +2 -0
  196. package/dist/ui/openapi-docs/vendor/swagger-ui.css +3 -0
  197. package/package.json +53 -0
@@ -0,0 +1,691 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { withSqliteTransaction } from "../sqlite-transaction.js";
3
+ export const VAULT_SECRET_PREFIX = "vault/";
4
+ const SCHEMA = `
5
+ CREATE TABLE IF NOT EXISTS vaults (
6
+ id TEXT PRIMARY KEY,
7
+ workspace_id TEXT NOT NULL,
8
+ type TEXT NOT NULL,
9
+ display_name TEXT NOT NULL,
10
+ metadata TEXT NOT NULL,
11
+ created_at TEXT NOT NULL,
12
+ updated_at TEXT NOT NULL,
13
+ archived_at TEXT
14
+ );
15
+ CREATE INDEX IF NOT EXISTS vaults_by_workspace
16
+ ON vaults (workspace_id, id);
17
+
18
+ CREATE TABLE IF NOT EXISTS vault_credentials (
19
+ id TEXT PRIMARY KEY,
20
+ workspace_id TEXT NOT NULL,
21
+ vault_id TEXT NOT NULL,
22
+ type TEXT NOT NULL,
23
+ display_name TEXT,
24
+ metadata TEXT NOT NULL,
25
+ auth_type TEXT NOT NULL,
26
+ mcp_server_url TEXT NOT NULL,
27
+ token_endpoint TEXT,
28
+ client_id TEXT,
29
+ scope TEXT,
30
+ token_endpoint_auth_type TEXT,
31
+ expires_at TEXT,
32
+ auth_version INTEGER NOT NULL DEFAULT 1,
33
+ refresh_status TEXT,
34
+ refresh_attempts INTEGER NOT NULL DEFAULT 0,
35
+ next_refresh_at TEXT,
36
+ auth_hint_at TEXT,
37
+ created_at TEXT NOT NULL,
38
+ updated_at TEXT NOT NULL,
39
+ archived_at TEXT
40
+ );
41
+ CREATE INDEX IF NOT EXISTS vault_credentials_by_vault
42
+ ON vault_credentials (workspace_id, vault_id, id);
43
+ CREATE UNIQUE INDEX IF NOT EXISTS vault_credentials_active_server_url
44
+ ON vault_credentials (workspace_id, vault_id, mcp_server_url)
45
+ WHERE archived_at IS NULL;
46
+ `;
47
+ export class SqliteVaultStore {
48
+ db;
49
+ secrets;
50
+ insertVaultStmt;
51
+ retrieveVaultActiveStmt;
52
+ retrieveVaultAnyStmt;
53
+ updateVaultStmt;
54
+ archiveVaultStmt;
55
+ deleteVaultStmt;
56
+ deleteCredentialsByVaultStmt;
57
+ credentialRowsByVaultStmt;
58
+ insertCredentialStmt;
59
+ retrieveCredentialActiveStmt;
60
+ retrieveCredentialAnyStmt;
61
+ updateCredentialMetadataStmt;
62
+ archiveCredentialStmt;
63
+ deleteCredentialStmt;
64
+ countActiveCredentialsStmt;
65
+ resolveCredentialStmt;
66
+ readCredentialRuntimeMetadataStmt;
67
+ persistAuthHintStmt;
68
+ persistOauthRefreshSuccessStmt;
69
+ persistOauthRefreshFailureStmt;
70
+ listDueRefreshesStmt;
71
+ nextDueRefreshAtStmt;
72
+ listVaultStmts = new Map();
73
+ listCredentialStmts = new Map();
74
+ listAdminCredentialMetadataStmts = new Map();
75
+ constructor(db, secrets) {
76
+ this.db = db;
77
+ this.secrets = secrets;
78
+ this.db.exec(SCHEMA);
79
+ ensureVaultCredentialColumns(this.db);
80
+ this.insertVaultStmt = this.db.prepare(`INSERT INTO vaults (
81
+ id, workspace_id, type, display_name, metadata, created_at, updated_at, archived_at
82
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
83
+ this.retrieveVaultActiveStmt = this.db.prepare(`SELECT * FROM vaults
84
+ WHERE workspace_id = ? AND id = ? AND archived_at IS NULL`);
85
+ this.retrieveVaultAnyStmt = this.db.prepare(`SELECT * FROM vaults WHERE workspace_id = ? AND id = ?`);
86
+ this.updateVaultStmt = this.db.prepare(`UPDATE vaults
87
+ SET display_name = ?, metadata = ?, updated_at = ?
88
+ WHERE workspace_id = ? AND id = ? AND archived_at IS NULL`);
89
+ this.archiveVaultStmt = this.db.prepare(`UPDATE vaults
90
+ SET archived_at = COALESCE(archived_at, ?), updated_at = ?
91
+ WHERE workspace_id = ? AND id = ?`);
92
+ this.deleteVaultStmt = this.db.prepare(`DELETE FROM vaults WHERE workspace_id = ? AND id = ?`);
93
+ this.deleteCredentialsByVaultStmt = this.db.prepare(`DELETE FROM vault_credentials WHERE workspace_id = ? AND vault_id = ?`);
94
+ this.credentialRowsByVaultStmt = this.db.prepare(`SELECT * FROM vault_credentials WHERE workspace_id = ? AND vault_id = ?`);
95
+ this.insertCredentialStmt = this.db.prepare(`INSERT INTO vault_credentials (
96
+ id, workspace_id, vault_id, type, display_name, metadata, auth_type,
97
+ mcp_server_url, token_endpoint, client_id, scope, token_endpoint_auth_type,
98
+ expires_at, auth_version, next_refresh_at, created_at, updated_at, archived_at
99
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
100
+ this.retrieveCredentialActiveStmt = this.db.prepare(`SELECT * FROM vault_credentials
101
+ WHERE workspace_id = ? AND vault_id = ? AND id = ? AND archived_at IS NULL`);
102
+ this.retrieveCredentialAnyStmt = this.db.prepare(`SELECT * FROM vault_credentials
103
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?`);
104
+ this.updateCredentialMetadataStmt = this.db.prepare(`UPDATE vault_credentials
105
+ SET display_name = ?, metadata = ?, expires_at = ?, auth_version = ?,
106
+ refresh_status = CASE WHEN ? THEN NULL ELSE refresh_status END,
107
+ refresh_attempts = CASE WHEN ? THEN 0 ELSE refresh_attempts END,
108
+ next_refresh_at = CASE WHEN ? THEN ? ELSE next_refresh_at END,
109
+ auth_hint_at = CASE WHEN ? THEN NULL ELSE auth_hint_at END,
110
+ updated_at = ?
111
+ WHERE workspace_id = ? AND vault_id = ? AND id = ? AND archived_at IS NULL`);
112
+ this.archiveCredentialStmt = this.db.prepare(`UPDATE vault_credentials
113
+ SET archived_at = COALESCE(archived_at, ?), auth_version = auth_version + 1,
114
+ updated_at = ?
115
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?`);
116
+ this.deleteCredentialStmt = this.db.prepare(`DELETE FROM vault_credentials
117
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?`);
118
+ this.countActiveCredentialsStmt = this.db.prepare(`SELECT COUNT(*) AS n FROM vault_credentials
119
+ WHERE workspace_id = ? AND vault_id = ? AND archived_at IS NULL`);
120
+ this.resolveCredentialStmt = this.db.prepare(`SELECT * FROM vault_credentials
121
+ WHERE workspace_id = ? AND vault_id = ? AND mcp_server_url = ? AND archived_at IS NULL
122
+ ORDER BY id ASC
123
+ LIMIT 1`);
124
+ this.readCredentialRuntimeMetadataStmt = this.db.prepare(`SELECT id, vault_id, auth_type, token_endpoint, client_id,
125
+ token_endpoint_auth_type, auth_version, expires_at, refresh_status,
126
+ auth_hint_at, next_refresh_at, refresh_attempts
127
+ FROM vault_credentials
128
+ WHERE workspace_id = ? AND vault_id = ? AND id = ? AND archived_at IS NULL`);
129
+ this.persistAuthHintStmt = this.db.prepare(`UPDATE vault_credentials
130
+ SET auth_hint_at = ?
131
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?
132
+ AND auth_type = 'mcp_oauth'
133
+ AND auth_version = ?
134
+ AND archived_at IS NULL`);
135
+ this.persistOauthRefreshSuccessStmt = this.db.prepare(`UPDATE vault_credentials
136
+ SET expires_at = ?, scope = ?, auth_version = auth_version + 1,
137
+ refresh_status = 'ok', refresh_attempts = 0, next_refresh_at = ?,
138
+ auth_hint_at = NULL, updated_at = ?
139
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?
140
+ AND auth_type = 'mcp_oauth'
141
+ AND auth_version = ?
142
+ AND archived_at IS NULL`);
143
+ this.persistOauthRefreshFailureStmt = this.db.prepare(`UPDATE vault_credentials
144
+ SET refresh_status = ?, refresh_attempts = ?, next_refresh_at = ?,
145
+ auth_hint_at = NULL
146
+ WHERE workspace_id = ? AND vault_id = ? AND id = ?
147
+ AND auth_type = 'mcp_oauth'
148
+ AND auth_version = ?
149
+ AND archived_at IS NULL`);
150
+ this.listDueRefreshesStmt = this.db.prepare(`SELECT workspace_id, vault_id, id, auth_version, next_refresh_at
151
+ FROM vault_credentials
152
+ WHERE auth_type = 'mcp_oauth'
153
+ AND archived_at IS NULL
154
+ AND next_refresh_at IS NOT NULL
155
+ AND next_refresh_at <= ?
156
+ AND COALESCE(refresh_status, '') != 'invalid'
157
+ ORDER BY next_refresh_at ASC, id ASC
158
+ LIMIT ?`);
159
+ this.nextDueRefreshAtStmt = this.db.prepare(`SELECT MIN(next_refresh_at) AS next_refresh_at
160
+ FROM vault_credentials
161
+ WHERE auth_type = 'mcp_oauth'
162
+ AND archived_at IS NULL
163
+ AND next_refresh_at IS NOT NULL
164
+ AND COALESCE(refresh_status, '') != 'invalid'`);
165
+ }
166
+ static open(path = ":memory:", secrets) {
167
+ return new SqliteVaultStore(new DatabaseSync(path), secrets);
168
+ }
169
+ createVault(record) {
170
+ const v = record.row;
171
+ this.insertVaultStmt.run(v.id, v.workspace_id, v.type, v.display_name, JSON.stringify(v.metadata), v.created_at, v.updated_at, v.archived_at);
172
+ return v;
173
+ }
174
+ retrieveVault(workspaceId, vaultId) {
175
+ const row = this.retrieveVaultActiveStmt.get(workspaceId, vaultId);
176
+ return row ? deserializeVault(row) : undefined;
177
+ }
178
+ retrieveVaultAny(workspaceId, vaultId) {
179
+ const row = this.retrieveVaultAnyStmt.get(workspaceId, vaultId);
180
+ return row ? deserializeVault(row) : undefined;
181
+ }
182
+ listVaults(workspaceId, opts = {}) {
183
+ if (opts.page === "")
184
+ return { data: [], has_more: false, next_page: null };
185
+ const limit = normalizeLimit(opts.limit);
186
+ const rows = this.listVaultStmt({
187
+ includeArchived: opts.includeArchived ?? false,
188
+ hasPage: opts.page !== undefined,
189
+ }).all(...selectListArgs(workspaceId, limit + 1, opts.page));
190
+ const data = rows.slice(0, limit).map(deserializeVault);
191
+ return {
192
+ data,
193
+ has_more: rows.length > limit,
194
+ next_page: rows.length > limit ? data[data.length - 1]?.id ?? null : null,
195
+ };
196
+ }
197
+ listWorkspaceCredentialAdminMetadata(workspaceId, opts = {}) {
198
+ if (opts.page === "")
199
+ return { data: [], has_more: false, next_page: null };
200
+ const limit = normalizeLimit(opts.limit);
201
+ const rows = this.listAdminCredentialMetadataStmt({ hasPage: opts.page !== undefined })
202
+ .all(...selectListArgs(workspaceId, limit + 1, opts.page));
203
+ const data = rows.slice(0, limit).map(adminCredentialMetadata);
204
+ return {
205
+ data,
206
+ has_more: rows.length > limit,
207
+ next_page: rows.length > limit ? data[data.length - 1]?.credentialId ?? null : null,
208
+ };
209
+ }
210
+ updateVault(workspaceId, vaultId, updates, updatedAt) {
211
+ const existing = this.retrieveVault(workspaceId, vaultId);
212
+ if (!existing)
213
+ return undefined;
214
+ this.updateVaultStmt.run(updates.displayName ?? existing.display_name, JSON.stringify(updates.metadata ?? existing.metadata), updatedAt, workspaceId, vaultId);
215
+ return this.retrieveVaultAny(workspaceId, vaultId);
216
+ }
217
+ archiveVault(workspaceId, vaultId, archivedAt) {
218
+ const existing = this.retrieveVaultAny(workspaceId, vaultId);
219
+ if (!existing)
220
+ return undefined;
221
+ return withSqliteTransaction(this.db, () => {
222
+ const credentials = this.credentialsForVault(workspaceId, vaultId);
223
+ for (const credential of credentials) {
224
+ this.secrets?.delete(workspaceId, secretName(vaultId, credential.id));
225
+ }
226
+ this.archiveVaultStmt.run(archivedAt, archivedAt, workspaceId, vaultId);
227
+ for (const credential of credentials) {
228
+ this.archiveCredentialStmt.run(archivedAt, archivedAt, workspaceId, vaultId, credential.id);
229
+ }
230
+ return this.retrieveVaultAny(workspaceId, vaultId);
231
+ });
232
+ }
233
+ deleteVault(workspaceId, vaultId) {
234
+ const existing = this.retrieveVaultAny(workspaceId, vaultId);
235
+ if (!existing)
236
+ return undefined;
237
+ return withSqliteTransaction(this.db, () => {
238
+ for (const credential of this.credentialsForVault(workspaceId, vaultId)) {
239
+ this.secrets?.delete(workspaceId, secretName(vaultId, credential.id));
240
+ }
241
+ this.deleteCredentialsByVaultStmt.run(workspaceId, vaultId);
242
+ this.deleteVaultStmt.run(workspaceId, vaultId);
243
+ return existing;
244
+ });
245
+ }
246
+ createCredential(record) {
247
+ return withSqliteTransaction(this.db, () => {
248
+ const c = record.row;
249
+ this.requireSecrets().put(c.workspace_id, secretName(c.vault_id, c.id), record.token);
250
+ this.insertCredentialStmt.run(c.id, c.workspace_id, c.vault_id, c.type, c.display_name, JSON.stringify(c.metadata), c.auth.type, c.auth.mcp_server_url, c.auth.type === "mcp_oauth" ? c.auth.refresh?.token_endpoint ?? null : null, c.auth.type === "mcp_oauth" ? c.auth.refresh?.client_id ?? null : null, c.auth.type === "mcp_oauth" ? c.auth.refresh?.scope ?? null : null, c.auth.type === "mcp_oauth"
251
+ ? c.auth.refresh?.token_endpoint_auth.type ?? null
252
+ : null, c.auth.type === "mcp_oauth" ? c.auth.expires_at ?? null : null, c.auth_version, record.nextRefreshAt ?? null, c.created_at, c.updated_at, c.archived_at);
253
+ return c;
254
+ });
255
+ }
256
+ retrieveCredential(workspaceId, vaultId, credentialId) {
257
+ const row = this.retrieveCredentialActiveStmt.get(workspaceId, vaultId, credentialId);
258
+ return row ? deserializeCredential(row) : undefined;
259
+ }
260
+ retrieveCredentialAny(workspaceId, vaultId, credentialId) {
261
+ const row = this.retrieveCredentialAnyStmt.get(workspaceId, vaultId, credentialId);
262
+ return row ? deserializeCredential(row) : undefined;
263
+ }
264
+ listCredentials(workspaceId, vaultId, opts = {}) {
265
+ if (opts.page === "")
266
+ return { data: [], has_more: false, next_page: null };
267
+ const limit = normalizeLimit(opts.limit);
268
+ const rows = this.listCredentialStmt({
269
+ includeArchived: opts.includeArchived ?? false,
270
+ hasPage: opts.page !== undefined,
271
+ }).all(...selectCredentialListArgs(workspaceId, vaultId, limit + 1, opts.page));
272
+ const data = rows.slice(0, limit).map(deserializeCredential);
273
+ return {
274
+ data,
275
+ has_more: rows.length > limit,
276
+ next_page: rows.length > limit ? data[data.length - 1]?.id ?? null : null,
277
+ };
278
+ }
279
+ updateCredential(workspaceId, vaultId, credentialId, updates, updatedAt, scheduling) {
280
+ const existing = this.retrieveCredential(workspaceId, vaultId, credentialId);
281
+ if (!existing)
282
+ return undefined;
283
+ return withSqliteTransaction(this.db, () => {
284
+ if (updates.auth !== undefined) {
285
+ this.putUpdatedSecret(workspaceId, vaultId, credentialId, existing, updates.auth);
286
+ }
287
+ const nextAuthVersion = updates.auth === undefined ? existing.auth_version : existing.auth_version + 1;
288
+ const nextExpiresAt = updates.auth?.type === "mcp_oauth" && updates.auth.expiresAt !== undefined
289
+ ? updates.auth.expiresAt
290
+ : existing.auth.type === "mcp_oauth"
291
+ ? existing.auth.expires_at ?? null
292
+ : null;
293
+ this.updateCredentialMetadataStmt.run(updates.displayName === undefined
294
+ ? existing.display_name
295
+ : updates.displayName, JSON.stringify(updates.metadata ?? existing.metadata), nextExpiresAt, nextAuthVersion, updates.auth === undefined ? 0 : 1, updates.auth === undefined ? 0 : 1, updates.auth === undefined ? 0 : 1, scheduling?.nextRefreshAt ?? null, updates.auth === undefined ? 0 : 1, updatedAt, workspaceId, vaultId, credentialId);
296
+ return this.retrieveCredentialAny(workspaceId, vaultId, credentialId);
297
+ });
298
+ }
299
+ archiveCredential(workspaceId, vaultId, credentialId, archivedAt) {
300
+ const existing = this.retrieveCredentialAny(workspaceId, vaultId, credentialId);
301
+ if (!existing)
302
+ return undefined;
303
+ return withSqliteTransaction(this.db, () => {
304
+ this.secrets?.delete(workspaceId, secretName(vaultId, credentialId));
305
+ this.archiveCredentialStmt.run(archivedAt, archivedAt, workspaceId, vaultId, credentialId);
306
+ return this.retrieveCredentialAny(workspaceId, vaultId, credentialId);
307
+ });
308
+ }
309
+ deleteCredential(workspaceId, vaultId, credentialId) {
310
+ const existing = this.retrieveCredentialAny(workspaceId, vaultId, credentialId);
311
+ if (!existing)
312
+ return undefined;
313
+ return withSqliteTransaction(this.db, () => {
314
+ this.secrets?.delete(workspaceId, secretName(vaultId, credentialId));
315
+ this.deleteCredentialStmt.run(workspaceId, vaultId, credentialId);
316
+ return existing;
317
+ });
318
+ }
319
+ countActiveCredentials(workspaceId, vaultId) {
320
+ return this.countActiveCredentialsStmt.get(workspaceId, vaultId).n;
321
+ }
322
+ resolveCredential(workspaceId, vaultIds, serverUrl) {
323
+ for (const vaultId of vaultIds) {
324
+ const row = this.resolveCredentialStmt.get(workspaceId, vaultId, serverUrl);
325
+ if (!row)
326
+ continue;
327
+ const token = this.secrets?.reveal(workspaceId, secretName(vaultId, row.id));
328
+ if (token === undefined)
329
+ return undefined;
330
+ const accessToken = row.auth_type === "mcp_oauth" ? oauthAccessToken(token) : token;
331
+ if (accessToken === undefined)
332
+ return undefined;
333
+ return {
334
+ vaultId,
335
+ credentialId: row.id,
336
+ authType: row.auth_type,
337
+ authVersion: row.auth_version,
338
+ ...(row.expires_at === null ? {} : { expiresAt: row.expires_at }),
339
+ refreshStatus: row.refresh_status,
340
+ authHintAt: row.auth_hint_at,
341
+ updatedAt: row.updated_at,
342
+ token: accessToken,
343
+ };
344
+ }
345
+ return undefined;
346
+ }
347
+ readCredentialRuntimeMetadata(workspaceId, vaultId, credentialId) {
348
+ const row = this.readCredentialRuntimeMetadataStmt.get(workspaceId, vaultId, credentialId);
349
+ return row === undefined ? undefined : runtimeMetadata(row);
350
+ }
351
+ persistAuthHint(input) {
352
+ return withSqliteTransaction(this.db, () => {
353
+ const result = this.persistAuthHintStmt.run(input.authHintAt, input.workspaceId, input.vaultId, input.credentialId, input.expectedAuthVersion);
354
+ const metadata = this.readCredentialRuntimeMetadata(input.workspaceId, input.vaultId, input.credentialId);
355
+ return result.changes === 1 && metadata !== undefined
356
+ ? { status: "updated", metadata }
357
+ : { status: "stale", metadata };
358
+ });
359
+ }
360
+ readOauthRefreshState(workspaceId, vaultId, credentialId) {
361
+ return this.readOauthRefreshStateInternal(workspaceId, vaultId, credentialId);
362
+ }
363
+ persistOauthRefreshSuccess(input) {
364
+ return withSqliteTransaction(this.db, () => {
365
+ const current = this.readOauthRefreshStateInternal(input.workspaceId, input.vaultId, input.credentialId);
366
+ if (current === undefined)
367
+ return { status: "stale", state: undefined };
368
+ const result = this.persistOauthRefreshSuccessStmt.run(input.expiresAt === undefined ? current.expiresAt ?? null : input.expiresAt, input.scope === undefined ? current.refresh?.scope ?? null : input.scope, input.nextRefreshAt ?? null, input.updatedAt, input.workspaceId, input.vaultId, input.credentialId, input.expectedAuthVersion);
369
+ if (result.changes !== 1) {
370
+ return {
371
+ status: "stale",
372
+ state: this.readOauthRefreshStateInternal(input.workspaceId, input.vaultId, input.credentialId),
373
+ };
374
+ }
375
+ const nextRefreshToken = input.refreshToken ?? current.secrets.refreshToken;
376
+ const nextSecret = {
377
+ access_token: input.accessToken,
378
+ ...(nextRefreshToken === undefined
379
+ ? {}
380
+ : { refresh_token: nextRefreshToken }),
381
+ ...(current.secrets.clientSecret === undefined
382
+ ? {}
383
+ : { client_secret: current.secrets.clientSecret }),
384
+ };
385
+ this.requireSecrets().put(input.workspaceId, secretName(input.vaultId, input.credentialId), JSON.stringify(nextSecret));
386
+ return {
387
+ status: "updated",
388
+ state: this.readOauthRefreshStateInternal(input.workspaceId, input.vaultId, input.credentialId),
389
+ };
390
+ });
391
+ }
392
+ persistOauthRefreshFailure(input) {
393
+ return withSqliteTransaction(this.db, () => {
394
+ const result = this.persistOauthRefreshFailureStmt.run(input.status, input.refreshAttempts, input.nextRefreshAt, input.workspaceId, input.vaultId, input.credentialId, input.expectedAuthVersion);
395
+ return result.changes === 1
396
+ ? {
397
+ status: "updated",
398
+ state: this.readOauthRefreshStateInternal(input.workspaceId, input.vaultId, input.credentialId),
399
+ }
400
+ : {
401
+ status: "stale",
402
+ state: this.readOauthRefreshStateInternal(input.workspaceId, input.vaultId, input.credentialId),
403
+ };
404
+ });
405
+ }
406
+ listDueRefreshes(now, limit = 50) {
407
+ const rows = this.listDueRefreshesStmt.all(now, limit);
408
+ return rows.map((row) => ({
409
+ workspaceId: row.workspace_id,
410
+ vaultId: row.vault_id,
411
+ credentialId: row.id,
412
+ authVersion: row.auth_version,
413
+ nextRefreshAt: row.next_refresh_at,
414
+ }));
415
+ }
416
+ nextDueRefreshAt(_now) {
417
+ const row = this.nextDueRefreshAtStmt.get();
418
+ return row?.next_refresh_at ?? null;
419
+ }
420
+ close() {
421
+ this.db.close();
422
+ }
423
+ requireSecrets() {
424
+ if (this.secrets === undefined) {
425
+ throw new Error("Secrets require a master key: set OMA_MASTER_KEY or OMA_MASTER_KEY_FILE on the deployment");
426
+ }
427
+ return this.secrets;
428
+ }
429
+ putUpdatedSecret(workspaceId, vaultId, credentialId, existing, auth) {
430
+ if (auth.type !== existing.auth.type) {
431
+ throw new Error("Credential auth type cannot be changed");
432
+ }
433
+ const name = secretName(vaultId, credentialId);
434
+ if (auth.type === "static_bearer") {
435
+ this.requireSecrets().put(workspaceId, name, auth.token);
436
+ return;
437
+ }
438
+ const current = this.requireSecrets().reveal(workspaceId, name);
439
+ const parsed = current === undefined ? {} : parseOauthSecret(current);
440
+ const next = {
441
+ ...parsed,
442
+ ...(auth.accessToken === undefined ? {} : { access_token: auth.accessToken }),
443
+ ...(auth.refreshToken === undefined
444
+ ? {}
445
+ : { refresh_token: auth.refreshToken }),
446
+ };
447
+ this.requireSecrets().put(workspaceId, name, JSON.stringify(next));
448
+ }
449
+ credentialsForVault(workspaceId, vaultId) {
450
+ return this.credentialRowsByVaultStmt.all(workspaceId, vaultId).map(deserializeCredential);
451
+ }
452
+ readOauthRefreshStateInternal(workspaceId, vaultId, credentialId) {
453
+ const row = this.retrieveCredentialActiveStmt.get(workspaceId, vaultId, credentialId);
454
+ if (!row || row.auth_type !== "mcp_oauth")
455
+ return undefined;
456
+ const raw = this.secrets?.reveal(workspaceId, secretName(vaultId, credentialId));
457
+ const parsed = raw === undefined ? {} : parseOauthSecret(raw);
458
+ const auth = deserializeCredentialAuth(row);
459
+ if (auth.type !== "mcp_oauth")
460
+ return undefined;
461
+ return {
462
+ workspaceId,
463
+ vaultId,
464
+ credentialId,
465
+ authVersion: row.auth_version,
466
+ mcpServerUrl: row.mcp_server_url,
467
+ ...(row.expires_at === null ? {} : { expiresAt: row.expires_at }),
468
+ ...(auth.refresh === undefined
469
+ ? {}
470
+ : {
471
+ refresh: {
472
+ tokenEndpoint: auth.refresh.token_endpoint,
473
+ clientId: auth.refresh.client_id,
474
+ ...(auth.refresh.scope === undefined
475
+ ? {}
476
+ : { scope: auth.refresh.scope }),
477
+ tokenEndpointAuth: auth.refresh.token_endpoint_auth,
478
+ },
479
+ }),
480
+ secrets: {
481
+ ...(typeof parsed.access_token === "string"
482
+ ? { accessToken: parsed.access_token }
483
+ : {}),
484
+ ...(typeof parsed.refresh_token === "string"
485
+ ? { refreshToken: parsed.refresh_token }
486
+ : {}),
487
+ ...(typeof parsed.client_secret === "string"
488
+ ? { clientSecret: parsed.client_secret }
489
+ : {}),
490
+ },
491
+ refreshStatus: row.refresh_status,
492
+ refreshAttempts: row.refresh_attempts,
493
+ nextRefreshAt: row.next_refresh_at,
494
+ authHintAt: row.auth_hint_at,
495
+ };
496
+ }
497
+ listVaultStmt(opts) {
498
+ const key = JSON.stringify(opts);
499
+ const existing = this.listVaultStmts.get(key);
500
+ if (existing)
501
+ return existing;
502
+ const predicates = ["workspace_id = ?"];
503
+ if (!opts.includeArchived)
504
+ predicates.push("archived_at IS NULL");
505
+ if (opts.hasPage)
506
+ predicates.push("id < ?");
507
+ const stmt = this.db.prepare(`SELECT * FROM vaults
508
+ WHERE ${predicates.join(" AND ")}
509
+ ORDER BY id DESC
510
+ LIMIT ?`);
511
+ this.listVaultStmts.set(key, stmt);
512
+ return stmt;
513
+ }
514
+ listCredentialStmt(opts) {
515
+ const key = JSON.stringify(opts);
516
+ const existing = this.listCredentialStmts.get(key);
517
+ if (existing)
518
+ return existing;
519
+ const predicates = ["workspace_id = ?", "vault_id = ?"];
520
+ if (!opts.includeArchived)
521
+ predicates.push("archived_at IS NULL");
522
+ if (opts.hasPage)
523
+ predicates.push("id < ?");
524
+ const stmt = this.db.prepare(`SELECT * FROM vault_credentials
525
+ WHERE ${predicates.join(" AND ")}
526
+ ORDER BY id DESC
527
+ LIMIT ?`);
528
+ this.listCredentialStmts.set(key, stmt);
529
+ return stmt;
530
+ }
531
+ listAdminCredentialMetadataStmt(opts) {
532
+ const key = JSON.stringify(opts);
533
+ const existing = this.listAdminCredentialMetadataStmts.get(key);
534
+ if (existing)
535
+ return existing;
536
+ const predicates = ["c.workspace_id = ?"];
537
+ if (opts.hasPage)
538
+ predicates.push("c.id < ?");
539
+ const stmt = this.db.prepare(`SELECT c.id, c.vault_id, c.auth_type, c.token_endpoint, c.client_id,
540
+ c.token_endpoint_auth_type, c.auth_version, c.expires_at,
541
+ c.refresh_status, c.refresh_attempts, c.next_refresh_at, c.auth_hint_at,
542
+ c.mcp_server_url, c.display_name AS credential_display_name,
543
+ c.archived_at AS credential_archived_at,
544
+ v.display_name AS vault_display_name, v.archived_at AS vault_archived_at
545
+ FROM vault_credentials c
546
+ INNER JOIN vaults v ON v.workspace_id = c.workspace_id AND v.id = c.vault_id
547
+ WHERE ${predicates.join(" AND ")}
548
+ ORDER BY c.id DESC
549
+ LIMIT ?`);
550
+ this.listAdminCredentialMetadataStmts.set(key, stmt);
551
+ return stmt;
552
+ }
553
+ }
554
+ export function vaultSecretName(vaultId, credentialId) {
555
+ return secretName(vaultId, credentialId);
556
+ }
557
+ function secretName(vaultId, credentialId) {
558
+ return `${VAULT_SECRET_PREFIX}${vaultId}/${credentialId}`;
559
+ }
560
+ function selectListArgs(workspaceId, limit, page) {
561
+ return page === undefined ? [workspaceId, limit] : [workspaceId, page, limit];
562
+ }
563
+ function selectCredentialListArgs(workspaceId, vaultId, limit, page) {
564
+ return page === undefined
565
+ ? [workspaceId, vaultId, limit]
566
+ : [workspaceId, vaultId, page, limit];
567
+ }
568
+ function normalizeLimit(limit) {
569
+ if (limit === undefined)
570
+ return 20;
571
+ if (!Number.isSafeInteger(limit) || limit <= 0)
572
+ return 20;
573
+ return Math.min(limit, 100);
574
+ }
575
+ function deserializeVault(row) {
576
+ return {
577
+ id: row.id,
578
+ workspace_id: row.workspace_id,
579
+ type: "vault",
580
+ display_name: row.display_name,
581
+ metadata: JSON.parse(row.metadata),
582
+ created_at: row.created_at,
583
+ updated_at: row.updated_at,
584
+ archived_at: row.archived_at,
585
+ };
586
+ }
587
+ function deserializeCredential(row) {
588
+ const auth = deserializeCredentialAuth(row);
589
+ return {
590
+ id: row.id,
591
+ workspace_id: row.workspace_id,
592
+ vault_id: row.vault_id,
593
+ type: "vault_credential",
594
+ display_name: row.display_name,
595
+ metadata: JSON.parse(row.metadata),
596
+ auth,
597
+ auth_version: row.auth_version,
598
+ created_at: row.created_at,
599
+ updated_at: row.updated_at,
600
+ archived_at: row.archived_at,
601
+ };
602
+ }
603
+ function deserializeCredentialAuth(row) {
604
+ if (row.auth_type === "static_bearer") {
605
+ return {
606
+ type: "static_bearer",
607
+ mcp_server_url: row.mcp_server_url,
608
+ };
609
+ }
610
+ return {
611
+ type: "mcp_oauth",
612
+ mcp_server_url: row.mcp_server_url,
613
+ ...(row.expires_at === null ? {} : { expires_at: row.expires_at }),
614
+ ...(row.token_endpoint === null ||
615
+ row.client_id === null ||
616
+ row.token_endpoint_auth_type === null
617
+ ? {}
618
+ : {
619
+ refresh: {
620
+ token_endpoint: row.token_endpoint,
621
+ client_id: row.client_id,
622
+ ...(row.scope === null ? {} : { scope: row.scope }),
623
+ token_endpoint_auth: { type: row.token_endpoint_auth_type },
624
+ },
625
+ }),
626
+ };
627
+ }
628
+ function runtimeMetadata(row) {
629
+ return {
630
+ vaultId: row.vault_id,
631
+ credentialId: row.id,
632
+ authType: row.auth_type,
633
+ hasRefresh: row.auth_type === "mcp_oauth" &&
634
+ row.token_endpoint !== null &&
635
+ row.client_id !== null &&
636
+ row.token_endpoint_auth_type !== null,
637
+ authVersion: row.auth_version,
638
+ ...(row.expires_at === null ? {} : { expiresAt: row.expires_at }),
639
+ refreshStatus: row.refresh_status,
640
+ authHintAt: row.auth_hint_at,
641
+ nextRefreshAt: row.next_refresh_at,
642
+ refreshAttempts: row.refresh_attempts,
643
+ };
644
+ }
645
+ function adminCredentialMetadata(row) {
646
+ return {
647
+ ...runtimeMetadata(row),
648
+ vaultDisplayName: row.vault_display_name,
649
+ vaultArchivedAt: row.vault_archived_at,
650
+ credentialDisplayName: row.credential_display_name,
651
+ credentialArchivedAt: row.credential_archived_at,
652
+ mcpServerUrl: row.mcp_server_url,
653
+ };
654
+ }
655
+ function ensureVaultCredentialColumns(db) {
656
+ const columns = db.prepare("PRAGMA table_info(vault_credentials)").all();
657
+ const names = new Set(columns.map((column) => column.name));
658
+ for (const [name, definition] of [
659
+ ["token_endpoint", "TEXT"],
660
+ ["client_id", "TEXT"],
661
+ ["scope", "TEXT"],
662
+ ["token_endpoint_auth_type", "TEXT"],
663
+ ["expires_at", "TEXT"],
664
+ ["auth_version", "INTEGER NOT NULL DEFAULT 1"],
665
+ ["refresh_status", "TEXT"],
666
+ ["refresh_attempts", "INTEGER NOT NULL DEFAULT 0"],
667
+ ["next_refresh_at", "TEXT"],
668
+ ["auth_hint_at", "TEXT"],
669
+ ]) {
670
+ if (!names.has(name)) {
671
+ db.exec(`ALTER TABLE vault_credentials ADD COLUMN ${name} ${definition}`);
672
+ }
673
+ }
674
+ }
675
+ function oauthAccessToken(value) {
676
+ const parsed = parseOauthSecret(value);
677
+ return typeof parsed.access_token === "string" && parsed.access_token.length > 0
678
+ ? parsed.access_token
679
+ : undefined;
680
+ }
681
+ function parseOauthSecret(value) {
682
+ try {
683
+ const parsed = JSON.parse(value);
684
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
685
+ ? parsed
686
+ : {};
687
+ }
688
+ catch {
689
+ return {};
690
+ }
691
+ }
@@ -0,0 +1 @@
1
+ export {};