@k2b/cloud 0.7.0 → 0.9.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/package.json +5 -4
- package/scripts/README.md +10 -0
- package/scripts/build.ts +14 -1
- package/scripts/preload.ts +7 -0
- package/scripts/sync-recovery-smoke.ts +21 -6
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +35 -12
- package/src/_internal/define-app.ts +28 -11
- package/src/_internal/page-responses.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/runtime-context.ts +1 -1
- package/src/access/PermissionEditor.tsx +15 -9
- package/src/access/PrincipalPicker.tsx +9 -3
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -2
- package/src/ai/admin.ts +2 -2
- package/src/ai/assistant-models.ts +1 -1
- package/src/ai/audio-tool.ts +1 -1
- package/src/ai/browser-code-contracts.ts +174 -52
- package/src/ai/browser.ts +4 -2
- package/src/ai/capabilities.ts +3 -3
- package/src/ai/chat/blocks.tsx +127 -50
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-table.tsx +1 -1
- package/src/ai/chat/composer-adapter.ts +48 -13
- package/src/ai/chat/message-utils.ts +18 -5
- package/src/ai/chat/presentation.tsx +24 -11
- package/src/ai/chat/tool-disclosure.tsx +6 -2
- package/src/ai/chat/tool-groups.ts +8 -2
- package/src/ai/chat-quotas.ts +2 -2
- package/src/ai/chat-task-contracts.ts +9 -13
- package/src/ai/chat-tasks.ts +39 -18
- package/src/ai/client/controller.ts +87 -38
- package/src/ai/client/projection.ts +13 -6
- package/src/ai/client/transport.ts +4 -2
- package/src/ai/code-capability-routes.ts +22 -27
- package/src/ai/code-capability-transport.ts +2 -1
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +9 -5
- package/src/ai/code-runtime-tools.ts +16 -3
- package/src/ai/code-source-contracts.ts +100 -32
- package/src/ai/code-source-tools.ts +49 -6
- package/src/ai/compaction.ts +3 -3
- package/src/ai/default-tools.ts +87 -14
- package/src/ai/dictation-runtime.ts +1 -1
- package/src/ai/draft-content.ts +27 -12
- package/src/ai/enrich.ts +1 -1
- package/src/ai/executor.ts +8 -12
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +6 -1
- package/src/ai/file-tools.ts +8 -2
- package/src/ai/files-store.ts +55 -17
- package/src/ai/grids-skill.ts +2 -0
- package/src/ai/http.ts +18 -7
- package/src/ai/index.ts +24 -25
- package/src/ai/inference-calls.ts +3 -4
- 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 +5 -5
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +23 -12
- package/src/ai/migrate.ts +6 -4
- package/src/ai/model-pricing.ts +4 -4
- package/src/ai/pdf-render-worker.ts +3 -2
- package/src/ai/projects-routes.ts +15 -40
- package/src/ai/projects.ts +18 -13
- package/src/ai/quota-provider.ts +6 -5
- package/src/ai/quota-report.ts +5 -5
- package/src/ai/quotas.ts +3 -3
- package/src/ai/routes.ts +60 -34
- package/src/ai/run-timeout.ts +3 -1
- package/src/ai/runtime-tools.ts +6 -7
- package/src/ai/runtime.ts +38 -20
- package/src/ai/settings.ts +1 -1
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-search.ts +21 -10
- package/src/ai/skill-seeds.ts +16 -7
- package/src/ai/skill-tool.ts +6 -1
- package/src/ai/skills-routes.ts +32 -15
- package/src/ai/skills.ts +54 -28
- package/src/ai/store.ts +80 -47
- package/src/ai/structured.ts +6 -2
- package/src/ai/system-prompt.ts +7 -5
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/todo-contracts.ts +24 -12
- package/src/ai/todo-tool.ts +16 -13
- package/src/ai/tools.ts +1 -1
- package/src/ai/transcription.ts +4 -4
- package/src/ai/turn-timing.ts +1 -1
- package/src/ai/ui.tsx +2 -1
- package/src/ai/usage.ts +1 -1
- package/src/ai/vision-tool.ts +38 -17
- package/src/api/admin-ai-quotas.ts +14 -8
- package/src/api/admin-ai-skills.ts +3 -3
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +2 -2
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth/schemas.ts +7 -1
- package/src/api/auth.ts +4 -3
- package/src/api/capabilities.ts +45 -13
- package/src/api/index.ts +5 -5
- package/src/api/mcp.ts +5 -12
- package/src/browser/CloudResourceSearch.tsx +1 -1
- package/src/browser/command-bridge.ts +1 -1
- package/src/browser/command-shortcuts.ts +1 -1
- package/src/browser/commands.ts +8 -7
- package/src/browser/testing.ts +2 -1
- package/src/capabilities/client.ts +1 -1
- package/src/capabilities/command-link.ts +1 -1
- package/src/capabilities/server.ts +2 -1
- package/src/cli/admin/ai-quotas.ts +5 -5
- package/src/cli/admin/app-credentials.ts +7 -9
- package/src/cli/admin/index.ts +3 -3
- 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 -29
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -54
- package/src/config/index.ts +3 -1
- package/src/contracts/capabilities.ts +8 -1
- package/src/contracts/index.ts +5 -7
- package/src/contracts/registry.ts +2 -0
- package/src/contracts/shared.ts +12 -3
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -2
- package/src/server/app-assets.ts +27 -0
- package/src/server/index.ts +3 -2
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +3 -3
- package/src/server/services/access.ts +3 -1
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/announcements/index.ts +4 -4
- package/src/services/app-approval.ts +11 -10
- package/src/services/auth-flows/magic-link.ts +13 -1
- package/src/services/identity/key-config.ts +6 -4
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/logging/index.ts +1 -1
- package/src/services/logging/trace.ts +1 -1
- package/src/services/mandates/index.ts +5 -2
- package/src/services/mandates/policy.ts +106 -6
- package/src/services/notifications/batches.ts +1 -0
- package/src/services/pdf/gotenberg.ts +50 -14
- package/src/services/pdf/index.ts +11 -11
- package/src/services/public-http.ts +1 -1
- package/src/services/rail-shortcuts.ts +1 -1
- package/src/services/rail-snapshot.ts +1 -1
- package/src/services/request-cache-redis.ts +2 -1
- package/src/services/session/user.ts +1 -1
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +6 -8
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +3 -3
- package/src/services/webauthn.ts +1 -1
- package/src/shared/index.ts +3 -6
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminSidebar.tsx +2 -2
- package/src/ssr/AppLaunchpad.island.tsx +12 -2
- package/src/ssr/AppLaunchpadPanel.tsx +4 -4
- package/src/ssr/GlobalSearchDialog.tsx +6 -6
- package/src/ssr/GlobalSearchTrigger.island.tsx +2 -2
- package/src/ssr/Layout.tsx +4 -3
- package/src/ssr/LayoutHeader.tsx +1 -1
- package/src/ssr/LayoutHelp.tsx +4 -6
- package/src/ssr/LayoutHelpTrigger.island.tsx +2 -2
- package/src/ssr/LayoutRail.tsx +3 -2
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +2 -2
- package/src/ssr/ProfilePreferences.island.tsx +1 -1
- package/src/ssr/RailApps.island.tsx +7 -7
- package/src/ssr/admin-navigation.ts +6 -2
- package/src/ssr/index.ts +1 -0
- package/src/ssr/islands/index.ts +2 -2
- package/src/ssr/mobile-menu-history.ts +1 -1
- package/src/ssr/rail-navigation.ts +3 -2
- package/src/ssr/request-path.ts +12 -0
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +16 -91
- package/src/workflows/ai/store.ts +1 -1
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/store/index.ts +2 -2
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/session/test-fixture.ts +0 -18
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { type DialogRender, dialogCore, toast, useLocale } from "@k2b/ui";
|
|
2
1
|
import { query } from "@k2b/stdlib/solid";
|
|
3
|
-
import {
|
|
4
|
-
import { COMMANDS_CHANGED, collectContextAwareCommands } from "../browser/command-bridge";
|
|
5
|
-
import { contextCommandsWithShortcuts } from "../browser/command-shortcuts";
|
|
6
|
-
import { openCommand, runContextAwareCommand } from "../browser/commands";
|
|
7
|
-
import { loadSearchCommands, type PaletteCommand } from "../browser/search-commands";
|
|
2
|
+
import { type DialogRender, dialogCore, toast, useLocale } from "@k2b/ui";
|
|
8
3
|
import { createEffect, createSignal, For, onCleanup, onMount } from "solid-js";
|
|
9
4
|
import type { SearchItem } from "../api/search/schemas";
|
|
10
5
|
import CloudResourceSearch from "../browser/CloudResourceSearch";
|
|
6
|
+
import { COMMANDS_CHANGED, collectContextAwareCommands } from "../browser/command-bridge";
|
|
7
|
+
import { contextCommandsWithShortcuts } from "../browser/command-shortcuts";
|
|
8
|
+
import { openCommand, runContextAwareCommand } from "../browser/commands";
|
|
11
9
|
import type { NavigationSearchItem } from "../browser/navigation-search";
|
|
12
10
|
import { resourceSearchDialogOptions } from "../browser/resource-search-dialog";
|
|
13
11
|
import { resourceSearchMessages } from "../browser/resource-search-messages";
|
|
14
12
|
import { type GlobalSearchOptions, requestSearchNavigation } from "../browser/search-bridge";
|
|
13
|
+
import { loadSearchCommands, type PaletteCommand } from "../browser/search-commands";
|
|
15
14
|
import { attachSpotlightPosition } from "../browser/spotlight-position";
|
|
15
|
+
import { resolveCommand } from "../capabilities/client";
|
|
16
16
|
|
|
17
17
|
type GlobalSearchDialogProps = {
|
|
18
18
|
request?: GlobalSearchOptions;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { registerContextAwareCommand, runContextAwareCommand } from "../browser/commands";
|
|
2
|
-
import { attachCommandShortcuts } from "../browser/command-shortcuts";
|
|
3
1
|
import { IconButton, Tooltip, useLocale } from "@k2b/ui";
|
|
4
2
|
import { createEffect, onCleanup, onMount } from "solid-js";
|
|
3
|
+
import { attachCommandShortcuts } from "../browser/command-shortcuts";
|
|
4
|
+
import { registerContextAwareCommand, runContextAwareCommand } from "../browser/commands";
|
|
5
5
|
import type { NavigationSearchItem } from "../browser/navigation-search";
|
|
6
6
|
import { openGlobalSearch } from "../browser/search";
|
|
7
7
|
import { registerGlobalSearchHost } from "../browser/search-bridge";
|
package/src/ssr/Layout.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { getLayoutHelp } from "./help";
|
|
2
|
-
import { navigationSearchItems } from "../browser/navigation-search";
|
|
3
1
|
import type { DateContext } from "@k2b/stdlib";
|
|
4
2
|
import { AppWorkspace, appWorkspaceLayoutStyle, LocaleProvider, NoticeCard } from "@k2b/ui";
|
|
5
3
|
import type { JSX } from "solid-js/jsx-runtime";
|
|
6
4
|
import { readAppWorkspaceLayoutCookie, resolveAppWorkspaceLayoutForSidebar } from "../_internal/app-workspace-state";
|
|
5
|
+
import { navigationSearchItems } from "../browser/navigation-search";
|
|
7
6
|
import { resolveNavMatch } from "../contracts/app"; // ==========================
|
|
8
7
|
import { defaultRailPreferences } from "../contracts/rail-preferences";
|
|
9
8
|
import { hasRole, type User } from "../contracts/shared";
|
|
@@ -18,6 +17,7 @@ import { visibleNavigationApps } from "./app-navigation";
|
|
|
18
17
|
import BrowserPushRegistration from "./BrowserPushRegistration.island";
|
|
19
18
|
import GlobalAnnouncements from "./GlobalAnnouncements.island";
|
|
20
19
|
import type { GlobalSearchHelpApp } from "./GlobalSearchHelpDialog";
|
|
20
|
+
import { getLayoutHelp } from "./help";
|
|
21
21
|
import LayoutFooter from "./LayoutFooter";
|
|
22
22
|
import LayoutHeader from "./LayoutHeader";
|
|
23
23
|
import LayoutRail, { type LayoutAppLink } from "./LayoutRail";
|
|
@@ -26,6 +26,7 @@ import type { LayoutBreadcrumb } from "./layout-runtime";
|
|
|
26
26
|
import { platformMessages } from "./platform-messages";
|
|
27
27
|
import RegisteredHelpDocuments from "./RegisteredHelpDocuments.island";
|
|
28
28
|
import { sortRailApps } from "./rail-navigation";
|
|
29
|
+
import { requestPath } from "./request-path";
|
|
29
30
|
import { getLocalizedRuntimeContext, type RuntimeContext } from "./runtime";
|
|
30
31
|
import TimezoneCookie from "./TimezoneCookie.island";
|
|
31
32
|
|
|
@@ -257,7 +258,7 @@ export default function Layout(props: LayoutProps) {
|
|
|
257
258
|
openAppsLabel={t.openApps}
|
|
258
259
|
apps={allApps}
|
|
259
260
|
railSettings={c.get("railPreferences") ?? defaultRailPreferences()}
|
|
260
|
-
|
|
261
|
+
currentPath={requestPath(c)}
|
|
261
262
|
profileAvatarSrc={profileAvatarSrc}
|
|
262
263
|
profileName={profileName}
|
|
263
264
|
searchHelpApps={searchHelpApps}
|
package/src/ssr/LayoutHeader.tsx
CHANGED
|
@@ -4,8 +4,8 @@ import type { CloudTheme } from "../shared/theme";
|
|
|
4
4
|
import AppLaunchpad, { type AppLaunchpadApp } from "./AppLaunchpad.island";
|
|
5
5
|
import type { GlobalSearchHelpApp } from "./GlobalSearchHelpDialog";
|
|
6
6
|
import GlobalSearchTrigger from "./GlobalSearchTrigger.island";
|
|
7
|
-
import LayoutHelpTrigger from "./LayoutHelpTrigger.island";
|
|
8
7
|
import LayoutBreadcrumbs from "./LayoutBreadcrumbs.island";
|
|
8
|
+
import LayoutHelpTrigger from "./LayoutHelpTrigger.island";
|
|
9
9
|
import LayoutPreferences from "./LayoutPreferences.island";
|
|
10
10
|
import type { LayoutBreadcrumb } from "./layout-runtime";
|
|
11
11
|
import ProfilePreferences from "./ProfilePreferences.island";
|
package/src/ssr/LayoutHelp.tsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { searchHelpTopics } from "./layout-help-search";
|
|
1
|
+
import type { HelpDocumentManifest, HelpDocumentPayload, HelpSearchPayload } from "@k2b/cloud/shared";
|
|
3
2
|
import { clipboard } from "@k2b/stdlib/solid";
|
|
4
3
|
import { Button, IconButton, IconButtonLink, MarkdownView, NoticeCard, Placeholder, prompts, ScrollArea, useLocale } from "@k2b/ui";
|
|
5
|
-
import type { HelpDocumentManifest, HelpDocumentPayload, HelpSearchPayload } from "@k2b/cloud/shared";
|
|
6
4
|
import { createEffect, createMemo, createSignal, For, type JSX, onCleanup, onMount, Show } from "solid-js";
|
|
5
|
+
import { COMMANDS_CHANGED, contextCommandsWithShortcuts, shortcutLabel } from "../browser/command-shortcuts";
|
|
7
6
|
import { appAccentStyle } from "./app-appearance";
|
|
8
7
|
import { type GlobalSearchHelpApp, openGlobalSearchHelpDialog } from "./GlobalSearchHelpDialog";
|
|
9
8
|
import { helpMessages } from "./help-messages";
|
|
10
9
|
import { formatHelpBundleMarkdown, formatHelpDocumentMarkdown } from "./layout-help-markdown";
|
|
11
10
|
import { adjacentHelpDocuments, focusHelpArticleHeading, resetHelpArticleScroll } from "./layout-help-navigation";
|
|
11
|
+
import { searchHelpTopics } from "./layout-help-search";
|
|
12
12
|
import { layoutHelpTopicHref } from "./layout-help-url";
|
|
13
13
|
|
|
14
14
|
type HelpTopicBase = {
|
|
@@ -114,9 +114,7 @@ const Shortcuts = (props: { openSearchHelp: () => void }) => {
|
|
|
114
114
|
window.addEventListener(COMMANDS_CHANGED, update);
|
|
115
115
|
onCleanup(() => window.removeEventListener(COMMANDS_CHANGED, update));
|
|
116
116
|
});
|
|
117
|
-
const entries = createMemo(() =>
|
|
118
|
-
commands().filter((command) => command.shortcut),
|
|
119
|
-
);
|
|
117
|
+
const entries = createMemo(() => commands().filter((command) => command.shortcut));
|
|
120
118
|
return (
|
|
121
119
|
<div class="flex flex-col gap-3">
|
|
122
120
|
<p class="text-sm leading-relaxed text-dimmed">{t().shortcutsIntro}</p>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { registerContextAwareCommand } from "../browser/commands";
|
|
2
|
-
import { createEffect, onCleanup } from "solid-js";
|
|
3
1
|
import { IconButton, Tooltip, useLocale } from "@k2b/ui";
|
|
2
|
+
import { createEffect, onCleanup } from "solid-js";
|
|
3
|
+
import { registerContextAwareCommand } from "../browser/commands";
|
|
4
4
|
import type { GlobalSearchHelpApp } from "./GlobalSearchHelpDialog";
|
|
5
5
|
import { openLayoutHelpDialog } from "./LayoutHelp";
|
|
6
6
|
import { platformMessages } from "./platform-messages";
|
package/src/ssr/LayoutRail.tsx
CHANGED
|
@@ -19,7 +19,8 @@ type LayoutRailProps = {
|
|
|
19
19
|
openAppsLabel: string;
|
|
20
20
|
apps: RailApp[];
|
|
21
21
|
railSettings: RailSnapshot;
|
|
22
|
-
|
|
22
|
+
/** `pathname + search` of the request; the island resolves it against the browser origin. */
|
|
23
|
+
currentPath: string;
|
|
23
24
|
profileAvatarSrc?: string;
|
|
24
25
|
profileName: string;
|
|
25
26
|
searchHelpApps: GlobalSearchHelpApp[];
|
|
@@ -46,7 +47,7 @@ export default function LayoutRail(props: LayoutRailProps) {
|
|
|
46
47
|
</a>
|
|
47
48
|
</div>
|
|
48
49
|
<nav class="layout-rail-navigation flex min-h-0 flex-1 flex-col items-center gap-1" aria-label={props.appsLabel}>
|
|
49
|
-
<RailApps apps={props.apps} settings={props.railSettings}
|
|
50
|
+
<RailApps apps={props.apps} settings={props.railSettings} currentPath={props.currentPath} />
|
|
50
51
|
<AppLaunchpad
|
|
51
52
|
profile={{ name: props.profileName, theme: props.theme }}
|
|
52
53
|
apps={props.launchpadApps}
|
|
@@ -2,8 +2,8 @@ import { LocaleProvider } from "@k2b/ui";
|
|
|
2
2
|
import type { JSX } from "solid-js/jsx-runtime";
|
|
3
3
|
import { getLocale } from "../server/locale";
|
|
4
4
|
import { readThemeFromCookieHeader } from "../shared/theme";
|
|
5
|
-
import type { MinimalLayoutContext } from "./layout-context";
|
|
6
5
|
import LayoutPreferences from "./LayoutPreferences.island";
|
|
6
|
+
import type { MinimalLayoutContext } from "./layout-context";
|
|
7
7
|
import TimezoneCookie from "./TimezoneCookie.island";
|
|
8
8
|
|
|
9
9
|
export type MinimalLayoutPreferencePosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BottomSheet, Navigation, SegmentedControl, useLocale } from "@k2b/ui";
|
|
2
2
|
import { createSignal, onCleanup, Show } from "solid-js";
|
|
3
|
-
import {
|
|
3
|
+
import { type AppLaunchpadContext, AppLaunchpadPanel } from "./AppLaunchpadPanel";
|
|
4
4
|
import { openMobileMenu } from "./mobile-menu-history";
|
|
5
|
-
import { observeWorkspaceNavigation, readWorkspaceNavigation } from "./workspace-navigation";
|
|
6
5
|
import { platformMessages } from "./platform-messages";
|
|
6
|
+
import { observeWorkspaceNavigation, readWorkspaceNavigation } from "./workspace-navigation";
|
|
7
7
|
|
|
8
8
|
export function openCloudMobileMenu(apps: AppLaunchpadContext) {
|
|
9
9
|
return openMobileMenu((beforeSelect) => (close, context) => (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createProfileActions } from "./profile-actions";
|
|
2
1
|
import { Avatar, Dropdown } from "@k2b/ui";
|
|
3
2
|
import type { CloudTheme } from "../shared/theme";
|
|
3
|
+
import { createProfileActions } from "./profile-actions";
|
|
4
4
|
|
|
5
5
|
type ProfilePreferencesProps = {
|
|
6
6
|
avatarSrc?: string;
|
|
@@ -5,9 +5,9 @@ import { appAccentStyle } from "./app-appearance";
|
|
|
5
5
|
import { RAIL_PREFERENCES_EVENT, readRailContext } from "./rail-context";
|
|
6
6
|
import { projectRailNavigation, type RailApp, type RailLink, railLinkActive } from "./rail-navigation";
|
|
7
7
|
|
|
8
|
-
function RailIcon(props: { link: RailLink;
|
|
8
|
+
function RailIcon(props: { link: RailLink; currentPath: string }) {
|
|
9
9
|
let target: HTMLAnchorElement | undefined;
|
|
10
|
-
const active = () => railLinkActive(props.link, props.
|
|
10
|
+
const active = () => railLinkActive(props.link, props.currentPath);
|
|
11
11
|
return (
|
|
12
12
|
<>
|
|
13
13
|
<a
|
|
@@ -26,14 +26,14 @@ function RailIcon(props: { link: RailLink; currentUrl: string }) {
|
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export default function RailApps(props: { apps: RailApp[]; settings: RailSnapshot;
|
|
29
|
+
export default function RailApps(props: { apps: RailApp[]; settings: RailSnapshot; currentPath: string }) {
|
|
30
30
|
const locale = useLocale();
|
|
31
31
|
const [settings, setSettings] = createSignal(props.settings);
|
|
32
|
-
const [
|
|
32
|
+
const [currentPath, setCurrentPath] = createSignal(props.currentPath);
|
|
33
33
|
const navigation = createMemo(() => projectRailNavigation(props.apps, settings(), locale()));
|
|
34
34
|
onMount(() => {
|
|
35
35
|
const sync = () => setSettings(readRailContext()?.settings ?? props.settings);
|
|
36
|
-
const syncLocation = () =>
|
|
36
|
+
const syncLocation = () => setCurrentPath(`${window.location.pathname}${window.location.search}${window.location.hash}`);
|
|
37
37
|
sync();
|
|
38
38
|
syncLocation();
|
|
39
39
|
window.addEventListener(RAIL_PREFERENCES_EVENT, sync);
|
|
@@ -51,11 +51,11 @@ export default function RailApps(props: { apps: RailApp[]; settings: RailSnapsho
|
|
|
51
51
|
style={{ flex: "0 1 auto", "scrollbar-width": "none", "scrollbar-gutter": "auto", "overflow-x": "hidden" }}
|
|
52
52
|
data-cloud-rail-apps
|
|
53
53
|
>
|
|
54
|
-
<For each={navigation().shortcuts}>{(link) => <RailIcon link={link}
|
|
54
|
+
<For each={navigation().shortcuts}>{(link) => <RailIcon link={link} currentPath={currentPath()} />}</For>
|
|
55
55
|
<Show when={navigation().shortcuts.length > 0 && navigation().apps.length > 0}>
|
|
56
56
|
<div role="separator" class="my-1 h-px w-5 shrink-0" style={{ background: "var(--ui-divider)" }} />
|
|
57
57
|
</Show>
|
|
58
|
-
<For each={navigation().apps}>{(link) => <RailIcon link={link}
|
|
58
|
+
<For each={navigation().apps}>{(link) => <RailIcon link={link} currentPath={currentPath()} />}</For>
|
|
59
59
|
</ScrollArea>
|
|
60
60
|
);
|
|
61
61
|
}
|
|
@@ -45,7 +45,9 @@ export const buildAdminGroups = (apps: readonly RuntimeContext["apps"][number][]
|
|
|
45
45
|
}))
|
|
46
46
|
.sort((a, b) => a.app.name.localeCompare(b.app.name));
|
|
47
47
|
|
|
48
|
-
aiLinks.push(
|
|
48
|
+
aiLinks.push(
|
|
49
|
+
...contributedApps.flatMap(({ groups }) => groups.filter((group) => group.section === "ai").flatMap((group) => group.links)),
|
|
50
|
+
);
|
|
49
51
|
|
|
50
52
|
const appsWithGroups = new Set(contributedApps.filter(({ groups }) => groups.length > 0).map(({ app }) => app.id));
|
|
51
53
|
const appLinks = apps
|
|
@@ -66,7 +68,9 @@ export const buildAdminGroups = (apps: readonly RuntimeContext["apps"][number][]
|
|
|
66
68
|
{ href: "/admin/announcements", icon: "ti-speakerphone", label: t.announcements },
|
|
67
69
|
],
|
|
68
70
|
},
|
|
69
|
-
...contributedApps.flatMap(({ groups }) =>
|
|
71
|
+
...contributedApps.flatMap(({ groups }) =>
|
|
72
|
+
groups.filter((group) => group.section !== "ai").map(({ label, links }) => ({ label, links })),
|
|
73
|
+
),
|
|
70
74
|
{
|
|
71
75
|
label: t.userManagement,
|
|
72
76
|
links: [
|
package/src/ssr/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export {
|
|
|
9
9
|
type MinimalLayoutPreferencePosition,
|
|
10
10
|
type MinimalLayoutProps,
|
|
11
11
|
} from "./MinimalLayout";
|
|
12
|
+
export { requestPath } from "./request-path";
|
|
12
13
|
export { getLocalizedRuntimeContext, getRuntimeContext, type RuntimeContext } from "./runtime";
|
|
13
14
|
export type { UrlFilterField } from "./url-filter";
|
|
14
15
|
export { createUrlFilter, flag, list, oneOf, page, text } from "./url-filter";
|
package/src/ssr/islands/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default as SearchBar } from "./SearchBar";
|
|
2
|
-
export { provideWorkspaceNavigation } from "../workspace-navigation";
|
|
3
1
|
export { default as WorkspaceNavigationProvider } from "../WorkspaceNavigationProvider";
|
|
2
|
+
export { provideWorkspaceNavigation } from "../workspace-navigation";
|
|
3
|
+
export { default as SearchBar } from "./SearchBar";
|
|
4
4
|
|
|
5
5
|
import { AppLaunchpadButton, AppLaunchpadProvider } from "../AppLaunchpad.island";
|
|
6
6
|
import { LayoutHelpDocuments, LayoutHelpPage } from "../LayoutHelp";
|
|
@@ -48,8 +48,9 @@ export const projectRailNavigation = (apps: readonly RailApp[], settings: RailSn
|
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
/** `currentPath` is the route as `pathname + search`; an absolute URL is accepted but never required. */
|
|
52
|
+
export const railLinkActive = (link: RailLink, currentPath: string): boolean => {
|
|
53
|
+
const current = new URL(currentPath, "https://cloud.invalid");
|
|
53
54
|
const target = new URL(link.match, current);
|
|
54
55
|
if (target.origin !== current.origin) return false;
|
|
55
56
|
if (link.exact) return target.pathname === current.pathname && target.search === current.search && target.hash === current.hash;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The route of the current request as `pathname + search`.
|
|
3
|
+
*
|
|
4
|
+
* Behind the gateway `c.req.raw.url` carries the internal upstream origin
|
|
5
|
+
* (`http://app-mail:3000`), never the public one. Islands and links must
|
|
6
|
+
* therefore receive the route as a path and resolve it against
|
|
7
|
+
* `window.location.origin` in the browser.
|
|
8
|
+
*/
|
|
9
|
+
export const requestPath = (c: { req: { raw: { url: string } } }): string => {
|
|
10
|
+
const url = new URL(c.req.raw.url);
|
|
11
|
+
return `${url.pathname}${url.search}`;
|
|
12
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
export { startWorkflowAiRuntime, stopWorkflowAiRuntime, submitWorkflowAiTask, type WorkflowAiRuntimeOptions } from "./runtime";
|
|
1
2
|
export {
|
|
2
|
-
WORKFLOW_AI_DEPENDENCY_KIND,
|
|
3
3
|
createWorkflowAiTask,
|
|
4
4
|
getWorkflowAiTask,
|
|
5
5
|
getWorkflowAiTaskByEffectKey,
|
|
6
6
|
migrateWorkflowAi,
|
|
7
|
+
WORKFLOW_AI_DEPENDENCY_KIND,
|
|
7
8
|
wakeWorkflowAiTask,
|
|
8
9
|
workflowAiTaskExists,
|
|
9
10
|
} from "./store";
|
|
10
|
-
export { startWorkflowAiRuntime, stopWorkflowAiRuntime, submitWorkflowAiTask, type WorkflowAiRuntimeOptions } from "./runtime";
|
|
11
11
|
export {
|
|
12
12
|
type WorkflowAiRequest,
|
|
13
13
|
type WorkflowAiRequestInput,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { AiBackgroundAdmissionError, AiBackgroundCostError } from "../../ai/inference-calls";
|
|
2
1
|
import { StructuredOutputError } from "@k2b/nessi";
|
|
3
2
|
import type { Job, Worker } from "@k2b/sync";
|
|
4
|
-
import { z } from "zod";
|
|
5
3
|
import { lazySync } from "../../_internal/process-sync";
|
|
6
|
-
import { isAiSettingsError,
|
|
4
|
+
import { isAiSettingsError, runAiStructured } from "../../ai";
|
|
5
|
+
import { AiBackgroundAdmissionError, AiBackgroundCostError } from "../../ai/inference-calls";
|
|
6
|
+
import { executeAiTask } from "../../ai/task-execution";
|
|
7
7
|
|
|
8
|
-
import type { WorkflowJsonValue } from "../contracts";
|
|
9
8
|
import {
|
|
10
9
|
claimWorkflowAiTask,
|
|
11
10
|
completeWorkflowAiTask,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
wakeWorkflowAiTask,
|
|
18
17
|
workflowAiTaskCancellationRequested,
|
|
19
18
|
} from "./store";
|
|
20
|
-
import type {
|
|
19
|
+
import type { WorkflowAiTask } from "./types";
|
|
21
20
|
|
|
22
21
|
const JOB_ID = "cloud.workflow-ai";
|
|
23
22
|
const MAX_ATTEMPTS = 3;
|
|
@@ -72,92 +71,18 @@ export const settleWorkflowAiAttemptFailure = async (
|
|
|
72
71
|
return "failed";
|
|
73
72
|
};
|
|
74
73
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
: field.type === "date_time"
|
|
88
|
-
? z.iso.datetime({ offset: true })
|
|
89
|
-
: choiceEnum(field.choices!);
|
|
90
|
-
if (!field.required) schema = schema.optional();
|
|
91
|
-
shape[field.name] = schema.describe(field.description);
|
|
92
|
-
}
|
|
93
|
-
return z.object(shape).strict();
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const executeWorkflowAiRequest = async (task: WorkflowAiTask, runStructured: StructuredRunner, signal: AbortSignal) => {
|
|
97
|
-
const request = task.request;
|
|
98
|
-
const common = {
|
|
99
|
-
appId: task.appId,
|
|
100
|
-
attribution: { workflowRunId: task.runId, stepKey: task.stepKey, userId: task.usageUserId },
|
|
101
|
-
requestedModelId: task.modelProfileId,
|
|
102
|
-
signal,
|
|
103
|
-
temperature: 0,
|
|
104
|
-
} satisfies Partial<RunAiStructuredInput<z.ZodType>>;
|
|
105
|
-
|
|
106
|
-
if (request.kind === "generate_text") {
|
|
107
|
-
const result = await runStructured({
|
|
108
|
-
...common,
|
|
109
|
-
task: "workflow-generate-text",
|
|
110
|
-
systemPrompt: request.prompt,
|
|
111
|
-
input: request.input === undefined ? "Create the requested text." : JSON.stringify(request.input),
|
|
112
|
-
outputName: "generated_text",
|
|
113
|
-
output: z.object({ text: z.string().max(request.maxOutputChars) }),
|
|
114
|
-
maxOutputTokens: Math.min(8_192, Math.max(64, Math.ceil(request.maxOutputChars / 2))),
|
|
115
|
-
});
|
|
116
|
-
return { output: result.output.text as WorkflowJsonValue, usage: result.usage ? asJson(result.usage) : null };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (request.kind === "classify") {
|
|
120
|
-
const result = await runStructured({
|
|
121
|
-
...common,
|
|
122
|
-
task: "workflow-classify",
|
|
123
|
-
systemPrompt: `${request.prompt}\nReturn exactly one of the declared choices.`,
|
|
124
|
-
input: JSON.stringify(request.input),
|
|
125
|
-
outputName: "classification",
|
|
126
|
-
output: z.object({ choice: choiceEnum(request.choices) }),
|
|
127
|
-
maxOutputTokens: 200,
|
|
128
|
-
});
|
|
129
|
-
return { output: result.output.choice as WorkflowJsonValue, usage: result.usage ? asJson(result.usage) : null };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (request.kind === "extract_data") {
|
|
133
|
-
const result = await runStructured({
|
|
134
|
-
...common,
|
|
135
|
-
task: "workflow-extract-data",
|
|
136
|
-
systemPrompt: `${request.prompt}\nReturn only the declared fields. Do not invent values that are not supported by the input.`,
|
|
137
|
-
input: JSON.stringify(request.input),
|
|
138
|
-
outputName: "structured_data",
|
|
139
|
-
output: structuredOutputSchema(request.fields),
|
|
140
|
-
maxOutputTokens: 4_096,
|
|
141
|
-
});
|
|
142
|
-
return { output: asJson(result.output), usage: result.usage ? asJson(result.usage) : null };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const maximum = request.maxChoices ?? request.choices.length;
|
|
146
|
-
const result = await runStructured({
|
|
147
|
-
...common,
|
|
148
|
-
task: "workflow-classify-many",
|
|
149
|
-
systemPrompt: `${request.prompt}\nReturn only unique values from the declared choices.`,
|
|
150
|
-
input: JSON.stringify(request.input),
|
|
151
|
-
outputName: "classifications",
|
|
152
|
-
output: z.object({ choices: z.array(choiceEnum(request.choices)).min(request.minChoices).max(maximum) }),
|
|
153
|
-
maxOutputTokens: 500,
|
|
154
|
-
});
|
|
155
|
-
const selected = new Set(result.output.choices);
|
|
156
|
-
return {
|
|
157
|
-
output: request.choices.filter((choice) => selected.has(choice)) as WorkflowJsonValue,
|
|
158
|
-
usage: result.usage ? asJson(result.usage) : null,
|
|
159
|
-
};
|
|
160
|
-
};
|
|
74
|
+
export const executeWorkflowAiRequest = async (task: WorkflowAiTask, runStructured: StructuredRunner, signal: AbortSignal) =>
|
|
75
|
+
executeAiTask(
|
|
76
|
+
task.request,
|
|
77
|
+
{
|
|
78
|
+
appId: task.appId,
|
|
79
|
+
attribution: { workflowRunId: task.runId, stepKey: task.stepKey, userId: task.usageUserId },
|
|
80
|
+
requestedModelId: task.modelProfileId,
|
|
81
|
+
signal,
|
|
82
|
+
taskPrefix: "workflow",
|
|
83
|
+
},
|
|
84
|
+
runStructured,
|
|
85
|
+
);
|
|
161
86
|
|
|
162
87
|
const retryableError = (error: unknown): boolean => {
|
|
163
88
|
if (error instanceof AiBackgroundAdmissionError) return error.retryable;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { notifyWorkflowWorker } from "../store/worker-runtime";
|
|
2
1
|
import { type SQL, sql } from "bun";
|
|
3
2
|
import type { WorkflowJsonValue } from "../contracts";
|
|
4
3
|
import { wakeWorkflowRunsWaitingOn } from "../store/runs";
|
|
4
|
+
import { notifyWorkflowWorker } from "../store/worker-runtime";
|
|
5
5
|
import {
|
|
6
6
|
type WorkflowAiRequest,
|
|
7
7
|
type WorkflowAiRequestInput,
|
|
@@ -1,88 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AiTaskRequest as WorkflowAiRequest } from "../../ai/task-contracts";
|
|
2
2
|
import type { WorkflowJsonValue } from "../contracts";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.min(2)
|
|
10
|
-
.max(50)
|
|
11
|
-
.refine((values) => new Set(values).size === values.length, "Choices must be unique.");
|
|
4
|
+
export {
|
|
5
|
+
type AiTaskRequest as WorkflowAiRequest,
|
|
6
|
+
type AiTaskRequestInput as WorkflowAiRequestInput,
|
|
7
|
+
AiTaskRequestSchema as workflowAiRequestSchema,
|
|
8
|
+
} from "../../ai/task-contracts";
|
|
12
9
|
|
|
13
|
-
const structuredField = z
|
|
14
|
-
.object({
|
|
15
|
-
name: z
|
|
16
|
-
.string()
|
|
17
|
-
.trim()
|
|
18
|
-
.regex(/^[A-Za-z][A-Za-z0-9_]{0,79}$/),
|
|
19
|
-
type: z.enum(["text", "number", "boolean", "date_time", "enum"]),
|
|
20
|
-
description: z.string().trim().min(1).max(500),
|
|
21
|
-
required: z.boolean().default(true),
|
|
22
|
-
choices: z.array(choice).min(1).max(50).optional(),
|
|
23
|
-
maxLength: z.number().int().min(1).max(20_000).optional(),
|
|
24
|
-
})
|
|
25
|
-
.strict()
|
|
26
|
-
.superRefine((field, ctx) => {
|
|
27
|
-
if (field.type === "enum" && !field.choices)
|
|
28
|
-
ctx.addIssue({ code: "custom", path: ["choices"], message: "Enum fields require choices." });
|
|
29
|
-
if (field.type !== "enum" && field.choices)
|
|
30
|
-
ctx.addIssue({ code: "custom", path: ["choices"], message: "Choices are only valid for enum fields." });
|
|
31
|
-
if (field.type !== "text" && field.maxLength)
|
|
32
|
-
ctx.addIssue({ code: "custom", path: ["maxLength"], message: "maxLength is only valid for text fields." });
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const structuredFields = z
|
|
36
|
-
.array(structuredField)
|
|
37
|
-
.min(1)
|
|
38
|
-
.max(40)
|
|
39
|
-
.refine((fields) => new Set(fields.map((field) => field.name)).size === fields.length, "Structured field names must be unique.");
|
|
40
|
-
|
|
41
|
-
export const workflowAiRequestSchema = z.discriminatedUnion("kind", [
|
|
42
|
-
z.object({
|
|
43
|
-
kind: z.literal("generate_text"),
|
|
44
|
-
prompt,
|
|
45
|
-
input: z.unknown().optional(),
|
|
46
|
-
modelProfileId,
|
|
47
|
-
maxOutputChars: z.number().int().min(1).max(20_000).default(4_000),
|
|
48
|
-
}),
|
|
49
|
-
z.object({
|
|
50
|
-
kind: z.literal("classify"),
|
|
51
|
-
prompt,
|
|
52
|
-
input: z.unknown(),
|
|
53
|
-
choices,
|
|
54
|
-
modelProfileId,
|
|
55
|
-
}),
|
|
56
|
-
z
|
|
57
|
-
.object({
|
|
58
|
-
kind: z.literal("classify_many"),
|
|
59
|
-
prompt,
|
|
60
|
-
input: z.unknown(),
|
|
61
|
-
choices,
|
|
62
|
-
minChoices: z.number().int().min(0).max(50).default(0),
|
|
63
|
-
maxChoices: z.number().int().min(0).max(50).optional(),
|
|
64
|
-
modelProfileId,
|
|
65
|
-
})
|
|
66
|
-
.superRefine((value, ctx) => {
|
|
67
|
-
const maximum = value.maxChoices ?? value.choices.length;
|
|
68
|
-
if (maximum > value.choices.length) {
|
|
69
|
-
ctx.addIssue({ code: "custom", path: ["maxChoices"], message: "maxChoices cannot exceed the number of choices." });
|
|
70
|
-
}
|
|
71
|
-
if (value.minChoices > maximum) {
|
|
72
|
-
ctx.addIssue({ code: "custom", path: ["minChoices"], message: "minChoices cannot exceed maxChoices." });
|
|
73
|
-
}
|
|
74
|
-
}),
|
|
75
|
-
z.object({
|
|
76
|
-
kind: z.literal("extract_data"),
|
|
77
|
-
prompt,
|
|
78
|
-
input: z.unknown(),
|
|
79
|
-
fields: structuredFields,
|
|
80
|
-
modelProfileId,
|
|
81
|
-
}),
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
export type WorkflowAiRequest = z.infer<typeof workflowAiRequestSchema>;
|
|
85
|
-
export type WorkflowAiRequestInput = z.input<typeof workflowAiRequestSchema>;
|
|
86
10
|
export type WorkflowAiTaskStatus = "queued" | "running" | "succeeded" | "failed" | "canceled";
|
|
87
11
|
|
|
88
12
|
export type WorkflowAiTask = {
|
|
@@ -50,11 +50,11 @@ export {
|
|
|
50
50
|
} from "./events";
|
|
51
51
|
export {
|
|
52
52
|
getWorkflowRun,
|
|
53
|
-
listWorkflowFamilies,
|
|
54
|
-
listWorkflowRunTimeline,
|
|
55
53
|
listStrandedWorkflowEffects,
|
|
54
|
+
listWorkflowFamilies,
|
|
56
55
|
listWorkflowRunSteps,
|
|
57
56
|
listWorkflowRuns,
|
|
57
|
+
listWorkflowRunTimeline,
|
|
58
58
|
type StrandedWorkflowEffect,
|
|
59
59
|
type WorkflowAppHealth,
|
|
60
60
|
type WorkflowFamilyFilter,
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export const TEST_CA_CERT = `-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIBljCCATugAwIBAgIUaD/zikxyQaxGreCVzb9YufuusxIwCgYIKoZIzj0EAwIw
|
|
3
|
-
IDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0IENBMB4XDTI2MDcyOTE1NTgx
|
|
4
|
-
MFoXDTM2MDcyNjE1NTgxMFowIDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0
|
|
5
|
-
IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYZ7eU7/C71ilbpKa9k/FXObw
|
|
6
|
-
Vq4u/3rtpW/kSjsJaIVNPFp5oFBdHceL0UPgoxwpaJiJNHiwQHF/BBxaJ7HOAKNT
|
|
7
|
-
MFEwHQYDVR0OBBYEFOflw/p5xNlS0am+HytNLyXVEUndMB8GA1UdIwQYMBaAFOfl
|
|
8
|
-
w/p5xNlS0am+HytNLyXVEUndMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID
|
|
9
|
-
SQAwRgIhAJmRoNV5dxKvNOd2KoytvK/6ckRWN+Uu0ljc5y/g4izqAiEAsLCjxWvz
|
|
10
|
-
mgt1Z3uk+QkT9D1vHCuKSvcqv3aVn0DClxA=
|
|
11
|
-
-----END CERTIFICATE-----`;
|
|
12
|
-
|
|
13
|
-
export const TEST_SERVER_CERT = `-----BEGIN CERTIFICATE-----
|
|
14
|
-
MIIBpDCCAUmgAwIBAgIUNGe5IovnDTTKxjxwHBGVcnOaXaQwCgYIKoZIzj0EAwIw
|
|
15
|
-
IDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0IENBMB4XDTI2MDcyOTE1NTgx
|
|
16
|
-
MFoXDTM2MDcyNjE1NTgxMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZI
|
|
17
|
-
zj0CAQYIKoZIzj0DAQcDQgAEolKc1EyyTH6MKX0GR7FhbXCN0O3G/D2riPJ045K+
|
|
18
|
-
qCL6m0Fso38eNxKbNENSkE1tX7j4uv6tcLmtHU/cKxjUg6NtMGswFAYDVR0RBA0w
|
|
19
|
-
C4IJbG9jYWxob3N0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBT/iu3f
|
|
20
|
-
aYfd6r4xoPTkZujj/0rwWjAfBgNVHSMEGDAWgBTn5cP6ecTZUtGpvh8rTS8l1RFJ
|
|
21
|
-
3TAKBggqhkjOPQQDAgNJADBGAiEAgsXqgbBm2RJaUZIs0IR2rbI+6S+1CtugVMHl
|
|
22
|
-
oxuRagcCIQCtoMZh0rZFlmUkH19BxrDvQe3JqCuQpd2HiZdvZTJhyQ==
|
|
23
|
-
-----END CERTIFICATE-----`;
|
|
24
|
-
|
|
25
|
-
export const TEST_SERVER_KEY = `-----BEGIN EC PARAMETERS-----
|
|
26
|
-
BggqhkjOPQMBBw==
|
|
27
|
-
-----END EC PARAMETERS-----
|
|
28
|
-
-----BEGIN EC PRIVATE KEY-----
|
|
29
|
-
MHcCAQEEIKFSLmqZO5KgG9hGbNhhJa0V2IMl39N2UHUj5VUh6DsmoAoGCCqGSM49
|
|
30
|
-
AwEHoUQDQgAEolKc1EyyTH6MKX0GR7FhbXCN0O3G/D2riPJ045K+qCL6m0Fso38e
|
|
31
|
-
NxKbNENSkE1tX7j4uv6tcLmtHU/cKxjUgw==
|
|
32
|
-
-----END EC PRIVATE KEY-----`;
|
|
33
|
-
|
|
34
|
-
export const TEST_WRONG_CA_CERT = `-----BEGIN CERTIFICATE-----
|
|
35
|
-
MIIBhDCCASugAwIBAgIUWM3XX235lciHJ/UKoajhrSx2dPwwCgYIKoZIzj0EAwIw
|
|
36
|
-
GDEWMBQGA1UEAwwNV3JvbmcgVGVzdCBDQTAeFw0yNjA3MjkxNTU4MTBaFw0zNjA3
|
|
37
|
-
MjYxNTU4MTBaMBgxFjAUBgNVBAMMDVdyb25nIFRlc3QgQ0EwWTATBgcqhkjOPQIB
|
|
38
|
-
BggqhkjOPQMBBwNCAAREOwLQCQYQI7zEa7GaSZag98eOF5KMckBPrDsDxS0Bb5lx
|
|
39
|
-
uIa3iWu9CI6Xkw+v+avpPF+Oz3QB7GXgCboKHFico1MwUTAdBgNVHQ4EFgQU1PRs
|
|
40
|
-
qLXtaHVxaKu0e0le1KpD6GYwHwYDVR0jBBgwFoAU1PRsqLXtaHVxaKu0e0le1KpD
|
|
41
|
-
6GYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiA9vA9jI66Un7zQ
|
|
42
|
-
ycf0+6Ze0y5aSM9FLojGcVuzZb0iyAIgIC6ooFag9BuAZqcj/k07hjARi6UVOpEy
|
|
43
|
-
sIJIkokji38=
|
|
44
|
-
-----END CERTIFICATE-----`;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { sql } from "bun";
|
|
3
|
-
import { session } from "./index";
|
|
4
|
-
|
|
5
|
-
/** Integration fixture: run with an isolated Core authority and its public JWKS endpoint. */
|
|
6
|
-
export const createTestSession = async (userId: string): Promise<string> => {
|
|
7
|
-
// Most session fixtures represent established users, not first-use onboarding.
|
|
8
|
-
await sql`INSERT INTO auth.legal_acceptances (user_id, session_id, document_version, documents)
|
|
9
|
-
VALUES (${userId}::uuid, ${crypto.randomUUID()}::uuid, 'test-fixture', '[]'::jsonb) ON CONFLICT DO NOTHING`;
|
|
10
|
-
const app = new Hono().post("/login", async (c) => c.json({ token: await session.create(c, userId) }));
|
|
11
|
-
const response = await app.request("/login", { method: "POST" });
|
|
12
|
-
if (response.status !== 200) throw new Error(`Session fixture login failed: ${response.status}`);
|
|
13
|
-
const body: unknown = await response.json();
|
|
14
|
-
if (!body || typeof body !== "object" || !("token" in body) || typeof body.token !== "string") {
|
|
15
|
-
throw new Error("Session fixture did not return a token");
|
|
16
|
-
}
|
|
17
|
-
return body.token;
|
|
18
|
-
};
|