@k2b/cloud 0.6.0 → 0.8.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 +2 -2
- package/package.json +22 -11
- package/scripts/README.md +10 -0
- package/scripts/browser-performance.ts +14 -0
- package/scripts/build-pdf-renderer.ts +39 -0
- package/scripts/build.ts +20 -35
- package/scripts/preload.ts +16 -12
- package/scripts/sync-recovery-smoke.ts +22 -6
- package/src/_internal/app-presentation.ts +14 -2
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +131 -7
- package/src/_internal/capability-streams.ts +81 -0
- package/src/_internal/define-app.ts +80 -37
- package/src/_internal/heartbeat.ts +4 -0
- package/src/_internal/help-catalog.ts +27 -172
- package/src/_internal/help.ts +13 -76
- package/src/_internal/page-responses.ts +2 -0
- package/src/_internal/postgres-application-name.ts +30 -0
- package/src/_internal/process-identity.ts +15 -0
- package/src/_internal/process-sync.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/registry-validation.ts +29 -25
- package/src/_internal/registry.ts +2 -53
- package/src/_internal/runtime-context.ts +5 -16
- package/src/_internal/server-timing.ts +13 -0
- package/src/_internal/status-preserving-ssr.ts +18 -6
- package/src/_internal/web-vitals-asset.ts +10 -0
- package/src/access/PermissionEditor.tsx +18 -151
- package/src/access/PrincipalPicker.tsx +110 -0
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -0
- package/src/ai/admin.ts +14 -13
- package/src/ai/assistant-models.ts +12 -1
- package/src/ai/audio-format.ts +34 -0
- package/src/ai/audio-tool.ts +90 -0
- package/src/ai/browser-code-contracts.ts +201 -0
- package/src/ai/browser.ts +4 -0
- package/src/ai/capabilities.ts +55 -36
- package/src/ai/capability-execution.ts +47 -12
- package/src/ai/chat/blocks.tsx +229 -90
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-result.ts +15 -0
- package/src/ai/chat/capability-table.tsx +2 -10
- package/src/ai/chat/composer-adapter.ts +83 -3
- package/src/ai/chat/message-actions.tsx +8 -7
- package/src/ai/chat/message-utils.ts +25 -1
- package/src/ai/chat/messages.ts +2 -0
- package/src/ai/chat/presentation.tsx +31 -47
- package/src/ai/chat/primitives.tsx +43 -1
- package/src/ai/chat/tool-disclosure.tsx +21 -2
- package/src/ai/chat/tool-groups.ts +58 -0
- package/src/ai/chat-quotas.ts +25 -0
- package/src/ai/chat-task-contracts.ts +14 -10
- package/src/ai/chat-tasks.ts +297 -43
- package/src/ai/client/controller.ts +165 -39
- package/src/ai/client/file-source.ts +12 -6
- package/src/ai/client/live-connection.ts +1 -0
- package/src/ai/client/projection.ts +29 -11
- package/src/ai/client/transport.ts +6 -0
- package/src/ai/code-capability-routes.ts +105 -0
- package/src/ai/code-capability-transport.ts +39 -0
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +118 -0
- package/src/ai/code-runtime-tools.ts +179 -0
- package/src/ai/code-source-contracts.ts +270 -0
- package/src/ai/code-source-tools.ts +188 -0
- package/src/ai/compaction.ts +27 -6
- package/src/ai/data-analysis-skill.ts +10 -0
- package/src/ai/default-tools.ts +99 -3
- package/src/ai/dictation-runtime.ts +171 -0
- package/src/ai/dictations.ts +188 -0
- package/src/ai/draft-content.ts +49 -0
- package/src/ai/enrich.ts +6 -0
- package/src/ai/executor.ts +189 -33
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +27 -0
- package/src/ai/file-context.ts +2 -1
- package/src/ai/file-media-type.ts +12 -0
- package/src/ai/file-reference-contracts.ts +15 -0
- package/src/ai/file-tools.ts +8 -1
- package/src/ai/files-store.ts +212 -71
- package/src/ai/fixtures/vision-encrypted.pdf +0 -0
- package/src/ai/grids-skill.ts +42 -10
- package/src/ai/http.ts +26 -8
- package/src/ai/index.ts +26 -3
- package/src/ai/inference-calls.ts +197 -0
- package/src/ai/live-events.ts +5 -1
- package/src/ai/live.ts +1 -1
- package/src/ai/markdown-pdf-tool.ts +2 -2
- package/src/ai/memories.ts +30 -27
- package/src/ai/memory-learning-runs.ts +1 -1
- package/src/ai/memory-learning.ts +64 -32
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +178 -0
- package/src/ai/migrate.ts +189 -11
- package/src/ai/model-pricing.ts +43 -0
- package/src/ai/pdf-render-worker.ts +75 -0
- package/src/ai/pdf-render.fixture.ts +28 -0
- package/src/ai/pdf-render.ts +77 -0
- package/src/ai/projects-routes.ts +18 -43
- package/src/ai/projects.ts +33 -14
- package/src/ai/protocol.ts +3 -0
- package/src/ai/provider.ts +1 -8
- package/src/ai/quota-provider.ts +192 -0
- package/src/ai/quota-report.ts +152 -0
- package/src/ai/quotas-migrate.ts +45 -0
- package/src/ai/quotas.ts +168 -0
- package/src/ai/routes.ts +241 -11
- package/src/ai/run-timeout.ts +12 -0
- package/src/ai/runtime-tools.ts +7 -5
- package/src/ai/runtime.ts +74 -17
- package/src/ai/settings.ts +36 -8
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-catalog.ts +0 -10
- package/src/ai/skill-search.ts +58 -0
- package/src/ai/skill-seeds.ts +114 -20
- package/src/ai/skill-tool.ts +21 -5
- package/src/ai/skills-routes.ts +49 -4
- package/src/ai/skills.ts +358 -163
- package/src/ai/store.ts +416 -201
- package/src/ai/stream.ts +5 -0
- package/src/ai/structured-runs.ts +4 -3
- package/src/ai/structured.ts +12 -1
- package/src/ai/system-prompt.ts +14 -2
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/timeline.ts +2 -5
- package/src/ai/todo-contracts.ts +32 -0
- package/src/ai/todo-tool.ts +19 -0
- package/src/ai/tool-audit.ts +30 -40
- package/src/ai/tools.ts +6 -0
- package/src/ai/transcription.ts +202 -0
- package/src/ai/turn-timing.ts +114 -0
- package/src/ai/types.ts +58 -10
- package/src/ai/ui.tsx +3 -0
- package/src/ai/usage.ts +118 -118
- package/src/ai/vision-tool.ts +60 -10
- package/src/api/admin-ai-projects.ts +2 -2
- package/src/api/admin-ai-quotas.ts +80 -0
- package/src/api/admin-ai-skills.ts +48 -5
- package/src/api/admin-ai-usage.ts +2 -2
- package/src/api/admin-core-settings.ts +25 -0
- package/src/api/admin-identity.ts +91 -51
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +58 -0
- package/src/api/announcements.ts +14 -0
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth.ts +1 -1
- package/src/api/capabilities.ts +324 -43
- package/src/api/capability-streams.ts +262 -0
- package/src/api/help.ts +8 -44
- package/src/api/index.ts +8 -2
- package/src/api/mcp.ts +45 -34
- package/src/api/me-web-vitals.ts +35 -0
- package/src/api/me.ts +2 -0
- package/src/api/search/schemas.ts +26 -15
- package/src/api/search.bench.ts +1 -1
- package/src/api/search.ts +54 -17
- package/src/browser/CloudResourceSearch.tsx +640 -702
- package/src/browser/app-approval-vault.ts +19 -7
- package/src/browser/command-bridge.ts +109 -0
- package/src/browser/command-shortcuts.ts +76 -0
- package/src/browser/commands.ts +67 -0
- package/src/browser/navigation-search.ts +48 -0
- package/src/browser/notifications.ts +1 -1
- package/src/browser/resource-picker.tsx +5 -18
- package/src/browser/resource-search-dialog.ts +9 -0
- package/src/browser/resource-search-input.ts +46 -0
- package/src/browser/resource-search-messages.ts +76 -40
- package/src/browser/resource-search.ts +7 -0
- package/src/browser/search-bridge.ts +102 -0
- package/src/browser/search-commands.ts +59 -0
- package/src/browser/search.ts +13 -0
- package/src/browser/spotlight-position.ts +208 -0
- package/src/browser/testing.ts +6 -0
- package/src/browser/web-vitals.ts +25 -0
- package/src/capabilities/claims.ts +179 -0
- package/src/capabilities/client.ts +34 -0
- package/src/capabilities/command-link.ts +16 -0
- package/src/capabilities/executions.ts +298 -0
- package/src/capabilities/migrate.ts +81 -0
- package/src/capabilities/server.ts +116 -35
- package/src/capabilities/stream-body.ts +16 -0
- package/src/capabilities/streams.ts +28 -0
- package/src/cli/admin/ai-quotas.ts +161 -0
- package/src/cli/admin/ai-skills.ts +64 -0
- package/src/cli/admin/ai-usage.ts +53 -30
- package/src/cli/admin/app-credentials.ts +77 -0
- package/src/cli/admin/data.ts +17 -0
- package/src/cli/admin/index.ts +10 -1
- package/src/cli/admin/instance.ts +2 -2
- package/src/cli/admin/linux.ts +4 -2
- package/src/cli/admin/sync.ts +1 -1
- package/src/cli/capabilities.ts +42 -0
- package/src/cli/capability-streams.ts +25 -0
- package/src/cli/index.ts +3 -2
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -51
- package/src/config/index.ts +3 -1
- package/src/contracts/app.ts +23 -3
- package/src/contracts/capabilities.ts +75 -5
- package/src/contracts/capability-streams.ts +46 -0
- package/src/contracts/commands.ts +49 -0
- package/src/contracts/index.ts +5 -2
- package/src/contracts/rail-admin.ts +38 -0
- package/src/contracts/rail-preferences.ts +16 -0
- package/src/contracts/registry.ts +5 -27
- package/src/contracts/settings-types.ts +1 -1
- package/src/contracts/shared.ts +18 -5
- package/src/contracts/web-vitals.ts +27 -0
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -6
- package/src/server/index.ts +3 -0
- package/src/server/middleware/auth.ts +3 -2
- package/src/server/middleware/route-template.ts +9 -3
- package/src/server/middleware/runtime.ts +2 -1
- package/src/server/middleware/settings.ts +17 -11
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +10 -0
- package/src/server/services/access.ts +3 -1
- package/src/server/services/index.ts +1 -0
- package/src/services/account-category-policy.ts +9 -0
- package/src/services/account-lifecycle/audit.ts +1 -1
- package/src/services/accounts/app.ts +12 -2
- package/src/services/accounts/email-write.ts +23 -0
- package/src/services/accounts/groups.ts +15 -4
- package/src/services/accounts/identities.ts +249 -0
- package/src/services/accounts/identity-reconciliation.ts +87 -0
- package/src/services/accounts/ipa-data.ts +2 -2
- package/src/services/accounts/local-groups.ts +2 -2
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/accounts/posix.ts +45 -29
- package/src/services/accounts/users.ts +2 -2
- package/src/services/announcements/index.ts +69 -8
- package/src/services/app-approval.ts +11 -10
- package/src/services/audit/index.ts +1 -1
- package/src/services/cache-fill.ts +35 -0
- package/src/services/help/index.ts +109 -0
- package/src/services/help/maintenance.ts +25 -0
- package/src/services/help/store.ts +180 -0
- package/src/services/help/types.ts +46 -0
- package/src/services/identity/invocation-actor.ts +2 -2
- package/src/services/identity/key-config.ts +8 -5
- package/src/services/identity/key-ring.ts +1 -1
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/index.ts +15 -0
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/ipa/users.ts +268 -221
- package/src/services/legal-consent.ts +1 -1
- package/src/services/logging/index.ts +15 -13
- package/src/services/logging/trace.ts +2 -1
- package/src/services/logging/web-vitals.ts +81 -0
- package/src/services/mandates/index.ts +21 -4
- package/src/services/mandates/policy.ts +165 -2
- package/src/services/notifications/batches.ts +125 -57
- package/src/services/notifications/browser.ts +12 -0
- package/src/services/notifications/index.ts +0 -2
- package/src/services/notifications/platform.ts +0 -4
- package/src/services/oauth-tokens.ts +3 -3
- package/src/services/pdf/gotenberg.ts +131 -72
- package/src/services/pdf/index.ts +11 -8
- package/src/services/providers/local/users.ts +25 -16
- package/src/services/public-http.ts +101 -0
- package/src/services/rail-shortcuts.ts +95 -0
- package/src/services/rail-snapshot.ts +53 -0
- package/src/services/request-cache-redis.ts +29 -0
- package/src/services/session/index.ts +15 -2
- package/src/services/session/user.ts +62 -37
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +26 -35
- package/src/services/settings/defaults.ts +5 -0
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +58 -84
- package/src/services/webauthn.ts +1 -1
- package/src/shared/ai-costs.ts +42 -0
- package/src/shared/ai-platform-prompt.ts +1 -1
- package/src/shared/ai-quotas.ts +136 -0
- package/src/shared/ai-usage.ts +6 -16
- package/src/shared/app-presentation.ts +21 -15
- package/src/shared/capability-messages.ts +14 -0
- package/src/shared/help.ts +6 -42
- package/src/shared/index.ts +3 -0
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminLayout.tsx +7 -5
- package/src/ssr/AdminSidebar.tsx +30 -16
- package/src/ssr/AppLaunchpad.island.tsx +33 -136
- package/src/ssr/AppLaunchpadPanel.tsx +181 -0
- package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
- package/src/ssr/GlobalSearchDialog.tsx +167 -20
- package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
- package/src/ssr/Layout.tsx +17 -6
- package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
- package/src/ssr/LayoutFooter.tsx +1 -1
- package/src/ssr/LayoutHeader.tsx +46 -14
- package/src/ssr/LayoutHelp.tsx +22 -23
- package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
- package/src/ssr/LayoutRail.tsx +17 -9
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +71 -0
- package/src/ssr/MobileProfileActions.tsx +49 -0
- package/src/ssr/ProfilePreferences.island.tsx +3 -36
- package/src/ssr/RailApps.island.tsx +2 -2
- package/src/ssr/RailEditor.tsx +17 -2
- package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
- package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
- package/src/ssr/admin-navigation.ts +11 -1
- package/src/ssr/help.ts +29 -0
- package/src/ssr/islands/SearchBar.tsx +67 -0
- package/src/ssr/islands/index.ts +3 -1
- package/src/ssr/layout-context.ts +2 -2
- package/src/ssr/layout-help-search.ts +15 -0
- package/src/ssr/mobile-menu-history.ts +70 -0
- package/src/ssr/platform-messages.ts +16 -8
- package/src/ssr/profile-actions.ts +42 -0
- package/src/ssr/rail-context.ts +8 -4
- package/src/ssr/rail-messages.ts +2 -0
- package/src/ssr/rail-navigation.ts +3 -3
- package/src/ssr/workspace-navigation.ts +75 -0
- package/src/styles/effects.css +6 -6
- package/src/styles/global.css +54 -0
- package/src/styles/input.css +43 -41
- package/src/styles/resource-search.css +505 -0
- package/src/styles/utilities-feedback.css +13 -0
- package/src/styles/utilities-layout.css +1 -5
- package/src/styles/utilities-navigation.css +3 -39
- package/src/types/ambient.d.ts +5 -0
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +19 -90
- package/src/workflows/ai/store.ts +2 -0
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/ai-actions.ts +16 -13
- package/src/workflows/definition.ts +10 -5
- package/src/workflows/store/actions.ts +44 -20
- package/src/workflows/store/index.ts +4 -2
- package/src/workflows/store/runs.ts +36 -0
- package/src/workflows/store/worker-pool.ts +55 -0
- package/src/workflows/store/worker-runtime.ts +90 -0
- package/src/ai/kit-skill.ts +0 -22
- package/src/ai/usage-migrate.ts +0 -81
- package/src/browser/notification-target.ts +0 -27
- package/src/contracts/notification-live.ts +0 -66
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/notifications/live.ts +0 -50
- package/src/services/session/test-fixture.ts +0 -18
- package/src/ssr/BrowserNotifications.island.tsx +0 -135
- package/src/ssr/islands/SearchBar.island.tsx +0 -80
package/README.md
CHANGED
|
@@ -78,9 +78,9 @@ A standard app declares four prefixes (`/api/<id>`, `/app/<id>`, `/admin/<id>`,
|
|
|
78
78
|
|
|
79
79
|
## Documentation
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Application setup, public contracts, and deployment guidance:
|
|
82
82
|
|
|
83
|
-
- **[
|
|
83
|
+
- **[Create the first application](https://github.com/k2b-dev/cloud/blob/main/docs-site/docs/en/build/getting-started.md)** — standalone project setup and a verified API endpoint
|
|
84
84
|
- **[github.com/k2b-dev/cloud](https://github.com/k2b-dev/cloud)** — the platform monorepo (gateway, core, all platform apps)
|
|
85
85
|
|
|
86
86
|
## License
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k2b/cloud",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Application platform library for independently deployed Hono and SolidJS services behind a dynamic gateway.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"!src/**/*.test.ts",
|
|
19
19
|
"!src/**/*.test.tsx",
|
|
20
20
|
"!src/**/*.integration.test.ts",
|
|
21
|
-
"!
|
|
21
|
+
"!src/**/*.test-fixture.ts",
|
|
22
|
+
"!scripts/**/*.test.ts",
|
|
23
|
+
"!scripts/runtime-recovery-*.ts"
|
|
22
24
|
],
|
|
23
25
|
"exports": {
|
|
24
26
|
".": "./src/index.ts",
|
|
@@ -31,9 +33,13 @@
|
|
|
31
33
|
"./browser/live": "./src/browser/live-websocket.ts",
|
|
32
34
|
"./browser/notifications": "./src/browser/notifications.ts",
|
|
33
35
|
"./browser/resource-clipboard": "./src/browser/resource-clipboard.ts",
|
|
36
|
+
"./browser/commands": "./src/browser/commands.ts",
|
|
37
|
+
"./browser/search": "./src/browser/search.ts",
|
|
38
|
+
"./browser/testing": "./src/browser/testing.ts",
|
|
34
39
|
"./browser/resource-picker": "./src/browser/resource-picker.tsx",
|
|
35
40
|
"./capabilities": "./src/capabilities/client.ts",
|
|
36
41
|
"./capabilities/server": "./src/capabilities/server.ts",
|
|
42
|
+
"./capabilities/store": "./src/capabilities/executions.ts",
|
|
37
43
|
"./capabilities/testing": "./src/capabilities/testing.ts",
|
|
38
44
|
"./cli": "./src/cli/index.ts",
|
|
39
45
|
"./cli/access": "./src/cli/access.ts",
|
|
@@ -59,6 +65,7 @@
|
|
|
59
65
|
"./access/ui": "./src/access/ui.ts",
|
|
60
66
|
"./ssr": "./src/ssr/index.ts",
|
|
61
67
|
"./ssr/islands": "./src/ssr/islands/index.ts",
|
|
68
|
+
"./ssr/WorkspaceNavigation.island": "./src/ssr/WorkspaceNavigation.island.tsx",
|
|
62
69
|
"./ssr/*": "./src/ssr/*",
|
|
63
70
|
"./config": "./src/config/index.ts",
|
|
64
71
|
"./config/*": "./src/config/*",
|
|
@@ -77,19 +84,22 @@
|
|
|
77
84
|
"./styles/global.css": "./src/styles/global.css"
|
|
78
85
|
},
|
|
79
86
|
"scripts": {
|
|
80
|
-
"test": "bun test",
|
|
81
|
-
"
|
|
87
|
+
"test": "bun test --isolate --path-ignore-patterns '**/*.behavior.test.tsx' --path-ignore-patterns '**/*.dom.test.tsx' && bun run test:dom",
|
|
88
|
+
"test:dom": "bun test --isolate --conditions=browser --preload ../ui/test/solid-dom-preload.ts behavior.test.tsx dom.test.tsx",
|
|
89
|
+
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
|
|
82
90
|
},
|
|
83
91
|
"dependencies": {
|
|
84
92
|
"@firecrawl/anydoc": "0.1.9",
|
|
93
|
+
"@napi-rs/canvas": "1.0.8",
|
|
94
|
+
"pdfjs-dist": "6.3.289",
|
|
85
95
|
"@hono/standard-validator": "0.2.2",
|
|
86
96
|
"@simplewebauthn/server": "13.3.2",
|
|
87
97
|
"@tabler/icons": "3.46.0",
|
|
88
98
|
"@tailwindcss/typography": "0.5.20",
|
|
89
|
-
"@k2b/nessi": "0.
|
|
90
|
-
"@k2b/ssr": "0.
|
|
91
|
-
"@k2b/ui": "0.
|
|
92
|
-
"@k2b/stdlib": "0.
|
|
99
|
+
"@k2b/nessi": "0.12.0",
|
|
100
|
+
"@k2b/ssr": "0.14.0",
|
|
101
|
+
"@k2b/ui": "0.4.0",
|
|
102
|
+
"@k2b/stdlib": "0.25.0",
|
|
93
103
|
"@k2b/sync": "6.4.0",
|
|
94
104
|
"@nats-io/transport-node": "3.4.0",
|
|
95
105
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
@@ -107,6 +117,7 @@
|
|
|
107
117
|
"seroval": "1.6.0",
|
|
108
118
|
"tailwindcss": "4.3.3",
|
|
109
119
|
"web-push": "3.6.7",
|
|
120
|
+
"web-vitals": "6.2.1",
|
|
110
121
|
"yaml": "2.9.0",
|
|
111
122
|
"hash-wasm": "4.12.0",
|
|
112
123
|
"@types/nodemailer": "7.0.12",
|
|
@@ -116,12 +127,12 @@
|
|
|
116
127
|
"devDependencies": {
|
|
117
128
|
"@babel/core": "7.29.7",
|
|
118
129
|
"@babel/preset-typescript": "7.29.7",
|
|
119
|
-
"@types/bun": "1.
|
|
130
|
+
"@types/bun": "1.4.2",
|
|
120
131
|
"babel-preset-solid": "1.9.12",
|
|
121
132
|
"hono": "4.12.32",
|
|
122
133
|
"solid-js": "1.9.14",
|
|
123
134
|
"typescript": "5.9.3",
|
|
124
|
-
"zod": "4.
|
|
135
|
+
"zod": "4.6.2"
|
|
125
136
|
},
|
|
126
137
|
"peerDependencies": {
|
|
127
138
|
"hono": "^4.12.25",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Cloud platform scripts
|
|
2
|
+
|
|
3
|
+
- `build.ts` — production build for one Cloud app (`APP_ID`); used by the Dockerfiles and `bun run build` targets.
|
|
4
|
+
- `preload.ts` — dev-mode preload that registers the SSR plugin and builds CSS before app code loads.
|
|
5
|
+
- `build-pdf-renderer.ts` — packages the PDF decoder and native assets for bundles that import PDF vision.
|
|
6
|
+
- `app-favicon.ts` — generates app favicons from Tabler icons; imported by `build.ts` and `preload.ts`.
|
|
7
|
+
- `browser-performance.ts` — bundles the web-vitals browser asset for core; imported by `build.ts` and `preload.ts`.
|
|
8
|
+
- `runtime-recovery-acceptance.ts` — shared-runtime recovery acceptance on disposable Docker containers: `bun packages/cloud/scripts/runtime-recovery-acceptance.ts` (also `bun run test:runtime-recovery`).
|
|
9
|
+
- `runtime-recovery-worker.ts` — the containerized fixture started by `runtime-recovery-acceptance.ts`; not run directly.
|
|
10
|
+
- `sync-recovery-smoke.ts` — two-phase NATS recovery smoke: `bun packages/cloud/scripts/sync-recovery-smoke.ts prepare --namespace cloud-recovery-smoke-<unique>`, restart the fleet, then `... recover --namespace <same>`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { WEB_VITALS_ASSET_NAME } from "../src/_internal/web-vitals-asset";
|
|
3
|
+
|
|
4
|
+
export async function buildBrowserPerformance(publicDir: string, appId: string): Promise<void> {
|
|
5
|
+
if (appId !== "core") return;
|
|
6
|
+
const result = await Bun.build({
|
|
7
|
+
entrypoints: [resolve(import.meta.dir, "../src/browser/web-vitals.ts")],
|
|
8
|
+
outdir: publicDir,
|
|
9
|
+
naming: WEB_VITALS_ASSET_NAME,
|
|
10
|
+
target: "browser",
|
|
11
|
+
minify: true,
|
|
12
|
+
});
|
|
13
|
+
if (!result.success) throw new AggregateError(result.logs, "Browser performance build failed");
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cp, mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
/** Package the decoder and native assets only for bundles importing PDF vision. */
|
|
7
|
+
export async function buildPdfRenderer(dist: string) {
|
|
8
|
+
const framework = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const out = resolve(dist, "pdf-render");
|
|
10
|
+
await mkdir(out, { recursive: true });
|
|
11
|
+
const worker = await Bun.build({
|
|
12
|
+
entrypoints: [resolve(framework, "src/ai/pdf-render-worker.ts")],
|
|
13
|
+
target: "bun",
|
|
14
|
+
outdir: out,
|
|
15
|
+
naming: "worker.js",
|
|
16
|
+
external: ["pdfjs-dist", "@napi-rs/canvas"],
|
|
17
|
+
});
|
|
18
|
+
if (!worker.success) throw new Error(`PDF decoder build failed: ${worker.logs.join("\n")}`);
|
|
19
|
+
for (const name of ["pdfjs-dist", "@napi-rs/canvas"]) {
|
|
20
|
+
const source = dirname(Bun.resolveSync(`${name}/package.json`, framework));
|
|
21
|
+
await cp(source, resolve(out, "node_modules", name), { recursive: true, dereference: true });
|
|
22
|
+
if (name !== "@napi-rs/canvas") continue;
|
|
23
|
+
const manifest = z
|
|
24
|
+
.object({ optionalDependencies: z.record(z.string(), z.string()) })
|
|
25
|
+
.parse(await Bun.file(resolve(source, "package.json")).json());
|
|
26
|
+
let nativePackages = 0;
|
|
27
|
+
for (const dependency of Object.keys(manifest.optionalDependencies)) {
|
|
28
|
+
let location: string;
|
|
29
|
+
try {
|
|
30
|
+
location = dirname(Bun.resolveSync(`${dependency}/package.json`, source));
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
} // Only the installed target-platform binary is needed.
|
|
34
|
+
await cp(location, resolve(out, "node_modules", dependency), { recursive: true, dereference: true });
|
|
35
|
+
nativePackages++;
|
|
36
|
+
}
|
|
37
|
+
if (!nativePackages) throw new Error("PDF decoder needs an installed native canvas binary for the build platform.");
|
|
38
|
+
}
|
|
39
|
+
}
|
package/scripts/build.ts
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Two consumer shapes:
|
|
5
5
|
*
|
|
6
6
|
* Monorepo (this repo):
|
|
7
|
-
* APP_ID=<id> bun run packages/cloud/scripts/build.ts
|
|
7
|
+
* NODE_ENV=production APP_ID=<id> bun run packages/cloud/scripts/build.ts
|
|
8
8
|
* # appDir defaults to packages/<APP_ID>, run from workspace root.
|
|
9
9
|
*
|
|
10
10
|
* Standalone (npm consumer, see cloud-template):
|
|
11
|
-
* APP_ID=<id> APP_DIR=. bun run node_modules/@k2b/cloud/scripts/build.ts
|
|
11
|
+
* NODE_ENV=production APP_ID=<id> APP_DIR=. bun run node_modules/@k2b/cloud/scripts/build.ts
|
|
12
12
|
* # appDir = APP_DIR (resolved against cwd) and must be the directory
|
|
13
13
|
* # that CONTAINS src/, since entrypoints resolve to <appDir>/src/*.
|
|
14
14
|
*
|
|
@@ -22,20 +22,21 @@
|
|
|
22
22
|
* it ships a `scripts/build-extras.ts` that this script runs at the end.
|
|
23
23
|
*/
|
|
24
24
|
import { existsSync } from "node:fs";
|
|
25
|
-
import { cp, mkdir,
|
|
25
|
+
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
26
26
|
import { dirname, extname, resolve } from "node:path";
|
|
27
27
|
import { fileURLToPath } from "node:url";
|
|
28
28
|
import { promisify } from "node:util";
|
|
29
29
|
import { brotliCompress, gzip, constants as zlibConstants } from "node:zlib";
|
|
30
|
-
import {
|
|
30
|
+
import { Glob } from "bun";
|
|
31
31
|
import tailwind from "bun-plugin-tailwind";
|
|
32
32
|
import { writeAppFavicon } from "./app-favicon";
|
|
33
|
+
import { buildBrowserPerformance } from "./browser-performance";
|
|
34
|
+
import { buildPdfRenderer } from "./build-pdf-renderer";
|
|
33
35
|
|
|
34
36
|
const appId = process.env.APP_ID;
|
|
35
37
|
if (!appId) throw new Error("APP_ID env var required");
|
|
36
38
|
|
|
37
|
-
//
|
|
38
|
-
// process.cwd() (set in defineApp), so we use the same here for hash parity.
|
|
39
|
+
// Build output is relative to the consuming project, including npm consumers.
|
|
39
40
|
const root = process.cwd();
|
|
40
41
|
|
|
41
42
|
// Framework dir — works whether this script is in packages/cloud/scripts/
|
|
@@ -46,6 +47,10 @@ const release = process.env.CLOUD_RELEASE?.trim() || "local";
|
|
|
46
47
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(release)) {
|
|
47
48
|
throw new Error(`Invalid CLOUD_RELEASE: ${JSON.stringify(release)}`);
|
|
48
49
|
}
|
|
50
|
+
const version = process.env.CLOUD_VERSION?.trim() || "0.0.0-local";
|
|
51
|
+
if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
|
|
52
|
+
throw new Error(`Invalid CLOUD_VERSION: ${JSON.stringify(version)}`);
|
|
53
|
+
}
|
|
49
54
|
const syncPackagePath = Bun.resolveSync("@k2b/sync/package.json", frameworkDir);
|
|
50
55
|
const syncPackage = JSON.parse(await readFile(syncPackagePath, "utf8")) as {
|
|
51
56
|
version?: unknown;
|
|
@@ -59,6 +64,8 @@ const syncVersion = syncPackage.version;
|
|
|
59
64
|
// convention. Resolved against cwd if relative.
|
|
60
65
|
const appDir = process.env.APP_DIR ? resolve(root, process.env.APP_DIR) : resolve(root, "packages", appId);
|
|
61
66
|
if (!existsSync(appDir)) throw new Error(`Unknown app dir: ${appDir} (set APP_DIR or check APP_ID)`);
|
|
67
|
+
// Share the resolved source directory with defineApp before importing config.
|
|
68
|
+
process.env.APP_DIR = appDir;
|
|
62
69
|
|
|
63
70
|
const dist = resolve(root, "dist");
|
|
64
71
|
const distPublic = resolve(dist, "public");
|
|
@@ -68,14 +75,6 @@ const compressGzip = promisify(gzip);
|
|
|
68
75
|
await rm(dist, { recursive: true, force: true });
|
|
69
76
|
await mkdir(distPublic, { recursive: true });
|
|
70
77
|
|
|
71
|
-
// Mirrors @k2b/ssr's island-id (md5 of POSIX path relative to the
|
|
72
|
-
// SSR plugin's rootDir, truncated to 12 chars). Both this script and the
|
|
73
|
-
// plugin use process.cwd() as the rootDir, so hashes match.
|
|
74
|
-
const islandId = (file: string): string => {
|
|
75
|
-
const rel = file.slice(root.length + 1).replace(/\\/g, "/");
|
|
76
|
-
return new CryptoHasher("md5").update(rel).digest("hex").slice(0, 12);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
78
|
const compressibleExtensions = new Set([".css", ".html", ".js", ".json", ".map", ".svg", ".txt", ".xml"]);
|
|
80
79
|
|
|
81
80
|
async function precompressDistAssets(dir: string): Promise<void> {
|
|
@@ -124,11 +123,14 @@ try {
|
|
|
124
123
|
naming: "server.js",
|
|
125
124
|
target: "bun",
|
|
126
125
|
minify: true,
|
|
126
|
+
metafile: true,
|
|
127
127
|
define: {
|
|
128
|
+
__CLOUD_VERSION__: JSON.stringify(version),
|
|
128
129
|
__CLOUD_RELEASE__: JSON.stringify(release),
|
|
129
130
|
__CLOUD_SYNC_VERSION__: JSON.stringify(syncVersion),
|
|
131
|
+
__CLOUD_PDF_RENDER_WORKER__: JSON.stringify("./pdf-render/worker.js"),
|
|
130
132
|
},
|
|
131
|
-
plugins: [plugin()],
|
|
133
|
+
plugins: [(app?.plugin ?? plugin)()],
|
|
132
134
|
});
|
|
133
135
|
} finally {
|
|
134
136
|
await rm(serverEntry, { force: true });
|
|
@@ -137,26 +139,8 @@ if (!server.success) {
|
|
|
137
139
|
for (const m of server.logs) console.error(m);
|
|
138
140
|
throw new Error("Server bundle failed");
|
|
139
141
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// across every reachable package (including any island-shaped files in
|
|
143
|
-
// other workspace packages or in node_modules). Keep only this app's own
|
|
144
|
-
// islands plus the framework's; drop the rest. chunk-* files are shared
|
|
145
|
-
// splits and always kept.
|
|
146
|
-
const ssrDir = resolve(dist, "_ssr");
|
|
147
|
-
if (existsSync(ssrDir)) {
|
|
148
|
-
const allowedDirs = [frameworkDir, appDir];
|
|
149
|
-
const allowedIds = new Set<string>();
|
|
150
|
-
for (const dir of allowedDirs) {
|
|
151
|
-
for await (const file of new Glob("**/*.{island,client}.tsx").scan({ cwd: dir, absolute: true })) {
|
|
152
|
-
allowedIds.add(islandId(file));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
for (const entry of await readdir(ssrDir)) {
|
|
156
|
-
if (entry.startsWith("chunk-") || !entry.endsWith(".js")) continue;
|
|
157
|
-
const id = entry.slice(0, -3);
|
|
158
|
-
if (!allowedIds.has(id)) await rm(resolve(ssrDir, entry));
|
|
159
|
-
}
|
|
142
|
+
if (Object.keys(server.metafile?.inputs ?? {}).some((path) => path.endsWith("/ai/pdf-render.ts"))) {
|
|
143
|
+
await buildPdfRenderer(dist);
|
|
160
144
|
}
|
|
161
145
|
|
|
162
146
|
// 2. Per-app Tailwind stylesheet.
|
|
@@ -199,6 +183,7 @@ if (existsSync(extras)) {
|
|
|
199
183
|
await import(extras);
|
|
200
184
|
}
|
|
201
185
|
|
|
186
|
+
await buildBrowserPerformance(distPublic, appId);
|
|
202
187
|
await precompressDistAssets(resolve(dist, "public"));
|
|
203
188
|
await precompressDistAssets(resolve(dist, "_ssr"));
|
|
204
189
|
|
package/scripts/preload.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { dirname, resolve } from "node:path";
|
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
24
|
import tailwind from "bun-plugin-tailwind";
|
|
25
25
|
import { writeAppFavicon } from "./app-favicon";
|
|
26
|
+
import { buildBrowserPerformance } from "./browser-performance";
|
|
26
27
|
|
|
27
28
|
const appId = process.env.APP_ID ?? "core";
|
|
28
29
|
|
|
@@ -38,9 +39,11 @@ const frameworkDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
38
39
|
// convention. Resolved against cwd if relative.
|
|
39
40
|
const appDir = process.env.APP_DIR ? resolve(root, process.env.APP_DIR) : resolve(root, "packages", appId);
|
|
40
41
|
if (!existsSync(appDir)) throw new Error(`Unknown app dir: ${appDir} (set APP_DIR or check APP_ID)`);
|
|
42
|
+
// Share the resolved source directory with defineApp before importing config.
|
|
43
|
+
process.env.APP_DIR = appDir;
|
|
41
44
|
|
|
42
45
|
const { app, plugin } = await import(resolve(appDir, "src/config"));
|
|
43
|
-
Bun.plugin(plugin());
|
|
46
|
+
Bun.plugin((app?.plugin ?? plugin)());
|
|
44
47
|
|
|
45
48
|
// ── Build CSS ───────────────────────────────────────────────────────────────
|
|
46
49
|
const publicDir = resolve(root, "public");
|
|
@@ -125,19 +128,17 @@ if (appId === "core" && existsSync(globalCssEntry)) {
|
|
|
125
128
|
await cp(resolve(frameworkDir, "public/logo.svg"), resolve(publicDir, "logo.svg"));
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
// katex.css is only needed by notebooks (served by core via Traefik /public/katex.css)
|
|
129
|
-
if (appId === "notebooks") {
|
|
130
|
-
try {
|
|
131
|
-
await cp(resolve(root, "node_modules/katex/dist/katex.min.css"), resolve(publicDir, "katex.css"));
|
|
132
|
-
} catch {
|
|
133
|
-
console.warn("[preload] katex.css not found, skipping");
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
131
|
// Each app builds its own app.css
|
|
138
132
|
const appPublicDir = resolve(publicDir, appId);
|
|
139
133
|
await mkdir(appPublicDir, { recursive: true });
|
|
140
134
|
|
|
135
|
+
// Static assets from <appDir>/public, same as step 3 of the production build.
|
|
136
|
+
const appPublicSource = resolve(appDir, "public");
|
|
137
|
+
// A standalone application's public directory can be the serving root itself; never copy a tree into itself.
|
|
138
|
+
if (existsSync(appPublicSource) && appPublicSource !== publicDir && !appPublicDir.startsWith(`${appPublicSource}/`)) {
|
|
139
|
+
await cp(appPublicSource, appPublicDir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
|
|
141
142
|
if (appId !== "core" && app) {
|
|
142
143
|
await writeAppFavicon({
|
|
143
144
|
publicDir,
|
|
@@ -146,9 +147,12 @@ if (appId !== "core" && app) {
|
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
|
|
150
|
+
if (existsSync(appCssPath)) {
|
|
151
|
+
await buildAppCss();
|
|
152
|
+
watchDevCss("app.css", [resolve(appCssPath, "..")], buildAppCss);
|
|
153
|
+
}
|
|
154
|
+
await buildBrowserPerformance(publicDir, appId);
|
|
150
155
|
|
|
151
|
-
watchDevCss("app.css", [resolve(appCssPath, "..")], buildAppCss);
|
|
152
156
|
if (appId === "core" && existsSync(globalCssEntry)) {
|
|
153
157
|
watchDevCss("global.css", [globalCssEntry, resolve(frameworkDir, "src/styles")], buildGlobalCss);
|
|
154
158
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Isolated two-process recovery acceptance for the local NATS cluster.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* bun packages/cloud/scripts/sync-recovery-smoke.ts prepare --namespace cloud-recovery-smoke-<unique>
|
|
5
5
|
* Stop the application fleet across the printed nextTick boundary, keeping NATS up.
|
|
6
6
|
* Restart the fleet, then run the same command with `recover`.
|
|
7
7
|
* No provider or application-domain effects; successful recovery deletes only
|
|
8
8
|
* the exact test streams after checking their broker identity metadata.
|
|
9
9
|
*/
|
|
10
|
+
|
|
11
|
+
import { parseArgs } from "node:util";
|
|
10
12
|
import { createSync, type SyncResourceSummary, type Worker } from "@k2b/sync";
|
|
11
13
|
import { connect, type NatsConnection } from "@nats-io/transport-node";
|
|
14
|
+
import { env } from "../src/config/env";
|
|
12
15
|
|
|
13
16
|
const APPLICATION = "cloud-recovery-smoke";
|
|
14
17
|
const JOB_ID = "restart-job";
|
|
@@ -48,16 +51,29 @@ const removeTestStreams = async (connection: NatsConnection, namespace: string,
|
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
export const main = async (): Promise<void> => {
|
|
51
|
-
const
|
|
54
|
+
const { values: options, positionals } = parseArgs({
|
|
55
|
+
args: Bun.argv.slice(2),
|
|
56
|
+
allowPositionals: true,
|
|
57
|
+
options: { namespace: { type: "string" }, help: { type: "boolean", default: false } },
|
|
58
|
+
});
|
|
59
|
+
if (options.help) {
|
|
60
|
+
console.log(`Usage: bun packages/cloud/scripts/sync-recovery-smoke.ts <prepare|recover> --namespace cloud-recovery-smoke-<unique>
|
|
61
|
+
|
|
62
|
+
Two-phase recovery acceptance against the application's NATS servers (NATS_SERVERS, default nats://127.0.0.1:4222).
|
|
63
|
+
Run "prepare", restart the application fleet while NATS stays up, then run "recover" with the same namespace.
|
|
64
|
+
`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const phase = positionals[0];
|
|
52
68
|
check(phase === "prepare" || phase === "recover", "Pass prepare or recover");
|
|
53
|
-
const namespace =
|
|
54
|
-
check(/^cloud-recovery-smoke-[A-Za-z0-9_-]{6,60}$/.test(namespace), "
|
|
55
|
-
const servers = (
|
|
69
|
+
const namespace = options.namespace?.trim() ?? "";
|
|
70
|
+
check(/^cloud-recovery-smoke-[A-Za-z0-9_-]{6,60}$/.test(namespace), "Pass a unique --namespace cloud-recovery-smoke-<suffix>");
|
|
71
|
+
const servers = (env.NATS_SERVERS ?? "nats://127.0.0.1:4222")
|
|
56
72
|
.split(",")
|
|
57
73
|
.map((value) => value.trim())
|
|
58
74
|
.filter(Boolean);
|
|
59
75
|
const connection = await connect({ servers, name: `${APPLICATION}-${phase}`, ignoreClusterUpdates: true });
|
|
60
|
-
const sync = createSync({ connection, namespace, application: APPLICATION, defaults: { replicas:
|
|
76
|
+
const sync = createSync({ connection, namespace, application: APPLICATION, defaults: { replicas: env.SYNC_REPLICAS } });
|
|
61
77
|
const job = sync.job<{ preparedAt: string }>({
|
|
62
78
|
id: JOB_ID,
|
|
63
79
|
delivery: { ackWaitMs: 30_000, maxAttempts: 3, backoffMs: [1_000, 2_000] },
|
|
@@ -11,12 +11,12 @@ const text = (value: string, label: string, max = MAX_SHORT_TEXT): string => {
|
|
|
11
11
|
return normalized;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
const labels = (values: Readonly<Record<string, string>> | undefined, allowed: Set<string>, label: string) => {
|
|
14
|
+
const labels = (values: Readonly<Record<string, string>> | undefined, allowed: Set<string>, label: string, max = MAX_SHORT_TEXT) => {
|
|
15
15
|
if (!values) return undefined;
|
|
16
16
|
const normalized: Record<string, string> = {};
|
|
17
17
|
for (const [key, value] of Object.entries(values)) {
|
|
18
18
|
if (!allowed.has(key)) throw new Error(`${label} contains unknown key ${JSON.stringify(key)}`);
|
|
19
|
-
normalized[key] = text(value, `${label}.${key}
|
|
19
|
+
normalized[key] = text(value, `${label}.${key}`, max);
|
|
20
20
|
}
|
|
21
21
|
return normalized;
|
|
22
22
|
};
|
|
@@ -34,6 +34,7 @@ export const compileAppPresentation = (app: AppMeta, catalog: AppPresentationCat
|
|
|
34
34
|
groupIds.add(group.id);
|
|
35
35
|
}
|
|
36
36
|
const adminHrefs = new Set((app.adminNav ?? []).flatMap((group) => group.links.map((link) => link.href)));
|
|
37
|
+
const searchHrefs = new Set((app.searchLinks ?? []).map((link) => link.href));
|
|
37
38
|
const legalHrefs = new Set((app.legalLinks ?? []).map((link) => link.href));
|
|
38
39
|
const translations: Record<string, AppPresentationTranslation> = {};
|
|
39
40
|
|
|
@@ -49,6 +50,17 @@ export const compileAppPresentation = (app: AppMeta, catalog: AppPresentationCat
|
|
|
49
50
|
: {}),
|
|
50
51
|
...(translation.adminGroups ? { adminGroups: labels(translation.adminGroups, groupIds, `${canonical}.adminGroups`) } : {}),
|
|
51
52
|
...(translation.adminLinks ? { adminLinks: labels(translation.adminLinks, adminHrefs, `${canonical}.adminLinks`) } : {}),
|
|
53
|
+
...(translation.searchLinks ? { searchLinks: labels(translation.searchLinks, searchHrefs, `${canonical}.searchLinks`) } : {}),
|
|
54
|
+
...(translation.searchLinkDescriptions
|
|
55
|
+
? {
|
|
56
|
+
searchLinkDescriptions: labels(
|
|
57
|
+
translation.searchLinkDescriptions,
|
|
58
|
+
searchHrefs,
|
|
59
|
+
`${canonical}.searchLinkDescriptions`,
|
|
60
|
+
MAX_DESCRIPTION,
|
|
61
|
+
),
|
|
62
|
+
}
|
|
63
|
+
: {}),
|
|
52
64
|
...(translation.legalLinks ? { legalLinks: labels(translation.legalLinks, legalHrefs, `${canonical}.legalLinks`) } : {}),
|
|
53
65
|
};
|
|
54
66
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { AppRuntimeMetadata } from "../contracts/registry";
|
|
2
2
|
|
|
3
|
+
declare const __CLOUD_VERSION__: string;
|
|
3
4
|
declare const __CLOUD_RELEASE__: string;
|
|
4
5
|
declare const __CLOUD_SYNC_VERSION__: string;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
/** Cloud version and release label baked into the bundle by `scripts/build.ts`. */
|
|
8
|
+
export const buildMetadata = {
|
|
9
|
+
version: typeof __CLOUD_VERSION__ === "string" ? __CLOUD_VERSION__ : "0.0.0-local",
|
|
7
10
|
release: typeof __CLOUD_RELEASE__ === "string" ? __CLOUD_RELEASE__ : "development",
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export const appRuntimeMetadata: AppRuntimeMetadata = {
|
|
14
|
+
...buildMetadata,
|
|
8
15
|
syncVersion: typeof __CLOUD_SYNC_VERSION__ === "string" ? __CLOUD_SYNC_VERSION__ : "unknown",
|
|
9
16
|
};
|