@jini-ai/admin 0.3.9 → 0.4.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.
- package/CHANGELOG.md +58 -0
- package/README.md +71 -37
- package/dist/agent-plugins/adapters/http.d.ts +7 -0
- package/dist/agent-plugins/adapters/http.js +15 -0
- package/dist/agent-plugins/adapters/memory.d.ts +8 -0
- package/dist/agent-plugins/adapters/memory.js +25 -0
- package/dist/agent-plugins/agent-plugins.module.d.ts +51 -0
- package/dist/agent-plugins/agent-plugins.module.js +6 -0
- package/dist/agent-plugins/conformance/agent-plugins-api.conformance.d.ts +12 -0
- package/dist/agent-plugins/conformance/agent-plugins-api.conformance.js +47 -0
- package/dist/agent-plugins/controllers/agent-plugin-files.controller.d.ts +20 -0
- package/dist/agent-plugins/controllers/agent-plugin-files.controller.js +43 -0
- package/dist/agent-plugins/controllers/agent-plugins.controller.d.ts +25 -0
- package/dist/agent-plugins/controllers/agent-plugins.controller.js +91 -0
- package/dist/agent-plugins/index.d.ts +9 -0
- package/dist/agent-plugins/index.js +9 -0
- package/dist/agent-plugins/messages.en.d.ts +23 -0
- package/dist/agent-plugins/messages.en.js +14 -0
- package/dist/agent-plugins/models.d.ts +57 -0
- package/dist/agent-plugins/models.js +2 -0
- package/dist/agent-plugins/package-file-tree.d.ts +111 -0
- package/dist/agent-plugins/package-file-tree.js +188 -0
- package/dist/agent-plugins/ports.d.ts +18 -0
- package/dist/agent-plugins/ports.js +3 -0
- package/dist/agent-plugins/react/components/AgentPluginFileContent.d.ts +5 -0
- package/dist/agent-plugins/react/components/AgentPluginFileContent.js +9 -0
- package/dist/agent-plugins/react/components/AgentPluginFileTree.d.ts +9 -0
- package/dist/agent-plugins/react/components/AgentPluginFileTree.js +7 -0
- package/dist/agent-plugins/react/components/AgentPluginInspector.d.ts +3 -0
- package/dist/agent-plugins/react/components/AgentPluginInspector.js +11 -0
- package/dist/agent-plugins/react/components/AgentPluginListPanel.d.ts +6 -0
- package/dist/agent-plugins/react/components/AgentPluginListPanel.js +10 -0
- package/dist/agent-plugins/react/components/AgentPluginRow.d.ts +5 -0
- package/dist/agent-plugins/react/components/AgentPluginRow.js +8 -0
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.d.ts +90 -0
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +74 -0
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +67 -0
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.js +50 -0
- package/dist/agent-plugins/react/hooks/AgentPluginRow.hooks.d.ts +55 -0
- package/dist/agent-plugins/react/hooks/AgentPluginRow.hooks.js +6 -0
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +64 -0
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +39 -0
- package/dist/agent-plugins/react/hooks/AgentPluginsPorts.hooks.d.ts +7 -0
- package/dist/agent-plugins/react/hooks/AgentPluginsPorts.hooks.js +10 -0
- package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.d.ts +6 -0
- package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.js +3 -0
- package/dist/agent-plugins/react/index.d.ts +245 -0
- package/dist/agent-plugins/react/index.js +13 -0
- package/dist/agent-plugins/react/pages/AgentPluginsPage.d.ts +4 -0
- package/dist/agent-plugins/react/pages/AgentPluginsPage.js +12 -0
- package/dist/agent-plugins/react/tabs/DownloadedTab.d.ts +4 -0
- package/dist/agent-plugins/react/tabs/DownloadedTab.js +5 -0
- package/dist/agent-plugins/react/tabs/InstalledTab.d.ts +4 -0
- package/dist/agent-plugins/react/tabs/InstalledTab.js +5 -0
- package/dist/agent-plugins/react/tabs/MarketplaceTab.d.ts +4 -0
- package/dist/agent-plugins/react/tabs/MarketplaceTab.js +10 -0
- package/dist/agent-plugins/rules.d.ts +33 -0
- package/dist/agent-plugins/rules.js +51 -0
- package/dist/browser/index.d.ts +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/navigation.d.ts +19 -4
- package/dist/browser/navigation.js +8 -8
- package/dist/browser/shell-navigation.d.ts +12 -0
- package/dist/browser/shell-navigation.js +16 -0
- package/dist/contracts/credential-management.d.ts +8 -0
- package/dist/contracts/credential-management.js +3 -0
- package/dist/contracts/media-picker.d.ts +17 -0
- package/dist/contracts/media-picker.js +5 -0
- package/dist/contracts/playground-render-target.d.ts +18 -0
- package/dist/contracts/playground-render-target.js +3 -0
- package/dist/core/entities/rules.d.ts +138 -0
- package/dist/core/entities/rules.js +344 -0
- package/dist/core/gated/types.d.ts +8 -4
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +1 -0
- package/dist/core/manifest/rules.d.ts +24 -6
- package/dist/core/manifest/rules.js +12 -11
- package/dist/core/module/controller-store.d.ts +22 -0
- package/dist/core/module/controller-store.js +32 -0
- package/dist/core/module/create-admin.d.ts +41 -0
- package/dist/core/module/create-admin.js +187 -0
- package/dist/core/module/define-admin-module.d.ts +4 -0
- package/dist/core/module/define-admin-module.js +5 -0
- package/dist/core/module/index.d.ts +7 -0
- package/dist/core/module/index.js +4 -0
- package/dist/core/module/token.d.ts +19 -0
- package/dist/core/module/token.js +4 -0
- package/dist/core/module/types.d.ts +79 -0
- package/dist/core/module/types.js +2 -0
- package/dist/core/permissions/rules.d.ts +4 -1
- package/dist/core/permissions/rules.js +1 -1
- package/dist/core/ports/analytics.d.ts +1 -1
- package/dist/core/ports/auth.d.ts +2 -2
- package/dist/core/ports/comments.d.ts +9 -6
- package/dist/core/ports/database.d.ts +13 -10
- package/dist/core/ports/entities.d.ts +302 -0
- package/dist/core/ports/entities.js +47 -0
- package/dist/core/ports/forms.d.ts +19 -7
- package/dist/core/ports/identity.d.ts +42 -17
- package/dist/core/ports/index.d.ts +2 -0
- package/dist/core/ports/integrations.d.ts +9 -4
- package/dist/core/ports/media.d.ts +16 -7
- package/dist/core/ports/members.d.ts +7 -3
- package/dist/core/ports/menus.d.ts +43 -0
- package/dist/core/ports/menus.js +43 -0
- package/dist/core/ports/plugins.d.ts +3 -2
- package/dist/core/ports/recovery.d.ts +10 -6
- package/dist/core/ports/redirects.d.ts +17 -7
- package/dist/core/ports/seo.d.ts +12 -6
- package/dist/core/ports/shell.d.ts +41 -0
- package/dist/core/ports/shell.js +2 -0
- package/dist/core/ports/workspace.d.ts +3 -3
- package/dist/core/routing/rules.d.ts +17 -4
- package/dist/core/routing/rules.js +4 -4
- package/dist/core/transport/errors.d.ts +13 -4
- package/dist/core/transport/errors.js +4 -4
- package/dist/core/transport/http.d.ts +26 -16
- package/dist/core/transport/http.js +59 -21
- package/dist/core/transport/types.d.ts +26 -14
- package/dist/core/transport/types.js +9 -7
- package/dist/media/adapters/http.d.ts +27 -0
- package/dist/media/adapters/http.js +44 -0
- package/dist/media/adapters/memory.d.ts +11 -0
- package/dist/media/adapters/memory.js +139 -0
- package/dist/media/conformance/media-api.conformance.d.ts +7 -0
- package/dist/media/conformance/media-api.conformance.js +69 -0
- package/dist/media/controllers/edit-media.controller.d.ts +24 -0
- package/dist/media/controllers/edit-media.controller.js +69 -0
- package/dist/media/controllers/library.controller.d.ts +47 -0
- package/dist/media/controllers/library.controller.js +173 -0
- package/dist/media/controllers/providers.controller.d.ts +30 -0
- package/dist/media/controllers/providers.controller.js +76 -0
- package/dist/media/html-attributes.d.ts +82 -0
- package/dist/media/html-attributes.js +204 -0
- package/dist/media/index.d.ts +12 -0
- package/dist/media/index.js +9 -0
- package/dist/media/media.module.d.ts +83 -0
- package/dist/media/media.module.js +43 -0
- package/dist/media/messages.en.d.ts +24 -0
- package/dist/media/messages.en.js +24 -0
- package/dist/media/models.d.ts +72 -0
- package/dist/media/models.js +2 -0
- package/dist/media/ports.d.ts +75 -0
- package/dist/media/ports.js +7 -0
- package/dist/media/react/components/EditMediaPanel.d.ts +3 -0
- package/dist/media/react/components/EditMediaPanel.js +10 -0
- package/dist/media/react/components/MediaCard.d.ts +5 -0
- package/dist/media/react/components/MediaCard.js +17 -0
- package/dist/media/react/components/MediaDialog.d.ts +3 -0
- package/dist/media/react/components/MediaDialog.js +8 -0
- package/dist/media/react/components/MediaGrid.d.ts +4 -0
- package/dist/media/react/components/MediaGrid.js +8 -0
- package/dist/media/react/components/MediaIcons.d.ts +14 -0
- package/dist/media/react/components/MediaIcons.js +39 -0
- package/dist/media/react/components/MediaLightbox.d.ts +5 -0
- package/dist/media/react/components/MediaLightbox.js +12 -0
- package/dist/media/react/components/MediaPicker.d.ts +3 -0
- package/dist/media/react/components/MediaPicker.js +10 -0
- package/dist/media/react/components/MediaPurgeDialog.d.ts +4 -0
- package/dist/media/react/components/MediaPurgeDialog.js +9 -0
- package/dist/media/react/components/UploadButton.d.ts +3 -0
- package/dist/media/react/components/UploadButton.js +8 -0
- package/dist/media/react/hooks/EditMediaPanel.hooks.d.ts +84 -0
- package/dist/media/react/hooks/EditMediaPanel.hooks.js +105 -0
- package/dist/media/react/hooks/LibraryTab.hooks.d.ts +103 -0
- package/dist/media/react/hooks/LibraryTab.hooks.js +164 -0
- package/dist/media/react/hooks/MediaCard.hooks.d.ts +79 -0
- package/dist/media/react/hooks/MediaCard.hooks.js +63 -0
- package/dist/media/react/hooks/MediaDialog.hooks.d.ts +10 -0
- package/dist/media/react/hooks/MediaDialog.hooks.js +20 -0
- package/dist/media/react/hooks/MediaGrid.hooks.d.ts +28 -0
- package/dist/media/react/hooks/MediaGrid.hooks.js +6 -0
- package/dist/media/react/hooks/MediaLightbox.hooks.d.ts +27 -0
- package/dist/media/react/hooks/MediaLightbox.hooks.js +64 -0
- package/dist/media/react/hooks/MediaPage.hooks.d.ts +68 -0
- package/dist/media/react/hooks/MediaPage.hooks.js +68 -0
- package/dist/media/react/hooks/MediaPicker.hooks.d.ts +26 -0
- package/dist/media/react/hooks/MediaPicker.hooks.js +25 -0
- package/dist/media/react/hooks/MediaPorts.hooks.d.ts +9 -0
- package/dist/media/react/hooks/MediaPorts.hooks.js +10 -0
- package/dist/media/react/hooks/MediaPurgeDialog.hooks.d.ts +22 -0
- package/dist/media/react/hooks/MediaPurgeDialog.hooks.js +6 -0
- package/dist/media/react/hooks/ProvidersTab.hooks.d.ts +55 -0
- package/dist/media/react/hooks/ProvidersTab.hooks.js +124 -0
- package/dist/media/react/hooks/UploadButton.hooks.d.ts +48 -0
- package/dist/media/react/hooks/UploadButton.hooks.js +118 -0
- package/dist/media/react/index.d.ts +373 -0
- package/dist/media/react/index.js +73 -0
- package/dist/media/react/pages/MediaPage.d.ts +4 -0
- package/dist/media/react/pages/MediaPage.js +9 -0
- package/dist/media/react/tabs/LibraryTab.d.ts +4 -0
- package/dist/media/react/tabs/LibraryTab.js +14 -0
- package/dist/media/react/tabs/ProvidersTab.d.ts +4 -0
- package/dist/media/react/tabs/ProvidersTab.js +10 -0
- package/dist/media/rules.d.ts +80 -0
- package/dist/media/rules.js +127 -0
- package/dist/media/styles.d.ts +4 -0
- package/dist/media/styles.js +5 -0
- package/dist/playground/adapters/http.d.ts +8 -0
- package/dist/playground/adapters/http.js +4 -0
- package/dist/playground/adapters/memory.d.ts +10 -0
- package/dist/playground/adapters/memory.js +30 -0
- package/dist/playground/conformance/playground-api.conformance.d.ts +6 -0
- package/dist/playground/conformance/playground-api.conformance.js +37 -0
- package/dist/playground/controllers/playground.controller.d.ts +16 -0
- package/dist/playground/controllers/playground.controller.js +21 -0
- package/dist/playground/index.d.ts +7 -0
- package/dist/playground/index.js +5 -0
- package/dist/playground/messages.en.d.ts +9 -0
- package/dist/playground/messages.en.js +2 -0
- package/dist/playground/models.d.ts +4 -0
- package/dist/playground/models.js +2 -0
- package/dist/playground/playground.module.d.ts +31 -0
- package/dist/playground/playground.module.js +5 -0
- package/dist/playground/ports.d.ts +5 -0
- package/dist/playground/ports.js +2 -0
- package/dist/playground/react/components/Canvas.d.ts +3 -0
- package/dist/playground/react/components/Canvas.js +9 -0
- package/dist/playground/react/hooks/Canvas.hooks.d.ts +7 -0
- package/dist/playground/react/hooks/Canvas.hooks.js +18 -0
- package/dist/playground/react/hooks/PlaygroundPage.hooks.d.ts +8 -0
- package/dist/playground/react/hooks/PlaygroundPage.hooks.js +2 -0
- package/dist/playground/react/hooks/PlaygroundPorts.hooks.d.ts +4 -0
- package/dist/playground/react/hooks/PlaygroundPorts.hooks.js +6 -0
- package/dist/playground/react/index.d.ts +136 -0
- package/dist/playground/react/index.js +10 -0
- package/dist/playground/react/pages/PlaygroundPage.d.ts +4 -0
- package/dist/playground/react/pages/PlaygroundPage.js +11 -0
- package/dist/playground/react/tabs/CanvasTab.d.ts +4 -0
- package/dist/playground/react/tabs/CanvasTab.js +5 -0
- package/dist/playground/rules.d.ts +4 -0
- package/dist/playground/rules.js +2 -0
- package/dist/react/OverlayHost.d.ts +3 -0
- package/dist/react/OverlayHost.hooks.d.ts +9 -0
- package/dist/react/OverlayHost.hooks.js +9 -0
- package/dist/react/OverlayHost.js +7 -0
- package/dist/react/bind-react.d.ts +46 -0
- package/dist/react/bind-react.js +28 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +7 -1
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +2 -2
- package/dist/react/components/ConfirmButton/ConfirmButton.js +1 -1
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +15 -3
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +17 -3
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +3 -3
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +6 -6
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +6 -2
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +7 -8
- package/dist/react/components/RowMenu/RowMenu.d.ts +5 -1
- package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +8 -2
- package/dist/react/components/RowMenu/RowMenu.hooks.js +4 -4
- package/dist/react/components/RowMenu/RowMenu.js +6 -6
- package/dist/react/components/Sidebar.d.ts +1 -1
- package/dist/react/components/Sidebar.js +103 -7
- package/dist/react/entities/EntityCell.d.ts +10 -0
- package/dist/react/entities/EntityCell.js +18 -0
- package/dist/react/entities/EntityDetail.d.ts +3 -0
- package/dist/react/entities/EntityDetail.js +21 -0
- package/dist/react/entities/EntityEdit.d.ts +13 -0
- package/dist/react/entities/EntityEdit.js +45 -0
- package/dist/react/entities/EntityField.d.ts +20 -0
- package/dist/react/entities/EntityField.js +31 -0
- package/dist/react/entities/EntityIndex.d.ts +3 -0
- package/dist/react/entities/EntityIndex.js +10 -0
- package/dist/react/entities/EntityList.d.ts +7 -0
- package/dist/react/entities/EntityList.js +52 -0
- package/dist/react/entities/contribution.d.ts +26 -0
- package/dist/react/entities/contribution.js +78 -0
- package/dist/react/entities/index.d.ts +10 -0
- package/dist/react/entities/index.js +7 -0
- package/dist/react/entities/rules.d.ts +179 -0
- package/dist/react/entities/rules.js +224 -0
- package/dist/react/entities/types.d.ts +45 -0
- package/dist/react/entities/types.js +5 -0
- package/dist/react/entities/use-entity-edit.d.ts +35 -0
- package/dist/react/entities/use-entity-edit.js +98 -0
- package/dist/react/entities/use-entity-read.d.ts +22 -0
- package/dist/react/entities/use-entity-read.js +27 -0
- package/dist/react/hooks/use-nav-sections.d.ts +12 -3
- package/dist/react/hooks/use-nav-sections.js +14 -14
- package/dist/react/hooks/use-sidebar-rail.d.ts +7 -1
- package/dist/react/hooks/use-sidebar-rail.js +11 -11
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +5 -2
- package/dist/react/kit/Kit.hooks.d.ts +13 -0
- package/dist/react/kit/Kit.hooks.js +10 -0
- package/dist/react/kit/Native.hooks.d.ts +38 -0
- package/dist/react/kit/Native.hooks.js +65 -0
- package/dist/react/kit/index.d.ts +12 -0
- package/dist/react/kit/index.js +21 -0
- package/dist/react/kit/native.d.ts +3 -0
- package/dist/react/kit/native.js +21 -0
- package/dist/react/kit/types.d.ts +40 -0
- package/dist/react/kit/types.js +2 -0
- package/dist/react/overlay.d.ts +36 -0
- package/dist/react/overlay.js +35 -0
- package/dist/react/overlays.d.ts +38 -0
- package/dist/react/overlays.js +46 -0
- package/dist/react/shell/AdminShell.d.ts +9 -0
- package/dist/react/shell/AdminShell.hooks.d.ts +15 -0
- package/dist/react/shell/AdminShell.hooks.js +27 -0
- package/dist/react/shell/AdminShell.js +46 -0
- package/dist/react/shell/index.d.ts +7 -0
- package/dist/react/shell/index.js +5 -0
- package/dist/react/shell/model.d.ts +25 -0
- package/dist/react/shell/model.js +29 -0
- package/dist/react/shell/theme-ports.d.ts +28 -0
- package/dist/react/shell/theme-ports.js +2 -0
- package/dist/react/shell/types.d.ts +99 -0
- package/dist/react/shell/types.js +2 -0
- package/dist/react/shell/use-admin-shell-session.d.ts +13 -0
- package/dist/react/shell/use-admin-shell-session.js +81 -0
- package/dist/react/shell/use-admin-theme.d.ts +16 -0
- package/dist/react/shell/use-admin-theme.js +57 -0
- package/dist/react/types.d.ts +6 -4
- package/dist/react/types.js +2 -2
- package/dist/react/use-controller.d.ts +16 -0
- package/dist/react/use-controller.js +18 -0
- package/dist/security/adapters/http.d.ts +16 -0
- package/dist/security/adapters/http.js +94 -0
- package/dist/security/adapters/memory.d.ts +15 -0
- package/dist/security/adapters/memory.js +60 -0
- package/dist/security/conformance/security-api.conformance.d.ts +10 -0
- package/dist/security/conformance/security-api.conformance.js +48 -0
- package/dist/security/controllers/access-tokens.controller.d.ts +44 -0
- package/dist/security/controllers/access-tokens.controller.js +112 -0
- package/dist/security/controllers/other-credentials.controller.d.ts +30 -0
- package/dist/security/controllers/other-credentials.controller.js +74 -0
- package/dist/security/controllers/root-key.controller.d.ts +35 -0
- package/dist/security/controllers/root-key.controller.js +90 -0
- package/dist/security/index.d.ts +9 -0
- package/dist/security/index.js +9 -0
- package/dist/security/messages.en.d.ts +12 -0
- package/dist/security/messages.en.js +2 -0
- package/dist/security/models.d.ts +112 -0
- package/dist/security/models.js +2 -0
- package/dist/security/ports.d.ts +58 -0
- package/dist/security/ports.js +5 -0
- package/dist/security/react/components/CredentialEditor.d.ts +3 -0
- package/dist/security/react/components/CredentialEditor.js +8 -0
- package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +94 -0
- package/dist/security/react/hooks/AccessTokensTab.hooks.js +36 -0
- package/dist/security/react/hooks/CredentialEditor.hooks.d.ts +49 -0
- package/dist/security/react/hooks/CredentialEditor.hooks.js +14 -0
- package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +29 -0
- package/dist/security/react/hooks/RootKeyTab.hooks.js +19 -0
- package/dist/security/react/hooks/SecurityPage.hooks.d.ts +17 -0
- package/dist/security/react/hooks/SecurityPage.hooks.js +12 -0
- package/dist/security/react/hooks/SecurityPorts.hooks.d.ts +9 -0
- package/dist/security/react/hooks/SecurityPorts.hooks.js +6 -0
- package/dist/security/react/index.d.ts +215 -0
- package/dist/security/react/index.js +10 -0
- package/dist/security/react/pages/SecurityPage.d.ts +4 -0
- package/dist/security/react/pages/SecurityPage.js +10 -0
- package/dist/security/react/tabs/AccessTokensTab.d.ts +4 -0
- package/dist/security/react/tabs/AccessTokensTab.js +10 -0
- package/dist/security/react/tabs/RootKeyTab.d.ts +4 -0
- package/dist/security/react/tabs/RootKeyTab.js +9 -0
- package/dist/security/rules.d.ts +57 -0
- package/dist/security/rules.js +63 -0
- package/dist/security/security.module.d.ts +45 -0
- package/dist/security/security.module.js +5 -0
- package/dist/source-control/adapters/http.d.ts +6 -0
- package/dist/source-control/adapters/http.js +13 -0
- package/dist/source-control/adapters/memory.d.ts +9 -0
- package/dist/source-control/adapters/memory.js +35 -0
- package/dist/source-control/conformance/source-control-api.conformance.d.ts +10 -0
- package/dist/source-control/conformance/source-control-api.conformance.js +48 -0
- package/dist/source-control/controllers/source-control.controller.d.ts +26 -0
- package/dist/source-control/controllers/source-control.controller.js +70 -0
- package/dist/source-control/index.d.ts +8 -0
- package/dist/source-control/index.js +6 -0
- package/dist/source-control/messages.en.d.ts +11 -0
- package/dist/source-control/messages.en.js +2 -0
- package/dist/source-control/models.d.ts +70 -0
- package/dist/source-control/models.js +2 -0
- package/dist/source-control/ports.d.ts +23 -0
- package/dist/source-control/ports.js +3 -0
- package/dist/source-control/react/components/SourceControlCredentialFields.d.ts +5 -0
- package/dist/source-control/react/components/SourceControlCredentialFields.js +8 -0
- package/dist/source-control/react/components/SourceControlProviderRow.d.ts +5 -0
- package/dist/source-control/react/components/SourceControlProviderRow.js +7 -0
- package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +45 -0
- package/dist/source-control/react/hooks/ProvidersTab.hooks.js +20 -0
- package/dist/source-control/react/hooks/SourceControlCredentialFields.hooks.d.ts +43 -0
- package/dist/source-control/react/hooks/SourceControlCredentialFields.hooks.js +9 -0
- package/dist/source-control/react/hooks/SourceControlPage.hooks.d.ts +17 -0
- package/dist/source-control/react/hooks/SourceControlPage.hooks.js +5 -0
- package/dist/source-control/react/hooks/SourceControlPorts.hooks.d.ts +9 -0
- package/dist/source-control/react/hooks/SourceControlPorts.hooks.js +6 -0
- package/dist/source-control/react/index.d.ts +156 -0
- package/dist/source-control/react/index.js +10 -0
- package/dist/source-control/react/pages/SourceControlPage.d.ts +4 -0
- package/dist/source-control/react/pages/SourceControlPage.js +11 -0
- package/dist/source-control/react/tabs/ProvidersTab.d.ts +4 -0
- package/dist/source-control/react/tabs/ProvidersTab.js +10 -0
- package/dist/source-control/rules.d.ts +32 -0
- package/dist/source-control/rules.js +35 -0
- package/dist/source-control/source-control.module.d.ts +36 -0
- package/dist/source-control/source-control.module.js +6 -0
- package/package.json +207 -4
|
@@ -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
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { OtherCredentialsPort } from '../ports.js';
|
|
2
|
+
import type { OtherCredentialSummary } from '../models.js';
|
|
3
|
+
export declare function createOtherCredentialsController({ api, permissions }: {
|
|
4
|
+
api: OtherCredentialsPort;
|
|
5
|
+
permissions?: readonly string[];
|
|
6
|
+
}, _optional?: {}): {
|
|
7
|
+
getSnapshot: () => Readonly<{
|
|
8
|
+
rows: readonly OtherCredentialSummary[];
|
|
9
|
+
drafts: Readonly<Record<string, string>>;
|
|
10
|
+
errors: Readonly<Record<string, string>>;
|
|
11
|
+
loading: boolean;
|
|
12
|
+
saving: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
subscribe: ({ listener }: {
|
|
15
|
+
listener: () => void;
|
|
16
|
+
}) => () => void;
|
|
17
|
+
load: (_required: Record<string, never>, _optional?: {}) => Promise<void>;
|
|
18
|
+
setDraft({ key, token }: {
|
|
19
|
+
key: string;
|
|
20
|
+
token: string;
|
|
21
|
+
}, _optional?: {}): void;
|
|
22
|
+
replace({ row }: {
|
|
23
|
+
row: OtherCredentialSummary;
|
|
24
|
+
}, _optional?: {}): Promise<boolean>;
|
|
25
|
+
remove({ row }: {
|
|
26
|
+
row: OtherCredentialSummary;
|
|
27
|
+
}, _optional?: {}): Promise<boolean>;
|
|
28
|
+
dispose(_required?: Record<string, never>, _optional?: {}): void;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=other-credentials.controller.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createControllerStore } from '../../core/module/controller-store.js';
|
|
2
|
+
import { OTHER_STORES, otherWritePermission } from '../rules.js';
|
|
3
|
+
export function createOtherCredentialsController({ api, permissions = [] }, _optional = {}) {
|
|
4
|
+
const grants = new Set(permissions);
|
|
5
|
+
let generation = 0;
|
|
6
|
+
const store = createControllerStore({ initial: { rows: [], drafts: {}, errors: {}, loading: false, saving: false } });
|
|
7
|
+
async function read(id, ticket) {
|
|
8
|
+
try {
|
|
9
|
+
const rows = await api.list({ store: id }, { signal: store.signal });
|
|
10
|
+
if (ticket === generation) {
|
|
11
|
+
const errors = { ...store.getSnapshot().errors };
|
|
12
|
+
delete errors[id];
|
|
13
|
+
store.set({ patch: { rows: [...store.getSnapshot().rows.filter(r => r.store !== id), ...rows], errors } });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
if (ticket === generation)
|
|
18
|
+
store.set({ patch: { errors: { ...store.getSnapshot().errors, [id]: 'Credential store unavailable' } } });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function load(_required, _optional = {}) {
|
|
22
|
+
if (store.signal.aborted || !grants.has('security.read'))
|
|
23
|
+
return;
|
|
24
|
+
const ticket = ++generation;
|
|
25
|
+
store.set({ patch: { loading: true } });
|
|
26
|
+
await Promise.all(OTHER_STORES.map(id => read(id, ticket)));
|
|
27
|
+
if (ticket === generation)
|
|
28
|
+
store.set({ patch: { loading: false } });
|
|
29
|
+
}
|
|
30
|
+
// One serial lane: whole-map media writes must read only after the previous write/refetch settled.
|
|
31
|
+
// This is tab-local; cross-session races still require a server concurrency check.
|
|
32
|
+
let lane = Promise.resolve();
|
|
33
|
+
function write(row, remove) {
|
|
34
|
+
if (store.signal.aborted || !grants.has('security.read') || !grants.has(otherWritePermission({ store: row.store })) || (!remove && !row.supportsReplace))
|
|
35
|
+
return Promise.resolve(false);
|
|
36
|
+
const token = store.getSnapshot().drafts[`${row.store}:${row.id}`]?.trim() ?? '';
|
|
37
|
+
if (!remove && !token)
|
|
38
|
+
return Promise.resolve(false);
|
|
39
|
+
const run = lane.then(async () => {
|
|
40
|
+
if (store.signal.aborted)
|
|
41
|
+
return false;
|
|
42
|
+
store.set({ patch: { saving: true } });
|
|
43
|
+
try {
|
|
44
|
+
if (remove)
|
|
45
|
+
await api.remove({ store: row.store, id: row.id }, { signal: store.signal });
|
|
46
|
+
else
|
|
47
|
+
await api.replace({ store: row.store, id: row.id, token }, { signal: store.signal });
|
|
48
|
+
const drafts = { ...store.getSnapshot().drafts };
|
|
49
|
+
delete drafts[`${row.store}:${row.id}`];
|
|
50
|
+
store.set({ patch: { drafts } });
|
|
51
|
+
await read(row.store, generation);
|
|
52
|
+
return !store.signal.aborted;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
store.set({ patch: { errors: { ...store.getSnapshot().errors, [row.store]: 'Unable to update credential' } } });
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
store.set({ patch: { saving: false } });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
lane = run.then(() => undefined);
|
|
63
|
+
return run;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load,
|
|
67
|
+
setDraft({ key, token }, _optional = {}) { if (!store.signal.aborted && !store.getSnapshot().saving)
|
|
68
|
+
store.set({ patch: { drafts: { ...store.getSnapshot().drafts, [key]: token } } }); },
|
|
69
|
+
replace({ row }, _optional = {}) { return write(row, false); },
|
|
70
|
+
remove({ row }, _optional = {}) { return write(row, true); },
|
|
71
|
+
dispose(_required = {}, _optional = {}) { generation++; store.dispose(); },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=other-credentials.controller.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RootKeyPort } from '../ports.js';
|
|
2
|
+
import type { RootKeyStatus, RootKeyPreview } from '../models.js';
|
|
3
|
+
export declare function createRootKeyController({ api, permissions }: {
|
|
4
|
+
api: RootKeyPort;
|
|
5
|
+
permissions?: readonly string[];
|
|
6
|
+
}, _optional?: {}): {
|
|
7
|
+
getSnapshot: () => Readonly<{
|
|
8
|
+
status: RootKeyStatus | null;
|
|
9
|
+
preview: RootKeyPreview | null;
|
|
10
|
+
token: string;
|
|
11
|
+
confirm: string;
|
|
12
|
+
loading: boolean;
|
|
13
|
+
saving: boolean;
|
|
14
|
+
error: string | null;
|
|
15
|
+
result: string | null;
|
|
16
|
+
confirming: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
subscribe: ({ listener }: {
|
|
19
|
+
listener: () => void;
|
|
20
|
+
}) => () => void;
|
|
21
|
+
load: (_required: Record<string, never>, _optional?: {}) => Promise<void>;
|
|
22
|
+
setToken({ value }: {
|
|
23
|
+
value: string;
|
|
24
|
+
}, _optional?: {}): void;
|
|
25
|
+
setConfirm({ value }: {
|
|
26
|
+
value: string;
|
|
27
|
+
}, _optional?: {}): void;
|
|
28
|
+
generate(_required: Record<string, never>, _optional?: {}): Promise<boolean>;
|
|
29
|
+
importToken(_required: Record<string, never>, _optional?: {}): Promise<boolean>;
|
|
30
|
+
preview(_required: Record<string, never>, _optional?: {}): Promise<boolean>;
|
|
31
|
+
startFresh(_required: Record<string, never>, _optional?: {}): Promise<boolean>;
|
|
32
|
+
cancel(_required: Record<string, never>, _optional?: {}): void;
|
|
33
|
+
dispose(_required?: Record<string, never>, _optional?: {}): void;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=root-key.controller.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createControllerStore } from '../../core/module/controller-store.js';
|
|
2
|
+
import { ROOT_KEY_PERMISSION, START_FRESH_CONFIRMATION, isRootKeyLocked } from '../rules.js';
|
|
3
|
+
export function createRootKeyController({ api, permissions = [] }, _optional = {}) {
|
|
4
|
+
const granted = permissions.includes(ROOT_KEY_PERMISSION);
|
|
5
|
+
const store = createControllerStore({ initial: { status: null, preview: null, token: '', confirm: '', loading: false, saving: false, error: null, result: null, confirming: false } });
|
|
6
|
+
let generation = 0;
|
|
7
|
+
const allowed = () => granted && !store.signal.aborted;
|
|
8
|
+
async function load(_required, _optional = {}) {
|
|
9
|
+
if (!allowed())
|
|
10
|
+
return;
|
|
11
|
+
const ticket = ++generation;
|
|
12
|
+
store.set({ patch: { loading: true } });
|
|
13
|
+
try {
|
|
14
|
+
const status = await api.status({}, { signal: store.signal });
|
|
15
|
+
if (ticket === generation)
|
|
16
|
+
store.set({ patch: { status, error: null } });
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
if (ticket === generation)
|
|
20
|
+
store.set({ patch: { error: 'Root key status unavailable' } });
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
if (ticket === generation)
|
|
24
|
+
store.set({ patch: { loading: false } });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function execute(run, result) {
|
|
28
|
+
if (!allowed() || store.getSnapshot().saving)
|
|
29
|
+
return false;
|
|
30
|
+
store.set({ patch: { saving: true, error: null } });
|
|
31
|
+
try {
|
|
32
|
+
const response = await run();
|
|
33
|
+
store.set({ patch: { token: '', confirm: '', preview: null, confirming: false, result: response.affectedWebhooks?.length ? `${result} Update receivers: ${response.affectedWebhooks.map(w => `${w.label} (${w.targetUrl})`).join(', ')}` : result } });
|
|
34
|
+
await load({});
|
|
35
|
+
return !store.signal.aborted;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
store.set({ patch: { error: 'Recovery refused. Check the host key configuration.' } });
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
store.set({ patch: { saving: false } });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load,
|
|
47
|
+
setToken({ value }, _optional = {}) { if (allowed() && !store.getSnapshot().saving)
|
|
48
|
+
store.set({ patch: { token: value } }); },
|
|
49
|
+
setConfirm({ value }, _optional = {}) { if (allowed() && !store.getSnapshot().saving)
|
|
50
|
+
store.set({ patch: { confirm: value } }); },
|
|
51
|
+
generate(_required, _optional = {}) {
|
|
52
|
+
const status = store.getSnapshot().status;
|
|
53
|
+
// No rotate/replace: replacing an active key would orphan every secret sealed under it.
|
|
54
|
+
if (!status || status.active || status.state !== 'missing')
|
|
55
|
+
return Promise.resolve(false);
|
|
56
|
+
return execute(() => api.generate({}, { signal: store.signal }), 'Root key ready');
|
|
57
|
+
},
|
|
58
|
+
importToken(_required, _optional = {}) { const token = store.getSnapshot().token.trim(); return token && isRootKeyLocked({ status: store.getSnapshot().status }) ? execute(() => api.importToken({ token }, { signal: store.signal }), 'Unlocked. Saved credentials work again.') : Promise.resolve(false); },
|
|
59
|
+
async preview(_required, _optional = {}) {
|
|
60
|
+
if (!allowed() || !isRootKeyLocked({ status: store.getSnapshot().status }) || store.getSnapshot().saving || store.getSnapshot().loading)
|
|
61
|
+
return false;
|
|
62
|
+
const ticket = ++generation;
|
|
63
|
+
store.set({ patch: { loading: true, preview: null, confirm: '', error: null } });
|
|
64
|
+
try {
|
|
65
|
+
const preview = await api.previewStartFresh({}, { signal: store.signal });
|
|
66
|
+
if (ticket !== generation || !allowed())
|
|
67
|
+
return false;
|
|
68
|
+
store.set({ patch: { preview, confirming: true } });
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
if (ticket === generation)
|
|
73
|
+
store.set({ patch: { error: 'Recovery preview unavailable' } });
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
if (ticket === generation)
|
|
78
|
+
store.set({ patch: { loading: false } });
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
startFresh(_required, _optional = {}) { const state = store.getSnapshot(); if (!isRootKeyLocked({ status: state.status }) || !state.preview || !state.confirming || state.confirm !== START_FRESH_CONFIRMATION)
|
|
82
|
+
return Promise.resolve(false); return execute(() => api.startFresh({ confirm: state.confirm }, { signal: store.signal }), 'Done. Re-enter removed credentials.'); },
|
|
83
|
+
cancel(_required, _optional = {}) { if (!store.getSnapshot().saving) {
|
|
84
|
+
generation++;
|
|
85
|
+
store.set({ patch: { confirming: false, preview: null, confirm: '', loading: false } });
|
|
86
|
+
} },
|
|
87
|
+
dispose(_required = {}, _optional = {}) { generation++; store.dispose(); },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=root-key.controller.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { securityModule } from './security.module.js';
|
|
2
|
+
export * from './models.js';
|
|
3
|
+
export * from './ports.js';
|
|
4
|
+
export * from './rules.js';
|
|
5
|
+
export { securityMessagesEn } from './messages.en.js';
|
|
6
|
+
export { createAccessTokensController } from './controllers/access-tokens.controller.js';
|
|
7
|
+
export { createOtherCredentialsController } from './controllers/other-credentials.controller.js';
|
|
8
|
+
export { createRootKeyController } from './controllers/root-key.controller.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { securityModule } from './security.module.js';
|
|
2
|
+
export * from './models.js';
|
|
3
|
+
export * from './ports.js';
|
|
4
|
+
export * from './rules.js';
|
|
5
|
+
export { securityMessagesEn } from './messages.en.js';
|
|
6
|
+
export { createAccessTokensController } from './controllers/access-tokens.controller.js';
|
|
7
|
+
export { createOtherCredentialsController } from './controllers/other-credentials.controller.js';
|
|
8
|
+
export { createRootKeyController } from './controllers/root-key.controller.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const securityMessagesEn: {
|
|
2
|
+
readonly security: "Secrets";
|
|
3
|
+
readonly accessTokens: "Access tokens";
|
|
4
|
+
readonly rootKey: "Root key";
|
|
5
|
+
readonly denied: "Permission denied";
|
|
6
|
+
readonly loading: "Loading credentials…";
|
|
7
|
+
readonly remove: "Remove credential";
|
|
8
|
+
readonly replace: "Replace";
|
|
9
|
+
readonly save: "Save";
|
|
10
|
+
readonly cancel: "Cancel";
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=messages.en.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export const securityMessagesEn = { security: 'Secrets', accessTokens: 'Access tokens', rootKey: 'Root key', denied: 'Permission denied', loading: 'Loading credentials…', remove: 'Remove credential', replace: 'Replace', save: 'Save', cancel: 'Cancel' };
|
|
2
|
+
//# sourceMappingURL=messages.en.js.map
|