@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.
Files changed (315) hide show
  1. package/README.md +2 -2
  2. package/package.json +30 -17
  3. package/scripts/browser-performance.ts +14 -0
  4. package/scripts/build-pdf-renderer.ts +39 -0
  5. package/scripts/build.ts +15 -35
  6. package/scripts/preload.ts +9 -12
  7. package/scripts/sync-recovery-smoke.ts +2 -1
  8. package/src/_internal/app-presentation.ts +14 -2
  9. package/src/_internal/capabilities.ts +108 -7
  10. package/src/_internal/capability-streams.ts +81 -0
  11. package/src/_internal/define-app.ts +62 -36
  12. package/src/_internal/heartbeat.ts +4 -0
  13. package/src/_internal/help-catalog.ts +27 -172
  14. package/src/_internal/help.ts +13 -76
  15. package/src/_internal/page-responses.ts +2 -0
  16. package/src/_internal/postgres-application-name.ts +30 -0
  17. package/src/_internal/process-identity.ts +15 -0
  18. package/src/_internal/process-sync.ts +1 -1
  19. package/src/_internal/registry-validation.ts +29 -25
  20. package/src/_internal/registry.ts +2 -53
  21. package/src/_internal/runtime-context.ts +5 -16
  22. package/src/_internal/server-timing.ts +13 -0
  23. package/src/_internal/status-preserving-ssr.ts +18 -6
  24. package/src/_internal/web-vitals-asset.ts +10 -0
  25. package/src/access/PermissionEditor.tsx +14 -153
  26. package/src/access/PrincipalPicker.tsx +104 -0
  27. package/src/access/ui.ts +2 -0
  28. package/src/ai/admin.ts +14 -13
  29. package/src/ai/assistant-models.ts +12 -1
  30. package/src/ai/audio-format.ts +34 -0
  31. package/src/ai/audio-tool.ts +90 -0
  32. package/src/ai/browser-code-contracts.ts +79 -0
  33. package/src/ai/browser.ts +2 -0
  34. package/src/ai/capabilities.ts +55 -36
  35. package/src/ai/capability-execution.ts +47 -12
  36. package/src/ai/chat/blocks.tsx +157 -95
  37. package/src/ai/chat/capability-result.ts +15 -0
  38. package/src/ai/chat/capability-table.tsx +2 -10
  39. package/src/ai/chat/composer-adapter.ts +48 -3
  40. package/src/ai/chat/message-actions.tsx +8 -7
  41. package/src/ai/chat/message-utils.ts +12 -1
  42. package/src/ai/chat/messages.ts +2 -0
  43. package/src/ai/chat/presentation.tsx +19 -48
  44. package/src/ai/chat/primitives.tsx +43 -1
  45. package/src/ai/chat/tool-disclosure.tsx +17 -2
  46. package/src/ai/chat/tool-groups.ts +52 -0
  47. package/src/ai/chat-quotas.ts +25 -0
  48. package/src/ai/chat-task-contracts.ts +9 -1
  49. package/src/ai/chat-tasks.ts +276 -43
  50. package/src/ai/client/controller.ts +110 -33
  51. package/src/ai/client/file-source.ts +12 -6
  52. package/src/ai/client/live-connection.ts +1 -0
  53. package/src/ai/client/projection.ts +22 -11
  54. package/src/ai/client/transport.ts +4 -0
  55. package/src/ai/code-capability-routes.ts +110 -0
  56. package/src/ai/code-capability-transport.ts +38 -0
  57. package/src/ai/code-mode-skill.ts +114 -0
  58. package/src/ai/code-runtime-tools.ts +166 -0
  59. package/src/ai/code-source-contracts.ts +202 -0
  60. package/src/ai/code-source-tools.ts +145 -0
  61. package/src/ai/compaction.ts +27 -6
  62. package/src/ai/data-analysis-skill.ts +10 -0
  63. package/src/ai/default-tools.ts +25 -2
  64. package/src/ai/dictation-runtime.ts +171 -0
  65. package/src/ai/dictations.ts +188 -0
  66. package/src/ai/draft-content.ts +34 -0
  67. package/src/ai/enrich.ts +6 -0
  68. package/src/ai/executor.ts +191 -31
  69. package/src/ai/file-content-version.ts +22 -0
  70. package/src/ai/file-context.ts +2 -1
  71. package/src/ai/file-media-type.ts +12 -0
  72. package/src/ai/file-reference-contracts.ts +15 -0
  73. package/src/ai/file-tools.ts +2 -1
  74. package/src/ai/files-store.ts +174 -71
  75. package/src/ai/fixtures/vision-encrypted.pdf +0 -0
  76. package/src/ai/grids-skill.ts +40 -10
  77. package/src/ai/http.ts +15 -8
  78. package/src/ai/index.ts +26 -2
  79. package/src/ai/inference-calls.ts +198 -0
  80. package/src/ai/live-events.ts +5 -1
  81. package/src/ai/memory-learning.ts +60 -28
  82. package/src/ai/message-queue.ts +167 -0
  83. package/src/ai/migrate.ts +187 -11
  84. package/src/ai/model-pricing.ts +43 -0
  85. package/src/ai/pdf-render-worker.ts +74 -0
  86. package/src/ai/pdf-render.fixture.ts +28 -0
  87. package/src/ai/pdf-render.ts +77 -0
  88. package/src/ai/projects-routes.ts +3 -3
  89. package/src/ai/projects.ts +20 -6
  90. package/src/ai/protocol.ts +3 -0
  91. package/src/ai/provider.ts +1 -8
  92. package/src/ai/quota-provider.ts +191 -0
  93. package/src/ai/quota-report.ts +152 -0
  94. package/src/ai/quotas-migrate.ts +45 -0
  95. package/src/ai/quotas.ts +168 -0
  96. package/src/ai/routes.ts +215 -11
  97. package/src/ai/run-timeout.ts +10 -0
  98. package/src/ai/runtime-tools.ts +3 -0
  99. package/src/ai/runtime.ts +55 -16
  100. package/src/ai/settings.ts +36 -8
  101. package/src/ai/short-id.ts +2 -2
  102. package/src/ai/skill-catalog.ts +0 -10
  103. package/src/ai/skill-search.ts +47 -0
  104. package/src/ai/skill-seeds.ts +105 -20
  105. package/src/ai/skill-tool.ts +16 -5
  106. package/src/ai/skills-routes.ts +32 -4
  107. package/src/ai/skills.ts +324 -155
  108. package/src/ai/store.ts +373 -191
  109. package/src/ai/stream.ts +5 -0
  110. package/src/ai/structured-runs.ts +4 -3
  111. package/src/ai/structured.ts +8 -1
  112. package/src/ai/system-prompt.ts +12 -2
  113. package/src/ai/timeline.ts +2 -5
  114. package/src/ai/todo-contracts.ts +20 -0
  115. package/src/ai/todo-tool.ts +16 -0
  116. package/src/ai/tool-audit.ts +30 -40
  117. package/src/ai/tools.ts +6 -0
  118. package/src/ai/transcription.ts +202 -0
  119. package/src/ai/turn-timing.ts +114 -0
  120. package/src/ai/types.ts +58 -10
  121. package/src/ai/ui.tsx +2 -0
  122. package/src/ai/usage.ts +118 -118
  123. package/src/ai/vision-tool.ts +39 -10
  124. package/src/api/admin-ai-projects.ts +2 -2
  125. package/src/api/admin-ai-quotas.ts +74 -0
  126. package/src/api/admin-ai-skills.ts +48 -5
  127. package/src/api/admin-ai-usage.ts +2 -2
  128. package/src/api/admin-core-settings.ts +25 -0
  129. package/src/api/admin-identity.ts +91 -51
  130. package/src/api/admin-rail.ts +58 -0
  131. package/src/api/announcements.ts +14 -0
  132. package/src/api/capabilities.ts +292 -43
  133. package/src/api/capability-streams.ts +262 -0
  134. package/src/api/help.ts +8 -44
  135. package/src/api/index.ts +6 -0
  136. package/src/api/mcp.ts +44 -26
  137. package/src/api/me-web-vitals.ts +35 -0
  138. package/src/api/me.ts +2 -0
  139. package/src/api/search/schemas.ts +26 -15
  140. package/src/api/search.bench.ts +1 -1
  141. package/src/api/search.ts +54 -17
  142. package/src/browser/CloudResourceSearch.tsx +640 -702
  143. package/src/browser/app-approval-vault.ts +19 -7
  144. package/src/browser/command-bridge.ts +109 -0
  145. package/src/browser/command-shortcuts.ts +76 -0
  146. package/src/browser/commands.ts +66 -0
  147. package/src/browser/navigation-search.ts +48 -0
  148. package/src/browser/notifications.ts +1 -1
  149. package/src/browser/resource-picker.tsx +5 -18
  150. package/src/browser/resource-search-dialog.ts +9 -0
  151. package/src/browser/resource-search-input.ts +46 -0
  152. package/src/browser/resource-search-messages.ts +76 -40
  153. package/src/browser/resource-search.ts +7 -0
  154. package/src/browser/search-bridge.ts +102 -0
  155. package/src/browser/search-commands.ts +59 -0
  156. package/src/browser/search.ts +13 -0
  157. package/src/browser/spotlight-position.ts +208 -0
  158. package/src/browser/testing.ts +5 -0
  159. package/src/browser/web-vitals.ts +25 -0
  160. package/src/capabilities/claims.ts +179 -0
  161. package/src/capabilities/client.ts +34 -0
  162. package/src/capabilities/command-link.ts +16 -0
  163. package/src/capabilities/executions.ts +298 -0
  164. package/src/capabilities/migrate.ts +81 -0
  165. package/src/capabilities/server.ts +114 -34
  166. package/src/capabilities/stream-body.ts +16 -0
  167. package/src/capabilities/streams.ts +28 -0
  168. package/src/cli/admin/ai-quotas.ts +161 -0
  169. package/src/cli/admin/ai-skills.ts +64 -0
  170. package/src/cli/admin/ai-usage.ts +53 -30
  171. package/src/cli/admin/app-credentials.ts +79 -0
  172. package/src/cli/admin/data.ts +17 -0
  173. package/src/cli/admin/index.ts +9 -0
  174. package/src/cli/capabilities.ts +29 -0
  175. package/src/cli/capability-streams.ts +25 -0
  176. package/src/cli/index.ts +3 -2
  177. package/src/config/env.ts +11 -8
  178. package/src/contracts/app.ts +23 -3
  179. package/src/contracts/capabilities.ts +68 -5
  180. package/src/contracts/capability-streams.ts +46 -0
  181. package/src/contracts/commands.ts +49 -0
  182. package/src/contracts/index.ts +6 -1
  183. package/src/contracts/rail-admin.ts +38 -0
  184. package/src/contracts/rail-preferences.ts +16 -0
  185. package/src/contracts/registry.ts +3 -27
  186. package/src/contracts/settings-types.ts +1 -1
  187. package/src/contracts/shared.ts +9 -5
  188. package/src/contracts/web-vitals.ts +27 -0
  189. package/src/desktop/solid.tsx +3 -3
  190. package/src/index.ts +0 -4
  191. package/src/server/index.ts +3 -0
  192. package/src/server/middleware/auth.ts +3 -2
  193. package/src/server/middleware/route-template.ts +9 -3
  194. package/src/server/middleware/runtime.ts +2 -1
  195. package/src/server/middleware/settings.ts +17 -11
  196. package/src/server/services/access-revision.ts +10 -0
  197. package/src/server/services/access.ts +1 -1
  198. package/src/server/services/index.ts +1 -0
  199. package/src/services/account-category-policy.ts +9 -0
  200. package/src/services/account-lifecycle/audit.ts +1 -1
  201. package/src/services/accounts/app.ts +12 -2
  202. package/src/services/accounts/email-write.ts +23 -0
  203. package/src/services/accounts/groups.ts +15 -4
  204. package/src/services/accounts/identities.ts +249 -0
  205. package/src/services/accounts/identity-reconciliation.ts +87 -0
  206. package/src/services/accounts/ipa-data.ts +2 -2
  207. package/src/services/accounts/local-groups.ts +2 -2
  208. package/src/services/accounts/posix.ts +45 -29
  209. package/src/services/accounts/users.ts +2 -2
  210. package/src/services/announcements/index.ts +69 -8
  211. package/src/services/audit/index.ts +1 -1
  212. package/src/services/cache-fill.ts +35 -0
  213. package/src/services/help/index.ts +109 -0
  214. package/src/services/help/maintenance.ts +25 -0
  215. package/src/services/help/store.ts +180 -0
  216. package/src/services/help/types.ts +46 -0
  217. package/src/services/identity/invocation-actor.ts +2 -2
  218. package/src/services/identity/key-config.ts +2 -1
  219. package/src/services/identity/key-ring.ts +1 -1
  220. package/src/services/index.ts +15 -0
  221. package/src/services/ipa/users.ts +268 -221
  222. package/src/services/legal-consent.ts +1 -1
  223. package/src/services/logging/index.ts +15 -13
  224. package/src/services/logging/trace.ts +2 -1
  225. package/src/services/logging/web-vitals.ts +81 -0
  226. package/src/services/mandates/index.ts +18 -4
  227. package/src/services/mandates/policy.ts +65 -2
  228. package/src/services/notifications/batches.ts +124 -57
  229. package/src/services/notifications/browser.ts +12 -0
  230. package/src/services/notifications/index.ts +0 -2
  231. package/src/services/notifications/platform.ts +0 -4
  232. package/src/services/oauth-tokens.ts +3 -3
  233. package/src/services/pdf/gotenberg.ts +107 -84
  234. package/src/services/pdf/index.ts +3 -0
  235. package/src/services/providers/local/users.ts +25 -16
  236. package/src/services/public-http.ts +101 -0
  237. package/src/services/rail-shortcuts.ts +95 -0
  238. package/src/services/rail-snapshot.ts +53 -0
  239. package/src/services/request-cache-redis.ts +28 -0
  240. package/src/services/session/index.ts +15 -2
  241. package/src/services/session/user.ts +62 -37
  242. package/src/services/settings/core-settings.ts +21 -28
  243. package/src/services/settings/defaults.ts +5 -0
  244. package/src/services/settings/store.ts +58 -84
  245. package/src/shared/ai-costs.ts +42 -0
  246. package/src/shared/ai-platform-prompt.ts +1 -1
  247. package/src/shared/ai-quotas.ts +136 -0
  248. package/src/shared/ai-usage.ts +6 -16
  249. package/src/shared/app-presentation.ts +21 -15
  250. package/src/shared/capability-messages.ts +14 -0
  251. package/src/shared/help.ts +6 -42
  252. package/src/shared/index.ts +6 -0
  253. package/src/ssr/AdminLayout.tsx +7 -5
  254. package/src/ssr/AdminSidebar.tsx +29 -15
  255. package/src/ssr/AppLaunchpad.island.tsx +24 -137
  256. package/src/ssr/AppLaunchpadPanel.tsx +181 -0
  257. package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
  258. package/src/ssr/GlobalSearchDialog.tsx +167 -20
  259. package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
  260. package/src/ssr/Layout.tsx +17 -6
  261. package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
  262. package/src/ssr/LayoutFooter.tsx +1 -1
  263. package/src/ssr/LayoutHeader.tsx +46 -14
  264. package/src/ssr/LayoutHelp.tsx +23 -22
  265. package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
  266. package/src/ssr/LayoutRail.tsx +17 -9
  267. package/src/ssr/MobileNavigation.tsx +71 -0
  268. package/src/ssr/MobileProfileActions.tsx +49 -0
  269. package/src/ssr/ProfilePreferences.island.tsx +3 -36
  270. package/src/ssr/RailApps.island.tsx +2 -2
  271. package/src/ssr/RailEditor.tsx +17 -2
  272. package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
  273. package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
  274. package/src/ssr/admin-navigation.ts +7 -1
  275. package/src/ssr/help.ts +29 -0
  276. package/src/ssr/islands/SearchBar.tsx +67 -0
  277. package/src/ssr/islands/index.ts +3 -1
  278. package/src/ssr/layout-context.ts +2 -2
  279. package/src/ssr/layout-help-search.ts +15 -0
  280. package/src/ssr/mobile-menu-history.ts +70 -0
  281. package/src/ssr/platform-messages.ts +16 -8
  282. package/src/ssr/profile-actions.ts +42 -0
  283. package/src/ssr/rail-context.ts +8 -4
  284. package/src/ssr/rail-messages.ts +2 -0
  285. package/src/ssr/rail-navigation.ts +3 -3
  286. package/src/ssr/workspace-navigation.ts +75 -0
  287. package/src/styles/effects.css +6 -6
  288. package/src/styles/global.css +54 -0
  289. package/src/styles/input.css +43 -41
  290. package/src/styles/resource-search.css +505 -0
  291. package/src/styles/utilities-feedback.css +13 -0
  292. package/src/styles/utilities-layout.css +1 -5
  293. package/src/styles/utilities-navigation.css +3 -39
  294. package/src/types/ambient.d.ts +5 -0
  295. package/src/workflows/ai/runtime.ts +5 -1
  296. package/src/workflows/ai/store.ts +2 -0
  297. package/src/workflows/ai-actions.ts +16 -13
  298. package/src/workflows/definition.ts +10 -5
  299. package/src/workflows/store/actions.ts +44 -20
  300. package/src/workflows/store/index.ts +2 -0
  301. package/src/workflows/store/runs.ts +36 -0
  302. package/src/workflows/store/worker-pool.ts +55 -0
  303. package/src/workflows/store/worker-runtime.ts +90 -0
  304. package/scripts/app-favicon.test.ts +0 -49
  305. package/src/ai/chat/blocks.render.test.tsx +0 -1108
  306. package/src/ai/kit-skill.ts +0 -22
  307. package/src/ai/usage-migrate.ts +0 -81
  308. package/src/browser/CloudResourceSearch.behavior.test.tsx +0 -74
  309. package/src/browser/notification-target.ts +0 -27
  310. package/src/contracts/notification-live.ts +0 -66
  311. package/src/services/notifications/live.ts +0 -50
  312. package/src/ssr/BrowserNotifications.island.tsx +0 -135
  313. package/src/ssr/GlobalSearchDialog.behavior.test.tsx +0 -96
  314. package/src/ssr/Layout.render.test.tsx +0 -148
  315. package/src/ssr/islands/SearchBar.island.tsx +0 -80
package/src/config/env.ts CHANGED
@@ -7,18 +7,20 @@ const str = (key: string, fallback: string = ""): string => process.env[key] ??
7
7
 
8
8
  const optional = (key: string): string | undefined => process.env[key]?.trim() || undefined;
9
9
 
10
- const int = (key: string, fallback: number): number => {
11
- const value = process.env[key];
12
- const parsed = parseInt(value ?? "", 10);
13
- return isNaN(parsed) ? fallback : parsed;
14
- };
15
-
16
10
  const bool = (key: string, fallback: boolean): boolean => {
17
11
  const value = process.env[key]?.trim().toLowerCase();
18
12
  if (!value) return fallback;
19
13
  return value === "true" || value === "1";
20
14
  };
21
15
 
16
+ const syncReplicas = (): 1 | 3 | 5 => {
17
+ const value = str("SYNC_REPLICAS", "3").trim();
18
+ if (value === "1") return 1;
19
+ if (value === "3") return 3;
20
+ if (value === "5") return 5;
21
+ throw new Error("SYNC_REPLICAS must be 1, 3, or 5");
22
+ };
23
+
22
24
  const list = (key: string): string[] =>
23
25
  (process.env[key] ?? "")
24
26
  .split(",")
@@ -28,10 +30,9 @@ const list = (key: string): string[] =>
28
30
  export const env = {
29
31
  // Application (infrastructure — not changeable at runtime)
30
32
  APP_SECRET: str("APP_SECRET"),
31
- PORT: int("PORT", 3000),
32
33
  IS_DEVELOPMENT: process.env.NODE_ENV === "development",
33
34
 
34
- // Admin login (local emergency access — token-based, no IPA required)
35
+ // Admin login (temporary first access or recovery — Core only, no IPA required)
35
36
  ADMIN_LOGIN_TOKEN: str("ADMIN_LOGIN_TOKEN"),
36
37
 
37
38
  // NATS / @k2b/sync (Postgres and Redis are read by Bun from DATABASE_URL / REDIS_URL)
@@ -39,6 +40,8 @@ export const env = {
39
40
  NATS_SERVERS: list("NATS_SERVERS"),
40
41
  /** Sync namespace shared by every app of one Cloud installation (e.g. `dev`, `prod`). Required. */
41
42
  SYNC_NAMESPACE: str("SYNC_NAMESPACE"),
43
+ /** Persistent stream replica count; consistent across the installation. */
44
+ SYNC_REPLICAS: syncReplicas(),
42
45
  /** Path to a mounted NATS `.creds` file (JWT + NKey). Unset = server-side no-auth. */
43
46
  NATS_CREDS_FILE: optional("NATS_CREDS_FILE"),
44
47
  /** Path to a mounted CA certificate; enables TLS with that CA. Unset = plain TCP. */
@@ -1,5 +1,5 @@
1
1
  import type { Sync } from "@k2b/sync";
2
- import type { HelpManifest } from "../shared/help";
2
+ import type { AppRegistryHelpSummary } from "./registry";
3
3
  import type { Role } from "./shared";
4
4
  import type { DashboardWidgetPresentation } from "./widgets";
5
5
 
@@ -14,6 +14,18 @@ export type LegalLink = {
14
14
  icon?: string;
15
15
  };
16
16
 
17
+ /** Static page links for the global search UI, ranked after resource results.
18
+ * These declare navigation only; they do not create capabilities or readers.
19
+ */
20
+ export type AppSearchLink = {
21
+ label: string;
22
+ /** Optional plain-text context shown with the result and its preview. */
23
+ description?: string;
24
+ href: string;
25
+ icon?: string;
26
+ keywords?: readonly string[];
27
+ };
28
+
17
29
  export type AppAppearanceColor = `#${string}`;
18
30
 
19
31
  export type AppAppearance = {
@@ -35,6 +47,8 @@ export type AppAdminNavigationLink = {
35
47
  };
36
48
 
37
49
  export type AppAdminNavigationGroup = {
50
+ /** Contribute links to the platform AI section instead of a separate group. */
51
+ section?: "ai";
38
52
  /** Stable key used only to localize this presentation group. */
39
53
  id?: string;
40
54
  label: string;
@@ -50,10 +64,14 @@ export type AppPresentationTranslation = {
50
64
  adminLinks?: Readonly<Record<string, string>>;
51
65
  /** Legal-link labels keyed by their stable same-origin href. */
52
66
  legalLinks?: Readonly<Record<string, string>>;
67
+ /** Search-link labels keyed by their stable same-origin href. */
68
+ searchLinks?: Readonly<Record<string, string>>;
69
+ /** Search-link descriptions keyed by their stable same-origin href. */
70
+ searchLinkDescriptions?: Readonly<Record<string, string>>;
53
71
  };
54
72
 
55
73
  export type AppPresentationCatalog = {
56
- /** Locale of the complete `name`, `description`, `adminNav`, and `legalLinks` declaration. */
74
+ /** Locale of the complete `name`, `description`, `adminNav`, `legalLinks`, and `searchLinks` declaration. */
57
75
  baseLocale: string;
58
76
  /** Partial presentation overlays with exact -> ancestor -> base fallback. */
59
77
  translations: Readonly<Record<string, AppPresentationTranslation>>;
@@ -87,6 +105,8 @@ export type AppMeta = {
87
105
  * contributes its own (e.g. settings → terms/privacy/imprint, faq → FAQ).
88
106
  */
89
107
  legalLinks?: LegalLink[];
108
+ /** Static search destinations, visible when the app is in the user's navigation catalog. */
109
+ searchLinks?: readonly AppSearchLink[];
90
110
  /**
91
111
  * Dashboard widget endpoints this app exposes. Each entry references an
92
112
  * HTTP endpoint that returns a `WidgetResponse` (see `contracts/widgets.ts`).
@@ -111,7 +131,7 @@ export type WidgetEndpoint = {
111
131
  };
112
132
 
113
133
  export type RuntimeAppMeta = AppMeta & {
114
- help?: HelpManifest;
134
+ help?: AppRegistryHelpSummary;
115
135
  searchTags?: string[];
116
136
  searchHelp?: string;
117
137
  searchTagHelp?: AppSearchTagHelpEntry[];
@@ -1,7 +1,10 @@
1
+ import { CapabilityStreamSchema, CapabilityStreamPolicySchema, type CapabilityStream, type CapabilityStreamDefinition } from "./capability-streams";
2
+ export * from "./capability-streams";
1
3
  import { z } from "zod";
4
+ import { CommandPathSchema } from "./commands";
2
5
  import type { AccessSubject, RequestActor, User } from "./shared";
3
6
 
4
- export const CAPABILITY_PROTOCOL_VERSION = 1 as const;
7
+ export const CAPABILITY_PROTOCOL_VERSION = 2 as const;
5
8
  export const CAPABILITY_MAX_REQUEST_BYTES = 256 * 1024;
6
9
  export const CAPABILITY_MAX_RESULT_BYTES = 256 * 1024;
7
10
  export const CAPABILITY_MAX_CATALOG_BYTES = 2 * 1024 * 1024;
@@ -14,6 +17,8 @@ export const CAPABILITY_FRAMEWORK_ERROR_CODES = {
14
17
  idempotencyKeyRequired: "IDEMPOTENCY_KEY_REQUIRED",
15
18
  idempotencyKeyNotAllowed: "IDEMPOTENCY_KEY_NOT_ALLOWED",
16
19
  idempotencyConflict: "IDEMPOTENCY_CONFLICT",
20
+ idempotencyInProgress: "IDEMPOTENCY_IN_PROGRESS",
21
+ idempotencyUncertain: "IDEMPOTENCY_UNCERTAIN",
17
22
  deadlineExceeded: "DEADLINE_EXCEEDED",
18
23
  actionOutcomeUnknown: "ACTION_OUTCOME_UNKNOWN",
19
24
  requestCancelled: "REQUEST_CANCELLED",
@@ -32,6 +37,17 @@ export const capabilityIdempotencyConflict = (
32
37
  ...(details ? { details } : {}),
33
38
  });
34
39
 
40
+ /**
41
+ * Cloud surface a capability invocation came from. The dispatcher resolves it
42
+ * once, records it on the execution row, and forwards it to the owning app.
43
+ */
44
+ export const CAPABILITY_ORIGINS = ["assistant", "mcp", "http", "app"] as const;
45
+ export type CapabilityOrigin = (typeof CAPABILITY_ORIGINS)[number];
46
+ export const CapabilityOriginSchema = z.enum(CAPABILITY_ORIGINS);
47
+
48
+ /** Transports the resolved origin from the Cloud dispatcher to the app endpoint. */
49
+ export const CAPABILITY_ORIGIN_HEADER = "x-cloud-capability-origin";
50
+
35
51
  export const CapabilityIdempotencyKeySchema = z
36
52
  .string()
37
53
  .trim()
@@ -94,10 +110,13 @@ const CapabilityActionReviewDetailSchema = z
94
110
  label: z.string().min(1).max(120),
95
111
  value: z.string().max(10_000),
96
112
  display: z.enum(["inline", "block"]).optional(),
97
- format: z.enum(["date", "date-time"]).optional(),
113
+ format: z.enum(["date", "date-time", "markdown"]).optional(),
98
114
  })
99
115
  .strict()
100
116
  .superRefine((detail, context) => {
117
+ if (detail.format === "markdown" && detail.display !== "block") {
118
+ context.addIssue({ code: "custom", path: ["display"], message: "Markdown review details require block display" });
119
+ }
101
120
  const schema =
102
121
  detail.format === "date" ? CapabilityReviewDateSchema : detail.format === "date-time" ? CapabilityReviewDateTimeSchema : null;
103
122
  if (schema?.safeParse(detail.value).success === false) {
@@ -175,6 +194,7 @@ export const capabilityDataAtPath = (data: unknown, path: readonly string[]): un
175
194
 
176
195
  export type CapabilityResult<T> = {
177
196
  data: T;
197
+ stream?: CapabilityStream;
178
198
  /** Provider-authored, user-facing summary of the successful result. Render as escaped plain text. */
179
199
  summary?: string;
180
200
  refs?: CloudResourceReference[];
@@ -190,6 +210,7 @@ export const capabilityResultSchema = <T extends z.ZodType>(
190
210
  z
191
211
  .object({
192
212
  data,
213
+ stream: CapabilityStreamSchema.optional(),
193
214
  summary: z.string().trim().min(1).max(500).optional(),
194
215
  refs: z.array(CloudResourceReferenceSchema).max(100).optional(),
195
216
  page: CapabilityPageSchema.optional(),
@@ -264,6 +285,9 @@ export const UniversalSearchInputSchema = z
264
285
  .object({
265
286
  query: z.string().max(500).describe("User-entered search text. Empty text is allowed when a facet narrows the query."),
266
287
  tags: z.array(z.string().min(1).max(64)).max(20).describe("Canonical search facets supported by this query."),
288
+ scope: CloudResourceRefSchema.optional().describe(
289
+ "Optional resource containing the search results; must be an explicitly supported scope type.",
290
+ ),
267
291
  limit: z.number().int().min(1).max(100).describe("Maximum number of results to return."),
268
292
  })
269
293
  .strict();
@@ -285,6 +309,14 @@ export type CapabilityExecutionContext = {
285
309
  * error codes and data must not depend on it.
286
310
  */
287
311
  locale: string;
312
+ /**
313
+ * Correlation id of the originating Cloud request. Write it into the app's
314
+ * own audit rows so a capability execution record and the app's domain trail
315
+ * can be joined without sharing payloads.
316
+ */
317
+ requestId: string;
318
+ /** Cloud surface that invoked this capability. */
319
+ origin: CapabilityOrigin;
288
320
  signal: AbortSignal;
289
321
  };
290
322
 
@@ -304,6 +336,8 @@ export type CapabilitySearchTagDefinition = {
304
336
 
305
337
  export type CapabilityUniversalSearchDefinition = {
306
338
  tags: readonly CapabilitySearchTagDefinition[];
339
+ /** Local resource types whose contents this Query can search. */
340
+ scopeTypes?: readonly string[];
307
341
  };
308
342
 
309
343
  export type CapabilitySchemaPresentation = Readonly<Record<string, string>>;
@@ -323,6 +357,7 @@ export type CapabilityPresentationTranslation = {
323
357
  types?: Readonly<Record<string, { title?: string; description?: string }>>;
324
358
  queries?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
325
359
  actions?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
360
+ commands?: Readonly<Record<string, Pick<CapabilityOperationPresentationTranslation, "title" | "description" | "input">>>;
326
361
  };
327
362
 
328
363
  export type CapabilityPresentationCatalog = {
@@ -338,6 +373,7 @@ export type CapabilityQueryDefinition<Input extends z.ZodType = z.ZodType<any>,
338
373
  input: Input;
339
374
  data: Data;
340
375
  openWorld: boolean;
376
+ stream?: CapabilityStreamDefinition;
341
377
  universalSearch?: CapabilityUniversalSearchDefinition;
342
378
  run: (
343
379
  input: z.output<Input>,
@@ -346,7 +382,7 @@ export type CapabilityQueryDefinition<Input extends z.ZodType = z.ZodType<any>,
346
382
  };
347
383
 
348
384
  export type CapabilityIdempotencyPolicy = "none" | "required";
349
- export type CapabilityActionApprovalPolicy = "rememberable";
385
+ export type CapabilityActionApprovalPolicy = "rememberable" | "none";
350
386
 
351
387
  export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>, Data extends z.ZodType = z.ZodType<any>> = {
352
388
  title: string;
@@ -355,6 +391,7 @@ export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>,
355
391
  data: Data;
356
392
  destructive: boolean;
357
393
  openWorld: boolean;
394
+ stream?: CapabilityStreamDefinition;
358
395
  idempotency: CapabilityIdempotencyPolicy;
359
396
  approval?: CapabilityActionApprovalPolicy;
360
397
  review?: (
@@ -367,6 +404,29 @@ export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>,
367
404
  ) => CapabilityInvocationResult<z.output<Data>> | Promise<CapabilityInvocationResult<z.output<Data>>>;
368
405
  };
369
406
 
407
+ /** A declarative UI entry. Resolution never executes application code or writes domain data. */
408
+ export type CapabilityCommandDefinition = {
409
+ title: string;
410
+ description: string;
411
+ icon?: string;
412
+ keywords?: readonly string[];
413
+ input: z.ZodType;
414
+ path: string;
415
+ };
416
+
417
+ export const CapabilityCommandManifestSchema = z
418
+ .object({
419
+ localId: CapabilityLocalIdSchema,
420
+ title: z.string().min(1).max(120),
421
+ description: z.string().min(1).max(1000),
422
+ icon: z.string().min(1).max(120).optional(),
423
+ keywords: z.array(z.string().min(1).max(120)).max(30),
424
+ inputSchema: z.record(z.string(), z.unknown()),
425
+ path: CommandPathSchema,
426
+ })
427
+ .strict();
428
+ export type CapabilityCommandManifest = z.infer<typeof CapabilityCommandManifestSchema>;
429
+
370
430
  type CapabilityDefinitionCatalog<T> = Readonly<Record<string, T>>;
371
431
 
372
432
  export type CapabilityDefinitions = {
@@ -375,6 +435,7 @@ export type CapabilityDefinitions = {
375
435
  types?: CapabilityDefinitionCatalog<CapabilityResourceTypeDefinition>;
376
436
  queries?: CapabilityDefinitionCatalog<CapabilityQueryDefinition>;
377
437
  actions?: CapabilityDefinitionCatalog<CapabilityActionDefinition>;
438
+ commands?: CapabilityDefinitionCatalog<CapabilityCommandDefinition>;
378
439
  };
379
440
 
380
441
  /**
@@ -409,6 +470,7 @@ const CapabilityOperationManifestBaseSchema = z
409
470
  description: z.string().min(1).max(1000),
410
471
  inputSchema: z.record(z.string(), z.unknown()),
411
472
  dataSchema: z.record(z.string(), z.unknown()),
473
+ stream: CapabilityStreamPolicySchema.optional(),
412
474
  schemaHash: z.string().regex(/^[a-f0-9]{64}$/),
413
475
  })
414
476
  .strict();
@@ -416,7 +478,7 @@ const CapabilityOperationManifestBaseSchema = z
416
478
  export const CapabilityQueryManifestSchema = CapabilityOperationManifestBaseSchema.extend({
417
479
  openWorld: z.boolean(),
418
480
  universalSearch: z
419
- .object({ tags: z.array(CapabilitySearchTagManifestSchema).max(100) })
481
+ .object({ tags: z.array(CapabilitySearchTagManifestSchema).max(100), scopeTypes: z.array(CapabilityLocalIdSchema).max(100).optional() })
420
482
  .strict()
421
483
  .optional(),
422
484
  }).strict();
@@ -425,7 +487,7 @@ export const CapabilityActionManifestSchema = CapabilityOperationManifestBaseSch
425
487
  destructive: z.boolean(),
426
488
  openWorld: z.boolean(),
427
489
  idempotency: z.enum(["none", "required"]),
428
- approval: z.literal("rememberable").optional(),
490
+ approval: z.enum(["rememberable", "none"]).optional(),
429
491
  review: z.literal(true).optional(),
430
492
  }).strict();
431
493
 
@@ -443,6 +505,7 @@ export const CapabilityManifestSchema = z
443
505
  types: z.array(CapabilityResourceTypeManifestSchema).max(200),
444
506
  queries: z.array(CapabilityQueryManifestSchema).max(200),
445
507
  actions: z.array(CapabilityActionManifestSchema).max(200),
508
+ commands: z.array(CapabilityCommandManifestSchema).max(200),
446
509
  })
447
510
  .strict();
448
511
 
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import type { CapabilityExecutionContext, CapabilityResult } from "./capabilities";
3
+
4
+ /** One binary payload. Provider IDs are limited to 2 KiB UTF-8; Core seals them into opaque references, never URLs. */
5
+ export const CapabilityStreamSchema = z
6
+ .object({
7
+ id: z.string().min(1).max(8192),
8
+ direction: z.enum(["read", "write"]),
9
+ name: z.string().min(1).max(255).optional(),
10
+ mediaType: z
11
+ .string()
12
+ .min(1)
13
+ .max(255)
14
+ .regex(/^[\x20-\x7e]+$/),
15
+ size: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
16
+ expiresAt: z.iso.datetime(),
17
+ })
18
+ .strict();
19
+ export type CapabilityStream = z.infer<typeof CapabilityStreamSchema>;
20
+ export const CapabilityStreamPolicySchema = z
21
+ .object({
22
+ direction: z.enum(["read", "write"]),
23
+ maxBytes: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
24
+ })
25
+ .strict();
26
+ export const CapabilityStreamStatusSchema = z.discriminatedUnion("state", [
27
+ z.object({ state: z.literal("open") }).strict(),
28
+ z.object({ state: z.literal("aborted") }).strict(),
29
+ z.object({ state: z.literal("completed"), result: z.unknown() }).strict(),
30
+ ]);
31
+ export type CapabilityStreamStatus = z.infer<typeof CapabilityStreamStatusSchema>;
32
+ export type CapabilityStreamDefinition = z.infer<typeof CapabilityStreamPolicySchema> &
33
+ (
34
+ | { direction: "read"; read: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<Response> }
35
+ | {
36
+ direction: "write";
37
+ /** Consume completely, then publish. Must reconcile retries using stream.id. */
38
+ write: (
39
+ stream: CapabilityStream,
40
+ body: ReadableStream<Uint8Array>,
41
+ context: CapabilityExecutionContext,
42
+ ) => Promise<CapabilityResult<unknown>>;
43
+ status: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<CapabilityStreamStatus>;
44
+ abort: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<void>;
45
+ }
46
+ );
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+
3
+ /** Commands carry small public references/options, never document bodies or secrets. */
4
+ export const COMMAND_MAX_URL_LENGTH = 8192;
5
+ export const CommandPathSchema = z
6
+ .string()
7
+ .max(2000)
8
+ .refine((value) => {
9
+ if (!value.startsWith("/") || /[\\\u0000-\u0020]/u.test(value)) return false;
10
+ try {
11
+ return new URL(value, "https://cloud.invalid").origin === "https://cloud.invalid";
12
+ } catch {
13
+ return false;
14
+ }
15
+ }, "Expected a Cloud path");
16
+
17
+ export const CommandOptionsSchema = z.object({ returnTo: CommandPathSchema.optional() }).strict();
18
+ export type CommandOptions = z.infer<typeof CommandOptionsSchema>;
19
+ export const CommandRequestSchema = CommandOptionsSchema.extend({ input: z.unknown() }).strict();
20
+ export const CommandLinkSchema = z.object({ href: z.url().max(COMMAND_MAX_URL_LENGTH) }).strict();
21
+
22
+ export const commandPath = (path: string, command: string, input: unknown, options: CommandOptions = {}): string => {
23
+ const url = new URL(CommandPathSchema.parse(path), "https://cloud.invalid");
24
+ url.searchParams.set("command", command);
25
+ url.searchParams.set("commandInput", JSON.stringify(input));
26
+ const parsed = CommandOptionsSchema.parse(options);
27
+ if (parsed.returnTo) url.searchParams.set("commandReturn", parsed.returnTo);
28
+ else url.searchParams.delete("commandReturn");
29
+ const result = `${url.pathname}${url.search}${url.hash}`;
30
+ if (result.length > COMMAND_MAX_URL_LENGTH) throw new Error("Command link is too large");
31
+ return result;
32
+ };
33
+
34
+ export const readCommand = (url: URL) => {
35
+ const id = url.searchParams.get("command");
36
+ if (!id) return null;
37
+ const raw = url.searchParams.get("commandInput") ?? "{}";
38
+ if (url.href.length > COMMAND_MAX_URL_LENGTH) throw new Error("Command link is too large");
39
+ return {
40
+ id,
41
+ input: JSON.parse(raw) as unknown,
42
+ options: CommandOptionsSchema.parse({ returnTo: url.searchParams.get("commandReturn") ?? undefined }),
43
+ };
44
+ };
45
+
46
+ export const clearCommand = (url: URL): string => {
47
+ for (const key of ["command", "commandInput", "commandReturn"]) url.searchParams.delete(key);
48
+ return `${url.pathname}${url.search}${url.hash}`;
49
+ };
@@ -2,7 +2,6 @@ export * from "./account-categories";
2
2
  export * from "./announcements";
3
3
  export * from "./app";
4
4
  export * from "./capabilities";
5
- export * from "./notification-live";
6
5
  export * from "./notification-types";
7
6
  export * from "./posix";
8
7
  export * from "./profile";
@@ -12,3 +11,9 @@ export * from "./shared";
12
11
  export * from "./user-notifications";
13
12
  export * from "./widgets";
14
13
  export * from "./app-approval";
14
+
15
+ // Core app bar administration and shared shortcut values.
16
+ export { RailAccessSchema, RailAdminInputSchema, RailAdminSchema, type RailAdminEntry, type RailAdminState } from "./rail-admin";
17
+ export type { RailShortcut } from "./rail-preferences";
18
+
19
+ export * from "./commands";
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { RAIL_PREFERENCES_MAX_BYTES, RailShortcutSchema } from "./rail-preferences";
3
+ import { AccessEntrySchema } from "./shared";
4
+
5
+ export const RailAccessSchema = AccessEntrySchema.extend({
6
+ principal: z.discriminatedUnion("type", [
7
+ z.object({ type: z.literal("authenticated") }).strict(),
8
+ z.object({ type: z.literal("user"), userId: z.uuid() }).strict(),
9
+ z.object({ type: z.literal("group"), groupId: z.uuid() }).strict(),
10
+ ]),
11
+ permission: z.literal("read"),
12
+ });
13
+ export const RailAdminEntrySchema = z.object({ shortcut: RailShortcutSchema, access: z.array(RailAccessSchema) }).strict();
14
+ const revision = z.number().int().nonnegative().max(2_147_483_647);
15
+ export const RailAdminSchema = z.object({ revision, entries: z.array(RailAdminEntrySchema) }).strict();
16
+ /** Strip presentation metadata from editor drafts before sending or persisting grants. */
17
+ export const RailAdminInputSchema = z
18
+ .object({
19
+ revision,
20
+ entries: z.array(
21
+ z
22
+ .object({
23
+ shortcut: RailShortcutSchema,
24
+ access: z.array(RailAccessSchema.pick({ principal: true, permission: true })),
25
+ })
26
+ .strict(),
27
+ ),
28
+ })
29
+ .strict()
30
+ .superRefine((value, ctx) => {
31
+ if (new TextEncoder().encode(JSON.stringify(value)).byteLength > RAIL_PREFERENCES_MAX_BYTES)
32
+ ctx.addIssue({ code: "custom", message: "Global app bar configuration exceeds 16 KiB" });
33
+ if (new Set(value.entries.map((entry) => entry.shortcut.id)).size !== value.entries.length)
34
+ ctx.addIssue({ code: "custom", message: "Shortcut IDs must be unique" });
35
+ });
36
+ export type RailAdminInput = z.infer<typeof RailAdminInputSchema>;
37
+ export type RailAdminState = z.infer<typeof RailAdminSchema>;
38
+ export type RailAdminEntry = z.infer<typeof RailAdminEntrySchema>;
@@ -51,3 +51,19 @@ export const RailPreferencesSchema = z
51
51
  });
52
52
  export type RailPreferences = z.infer<typeof RailPreferencesSchema>;
53
53
  export const defaultRailPreferences = (): RailPreferences => ({ revision: 0, visibility: {}, shortcuts: [] });
54
+
55
+ /** Managed entries are separate from the writable personal API contract. */
56
+ export type RailSnapshot = RailPreferences & { managedShortcuts?: RailShortcut[] };
57
+ export const RailSnapshotSchema = z
58
+ .object({
59
+ revision: z.number(),
60
+ visibility: z.record(z.string(), z.boolean()),
61
+ shortcuts: z.array(RailShortcutSchema),
62
+ managedShortcuts: z.array(RailShortcutSchema).optional(),
63
+ })
64
+ .strict()
65
+ .superRefine(({ managedShortcuts, ...personal }, ctx) => {
66
+ if (!RailPreferencesSchema.safeParse(personal).success) ctx.addIssue({ code: "custom", message: "Invalid personal app bar settings" });
67
+ if (new TextEncoder().encode(JSON.stringify(managedShortcuts ?? [])).byteLength > RAIL_PREFERENCES_MAX_BYTES)
68
+ ctx.addIssue({ code: "custom", message: "Managed shortcuts exceed the 16 KiB page budget" });
69
+ });
@@ -1,5 +1,4 @@
1
- import type { HelpManifest } from "../shared/help";
2
- import type { AppAdminNavigationGroup, AppAppearance, AppAppearanceColor, AppPresentationCatalog } from "./app";
1
+ import type { AppAdminNavigationGroup, AppAppearance, AppAppearanceColor, AppPresentationCatalog, AppSearchLink } from "./app";
3
2
  import type { CapabilityManifest, CapabilityPresentationCatalog } from "./capabilities";
4
3
  import type { Role } from "./shared";
5
4
  import type { DashboardWidgetPresentation } from "./widgets";
@@ -36,31 +35,7 @@ export type CapabilityRegistryEntry = {
36
35
  presentation?: CapabilityPresentationCatalog;
37
36
  };
38
37
 
39
- export type AppRegistryHelpSummary = HelpManifest;
40
-
41
- export type HelpRegistryDocument = {
42
- id: string;
43
- title: string;
44
- icon?: string;
45
- description?: string;
46
- order: number;
47
- markdown: string;
48
- /** Precomputed by the app. Older registry entries may omit it during rolling upgrades. */
49
- searchText?: string;
50
- };
51
-
52
- /** Full Markdown lives separately so normal app discovery stays small. */
53
- export type HelpRegistryEntry = {
54
- appId: string;
55
- appName: string;
56
- appIcon: string;
57
- manifestHash: string;
58
- /** Base language that owns the complete logical article set. Absent on legacy registrations. */
59
- baseLocale?: string;
60
- /** Partial localized article variants stored in the same bounded logical registration. */
61
- documentsByLocale?: Readonly<Record<string, readonly HelpRegistryDocument[]>>;
62
- documents: readonly HelpRegistryDocument[];
63
- };
38
+ export type AppRegistryHelpSummary = { manifestHash: string; pageBase: string; baseLocale: string };
64
39
 
65
40
  export type AppRegistryLegalLink = {
66
41
  label: string;
@@ -102,6 +77,7 @@ export type AppRegistryEntry = {
102
77
  capabilities?: AppRegistryCapabilitySummary;
103
78
  help?: AppRegistryHelpSummary;
104
79
  legalLinks?: AppRegistryLegalLink[];
80
+ searchLinks?: readonly AppSearchLink[];
105
81
  widgets?: AppRegistryWidget[];
106
82
  /** Setting keys declared by this app. Used by admin tooling to avoid treating live app-owned settings as legacy. */
107
83
  settingKeys?: readonly string[];
@@ -43,7 +43,7 @@ type StringLikeKind = "string" | "text" | "email" | "url" | "secret" | "image" |
43
43
  export type AppSettingDef =
44
44
  | (CommonDef & { kind: StringLikeKind; default: string; placeholder?: string; templateVars?: readonly string[] })
45
45
  | (CommonDef & { kind: "boolean"; default: boolean })
46
- | (CommonDef & { kind: "number"; default: number; min?: number; max?: number; placeholder?: string })
46
+ | (CommonDef & { kind: "number"; default: number; min?: number; max?: number; integer?: boolean; placeholder?: string })
47
47
  | (CommonDef & { kind: "enum"; default: string; options: ReadonlyArray<SettingOption> })
48
48
  | (CommonDef & { kind: "string_list"; default: readonly string[]; placeholder?: string })
49
49
  | (CommonDef & { kind: "number_list"; default: readonly number[]; placeholder?: string });
@@ -288,12 +288,16 @@ export const AccountActivityListResponseSchema = z.object({
288
288
  });
289
289
  export type AccountActivityListResponse = z.infer<typeof AccountActivityListResponseSchema>;
290
290
 
291
+ export const AuthenticatedPrincipalSchema = z.discriminatedUnion("type", [
292
+ z.object({ type: z.literal("user").describe("One user account."), userId: z.uuid().describe("Exact user ID returned by the Accounts directory.") }),
293
+ z.object({ type: z.literal("group").describe("Members of one group."), groupId: z.uuid().describe("Exact group ID returned by the Accounts directory.") }),
294
+ z.object({ type: z.literal("service_account").describe("One service account."), serviceAccountId: z.uuid().describe("Exact service account ID returned by the Accounts directory.") }),
295
+ z.object({ type: z.literal("authenticated").describe("Every authenticated identity; no directory ID is needed.") }),
296
+ ]);
297
+
291
298
  export const PrincipalSchema = z.discriminatedUnion("type", [
292
- z.object({ type: z.literal("user"), userId: z.uuid() }),
293
- z.object({ type: z.literal("group"), groupId: z.uuid() }),
294
- z.object({ type: z.literal("service_account"), serviceAccountId: z.uuid() }),
295
- z.object({ type: z.literal("authenticated") }),
296
- z.object({ type: z.literal("public") }),
299
+ ...AuthenticatedPrincipalSchema.options,
300
+ z.object({ type: z.literal("public").describe("Public access where supported by the resource; no directory ID is needed.") }),
297
301
  ]);
298
302
  export type Principal = z.infer<typeof PrincipalSchema>;
299
303
 
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+
3
+ /** One metric plus six server phases and bounded routing metadata. */
4
+ export const WEB_VITALS_MAX_BYTES = 4096;
5
+ export const WebVitalsReportSchema = z
6
+ .object({
7
+ appId: z
8
+ .string()
9
+ .min(1)
10
+ .max(64)
11
+ .regex(/^[a-z0-9-]+$/),
12
+ routeTemplate: z
13
+ .string()
14
+ .min(1)
15
+ .max(200)
16
+ .regex(/^\/[a-zA-Z0-9_/:.*-]*$/),
17
+ id: z.string().min(1).max(100),
18
+ name: z.enum(["LCP", "INP", "CLS"]),
19
+ value: z.number().nonnegative(),
20
+ navigationType: z.string().max(32),
21
+ serverTiming: z.partialRecord(
22
+ z.enum(["auth", "settings", "runtime", "ssr_data", "ssr_finalize", "ssr_render"]),
23
+ z.number().nonnegative(),
24
+ ),
25
+ })
26
+ .strict();
27
+ export type WebVitalsReport = z.infer<typeof WebVitalsReportSchema>;
@@ -1,4 +1,4 @@
1
- import { deserialize, serialize } from "seroval";
1
+ import { deserialize as deserializeProps, serialize as serializeProps } from "seroval";
2
2
  import type { Component, JSX, ParentProps } from "solid-js";
3
3
  import { children, createContext, createEffect, createMemo, createSignal, For, onCleanup, onMount, Show, useContext } from "solid-js";
4
4
  import { Dynamic, Portal } from "solid-js/web";
@@ -47,7 +47,7 @@ export const defineDesktopWindows = <Definitions extends Record<string, DesktopW
47
47
  ({
48
48
  kind: desktopWindowDescriptorKind,
49
49
  name,
50
- props: serialize(props ?? {}),
50
+ props: serializeProps(props ?? {}),
51
51
  }) satisfies DesktopWindowDescriptor as unknown as JSX.Element;
52
52
  }
53
53
 
@@ -73,7 +73,7 @@ export function DesktopWindowHost<Definitions extends Record<string, DesktopWind
73
73
  const windowProps = createMemo(() => {
74
74
  const current = descriptor();
75
75
  if (!current) return {};
76
- return deserialize<Record<string, unknown>>(current.props);
76
+ return deserializeProps<Record<string, unknown>>(current.props);
77
77
  });
78
78
 
79
79
  return createMemo(() => {
package/src/index.ts CHANGED
@@ -16,15 +16,11 @@ export {
16
16
  APP_REGISTRY_PREFIX,
17
17
  APP_REGISTRY_TTL_MS,
18
18
  CAPABILITY_REGISTRY_CONFIG,
19
- HELP_REGISTRY_CONFIG,
20
19
  appRegistry,
21
20
  capabilityRegistry,
22
21
  getApp,
23
- getHelp,
24
- helpRegistry,
25
22
  listApps,
26
23
  listAppsDetailed,
27
- listHelp,
28
24
  listLegalLinks,
29
25
  listWidgets,
30
26
  readAppRegistrySnapshot,
@@ -9,6 +9,7 @@ export { DEFAULT_LOCALE, getLocale, LOCALE_COOKIE, LOCALE_HEADER, locale, prefer
9
9
  export type {
10
10
  AuthContext,
11
11
  InvocationProvenance,
12
+ InvocationExpectation,
12
13
  RateLimitConfig,
13
14
  RateLimitRouteOverride,
14
15
  RequestActor,
@@ -25,6 +26,7 @@ export {
25
26
  openApiMeta,
26
27
  rateLimit,
27
28
  rejectReservedWorkloadCredential,
29
+ requireInvocation,
28
30
  requestLogger,
29
31
  requiresAdmin,
30
32
  requiresAuth,
@@ -56,6 +58,7 @@ export type {
56
58
  ServiceErrorCode,
57
59
  } from "./services";
58
60
  export {
61
+ accessRevision,
59
62
  buildAccessPrincipalCondition,
60
63
  buildAccessPrincipalTierConditions,
61
64
  createAccess,