@k2b/cloud 0.6.0-rc.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/README.md +98 -0
- package/package.json +128 -0
- package/public/logo.svg +1 -0
- package/scripts/app-favicon.test.ts +49 -0
- package/scripts/app-favicon.ts +51 -0
- package/scripts/build.ts +205 -0
- package/scripts/preload.ts +164 -0
- package/scripts/sync-recovery-smoke.ts +200 -0
- package/src/_internal/app-favicon.ts +2 -0
- package/src/_internal/app-presentation.ts +61 -0
- package/src/_internal/app-workspace-state.ts +24 -0
- package/src/_internal/bounded-json.ts +47 -0
- package/src/_internal/build-metadata.ts +9 -0
- package/src/_internal/capabilities.ts +1118 -0
- package/src/_internal/define-app.ts +801 -0
- package/src/_internal/heartbeat.ts +167 -0
- package/src/_internal/help-catalog.ts +241 -0
- package/src/_internal/help.ts +95 -0
- package/src/_internal/nats-connection.ts +34 -0
- package/src/_internal/page-responses.ts +40 -0
- package/src/_internal/process-sync.ts +117 -0
- package/src/_internal/readiness.ts +3 -0
- package/src/_internal/registry-validation.ts +136 -0
- package/src/_internal/registry-watch.ts +52 -0
- package/src/_internal/registry.ts +338 -0
- package/src/_internal/runtime-compatibility.ts +64 -0
- package/src/_internal/runtime-context.ts +84 -0
- package/src/_internal/runtime-watcher.ts +78 -0
- package/src/_internal/static-assets.ts +86 -0
- package/src/_internal/status-preserving-ssr.ts +49 -0
- package/src/access/PermissionEditor.tsx +486 -0
- package/src/access/ResourceApiKeys.tsx +271 -0
- package/src/access/messages.ts +121 -0
- package/src/access/ui.ts +16 -0
- package/src/account/Avatar.tsx +28 -0
- package/src/account/EntitySearch.tsx +363 -0
- package/src/account/avatar-upload-dialog.tsx +197 -0
- package/src/account/avatar-upload.ts +149 -0
- package/src/account/ui.ts +3 -0
- package/src/ai/admin.ts +47 -0
- package/src/ai/approval-routes.ts +130 -0
- package/src/ai/approvals.ts +139 -0
- package/src/ai/assistant-models.ts +61 -0
- package/src/ai/attachments.ts +40 -0
- package/src/ai/browser.ts +92 -0
- package/src/ai/capabilities.ts +714 -0
- package/src/ai/capability-execution.ts +151 -0
- package/src/ai/chat/blocks.render.test.tsx +1108 -0
- package/src/ai/chat/blocks.tsx +730 -0
- package/src/ai/chat/builtin-tools.tsx +428 -0
- package/src/ai/chat/capability-table.tsx +87 -0
- package/src/ai/chat/composer-adapter.ts +169 -0
- package/src/ai/chat/file-tools.tsx +81 -0
- package/src/ai/chat/message-actions.tsx +370 -0
- package/src/ai/chat/message-utils.ts +479 -0
- package/src/ai/chat/messages.ts +43 -0
- package/src/ai/chat/presentation.tsx +395 -0
- package/src/ai/chat/primitives.tsx +3 -0
- package/src/ai/chat/tool-disclosure.tsx +41 -0
- package/src/ai/chat/turn-navigator-utils.ts +28 -0
- package/src/ai/chat/turn-navigator.tsx +164 -0
- package/src/ai/chat/user-message.tsx +149 -0
- package/src/ai/chat/visual-tools.tsx +435 -0
- package/src/ai/chat/web-tools.tsx +202 -0
- package/src/ai/chat-task-contracts.ts +113 -0
- package/src/ai/chat-tasks.ts +952 -0
- package/src/ai/client/controller.ts +1211 -0
- package/src/ai/client/file-source.ts +95 -0
- package/src/ai/client/live-connection.ts +140 -0
- package/src/ai/client/projection.ts +178 -0
- package/src/ai/client/transport.ts +111 -0
- package/src/ai/compaction.ts +182 -0
- package/src/ai/credentials.ts +124 -0
- package/src/ai/default-tool-contracts.ts +108 -0
- package/src/ai/default-tools.ts +127 -0
- package/src/ai/enrich.ts +280 -0
- package/src/ai/executor.ts +1624 -0
- package/src/ai/fetch-file-tool.ts +313 -0
- package/src/ai/file-context.ts +92 -0
- package/src/ai/file-media-type.ts +28 -0
- package/src/ai/file-mount.ts +16 -0
- package/src/ai/file-tools.ts +566 -0
- package/src/ai/files-store.ts +390 -0
- package/src/ai/firecrawl-tools.ts +305 -0
- package/src/ai/grids-skill.ts +126 -0
- package/src/ai/http.ts +265 -0
- package/src/ai/index.ts +337 -0
- package/src/ai/kit-skill.ts +22 -0
- package/src/ai/limits.ts +5 -0
- package/src/ai/live-events.ts +289 -0
- package/src/ai/live-messages.ts +45 -0
- package/src/ai/live-outbox.ts +102 -0
- package/src/ai/live-routes.ts +412 -0
- package/src/ai/live.ts +2 -0
- package/src/ai/maintenance.ts +302 -0
- package/src/ai/markdown-pdf-tool.ts +95 -0
- package/src/ai/memories.ts +605 -0
- package/src/ai/memory-learning-runs.ts +222 -0
- package/src/ai/memory-learning.ts +619 -0
- package/src/ai/memory-tool.ts +120 -0
- package/src/ai/memory-workflow-evidence.ts +158 -0
- package/src/ai/migrate.ts +2082 -0
- package/src/ai/model-access-migrate.ts +30 -0
- package/src/ai/model-access.ts +191 -0
- package/src/ai/personal-agent.ts +6 -0
- package/src/ai/prefs.ts +72 -0
- package/src/ai/project-tool.ts +94 -0
- package/src/ai/projects-routes.ts +277 -0
- package/src/ai/projects.ts +902 -0
- package/src/ai/protocol.ts +279 -0
- package/src/ai/provider.ts +73 -0
- package/src/ai/public-projection.ts +25 -0
- package/src/ai/resource-markers.ts +31 -0
- package/src/ai/resource-refs.ts +70 -0
- package/src/ai/routes.ts +1131 -0
- package/src/ai/runtime-tools.ts +39 -0
- package/src/ai/runtime.ts +544 -0
- package/src/ai/settings.ts +529 -0
- package/src/ai/short-id.ts +45 -0
- package/src/ai/skill-catalog.ts +73 -0
- package/src/ai/skill-format.ts +145 -0
- package/src/ai/skill-seeds.ts +430 -0
- package/src/ai/skill-tool.ts +81 -0
- package/src/ai/skills-routes.ts +143 -0
- package/src/ai/skills.ts +934 -0
- package/src/ai/solid.ts +27 -0
- package/src/ai/store.ts +3113 -0
- package/src/ai/stream.ts +308 -0
- package/src/ai/structured-runs.ts +66 -0
- package/src/ai/structured.ts +186 -0
- package/src/ai/system-prompt.ts +170 -0
- package/src/ai/task-prompt.ts +22 -0
- package/src/ai/timeline.ts +148 -0
- package/src/ai/tool-audit.ts +177 -0
- package/src/ai/tool-result-budget.ts +16 -0
- package/src/ai/tools.ts +155 -0
- package/src/ai/types.ts +967 -0
- package/src/ai/ui.tsx +39 -0
- package/src/ai/usage-migrate.ts +81 -0
- package/src/ai/usage.ts +315 -0
- package/src/ai/validate.ts +54 -0
- package/src/ai/vision-tool.ts +79 -0
- package/src/api/accounts-entities.ts +174 -0
- package/src/api/admin-ai-projects.ts +74 -0
- package/src/api/admin-ai-skills.ts +76 -0
- package/src/api/admin-ai-usage.ts +42 -0
- package/src/api/admin-core-settings.ts +508 -0
- package/src/api/admin-identity.ts +148 -0
- package/src/api/admin-lifecycle.ts +206 -0
- package/src/api/admin-linux-identities.ts +66 -0
- package/src/api/announcements.ts +131 -0
- package/src/api/app-approval.ts +129 -0
- package/src/api/apps.ts +51 -0
- package/src/api/auth/schemas.ts +54 -0
- package/src/api/auth.ts +370 -0
- package/src/api/capabilities.ts +658 -0
- package/src/api/help-messages.ts +19 -0
- package/src/api/help.ts +78 -0
- package/src/api/index.ts +108 -0
- package/src/api/mcp.ts +744 -0
- package/src/api/me-rail.ts +45 -0
- package/src/api/me.ts +753 -0
- package/src/api/search/schemas.ts +79 -0
- package/src/api/search.bench.ts +185 -0
- package/src/api/search.ts +407 -0
- package/src/api/sync-ops.ts +79 -0
- package/src/api/widgets.ts +143 -0
- package/src/browser/CloudResourceSearch.behavior.test.tsx +74 -0
- package/src/browser/CloudResourceSearch.tsx +791 -0
- package/src/browser/app-approval-vault.ts +305 -0
- package/src/browser/app-approval.ts +234 -0
- package/src/browser/live-websocket.ts +268 -0
- package/src/browser/locale-preference.ts +25 -0
- package/src/browser/notification-target.ts +27 -0
- package/src/browser/notification-timeout.ts +14 -0
- package/src/browser/notifications.ts +181 -0
- package/src/browser/resource-clipboard.ts +70 -0
- package/src/browser/resource-picker.tsx +39 -0
- package/src/browser/resource-search-messages.ts +55 -0
- package/src/browser/resource-search.ts +27 -0
- package/src/capabilities/client.ts +149 -0
- package/src/capabilities/response.ts +39 -0
- package/src/capabilities/server.ts +215 -0
- package/src/capabilities/signals.ts +4 -0
- package/src/capabilities/testing.ts +12 -0
- package/src/capabilities/types.ts +32 -0
- package/src/cli/access.ts +499 -0
- package/src/cli/account.ts +382 -0
- package/src/cli/admin/account-administration.ts +45 -0
- package/src/cli/admin/account-categories.ts +49 -0
- package/src/cli/admin/ai-usage.ts +118 -0
- package/src/cli/admin/app-sign-in.ts +49 -0
- package/src/cli/admin/data.ts +343 -0
- package/src/cli/admin/documentation.ts +34 -0
- package/src/cli/admin/gateway.ts +155 -0
- package/src/cli/admin/index.ts +61 -0
- package/src/cli/admin/instance.ts +250 -0
- package/src/cli/admin/jobs.ts +223 -0
- package/src/cli/admin/legal.ts +122 -0
- package/src/cli/admin/linux.ts +53 -0
- package/src/cli/admin/logs.ts +324 -0
- package/src/cli/admin/metrics.ts +142 -0
- package/src/cli/admin/nats.ts +167 -0
- package/src/cli/admin/notifications.ts +516 -0
- package/src/cli/admin/shared.ts +113 -0
- package/src/cli/admin/sync.ts +188 -0
- package/src/cli/admin/telemetry.ts +314 -0
- package/src/cli/admin/webhooks.ts +222 -0
- package/src/cli/admin/workflows.ts +367 -0
- package/src/cli/apps.ts +40 -0
- package/src/cli/capabilities.ts +239 -0
- package/src/cli/commands.ts +604 -0
- package/src/cli/index.ts +61 -0
- package/src/cli/locale.ts +31 -0
- package/src/cli/output.ts +58 -0
- package/src/clients/core.ts +20 -0
- package/src/config/env.ts +54 -0
- package/src/config/index.ts +6 -0
- package/src/contracts/account-categories.ts +62 -0
- package/src/contracts/announcements.ts +121 -0
- package/src/contracts/app-approval.ts +197 -0
- package/src/contracts/app.ts +162 -0
- package/src/contracts/capabilities.ts +484 -0
- package/src/contracts/index.ts +14 -0
- package/src/contracts/notification-live.ts +66 -0
- package/src/contracts/notification-types.ts +235 -0
- package/src/contracts/posix.ts +69 -0
- package/src/contracts/profile.ts +85 -0
- package/src/contracts/rail-preferences.ts +53 -0
- package/src/contracts/registry.ts +110 -0
- package/src/contracts/resource-clipboard.ts +33 -0
- package/src/contracts/settings-types.ts +98 -0
- package/src/contracts/shared.ts +408 -0
- package/src/contracts/user-notifications.ts +101 -0
- package/src/contracts/widgets.ts +183 -0
- package/src/desktop/index.ts +704 -0
- package/src/desktop/solid.tsx +938 -0
- package/src/index.ts +58 -0
- package/src/server/actor.ts +41 -0
- package/src/server/api/index.ts +2 -0
- package/src/server/api/respond.ts +96 -0
- package/src/server/api-client.ts +54 -0
- package/src/server/app-context.ts +39 -0
- package/src/server/help.ts +187 -0
- package/src/server/index.ts +89 -0
- package/src/server/locale.ts +55 -0
- package/src/server/middleware/auth.ts +386 -0
- package/src/server/middleware/index.ts +28 -0
- package/src/server/middleware/invocation.ts +55 -0
- package/src/server/middleware/middleware.ts +65 -0
- package/src/server/middleware/openapi.ts +126 -0
- package/src/server/middleware/rate-limit.ts +125 -0
- package/src/server/middleware/request-logger.ts +41 -0
- package/src/server/middleware/route-template.ts +46 -0
- package/src/server/middleware/runtime.ts +22 -0
- package/src/server/middleware/settings.ts +55 -0
- package/src/server/middleware/validator.ts +49 -0
- package/src/server/middleware/workload.ts +22 -0
- package/src/server/ratelimit.ts +151 -0
- package/src/server/request-cookies.ts +18 -0
- package/src/server/services/access.ts +644 -0
- package/src/server/services/freeipa/client.ts +137 -0
- package/src/server/services/freeipa/index.ts +9 -0
- package/src/server/services/freeipa/session.ts +123 -0
- package/src/server/services/freeipa/test-certificates.ts +44 -0
- package/src/server/services/freeipa/tls.ts +44 -0
- package/src/server/services/freeipa/transport.ts +116 -0
- package/src/server/services/freeipa/util.ts +59 -0
- package/src/server/services/geo.ts +198 -0
- package/src/server/services/index.ts +48 -0
- package/src/server/services/pagination.ts +22 -0
- package/src/server/services/services.ts +13 -0
- package/src/server/time.ts +33 -0
- package/src/services/account-category-policy.ts +51 -0
- package/src/services/account-lifecycle/audit.ts +41 -0
- package/src/services/account-lifecycle/index.ts +940 -0
- package/src/services/account-lifecycle/ipa-backfill.ts +152 -0
- package/src/services/account-lifecycle/notification-sender.ts +13 -0
- package/src/services/account-lifecycle/scheduler.ts +506 -0
- package/src/services/account-model.ts +22 -0
- package/src/services/accounts/app.ts +1671 -0
- package/src/services/accounts/authz.ts +44 -0
- package/src/services/accounts/avatar.ts +120 -0
- package/src/services/accounts/base-group.ts +11 -0
- package/src/services/accounts/base-user.ts +46 -0
- package/src/services/accounts/duplicate-emails.ts +82 -0
- package/src/services/accounts/entities.ts +622 -0
- package/src/services/accounts/group-sql.ts +106 -0
- package/src/services/accounts/groups.ts +272 -0
- package/src/services/accounts/index.ts +14 -0
- package/src/services/accounts/ipa-data.ts +66 -0
- package/src/services/accounts/lifecycle.ts +2 -0
- package/src/services/accounts/local-groups.ts +499 -0
- package/src/services/accounts/model.ts +129 -0
- package/src/services/accounts/notification-sender.ts +31 -0
- package/src/services/accounts/posix.ts +386 -0
- package/src/services/accounts/request-policy.ts +11 -0
- package/src/services/accounts/switching.ts +126 -0
- package/src/services/accounts/users.ts +745 -0
- package/src/services/announcements/index.ts +224 -0
- package/src/services/app-approval.ts +498 -0
- package/src/services/audit/index.ts +438 -0
- package/src/services/auth-flows/index.ts +15 -0
- package/src/services/auth-flows/ipa.ts +197 -0
- package/src/services/auth-flows/magic-link.ts +185 -0
- package/src/services/auth-flows/notification-sender.ts +10 -0
- package/src/services/auth-flows/password-reset.ts +268 -0
- package/src/services/auth-flows/proxy-return.ts +49 -0
- package/src/services/document-extraction.ts +148 -0
- package/src/services/freeipa-config.ts +179 -0
- package/src/services/gateway.ts +186 -0
- package/src/services/identity/constants.ts +18 -0
- package/src/services/identity/index.ts +52 -0
- package/src/services/identity/invocation-actor.ts +120 -0
- package/src/services/identity/invocation-authority.ts +53 -0
- package/src/services/identity/invocation-operations.ts +15 -0
- package/src/services/identity/invocation-token.ts +276 -0
- package/src/services/identity/key-config.ts +41 -0
- package/src/services/identity/key-ring.ts +530 -0
- package/src/services/identity/metrics.ts +29 -0
- package/src/services/identity/routes.ts +18 -0
- package/src/services/identity/runtime-config.ts +88 -0
- package/src/services/identity/session-token.ts +152 -0
- package/src/services/identity/signer-refresh.ts +44 -0
- package/src/services/identity/workload-auth.ts +64 -0
- package/src/services/index.ts +187 -0
- package/src/services/ipa/auth.ts +216 -0
- package/src/services/ipa/connection.ts +57 -0
- package/src/services/ipa/effective-groups.ts +70 -0
- package/src/services/ipa/groups.ts +722 -0
- package/src/services/ipa/guard.ts +17 -0
- package/src/services/ipa/index.ts +17 -0
- package/src/services/ipa/posix.ts +19 -0
- package/src/services/ipa/profile.ts +132 -0
- package/src/services/ipa/runtime.ts +28 -0
- package/src/services/ipa/search.ts +154 -0
- package/src/services/ipa/service-account.ts +15 -0
- package/src/services/ipa/sync-planning.ts +100 -0
- package/src/services/ipa/sync.ts +862 -0
- package/src/services/ipa/users.ts +806 -0
- package/src/services/legal-consent.ts +76 -0
- package/src/services/logging/index.ts +477 -0
- package/src/services/logging/redaction.ts +20 -0
- package/src/services/logging/trace.ts +1231 -0
- package/src/services/mandates/index.ts +855 -0
- package/src/services/mandates/policy.ts +85 -0
- package/src/services/network-security.ts +31 -0
- package/src/services/notifications/batches.ts +722 -0
- package/src/services/notifications/browser.ts +252 -0
- package/src/services/notifications/catalog.ts +113 -0
- package/src/services/notifications/channels.ts +104 -0
- package/src/services/notifications/dispatcher.ts +139 -0
- package/src/services/notifications/email.ts +118 -0
- package/src/services/notifications/index.ts +633 -0
- package/src/services/notifications/live.ts +50 -0
- package/src/services/notifications/observability.ts +407 -0
- package/src/services/notifications/platform.ts +421 -0
- package/src/services/notifications/runtime.ts +120 -0
- package/src/services/notifications/user.ts +248 -0
- package/src/services/notifications/web-push-transport.ts +135 -0
- package/src/services/oauth-tokens.ts +209 -0
- package/src/services/outbox.ts +187 -0
- package/src/services/pdf/gotenberg.ts +290 -0
- package/src/services/pdf/index.ts +43 -0
- package/src/services/pdf/markdown.ts +209 -0
- package/src/services/pdf/template-preview.ts +122 -0
- package/src/services/postgres.ts +76 -0
- package/src/services/providers/index.ts +27 -0
- package/src/services/providers/local/auth.ts +51 -0
- package/src/services/providers/local/index.ts +4 -0
- package/src/services/providers/local/users.ts +263 -0
- package/src/services/rail-preferences.ts +27 -0
- package/src/services/runtime-lifecycle.ts +191 -0
- package/src/services/secrets.ts +10 -0
- package/src/services/service-account-credentials.ts +891 -0
- package/src/services/service-accounts.ts +184 -0
- package/src/services/session/index.ts +236 -0
- package/src/services/session/test-fixture.ts +18 -0
- package/src/services/session/user.ts +144 -0
- package/src/services/settings/api.ts +61 -0
- package/src/services/settings/app.ts +86 -0
- package/src/services/settings/core-settings.ts +796 -0
- package/src/services/settings/crypto.ts +69 -0
- package/src/services/settings/defaults.ts +374 -0
- package/src/services/settings/index.ts +215 -0
- package/src/services/settings/namespace.ts +9 -0
- package/src/services/settings/snapshot.ts +49 -0
- package/src/services/settings/store.ts +241 -0
- package/src/services/settings/templates.ts +4 -0
- package/src/services/sync-ops.ts +403 -0
- package/src/services/topic-cursor.ts +22 -0
- package/src/services/weather/forecast.ts +323 -0
- package/src/services/weather/geo.ts +119 -0
- package/src/services/weather/index.ts +67 -0
- package/src/services/weather/location.ts +24 -0
- package/src/services/weather/locations.ts +133 -0
- package/src/services/weather/migrate.ts +45 -0
- package/src/services/weather/settings.ts +66 -0
- package/src/services/weather/short-id.ts +57 -0
- package/src/services/weather/types.ts +61 -0
- package/src/services/weather/ui.ts +50 -0
- package/src/services/webauthn.ts +385 -0
- package/src/shared/account-action-notice.ts +70 -0
- package/src/shared/account-display.ts +15 -0
- package/src/shared/account-session.ts +15 -0
- package/src/shared/ai-platform-prompt.ts +134 -0
- package/src/shared/ai-usage.ts +49 -0
- package/src/shared/app-presentation.ts +48 -0
- package/src/shared/app-url.ts +12 -0
- package/src/shared/branding.ts +14 -0
- package/src/shared/capability-messages.ts +70 -0
- package/src/shared/email-html.ts +54 -0
- package/src/shared/format.ts +91 -0
- package/src/shared/help.ts +68 -0
- package/src/shared/icons.ts +400 -0
- package/src/shared/index.ts +54 -0
- package/src/shared/locale.ts +48 -0
- package/src/shared/login-method.ts +44 -0
- package/src/shared/markdown/client.ts +130 -0
- package/src/shared/markdown/extensions/code.ts +105 -0
- package/src/shared/markdown/extensions/guided-help.ts +100 -0
- package/src/shared/markdown/extensions/images.ts +79 -0
- package/src/shared/markdown/extensions/info-blocks.ts +97 -0
- package/src/shared/markdown/extensions/katex.ts +120 -0
- package/src/shared/markdown/extensions/links.ts +43 -0
- package/src/shared/markdown/extensions/mark.ts +48 -0
- package/src/shared/markdown/extensions/sub-sup.ts +60 -0
- package/src/shared/markdown/extensions/tables.ts +109 -0
- package/src/shared/markdown/extensions/task-list.ts +53 -0
- package/src/shared/markdown/formula.ts +1187 -0
- package/src/shared/markdown/index.ts +193 -0
- package/src/shared/markdown/shared.ts +36 -0
- package/src/shared/mock-cover.ts +130 -0
- package/src/shared/network-address.ts +106 -0
- package/src/shared/redirect.ts +56 -0
- package/src/shared/template-rendering.ts +140 -0
- package/src/shared/theme.ts +68 -0
- package/src/shared/time.ts +13 -0
- package/src/ssr/AdminLayout.tsx +53 -0
- package/src/ssr/AdminSidebar.tsx +50 -0
- package/src/ssr/AppLaunchpad.island.tsx +236 -0
- package/src/ssr/AppWorkspaceController.island.tsx +21 -0
- package/src/ssr/BrowserNotifications.island.tsx +135 -0
- package/src/ssr/GlobalAnnouncements.island.tsx +142 -0
- package/src/ssr/GlobalSearchDialog.behavior.test.tsx +96 -0
- package/src/ssr/GlobalSearchDialog.tsx +35 -0
- package/src/ssr/GlobalSearchHelpDialog.tsx +104 -0
- package/src/ssr/GlobalSearchTrigger.island.tsx +55 -0
- package/src/ssr/HotkeysHelpRail.island.tsx +55 -0
- package/src/ssr/Layout.render.test.tsx +148 -0
- package/src/ssr/Layout.tsx +292 -0
- package/src/ssr/LayoutBreadcrumbs.island.tsx +44 -0
- package/src/ssr/LayoutFooter.tsx +22 -0
- package/src/ssr/LayoutHeader.tsx +81 -0
- package/src/ssr/LayoutHelp.tsx +869 -0
- package/src/ssr/LayoutPreferences.island.tsx +36 -0
- package/src/ssr/LayoutRail.tsx +58 -0
- package/src/ssr/MinimalLayout.tsx +46 -0
- package/src/ssr/PageError.tsx +29 -0
- package/src/ssr/ProfilePreferences.island.tsx +92 -0
- package/src/ssr/RailApps.island.tsx +61 -0
- package/src/ssr/RailEditor.tsx +293 -0
- package/src/ssr/RegisteredHelpDocuments.island.tsx +3 -0
- package/src/ssr/TimezoneCookie.island.tsx +23 -0
- package/src/ssr/admin-active-link.ts +47 -0
- package/src/ssr/admin-navigation.ts +78 -0
- package/src/ssr/app-appearance.ts +23 -0
- package/src/ssr/app-navigation.ts +41 -0
- package/src/ssr/help-messages.ts +104 -0
- package/src/ssr/index.ts +14 -0
- package/src/ssr/islands/SearchBar.island.tsx +80 -0
- package/src/ssr/islands/index.ts +16 -0
- package/src/ssr/layout-context.ts +17 -0
- package/src/ssr/layout-help-markdown.ts +9 -0
- package/src/ssr/layout-help-navigation.ts +24 -0
- package/src/ssr/layout-help-url.ts +5 -0
- package/src/ssr/layout-runtime.ts +22 -0
- package/src/ssr/page-error-messages.ts +25 -0
- package/src/ssr/platform-messages.ts +135 -0
- package/src/ssr/preference-controller.ts +44 -0
- package/src/ssr/profile-preferences-messages.ts +29 -0
- package/src/ssr/rail-context.ts +21 -0
- package/src/ssr/rail-messages.ts +66 -0
- package/src/ssr/rail-navigation.ts +60 -0
- package/src/ssr/runtime.ts +31 -0
- package/src/ssr/url-filter.ts +127 -0
- package/src/styles/base-popover.css +36 -0
- package/src/styles/effects.css +851 -0
- package/src/styles/global.css +268 -0
- package/src/styles/input.css +58 -0
- package/src/styles/tokens.css +230 -0
- package/src/styles/utilities-buttons.css +405 -0
- package/src/styles/utilities-data.css +33 -0
- package/src/styles/utilities-feedback.css +232 -0
- package/src/styles/utilities-layout.css +603 -0
- package/src/styles/utilities-markdown-editor.css +525 -0
- package/src/styles/utilities-markdown-table.css +234 -0
- package/src/styles/utilities-navigation.css +1054 -0
- package/src/types/ambient.d.ts +24 -0
- package/src/workflows/ai/index.ts +17 -0
- package/src/workflows/ai/runtime.ts +286 -0
- package/src/workflows/ai/store.ts +314 -0
- package/src/workflows/ai/types.ts +111 -0
- package/src/workflows/ai-actions.ts +269 -0
- package/src/workflows/authoring.ts +88 -0
- package/src/workflows/builtins.ts +193 -0
- package/src/workflows/contracts.ts +280 -0
- package/src/workflows/definition.ts +334 -0
- package/src/workflows/editor.ts +113 -0
- package/src/workflows/index.ts +71 -0
- package/src/workflows/language/binder.ts +45 -0
- package/src/workflows/language/canonical.ts +29 -0
- package/src/workflows/language/compiler.ts +396 -0
- package/src/workflows/language/expressions.ts +34 -0
- package/src/workflows/language/index.ts +20 -0
- package/src/workflows/language/references.ts +55 -0
- package/src/workflows/language/schema.ts +134 -0
- package/src/workflows/language/strict-yaml.ts +131 -0
- package/src/workflows/manifest.ts +24 -0
- package/src/workflows/module.ts +12 -0
- package/src/workflows/runtime/coordinator.ts +115 -0
- package/src/workflows/runtime/executor.ts +1003 -0
- package/src/workflows/runtime/index.ts +60 -0
- package/src/workflows/runtime/instant.ts +8 -0
- package/src/workflows/runtime/ports.ts +213 -0
- package/src/workflows/runtime/schedule.ts +203 -0
- package/src/workflows/runtime/trigger.ts +37 -0
- package/src/workflows/runtime/wake.ts +13 -0
- package/src/workflows/store/actions.ts +438 -0
- package/src/workflows/store/budget.ts +145 -0
- package/src/workflows/store/definitions.ts +345 -0
- package/src/workflows/store/events.ts +383 -0
- package/src/workflows/store/index.ts +107 -0
- package/src/workflows/store/observability.ts +594 -0
- package/src/workflows/store/runs.ts +975 -0
- package/src/workflows/store/transaction.ts +23 -0
- package/src/workflows/store/worker.ts +439 -0
- package/src/workflows/testing/conformance.ts +72 -0
- package/src/workflows/testing/index.ts +11 -0
- package/src/workflows/testing/process-fixtures.ts +275 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type { AppDefinition, AppOptions, StartOptions, StartResult } from "./_internal/define-app";
|
|
2
|
+
export { defineApp } from "./_internal/define-app";
|
|
3
|
+
export { createHeartbeat } from "./_internal/heartbeat";
|
|
4
|
+
export type { ProcessSync } from "./_internal/process-sync";
|
|
5
|
+
export {
|
|
6
|
+
bindProcessSync,
|
|
7
|
+
getProcessSync,
|
|
8
|
+
lazySync,
|
|
9
|
+
startProcessSync,
|
|
10
|
+
unbindProcessSync,
|
|
11
|
+
} from "./_internal/process-sync";
|
|
12
|
+
export { APP_READINESS_PATH } from "./_internal/readiness";
|
|
13
|
+
export type { AppRegistryDetail, AppRegistryIssue, AppRegistrySnapshot, CapabilityRegistryRecord, DashboardWidget } from "./_internal/registry";
|
|
14
|
+
export {
|
|
15
|
+
APP_REGISTRY_CONFIG,
|
|
16
|
+
APP_REGISTRY_PREFIX,
|
|
17
|
+
APP_REGISTRY_TTL_MS,
|
|
18
|
+
CAPABILITY_REGISTRY_CONFIG,
|
|
19
|
+
HELP_REGISTRY_CONFIG,
|
|
20
|
+
appRegistry,
|
|
21
|
+
capabilityRegistry,
|
|
22
|
+
getApp,
|
|
23
|
+
getHelp,
|
|
24
|
+
helpRegistry,
|
|
25
|
+
listApps,
|
|
26
|
+
listAppsDetailed,
|
|
27
|
+
listHelp,
|
|
28
|
+
listLegalLinks,
|
|
29
|
+
listWidgets,
|
|
30
|
+
readAppRegistrySnapshot,
|
|
31
|
+
watchAppRegistry,
|
|
32
|
+
} from "./_internal/registry";
|
|
33
|
+
export type { RuntimeCompatibilityIssue } from "./_internal/runtime-compatibility";
|
|
34
|
+
export { assessRuntimeCompatibility } from "./_internal/runtime-compatibility";
|
|
35
|
+
export { buildRuntimeFromRegistry } from "./_internal/runtime-context";
|
|
36
|
+
export { defineCapabilities } from "./contracts/capabilities";
|
|
37
|
+
export type {
|
|
38
|
+
AnyBoundNotificationDefinition,
|
|
39
|
+
BoundNotificationDefinition,
|
|
40
|
+
BoundNotificationMap,
|
|
41
|
+
EmailNotificationPresentation,
|
|
42
|
+
NotificationChannelId,
|
|
43
|
+
NotificationChannelRegistry,
|
|
44
|
+
NotificationDefinition,
|
|
45
|
+
NotificationDefinitionInput,
|
|
46
|
+
NotificationDefinitionMap,
|
|
47
|
+
NotificationDefinitionPresentationCatalog,
|
|
48
|
+
NotificationDefinitionPresentationTranslation,
|
|
49
|
+
NotificationDeliveryPolicy,
|
|
50
|
+
NotificationPresentation,
|
|
51
|
+
NotificationRecipient,
|
|
52
|
+
NotificationRecipientKind,
|
|
53
|
+
NotificationRenderContext,
|
|
54
|
+
NotificationSendInput,
|
|
55
|
+
} from "./contracts/notification-types";
|
|
56
|
+
export { notification } from "./contracts/notification-types";
|
|
57
|
+
export type { HelpDefinition, HelpDefinitionDocument } from "./server/help";
|
|
58
|
+
export { defineHelp } from "./server/help";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deriving the acting user from a request actor.
|
|
3
|
+
*
|
|
4
|
+
* Roles, display name and avatar are user properties, so features that need
|
|
5
|
+
* them still need a user — but it must come **from the actor**, never from a
|
|
6
|
+
* separate context variable. `c.get("user")` drops the credential context on
|
|
7
|
+
* the way, which is how a scope cap silently stops applying and how a route
|
|
8
|
+
* ends up unable to tell a session from an API key.
|
|
9
|
+
*
|
|
10
|
+
* For authorization, do not use these helpers at all: pass
|
|
11
|
+
* `c.get("accessSubject")` into the shared access helpers, which already
|
|
12
|
+
* normalises a user-delegated credential to its user.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { Context } from "hono";
|
|
16
|
+
import type { AuthContext } from "./middleware/auth";
|
|
17
|
+
|
|
18
|
+
type RequestActor = AuthContext["Variables"]["actor"];
|
|
19
|
+
type ActingUser = AuthContext["Variables"]["user"];
|
|
20
|
+
|
|
21
|
+
/** The user behind an actor: itself for a session, the delegate for a user-bound credential, null for a resource-bound one. */
|
|
22
|
+
export const userFromActor = (actor: RequestActor | undefined): ActingUser | null => {
|
|
23
|
+
if (!actor) return null;
|
|
24
|
+
return actor.kind === "user" ? actor.user : actor.delegatedUser;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Same, read off the request context. */
|
|
28
|
+
export const getUserBackedActor = <T extends AuthContext>(c: Context<T>): ActingUser | null =>
|
|
29
|
+
userFromActor(c.get("actor") as RequestActor | undefined);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The acting user, or throw.
|
|
33
|
+
*
|
|
34
|
+
* Only for routes already gated to a user-backed role — the throw is a
|
|
35
|
+
* programming-error guard, not an access check.
|
|
36
|
+
*/
|
|
37
|
+
export const expectUserBackedActor = <T extends AuthContext>(c: Context<T>): ActingUser => {
|
|
38
|
+
const user = getUserBackedActor(c);
|
|
39
|
+
if (!user) throw new Error("Expected user-backed actor after role middleware");
|
|
40
|
+
return user;
|
|
41
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { isServiceError, ok, type Result, type ServiceError } from "@k2b/stdlib";
|
|
2
|
+
import type { Context, TypedResponse } from "hono";
|
|
3
|
+
import type { StatusCode } from "hono/utils/http-status";
|
|
4
|
+
|
|
5
|
+
type LegacyErrorStatus = ServiceError["status"] | 413 | 422 | 502 | 503 | 504;
|
|
6
|
+
type LegacyErrorResult<S extends number = number> = { ok: false; error: string; status: S; code?: string };
|
|
7
|
+
type LegacyResult<T = void> = { ok: true; data: T } | LegacyErrorResult;
|
|
8
|
+
|
|
9
|
+
type AnyResult<T = unknown> = Result<T> | LegacyResult<T>;
|
|
10
|
+
type ResultOrFn<T> = T | Promise<T> | (() => T | Promise<T>);
|
|
11
|
+
type SuccessStatus = 200 | 201;
|
|
12
|
+
export type ApiErrorStatus = ServiceError["status"] | LegacyErrorStatus;
|
|
13
|
+
type JsonTypedResponse<T, Status extends StatusCode> = Response & TypedResponse<T, Status, "json">;
|
|
14
|
+
|
|
15
|
+
export type ApiErrorBody = {
|
|
16
|
+
message: string;
|
|
17
|
+
code?: string;
|
|
18
|
+
};
|
|
19
|
+
export type ApiErrorResponse = JsonTypedResponse<ApiErrorBody, ApiErrorStatus>;
|
|
20
|
+
|
|
21
|
+
const toErrorResponse = (result: AnyResult): [ApiErrorBody, number] => {
|
|
22
|
+
if (result.ok) {
|
|
23
|
+
throw new Error("toErrorResponse called with successful result");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Legacy shape: { ok: false, error: string, status: number, code?: string }
|
|
27
|
+
if ("status" in result && typeof result.status === "number") {
|
|
28
|
+
return [result.code ? { message: result.error, code: result.code } : { message: result.error }, result.status];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// New shape: { ok: false, error: ServiceError }
|
|
32
|
+
if (isServiceError(result.error)) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
message: result.error.message,
|
|
36
|
+
code: result.error.code,
|
|
37
|
+
},
|
|
38
|
+
result.error.status,
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Defensive fallback
|
|
43
|
+
return [{ message: "Internal server error", code: "INTERNAL" }, 500];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export async function respond<E extends ServiceError>(
|
|
47
|
+
c: Context,
|
|
48
|
+
resultOrFn: ResultOrFn<Result<never, E>>,
|
|
49
|
+
successStatus?: SuccessStatus,
|
|
50
|
+
): Promise<JsonTypedResponse<ApiErrorBody, E["status"]>>;
|
|
51
|
+
export async function respond<T>(
|
|
52
|
+
c: Context,
|
|
53
|
+
resultOrFn: ResultOrFn<Result<T, never>>,
|
|
54
|
+
successStatus?: SuccessStatus,
|
|
55
|
+
): Promise<JsonTypedResponse<T, SuccessStatus>>;
|
|
56
|
+
export async function respond<T, E extends ServiceError>(
|
|
57
|
+
c: Context,
|
|
58
|
+
resultOrFn: ResultOrFn<Result<T, E>>,
|
|
59
|
+
successStatus?: SuccessStatus,
|
|
60
|
+
): Promise<JsonTypedResponse<T, SuccessStatus> | JsonTypedResponse<ApiErrorBody, E["status"]>>;
|
|
61
|
+
export async function respond<S extends LegacyErrorStatus>(
|
|
62
|
+
c: Context,
|
|
63
|
+
resultOrFn: ResultOrFn<LegacyErrorResult<S>>,
|
|
64
|
+
successStatus?: SuccessStatus,
|
|
65
|
+
): Promise<JsonTypedResponse<ApiErrorBody, S>>;
|
|
66
|
+
export async function respond<T>(
|
|
67
|
+
c: Context,
|
|
68
|
+
resultOrFn: ResultOrFn<AnyResult<T>>,
|
|
69
|
+
successStatus?: SuccessStatus,
|
|
70
|
+
): Promise<JsonTypedResponse<T, SuccessStatus> | ApiErrorResponse>;
|
|
71
|
+
export async function respond<T>(
|
|
72
|
+
c: Context,
|
|
73
|
+
resultOrFn: ResultOrFn<AnyResult<T>>,
|
|
74
|
+
successStatus: SuccessStatus = 200,
|
|
75
|
+
): Promise<JsonTypedResponse<T, SuccessStatus> | ApiErrorResponse> {
|
|
76
|
+
const result = typeof resultOrFn === "function" ? await resultOrFn() : await resultOrFn;
|
|
77
|
+
|
|
78
|
+
if (!result.ok) {
|
|
79
|
+
const [body, status] = toErrorResponse(result);
|
|
80
|
+
return c.json(body, status as ApiErrorStatus) as ApiErrorResponse;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return c.json(result.data, successStatus as 200 | 201) as JsonTypedResponse<T, SuccessStatus>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const respondMessage = (c: Context, resultPromise: Promise<Result<void>>, message: string) =>
|
|
87
|
+
respond(c, async () => {
|
|
88
|
+
const result = await resultPromise;
|
|
89
|
+
if (!result.ok) return result;
|
|
90
|
+
return ok({ message });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const api = {
|
|
94
|
+
respond,
|
|
95
|
+
respondMessage,
|
|
96
|
+
} as const;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import { hc } from "hono/client";
|
|
3
|
+
|
|
4
|
+
export type CreateApiClientConfig = {
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// ==========================
|
|
9
|
+
// API Client
|
|
10
|
+
// ==========================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a typed Hono API client.
|
|
14
|
+
*/
|
|
15
|
+
export const createApiClient = <TApi extends Hono<any, any, any>>(config: CreateApiClientConfig = {}) => hc<TApi>(config.baseUrl ?? "/api");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Untyped fallback API client for core-only browser code.
|
|
19
|
+
*/
|
|
20
|
+
export const apiClient: any = hc("/api");
|
|
21
|
+
|
|
22
|
+
// ==========================
|
|
23
|
+
// Clipboard
|
|
24
|
+
// ==========================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Copies text to the clipboard.
|
|
28
|
+
* Fails silently with console error if clipboard API is unavailable.
|
|
29
|
+
*/
|
|
30
|
+
export const copyToClipboard = async (text: string): Promise<void> => {
|
|
31
|
+
try {
|
|
32
|
+
await navigator.clipboard.writeText(text);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error("Failed to copy:", err);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a value is an image URL served by the API.
|
|
40
|
+
* Used to determine if an image field contains an existing server URL or new base64 data.
|
|
41
|
+
*/
|
|
42
|
+
export const isImageUrl = (value: string | null | undefined): boolean => typeof value === "string" && value.includes("/avatar");
|
|
43
|
+
|
|
44
|
+
export const api = {
|
|
45
|
+
create: createApiClient,
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
export const clipboard = {
|
|
49
|
+
copy: copyToClipboard,
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export const url = {
|
|
53
|
+
isImage: isImageUrl,
|
|
54
|
+
} as const;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AppContext<App>` — Hono context type for routes mounted by an app.
|
|
3
|
+
*
|
|
4
|
+
* Combines the existing `AuthContext` variables (user, sessionToken) with a
|
|
5
|
+
* typed per-request settings snapshot derived from the app's `defineApp.settings`
|
|
6
|
+
* declaration.
|
|
7
|
+
*
|
|
8
|
+
* Convention: each app exports a named alias from its `index.ts`:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { app } from "./config";
|
|
12
|
+
* import type { AppContext } from "@k2b/cloud/server";
|
|
13
|
+
* export type FilesAppContext = AppContext<typeof app>;
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Then routes:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { type FilesAppContext } from "..";
|
|
20
|
+
* new Hono<FilesAppContext>().get("/", (c) => {
|
|
21
|
+
* const s = c.get("settings"); // typed nested readonly object
|
|
22
|
+
* s.app.name // string (from core's settings)
|
|
23
|
+
* s.files.filegate_url // string (from app-files's own settings)
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* The `settings` variable is populated by the per-request snapshot middleware
|
|
28
|
+
* registered by `app.start()`; the snapshot is frozen for the duration of the
|
|
29
|
+
* request.
|
|
30
|
+
*/
|
|
31
|
+
import type { AppDefinition } from "../_internal/define-app";
|
|
32
|
+
import type { AppSettings } from "../contracts/settings-types";
|
|
33
|
+
import type { AuthContext } from "./middleware/auth";
|
|
34
|
+
|
|
35
|
+
export type AppContext<App extends AppDefinition<any>> = {
|
|
36
|
+
Variables: AuthContext["Variables"] & {
|
|
37
|
+
settings: AppSettings<App>;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { type HelpDocumentManifest, type HelpDocumentPayload, type HelpSearchPayload, helpLocaleChain } from "../shared/help";
|
|
5
|
+
import { markdownToPlainText, renderHelpMarkdown } from "../shared/markdown";
|
|
6
|
+
|
|
7
|
+
const metadataSchema = z.object({
|
|
8
|
+
id: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
9
|
+
title: z.string().trim().min(1),
|
|
10
|
+
icon: z.string().trim().min(1).optional(),
|
|
11
|
+
description: z.string().trim().min(1).optional(),
|
|
12
|
+
order: z.number().int().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type HelpDefinitionDocument = Omit<z.infer<typeof metadataSchema>, "order"> & {
|
|
16
|
+
order: number;
|
|
17
|
+
markdown: string;
|
|
18
|
+
html: string;
|
|
19
|
+
searchText: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type HelpDefinition = {
|
|
23
|
+
baseLocale?: string;
|
|
24
|
+
documentsByLocale?: Readonly<Record<string, readonly HelpDefinitionDocument[]>>;
|
|
25
|
+
documents: readonly HelpDefinitionDocument[];
|
|
26
|
+
getMarkdown: (id: string, locale?: string) => string | undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type HelpCollection = {
|
|
30
|
+
manifest: readonly HelpDocumentManifest[];
|
|
31
|
+
router: Hono;
|
|
32
|
+
/** Raw Markdown for future agent context and non-UI consumers. */
|
|
33
|
+
getMarkdown: (id: string) => string | undefined;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type ParsedHelpDocument = Omit<HelpDefinitionDocument, "order"> & { order?: number };
|
|
37
|
+
|
|
38
|
+
const parseSource = (source: string): ParsedHelpDocument => {
|
|
39
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/.exec(source);
|
|
40
|
+
if (!match) throw new Error("Help documents require YAML frontmatter wrapped in --- markers");
|
|
41
|
+
|
|
42
|
+
const metadata = metadataSchema.parse(parseYaml(match[1]!));
|
|
43
|
+
const markdown = match[2]!.trim();
|
|
44
|
+
if (!markdown) throw new Error(`Help document "${metadata.id}" has no body`);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...metadata,
|
|
48
|
+
markdown,
|
|
49
|
+
html: renderHelpMarkdown(markdown),
|
|
50
|
+
searchText: markdownToPlainText(markdown),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const canonicalLocale = (value: string): string => {
|
|
55
|
+
try {
|
|
56
|
+
return Intl.getCanonicalLocales(value)[0]!;
|
|
57
|
+
} catch {
|
|
58
|
+
throw new Error(`Invalid help locale "${value}"`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const parseDocuments = (
|
|
63
|
+
sources: readonly string[],
|
|
64
|
+
locale: string,
|
|
65
|
+
baseById?: ReadonlyMap<string, HelpDefinitionDocument>,
|
|
66
|
+
): readonly HelpDefinitionDocument[] => {
|
|
67
|
+
const documents = sources
|
|
68
|
+
.map(parseSource)
|
|
69
|
+
.map((document): HelpDefinitionDocument => {
|
|
70
|
+
const base = baseById?.get(document.id);
|
|
71
|
+
if (!baseById) return { ...document, order: document.order ?? 100 };
|
|
72
|
+
if (!base) throw new Error(`Help locale "${locale}" contains unknown document id "${document.id}"`);
|
|
73
|
+
if ((document.icon !== undefined && document.icon !== base.icon) || (document.order !== undefined && document.order !== base.order)) {
|
|
74
|
+
throw new Error(`Help locale "${locale}" must preserve icon and order for document "${document.id}"`);
|
|
75
|
+
}
|
|
76
|
+
return { ...document, icon: base.icon, description: document.description ?? base.description, order: base.order };
|
|
77
|
+
})
|
|
78
|
+
.sort((a, b) => a.order - b.order || a.title.localeCompare(b.title))
|
|
79
|
+
.map((document) => Object.freeze(document));
|
|
80
|
+
const ids = new Set<string>();
|
|
81
|
+
for (const document of documents) {
|
|
82
|
+
if (ids.has(document.id)) throw new Error(`Duplicate help document id "${document.id}" in locale "${locale}"`);
|
|
83
|
+
ids.add(document.id);
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze(documents);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** Define one app-owned Help corpus without routing or authorization config. */
|
|
89
|
+
export const defineHelp = (
|
|
90
|
+
options:
|
|
91
|
+
| { documents: readonly string[]; baseLocale?: never }
|
|
92
|
+
| { baseLocale: string; documents: Readonly<Record<string, readonly string[]>> },
|
|
93
|
+
): HelpDefinition => {
|
|
94
|
+
const localized = (value: typeof options): value is { baseLocale: string; documents: Readonly<Record<string, readonly string[]>> } =>
|
|
95
|
+
typeof value.baseLocale === "string";
|
|
96
|
+
const baseLocale = canonicalLocale(localized(options) ? options.baseLocale : "en");
|
|
97
|
+
const rawSourceMap: Readonly<Record<string, readonly string[]>> = localized(options)
|
|
98
|
+
? options.documents
|
|
99
|
+
: { [baseLocale]: options.documents };
|
|
100
|
+
const sourceMap: Record<string, readonly string[]> = {};
|
|
101
|
+
for (const [rawLocale, sources] of Object.entries(rawSourceMap)) {
|
|
102
|
+
const locale = canonicalLocale(rawLocale);
|
|
103
|
+
if (sourceMap[locale]) throw new Error(`Duplicate help locale "${locale}"`);
|
|
104
|
+
sourceMap[locale] = sources;
|
|
105
|
+
}
|
|
106
|
+
const documentsByLocale: Record<string, readonly HelpDefinitionDocument[]> = {};
|
|
107
|
+
const baseSources = sourceMap[baseLocale];
|
|
108
|
+
if (!baseSources) throw new Error(`Help documents require the base locale "${baseLocale}"`);
|
|
109
|
+
const documents = parseDocuments(baseSources, baseLocale);
|
|
110
|
+
documentsByLocale[baseLocale] = documents;
|
|
111
|
+
const baseById = new Map(documents.map((document) => [document.id, document]));
|
|
112
|
+
for (const [locale, sources] of Object.entries(sourceMap)) {
|
|
113
|
+
if (locale === baseLocale) continue;
|
|
114
|
+
if (documentsByLocale[locale]) throw new Error(`Duplicate help locale "${locale}"`);
|
|
115
|
+
documentsByLocale[locale] = parseDocuments(sources, locale, baseById);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
baseLocale,
|
|
120
|
+
documentsByLocale: Object.freeze(documentsByLocale),
|
|
121
|
+
documents: Object.freeze(documents),
|
|
122
|
+
getMarkdown: (id, locale = baseLocale) => {
|
|
123
|
+
for (const candidate of helpLocaleChain(canonicalLocale(locale), baseLocale)) {
|
|
124
|
+
const localized = documentsByLocale[candidate]?.find((document) => document.id === id);
|
|
125
|
+
if (localized) return localized.markdown;
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Define one app-owned help corpus. The explicit source list is deliberate:
|
|
134
|
+
* IDs, ordering and ownership stay visible in code; no filesystem scanning or
|
|
135
|
+
* build-time convention is required.
|
|
136
|
+
*/
|
|
137
|
+
export const defineHelpCollection = (options: { basePath: string; sources: readonly string[] }): HelpCollection => {
|
|
138
|
+
const basePath = options.basePath.replace(/\/$/, "");
|
|
139
|
+
const definition = defineHelp({ documents: options.sources });
|
|
140
|
+
const documents = definition.documents;
|
|
141
|
+
const byId = new Map(documents.map((document) => [document.id, document]));
|
|
142
|
+
|
|
143
|
+
const searchUrl = `${basePath}/search`;
|
|
144
|
+
const manifest = documents.map<HelpDocumentManifest>(({ id, title, icon, description, order }) => ({
|
|
145
|
+
id,
|
|
146
|
+
title,
|
|
147
|
+
icon,
|
|
148
|
+
description,
|
|
149
|
+
order,
|
|
150
|
+
searchUrl,
|
|
151
|
+
url: `${basePath}/${encodeURIComponent(id)}`,
|
|
152
|
+
}));
|
|
153
|
+
|
|
154
|
+
const router = new Hono()
|
|
155
|
+
.get("/search", (context) => {
|
|
156
|
+
const query = context.req.query("q")?.trim().toLocaleLowerCase().slice(0, 200) ?? "";
|
|
157
|
+
const payload: HelpSearchPayload = {
|
|
158
|
+
locale: "en",
|
|
159
|
+
ids: query
|
|
160
|
+
? documents
|
|
161
|
+
.filter((document) =>
|
|
162
|
+
[document.title, document.description, document.searchText].some((value) => value?.toLocaleLowerCase().includes(query)),
|
|
163
|
+
)
|
|
164
|
+
.map((document) => document.id)
|
|
165
|
+
: [],
|
|
166
|
+
};
|
|
167
|
+
return context.json(payload);
|
|
168
|
+
})
|
|
169
|
+
.get("/:id", (context) => {
|
|
170
|
+
const document = byId.get(context.req.param("id"));
|
|
171
|
+
if (!document) return context.json({ error: "Help document not found" }, 404);
|
|
172
|
+
const payload: HelpDocumentPayload = {
|
|
173
|
+
locale: "en",
|
|
174
|
+
id: document.id,
|
|
175
|
+
title: document.title,
|
|
176
|
+
markdown: document.markdown,
|
|
177
|
+
html: document.html,
|
|
178
|
+
};
|
|
179
|
+
return context.json(payload);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
manifest,
|
|
184
|
+
router,
|
|
185
|
+
getMarkdown: definition.getMarkdown,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export { expectUserBackedActor, getUserBackedActor, userFromActor } from "./actor";
|
|
2
|
+
export type { ApiErrorBody, ApiErrorResponse, ApiErrorStatus } from "./api";
|
|
3
|
+
export { api, respond, respondMessage } from "./api";
|
|
4
|
+
export type { CreateApiClientConfig } from "./api-client";
|
|
5
|
+
export { api as apiClient } from "./api-client";
|
|
6
|
+
export type { AppContext } from "./app-context";
|
|
7
|
+
export { defineHelp, defineHelpCollection, type HelpCollection, type HelpDefinition, type HelpDefinitionDocument } from "./help";
|
|
8
|
+
export { DEFAULT_LOCALE, getLocale, LOCALE_COOKIE, LOCALE_HEADER, locale, preferredLocale, resolveLocale } from "./locale";
|
|
9
|
+
export type {
|
|
10
|
+
AuthContext,
|
|
11
|
+
InvocationProvenance,
|
|
12
|
+
RateLimitConfig,
|
|
13
|
+
RateLimitRouteOverride,
|
|
14
|
+
RequestActor,
|
|
15
|
+
RequestAuthority,
|
|
16
|
+
RequestCredentialKind,
|
|
17
|
+
ServiceAccountRequestActor,
|
|
18
|
+
UserRequestActor,
|
|
19
|
+
} from "./middleware";
|
|
20
|
+
export {
|
|
21
|
+
auth,
|
|
22
|
+
imageResponse,
|
|
23
|
+
jsonResponse,
|
|
24
|
+
middleware,
|
|
25
|
+
openApiMeta,
|
|
26
|
+
rateLimit,
|
|
27
|
+
rejectReservedWorkloadCredential,
|
|
28
|
+
requestLogger,
|
|
29
|
+
requiresAdmin,
|
|
30
|
+
requiresAuth,
|
|
31
|
+
requiresIpa,
|
|
32
|
+
requiresIpaUser,
|
|
33
|
+
requiresUser,
|
|
34
|
+
v,
|
|
35
|
+
validator,
|
|
36
|
+
} from "./middleware";
|
|
37
|
+
export { RateLimitError, type RateLimiter, type RateLimiterConfig, type RateLimitResult, ratelimit } from "./ratelimit";
|
|
38
|
+
export type {
|
|
39
|
+
AccessEntry,
|
|
40
|
+
AccessPrincipalColumns,
|
|
41
|
+
AccessPrincipalTierConditions,
|
|
42
|
+
AccessSubject,
|
|
43
|
+
AccessUser,
|
|
44
|
+
AccessUserSource,
|
|
45
|
+
EffectiveGroup,
|
|
46
|
+
GeoPlace,
|
|
47
|
+
GeoService,
|
|
48
|
+
PageParams,
|
|
49
|
+
Paginated,
|
|
50
|
+
PermissionLevel,
|
|
51
|
+
Principal,
|
|
52
|
+
PrincipalType,
|
|
53
|
+
ResourceAccessAdapter,
|
|
54
|
+
Result,
|
|
55
|
+
ServiceError,
|
|
56
|
+
ServiceErrorCode,
|
|
57
|
+
} from "./services";
|
|
58
|
+
export {
|
|
59
|
+
buildAccessPrincipalCondition,
|
|
60
|
+
buildAccessPrincipalTierConditions,
|
|
61
|
+
createAccess,
|
|
62
|
+
deleteAccess,
|
|
63
|
+
err,
|
|
64
|
+
fail,
|
|
65
|
+
freeipa,
|
|
66
|
+
generatePassword,
|
|
67
|
+
geo,
|
|
68
|
+
geoService,
|
|
69
|
+
getAccess,
|
|
70
|
+
getEffectiveGroupIds,
|
|
71
|
+
getEffectiveGroups,
|
|
72
|
+
getEffectivePermission,
|
|
73
|
+
hasPermission,
|
|
74
|
+
images,
|
|
75
|
+
isServiceError,
|
|
76
|
+
listUsersWithAccess,
|
|
77
|
+
ok,
|
|
78
|
+
okMany,
|
|
79
|
+
PERMISSION_LEVELS,
|
|
80
|
+
paginate,
|
|
81
|
+
paginateItems,
|
|
82
|
+
password,
|
|
83
|
+
resolveDisplayNames,
|
|
84
|
+
services,
|
|
85
|
+
tryCatch,
|
|
86
|
+
unwrap,
|
|
87
|
+
updateAccess,
|
|
88
|
+
} from "./services";
|
|
89
|
+
export { getDateConfig, getTimeZone, TIMEZONE_COOKIE, time } from "./time";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
import { canonicalLocale, DEFAULT_LOCALE, LOCALE_COOKIE, LOCALE_HEADER, normalizeLocale } from "../shared/locale";
|
|
3
|
+
import { readCookie } from "./request-cookies";
|
|
4
|
+
|
|
5
|
+
export { DEFAULT_LOCALE, LOCALE_COOKIE, LOCALE_HEADER };
|
|
6
|
+
|
|
7
|
+
type LocaleContext = {
|
|
8
|
+
get(key: "settings"): Record<string, any> | undefined;
|
|
9
|
+
req: { raw: { headers: Headers } };
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The caller's explicit locale preference, or `undefined` when the request
|
|
14
|
+
* carries none. Precedence: `x-cloud-locale` transport metadata, then the
|
|
15
|
+
* `cloud.locale` cookie, then `Accept-Language` in quality order. Every
|
|
16
|
+
* candidate is canonicalized; invalid tags fall through to the next source.
|
|
17
|
+
*/
|
|
18
|
+
export const preferredLocale = (headers: Headers): string | undefined => {
|
|
19
|
+
const explicit = canonicalLocale(headers.get(LOCALE_HEADER)) ?? canonicalLocale(readCookie(headers, LOCALE_COOKIE));
|
|
20
|
+
if (explicit) return explicit;
|
|
21
|
+
for (const tag of i18n.parseAcceptLanguage(headers.get("Accept-Language"))) {
|
|
22
|
+
const candidate = canonicalLocale(tag);
|
|
23
|
+
if (candidate) return candidate;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the request locale from plain headers: the caller's preference when
|
|
30
|
+
* present, then the operator default, then the deterministic `"en"` fallback.
|
|
31
|
+
* Pure per-request derivation — never cached in process-global state.
|
|
32
|
+
*/
|
|
33
|
+
export const resolveLocale = (headers: Headers, operatorDefault?: string | null): string =>
|
|
34
|
+
preferredLocale(headers) ?? normalizeLocale(operatorDefault);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The canonical request locale: explicit preference (`x-cloud-locale` header,
|
|
38
|
+
* `cloud.locale` cookie, `Accept-Language`), then the operator's `app.locale`
|
|
39
|
+
* setting, then `"en"`. The same value drives the SSR `<html lang>` attribute,
|
|
40
|
+
* the Layout `LocaleProvider`, and `getDateConfig(c).locale`. Timezone stays a
|
|
41
|
+
* separate value — see `getTimeZone`.
|
|
42
|
+
*/
|
|
43
|
+
export const getLocale = (c: LocaleContext): string => {
|
|
44
|
+
const settingsLocale = c.get("settings")?.app?.locale;
|
|
45
|
+
return resolveLocale(c.req.raw.headers, typeof settingsLocale === "string" ? settingsLocale : undefined);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const locale = {
|
|
49
|
+
LOCALE_COOKIE,
|
|
50
|
+
LOCALE_HEADER,
|
|
51
|
+
DEFAULT_LOCALE,
|
|
52
|
+
getLocale,
|
|
53
|
+
preferredLocale,
|
|
54
|
+
resolveLocale,
|
|
55
|
+
} as const;
|