@opengeni/contracts 0.44.1 → 1.0.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 (382) hide show
  1. package/dist/agent-authored-durable-text.d.ts +70 -0
  2. package/dist/agent-config.d.ts +869 -0
  3. package/dist/agent-instruction-changes.d.ts +110 -0
  4. package/dist/agent-learning.d.ts +243 -0
  5. package/dist/agent-topology.d.ts +292 -0
  6. package/dist/allowance-refusal.d.ts +9 -0
  7. package/dist/allowance-refusal.js +50 -0
  8. package/dist/allowance-refusal.js.map +1 -0
  9. package/dist/analytics-consent-report.d.ts +19 -0
  10. package/dist/analytics-consent-report.js +10 -0
  11. package/dist/analytics-consent-report.js.map +1 -0
  12. package/dist/api-key-presets.d.ts +19 -0
  13. package/dist/artifact-catalog.d.ts +161 -0
  14. package/dist/artifacts.d.ts +135 -11
  15. package/dist/atlassian-native-retirement.d.ts +16 -0
  16. package/dist/atlassian-native-retirement.js +30 -0
  17. package/dist/atlassian-native-retirement.js.map +1 -0
  18. package/dist/atlassian.d.ts +2 -0
  19. package/dist/atlassian.js +27 -11
  20. package/dist/browser-storage.d.ts +5 -0
  21. package/dist/browser-storage.js +9 -0
  22. package/dist/browser-storage.js.map +1 -0
  23. package/dist/bundled-skills.d.ts +40 -0
  24. package/dist/canonical-human-identities.d.ts +157 -0
  25. package/dist/canonical-human-identities.js +23 -0
  26. package/dist/canonical-human-identities.js.map +1 -0
  27. package/dist/chunk-2ACYHZFB.js +292 -0
  28. package/dist/chunk-2ACYHZFB.js.map +1 -0
  29. package/dist/chunk-2VORLN2R.js +353 -0
  30. package/dist/chunk-2VORLN2R.js.map +1 -0
  31. package/dist/{chunk-Y3MLSLB4.js → chunk-3SIZGL3O.js} +42 -30
  32. package/dist/chunk-3SIZGL3O.js.map +1 -0
  33. package/dist/chunk-46KLD2UH.js +186 -0
  34. package/dist/chunk-46KLD2UH.js.map +1 -0
  35. package/dist/chunk-4JGHSSB7.js +11 -0
  36. package/dist/chunk-4JGHSSB7.js.map +1 -0
  37. package/dist/{chunk-52SGB2QO.js → chunk-5IXYF6XN.js} +50 -10
  38. package/dist/chunk-5IXYF6XN.js.map +1 -0
  39. package/dist/chunk-BCS7WHCK.js +139 -0
  40. package/dist/chunk-BCS7WHCK.js.map +1 -0
  41. package/dist/chunk-EK7NDGFR.js +128 -0
  42. package/dist/chunk-EK7NDGFR.js.map +1 -0
  43. package/dist/{chunk-5UDNP7AO.js → chunk-FZ6BXQHL.js} +78 -38
  44. package/dist/chunk-FZ6BXQHL.js.map +1 -0
  45. package/dist/chunk-GRG7PHWQ.js +25 -0
  46. package/dist/chunk-GRG7PHWQ.js.map +1 -0
  47. package/dist/chunk-JUFK3T4Q.js +80 -0
  48. package/dist/chunk-JUFK3T4Q.js.map +1 -0
  49. package/dist/chunk-KHHZTBP7.js +11 -0
  50. package/dist/chunk-KHHZTBP7.js.map +1 -0
  51. package/dist/chunk-KR2V42UZ.js +187 -0
  52. package/dist/chunk-KR2V42UZ.js.map +1 -0
  53. package/dist/chunk-MZLBPKFE.js +168 -0
  54. package/dist/chunk-MZLBPKFE.js.map +1 -0
  55. package/dist/{chunk-H5BVCZKF.js → chunk-NRMCVHAU.js} +6 -5
  56. package/dist/chunk-NRMCVHAU.js.map +1 -0
  57. package/dist/{chunk-TZ6YEYN4.js → chunk-NVJMJWLL.js} +3 -1
  58. package/dist/chunk-NVJMJWLL.js.map +1 -0
  59. package/dist/chunk-O77VSFYZ.js +70 -0
  60. package/dist/chunk-O77VSFYZ.js.map +1 -0
  61. package/dist/chunk-PX3VCKAU.js +29 -0
  62. package/dist/chunk-PX3VCKAU.js.map +1 -0
  63. package/dist/chunk-QR5D2IQC.js +61 -0
  64. package/dist/chunk-QR5D2IQC.js.map +1 -0
  65. package/dist/chunk-RJ76DRPO.js +117 -0
  66. package/dist/chunk-RJ76DRPO.js.map +1 -0
  67. package/dist/chunk-RKX3NQYS.js +28 -0
  68. package/dist/chunk-RKX3NQYS.js.map +1 -0
  69. package/dist/{chunk-FJBG5E4O.js → chunk-SIOU2K4U.js} +45 -22
  70. package/dist/chunk-SIOU2K4U.js.map +1 -0
  71. package/dist/chunk-TSCDAGET.js +75 -0
  72. package/dist/chunk-TSCDAGET.js.map +1 -0
  73. package/dist/{chunk-LSB7GRLG.js → chunk-TXTQIYCV.js} +15 -11
  74. package/dist/chunk-TXTQIYCV.js.map +1 -0
  75. package/dist/chunk-X7ETVO4P.js +26544 -0
  76. package/dist/chunk-X7ETVO4P.js.map +1 -0
  77. package/dist/{chunk-CADSX6UN.js → chunk-Y3KNXVTD.js} +2 -2
  78. package/dist/chunk-YBW5JSA3.js +251 -0
  79. package/dist/chunk-YBW5JSA3.js.map +1 -0
  80. package/dist/chunk-YRXAWWCU.js +45 -0
  81. package/dist/chunk-YRXAWWCU.js.map +1 -0
  82. package/dist/claude-provider-account-authority.d.ts +18 -0
  83. package/dist/claude-subscription-oauth.d.ts +42 -0
  84. package/dist/claude-subscription-usage.d.ts +159 -0
  85. package/dist/client-error-report.d.ts +109 -0
  86. package/dist/client-error-report.js +87 -0
  87. package/dist/client-error-report.js.map +1 -0
  88. package/dist/code-search.d.ts +52 -0
  89. package/dist/code-search.js +40 -0
  90. package/dist/code-search.js.map +1 -0
  91. package/dist/codex-provider-account-authority.d.ts +23 -0
  92. package/dist/codex-provider-account-authority.js +23 -0
  93. package/dist/codex-provider-account-authority.js.map +1 -0
  94. package/dist/company-brain-governed-writes.d.ts +475 -0
  95. package/dist/company-brain.d.ts +336 -0
  96. package/dist/company-profile.d.ts +566 -0
  97. package/dist/connect.d.ts +325 -0
  98. package/dist/connect.js +191 -0
  99. package/dist/connect.js.map +1 -0
  100. package/dist/connection-account-label.d.ts +2 -0
  101. package/dist/connection-account-label.js +35 -0
  102. package/dist/connection-account-label.js.map +1 -0
  103. package/dist/connection-authority.d.ts +193 -0
  104. package/dist/connection-authority.js +50 -0
  105. package/dist/connection-authority.js.map +1 -0
  106. package/dist/connector-attachments.d.ts +95 -0
  107. package/dist/connector-attachments.js +51 -0
  108. package/dist/connector-attachments.js.map +1 -0
  109. package/dist/connector-tool-permissions.d.ts +73 -0
  110. package/dist/direct-model-provider.d.ts +36 -0
  111. package/dist/editable-artifact-codec-registry.d.ts +16 -7
  112. package/dist/editable-artifact-codec-registry.js +19 -9
  113. package/dist/editable-artifact-committed-transaction.d.ts +2 -2
  114. package/dist/editable-artifact-committed-transaction.js +2 -2
  115. package/dist/editable-artifact-live.d.ts +11 -12
  116. package/dist/editable-artifact-live.js +110 -45
  117. package/dist/editable-artifact-live.js.map +1 -1
  118. package/dist/editable-artifact-serialized-commit.d.ts +2 -1
  119. package/dist/editable-artifact-serialized-commit.js +8 -7
  120. package/dist/editable-artifact-versions.d.ts +20 -5
  121. package/dist/editable-artifact-versions.js +23 -5
  122. package/dist/editable-artifacts.d.ts +2 -0
  123. package/dist/editable-artifacts.js +48 -36
  124. package/dist/external-identities.d.ts +784 -0
  125. package/dist/external-identities.js +44 -0
  126. package/dist/external-identities.js.map +1 -0
  127. package/dist/feedback.d.ts +51 -0
  128. package/dist/github-repository-contracts.d.ts +36 -0
  129. package/dist/github-repository-contracts.js +59 -0
  130. package/dist/github-repository-contracts.js.map +1 -0
  131. package/dist/github-repository.d.ts +14 -0
  132. package/dist/github-repository.js +36 -0
  133. package/dist/github-repository.js.map +1 -0
  134. package/dist/google-drive.d.ts +90 -1
  135. package/dist/google-drive.js +91 -15
  136. package/dist/google-drive.js.map +1 -1
  137. package/dist/governed-learning-activation.d.ts +154 -0
  138. package/dist/governed-learning-evaluator.d.ts +152 -0
  139. package/dist/host-mcp-bindings.d.ts +326 -0
  140. package/dist/host-mcp-bindings.js +252 -0
  141. package/dist/host-mcp-bindings.js.map +1 -0
  142. package/dist/image-generation.d.ts +1 -0
  143. package/dist/index.d.ts +27574 -5374
  144. package/dist/index.js +2531 -177
  145. package/dist/insights-usage.d.ts +877 -0
  146. package/dist/insights-usage.js +509 -0
  147. package/dist/insights-usage.js.map +1 -0
  148. package/dist/interaction.d.ts +1752 -13
  149. package/dist/knowledge-entries.d.ts +982 -0
  150. package/dist/knowledge-preparation.d.ts +237 -0
  151. package/dist/knowledge.d.ts +740 -0
  152. package/dist/managed-auth-session-sets.d.ts +241 -0
  153. package/dist/managed-auth-session-sets.js +191 -0
  154. package/dist/managed-auth-session-sets.js.map +1 -0
  155. package/dist/managed-sign-in-methods.d.ts +56 -0
  156. package/dist/managed-sign-in-methods.js +46 -0
  157. package/dist/managed-sign-in-methods.js.map +1 -0
  158. package/dist/mcp-catalog-limits.d.ts +2 -0
  159. package/dist/mcp-endpoint.d.ts +7 -0
  160. package/dist/mcp-endpoint.js +9 -0
  161. package/dist/mcp-endpoint.js.map +1 -0
  162. package/dist/mcp-oauth.d.ts +71 -0
  163. package/dist/modal-native-proof-v2.d.ts +587 -0
  164. package/dist/modal-native-proof-v2.js +37 -0
  165. package/dist/modal-native-proof-v2.js.map +1 -0
  166. package/dist/model-availability.d.ts +15 -0
  167. package/dist/model-connection-access.d.ts +24 -0
  168. package/dist/model-context-inspector.d.ts +329 -0
  169. package/dist/model-display.d.ts +38 -0
  170. package/dist/model-display.js +134 -0
  171. package/dist/model-display.js.map +1 -0
  172. package/dist/model-picker-order.d.ts +25 -0
  173. package/dist/model-picker-order.js +42 -0
  174. package/dist/model-picker-order.js.map +1 -0
  175. package/dist/organization-access.d.ts +231 -0
  176. package/dist/organization-access.js +34 -0
  177. package/dist/organization-access.js.map +1 -0
  178. package/dist/organization-integration-policy.d.ts +27 -0
  179. package/dist/organization-membership-lifecycle.d.ts +1022 -0
  180. package/dist/organization-model-usage.d.ts +146 -0
  181. package/dist/organization-model-usage.js +67 -0
  182. package/dist/organization-model-usage.js.map +1 -0
  183. package/dist/organization-recovery.d.ts +337 -0
  184. package/dist/organization-recovery.js +37 -0
  185. package/dist/organization-recovery.js.map +1 -0
  186. package/dist/organization-usage.d.ts +138 -0
  187. package/dist/permissions.d.ts +54 -0
  188. package/dist/personal-github.d.ts +320 -0
  189. package/dist/personal-github.js +222 -0
  190. package/dist/personal-github.js.map +1 -0
  191. package/dist/plugin-discovery.d.ts +35 -0
  192. package/dist/plugin-discovery.js +7 -0
  193. package/dist/plugin-discovery.js.map +1 -0
  194. package/dist/preference-registry.d.ts +44 -1
  195. package/dist/product-analytics.d.ts +113 -0
  196. package/dist/product-lifecycle-facts.d.ts +73 -0
  197. package/dist/remember.d.ts +350 -0
  198. package/dist/retained-output.d.ts +8 -0
  199. package/dist/sandbox-file-artifacts.d.ts +57 -0
  200. package/dist/sandbox-provider-command.d.ts +113 -0
  201. package/dist/sandbox-recovery.d.ts +146 -0
  202. package/dist/sandbox-snapshots.d.ts +39 -0
  203. package/dist/session-final-reply.d.ts +6 -0
  204. package/dist/session-final-reply.js +9 -0
  205. package/dist/session-final-reply.js.map +1 -0
  206. package/dist/session-goal-reports.d.ts +21 -0
  207. package/dist/session-history-import.d.ts +947 -0
  208. package/dist/session-list-entries.d.ts +4 -0
  209. package/dist/session-list-entries.js +51 -0
  210. package/dist/session-list-entries.js.map +1 -0
  211. package/dist/session-mcp-projections.d.ts +215 -0
  212. package/dist/session-message-search.d.ts +68 -0
  213. package/dist/session-titles.d.ts +68 -0
  214. package/dist/session-titles.js +25 -0
  215. package/dist/session-titles.js.map +1 -0
  216. package/dist/session-topology-primitives.d.ts +22 -0
  217. package/dist/signup-attribution.d.ts +39 -0
  218. package/dist/site-request-headers.test.d.ts +1 -0
  219. package/dist/site-session-http.d.ts +11 -0
  220. package/dist/site-session-http.js +11 -0
  221. package/dist/site-session-http.js.map +1 -0
  222. package/dist/skill-catalog-context.d.ts +7 -0
  223. package/dist/skill-files.d.ts +12 -0
  224. package/dist/skill-metadata.d.ts +9 -0
  225. package/dist/skill-use.d.ts +61 -0
  226. package/dist/skills.d.ts +185 -0
  227. package/dist/slack-bot-scopes.d.ts +46 -21
  228. package/dist/slack-bot-scopes.js +14 -3
  229. package/dist/slack-rest-mcp.d.ts +31 -0
  230. package/dist/slack-rest-mcp.js +19 -0
  231. package/dist/slack-rest-mcp.js.map +1 -0
  232. package/dist/slack-task-policy.d.ts +294 -0
  233. package/dist/spreadsheet-artifact-commands.d.ts +2 -3
  234. package/dist/spreadsheet-artifact-commands.js +4 -2
  235. package/dist/spreadsheet-artifact-query.js +3 -2
  236. package/dist/subscription-account-pools.d.ts +292 -0
  237. package/dist/task-notes.d.ts +169 -0
  238. package/dist/tool-catalog.d.ts +286 -0
  239. package/dist/tool-result-spill.d.ts +16 -0
  240. package/dist/usage-allowances.d.ts +285 -0
  241. package/dist/usage-allowances.js +49 -0
  242. package/dist/usage-allowances.js.map +1 -0
  243. package/dist/video-generation.d.ts +51 -0
  244. package/dist/video-generation.js +9 -1
  245. package/dist/work-claims.d.ts +411 -0
  246. package/dist/workspace-instruction-policies.d.ts +94 -0
  247. package/dist/workspace-integration-wire.d.ts +36 -0
  248. package/dist/workspace-integration-wire.js +23 -0
  249. package/dist/workspace-integration-wire.js.map +1 -0
  250. package/dist/workspace-integrations.d.ts +948 -0
  251. package/dist/workspace-learning-administration.d.ts +289 -0
  252. package/dist/workspace-learning-policy.d.ts +1 -1
  253. package/dist/workspace-state.d.ts +85 -416
  254. package/dist/xai-provider-account-authority.d.ts +26 -0
  255. package/dist/xai-provider-account-authority.js +9 -0
  256. package/dist/xai-provider-account-authority.js.map +1 -0
  257. package/package.json +146 -1
  258. package/src/agent-authored-durable-text.ts +116 -0
  259. package/src/agent-config.ts +1527 -0
  260. package/src/agent-instruction-changes.ts +98 -0
  261. package/src/agent-learning.ts +161 -0
  262. package/src/agent-topology.ts +69 -0
  263. package/src/allowance-refusal.ts +81 -0
  264. package/src/analytics-consent-report.ts +20 -0
  265. package/src/api-key-presets.ts +25 -0
  266. package/src/artifact-catalog.ts +60 -0
  267. package/src/artifacts.ts +146 -18
  268. package/src/atlassian-native-retirement.ts +33 -0
  269. package/src/browser-storage.ts +10 -0
  270. package/src/bundled-skills.ts +73 -0
  271. package/src/canonical-human-identities.ts +93 -0
  272. package/src/claude-provider-account-authority.ts +12 -0
  273. package/src/claude-subscription-oauth.ts +62 -0
  274. package/src/claude-subscription-usage.ts +59 -0
  275. package/src/client-error-report.ts +184 -0
  276. package/src/code-search.ts +105 -0
  277. package/src/codex-provider-account-authority.ts +37 -0
  278. package/src/company-brain-governed-writes.ts +356 -0
  279. package/src/company-brain.ts +201 -0
  280. package/src/company-profile.ts +167 -1
  281. package/src/connect.ts +202 -0
  282. package/src/connection-account-label.ts +46 -0
  283. package/src/connection-authority.ts +213 -0
  284. package/src/connector-attachments.ts +327 -0
  285. package/src/connector-tool-permissions.ts +60 -0
  286. package/src/direct-model-provider.ts +98 -0
  287. package/src/editable-artifact-codec-registry.ts +55 -17
  288. package/src/editable-artifact-committed-transaction.ts +44 -31
  289. package/src/editable-artifact-live.ts +123 -57
  290. package/src/editable-artifact-serialized-commit.ts +2 -1
  291. package/src/editable-artifact-versions.ts +26 -5
  292. package/src/editable-artifacts.ts +2 -0
  293. package/src/external-identities.ts +285 -0
  294. package/src/feedback.ts +39 -0
  295. package/src/github-repository-contracts.ts +85 -0
  296. package/src/github-repository.ts +59 -0
  297. package/src/google-drive.ts +76 -4
  298. package/src/governed-learning-activation.ts +191 -0
  299. package/src/governed-learning-evaluator.ts +176 -0
  300. package/src/host-mcp-bindings.ts +298 -0
  301. package/src/image-generation.ts +8 -2
  302. package/src/index.ts +8019 -1799
  303. package/src/insights-usage.ts +679 -0
  304. package/src/interaction.ts +1102 -6
  305. package/src/knowledge-entries.ts +375 -0
  306. package/src/knowledge-preparation.ts +50 -0
  307. package/src/knowledge.ts +335 -0
  308. package/src/managed-auth-session-sets.ts +253 -0
  309. package/src/managed-sign-in-methods.ts +37 -0
  310. package/src/mcp-catalog-limits.ts +2 -0
  311. package/src/mcp-endpoint.ts +30 -0
  312. package/src/mcp-oauth.ts +66 -0
  313. package/src/modal-native-proof-v2.ts +398 -0
  314. package/src/model-availability.ts +22 -0
  315. package/src/model-connection-access.ts +17 -0
  316. package/src/model-context-inspector.ts +139 -0
  317. package/src/model-display.ts +195 -0
  318. package/src/model-picker-order.ts +97 -0
  319. package/src/organization-access.ts +176 -0
  320. package/src/organization-integration-policy.ts +54 -0
  321. package/src/organization-membership-lifecycle.ts +559 -0
  322. package/src/organization-model-usage.ts +72 -0
  323. package/src/organization-recovery.ts +186 -0
  324. package/src/organization-usage.ts +79 -0
  325. package/src/permissions.ts +58 -0
  326. package/src/personal-github.ts +267 -0
  327. package/src/plugin-discovery.ts +33 -0
  328. package/src/preference-registry.ts +20 -1
  329. package/src/product-analytics.ts +253 -0
  330. package/src/product-lifecycle-facts.ts +121 -0
  331. package/src/remember.ts +243 -0
  332. package/src/retained-output.ts +20 -3
  333. package/src/sandbox-file-artifacts.ts +73 -0
  334. package/src/sandbox-provider-command.ts +82 -0
  335. package/src/sandbox-recovery.ts +116 -0
  336. package/src/sandbox-snapshots.ts +142 -0
  337. package/src/session-final-reply.ts +16 -0
  338. package/src/session-goal-reports.ts +55 -0
  339. package/src/session-history-import.ts +159 -0
  340. package/src/session-list-entries.ts +91 -0
  341. package/src/session-mcp-projections.ts +273 -0
  342. package/src/session-message-search.ts +54 -0
  343. package/src/session-titles.ts +467 -0
  344. package/src/session-topology-primitives.ts +21 -0
  345. package/src/signup-attribution.ts +81 -0
  346. package/src/site-request-headers.test.ts +28 -0
  347. package/src/site-session-http.ts +63 -0
  348. package/src/skill-catalog-context.ts +50 -0
  349. package/src/skill-files.ts +52 -0
  350. package/src/skill-metadata.ts +40 -0
  351. package/src/skill-use.ts +77 -0
  352. package/src/skills.ts +136 -0
  353. package/src/slack-bot-scopes.ts +106 -42
  354. package/src/slack-rest-mcp.ts +194 -0
  355. package/src/slack-task-policy.ts +215 -0
  356. package/src/spreadsheet-artifact-commands.ts +12 -13
  357. package/src/subscription-account-pools.ts +44 -0
  358. package/src/task-notes.ts +105 -0
  359. package/src/tool-catalog.ts +155 -0
  360. package/src/tool-result-spill.ts +35 -0
  361. package/src/usage-allowances.ts +187 -0
  362. package/src/video-generation.ts +43 -6
  363. package/src/work-claims.ts +266 -0
  364. package/src/workspace-instruction-policies.ts +31 -0
  365. package/src/workspace-integration-wire.ts +99 -0
  366. package/src/workspace-integrations.ts +640 -0
  367. package/src/workspace-learning-administration.ts +88 -0
  368. package/src/workspace-learning-policy.ts +4 -3
  369. package/src/workspace-state.ts +16 -126
  370. package/src/xai-provider-account-authority.ts +38 -0
  371. package/dist/chunk-52SGB2QO.js.map +0 -1
  372. package/dist/chunk-5UDNP7AO.js.map +0 -1
  373. package/dist/chunk-BVGIYW7D.js +0 -11
  374. package/dist/chunk-BVGIYW7D.js.map +0 -1
  375. package/dist/chunk-FJBG5E4O.js.map +0 -1
  376. package/dist/chunk-H5BVCZKF.js.map +0 -1
  377. package/dist/chunk-LSB7GRLG.js.map +0 -1
  378. package/dist/chunk-TZ6YEYN4.js.map +0 -1
  379. package/dist/chunk-VA22KRHS.js +0 -15177
  380. package/dist/chunk-VA22KRHS.js.map +0 -1
  381. package/dist/chunk-Y3MLSLB4.js.map +0 -1
  382. /package/dist/{chunk-CADSX6UN.js.map → chunk-Y3KNXVTD.js.map} +0 -0
@@ -0,0 +1,213 @@
1
+ import { z } from "zod";
2
+ import { ConnectionKind, SessionTenancyVisibility } from "./index";
3
+
4
+ export const ConnectionAuthoritySelectionSource = z.enum(["explicit_workspace", "sender"]);
5
+ export type ConnectionAuthoritySelectionSource = z.infer<typeof ConnectionAuthoritySelectionSource>;
6
+
7
+ export const ConnectionUseSelectionSource = z
8
+ .string()
9
+ .min(1)
10
+ .max(128)
11
+ .regex(/^[a-z0-9](?:[a-z0-9._:-]*[a-z0-9])?$/u);
12
+ export type ConnectionUseSelectionSource = z.infer<typeof ConnectionUseSelectionSource>;
13
+
14
+ const AcceptedConnectionWork = z.discriminatedUnion("kind", [
15
+ z
16
+ .object({
17
+ kind: z.literal("turn"),
18
+ turnId: z.string().uuid(),
19
+ })
20
+ .strict(),
21
+ z
22
+ .object({
23
+ kind: z.literal("scheduled_task"),
24
+ taskId: z.string().uuid(),
25
+ taskAuthorityRevision: z.number().int().positive(),
26
+ runId: z.string().uuid(),
27
+ })
28
+ .strict(),
29
+ ]);
30
+
31
+ /**
32
+ * Internal, credential-free authority frozen when work is accepted. Personal
33
+ * owner identity is retained only for live authorization and usage/audit
34
+ * attribution; it is never part of the public delegation envelope.
35
+ */
36
+ export const ConnectionUseAuthoritySnapshot = z
37
+ .object({
38
+ organizationId: z.string().uuid(),
39
+ originWorkspaceId: z.string().uuid(),
40
+ targetWorkspaceId: z.string().uuid(),
41
+ targetSessionId: z.string().uuid(),
42
+ targetSessionVisibility: SessionTenancyVisibility,
43
+ targetSessionAuthorityEpoch: z.number().int().positive(),
44
+ acceptedWork: AcceptedConnectionWork,
45
+ connectionId: z.string().uuid(),
46
+ connectionGeneration: z.number().int().positive(),
47
+ connectionStatus: z.literal("active"),
48
+ providerDomain: z.string().min(1).max(2048),
49
+ connectionKind: ConnectionKind,
50
+ scope: z.enum(["workspace", "user"]),
51
+ ownerSubjectId: z.string().min(1).max(512).nullable(),
52
+ ownerOrganizationMembershipId: z.string().uuid().nullable(),
53
+ ownerMembershipAuthorizationRevision: z.number().int().positive().nullable().default(null),
54
+ authoritySource: ConnectionAuthoritySelectionSource,
55
+ selectionSources: z.array(ConnectionUseSelectionSource).min(1).max(128),
56
+ userDelegation: z.null(),
57
+ })
58
+ .strict()
59
+ .superRefine((value, context) => {
60
+ const ownedBySubject = value.scope !== "workspace";
61
+ const delegated = value.scope === "user";
62
+ if (ownedBySubject !== (value.ownerSubjectId !== null)) {
63
+ context.addIssue({
64
+ code: "custom",
65
+ path: ["ownerSubjectId"],
66
+ message: "personal connections retain an owner subject",
67
+ });
68
+ }
69
+ if (delegated !== (value.ownerOrganizationMembershipId !== null)) {
70
+ context.addIssue({
71
+ code: "custom",
72
+ path: ["ownerOrganizationMembershipId"],
73
+ message: "only user connections retain an owner membership",
74
+ });
75
+ }
76
+ if (delegated !== (value.ownerMembershipAuthorizationRevision !== null)) {
77
+ context.addIssue({
78
+ code: "custom",
79
+ path: ["ownerMembershipAuthorizationRevision"],
80
+ message: "only user connections retain an owner membership revision",
81
+ });
82
+ }
83
+ if (delegated && value.authoritySource !== "sender") {
84
+ context.addIssue({
85
+ code: "custom",
86
+ path: ["authoritySource"],
87
+ message: "user connections require authenticated sender provenance",
88
+ });
89
+ }
90
+ if (!delegated && value.authoritySource === "sender") {
91
+ context.addIssue({
92
+ code: "custom",
93
+ path: ["authoritySource"],
94
+ message: "workspace connections cannot claim sender provenance",
95
+ });
96
+ }
97
+ if (!delegated && value.originWorkspaceId !== value.targetWorkspaceId) {
98
+ context.addIssue({
99
+ code: "custom",
100
+ path: ["originWorkspaceId"],
101
+ message: "workspace connections must be owned by the target workspace",
102
+ });
103
+ }
104
+ });
105
+ export type ConnectionUseAuthoritySnapshot = z.infer<typeof ConnectionUseAuthoritySnapshot>;
106
+
107
+ export const ConnectionUseDenialReason = z.enum([
108
+ "tenant_mismatch",
109
+ "workspace_access_inactive",
110
+ "session_inactive",
111
+ "session_identity_changed",
112
+ "session_visibility_changed",
113
+ "session_authority_epoch_changed",
114
+ "accepted_attempt_authority_required",
115
+ "accepted_snapshot_digest_changed",
116
+ "connection_missing",
117
+ "connection_identity_changed",
118
+ "connection_generation_changed",
119
+ "connection_status_inactive",
120
+ "connection_owner_changed",
121
+ "owner_membership_inactive",
122
+ "authority_missing",
123
+ "authority_identity_changed",
124
+ "authority_generation_changed",
125
+ "authority_status_inactive",
126
+ "grant_missing",
127
+ "grant_identity_changed",
128
+ "grant_generation_changed",
129
+ "grant_status_inactive",
130
+ "grant_expired",
131
+ "grant_already_consumed",
132
+ ]);
133
+ export type ConnectionUseDenialReason = z.infer<typeof ConnectionUseDenialReason>;
134
+
135
+ const ConnectionUseAttributionFields = z
136
+ .object({
137
+ organizationId: z.string().uuid(),
138
+ workspaceId: z.string().uuid(),
139
+ sessionId: z.string().uuid(),
140
+ connectionId: z.string().uuid(),
141
+ connectionGeneration: z.number().int().positive(),
142
+ scope: z.enum(["workspace", "user", "legacy_user"]),
143
+ ownerSubjectId: z.string().min(1).max(512).nullable(),
144
+ authorityId: z.string().uuid().nullable(),
145
+ grantId: z.string().uuid().nullable(),
146
+ })
147
+ .strict();
148
+
149
+ function refineConnectionUseAttribution(
150
+ value: z.infer<typeof ConnectionUseAttributionFields>,
151
+ context: z.RefinementCtx,
152
+ ): void {
153
+ const personal = value.scope !== "workspace";
154
+ for (const field of ["ownerSubjectId"] as const) {
155
+ if (personal !== (value[field] !== null)) {
156
+ context.addIssue({
157
+ code: "custom",
158
+ path: [field],
159
+ message: personal
160
+ ? `personal attribution requires ${field}`
161
+ : `workspace attribution cannot carry ${field}`,
162
+ });
163
+ }
164
+ }
165
+ const owned = value.scope === "user";
166
+ for (const field of ["authorityId"] as const) {
167
+ if (owned !== (value[field] !== null)) {
168
+ context.addIssue({
169
+ code: "custom",
170
+ path: [field],
171
+ message: owned
172
+ ? `personal attribution requires ${field}`
173
+ : `non-personal attribution cannot carry ${field}`,
174
+ });
175
+ }
176
+ }
177
+ if (!owned && value.grantId !== null) {
178
+ context.addIssue({
179
+ code: "custom",
180
+ path: ["grantId"],
181
+ message: "only historical personal attribution can carry a grant",
182
+ });
183
+ }
184
+ }
185
+
186
+ /** Metadata-only attribution emitted after pre-use authorization. */
187
+ export const ConnectionUseAttribution = ConnectionUseAttributionFields.extend({
188
+ scope: z.enum(["workspace", "user"]),
189
+ grantId: z.null(),
190
+ }).superRefine(refineConnectionUseAttribution);
191
+ export type ConnectionUseAttribution = z.infer<typeof ConnectionUseAttribution>;
192
+
193
+ export const ConnectionUseAuditFact = ConnectionUseAttributionFields.extend({
194
+ outcome: z.enum(["authorized", "denied"]),
195
+ denialReason: ConnectionUseDenialReason.nullable(),
196
+ occurredAt: z.string().datetime({ offset: true }),
197
+ }).superRefine((value, context) => {
198
+ refineConnectionUseAttribution(value, context);
199
+ if ((value.outcome === "denied") !== (value.denialReason !== null)) {
200
+ context.addIssue({
201
+ code: "custom",
202
+ path: ["denialReason"],
203
+ message: "only denied connection use carries a denial reason",
204
+ });
205
+ }
206
+ });
207
+ export type ConnectionUseAuditFact = z.infer<typeof ConnectionUseAuditFact>;
208
+
209
+ export const ConnectionUseAuthorizationResult = z.discriminatedUnion("status", [
210
+ z.object({ status: z.literal("authorized"), attribution: ConnectionUseAttribution }).strict(),
211
+ z.object({ status: z.literal("denied"), reason: ConnectionUseDenialReason }).strict(),
212
+ ]);
213
+ export type ConnectionUseAuthorizationResult = z.infer<typeof ConnectionUseAuthorizationResult>;
@@ -0,0 +1,327 @@
1
+ import { z } from "zod";
2
+
3
+ export const CONNECTOR_ATTACHMENT_TRANSFER_VERSION = 1 as const;
4
+ export const CONNECTOR_ATTACHMENT_RECEIPT_VERSION = 1 as const;
5
+ export const CONNECTOR_ATTACHMENT_TRANSFER_META_KEY =
6
+ "opengeni/connector-attachment-transfers" as const;
7
+ export const CONNECTOR_ATTACHMENT_RECEIPT_META_KEY =
8
+ "opengeni/connector-attachment-receipts" as const;
9
+ export const CONNECTOR_ATTACHMENT_MAX_COUNT = 16;
10
+ // Must remain byte-for-byte aligned with Channel A's exact workspace importer.
11
+ export const CONNECTOR_ATTACHMENT_MAX_BYTES = 5_000_000_000;
12
+ export const CONNECTOR_ATTACHMENT_FILENAME_MAX_UTF8_BYTES = 255;
13
+ export const CONNECTOR_ATTACHMENT_MEDIA_TYPE_MAX_UTF8_BYTES = 256;
14
+ export const CONNECTOR_ATTACHMENT_PROVIDER_MAX_UTF8_BYTES = 128;
15
+ export const CONNECTOR_ATTACHMENT_PROVIDER_ID_MAX_UTF8_BYTES = 512;
16
+ export const CONNECTOR_ATTACHMENT_SOURCE_URL_MAX_UTF8_BYTES = 8 * 1024;
17
+ export const CONNECTOR_ATTACHMENT_SANDBOX_PATH_MAX_UTF8_BYTES = 2 * 1024;
18
+
19
+ const PROVIDER_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/u;
20
+ const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
21
+ const MEDIA_TYPE_PATTERN =
22
+ /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+(?:\s*;\s*[a-z0-9!#$&^_.+-]+=(?:[a-z0-9!#$&^_.+-]+|"[^"\r\n]*"))*$/iu;
23
+ const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
24
+ const HTTP_URL_REFERENCE_PATTERN = /(?:https?:)?\/\/[^\s]/iu;
25
+ const PORTABLE_FILENAME_FORBIDDEN_PATTERN = /[<>:"|?*]/u;
26
+ const PORTABLE_FILENAME_RESERVED_PATTERN = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu;
27
+ const textEncoder = new TextEncoder();
28
+
29
+ function utf8Bytes(value: string): number {
30
+ return textEncoder.encode(value).byteLength;
31
+ }
32
+
33
+ function boundedString(maxUtf8Bytes: number) {
34
+ return z.string().refine((value) => utf8Bytes(value) <= maxUtf8Bytes, {
35
+ message: `must be at most ${maxUtf8Bytes} UTF-8 bytes`,
36
+ });
37
+ }
38
+
39
+ function isHttpUrl(value: string): boolean {
40
+ try {
41
+ const parsed = new URL(value);
42
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ function containsHttpUrlReference(value: string): boolean {
49
+ return HTTP_URL_REFERENCE_PATTERN.test(value);
50
+ }
51
+
52
+ function isPrivateUrlCredentialQueryName(value: string): boolean {
53
+ const normalized = value.toLowerCase().replace(/[^a-z0-9]/gu, "");
54
+ return (
55
+ normalized === "sig" ||
56
+ normalized === "auth" ||
57
+ normalized.endsWith("signature") ||
58
+ normalized.endsWith("token") ||
59
+ normalized.endsWith("credential") ||
60
+ normalized.endsWith("secret") ||
61
+ normalized.endsWith("password") ||
62
+ normalized.endsWith("passcode") ||
63
+ normalized.endsWith("authorization") ||
64
+ normalized.endsWith("apikey") ||
65
+ normalized.endsWith("accesskey") ||
66
+ normalized.endsWith("securitytoken") ||
67
+ normalized.endsWith("sas") ||
68
+ normalized === "googleaccessid"
69
+ );
70
+ }
71
+
72
+ function privateUrlCredentialValues(value: string): string[] {
73
+ let parsed: URL;
74
+ try {
75
+ parsed = new URL(value);
76
+ } catch {
77
+ return [];
78
+ }
79
+ const credentials = new Set<string>();
80
+ for (const [name, credential] of parsed.searchParams) {
81
+ if (credential && isPrivateUrlCredentialQueryName(name)) credentials.add(credential);
82
+ }
83
+ for (const pair of parsed.search.slice(1).split("&")) {
84
+ if (!pair) continue;
85
+ const separator = pair.indexOf("=");
86
+ const rawName = separator === -1 ? pair : pair.slice(0, separator);
87
+ const rawCredential = separator === -1 ? "" : pair.slice(separator + 1);
88
+ let decodedName: string;
89
+ try {
90
+ decodedName = decodeURIComponent(rawName.replace(/\+/gu, " "));
91
+ } catch {
92
+ continue;
93
+ }
94
+ if (rawCredential && isPrivateUrlCredentialQueryName(decodedName)) {
95
+ credentials.add(rawCredential);
96
+ }
97
+ }
98
+ return [...credentials];
99
+ }
100
+
101
+ function publicMetadataContainsCredential(publicValue: string, credential: string): boolean {
102
+ return publicValue.includes(credential);
103
+ }
104
+
105
+ export const ConnectorAttachmentProviderIdentity = z
106
+ .object({
107
+ provider: boundedString(CONNECTOR_ATTACHMENT_PROVIDER_MAX_UTF8_BYTES).regex(PROVIDER_PATTERN),
108
+ kind: z.literal("attachment"),
109
+ value: boundedString(CONNECTOR_ATTACHMENT_PROVIDER_ID_MAX_UTF8_BYTES)
110
+ .min(1)
111
+ .refine((value) => !CONTROL_CHARACTER_PATTERN.test(value), {
112
+ message: "must not contain control characters",
113
+ })
114
+ .refine((value) => !isHttpUrl(value) && !containsHttpUrlReference(value), {
115
+ message: "must be an opaque provider attachment identity, not a URL",
116
+ }),
117
+ })
118
+ .strict();
119
+ export type ConnectorAttachmentProviderIdentity = z.infer<
120
+ typeof ConnectorAttachmentProviderIdentity
121
+ >;
122
+
123
+ export const ConnectorAttachmentFileName = boundedString(
124
+ CONNECTOR_ATTACHMENT_FILENAME_MAX_UTF8_BYTES,
125
+ )
126
+ .min(1)
127
+ .refine(
128
+ (value) =>
129
+ value !== "." &&
130
+ value !== ".." &&
131
+ value === value.trim() &&
132
+ !value.includes("/") &&
133
+ !value.includes("\\") &&
134
+ !CONTROL_CHARACTER_PATTERN.test(value) &&
135
+ !PORTABLE_FILENAME_FORBIDDEN_PATTERN.test(value) &&
136
+ !/[ .]$/u.test(value) &&
137
+ !PORTABLE_FILENAME_RESERVED_PATTERN.test(value),
138
+ { message: "must be a safe leaf filename" },
139
+ );
140
+
141
+ export const ConnectorAttachmentMediaType = boundedString(
142
+ CONNECTOR_ATTACHMENT_MEDIA_TYPE_MAX_UTF8_BYTES,
143
+ )
144
+ .regex(MEDIA_TYPE_PATTERN)
145
+ .refine((value) => !containsHttpUrlReference(value), {
146
+ message: "must not contain an HTTP URL reference",
147
+ });
148
+
149
+ export const ConnectorAttachmentSha256 = z.string().regex(SHA256_PATTERN);
150
+
151
+ export const ConnectorAttachmentPrivateSource = z
152
+ .object({
153
+ url: boundedString(CONNECTOR_ATTACHMENT_SOURCE_URL_MAX_UTF8_BYTES).superRefine(
154
+ (value, context) => {
155
+ let parsed: URL;
156
+ try {
157
+ parsed = new URL(value);
158
+ } catch {
159
+ context.addIssue({
160
+ code: "custom",
161
+ message: "must be an absolute URL",
162
+ });
163
+ return;
164
+ }
165
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
166
+ context.addIssue({ code: "custom", message: "must use http or https" });
167
+ }
168
+ if (parsed.username || parsed.password) {
169
+ context.addIssue({
170
+ code: "custom",
171
+ message: "must not contain URL userinfo",
172
+ });
173
+ }
174
+ if (parsed.hash) {
175
+ context.addIssue({
176
+ code: "custom",
177
+ message: "must not contain a URL fragment",
178
+ });
179
+ }
180
+ },
181
+ ),
182
+ expiresAt: z.iso.datetime({ offset: true }),
183
+ })
184
+ .strict();
185
+ export type ConnectorAttachmentPrivateSource = z.infer<typeof ConnectorAttachmentPrivateSource>;
186
+
187
+ export const ConnectorAttachmentTransfer = z
188
+ .object({
189
+ providerAttachmentId: ConnectorAttachmentProviderIdentity,
190
+ fileName: ConnectorAttachmentFileName,
191
+ mediaType: ConnectorAttachmentMediaType,
192
+ byteSize: z.number().int().min(0).max(CONNECTOR_ATTACHMENT_MAX_BYTES),
193
+ contentSha256: ConnectorAttachmentSha256,
194
+ source: ConnectorAttachmentPrivateSource,
195
+ })
196
+ .strict()
197
+ .superRefine((attachment, context) => {
198
+ const publicValues = [
199
+ attachment.providerAttachmentId.value,
200
+ attachment.fileName,
201
+ attachment.mediaType,
202
+ ];
203
+ for (const credential of privateUrlCredentialValues(attachment.source.url)) {
204
+ if (publicValues.some((value) => publicMetadataContainsCredential(value, credential))) {
205
+ context.addIssue({
206
+ code: "custom",
207
+ message: "private source credentials must not appear in public attachment metadata",
208
+ });
209
+ return;
210
+ }
211
+ }
212
+ });
213
+ export type ConnectorAttachmentTransfer = z.infer<typeof ConnectorAttachmentTransfer>;
214
+
215
+ export const ConnectorAttachmentTransferEnvelope = z
216
+ .object({
217
+ version: z.literal(CONNECTOR_ATTACHMENT_TRANSFER_VERSION),
218
+ attachments: z.array(ConnectorAttachmentTransfer).min(1).max(CONNECTOR_ATTACHMENT_MAX_COUNT),
219
+ })
220
+ .strict()
221
+ .superRefine((envelope, context) => {
222
+ const identities = new Set<string>();
223
+ for (const [index, attachment] of envelope.attachments.entries()) {
224
+ const identity = `${attachment.providerAttachmentId.provider}\0${attachment.providerAttachmentId.value}`;
225
+ if (identities.has(identity)) {
226
+ context.addIssue({
227
+ code: "custom",
228
+ message: "provider attachment identities must be unique",
229
+ path: ["attachments", index, "providerAttachmentId"],
230
+ });
231
+ }
232
+ identities.add(identity);
233
+ }
234
+ });
235
+ export type ConnectorAttachmentTransferEnvelope = z.infer<
236
+ typeof ConnectorAttachmentTransferEnvelope
237
+ >;
238
+
239
+ export const ConnectorAttachmentSandboxPath = boundedString(
240
+ CONNECTOR_ATTACHMENT_SANDBOX_PATH_MAX_UTF8_BYTES,
241
+ )
242
+ .min(1)
243
+ .refine(
244
+ (value) => {
245
+ if (
246
+ value !== value.trim() ||
247
+ value.startsWith("/") ||
248
+ /^[A-Za-z]:[\\/]/u.test(value) ||
249
+ value.includes("\\") ||
250
+ CONTROL_CHARACTER_PATTERN.test(value)
251
+ ) {
252
+ return false;
253
+ }
254
+ const segments = value.split("/");
255
+ if (
256
+ segments.length !== 5 ||
257
+ segments[0] !== ".opengeni" ||
258
+ segments[1] !== "connector-attachments" ||
259
+ !PROVIDER_PATTERN.test(segments[2] ?? "") ||
260
+ !/^[0-9a-f]{32}$/u.test(segments[3] ?? "") ||
261
+ !ConnectorAttachmentFileName.safeParse(segments[4]).success
262
+ ) {
263
+ return false;
264
+ }
265
+ return segments.every(
266
+ (segment) =>
267
+ segment.length > 0 &&
268
+ segment !== "." &&
269
+ segment !== ".." &&
270
+ !PORTABLE_FILENAME_FORBIDDEN_PATTERN.test(segment) &&
271
+ !/[ .]$/u.test(segment) &&
272
+ !PORTABLE_FILENAME_RESERVED_PATTERN.test(segment),
273
+ );
274
+ },
275
+ { message: "must be a confined connector attachment sandbox path" },
276
+ );
277
+
278
+ export const ConnectorAttachmentReceipt = z
279
+ .object({
280
+ providerAttachmentId: ConnectorAttachmentProviderIdentity,
281
+ fileName: ConnectorAttachmentFileName,
282
+ mediaType: ConnectorAttachmentMediaType,
283
+ byteSize: z.number().int().min(0).max(CONNECTOR_ATTACHMENT_MAX_BYTES),
284
+ contentSha256: ConnectorAttachmentSha256,
285
+ sandboxPath: ConnectorAttachmentSandboxPath,
286
+ })
287
+ .strict()
288
+ .superRefine((receipt, context) => {
289
+ const segments = receipt.sandboxPath.split("/");
290
+ if (segments[2] !== receipt.providerAttachmentId.provider) {
291
+ context.addIssue({
292
+ code: "custom",
293
+ message: "sandbox path provider must match the provider attachment identity",
294
+ path: ["sandboxPath"],
295
+ });
296
+ }
297
+ if (segments[4] !== receipt.fileName) {
298
+ context.addIssue({
299
+ code: "custom",
300
+ message: "sandbox path filename must match the attachment filename",
301
+ path: ["sandboxPath"],
302
+ });
303
+ }
304
+ });
305
+ export type ConnectorAttachmentReceipt = z.infer<typeof ConnectorAttachmentReceipt>;
306
+
307
+ export const ConnectorAttachmentReceiptEnvelope = z
308
+ .object({
309
+ version: z.literal(CONNECTOR_ATTACHMENT_RECEIPT_VERSION),
310
+ attachments: z.array(ConnectorAttachmentReceipt).min(1).max(CONNECTOR_ATTACHMENT_MAX_COUNT),
311
+ })
312
+ .strict();
313
+ export type ConnectorAttachmentReceiptEnvelope = z.infer<typeof ConnectorAttachmentReceiptEnvelope>;
314
+
315
+ export function parseConnectorAttachmentTransferEnvelope(
316
+ value: unknown,
317
+ options: { nowMs?: number } = {},
318
+ ): ConnectorAttachmentTransferEnvelope {
319
+ const envelope = ConnectorAttachmentTransferEnvelope.parse(value);
320
+ const nowMs = options.nowMs ?? Date.now();
321
+ for (const attachment of envelope.attachments) {
322
+ if (Date.parse(attachment.source.expiresAt) <= nowMs) {
323
+ throw new Error("connector attachment source is expired");
324
+ }
325
+ }
326
+ return envelope;
327
+ }
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { MCP_MAX_CATALOG_TOOL_ENTRIES } from "./mcp-catalog-limits";
3
+
4
+ export const ConnectorToolPermission = z.enum(["allow", "ask", "block"]);
5
+ export type ConnectorToolPermission = z.infer<typeof ConnectorToolPermission>;
6
+
7
+ export const ConnectorToolPermissionEntry = z.object({
8
+ name: z.string().min(1).max(512),
9
+ title: z.string().optional(),
10
+ description: z.string().optional(),
11
+ group: z.enum(["read", "write", "other"]),
12
+ permission: ConnectorToolPermission,
13
+ inherited: z.boolean(),
14
+ approvalRequired: z.boolean(),
15
+ });
16
+ export type ConnectorToolPermissionEntry = z.infer<typeof ConnectorToolPermissionEntry>;
17
+
18
+ export const ConnectorToolPermissionsResponse = z.object({
19
+ connectionId: z.string(),
20
+ serverId: z.string(),
21
+ defaultPermission: ConnectorToolPermission.nullable(),
22
+ tools: z.array(ConnectorToolPermissionEntry),
23
+ discoveryError: z.string().nullable(),
24
+ canManage: z.boolean(),
25
+ });
26
+ export type ConnectorToolPermissionsResponse = z.infer<typeof ConnectorToolPermissionsResponse>;
27
+
28
+ // Group changes name the currently displayed tools explicitly. MCP annotations
29
+ // organize the UI only; they never grant future tools permission automatically.
30
+ export const UpdateConnectorToolPermissionsRequest = z.discriminatedUnion("target", [
31
+ z
32
+ .object({
33
+ connectionId: z.string().min(1).max(512),
34
+ target: z.literal("default"),
35
+ permission: ConnectorToolPermission,
36
+ })
37
+ .strict(),
38
+ z
39
+ .object({
40
+ connectionId: z.string().min(1).max(512),
41
+ target: z.literal("tools"),
42
+ toolNames: z
43
+ .array(
44
+ z
45
+ .string()
46
+ .min(1)
47
+ .max(512)
48
+ .refine((name) => name !== "*" && name === name.trim(), {
49
+ message: "Tool names must be exact and cannot use the connector-default wildcard.",
50
+ }),
51
+ )
52
+ .min(1)
53
+ .max(MCP_MAX_CATALOG_TOOL_ENTRIES),
54
+ permission: ConnectorToolPermission,
55
+ })
56
+ .strict(),
57
+ ]);
58
+ export type UpdateConnectorToolPermissionsRequest = z.infer<
59
+ typeof UpdateConnectorToolPermissionsRequest
60
+ >;
@@ -0,0 +1,98 @@
1
+ import { z } from "zod";
2
+
3
+ export const DirectModelProvider = z.enum(["openai", "azure_openai"]);
4
+ export type DirectModelProvider = z.infer<typeof DirectModelProvider>;
5
+
6
+ /** Pin customer credentials to official provider origins, never arbitrary URLs. */
7
+ export const AzureOpenAIEndpoint = z
8
+ .string()
9
+ .trim()
10
+ .url()
11
+ .superRefine((value, ctx) => {
12
+ let url: URL;
13
+ try {
14
+ url = new URL(value);
15
+ } catch {
16
+ // The preceding URL validator supplies the normal validation issue.
17
+ return;
18
+ }
19
+ if (
20
+ url.protocol !== "https:" ||
21
+ url.username ||
22
+ url.password ||
23
+ url.port ||
24
+ !/^[a-z0-9-]+\.openai\.azure\.com$/i.test(url.hostname) ||
25
+ !["", "/", "/openai/v1", "/openai/v1/"].includes(url.pathname) ||
26
+ url.search ||
27
+ url.hash
28
+ ) {
29
+ ctx.addIssue({ code: "custom", message: "Enter your Azure OpenAI HTTPS resource endpoint" });
30
+ }
31
+ })
32
+ .transform((value) => new URL(value).origin + "/openai/v1");
33
+
34
+ export const DirectModelProviderMetadata = z
35
+ .object({
36
+ provider: DirectModelProvider,
37
+ model: z
38
+ .string()
39
+ .trim()
40
+ .min(1)
41
+ .max(128)
42
+ .regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/),
43
+ endpoint: AzureOpenAIEndpoint.optional(),
44
+ })
45
+ .strict()
46
+ .superRefine((value, ctx) => {
47
+ if (value.provider === "azure_openai" && !value.endpoint) {
48
+ ctx.addIssue({
49
+ code: "custom",
50
+ path: ["endpoint"],
51
+ message: "Azure OpenAI needs an endpoint",
52
+ });
53
+ }
54
+ if (value.provider === "openai" && value.endpoint) {
55
+ ctx.addIssue({
56
+ code: "custom",
57
+ path: ["endpoint"],
58
+ message: "OpenAI uses its official API endpoint",
59
+ });
60
+ }
61
+ });
62
+ export type DirectModelProviderMetadata = z.infer<typeof DirectModelProviderMetadata>;
63
+
64
+ export function directModelConnectionSpec(connection: {
65
+ id: string;
66
+ version: number;
67
+ subjectId: string | null;
68
+ kind: string;
69
+ status: string;
70
+ providerDomain: string;
71
+ metadata: Record<string, unknown>;
72
+ }) {
73
+ if (
74
+ connection.subjectId !== null ||
75
+ connection.kind !== "api_key" ||
76
+ connection.status !== "active"
77
+ )
78
+ return null;
79
+ const parsed = DirectModelProviderMetadata.safeParse(connection.metadata.directModelProvider);
80
+ if (!parsed.success || connection.metadata.credentialRole !== `direct_${parsed.data.provider}`)
81
+ return null;
82
+ const config = parsed.data;
83
+ const baseUrl = config.provider === "openai" ? "https://api.openai.com/v1" : config.endpoint!;
84
+ if (connection.providerDomain.toLowerCase() !== new URL(baseUrl).hostname) return null;
85
+ const providerId = `workspace-${config.provider === "openai" ? "openai" : "azure-openai"}-${connection.id}`;
86
+ return {
87
+ ...config,
88
+ baseUrl,
89
+ providerId,
90
+ modelId: `${providerId}/${connection.version}/${config.model}`,
91
+ connectionId: connection.id,
92
+ version: connection.version,
93
+ };
94
+ }
95
+
96
+ export function isDirectModelId(modelId: string): boolean {
97
+ return /^workspace-(?:openai|azure-openai)-[0-9a-f-]{36}\//.test(modelId);
98
+ }