@k2b/cloud 0.6.0-rc.0 → 0.7.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 +30 -17
- package/scripts/browser-performance.ts +14 -0
- package/scripts/build-pdf-renderer.ts +39 -0
- package/scripts/build.ts +15 -35
- package/scripts/preload.ts +9 -12
- package/scripts/sync-recovery-smoke.ts +2 -1
- package/src/_internal/app-presentation.ts +14 -2
- package/src/_internal/capabilities.ts +108 -7
- package/src/_internal/capability-streams.ts +81 -0
- package/src/_internal/define-app.ts +62 -36
- 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/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 +14 -153
- package/src/access/PrincipalPicker.tsx +104 -0
- package/src/access/ui.ts +2 -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 +79 -0
- package/src/ai/browser.ts +2 -0
- package/src/ai/capabilities.ts +55 -36
- package/src/ai/capability-execution.ts +47 -12
- package/src/ai/chat/blocks.tsx +157 -95
- 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 +48 -3
- package/src/ai/chat/message-actions.tsx +8 -7
- package/src/ai/chat/message-utils.ts +12 -1
- package/src/ai/chat/messages.ts +2 -0
- package/src/ai/chat/presentation.tsx +19 -48
- package/src/ai/chat/primitives.tsx +43 -1
- package/src/ai/chat/tool-disclosure.tsx +17 -2
- package/src/ai/chat/tool-groups.ts +52 -0
- package/src/ai/chat-quotas.ts +25 -0
- package/src/ai/chat-task-contracts.ts +9 -1
- package/src/ai/chat-tasks.ts +276 -43
- package/src/ai/client/controller.ts +110 -33
- package/src/ai/client/file-source.ts +12 -6
- package/src/ai/client/live-connection.ts +1 -0
- package/src/ai/client/projection.ts +22 -11
- package/src/ai/client/transport.ts +4 -0
- package/src/ai/code-capability-routes.ts +110 -0
- package/src/ai/code-capability-transport.ts +38 -0
- package/src/ai/code-mode-skill.ts +114 -0
- package/src/ai/code-runtime-tools.ts +166 -0
- package/src/ai/code-source-contracts.ts +202 -0
- package/src/ai/code-source-tools.ts +145 -0
- package/src/ai/compaction.ts +27 -6
- package/src/ai/data-analysis-skill.ts +10 -0
- package/src/ai/default-tools.ts +25 -2
- package/src/ai/dictation-runtime.ts +171 -0
- package/src/ai/dictations.ts +188 -0
- package/src/ai/draft-content.ts +34 -0
- package/src/ai/enrich.ts +6 -0
- package/src/ai/executor.ts +191 -31
- package/src/ai/file-content-version.ts +22 -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 +2 -1
- package/src/ai/files-store.ts +174 -71
- package/src/ai/fixtures/vision-encrypted.pdf +0 -0
- package/src/ai/grids-skill.ts +40 -10
- package/src/ai/http.ts +15 -8
- package/src/ai/index.ts +26 -2
- package/src/ai/inference-calls.ts +198 -0
- package/src/ai/live-events.ts +5 -1
- package/src/ai/memory-learning.ts +60 -28
- package/src/ai/message-queue.ts +167 -0
- package/src/ai/migrate.ts +187 -11
- package/src/ai/model-pricing.ts +43 -0
- package/src/ai/pdf-render-worker.ts +74 -0
- package/src/ai/pdf-render.fixture.ts +28 -0
- package/src/ai/pdf-render.ts +77 -0
- package/src/ai/projects-routes.ts +3 -3
- package/src/ai/projects.ts +20 -6
- package/src/ai/protocol.ts +3 -0
- package/src/ai/provider.ts +1 -8
- package/src/ai/quota-provider.ts +191 -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 +215 -11
- package/src/ai/run-timeout.ts +10 -0
- package/src/ai/runtime-tools.ts +3 -0
- package/src/ai/runtime.ts +55 -16
- package/src/ai/settings.ts +36 -8
- package/src/ai/short-id.ts +2 -2
- package/src/ai/skill-catalog.ts +0 -10
- package/src/ai/skill-search.ts +47 -0
- package/src/ai/skill-seeds.ts +105 -20
- package/src/ai/skill-tool.ts +16 -5
- package/src/ai/skills-routes.ts +32 -4
- package/src/ai/skills.ts +324 -155
- package/src/ai/store.ts +373 -191
- package/src/ai/stream.ts +5 -0
- package/src/ai/structured-runs.ts +4 -3
- package/src/ai/structured.ts +8 -1
- package/src/ai/system-prompt.ts +12 -2
- package/src/ai/timeline.ts +2 -5
- package/src/ai/todo-contracts.ts +20 -0
- package/src/ai/todo-tool.ts +16 -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 +2 -0
- package/src/ai/usage.ts +118 -118
- package/src/ai/vision-tool.ts +39 -10
- package/src/api/admin-ai-projects.ts +2 -2
- package/src/api/admin-ai-quotas.ts +74 -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-rail.ts +58 -0
- package/src/api/announcements.ts +14 -0
- package/src/api/capabilities.ts +292 -43
- package/src/api/capability-streams.ts +262 -0
- package/src/api/help.ts +8 -44
- package/src/api/index.ts +6 -0
- package/src/api/mcp.ts +44 -26
- 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 +66 -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 +5 -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 +114 -34
- 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 +79 -0
- package/src/cli/admin/data.ts +17 -0
- package/src/cli/admin/index.ts +9 -0
- package/src/cli/capabilities.ts +29 -0
- package/src/cli/capability-streams.ts +25 -0
- package/src/cli/index.ts +3 -2
- package/src/config/env.ts +11 -8
- package/src/contracts/app.ts +23 -3
- package/src/contracts/capabilities.ts +68 -5
- package/src/contracts/capability-streams.ts +46 -0
- package/src/contracts/commands.ts +49 -0
- package/src/contracts/index.ts +6 -1
- package/src/contracts/rail-admin.ts +38 -0
- package/src/contracts/rail-preferences.ts +16 -0
- package/src/contracts/registry.ts +3 -27
- package/src/contracts/settings-types.ts +1 -1
- package/src/contracts/shared.ts +9 -5
- package/src/contracts/web-vitals.ts +27 -0
- package/src/desktop/solid.tsx +3 -3
- package/src/index.ts +0 -4
- 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/services/access-revision.ts +10 -0
- package/src/server/services/access.ts +1 -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/posix.ts +45 -29
- package/src/services/accounts/users.ts +2 -2
- package/src/services/announcements/index.ts +69 -8
- 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 +2 -1
- package/src/services/identity/key-ring.ts +1 -1
- package/src/services/index.ts +15 -0
- 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 +18 -4
- package/src/services/mandates/policy.ts +65 -2
- package/src/services/notifications/batches.ts +124 -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 +107 -84
- package/src/services/pdf/index.ts +3 -0
- 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 +28 -0
- package/src/services/session/index.ts +15 -2
- package/src/services/session/user.ts +62 -37
- package/src/services/settings/core-settings.ts +21 -28
- package/src/services/settings/defaults.ts +5 -0
- package/src/services/settings/store.ts +58 -84
- 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 +6 -0
- package/src/ssr/AdminLayout.tsx +7 -5
- package/src/ssr/AdminSidebar.tsx +29 -15
- package/src/ssr/AppLaunchpad.island.tsx +24 -137
- 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 +23 -22
- package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
- package/src/ssr/LayoutRail.tsx +17 -9
- 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 +7 -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/runtime.ts +5 -1
- package/src/workflows/ai/store.ts +2 -0
- 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 +2 -0
- 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/scripts/app-favicon.test.ts +0 -49
- package/src/ai/chat/blocks.render.test.tsx +0 -1108
- package/src/ai/kit-skill.ts +0 -22
- package/src/ai/usage-migrate.ts +0 -81
- package/src/browser/CloudResourceSearch.behavior.test.tsx +0 -74
- package/src/browser/notification-target.ts +0 -27
- package/src/contracts/notification-live.ts +0 -66
- package/src/services/notifications/live.ts +0 -50
- package/src/ssr/BrowserNotifications.island.tsx +0 -135
- package/src/ssr/GlobalSearchDialog.behavior.test.tsx +0 -96
- package/src/ssr/Layout.render.test.tsx +0 -148
- package/src/ssr/islands/SearchBar.island.tsx +0 -80
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Hono, type MiddlewareHandler } from "hono";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getBuiltinAiSkillTemplates } from "../ai/skill-seeds";
|
|
4
|
+
import { AiSkillInputError, AiSkillLastAdminError, AiSkillRevisionConflictError, aiSkills } from "../ai/skills";
|
|
5
|
+
import { AuthenticatedPrincipalSchema } from "../contracts/shared";
|
|
5
6
|
import { type AuthContext, auth, err, fail, ok, respond, v } from "../server";
|
|
6
7
|
|
|
7
8
|
const ListSkillsSchema = z
|
|
@@ -11,12 +12,11 @@ const ListSkillsSchema = z
|
|
|
11
12
|
perPage: z.coerce.number().int().min(1).max(500).default(100),
|
|
12
13
|
})
|
|
13
14
|
.strict();
|
|
14
|
-
const SkillAccessSchema = z.object({ principal:
|
|
15
|
+
const SkillAccessSchema = z.object({ principal: AuthenticatedPrincipalSchema, permission: z.enum(["read", "write", "admin"]) }).strict();
|
|
15
16
|
const SkillAccessUpdateSchema = z.object({ permission: z.enum(["read", "write", "admin"]) }).strict();
|
|
16
17
|
|
|
17
18
|
const notFound = (c: Parameters<typeof respond>[0], noun: string) => respond(c, fail(err.notFound(noun)));
|
|
18
|
-
const conflict = (c: Parameters<typeof respond>[0], error:
|
|
19
|
-
respond(c, { ok: false, error: error.message, status: 409 as const });
|
|
19
|
+
const conflict = (c: Parameters<typeof respond>[0], error: Error) => respond(c, { ok: false, error: error.message, status: 409 as const });
|
|
20
20
|
|
|
21
21
|
export const createAdminAiSkillsRoutes = (authenticate: MiddlewareHandler<AuthContext> = auth.requireRole("admin")) =>
|
|
22
22
|
new Hono<AuthContext>()
|
|
@@ -33,6 +33,49 @@ export const createAdminAiSkillsRoutes = (authenticate: MiddlewareHandler<AuthCo
|
|
|
33
33
|
}),
|
|
34
34
|
);
|
|
35
35
|
})
|
|
36
|
+
.get("/templates", (c) =>
|
|
37
|
+
respond(c, ok({ templates: getBuiltinAiSkillTemplates().map(({ key, version, name }) => ({ templateId: key, version, name })) })),
|
|
38
|
+
)
|
|
39
|
+
.post(
|
|
40
|
+
"/:skillId/template",
|
|
41
|
+
v(
|
|
42
|
+
"json",
|
|
43
|
+
z
|
|
44
|
+
.object({
|
|
45
|
+
templateId: z.string().min(1),
|
|
46
|
+
templateVersion: z.number().int().positive(),
|
|
47
|
+
expectedRevision: z.number().int().positive(),
|
|
48
|
+
mode: z.enum(["associate", "reset"]),
|
|
49
|
+
confirmed: z.literal(true),
|
|
50
|
+
})
|
|
51
|
+
.strict(),
|
|
52
|
+
),
|
|
53
|
+
async (c) => {
|
|
54
|
+
const skill = await aiSkills.admin.getByShortId(c.req.param("skillId")!);
|
|
55
|
+
if (!skill) return notFound(c, "Skill");
|
|
56
|
+
try {
|
|
57
|
+
return (await aiSkills.admin.applyTemplate(skill.id, c.req.valid("json")))
|
|
58
|
+
? respond(c, ok({ updated: true }))
|
|
59
|
+
: notFound(c, "Skill");
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error instanceof AiSkillRevisionConflictError) return conflict(c, error);
|
|
62
|
+
if (error instanceof AiSkillInputError) return respond(c, fail(err.badInput(error.message)));
|
|
63
|
+
if (
|
|
64
|
+
typeof error === "object" &&
|
|
65
|
+
error !== null &&
|
|
66
|
+
(("code" in error && error.code === "23505") || ("errno" in error && error.errno === "23505"))
|
|
67
|
+
)
|
|
68
|
+
return conflict(c, new Error("A Skill with this name already exists."));
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
.get("/:skillId/projects", async c => {
|
|
74
|
+
const skill = await aiSkills.admin.getByShortId(c.req.param("skillId")!);
|
|
75
|
+
if (!skill) return notFound(c, "Skill");
|
|
76
|
+
const projects = await aiSkills.admin.linkedProjects(skill.id,c.get("accessSubject") ?? null);
|
|
77
|
+
return respond(c,ok({ projects:projects.map(project=>({id:project.shortId,name:project.name})) }));
|
|
78
|
+
})
|
|
36
79
|
.get("/:skillId/access", async (c) => {
|
|
37
80
|
const skill = await aiSkills.admin.getByShortId(c.req.param("skillId")!);
|
|
38
81
|
return skill ? respond(c, ok({ access: await aiSkills.admin.listAccess(skill.id) })) : notFound(c, "Skill");
|
|
@@ -2,8 +2,8 @@ import { Hono, type MiddlewareHandler } from "hono";
|
|
|
2
2
|
import { describeRoute } from "hono-openapi";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { aiUsage } from "../ai/usage";
|
|
5
|
+
import { type AuthContext, auth, err, fail, ok, respond, v } from "../server";
|
|
5
6
|
import { AiUsageQuerySchema } from "../shared/ai-usage";
|
|
6
|
-
import { auth, type AuthContext, v, respond, ok, fail, err } from "../server";
|
|
7
7
|
|
|
8
8
|
export const createAdminAiUsageRoutes = (
|
|
9
9
|
authenticate: MiddlewareHandler<AuthContext> = auth.requireRole("admin"),
|
|
@@ -32,7 +32,7 @@ export const createAdminAiUsageRoutes = (
|
|
|
32
32
|
.get(
|
|
33
33
|
"/runs/:kind/:id",
|
|
34
34
|
describeRoute({ summary: "Read an AI run and its stored error", tags: ["Admin AI usage"] }),
|
|
35
|
-
v("param", z.object({ kind: z.enum(["chat", "background"
|
|
35
|
+
v("param", z.object({ kind: z.enum(["chat", "background"]), id: z.uuid() })),
|
|
36
36
|
async (c) => {
|
|
37
37
|
const { kind, id } = c.req.valid("param");
|
|
38
38
|
const result = await service.detail(kind, id);
|
|
@@ -31,6 +31,8 @@ import { GotenbergRenderError, testGotenberg } from "../services/pdf";
|
|
|
31
31
|
import * as settings from "../services/settings";
|
|
32
32
|
import { SETTINGS_MAP, validateSettingValue } from "../services/settings/defaults";
|
|
33
33
|
|
|
34
|
+
import { invalidateSettingsCacheForAdmin } from "../services/settings/store";
|
|
35
|
+
|
|
34
36
|
const BulkSaveSchema = z.union([
|
|
35
37
|
z
|
|
36
38
|
.object({
|
|
@@ -58,6 +60,7 @@ const AI_PROFILES_KEY = "ai.model_profiles_json";
|
|
|
58
60
|
const AI_ENABLED_KEY = "ai.enabled";
|
|
59
61
|
const AI_DEFAULT_MODEL_KEY = "ai.default_model_id";
|
|
60
62
|
const AI_BACKGROUND_MODEL_KEY = "ai.background_model_id";
|
|
63
|
+
const AI_AUDIO_MODEL_KEY = "ai.audio_model_id";
|
|
61
64
|
const AI_VISION_MODEL_KEY = "ai.vision_model_id";
|
|
62
65
|
const AI_WORKFLOW_MODEL_KEY = "ai.workflow_model_id";
|
|
63
66
|
const AI_CONFIGURATION_KEYS = new Set([
|
|
@@ -65,6 +68,7 @@ const AI_CONFIGURATION_KEYS = new Set([
|
|
|
65
68
|
AI_DEFAULT_MODEL_KEY,
|
|
66
69
|
AI_BACKGROUND_MODEL_KEY,
|
|
67
70
|
AI_VISION_MODEL_KEY,
|
|
71
|
+
AI_AUDIO_MODEL_KEY,
|
|
68
72
|
AI_WORKFLOW_MODEL_KEY,
|
|
69
73
|
AI_PROFILES_KEY,
|
|
70
74
|
]);
|
|
@@ -116,6 +120,7 @@ const prepareAiSettingsMutation = async (
|
|
|
116
120
|
currentDefaultModelId,
|
|
117
121
|
currentBackgroundModelId,
|
|
118
122
|
currentVisionModelId,
|
|
123
|
+
currentAudioModelId,
|
|
119
124
|
currentWorkflowModelId,
|
|
120
125
|
currentProfilesJson,
|
|
121
126
|
] = await Promise.all([
|
|
@@ -123,6 +128,7 @@ const prepareAiSettingsMutation = async (
|
|
|
123
128
|
settings.get<string>(AI_DEFAULT_MODEL_KEY),
|
|
124
129
|
settings.get<string>(AI_BACKGROUND_MODEL_KEY),
|
|
125
130
|
settings.get<string>(AI_VISION_MODEL_KEY),
|
|
131
|
+
settings.get<string>(AI_AUDIO_MODEL_KEY),
|
|
126
132
|
settings.get<string>(AI_WORKFLOW_MODEL_KEY),
|
|
127
133
|
settings.get<string>(AI_PROFILES_KEY),
|
|
128
134
|
]);
|
|
@@ -162,6 +168,7 @@ const prepareAiSettingsMutation = async (
|
|
|
162
168
|
enabled: nextEnabled,
|
|
163
169
|
defaultModelId: String(valueAfterMutation(AI_DEFAULT_MODEL_KEY, currentDefaultModelId ?? "", updates, resets)),
|
|
164
170
|
backgroundModelId: String(valueAfterMutation(AI_BACKGROUND_MODEL_KEY, currentBackgroundModelId ?? "", updates, resets)),
|
|
171
|
+
audioModelId: String(valueAfterMutation(AI_AUDIO_MODEL_KEY, currentAudioModelId ?? "", updates, resets)),
|
|
165
172
|
visionModelId: String(valueAfterMutation(AI_VISION_MODEL_KEY, currentVisionModelId ?? "", updates, resets)),
|
|
166
173
|
workflowModelId: String(valueAfterMutation(AI_WORKFLOW_MODEL_KEY, currentWorkflowModelId ?? "", updates, resets)),
|
|
167
174
|
profiles: nextParsed.profiles,
|
|
@@ -184,6 +191,24 @@ const invalidateCommittedSettings = async (keys: readonly string[]): Promise<voi
|
|
|
184
191
|
const liveSettingKeys = async () => (await listApps()).flatMap((app) => [...(app.settingKeys ?? [])]);
|
|
185
192
|
|
|
186
193
|
const app = new Hono<AuthContext>()
|
|
194
|
+
.get("/web-vitals", auth.requireRole("admin"), async (c) =>
|
|
195
|
+
c.json({ enabled: (await settings.get("observability.web_vitals.enabled")) === true }),
|
|
196
|
+
)
|
|
197
|
+
.delete(
|
|
198
|
+
"/cache",
|
|
199
|
+
auth.requireRole("admin"),
|
|
200
|
+
describeRoute({
|
|
201
|
+
tags: ["Administration"],
|
|
202
|
+
summary: "Invalidate registered settings cache",
|
|
203
|
+
...requiresAdmin,
|
|
204
|
+
responses: { 200: jsonResponse(z.object({ success: z.literal(true) }), "Cache invalidated") },
|
|
205
|
+
}),
|
|
206
|
+
async (c) => {
|
|
207
|
+
await invalidateSettingsCacheForAdmin(c.get("user"), await liveSettingKeys());
|
|
208
|
+
c.header("Cache-Control", "no-store");
|
|
209
|
+
return c.json({ success: true as const });
|
|
210
|
+
},
|
|
211
|
+
)
|
|
187
212
|
.get(
|
|
188
213
|
"/documentation",
|
|
189
214
|
auth.requireRole("admin"),
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { fail, ok } from "@k2b/stdlib";
|
|
2
2
|
import type { MiddlewareHandler } from "hono";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
|
+
import { describeRoute } from "hono-openapi";
|
|
4
5
|
import { z } from "zod";
|
|
6
|
+
import { listApps } from "../_internal/registry";
|
|
5
7
|
import { CapabilityAppIdSchema } from "../contracts/capabilities";
|
|
6
8
|
import { type AuthContext, auth, err, respond, v } from "../server";
|
|
7
9
|
import { getIdentitySigningKeyStatus, identityMetrics, revokeIdentitySigningKey, rewrapIdentitySigningKeys } from "../services/identity";
|
|
@@ -40,6 +42,7 @@ const MandateListQuerySchema = z
|
|
|
40
42
|
.strict();
|
|
41
43
|
|
|
42
44
|
type IdentityAdminDependencies = {
|
|
45
|
+
apps: () => Promise<Array<{ id: string; name: string }>>;
|
|
43
46
|
status: typeof getIdentitySigningKeyStatus;
|
|
44
47
|
rewrap: typeof rewrapIdentitySigningKeys;
|
|
45
48
|
revoke: typeof revokeIdentitySigningKey;
|
|
@@ -49,6 +52,7 @@ type IdentityAdminDependencies = {
|
|
|
49
52
|
};
|
|
50
53
|
|
|
51
54
|
const dependencies: IdentityAdminDependencies = {
|
|
55
|
+
apps: async () => (await listApps()).map(({ id, name }) => ({ id, name })),
|
|
52
56
|
status: getIdentitySigningKeyStatus,
|
|
53
57
|
rewrap: rewrapIdentitySigningKeys,
|
|
54
58
|
revoke: revokeIdentitySigningKey,
|
|
@@ -63,60 +67,96 @@ export const createAdminIdentityRoutes = (
|
|
|
63
67
|
) =>
|
|
64
68
|
new Hono<AuthContext>()
|
|
65
69
|
.use(authenticate)
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
.use("*", async (c, next) => {
|
|
71
|
+
c.header("Cache-Control", "no-store");
|
|
72
|
+
await next();
|
|
73
|
+
})
|
|
74
|
+
.get(
|
|
75
|
+
"/workloads",
|
|
76
|
+
describeRoute({ tags: ["App credentials"], summary: "List registered applications for workload credentials" }),
|
|
77
|
+
async (c) => c.json(await service.apps()),
|
|
78
|
+
)
|
|
79
|
+
.get(
|
|
80
|
+
"/workloads/credentials",
|
|
81
|
+
describeRoute({ tags: ["App credentials"], summary: "List credential metadata across applications without secrets" }),
|
|
82
|
+
v("query", WorkloadCredentialListQuerySchema),
|
|
83
|
+
async (c) =>
|
|
84
|
+
c.json(
|
|
85
|
+
await service.credentials.listOverview({
|
|
86
|
+
pagination: c.req.valid("query"),
|
|
87
|
+
filter: { serviceAccountKind: "resource_bound", resourceType: "cloud.app" },
|
|
88
|
+
}),
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
.post(
|
|
92
|
+
"/workloads/:appId/credentials",
|
|
93
|
+
describeRoute({ tags: ["App credentials"], summary: "Create an app-bound credential; return its token once" }),
|
|
94
|
+
v("param", WorkloadAppParamsSchema),
|
|
95
|
+
v("json", WorkloadCredentialInputSchema),
|
|
96
|
+
async (c) =>
|
|
97
|
+
respond(
|
|
98
|
+
c,
|
|
99
|
+
async () => {
|
|
100
|
+
const { appId } = c.req.valid("param");
|
|
101
|
+
const input = c.req.valid("json");
|
|
102
|
+
const actor = c.get("user");
|
|
103
|
+
const account = await service.serviceAccounts.getOrCreateResourceBound({
|
|
104
|
+
name: `${appId} workload`,
|
|
105
|
+
appId,
|
|
106
|
+
resourceType: "cloud.app",
|
|
107
|
+
resourceId: appId,
|
|
108
|
+
createdBy: actor.id,
|
|
109
|
+
});
|
|
110
|
+
if (!account.ok) return fail(account.error);
|
|
81
111
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
// The raw token intentionally appears only in this one create response.
|
|
113
|
+
return service.credentials.createResourceApiToken({
|
|
114
|
+
serviceAccountId: account.data.id,
|
|
115
|
+
actor,
|
|
116
|
+
name: input.name,
|
|
117
|
+
scopes: input.scopes,
|
|
118
|
+
expiresAt: input.expiresAt,
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
201,
|
|
122
|
+
),
|
|
93
123
|
)
|
|
94
|
-
.get(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
.get(
|
|
125
|
+
"/workloads/:appId/credentials",
|
|
126
|
+
describeRoute({ tags: ["App credentials"], summary: "List app credential metadata without secrets" }),
|
|
127
|
+
v("param", WorkloadAppParamsSchema),
|
|
128
|
+
v("query", WorkloadCredentialListQuerySchema),
|
|
129
|
+
async (c) => {
|
|
130
|
+
const { appId } = c.req.valid("param");
|
|
131
|
+
return c.json(
|
|
132
|
+
await service.credentials.listOverview({
|
|
133
|
+
pagination: c.req.valid("query"),
|
|
134
|
+
filter: { serviceAccountKind: "resource_bound", appId, resourceType: "cloud.app", resourceId: appId },
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
.delete(
|
|
140
|
+
"/workloads/:appId/credentials/:credentialId",
|
|
141
|
+
describeRoute({ tags: ["App credentials"], summary: "Revoke one exact app credential" }),
|
|
142
|
+
v("param", WorkloadCredentialParamsSchema),
|
|
143
|
+
async (c) =>
|
|
144
|
+
respond(c, async () => {
|
|
145
|
+
const { appId, credentialId } = c.req.valid("param");
|
|
146
|
+
const credential = await service.credentials.getOverview({ id: credentialId });
|
|
147
|
+
if (
|
|
148
|
+
!credential ||
|
|
149
|
+
credential.owner.type !== "resource" ||
|
|
150
|
+
credential.owner.appId !== appId ||
|
|
151
|
+
credential.owner.resourceType !== "cloud.app" ||
|
|
152
|
+
credential.owner.resourceId !== appId
|
|
153
|
+
) {
|
|
154
|
+
return fail(err.notFound("Workload credential"));
|
|
155
|
+
}
|
|
116
156
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
157
|
+
const revoked = await service.credentials.revoke({ credentialId, actor: c.get("user") });
|
|
158
|
+
return revoked.ok ? ok({ revoked: true as const }) : revoked;
|
|
159
|
+
}),
|
|
120
160
|
)
|
|
121
161
|
.get("/mandates", v("query", MandateListQuerySchema), async (c) => {
|
|
122
162
|
const query = c.req.valid("query");
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Hono, type MiddlewareHandler } from "hono";
|
|
2
|
+
import { HTTPException } from "hono/http-exception";
|
|
3
|
+
import { bodyLimit } from "hono/body-limit";
|
|
4
|
+
import { describeRoute } from "hono-openapi";
|
|
5
|
+
import { RailAdminSchema, RailAdminInputSchema } from "../contracts/rail-admin";
|
|
6
|
+
import { RAIL_PREFERENCES_MAX_BYTES } from "../contracts/rail-preferences";
|
|
7
|
+
import { type AuthContext, auth, jsonResponse, requiresAdmin, v } from "../server";
|
|
8
|
+
import { RailAdminError, railShortcuts } from "../services/rail-shortcuts";
|
|
9
|
+
|
|
10
|
+
export const createAdminRailRoutes = (service = railShortcuts, authenticate: MiddlewareHandler<AuthContext> = auth.requireRole("admin")) =>
|
|
11
|
+
new Hono<AuthContext>()
|
|
12
|
+
.use("*", authenticate)
|
|
13
|
+
.onError((error, c) => {
|
|
14
|
+
if (error instanceof RailAdminError) return c.json({ message: error.message }, error.status);
|
|
15
|
+
if (error instanceof HTTPException) return error.getResponse();
|
|
16
|
+
throw error;
|
|
17
|
+
})
|
|
18
|
+
.use("*", async (c, next) => {
|
|
19
|
+
c.header("Cache-Control", "no-store");
|
|
20
|
+
await next();
|
|
21
|
+
})
|
|
22
|
+
.delete(
|
|
23
|
+
"/cache",
|
|
24
|
+
describeRoute({
|
|
25
|
+
tags: ["Admin app bar"],
|
|
26
|
+
summary: "Invalidate app bar caches for all users",
|
|
27
|
+
...requiresAdmin,
|
|
28
|
+
responses: { 204: { description: "Caches invalidated; rebuilt on the next read" } },
|
|
29
|
+
}),
|
|
30
|
+
async (c) => {
|
|
31
|
+
await service.invalidateCache(c.get("user"));
|
|
32
|
+
return c.body(null, 204);
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
.get(
|
|
36
|
+
"/",
|
|
37
|
+
describeRoute({
|
|
38
|
+
tags: ["Admin app bar"],
|
|
39
|
+
summary: "Read global app bar shortcuts and audiences",
|
|
40
|
+
...requiresAdmin,
|
|
41
|
+
responses: { 200: jsonResponse(RailAdminSchema, "Global app bar configuration") },
|
|
42
|
+
}),
|
|
43
|
+
async (c) => c.json(await service.list(c.get("user"))),
|
|
44
|
+
)
|
|
45
|
+
.put(
|
|
46
|
+
"/",
|
|
47
|
+
describeRoute({
|
|
48
|
+
tags: ["Admin app bar"],
|
|
49
|
+
summary: "Save global app bar shortcuts and audiences",
|
|
50
|
+
...requiresAdmin,
|
|
51
|
+
responses: { 200: jsonResponse(RailAdminSchema, "Saved configuration"), 409: { description: "Configuration changed" } },
|
|
52
|
+
}),
|
|
53
|
+
bodyLimit({ maxSize: RAIL_PREFERENCES_MAX_BYTES }),
|
|
54
|
+
v("json", RailAdminInputSchema),
|
|
55
|
+
async (c) => c.json(await service.save(c.get("user"), c.req.valid("json"))),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export default createAdminRailRoutes();
|
package/src/api/announcements.ts
CHANGED
|
@@ -44,6 +44,20 @@ export const announcementRoutes = new Hono<AuthContext>().get(
|
|
|
44
44
|
|
|
45
45
|
export const adminAnnouncementRoutes = new Hono<AuthContext>()
|
|
46
46
|
.use(auth.requireRole("admin"))
|
|
47
|
+
.delete(
|
|
48
|
+
"/cache",
|
|
49
|
+
describeRoute({
|
|
50
|
+
tags: ["Admin Announcements"],
|
|
51
|
+
summary: "Invalidate announcement cache",
|
|
52
|
+
...requiresAdmin,
|
|
53
|
+
responses: { 200: jsonResponse(z.object({ success: z.literal(true) }), "Cache invalidated") },
|
|
54
|
+
}),
|
|
55
|
+
async (c) => {
|
|
56
|
+
await announcements.admin.invalidateCache(c.get("user"));
|
|
57
|
+
c.header("Cache-Control", "no-store");
|
|
58
|
+
return c.json({ success: true as const });
|
|
59
|
+
},
|
|
60
|
+
)
|
|
47
61
|
.get(
|
|
48
62
|
"/",
|
|
49
63
|
describeRoute({
|