@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
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { sql } from "bun";
|
|
2
|
+
import { logger } from "./logging";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PostgreSQL transactional-outbox dispatcher.
|
|
6
|
+
*
|
|
7
|
+
* Domain writers insert a row in their own transaction; this dispatcher claims
|
|
8
|
+
* pending rows (`FOR UPDATE SKIP LOCKED`), publishes them, and records
|
|
9
|
+
* delivery or an exponential-backoff retry. Rows stay durable until they are
|
|
10
|
+
* delivered (or dead after `maxAttempts`, when the table has a `dead_at`
|
|
11
|
+
* column), and delivered rows are pruned after a retention period.
|
|
12
|
+
*
|
|
13
|
+
* Required columns: `id uuid`, `attempts int`, `next_attempt_at timestamptz`,
|
|
14
|
+
* `claimed_until timestamptz`, `delivered_at timestamptz`, `last_error text`,
|
|
15
|
+
* `created_at timestamptz`. `maxAttempts` additionally needs `dead_at`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const DEFAULT_CLAIM_MS = 30_000;
|
|
19
|
+
const DEFAULT_BATCH_SIZE = 100;
|
|
20
|
+
const DELIVERED_RETENTION = "7 days";
|
|
21
|
+
const DEAD_RETENTION = "30 days";
|
|
22
|
+
const IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
|
|
23
|
+
|
|
24
|
+
export type OutboxRow = {
|
|
25
|
+
id: string;
|
|
26
|
+
attempts: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type PgOutboxConfig<Row extends OutboxRow> = {
|
|
30
|
+
/** Schema-qualified table, e.g. `mail.live_invalidation_outbox`. */
|
|
31
|
+
table: string;
|
|
32
|
+
/** Log source. */
|
|
33
|
+
name: string;
|
|
34
|
+
publish: (row: Row) => Promise<unknown>;
|
|
35
|
+
reconcileIntervalMs: number;
|
|
36
|
+
/**
|
|
37
|
+
* Column whose rows must be delivered in insertion order. A pending earlier
|
|
38
|
+
* row with the same value blocks later ones until it is delivered or dead.
|
|
39
|
+
*/
|
|
40
|
+
orderBy?: string;
|
|
41
|
+
/** Mark rows dead after this many failed attempts (requires `dead_at`). */
|
|
42
|
+
maxAttempts?: number;
|
|
43
|
+
claimMs?: number;
|
|
44
|
+
batchSize?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type PgOutbox<Row extends OutboxRow> = {
|
|
48
|
+
claim(limit?: number): Promise<Row[]>;
|
|
49
|
+
dispatch(row: Row, publish?: (row: Row) => Promise<unknown>): Promise<void>;
|
|
50
|
+
/** Drain every claimable row; concurrent calls join the active pass. */
|
|
51
|
+
reconcile(): Promise<number>;
|
|
52
|
+
/** `reconcile()` with failures logged instead of thrown. */
|
|
53
|
+
notify(): Promise<void>;
|
|
54
|
+
start(): void;
|
|
55
|
+
stop(): Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const identifier = (name: string, label: string): ReturnType<typeof sql.unsafe> => {
|
|
59
|
+
if (!name.split(".").every((part) => IDENTIFIER.test(part))) throw new Error(`Invalid outbox ${label}: ${name}`);
|
|
60
|
+
return sql.unsafe(name);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const createPgOutbox = <Row extends OutboxRow>(config: PgOutboxConfig<Row>): PgOutbox<Row> => {
|
|
64
|
+
const table = identifier(config.table, "table");
|
|
65
|
+
const orderBy = config.orderBy ? identifier(config.orderBy, "ordering column") : null;
|
|
66
|
+
const maxAttempts = config.maxAttempts ?? null;
|
|
67
|
+
const claimMs = config.claimMs ?? DEFAULT_CLAIM_MS;
|
|
68
|
+
const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
69
|
+
const log = logger(config.name);
|
|
70
|
+
const notDead = maxAttempts === null ? sql`` : sql`AND dead_at IS NULL`;
|
|
71
|
+
const earlierNotDead = maxAttempts === null ? sql`` : sql`AND earlier.dead_at IS NULL`;
|
|
72
|
+
|
|
73
|
+
const claim: PgOutbox<Row>["claim"] = async (limit = batchSize) => {
|
|
74
|
+
const cap = Math.min(Math.max(limit, 1), batchSize);
|
|
75
|
+
const ordered =
|
|
76
|
+
orderBy === null
|
|
77
|
+
? sql``
|
|
78
|
+
: sql`
|
|
79
|
+
AND NOT EXISTS (
|
|
80
|
+
SELECT 1
|
|
81
|
+
FROM ${table} earlier
|
|
82
|
+
WHERE earlier.${orderBy} = current.${orderBy}
|
|
83
|
+
AND earlier.delivered_at IS NULL
|
|
84
|
+
${earlierNotDead}
|
|
85
|
+
AND (earlier.created_at, earlier.id) < (current.created_at, current.id)
|
|
86
|
+
)
|
|
87
|
+
`;
|
|
88
|
+
// One statement: the CTE claim and the update commit atomically.
|
|
89
|
+
return sql<Row[]>`
|
|
90
|
+
WITH candidates AS MATERIALIZED (
|
|
91
|
+
SELECT current.id
|
|
92
|
+
FROM ${table} current
|
|
93
|
+
WHERE current.delivered_at IS NULL
|
|
94
|
+
${notDead}
|
|
95
|
+
AND current.next_attempt_at <= now()
|
|
96
|
+
AND (current.claimed_until IS NULL OR current.claimed_until <= now())
|
|
97
|
+
${ordered}
|
|
98
|
+
ORDER BY current.next_attempt_at, current.created_at, current.id
|
|
99
|
+
LIMIT ${cap}
|
|
100
|
+
FOR UPDATE SKIP LOCKED
|
|
101
|
+
)
|
|
102
|
+
UPDATE ${table} outbox
|
|
103
|
+
SET claimed_until = now() + (${claimMs} * interval '1 millisecond')
|
|
104
|
+
FROM candidates
|
|
105
|
+
WHERE outbox.id = candidates.id
|
|
106
|
+
RETURNING outbox.*
|
|
107
|
+
`;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const dispatch: PgOutbox<Row>["dispatch"] = async (row, publish = config.publish) => {
|
|
111
|
+
try {
|
|
112
|
+
await publish(row);
|
|
113
|
+
await sql`
|
|
114
|
+
UPDATE ${table}
|
|
115
|
+
SET delivered_at = now(), claimed_until = NULL, last_error = NULL
|
|
116
|
+
WHERE id = ${row.id}::uuid AND delivered_at IS NULL ${notDead} AND attempts = ${row.attempts}
|
|
117
|
+
`;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
const attempts = row.attempts + 1;
|
|
120
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
121
|
+
const delaySeconds = Math.min(300, 2 ** Math.min(attempts, 8));
|
|
122
|
+
const dead = maxAttempts === null ? sql`` : sql`dead_at = CASE WHEN ${attempts} >= ${maxAttempts} THEN now() ELSE dead_at END,`;
|
|
123
|
+
await sql`
|
|
124
|
+
UPDATE ${table}
|
|
125
|
+
SET attempts = ${attempts},
|
|
126
|
+
next_attempt_at = now() + (${delaySeconds} * interval '1 second'),
|
|
127
|
+
claimed_until = NULL,
|
|
128
|
+
${dead}
|
|
129
|
+
last_error = ${message.slice(0, 1_000)}
|
|
130
|
+
WHERE id = ${row.id}::uuid AND delivered_at IS NULL ${notDead} AND attempts = ${row.attempts}
|
|
131
|
+
`;
|
|
132
|
+
log.warn("Outbox delivery failed", { outboxId: row.id, attempts, error: message });
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
let activeReconcile: Promise<number> | null = null;
|
|
137
|
+
let reconcileRequested = false;
|
|
138
|
+
|
|
139
|
+
const reconcile: PgOutbox<Row>["reconcile"] = () => {
|
|
140
|
+
reconcileRequested = true;
|
|
141
|
+
if (activeReconcile) return activeReconcile;
|
|
142
|
+
activeReconcile = (async () => {
|
|
143
|
+
const deadExpired = maxAttempts === null ? sql`` : sql`OR dead_at < now() - ${DEAD_RETENTION}::interval`;
|
|
144
|
+
await sql`
|
|
145
|
+
DELETE FROM ${table}
|
|
146
|
+
WHERE delivered_at < now() - ${DELIVERED_RETENTION}::interval
|
|
147
|
+
${deadExpired}
|
|
148
|
+
`;
|
|
149
|
+
let processed = 0;
|
|
150
|
+
let rows: Row[];
|
|
151
|
+
do {
|
|
152
|
+
reconcileRequested = false;
|
|
153
|
+
rows = await claim();
|
|
154
|
+
// Sequential: a claimed batch may contain ordered rows of one key.
|
|
155
|
+
for (const row of rows) await dispatch(row);
|
|
156
|
+
processed += rows.length;
|
|
157
|
+
} while (reconcileRequested || rows.length > 0);
|
|
158
|
+
return processed;
|
|
159
|
+
})().finally(() => {
|
|
160
|
+
activeReconcile = null;
|
|
161
|
+
});
|
|
162
|
+
return activeReconcile;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const notify: PgOutbox<Row>["notify"] = async () => {
|
|
166
|
+
await reconcile().catch((error) => {
|
|
167
|
+
log.warn("Outbox reconcile failed", { error: error instanceof Error ? error.message : String(error) });
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
172
|
+
|
|
173
|
+
const start: PgOutbox<Row>["start"] = () => {
|
|
174
|
+
if (timer) return;
|
|
175
|
+
timer = setInterval(() => void notify(), config.reconcileIntervalMs);
|
|
176
|
+
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
177
|
+
void notify();
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const stop: PgOutbox<Row>["stop"] = async () => {
|
|
181
|
+
if (timer) clearInterval(timer);
|
|
182
|
+
timer = null;
|
|
183
|
+
await activeReconcile;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
return { claim, dispatch, reconcile, notify, start, stop };
|
|
187
|
+
};
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import * as settings from "../settings";
|
|
2
|
+
|
|
3
|
+
export type GotenbergRenderErrorCode =
|
|
4
|
+
| "bad_input"
|
|
5
|
+
| "not_configured"
|
|
6
|
+
| "html_too_large"
|
|
7
|
+
| "pdf_too_large"
|
|
8
|
+
| "request_failed"
|
|
9
|
+
| "bad_response"
|
|
10
|
+
| "timeout";
|
|
11
|
+
|
|
12
|
+
export class GotenbergRenderError extends Error {
|
|
13
|
+
constructor(
|
|
14
|
+
readonly code: GotenbergRenderErrorCode,
|
|
15
|
+
message: string,
|
|
16
|
+
readonly status?: number,
|
|
17
|
+
) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "GotenbergRenderError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type GotenbergConfig = {
|
|
24
|
+
url: string;
|
|
25
|
+
username?: string;
|
|
26
|
+
password?: string;
|
|
27
|
+
timeoutMs: number;
|
|
28
|
+
maxHtmlBytes: number;
|
|
29
|
+
maxPdfBytes: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type RenderHtmlToPdfInput = {
|
|
33
|
+
html: string;
|
|
34
|
+
headerHtml?: string | null;
|
|
35
|
+
footerHtml?: string | null;
|
|
36
|
+
filename?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type RenderFacturXHtmlToPdfInput = RenderHtmlToPdfInput & {
|
|
40
|
+
xml: string;
|
|
41
|
+
conformanceLevel?: "MINIMUM" | "BASIC WL" | "BASIC" | "EN 16931" | "EXTENDED";
|
|
42
|
+
documentType?: "INVOICE" | "ORDER" | "ORDER RESPONSE";
|
|
43
|
+
facturXVersion?: "1.0";
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type RenderHtmlToPdfResult = {
|
|
47
|
+
pdf: Uint8Array;
|
|
48
|
+
contentType: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type MergePdfsInput = {
|
|
52
|
+
files: Array<{
|
|
53
|
+
pdf: Uint8Array;
|
|
54
|
+
filename?: string;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type GotenbergFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
59
|
+
|
|
60
|
+
export type RenderHtmlToPdfOptions = {
|
|
61
|
+
fetch?: GotenbergFetch;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const DEFAULT_PDF_CONTENT_TYPE = "application/pdf";
|
|
65
|
+
const TEST_HTML = "<!doctype html><html><body><h1>Cloud PDF renderer test</h1></body></html>";
|
|
66
|
+
|
|
67
|
+
const byteLength = (value: string): number => new TextEncoder().encode(value).byteLength;
|
|
68
|
+
|
|
69
|
+
const normalizeBaseUrl = (url: string): string => {
|
|
70
|
+
const trimmed = url.trim();
|
|
71
|
+
if (!trimmed) {
|
|
72
|
+
throw new GotenbergRenderError("not_configured", "Gotenberg URL is not configured.");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const parsed = new URL(trimmed);
|
|
77
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
78
|
+
} catch {
|
|
79
|
+
throw new GotenbergRenderError("not_configured", "Gotenberg URL is invalid.");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const basicAuthHeader = (config: GotenbergConfig): string | null => {
|
|
84
|
+
const username = config.username?.trim() ?? "";
|
|
85
|
+
const password = config.password ?? "";
|
|
86
|
+
if (!username && !password) return null;
|
|
87
|
+
return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const abortSignal = (timeoutMs: number): AbortSignal => {
|
|
91
|
+
if (timeoutMs <= 0) {
|
|
92
|
+
throw new GotenbergRenderError("not_configured", "Gotenberg timeout must be greater than 0 ms.");
|
|
93
|
+
}
|
|
94
|
+
return AbortSignal.timeout(timeoutMs);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const sanitizeFetchError = (error: unknown): GotenbergRenderError => {
|
|
98
|
+
if (error instanceof GotenbergRenderError) return error;
|
|
99
|
+
if (error instanceof DOMException && error.name === "TimeoutError") {
|
|
100
|
+
return new GotenbergRenderError("timeout", "Gotenberg request timed out.");
|
|
101
|
+
}
|
|
102
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
103
|
+
return new GotenbergRenderError("timeout", "Gotenberg request timed out.");
|
|
104
|
+
}
|
|
105
|
+
return new GotenbergRenderError("request_failed", "Gotenberg request failed.");
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const renderHtmlToPdfWithConfig = async (
|
|
109
|
+
input: RenderHtmlToPdfInput,
|
|
110
|
+
config: GotenbergConfig,
|
|
111
|
+
options: RenderHtmlToPdfOptions = {},
|
|
112
|
+
): Promise<RenderHtmlToPdfResult> => {
|
|
113
|
+
const htmlBytes = byteLength(input.html);
|
|
114
|
+
if (htmlBytes > config.maxHtmlBytes) {
|
|
115
|
+
throw new GotenbergRenderError("html_too_large", `HTML input is too large (${htmlBytes} bytes, limit ${config.maxHtmlBytes} bytes).`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const baseUrl = normalizeBaseUrl(config.url);
|
|
119
|
+
const form = new FormData();
|
|
120
|
+
form.append("files", new Blob([input.html], { type: "text/html" }), "index.html");
|
|
121
|
+
if (input.headerHtml?.trim()) form.append("files", new Blob([input.headerHtml], { type: "text/html" }), "header.html");
|
|
122
|
+
if (input.footerHtml?.trim()) form.append("files", new Blob([input.footerHtml], { type: "text/html" }), "footer.html");
|
|
123
|
+
form.append("preferCssPageSize", "true");
|
|
124
|
+
form.append("printBackground", "true");
|
|
125
|
+
|
|
126
|
+
const headers = new Headers();
|
|
127
|
+
const authHeader = basicAuthHeader(config);
|
|
128
|
+
if (authHeader) headers.set("Authorization", authHeader);
|
|
129
|
+
|
|
130
|
+
const transport = options.fetch ?? fetch;
|
|
131
|
+
let response: Response;
|
|
132
|
+
try {
|
|
133
|
+
response = await transport(`${baseUrl}/forms/chromium/convert/html`, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers,
|
|
136
|
+
body: form,
|
|
137
|
+
signal: abortSignal(config.timeoutMs),
|
|
138
|
+
});
|
|
139
|
+
} catch (error) {
|
|
140
|
+
throw sanitizeFetchError(error);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new GotenbergRenderError("bad_response", `Gotenberg returned HTTP ${response.status}.`, response.status);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const buffer = await response.arrayBuffer();
|
|
148
|
+
if (buffer.byteLength > config.maxPdfBytes) {
|
|
149
|
+
throw new GotenbergRenderError(
|
|
150
|
+
"pdf_too_large",
|
|
151
|
+
`PDF output is too large (${buffer.byteLength} bytes, limit ${config.maxPdfBytes} bytes).`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
pdf: new Uint8Array(buffer),
|
|
157
|
+
contentType: response.headers.get("content-type") || DEFAULT_PDF_CONTENT_TYPE,
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const renderFacturXHtmlToPdfWithConfig = async (
|
|
162
|
+
input: RenderFacturXHtmlToPdfInput,
|
|
163
|
+
config: GotenbergConfig,
|
|
164
|
+
options: RenderHtmlToPdfOptions = {},
|
|
165
|
+
): Promise<RenderHtmlToPdfResult> => {
|
|
166
|
+
const htmlBytes = byteLength(input.html);
|
|
167
|
+
const xmlBytes = byteLength(input.xml);
|
|
168
|
+
if (htmlBytes > config.maxHtmlBytes) {
|
|
169
|
+
throw new GotenbergRenderError("html_too_large", `HTML input is too large (${htmlBytes} bytes, limit ${config.maxHtmlBytes} bytes).`);
|
|
170
|
+
}
|
|
171
|
+
if (xmlBytes === 0 || xmlBytes > config.maxHtmlBytes) {
|
|
172
|
+
throw new GotenbergRenderError(
|
|
173
|
+
xmlBytes === 0 ? "bad_input" : "html_too_large",
|
|
174
|
+
xmlBytes === 0
|
|
175
|
+
? "Factur-X XML must not be empty."
|
|
176
|
+
: `Factur-X XML input is too large (${xmlBytes} bytes, limit ${config.maxHtmlBytes} bytes).`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const baseUrl = normalizeBaseUrl(config.url);
|
|
181
|
+
const form = new FormData();
|
|
182
|
+
form.append("files", new Blob([input.html], { type: "text/html" }), "index.html");
|
|
183
|
+
if (input.headerHtml?.trim()) form.append("files", new Blob([input.headerHtml], { type: "text/html" }), "header.html");
|
|
184
|
+
if (input.footerHtml?.trim()) form.append("files", new Blob([input.footerHtml], { type: "text/html" }), "footer.html");
|
|
185
|
+
form.append("facturxXml", new Blob([input.xml], { type: "application/xml" }), "factur-x.xml");
|
|
186
|
+
form.append("facturxConformanceLevel", input.conformanceLevel ?? "EN 16931");
|
|
187
|
+
form.append("facturxDocumentType", input.documentType ?? "INVOICE");
|
|
188
|
+
form.append("facturxVersion", input.facturXVersion ?? "1.0");
|
|
189
|
+
form.append("pdfa", "PDF/A-3b");
|
|
190
|
+
form.append("preferCssPageSize", "true");
|
|
191
|
+
form.append("printBackground", "true");
|
|
192
|
+
|
|
193
|
+
const headers = new Headers();
|
|
194
|
+
const authHeader = basicAuthHeader(config);
|
|
195
|
+
if (authHeader) headers.set("Authorization", authHeader);
|
|
196
|
+
let response: Response;
|
|
197
|
+
try {
|
|
198
|
+
response = await (options.fetch ?? fetch)(`${baseUrl}/forms/chromium/convert/html`, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers,
|
|
201
|
+
body: form,
|
|
202
|
+
signal: abortSignal(config.timeoutMs),
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
throw sanitizeFetchError(error);
|
|
206
|
+
}
|
|
207
|
+
if (!response.ok) throw new GotenbergRenderError("bad_response", `Gotenberg returned HTTP ${response.status}.`, response.status);
|
|
208
|
+
const buffer = await response.arrayBuffer();
|
|
209
|
+
if (buffer.byteLength > config.maxPdfBytes) {
|
|
210
|
+
throw new GotenbergRenderError("pdf_too_large", `PDF output is too large (${buffer.byteLength} bytes, limit ${config.maxPdfBytes} bytes).`);
|
|
211
|
+
}
|
|
212
|
+
return { pdf: new Uint8Array(buffer), contentType: response.headers.get("content-type") || DEFAULT_PDF_CONTENT_TYPE };
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export const mergePdfsWithConfig = async (
|
|
216
|
+
input: MergePdfsInput,
|
|
217
|
+
config: GotenbergConfig,
|
|
218
|
+
options: RenderHtmlToPdfOptions = {},
|
|
219
|
+
): Promise<RenderHtmlToPdfResult> => {
|
|
220
|
+
if (input.files.length === 0) {
|
|
221
|
+
throw new GotenbergRenderError("bad_input", "At least one PDF file is required.");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const baseUrl = normalizeBaseUrl(config.url);
|
|
225
|
+
const form = new FormData();
|
|
226
|
+
input.files.forEach((file, index) => {
|
|
227
|
+
const filename = `${String(index + 1).padStart(6, "0")}.pdf`;
|
|
228
|
+
const bytes = file.pdf.buffer.slice(file.pdf.byteOffset, file.pdf.byteOffset + file.pdf.byteLength) as ArrayBuffer;
|
|
229
|
+
form.append("files", new Blob([bytes], { type: DEFAULT_PDF_CONTENT_TYPE }), filename);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const headers = new Headers();
|
|
233
|
+
const authHeader = basicAuthHeader(config);
|
|
234
|
+
if (authHeader) headers.set("Authorization", authHeader);
|
|
235
|
+
|
|
236
|
+
const transport = options.fetch ?? fetch;
|
|
237
|
+
let response: Response;
|
|
238
|
+
try {
|
|
239
|
+
response = await transport(`${baseUrl}/forms/pdfengines/merge`, {
|
|
240
|
+
method: "POST",
|
|
241
|
+
headers,
|
|
242
|
+
body: form,
|
|
243
|
+
signal: abortSignal(config.timeoutMs),
|
|
244
|
+
});
|
|
245
|
+
} catch (error) {
|
|
246
|
+
throw sanitizeFetchError(error);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!response.ok) {
|
|
250
|
+
throw new GotenbergRenderError("bad_response", `Gotenberg returned HTTP ${response.status}.`, response.status);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const buffer = await response.arrayBuffer();
|
|
254
|
+
if (buffer.byteLength > config.maxPdfBytes) {
|
|
255
|
+
throw new GotenbergRenderError(
|
|
256
|
+
"pdf_too_large",
|
|
257
|
+
`PDF output is too large (${buffer.byteLength} bytes, limit ${config.maxPdfBytes} bytes).`,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
pdf: new Uint8Array(buffer),
|
|
263
|
+
contentType: response.headers.get("content-type") || DEFAULT_PDF_CONTENT_TYPE,
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export const getGotenbergConfig = async (): Promise<GotenbergConfig> => ({
|
|
268
|
+
url: await settings.get<string>("gotenberg.url"),
|
|
269
|
+
username: await settings.get<string>("gotenberg.username"),
|
|
270
|
+
password: await settings.get<string>("gotenberg.password"),
|
|
271
|
+
timeoutMs: await settings.get<number>("gotenberg.timeout_ms"),
|
|
272
|
+
maxHtmlBytes: await settings.get<number>("gotenberg.max_html_bytes"),
|
|
273
|
+
maxPdfBytes: await settings.get<number>("gotenberg.max_pdf_bytes"),
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
export const renderHtmlToPdf = async (input: RenderHtmlToPdfInput, options: RenderHtmlToPdfOptions = {}): Promise<RenderHtmlToPdfResult> =>
|
|
277
|
+
renderHtmlToPdfWithConfig(input, await getGotenbergConfig(), options);
|
|
278
|
+
|
|
279
|
+
export const renderFacturXHtmlToPdf = async (
|
|
280
|
+
input: RenderFacturXHtmlToPdfInput,
|
|
281
|
+
options: RenderHtmlToPdfOptions = {},
|
|
282
|
+
): Promise<RenderHtmlToPdfResult> => renderFacturXHtmlToPdfWithConfig(input, await getGotenbergConfig(), options);
|
|
283
|
+
|
|
284
|
+
export const mergePdfs = async (input: MergePdfsInput, options: RenderHtmlToPdfOptions = {}): Promise<RenderHtmlToPdfResult> =>
|
|
285
|
+
mergePdfsWithConfig(input, await getGotenbergConfig(), options);
|
|
286
|
+
|
|
287
|
+
export const testGotenberg = async (options: RenderHtmlToPdfOptions = {}): Promise<{ bytes: number; contentType: string }> => {
|
|
288
|
+
const result = await renderHtmlToPdf({ html: TEST_HTML, filename: "index.html" }, options);
|
|
289
|
+
return { bytes: result.pdf.byteLength, contentType: result.contentType };
|
|
290
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
GotenbergConfig,
|
|
3
|
+
GotenbergRenderErrorCode,
|
|
4
|
+
MergePdfsInput,
|
|
5
|
+
RenderFacturXHtmlToPdfInput,
|
|
6
|
+
RenderHtmlToPdfInput,
|
|
7
|
+
RenderHtmlToPdfOptions,
|
|
8
|
+
RenderHtmlToPdfResult,
|
|
9
|
+
} from "./gotenberg";
|
|
10
|
+
export {
|
|
11
|
+
GotenbergRenderError,
|
|
12
|
+
getGotenbergConfig,
|
|
13
|
+
mergePdfs,
|
|
14
|
+
mergePdfsWithConfig,
|
|
15
|
+
renderFacturXHtmlToPdf,
|
|
16
|
+
renderFacturXHtmlToPdfWithConfig,
|
|
17
|
+
renderHtmlToPdf,
|
|
18
|
+
renderHtmlToPdfWithConfig,
|
|
19
|
+
testGotenberg,
|
|
20
|
+
} from "./gotenberg";
|
|
21
|
+
export type {
|
|
22
|
+
RenderTemplatePdfPreviewInput,
|
|
23
|
+
RenderTemplatePdfPreviewOptions,
|
|
24
|
+
TemplatePdfPreviewError,
|
|
25
|
+
TemplatePdfPreviewPhase,
|
|
26
|
+
TemplatePdfPreviewResult,
|
|
27
|
+
} from "./template-preview";
|
|
28
|
+
export { renderTemplatePdfPreview } from "./template-preview";
|
|
29
|
+
export type {
|
|
30
|
+
MarkdownPdfErrorCode,
|
|
31
|
+
MarkdownPdfTemplateId,
|
|
32
|
+
RenderMarkdownToPdfInput,
|
|
33
|
+
RenderMarkdownToPdfOptions,
|
|
34
|
+
} from "./markdown";
|
|
35
|
+
export {
|
|
36
|
+
buildMarkdownPdfHtml,
|
|
37
|
+
MARKDOWN_PDF_MAX_CUSTOM_CSS_BYTES,
|
|
38
|
+
MARKDOWN_PDF_MAX_MARKDOWN_BYTES,
|
|
39
|
+
MARKDOWN_PDF_TEMPLATE_IDS,
|
|
40
|
+
MarkdownPdfError,
|
|
41
|
+
renderMarkdownToPdf,
|
|
42
|
+
renderMarkdownToPdfWithConfig,
|
|
43
|
+
} from "./markdown";
|