@jini-ai/admin 0.3.10 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +71 -37
  3. package/dist/agent-plugins/adapters/http.d.ts +7 -0
  4. package/dist/agent-plugins/adapters/http.js +15 -0
  5. package/dist/agent-plugins/adapters/memory.d.ts +8 -0
  6. package/dist/agent-plugins/adapters/memory.js +25 -0
  7. package/dist/agent-plugins/agent-plugins.module.d.ts +51 -0
  8. package/dist/agent-plugins/agent-plugins.module.js +6 -0
  9. package/dist/agent-plugins/conformance/agent-plugins-api.conformance.d.ts +12 -0
  10. package/dist/agent-plugins/conformance/agent-plugins-api.conformance.js +47 -0
  11. package/dist/agent-plugins/controllers/agent-plugin-files.controller.d.ts +20 -0
  12. package/dist/agent-plugins/controllers/agent-plugin-files.controller.js +43 -0
  13. package/dist/agent-plugins/controllers/agent-plugins.controller.d.ts +25 -0
  14. package/dist/agent-plugins/controllers/agent-plugins.controller.js +91 -0
  15. package/dist/agent-plugins/index.d.ts +9 -0
  16. package/dist/agent-plugins/index.js +9 -0
  17. package/dist/agent-plugins/messages.en.d.ts +23 -0
  18. package/dist/agent-plugins/messages.en.js +14 -0
  19. package/dist/agent-plugins/models.d.ts +57 -0
  20. package/dist/agent-plugins/models.js +2 -0
  21. package/dist/agent-plugins/package-file-tree.d.ts +111 -0
  22. package/dist/agent-plugins/package-file-tree.js +188 -0
  23. package/dist/agent-plugins/ports.d.ts +18 -0
  24. package/dist/agent-plugins/ports.js +3 -0
  25. package/dist/agent-plugins/react/components/AgentPluginFileContent.d.ts +5 -0
  26. package/dist/agent-plugins/react/components/AgentPluginFileContent.js +9 -0
  27. package/dist/agent-plugins/react/components/AgentPluginFileTree.d.ts +9 -0
  28. package/dist/agent-plugins/react/components/AgentPluginFileTree.js +7 -0
  29. package/dist/agent-plugins/react/components/AgentPluginInspector.d.ts +3 -0
  30. package/dist/agent-plugins/react/components/AgentPluginInspector.js +11 -0
  31. package/dist/agent-plugins/react/components/AgentPluginListPanel.d.ts +6 -0
  32. package/dist/agent-plugins/react/components/AgentPluginListPanel.js +10 -0
  33. package/dist/agent-plugins/react/components/AgentPluginRow.d.ts +5 -0
  34. package/dist/agent-plugins/react/components/AgentPluginRow.js +8 -0
  35. package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.d.ts +90 -0
  36. package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +74 -0
  37. package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +67 -0
  38. package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.js +50 -0
  39. package/dist/agent-plugins/react/hooks/AgentPluginRow.hooks.d.ts +55 -0
  40. package/dist/agent-plugins/react/hooks/AgentPluginRow.hooks.js +6 -0
  41. package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +64 -0
  42. package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +39 -0
  43. package/dist/agent-plugins/react/hooks/AgentPluginsPorts.hooks.d.ts +7 -0
  44. package/dist/agent-plugins/react/hooks/AgentPluginsPorts.hooks.js +10 -0
  45. package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.d.ts +6 -0
  46. package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.js +3 -0
  47. package/dist/agent-plugins/react/index.d.ts +245 -0
  48. package/dist/agent-plugins/react/index.js +13 -0
  49. package/dist/agent-plugins/react/pages/AgentPluginsPage.d.ts +4 -0
  50. package/dist/agent-plugins/react/pages/AgentPluginsPage.js +12 -0
  51. package/dist/agent-plugins/react/tabs/DownloadedTab.d.ts +4 -0
  52. package/dist/agent-plugins/react/tabs/DownloadedTab.js +5 -0
  53. package/dist/agent-plugins/react/tabs/InstalledTab.d.ts +4 -0
  54. package/dist/agent-plugins/react/tabs/InstalledTab.js +5 -0
  55. package/dist/agent-plugins/react/tabs/MarketplaceTab.d.ts +4 -0
  56. package/dist/agent-plugins/react/tabs/MarketplaceTab.js +10 -0
  57. package/dist/agent-plugins/rules.d.ts +33 -0
  58. package/dist/agent-plugins/rules.js +51 -0
  59. package/dist/browser/index.d.ts +1 -0
  60. package/dist/browser/index.js +1 -0
  61. package/dist/browser/navigation.d.ts +19 -4
  62. package/dist/browser/navigation.js +8 -8
  63. package/dist/browser/shell-navigation.d.ts +12 -0
  64. package/dist/browser/shell-navigation.js +16 -0
  65. package/dist/contracts/credential-management.d.ts +8 -0
  66. package/dist/contracts/credential-management.js +3 -0
  67. package/dist/contracts/media-picker.d.ts +17 -0
  68. package/dist/contracts/media-picker.js +5 -0
  69. package/dist/contracts/playground-render-target.d.ts +18 -0
  70. package/dist/contracts/playground-render-target.js +3 -0
  71. package/dist/core/entities/rules.d.ts +138 -0
  72. package/dist/core/entities/rules.js +344 -0
  73. package/dist/core/gated/types.d.ts +8 -4
  74. package/dist/core/index.d.ts +4 -0
  75. package/dist/core/index.js +1 -0
  76. package/dist/core/manifest/rules.d.ts +24 -6
  77. package/dist/core/manifest/rules.js +12 -11
  78. package/dist/core/module/controller-store.d.ts +22 -0
  79. package/dist/core/module/controller-store.js +32 -0
  80. package/dist/core/module/create-admin.d.ts +41 -0
  81. package/dist/core/module/create-admin.js +187 -0
  82. package/dist/core/module/define-admin-module.d.ts +4 -0
  83. package/dist/core/module/define-admin-module.js +5 -0
  84. package/dist/core/module/index.d.ts +7 -0
  85. package/dist/core/module/index.js +4 -0
  86. package/dist/core/module/token.d.ts +19 -0
  87. package/dist/core/module/token.js +4 -0
  88. package/dist/core/module/types.d.ts +79 -0
  89. package/dist/core/module/types.js +2 -0
  90. package/dist/core/permissions/rules.d.ts +4 -1
  91. package/dist/core/permissions/rules.js +1 -1
  92. package/dist/core/ports/analytics.d.ts +1 -1
  93. package/dist/core/ports/auth.d.ts +2 -2
  94. package/dist/core/ports/comments.d.ts +9 -6
  95. package/dist/core/ports/database.d.ts +13 -10
  96. package/dist/core/ports/entities.d.ts +302 -0
  97. package/dist/core/ports/entities.js +47 -0
  98. package/dist/core/ports/forms.d.ts +19 -7
  99. package/dist/core/ports/identity.d.ts +42 -17
  100. package/dist/core/ports/index.d.ts +2 -0
  101. package/dist/core/ports/integrations.d.ts +9 -4
  102. package/dist/core/ports/media.d.ts +16 -7
  103. package/dist/core/ports/members.d.ts +7 -3
  104. package/dist/core/ports/menus.d.ts +46 -0
  105. package/dist/core/ports/menus.js +43 -0
  106. package/dist/core/ports/plugins.d.ts +3 -2
  107. package/dist/core/ports/recovery.d.ts +10 -6
  108. package/dist/core/ports/redirects.d.ts +17 -7
  109. package/dist/core/ports/seo.d.ts +12 -6
  110. package/dist/core/ports/shell.d.ts +41 -0
  111. package/dist/core/ports/shell.js +2 -0
  112. package/dist/core/ports/workspace.d.ts +3 -3
  113. package/dist/core/routing/rules.d.ts +17 -4
  114. package/dist/core/routing/rules.js +4 -4
  115. package/dist/core/transport/errors.d.ts +13 -4
  116. package/dist/core/transport/errors.js +4 -4
  117. package/dist/core/transport/http.d.ts +26 -16
  118. package/dist/core/transport/http.js +59 -21
  119. package/dist/core/transport/types.d.ts +26 -14
  120. package/dist/core/transport/types.js +9 -7
  121. package/dist/media/adapters/http.d.ts +27 -0
  122. package/dist/media/adapters/http.js +44 -0
  123. package/dist/media/adapters/memory.d.ts +11 -0
  124. package/dist/media/adapters/memory.js +139 -0
  125. package/dist/media/conformance/media-api.conformance.d.ts +7 -0
  126. package/dist/media/conformance/media-api.conformance.js +69 -0
  127. package/dist/media/controllers/edit-media.controller.d.ts +24 -0
  128. package/dist/media/controllers/edit-media.controller.js +69 -0
  129. package/dist/media/controllers/library.controller.d.ts +47 -0
  130. package/dist/media/controllers/library.controller.js +173 -0
  131. package/dist/media/controllers/providers.controller.d.ts +30 -0
  132. package/dist/media/controllers/providers.controller.js +76 -0
  133. package/dist/media/html-attributes.d.ts +82 -0
  134. package/dist/media/html-attributes.js +204 -0
  135. package/dist/media/index.d.ts +12 -0
  136. package/dist/media/index.js +9 -0
  137. package/dist/media/media.module.d.ts +83 -0
  138. package/dist/media/media.module.js +43 -0
  139. package/dist/media/messages.en.d.ts +24 -0
  140. package/dist/media/messages.en.js +24 -0
  141. package/dist/media/models.d.ts +72 -0
  142. package/dist/media/models.js +2 -0
  143. package/dist/media/ports.d.ts +75 -0
  144. package/dist/media/ports.js +7 -0
  145. package/dist/media/react/components/EditMediaPanel.d.ts +3 -0
  146. package/dist/media/react/components/EditMediaPanel.js +10 -0
  147. package/dist/media/react/components/MediaCard.d.ts +5 -0
  148. package/dist/media/react/components/MediaCard.js +17 -0
  149. package/dist/media/react/components/MediaDialog.d.ts +3 -0
  150. package/dist/media/react/components/MediaDialog.js +8 -0
  151. package/dist/media/react/components/MediaGrid.d.ts +4 -0
  152. package/dist/media/react/components/MediaGrid.js +8 -0
  153. package/dist/media/react/components/MediaIcons.d.ts +14 -0
  154. package/dist/media/react/components/MediaIcons.js +39 -0
  155. package/dist/media/react/components/MediaLightbox.d.ts +5 -0
  156. package/dist/media/react/components/MediaLightbox.js +12 -0
  157. package/dist/media/react/components/MediaPicker.d.ts +3 -0
  158. package/dist/media/react/components/MediaPicker.js +10 -0
  159. package/dist/media/react/components/MediaPurgeDialog.d.ts +4 -0
  160. package/dist/media/react/components/MediaPurgeDialog.js +9 -0
  161. package/dist/media/react/components/UploadButton.d.ts +3 -0
  162. package/dist/media/react/components/UploadButton.js +8 -0
  163. package/dist/media/react/hooks/EditMediaPanel.hooks.d.ts +84 -0
  164. package/dist/media/react/hooks/EditMediaPanel.hooks.js +105 -0
  165. package/dist/media/react/hooks/LibraryTab.hooks.d.ts +103 -0
  166. package/dist/media/react/hooks/LibraryTab.hooks.js +164 -0
  167. package/dist/media/react/hooks/MediaCard.hooks.d.ts +83 -0
  168. package/dist/media/react/hooks/MediaCard.hooks.js +66 -0
  169. package/dist/media/react/hooks/MediaDialog.hooks.d.ts +10 -0
  170. package/dist/media/react/hooks/MediaDialog.hooks.js +20 -0
  171. package/dist/media/react/hooks/MediaGrid.hooks.d.ts +29 -0
  172. package/dist/media/react/hooks/MediaGrid.hooks.js +6 -0
  173. package/dist/media/react/hooks/MediaLightbox.hooks.d.ts +27 -0
  174. package/dist/media/react/hooks/MediaLightbox.hooks.js +64 -0
  175. package/dist/media/react/hooks/MediaPage.hooks.d.ts +68 -0
  176. package/dist/media/react/hooks/MediaPage.hooks.js +68 -0
  177. package/dist/media/react/hooks/MediaPicker.hooks.d.ts +26 -0
  178. package/dist/media/react/hooks/MediaPicker.hooks.js +25 -0
  179. package/dist/media/react/hooks/MediaPorts.hooks.d.ts +9 -0
  180. package/dist/media/react/hooks/MediaPorts.hooks.js +10 -0
  181. package/dist/media/react/hooks/MediaPurgeDialog.hooks.d.ts +22 -0
  182. package/dist/media/react/hooks/MediaPurgeDialog.hooks.js +6 -0
  183. package/dist/media/react/hooks/ProvidersTab.hooks.d.ts +55 -0
  184. package/dist/media/react/hooks/ProvidersTab.hooks.js +124 -0
  185. package/dist/media/react/hooks/UploadButton.hooks.d.ts +48 -0
  186. package/dist/media/react/hooks/UploadButton.hooks.js +118 -0
  187. package/dist/media/react/index.d.ts +373 -0
  188. package/dist/media/react/index.js +73 -0
  189. package/dist/media/react/pages/MediaPage.d.ts +4 -0
  190. package/dist/media/react/pages/MediaPage.js +9 -0
  191. package/dist/media/react/tabs/LibraryTab.d.ts +4 -0
  192. package/dist/media/react/tabs/LibraryTab.js +14 -0
  193. package/dist/media/react/tabs/ProvidersTab.d.ts +4 -0
  194. package/dist/media/react/tabs/ProvidersTab.js +10 -0
  195. package/dist/media/rules.d.ts +86 -0
  196. package/dist/media/rules.js +134 -0
  197. package/dist/media/styles.d.ts +4 -0
  198. package/dist/media/styles.js +5 -0
  199. package/dist/playground/adapters/http.d.ts +8 -0
  200. package/dist/playground/adapters/http.js +4 -0
  201. package/dist/playground/adapters/memory.d.ts +10 -0
  202. package/dist/playground/adapters/memory.js +30 -0
  203. package/dist/playground/conformance/playground-api.conformance.d.ts +6 -0
  204. package/dist/playground/conformance/playground-api.conformance.js +37 -0
  205. package/dist/playground/controllers/playground.controller.d.ts +16 -0
  206. package/dist/playground/controllers/playground.controller.js +21 -0
  207. package/dist/playground/index.d.ts +7 -0
  208. package/dist/playground/index.js +5 -0
  209. package/dist/playground/messages.en.d.ts +9 -0
  210. package/dist/playground/messages.en.js +2 -0
  211. package/dist/playground/models.d.ts +4 -0
  212. package/dist/playground/models.js +2 -0
  213. package/dist/playground/playground.module.d.ts +31 -0
  214. package/dist/playground/playground.module.js +5 -0
  215. package/dist/playground/ports.d.ts +5 -0
  216. package/dist/playground/ports.js +2 -0
  217. package/dist/playground/react/components/Canvas.d.ts +3 -0
  218. package/dist/playground/react/components/Canvas.js +9 -0
  219. package/dist/playground/react/hooks/Canvas.hooks.d.ts +7 -0
  220. package/dist/playground/react/hooks/Canvas.hooks.js +18 -0
  221. package/dist/playground/react/hooks/PlaygroundPage.hooks.d.ts +8 -0
  222. package/dist/playground/react/hooks/PlaygroundPage.hooks.js +2 -0
  223. package/dist/playground/react/hooks/PlaygroundPorts.hooks.d.ts +4 -0
  224. package/dist/playground/react/hooks/PlaygroundPorts.hooks.js +6 -0
  225. package/dist/playground/react/index.d.ts +136 -0
  226. package/dist/playground/react/index.js +10 -0
  227. package/dist/playground/react/pages/PlaygroundPage.d.ts +4 -0
  228. package/dist/playground/react/pages/PlaygroundPage.js +11 -0
  229. package/dist/playground/react/tabs/CanvasTab.d.ts +4 -0
  230. package/dist/playground/react/tabs/CanvasTab.js +5 -0
  231. package/dist/playground/rules.d.ts +4 -0
  232. package/dist/playground/rules.js +2 -0
  233. package/dist/react/OverlayHost.d.ts +3 -0
  234. package/dist/react/OverlayHost.hooks.d.ts +9 -0
  235. package/dist/react/OverlayHost.hooks.js +9 -0
  236. package/dist/react/OverlayHost.js +7 -0
  237. package/dist/react/bind-react.d.ts +46 -0
  238. package/dist/react/bind-react.js +28 -0
  239. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +7 -1
  240. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +2 -2
  241. package/dist/react/components/ConfirmButton/ConfirmButton.js +1 -1
  242. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +17 -3
  243. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +3 -3
  244. package/dist/react/components/ConfirmDialog/ConfirmDialog.js +5 -5
  245. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +6 -2
  246. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +7 -8
  247. package/dist/react/components/RowMenu/RowMenu.d.ts +5 -1
  248. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +8 -2
  249. package/dist/react/components/RowMenu/RowMenu.hooks.js +4 -4
  250. package/dist/react/components/RowMenu/RowMenu.js +6 -6
  251. package/dist/react/components/Sidebar.d.ts +1 -1
  252. package/dist/react/components/Sidebar.js +103 -7
  253. package/dist/react/entities/EntityCell.d.ts +10 -0
  254. package/dist/react/entities/EntityCell.js +18 -0
  255. package/dist/react/entities/EntityDetail.d.ts +3 -0
  256. package/dist/react/entities/EntityDetail.js +21 -0
  257. package/dist/react/entities/EntityEdit.d.ts +13 -0
  258. package/dist/react/entities/EntityEdit.js +45 -0
  259. package/dist/react/entities/EntityField.d.ts +20 -0
  260. package/dist/react/entities/EntityField.js +31 -0
  261. package/dist/react/entities/EntityIndex.d.ts +3 -0
  262. package/dist/react/entities/EntityIndex.js +10 -0
  263. package/dist/react/entities/EntityList.d.ts +7 -0
  264. package/dist/react/entities/EntityList.js +52 -0
  265. package/dist/react/entities/contribution.d.ts +26 -0
  266. package/dist/react/entities/contribution.js +78 -0
  267. package/dist/react/entities/index.d.ts +10 -0
  268. package/dist/react/entities/index.js +7 -0
  269. package/dist/react/entities/rules.d.ts +179 -0
  270. package/dist/react/entities/rules.js +224 -0
  271. package/dist/react/entities/types.d.ts +45 -0
  272. package/dist/react/entities/types.js +5 -0
  273. package/dist/react/entities/use-entity-edit.d.ts +35 -0
  274. package/dist/react/entities/use-entity-edit.js +98 -0
  275. package/dist/react/entities/use-entity-read.d.ts +22 -0
  276. package/dist/react/entities/use-entity-read.js +27 -0
  277. package/dist/react/hooks/use-nav-sections.d.ts +12 -3
  278. package/dist/react/hooks/use-nav-sections.js +14 -14
  279. package/dist/react/hooks/use-sidebar-rail.d.ts +7 -1
  280. package/dist/react/hooks/use-sidebar-rail.js +11 -11
  281. package/dist/react/index.d.ts +3 -1
  282. package/dist/react/index.js +5 -2
  283. package/dist/react/overlays.d.ts +38 -0
  284. package/dist/react/overlays.js +46 -0
  285. package/dist/react/shell/AdminShell.d.ts +9 -0
  286. package/dist/react/shell/AdminShell.hooks.d.ts +15 -0
  287. package/dist/react/shell/AdminShell.hooks.js +27 -0
  288. package/dist/react/shell/AdminShell.js +46 -0
  289. package/dist/react/shell/index.d.ts +7 -0
  290. package/dist/react/shell/index.js +5 -0
  291. package/dist/react/shell/model.d.ts +25 -0
  292. package/dist/react/shell/model.js +29 -0
  293. package/dist/react/shell/theme-ports.d.ts +28 -0
  294. package/dist/react/shell/theme-ports.js +2 -0
  295. package/dist/react/shell/types.d.ts +99 -0
  296. package/dist/react/shell/types.js +2 -0
  297. package/dist/react/shell/use-admin-shell-session.d.ts +13 -0
  298. package/dist/react/shell/use-admin-shell-session.js +81 -0
  299. package/dist/react/shell/use-admin-theme.d.ts +16 -0
  300. package/dist/react/shell/use-admin-theme.js +57 -0
  301. package/dist/react/types.d.ts +6 -4
  302. package/dist/react/types.js +2 -2
  303. package/dist/react/use-controller.d.ts +16 -0
  304. package/dist/react/use-controller.js +18 -0
  305. package/dist/security/adapters/http.d.ts +16 -0
  306. package/dist/security/adapters/http.js +94 -0
  307. package/dist/security/adapters/memory.d.ts +15 -0
  308. package/dist/security/adapters/memory.js +60 -0
  309. package/dist/security/conformance/security-api.conformance.d.ts +10 -0
  310. package/dist/security/conformance/security-api.conformance.js +48 -0
  311. package/dist/security/controllers/access-tokens.controller.d.ts +44 -0
  312. package/dist/security/controllers/access-tokens.controller.js +112 -0
  313. package/dist/security/controllers/other-credentials.controller.d.ts +30 -0
  314. package/dist/security/controllers/other-credentials.controller.js +74 -0
  315. package/dist/security/controllers/root-key.controller.d.ts +35 -0
  316. package/dist/security/controllers/root-key.controller.js +90 -0
  317. package/dist/security/index.d.ts +9 -0
  318. package/dist/security/index.js +9 -0
  319. package/dist/security/messages.en.d.ts +12 -0
  320. package/dist/security/messages.en.js +2 -0
  321. package/dist/security/models.d.ts +112 -0
  322. package/dist/security/models.js +2 -0
  323. package/dist/security/ports.d.ts +58 -0
  324. package/dist/security/ports.js +5 -0
  325. package/dist/security/react/components/CredentialEditor.d.ts +3 -0
  326. package/dist/security/react/components/CredentialEditor.js +8 -0
  327. package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +94 -0
  328. package/dist/security/react/hooks/AccessTokensTab.hooks.js +36 -0
  329. package/dist/security/react/hooks/CredentialEditor.hooks.d.ts +49 -0
  330. package/dist/security/react/hooks/CredentialEditor.hooks.js +14 -0
  331. package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +29 -0
  332. package/dist/security/react/hooks/RootKeyTab.hooks.js +19 -0
  333. package/dist/security/react/hooks/SecurityPage.hooks.d.ts +17 -0
  334. package/dist/security/react/hooks/SecurityPage.hooks.js +12 -0
  335. package/dist/security/react/hooks/SecurityPorts.hooks.d.ts +9 -0
  336. package/dist/security/react/hooks/SecurityPorts.hooks.js +6 -0
  337. package/dist/security/react/index.d.ts +215 -0
  338. package/dist/security/react/index.js +10 -0
  339. package/dist/security/react/pages/SecurityPage.d.ts +4 -0
  340. package/dist/security/react/pages/SecurityPage.js +10 -0
  341. package/dist/security/react/tabs/AccessTokensTab.d.ts +4 -0
  342. package/dist/security/react/tabs/AccessTokensTab.js +10 -0
  343. package/dist/security/react/tabs/RootKeyTab.d.ts +4 -0
  344. package/dist/security/react/tabs/RootKeyTab.js +9 -0
  345. package/dist/security/rules.d.ts +57 -0
  346. package/dist/security/rules.js +63 -0
  347. package/dist/security/security.module.d.ts +45 -0
  348. package/dist/security/security.module.js +5 -0
  349. package/dist/source-control/adapters/http.d.ts +6 -0
  350. package/dist/source-control/adapters/http.js +13 -0
  351. package/dist/source-control/adapters/memory.d.ts +9 -0
  352. package/dist/source-control/adapters/memory.js +35 -0
  353. package/dist/source-control/conformance/source-control-api.conformance.d.ts +10 -0
  354. package/dist/source-control/conformance/source-control-api.conformance.js +48 -0
  355. package/dist/source-control/controllers/source-control.controller.d.ts +26 -0
  356. package/dist/source-control/controllers/source-control.controller.js +70 -0
  357. package/dist/source-control/index.d.ts +8 -0
  358. package/dist/source-control/index.js +6 -0
  359. package/dist/source-control/messages.en.d.ts +11 -0
  360. package/dist/source-control/messages.en.js +2 -0
  361. package/dist/source-control/models.d.ts +70 -0
  362. package/dist/source-control/models.js +2 -0
  363. package/dist/source-control/ports.d.ts +23 -0
  364. package/dist/source-control/ports.js +3 -0
  365. package/dist/source-control/react/components/SourceControlCredentialFields.d.ts +5 -0
  366. package/dist/source-control/react/components/SourceControlCredentialFields.js +8 -0
  367. package/dist/source-control/react/components/SourceControlProviderRow.d.ts +5 -0
  368. package/dist/source-control/react/components/SourceControlProviderRow.js +7 -0
  369. package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +45 -0
  370. package/dist/source-control/react/hooks/ProvidersTab.hooks.js +20 -0
  371. package/dist/source-control/react/hooks/SourceControlCredentialFields.hooks.d.ts +43 -0
  372. package/dist/source-control/react/hooks/SourceControlCredentialFields.hooks.js +9 -0
  373. package/dist/source-control/react/hooks/SourceControlPage.hooks.d.ts +17 -0
  374. package/dist/source-control/react/hooks/SourceControlPage.hooks.js +5 -0
  375. package/dist/source-control/react/hooks/SourceControlPorts.hooks.d.ts +9 -0
  376. package/dist/source-control/react/hooks/SourceControlPorts.hooks.js +6 -0
  377. package/dist/source-control/react/index.d.ts +156 -0
  378. package/dist/source-control/react/index.js +10 -0
  379. package/dist/source-control/react/pages/SourceControlPage.d.ts +4 -0
  380. package/dist/source-control/react/pages/SourceControlPage.js +11 -0
  381. package/dist/source-control/react/tabs/ProvidersTab.d.ts +4 -0
  382. package/dist/source-control/react/tabs/ProvidersTab.js +10 -0
  383. package/dist/source-control/rules.d.ts +32 -0
  384. package/dist/source-control/rules.js +35 -0
  385. package/dist/source-control/source-control.module.d.ts +36 -0
  386. package/dist/source-control/source-control.module.js +6 -0
  387. package/package.json +207 -4
@@ -0,0 +1,81 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ /**
3
+ * Own session reads and invalidation without any host API imports.
4
+ * @param args Stable context and session port. Changing either starts a new session check.
5
+ * @returns Gate state plus refresh/logout actions; adapter failures become an error state.
6
+ */
7
+ export function useAdminShellSession(args) {
8
+ const { context, port } = args;
9
+ const active = useRef(null);
10
+ const loggingOut = useRef(null);
11
+ const generation = useRef(0);
12
+ const [owned, setOwned] = useState({ context, port, state: { status: 'checking' } });
13
+ const run = useCallback(async (operation) => {
14
+ const owner = active.current;
15
+ if (!owner || owner.context !== context || owner.port !== port)
16
+ return;
17
+ // A refresh must not race a pending logout and restore a soon-to-be-revoked principal.
18
+ if (loggingOut.current === owner)
19
+ return;
20
+ if (operation === 'logout')
21
+ loggingOut.current = owner;
22
+ const request = ++generation.current;
23
+ const isCurrent = () => active.current === owner && generation.current === request;
24
+ setOwned({ context, port, state: { status: 'checking' } });
25
+ try {
26
+ if (operation === 'logout') {
27
+ await port.logout(context);
28
+ if (isCurrent())
29
+ setOwned({ context, port, state: { status: 'anonymous' } });
30
+ return;
31
+ }
32
+ const session = await port.read(context);
33
+ if (!isCurrent())
34
+ return;
35
+ const state = session === null
36
+ ? { status: 'anonymous' }
37
+ : { status: 'authenticated', session };
38
+ setOwned({ context, port, state });
39
+ }
40
+ catch (error) {
41
+ // Local sign-out must complete even when the server cannot revoke its cookie. A read
42
+ // retry here would quietly restore that still-valid session instead of showing login.
43
+ if (isCurrent())
44
+ setOwned({ context, port, state: operation === 'logout'
45
+ ? { status: 'anonymous' }
46
+ : { status: 'error', error } });
47
+ }
48
+ finally {
49
+ if (operation === 'logout' && loggingOut.current === owner)
50
+ loggingOut.current = null;
51
+ }
52
+ }, [context, port]);
53
+ const refresh = useCallback(() => run('read'), [run]);
54
+ const logout = useCallback(() => run('logout'), [run]);
55
+ useEffect(() => {
56
+ const owner = { context, port };
57
+ active.current = owner;
58
+ const unsubscribe = port.onUnauthenticated({
59
+ ...context,
60
+ onUnauthenticated: () => {
61
+ if (active.current !== owner)
62
+ return;
63
+ // Retire all older reads before clearing the gate; none may restore the principal.
64
+ generation.current += 1;
65
+ setOwned({ context, port, state: { status: 'anonymous' } });
66
+ },
67
+ });
68
+ void refresh();
69
+ return () => {
70
+ active.current = null;
71
+ generation.current += 1;
72
+ unsubscribe();
73
+ };
74
+ }, [context, port, refresh]);
75
+ // Mask the old workspace synchronously, before effect cleanup/initialization executes.
76
+ const state = owned.context === context && owned.port === port
77
+ ? owned.state
78
+ : { status: 'checking' };
79
+ return { state, refresh, logout };
80
+ }
81
+ //# sourceMappingURL=use-admin-shell-session.js.map
@@ -0,0 +1,16 @@
1
+ import { type AdminTheme, type ColorSchemePreference } from '@jini-ai/ui/theme';
2
+ import type { AdminShellAppearance, AdminThemeEnvironment, AdminThemePreferenceStorePort } from './theme-ports.js';
3
+ /** Keep effects inside the host's scope; storage reads/writes never use ambient browser state. */
4
+ export declare function useAdminTheme({ userId, workspace }: {
5
+ readonly userId: string | null;
6
+ readonly workspace: Readonly<Record<string, string>>;
7
+ }, { theme, colorScheme, environment, preferenceStore, onColorSchemeChange }?: {
8
+ readonly theme?: AdminTheme;
9
+ readonly colorScheme?: ColorSchemePreference;
10
+ readonly environment?: AdminThemeEnvironment;
11
+ readonly preferenceStore?: AdminThemePreferenceStorePort;
12
+ readonly onColorSchemeChange?: (args: {
13
+ readonly preference: ColorSchemePreference;
14
+ }) => void;
15
+ }): AdminShellAppearance | undefined;
16
+ //# sourceMappingURL=use-admin-theme.d.ts.map
@@ -0,0 +1,57 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { applyAdminTheme, resolveColorScheme } from '@jini-ai/ui/theme';
3
+ /** Keep effects inside the host's scope; storage reads/writes never use ambient browser state. */
4
+ export function useAdminTheme({ userId, workspace }, { theme, colorScheme, environment, preferenceStore, onColorSchemeChange } = {}) {
5
+ const scope = JSON.stringify([userId, Object.entries(workspace).sort(([a], [b]) => a.localeCompare(b))]);
6
+ const [saved, setSaved] = useState(null);
7
+ const [mediaRevision, setMediaRevision] = useState(0);
8
+ const preference = colorScheme ?? (saved?.scope === scope ? saved.preference : 'system');
9
+ useEffect(() => {
10
+ if (!userId || !preferenceStore) {
11
+ setSaved(null);
12
+ return;
13
+ }
14
+ const stored = preferenceStore.read({ userId, workspace });
15
+ setSaved(stored === 'light' || stored === 'dark' || stored === 'system' ? { scope, preference: stored } : null);
16
+ }, [userId, workspace, scope, preferenceStore]);
17
+ useEffect(() => {
18
+ if (!theme)
19
+ return;
20
+ if (!environment)
21
+ throw new TypeError('AdminShell theme requires a themeEnvironment port');
22
+ return applyAdminTheme({ theme }, environment);
23
+ }, [theme, environment]);
24
+ useEffect(() => {
25
+ if (!environment || preference !== 'system')
26
+ return;
27
+ const media = environment.matchMedia('(prefers-color-scheme: dark)');
28
+ const changed = () => setMediaRevision((revision) => revision + 1);
29
+ media.addEventListener?.('change', changed);
30
+ return () => media.removeEventListener?.('change', changed);
31
+ }, [environment, preference]);
32
+ // A revision refreshes the live media snapshot; explicit choices never query the OS.
33
+ void mediaRevision;
34
+ const resolved = environment ? resolveColorScheme({ preference }, { matchMedia: environment.matchMedia }) : 'light';
35
+ useEffect(() => {
36
+ if (!environment)
37
+ return;
38
+ const previous = environment.target.getAttribute('data-color-scheme');
39
+ environment.target.setAttribute('data-color-scheme', resolved);
40
+ return () => {
41
+ if (previous === null)
42
+ environment.target.removeAttribute('data-color-scheme');
43
+ else
44
+ environment.target.setAttribute('data-color-scheme', previous);
45
+ };
46
+ }, [environment, resolved]);
47
+ const setPreference = useCallback(({ preference: next }) => {
48
+ if (next !== 'light' && next !== 'dark' && next !== 'system')
49
+ throw new TypeError('Invalid color scheme preference');
50
+ if (userId && preferenceStore)
51
+ preferenceStore.write({ userId, workspace, preference: next });
52
+ setSaved({ scope, preference: next });
53
+ onColorSchemeChange?.({ preference: next });
54
+ }, [userId, preferenceStore, workspace, scope, onColorSchemeChange]);
55
+ return environment ? { preference, resolved, setPreference } : undefined;
56
+ }
57
+ //# sourceMappingURL=use-admin-theme.js.map
@@ -18,11 +18,13 @@
18
18
  export type ConfirmTone = 'default' | 'warning' | 'danger';
19
19
  /** Maps a tone onto the class name the host stylesheet is expected to define. `"default"` yields
20
20
  * `undefined` — the plain button, no class. */
21
- export declare function toneClassName(tone: ConfirmTone): string | undefined;
21
+ export declare function toneClassName({ tone }: {
22
+ readonly tone: ConfirmTone;
23
+ }): string | undefined;
22
24
  /** `tone` wins when both `tone` and the deprecated `destructive` are passed; `destructive: true`
23
25
  * alone still maps to `"danger"` (its only prior meaning) for callers that haven't migrated. */
24
- export declare function resolveTone(source: {
25
- tone?: ConfirmTone;
26
- destructive?: boolean;
26
+ export declare function resolveTone(_requiredArgs: Record<string, never>, source?: {
27
+ tone?: ConfirmTone | undefined;
28
+ destructive?: boolean | undefined;
27
29
  }): ConfirmTone;
28
30
  //# sourceMappingURL=types.d.ts.map
@@ -8,7 +8,7 @@
8
8
  */
9
9
  /** Maps a tone onto the class name the host stylesheet is expected to define. `"default"` yields
10
10
  * `undefined` — the plain button, no class. */
11
- export function toneClassName(tone) {
11
+ export function toneClassName({ tone }) {
12
12
  if (tone === 'danger')
13
13
  return 'btn-danger';
14
14
  if (tone === 'warning')
@@ -17,7 +17,7 @@ export function toneClassName(tone) {
17
17
  }
18
18
  /** `tone` wins when both `tone` and the deprecated `destructive` are passed; `destructive: true`
19
19
  * alone still maps to `"danger"` (its only prior meaning) for callers that haven't migrated. */
20
- export function resolveTone(source) {
20
+ export function resolveTone(_requiredArgs, source = {}) {
21
21
  return source.tone ?? (source.destructive ? 'danger' : 'default');
22
22
  }
23
23
  //# sourceMappingURL=types.js.map
@@ -0,0 +1,16 @@
1
+ import type { DependencyList } from 'react';
2
+ import type { ControllerStore } from '../core/module/controller-store.js';
3
+ /** Factory runs after commit, never during render. Each effect attachment owns a fresh
4
+ * controller, so StrictMode's cleanup/replay cannot revive a disposed controller. */
5
+ export declare function useController<C extends ControllerStore<unknown>>({ create, dependencies }: {
6
+ create: () => C;
7
+ dependencies: DependencyList;
8
+ }, { start, }?: {
9
+ start?: (required: {
10
+ controller: C;
11
+ }, optional?: Record<string, never>) => void;
12
+ }): {
13
+ controller: C | null;
14
+ snapshot: ReturnType<C["getSnapshot"]> | null;
15
+ };
16
+ //# sourceMappingURL=use-controller.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { useEffect, useState, useSyncExternalStore, useCallback } from 'react';
2
+ /** Factory runs after commit, never during render. Each effect attachment owns a fresh
3
+ * controller, so StrictMode's cleanup/replay cannot revive a disposed controller. */
4
+ export function useController({ create, dependencies }, { start, } = {}) {
5
+ const [controller, setController] = useState(null);
6
+ useEffect(() => {
7
+ const current = create();
8
+ setController(current);
9
+ start?.({ controller: current });
10
+ return () => current.dispose();
11
+ // Dependencies are explicitly supplied by the owning hook, like useMemo's contract.
12
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13
+ }, dependencies);
14
+ const subscribe = useCallback((listener) => controller?.subscribe({ listener }) ?? (() => { }), [controller]);
15
+ const snapshot = useSyncExternalStore(subscribe, () => (controller?.getSnapshot() ?? null), () => null);
16
+ return { controller, snapshot };
17
+ }
18
+ //# sourceMappingURL=use-controller.js.map
@@ -0,0 +1,16 @@
1
+ import type { SecurityApiPort, SecurityTransportPort, OtherCredentialsPort, RootKeyPort } from '../ports.js';
2
+ export declare function createHttpSecurityApi({ transport, workspacePath }: {
3
+ transport: SecurityTransportPort;
4
+ workspacePath: string;
5
+ }, _optional?: {}): SecurityApiPort;
6
+ export declare function createHttpOtherCredentials({ transport, workspacePath }: {
7
+ transport: SecurityTransportPort;
8
+ workspacePath: string;
9
+ }, { mediaLabels }?: {
10
+ mediaLabels?: Readonly<Record<string, string>>;
11
+ }): OtherCredentialsPort;
12
+ export declare function createHttpRootKey({ transport, workspacePath }: {
13
+ transport: SecurityTransportPort;
14
+ workspacePath: string;
15
+ }, _optional?: {}): RootKeyPort;
16
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1,94 @@
1
+ /** Explicit projection strips accidental server extras, including token/ciphertext/hex. */
2
+ function summary(row, kind) {
3
+ return Object.freeze({ kind, id: row.id, providerId: row.providerId ?? '', label: row.label, configured: row.configured, isDefault: row.isDefault ?? false, createdAt: row.createdAt, updatedAt: row.updatedAt,
4
+ ...(row.accountLabel !== undefined ? { accountLabel: row.accountLabel } : {}), ...(kind === 'custom' ? { category: row.category ?? 'general', baseUrl: row.baseUrl ?? '', additionalHosts: Object.freeze([...(row.additionalHosts ?? [])]), ...(row.username ? { username: row.username } : {}) } : {}) });
5
+ }
6
+ export function createHttpSecurityApi({ transport, workspacePath }, _optional = {}) {
7
+ const base = workspacePath.replace(/\/$/, '');
8
+ function store(kind, suffix) {
9
+ const path = `${base}/system/${suffix}/credentials`;
10
+ async function mutate(method, target, body, options) { options.signal?.throwIfAborted(); const r = await transport.request({ method, path: target, body }, options); return summary(r.credential, kind); }
11
+ return {
12
+ async list(_r, options = {}) { options.signal?.throwIfAborted(); const r = await transport.request({ method: 'GET', path }, options); return Object.freeze(r.credentials.map(row => summary(row, kind))); },
13
+ create(input, options = {}) { return mutate('POST', path, input, options); },
14
+ update({ id, patch }, options = {}) { return mutate('PUT', `${path}/${encodeURIComponent(id)}`, patch, options); },
15
+ async remove({ id }, options = {}) { options.signal?.throwIfAborted(); await transport.request({ method: 'DELETE', path: `${path}/${encodeURIComponent(id)}` }, options); },
16
+ };
17
+ }
18
+ return {
19
+ async providers(_r, options = {}) {
20
+ options.signal?.throwIfAborted();
21
+ const [publish, source] = await Promise.all([
22
+ transport.request({ method: 'GET', path: `${base}/system/publish-targets` }, options),
23
+ transport.request({ method: 'GET', path: `${base}/system/source-control/providers` }, options),
24
+ ]);
25
+ const map = (kind, d) => ({ kind, id: d.id, label: d.label, vendorLabel: d.credential?.vendorLabel ?? d.label, category: kind === 'publish' ? 'hosting' : 'source-control', tokenField: d.credential?.tokenField ?? 'token', fields: d.credential?.fields ?? [], ...(d.credential?.tokenPageUrl ? { tokenPageUrl: d.credential.tokenPageUrl } : {}), ...((d.credential?.userHelp ?? d.credential?.help) ? { help: d.credential.userHelp ?? d.credential.help } : {}) });
26
+ return [...publish.targets.filter(d => d.credential).map(d => map('publish', d)), ...source.providers.map(d => map('source-control', d))];
27
+ },
28
+ publish: store('publish', 'publish'), sourceControl: store('source-control', 'source-control'), custom: store('custom', 'custom'),
29
+ };
30
+ }
31
+ /** Replacing the ENTIRE map requires sibling settings unchanged. Blank apiKey preserves their stored keys. */
32
+ function rebuildMedia(current, id, token) {
33
+ const next = {};
34
+ for (const [key, entry] of Object.entries(current)) {
35
+ if (key === id && token === undefined)
36
+ continue;
37
+ next[key] = { ...(entry.baseUrl !== undefined ? { baseUrl: entry.baseUrl } : {}), ...(entry.model !== undefined ? { model: entry.model } : {}), ...(key === id && token !== undefined ? { apiKey: token } : {}) };
38
+ }
39
+ return next;
40
+ }
41
+ export function createHttpOtherCredentials({ transport, workspacePath }, { mediaLabels = {} } = {}) {
42
+ const base = workspacePath.replace(/\/$/, '');
43
+ const singles = { 'site-assistant': { path: '/assistant/site-credential', label: 'Assistant model key' }, 'admin-byok': { path: '/assistant/execution-credential', label: 'Admin model key' } };
44
+ async function request(path, method, options, body) { options.signal?.throwIfAborted(); return transport.request({ path: `${base}${path}`, method, ...(body !== undefined ? { body } : {}) }, options); }
45
+ return {
46
+ async list({ store }, options = {}) {
47
+ if (store === 'site-assistant' || store === 'admin-byok') {
48
+ const r = await request(singles[store].path, 'GET', options);
49
+ return r.data.isSet ? [{ store, id: store, label: singles[store].label, category: 'ai', configured: true, supportsReplace: true, updatedAt: r.data.updatedAt }] : [];
50
+ }
51
+ if (store === 'media-provider') {
52
+ const map = await request('/media/providers', 'GET', options);
53
+ return Object.entries(map).filter(([, entry]) => entry.apiKeyConfigured).map(([id]) => ({ store, id, label: mediaLabels[id] ?? id, category: 'media', configured: true, supportsReplace: true }));
54
+ }
55
+ const { servers } = await request('/mcp-servers', 'GET', options);
56
+ return servers.map(s => ({ store, id: s.serverId, label: s.label, category: 'ai', configured: true, supportsReplace: false, envNames: Object.freeze([...s.envNames]) }));
57
+ },
58
+ async replace({ store, id, token }, options = {}) {
59
+ if (!token.trim())
60
+ throw new Error('Enter a credential');
61
+ if (store === 'external-mcp')
62
+ throw new Error('Edit the full server configuration on its own screen');
63
+ if (store === 'media-provider') {
64
+ const current = await request('/media/providers', 'GET', options);
65
+ await request('/media/providers', 'PUT', options, rebuildMedia(current, id, token));
66
+ }
67
+ else
68
+ await request(singles[store].path, 'PUT', options, { apiKey: token });
69
+ },
70
+ async remove({ store, id }, options = {}) {
71
+ if (store === 'media-provider') {
72
+ const current = await request('/media/providers', 'GET', options);
73
+ await request('/media/providers', 'PUT', options, rebuildMedia(current, id));
74
+ }
75
+ else if (store === 'external-mcp')
76
+ await request(`/mcp-servers/${encodeURIComponent(id)}`, 'DELETE', options);
77
+ else
78
+ await request(singles[store].path, 'DELETE', options);
79
+ },
80
+ };
81
+ }
82
+ export function createHttpRootKey({ transport, workspacePath }, _optional = {}) {
83
+ const path = `${workspacePath.replace(/\/$/, '')}/system/site-token`;
84
+ async function request(suffix, method, options, body) { options.signal?.throwIfAborted(); return transport.request({ path: `${path}${suffix}`, method, ...(body !== undefined ? { body } : {}) }, options); }
85
+ function result(r) { return { outcome: r.outcome, fingerprint: r.fingerprint, keyFilePath: r.keyFilePath, runtimeMode: r.runtimeMode, ...(r.resealed !== undefined ? { resealed: r.resealed } : {}), ...(r.discarded !== undefined ? { discarded: r.discarded } : {}), ...(r.kept !== undefined ? { kept: r.kept } : {}), ...(r.restorePointId ? { restorePointId: r.restorePointId } : {}), ...(r.affectedWebhooks ? { affectedWebhooks: r.affectedWebhooks.map(w => ({ label: w.label, targetUrl: w.targetUrl })) } : {}) }; }
86
+ return {
87
+ async status(_r, o = {}) { const r = await request('', 'GET', o); return { active: r.active, source: r.source, state: r.state, keyFilePath: r.keyFilePath, runtimeMode: r.runtimeMode, ...(r.fingerprint ? { fingerprint: r.fingerprint } : {}), ...(r.invalid !== undefined ? { invalid: r.invalid } : {}) }; },
88
+ async generate(_r, o = {}) { return result(await request('/generate', 'POST', o)); },
89
+ async importToken({ token }, o = {}) { return result(await request('/import', 'POST', o, { token })); },
90
+ async previewStartFresh(_r, o = {}) { const r = await request('/start-fresh', 'GET', o); return { removes: r.removes, detail: r.detail, runtimeMode: r.runtimeMode, affectedWebhooks: r.affectedWebhooks.map(w => ({ label: w.label, targetUrl: w.targetUrl })) }; },
91
+ async startFresh({ confirm }, o = {}) { return result(await request('/start-fresh', 'POST', o, { confirm })); },
92
+ };
93
+ }
94
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1,15 @@
1
+ import type { SecurityApiPort, OtherCredentialsPort, RootKeyPort } from '../ports.js';
2
+ import type { CredentialSummary, CredentialProvider, OtherCredentialSummary, RootKeyStatus, RootKeyPreview } from '../models.js';
3
+ /** Fake backend: retains only read models, never credential material. */
4
+ export declare function createMemorySecurityApi({ providers, rows }: {
5
+ providers?: readonly CredentialProvider[];
6
+ rows?: readonly CredentialSummary[];
7
+ }, _optional?: {}): SecurityApiPort;
8
+ export declare function createMemoryOtherCredentials({ rows }: {
9
+ rows?: readonly OtherCredentialSummary[];
10
+ }, _optional?: {}): OtherCredentialsPort;
11
+ export declare function createMemoryRootKey({ status, preview }: {
12
+ status?: RootKeyStatus;
13
+ preview?: RootKeyPreview;
14
+ }, _optional?: {}): RootKeyPort;
15
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { START_FRESH_CONFIRMATION } from '../rules.js';
2
+ /** Fake backend: retains only read models, never credential material. */
3
+ export function createMemorySecurityApi({ providers = [], rows = [] }, _optional = {}) {
4
+ let items = rows.map(r => Object.freeze({ ...r }));
5
+ let sequence = 0;
6
+ function store(kind) {
7
+ function project(id, patch, providerId, initial) {
8
+ const now = new Date().toISOString();
9
+ return Object.freeze({ kind, id, providerId, label: patch.label ?? initial?.label ?? '', configured: true, isDefault: kind === 'custom' ? false : patch.isDefault ?? initial?.isDefault ?? !items.some(r => r.kind === kind && r.providerId === providerId), createdAt: initial?.createdAt ?? now, updatedAt: now,
10
+ ...(kind === 'custom' ? { category: patch.category ?? initial?.category ?? 'general', baseUrl: patch.baseUrl ?? initial?.baseUrl ?? '', additionalHosts: Object.freeze([...(patch.additionalHosts ?? initial?.additionalHosts ?? [])]), ...((patch.username !== undefined ? patch.username : patch.connection?.username ?? initial?.username) ? { username: (patch.username !== undefined ? patch.username : patch.connection?.username ?? initial?.username) } : {}) } : {}),
11
+ });
12
+ }
13
+ function check(label, providerId, id) { if (items.some(r => r.kind === kind && r.id !== id && (kind === 'custom' || r.providerId === providerId) && r.label.toLowerCase() === label.toLowerCase()))
14
+ throw new Error('Duplicate label'); }
15
+ function insert(row) {
16
+ if (row.isDefault)
17
+ items = items.map(r => r.kind === kind && r.providerId === row.providerId ? Object.freeze({ ...r, isDefault: false }) : r);
18
+ items = [...items.filter(r => !(r.kind === kind && r.id === row.id)), row];
19
+ return row;
20
+ }
21
+ return {
22
+ async list(_r, o = {}) { o.signal?.throwIfAborted(); return Object.freeze(items.filter(r => r.kind === kind)); },
23
+ async create(input, o = {}) { o.signal?.throwIfAborted(); if (!Object.values(input.connection).some(v => v.trim()) || !input.label.trim())
24
+ throw new Error('Incomplete credential'); const providerId = kind === 'custom' ? '' : input.connection.providerId ?? ''; check(input.label, providerId); return insert(project(`credential-${++sequence}`, input, providerId)); },
25
+ async update({ id, patch }, o = {}) { o.signal?.throwIfAborted(); const old = items.find(r => r.id === id && r.kind === kind); if (!old)
26
+ throw new Error('Credential not found'); check(patch.label ?? old.label, old.providerId, id); return insert(project(id, patch, old.providerId, old)); },
27
+ async remove({ id }, o = {}) { o.signal?.throwIfAborted(); const old = items.find(r => r.id === id && r.kind === kind); items = items.filter(r => !(r.id === id && r.kind === kind)); if (old?.isDefault) {
28
+ const next = items.filter(r => r.kind === kind && r.providerId === old.providerId).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))[0];
29
+ if (next)
30
+ insert(Object.freeze({ ...next, isDefault: true }));
31
+ } },
32
+ };
33
+ }
34
+ return { async providers(_r, o = {}) { o.signal?.throwIfAborted(); return providers; }, publish: store('publish'), sourceControl: store('source-control'), custom: store('custom') };
35
+ }
36
+ export function createMemoryOtherCredentials({ rows = [] }, _optional = {}) {
37
+ let items = rows.map(row => Object.freeze({ ...row }));
38
+ return {
39
+ async list({ store }, o = {}) { o.signal?.throwIfAborted(); return items.filter(r => r.store === store); },
40
+ async replace({ store, id, token }, o = {}) { o.signal?.throwIfAborted(); const row = items.find(r => r.store === store && r.id === id); if (!row?.supportsReplace || !token.trim())
41
+ throw new Error('Replacement unavailable'); items = items.map(r => r === row ? Object.freeze({ ...r, configured: true, updatedAt: new Date().toISOString() }) : r); },
42
+ async remove({ store, id }, o = {}) { o.signal?.throwIfAborted(); items = items.filter(r => r.store !== store || r.id !== id); },
43
+ };
44
+ }
45
+ export function createMemoryRootKey({ status = { active: false, source: 'none', state: 'missing', keyFilePath: '/memory/key', runtimeMode: 'local' }, preview = { removes: 0, affectedWebhooks: [], detail: 'Remove saved credentials and create a new root key.', runtimeMode: 'local' } }, _optional = {}) {
46
+ let current = Object.freeze({ ...status });
47
+ function activate(outcome) { current = Object.freeze({ ...current, active: true, state: 'active', source: 'file', fingerprint: 'memory-fingerprint' }); return { outcome, fingerprint: 'memory-fingerprint', keyFilePath: current.keyFilePath, runtimeMode: current.runtimeMode }; }
48
+ return {
49
+ async status(_r, o = {}) { o.signal?.throwIfAborted(); return current; },
50
+ async generate(_r, o = {}) { o.signal?.throwIfAborted(); if (current.active)
51
+ return { ...activate('already-active') }; if (current.state !== 'missing')
52
+ throw new Error('Key dependent data'); return activate('created'); },
53
+ async importToken({ token }, o = {}) { o.signal?.throwIfAborted(); if (!/^[0-9a-f]{64}$/i.test(token))
54
+ throw new Error('Invalid token'); return { ...activate('unlocked'), resealed: 0 }; },
55
+ async previewStartFresh(_r, o = {}) { o.signal?.throwIfAborted(); return preview; },
56
+ async startFresh({ confirm }, o = {}) { o.signal?.throwIfAborted(); if (confirm !== START_FRESH_CONFIRMATION)
57
+ throw new Error('Confirmation required'); return { ...activate('started-fresh'), discarded: preview.removes, kept: 0, affectedWebhooks: preview.affectedWebhooks, restorePointId: 'memory-restore-point' }; },
58
+ };
59
+ }
60
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1,10 @@
1
+ import type { SecurityApiPort } from '../ports.js';
2
+ import type { CredentialProvider } from '../models.js';
3
+ /** Use a disposable backend: this contract creates, updates and removes credentials. */
4
+ export declare function runSecurityApiConformance({ createApi, provider }: {
5
+ createApi: (required: Record<string, never>, optional?: Record<string, never>) => SecurityApiPort | Promise<SecurityApiPort>;
6
+ provider: CredentialProvider;
7
+ }, _optional?: {}): Promise<{
8
+ passed: number;
9
+ }>;
10
+ //# sourceMappingURL=security-api.conformance.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { credentialStore } from '../rules.js';
2
+ /** Use a disposable backend: this contract creates, updates and removes credentials. */
3
+ export async function runSecurityApiConformance({ createApi, provider }, _optional = {}) {
4
+ const api = await createApi({}), target = credentialStore({ api, kind: provider.kind });
5
+ let passed = 0;
6
+ function check(value, message) { if (!value)
7
+ throw new Error(`Security contract: ${message}`); passed++; }
8
+ const suffix = `${Date.now()}-${Math.random()}`;
9
+ const secret = `contract-secret-${suffix}`;
10
+ const connection = { providerId: provider.id, [provider.tokenField]: secret, ...Object.fromEntries(provider.fields.filter(f => f.name !== provider.tokenField).map(f => [f.name, 'test-value'])) };
11
+ const ids = [];
12
+ try {
13
+ const a = await target.create({ label: `First ${suffix}`, connection }, {});
14
+ ids.push(a.id);
15
+ check(a.configured, 'create produces configured summary');
16
+ check(!JSON.stringify(a).includes(secret), 'create cannot return secret');
17
+ const b = await target.create({ label: `Second ${suffix}`, connection }, {});
18
+ ids.push(b.id);
19
+ const renamed = await target.update({ id: a.id, patch: { label: `Renamed ${suffix}` } }, {});
20
+ check(renamed.id === a.id && renamed.label === `Renamed ${suffix}`, 'metadata update preserves identity');
21
+ const replaced = await target.update({ id: a.id, patch: { connection } }, {});
22
+ check(!JSON.stringify(replaced).includes(secret), 'replacement cannot return secret');
23
+ await target.update({ id: b.id, patch: { isDefault: true } }, {});
24
+ const listed = await target.list({}, {});
25
+ check(listed.filter(r => r.providerId === provider.id && r.isDefault).length === 1 && listed.find(r => r.id === b.id)?.isDefault === true, 'one server-owned default');
26
+ await target.remove({ id: b.id }, {});
27
+ const remaining = await target.list({}, {});
28
+ check(!remaining.some(r => r.id === b.id) && remaining.some(r => r.providerId === provider.id && r.isDefault), 'remove promotes remaining connection');
29
+ await target.remove({ id: b.id }, {});
30
+ check(true, 'remove is idempotent');
31
+ const abort = new AbortController();
32
+ abort.abort();
33
+ let refused = false;
34
+ try {
35
+ await target.create({ label: `Aborted ${suffix}`, connection }, { signal: abort.signal });
36
+ }
37
+ catch {
38
+ refused = true;
39
+ }
40
+ check(refused && !(await target.list({}, {})).some(r => r.label === `Aborted ${suffix}`), 'aborted mutation writes nothing');
41
+ }
42
+ finally {
43
+ for (const id of ids)
44
+ await target.remove({ id }, {});
45
+ }
46
+ return { passed };
47
+ }
48
+ //# sourceMappingURL=security-api.conformance.js.map
@@ -0,0 +1,44 @@
1
+ import type { SecurityApiPort } from '../ports.js';
2
+ import type { CredentialSummary, CredentialProvider, CredentialDraft, CredentialKind, CredentialCategory } from '../models.js';
3
+ export declare function createAccessTokensController({ api, permissions }: {
4
+ api: SecurityApiPort;
5
+ permissions?: readonly string[];
6
+ }, _optional?: {}): {
7
+ getSnapshot: () => Readonly<{
8
+ rows: readonly CredentialSummary[];
9
+ providers: readonly CredentialProvider[];
10
+ draft: CredentialDraft | null;
11
+ loading: boolean;
12
+ saving: boolean;
13
+ error: string | null;
14
+ errors: Readonly<Record<string, string>>;
15
+ query: string;
16
+ category: CredentialCategory | "all";
17
+ }>;
18
+ subscribe: ({ listener }: {
19
+ listener: () => void;
20
+ }) => () => void;
21
+ load: (_required: Record<string, never>, _optional?: {}) => Promise<void>;
22
+ begin: ({ row, kind, providerId }: {
23
+ row?: CredentialSummary;
24
+ kind?: CredentialKind;
25
+ providerId?: string;
26
+ }, _optional?: {}) => void;
27
+ save: (_required: Record<string, never>, _optional?: {}) => Promise<boolean>;
28
+ setDraft({ patch }: {
29
+ patch: Partial<Omit<CredentialDraft, "kind" | "id" | "providerId">>;
30
+ }, _optional?: {}): void;
31
+ cancel(_required: Record<string, never>, _optional?: {}): void;
32
+ filter({ query, category }: {
33
+ query?: string;
34
+ category?: CredentialCategory | "all";
35
+ }, _optional?: {}): void;
36
+ remove({ row }: {
37
+ row: CredentialSummary;
38
+ }, _optional?: {}): Promise<boolean>;
39
+ makeDefault({ row }: {
40
+ row: CredentialSummary;
41
+ }, _optional?: {}): Promise<boolean>;
42
+ dispose(_required?: Record<string, never>, _optional?: {}): void;
43
+ };
44
+ //# sourceMappingURL=access-tokens.controller.d.ts.map
@@ -0,0 +1,112 @@
1
+ import { createControllerStore } from '../../core/module/controller-store.js';
2
+ import { blankCredentialDraft, buildCredentialPatch, credentialStore, validateCredentialDraft, writePermission, credentialLabel } from '../rules.js';
3
+ export function createAccessTokensController({ api, permissions = [] }, _optional = {}) {
4
+ const grants = new Set(permissions);
5
+ const store = createControllerStore({ initial: { rows: [], providers: [], draft: null, loading: false, saving: false, error: null, errors: {}, query: '', category: 'all' } });
6
+ let generation = 0;
7
+ const allowed = (kind) => !store.signal.aborted && grants.has('security.read') && grants.has(writePermission({ kind }));
8
+ async function load(_required, _optional = {}) {
9
+ if (store.signal.aborted || !grants.has('security.read'))
10
+ return;
11
+ const ticket = ++generation;
12
+ store.set({ patch: { loading: true } });
13
+ // Independent stores retain their own successful results; one unavailable store cannot hide the rest.
14
+ const kinds = ['publish', 'source-control', 'custom'];
15
+ const tasks = kinds.map(async (kind) => {
16
+ try {
17
+ const rows = await credentialStore({ api, kind }).list({}, { signal: store.signal });
18
+ if (ticket === generation) {
19
+ const errors = { ...store.getSnapshot().errors };
20
+ delete errors[kind];
21
+ store.set({ patch: { rows: Object.freeze([...store.getSnapshot().rows.filter(r => r.kind !== kind), ...rows]), errors } });
22
+ }
23
+ }
24
+ catch {
25
+ if (ticket === generation)
26
+ store.set({ patch: { errors: { ...store.getSnapshot().errors, [kind]: 'Credential store unavailable' } } });
27
+ }
28
+ });
29
+ tasks.push((async () => { try {
30
+ const providers = await api.providers({}, { signal: store.signal });
31
+ if (ticket === generation)
32
+ store.set({ patch: { providers, error: null } });
33
+ }
34
+ catch {
35
+ if (ticket === generation)
36
+ store.set({ patch: { error: 'Provider catalog unavailable' } });
37
+ } })());
38
+ await Promise.all(tasks);
39
+ if (ticket === generation)
40
+ store.set({ patch: { loading: false } });
41
+ }
42
+ function begin({ row, kind, providerId }, _optional = {}) {
43
+ const k = row?.kind ?? kind ?? 'custom';
44
+ if (!allowed(k) || store.getSnapshot().saving)
45
+ return;
46
+ const draft = row ? { ...blankCredentialDraft({ kind: row.kind, providerId: row.providerId }), id: row.id, label: credentialLabel({ row, providers: store.getSnapshot().providers }), category: row.category ?? (row.kind === 'publish' ? 'hosting' : row.kind === 'source-control' ? 'source-control' : 'general'), baseUrl: row.baseUrl ?? '', additionalHosts: row.additionalHosts?.join('\n') ?? '', username: row.username ?? '' } : blankCredentialDraft({ kind: k, ...(providerId ? { providerId } : {}) });
47
+ store.set({ patch: { draft, error: null } });
48
+ }
49
+ async function save(_required, _optional = {}) {
50
+ const state = store.getSnapshot(), draft = state.draft;
51
+ if (!draft || !allowed(draft.kind) || state.saving)
52
+ return false;
53
+ const error = validateCredentialDraft({ draft, rows: state.rows, providers: state.providers });
54
+ if (error) {
55
+ store.set({ patch: { error } });
56
+ return false;
57
+ }
58
+ const patch = buildCredentialPatch({ draft, providers: state.providers });
59
+ const target = credentialStore({ api, kind: draft.kind });
60
+ store.set({ patch: { saving: true, error: null } });
61
+ try {
62
+ const row = draft.id ? await target.update({ id: draft.id, patch }, { signal: store.signal }) : await target.create(patch, { signal: store.signal });
63
+ // Clear accepted secrets before any later read can fail. A successful save must never leave a saved secret visible.
64
+ store.set({ patch: { draft: null, rows: Object.freeze([...store.getSnapshot().rows.filter(r => !(r.kind === row.kind && r.id === row.id)), row]) } });
65
+ // First-create default assignment can change siblings; the server owns that invariant.
66
+ await load({});
67
+ return !store.signal.aborted;
68
+ }
69
+ catch {
70
+ store.set({ patch: { error: 'Unable to save credential' } });
71
+ return false;
72
+ }
73
+ finally {
74
+ store.set({ patch: { saving: false } });
75
+ }
76
+ }
77
+ async function write({ row, remove }) {
78
+ if (!allowed(row.kind) || store.getSnapshot().saving)
79
+ return false;
80
+ store.set({ patch: { saving: true, error: null } });
81
+ try {
82
+ const target = credentialStore({ api, kind: row.kind });
83
+ if (remove)
84
+ await target.remove({ id: row.id }, { signal: store.signal });
85
+ else
86
+ await target.update({ id: row.id, patch: { isDefault: true } }, { signal: store.signal });
87
+ // Remove/default can promote another row. Refetch rather than duplicating server promotion rules.
88
+ await load({});
89
+ return !store.signal.aborted;
90
+ }
91
+ catch {
92
+ store.set({ patch: { error: 'Unable to update credential' } });
93
+ return false;
94
+ }
95
+ finally {
96
+ store.set({ patch: { saving: false } });
97
+ }
98
+ }
99
+ return {
100
+ getSnapshot: store.getSnapshot, subscribe: store.subscribe, load, begin, save,
101
+ setDraft({ patch }, _optional = {}) { const draft = store.getSnapshot().draft; if (draft && allowed(draft.kind) && !store.getSnapshot().saving)
102
+ store.set({ patch: { draft: { ...draft, ...patch } } }); },
103
+ cancel(_required, _optional = {}) { if (!store.getSnapshot().saving)
104
+ store.set({ patch: { draft: null, error: null } }); },
105
+ filter({ query, category }, _optional = {}) { store.set({ patch: { ...(query !== undefined ? { query } : {}), ...(category ? { category } : {}) } }); },
106
+ remove({ row }, _optional = {}) { return write({ row, remove: true }); },
107
+ makeDefault({ row }, _optional = {}) { if (row.kind === 'custom')
108
+ return Promise.resolve(false); return write({ row, remove: false }); },
109
+ dispose(_required = {}, _optional = {}) { generation++; store.dispose(); },
110
+ };
111
+ }
112
+ //# sourceMappingURL=access-tokens.controller.js.map