@k2b/cloud 0.43.0 → 0.45.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 (308) hide show
  1. package/package.json +11 -2
  2. package/src/_internal/app-access-request.ts +13 -0
  3. package/src/_internal/app-access-resources.ts +141 -0
  4. package/src/_internal/app-event-catalog.ts +40 -0
  5. package/src/_internal/app-event-schemas.ts +127 -0
  6. package/src/_internal/application-package.ts +40 -0
  7. package/src/_internal/built-in-app-ids.json +27 -0
  8. package/src/_internal/capabilities.ts +158 -12
  9. package/src/_internal/capability-origin.ts +4 -0
  10. package/src/_internal/capability-streams.ts +7 -5
  11. package/src/_internal/define-app.ts +57 -6
  12. package/src/_internal/object-store-area.ts +9 -0
  13. package/src/_internal/object-store-config.ts +101 -0
  14. package/src/_internal/object-store-key.ts +14 -0
  15. package/src/_internal/process-identity.ts +7 -2
  16. package/src/_internal/registry-validation.ts +11 -1
  17. package/src/_internal/registry.ts +8 -1
  18. package/src/_internal/runtime-context.ts +8 -1
  19. package/src/access/AppAccessEditor.tsx +2 -0
  20. package/src/access/GroupCoverage.tsx +20 -5
  21. package/src/access/PermissionEditor.tsx +20 -5
  22. package/src/access/PrincipalAvatar.tsx +30 -21
  23. package/src/access/PrincipalPicker.tsx +14 -4
  24. package/src/access/ResourceApiKeys.tsx +3 -4
  25. package/src/access/app-access-messages.ts +6 -0
  26. package/src/access/messages.ts +4 -4
  27. package/src/account/EntitySearch.tsx +12 -0
  28. package/src/account/ProfilePictureDialog.tsx +699 -0
  29. package/src/account/profile-picture-messages.ts +269 -0
  30. package/src/account/ui.ts +7 -0
  31. package/src/ai/admin.ts +3 -0
  32. package/src/ai/app-frame.ts +12 -0
  33. package/src/ai/application-tasks.ts +101 -0
  34. package/src/ai/assistant-models.ts +126 -64
  35. package/src/ai/capabilities.ts +19 -4
  36. package/src/ai/chart-block.ts +63 -30
  37. package/src/ai/chat/chart-block.tsx +12 -3
  38. package/src/ai/chat/composer-adapter.ts +8 -7
  39. package/src/ai/chat/message-actions.tsx +1 -1
  40. package/src/ai/chat/message-utils.ts +2 -2
  41. package/src/ai/chat/presentation.tsx +22 -1
  42. package/src/ai/chat-quotas.ts +5 -4
  43. package/src/ai/chat-tasks.ts +2 -2
  44. package/src/ai/client/controller.ts +11 -10
  45. package/src/ai/client/projection.ts +3 -3
  46. package/src/ai/compaction.ts +3 -3
  47. package/src/ai/credentials.ts +13 -114
  48. package/src/ai/default-tool-contracts.ts +4 -3
  49. package/src/ai/dictation-runtime.ts +10 -6
  50. package/src/ai/enrich.ts +2 -2
  51. package/src/ai/executor.ts +40 -25
  52. package/src/ai/http.ts +17 -29
  53. package/src/ai/index.ts +12 -5
  54. package/src/ai/inference-calls.ts +5 -4
  55. package/src/ai/maintenance.ts +1 -1
  56. package/src/ai/memory-learning-runs.ts +5 -5
  57. package/src/ai/memory-learning.ts +3 -3
  58. package/src/ai/message-queue.ts +1 -2
  59. package/src/ai/migrate.ts +75 -42
  60. package/src/ai/model-access-migrate.ts +3 -17
  61. package/src/ai/model-access.ts +44 -85
  62. package/src/ai/model-card.tsx +134 -0
  63. package/src/ai/model-catalog.ts +359 -0
  64. package/src/ai/model-chooser-messages.ts +88 -0
  65. package/src/ai/model-chooser.tsx +577 -0
  66. package/src/ai/model-delete.ts +234 -0
  67. package/src/ai/model-fixture.ts +39 -0
  68. package/src/ai/model-icon.tsx +36 -0
  69. package/src/ai/model-overview.ts +53 -0
  70. package/src/ai/model-usage.ts +45 -0
  71. package/src/ai/openai-api-messages.ts +0 -4
  72. package/src/ai/openai-api.ts +26 -9
  73. package/src/ai/personal-agent.ts +1 -1
  74. package/src/ai/prefs.ts +12 -10
  75. package/src/ai/project-tool.ts +4 -4
  76. package/src/ai/projects-authorization.ts +53 -0
  77. package/src/ai/projects-routes.ts +58 -47
  78. package/src/ai/projects.ts +110 -88
  79. package/src/ai/protocol.ts +2 -2
  80. package/src/ai/provider-connections.ts +161 -0
  81. package/src/ai/provider-errors.ts +55 -6
  82. package/src/ai/provider-fetch.ts +4 -0
  83. package/src/ai/provider.ts +1 -1
  84. package/src/ai/quota-limits.ts +36 -0
  85. package/src/ai/quota-provider.ts +4 -2
  86. package/src/ai/quota-report.ts +7 -4
  87. package/src/ai/quotas.ts +19 -8
  88. package/src/ai/recent-resources.ts +9 -3
  89. package/src/ai/request-headers.ts +14 -87
  90. package/src/ai/resource-refs.ts +6 -2
  91. package/src/ai/routes.ts +47 -48
  92. package/src/ai/runtime.ts +50 -22
  93. package/src/ai/settings.ts +93 -580
  94. package/src/ai/skill-tool.ts +4 -4
  95. package/src/ai/skills-routes.ts +27 -26
  96. package/src/ai/skills.ts +120 -81
  97. package/src/ai/store.ts +45 -23
  98. package/src/ai/stream.ts +1 -1
  99. package/src/ai/structured-runs.ts +2 -2
  100. package/src/ai/structured.ts +21 -44
  101. package/src/ai/task-contracts.ts +25 -5
  102. package/src/ai/task-execution.ts +15 -6
  103. package/src/ai/task-model.ts +9 -0
  104. package/src/ai/transcription.ts +27 -22
  105. package/src/ai/types.ts +50 -62
  106. package/src/ai/ui.tsx +13 -0
  107. package/src/ai/usage.ts +8 -8
  108. package/src/ai/validate.ts +8 -7
  109. package/src/ai/view-block.ts +2 -2
  110. package/src/api/accounts-entities.ts +22 -3
  111. package/src/api/admin-ai-quotas.ts +34 -56
  112. package/src/api/admin-ai-skills.ts +4 -1
  113. package/src/api/admin-ai-usage.ts +1 -1
  114. package/src/api/admin-ai.ts +173 -0
  115. package/src/api/admin-core-settings.ts +68 -244
  116. package/src/api/app-approval.ts +3 -1
  117. package/src/api/app-event-delivery.ts +51 -0
  118. package/src/api/app-events.ts +123 -0
  119. package/src/api/app-resource-access.ts +48 -0
  120. package/src/api/auth/account-mismatch.ts +24 -0
  121. package/src/api/auth.ts +35 -5
  122. package/src/api/capabilities.ts +28 -4
  123. package/src/api/index.ts +7 -1
  124. package/src/api/mcp.ts +175 -2
  125. package/src/api/me.ts +6 -4
  126. package/src/api/pwa-phone.ts +75 -26
  127. package/src/api/pwa.ts +34 -8
  128. package/src/api/resource-links.ts +83 -6
  129. package/src/api/resource-resolve.ts +50 -0
  130. package/src/api/search/schemas.ts +3 -1
  131. package/src/api/search.ts +9 -7
  132. package/src/app-pwa/contracts.ts +4 -0
  133. package/src/app-pwa/core-query-error.ts +20 -0
  134. package/src/app-pwa/index.ts +1 -0
  135. package/src/app-pwa/service.ts +91 -0
  136. package/src/app-pwa/transport.ts +22 -0
  137. package/src/approvals/messages.ts +2 -2
  138. package/src/browser/cloud-id.ts +86 -0
  139. package/src/browser/resource-clipboard.ts +4 -0
  140. package/src/browser/resource-links.ts +52 -0
  141. package/src/browser/session.ts +39 -0
  142. package/src/browser/shared-text-history-validation.ts +151 -0
  143. package/src/browser/shared-text-history.ts +464 -0
  144. package/src/browser/shared-text-offline-authorized.ts +29 -0
  145. package/src/browser/shared-text-offline.ts +351 -0
  146. package/src/browser/shared-text-provider.ts +714 -0
  147. package/src/browser/shared-text-table-contract.ts +150 -0
  148. package/src/browser/shared-text.ts +19 -0
  149. package/src/capabilities/server-invoke.ts +2 -11
  150. package/src/capabilities/testing.ts +5 -2
  151. package/src/cli/access.ts +6 -5
  152. package/src/cli/admin/ai-models.ts +199 -0
  153. package/src/cli/admin/ai-quotas.ts +6 -102
  154. package/src/cli/admin/ai-usage.ts +4 -4
  155. package/src/cli/admin/app-credentials.ts +5 -3
  156. package/src/cli/admin/index.ts +5 -2
  157. package/src/cli/apps.ts +89 -26
  158. package/src/cli/capabilities.ts +22 -1
  159. package/src/cli/events.ts +320 -0
  160. package/src/config/env.ts +40 -0
  161. package/src/contracts/app-access.ts +26 -2
  162. package/src/contracts/app-details.ts +89 -0
  163. package/src/contracts/app-events.ts +51 -0
  164. package/src/contracts/app.ts +21 -5
  165. package/src/contracts/capabilities.ts +143 -3
  166. package/src/contracts/index.ts +2 -0
  167. package/src/contracts/notification-types.ts +36 -9
  168. package/src/contracts/pwa.ts +17 -1
  169. package/src/contracts/registry.ts +6 -0
  170. package/src/contracts/resource-clipboard.ts +35 -0
  171. package/src/contracts/resource-pages.ts +140 -0
  172. package/src/contracts/resource-resolution.ts +13 -0
  173. package/src/contracts/shared.ts +6 -1
  174. package/src/contracts/user-notifications.ts +2 -0
  175. package/src/events/app-event-delivery.ts +100 -0
  176. package/src/events/app-events.testing.ts +65 -0
  177. package/src/events/app-events.ts +134 -0
  178. package/src/events/core-user-created.ts +24 -0
  179. package/src/events/index.ts +9 -0
  180. package/src/events/testing.ts +2 -0
  181. package/src/index.ts +1 -1
  182. package/src/server/api/respond.ts +17 -4
  183. package/src/server/index.ts +2 -0
  184. package/src/server/middleware/app-access.ts +1 -1
  185. package/src/server/middleware/auth.ts +21 -7
  186. package/src/server/middleware/index.ts +1 -0
  187. package/src/server/middleware/invocation.ts +2 -0
  188. package/src/server/public-storage.ts +106 -0
  189. package/src/server/services/access.ts +31 -10
  190. package/src/server/services/index.ts +1 -0
  191. package/src/services/accounts/app.ts +36 -13
  192. package/src/services/accounts/entities.ts +43 -19
  193. package/src/services/accounts/group-sql.ts +23 -0
  194. package/src/services/accounts/groups.ts +19 -14
  195. package/src/services/accounts/identities.ts +70 -11
  196. package/src/services/accounts/identity-reconciliation.ts +3 -1
  197. package/src/services/accounts/local-groups.ts +69 -4
  198. package/src/services/accounts/users.ts +45 -14
  199. package/src/services/app-access.ts +25 -7
  200. package/src/services/app-details.ts +224 -0
  201. package/src/services/app-discovery.ts +2 -1
  202. package/src/services/app-event-shapes.ts +139 -0
  203. package/src/services/app-events/accept.ts +116 -0
  204. package/src/services/app-events/admin.ts +250 -0
  205. package/src/services/app-events/declarations.ts +187 -0
  206. package/src/services/app-events/deliver.ts +218 -0
  207. package/src/services/app-events.ts +92 -0
  208. package/src/services/config-conflict.ts +11 -0
  209. package/src/services/core-user-events.ts +1 -0
  210. package/src/services/freeipa-config.ts +9 -0
  211. package/src/services/geo/ledger.ts +28 -10
  212. package/src/services/geo/service.ts +43 -24
  213. package/src/services/identity/core-origin.ts +12 -0
  214. package/src/services/identity/invocation-actor.ts +20 -2
  215. package/src/services/identity/invocation-authority.ts +4 -0
  216. package/src/services/identity/invocation-token.ts +238 -56
  217. package/src/services/identity/issue-invocation.ts +6 -1
  218. package/src/services/image-metadata.ts +65 -1
  219. package/src/services/index.ts +13 -1
  220. package/src/services/ipa/sync.ts +6 -2
  221. package/src/services/ipa/users.ts +4 -1
  222. package/src/services/mandates/index.ts +2 -2
  223. package/src/services/mandates/policy.ts +20 -12
  224. package/src/services/notifications/browser.ts +4 -0
  225. package/src/services/notifications/catalog.ts +5 -2
  226. package/src/services/notifications/platform.ts +7 -2
  227. package/src/services/notifications/user.ts +18 -7
  228. package/src/services/oauth-tokens.ts +28 -2
  229. package/src/services/object-store.ts +217 -0
  230. package/src/services/providers/local/users.ts +5 -0
  231. package/src/services/pwa-devices.ts +147 -37
  232. package/src/services/session/index.ts +26 -3
  233. package/src/services/settings/core-settings.ts +71 -43
  234. package/src/services/settings/index.ts +8 -0
  235. package/src/services/settings/versions.ts +26 -0
  236. package/src/shared/ai-models.ts +274 -0
  237. package/src/shared/ai-quotas.ts +2 -2
  238. package/src/shared/ai-usage.ts +2 -2
  239. package/src/shared/email-html.ts +1 -0
  240. package/src/shared/index.ts +2 -0
  241. package/src/shared/markdown/extensions/katex.ts +8 -1
  242. package/src/shared/markdown/extensions/tables.ts +14 -1
  243. package/src/shared/markdown/index.ts +22 -11
  244. package/src/shared-text/anchors.ts +29 -0
  245. package/src/shared-text/awareness.ts +87 -0
  246. package/src/shared-text/changes.ts +27 -0
  247. package/src/shared-text/documents.ts +433 -65
  248. package/src/shared-text/events.ts +12 -2
  249. package/src/shared-text/index.ts +16 -1
  250. package/src/shared-text/log.ts +24 -5
  251. package/src/shared-text/snapshots.ts +69 -23
  252. package/src/shared-text/structural-history.ts +377 -0
  253. package/src/shared-text/table-actions.ts +432 -0
  254. package/src/shared-text/text-diff.ts +75 -0
  255. package/src/shared-text/types.ts +24 -5
  256. package/src/ssr/AdminArea.tsx +131 -0
  257. package/src/ssr/AdminLayout.tsx +9 -3
  258. package/src/ssr/AdminSidebar.tsx +7 -7
  259. package/src/ssr/AppAccessDenied.tsx +2 -0
  260. package/src/ssr/AppBadge.tsx +14 -0
  261. package/src/ssr/AppLaunchpadPanel.tsx +2 -2
  262. package/src/ssr/CloudShell.island.tsx +44 -7
  263. package/src/ssr/Layout.tsx +9 -7
  264. package/src/ssr/MobileProfileActions.tsx +2 -2
  265. package/src/ssr/ProfilePreferences.tsx +2 -1
  266. package/src/ssr/PwaLayout.tsx +16 -1
  267. package/src/ssr/PwaPartCount.island.tsx +23 -0
  268. package/src/ssr/SettingsSaveOutcome.tsx +58 -0
  269. package/src/ssr/SettingsSaveStatus.island.tsx +16 -0
  270. package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +3 -3
  271. package/src/ssr/admin-active-link.ts +16 -0
  272. package/src/ssr/admin-navigation.ts +26 -31
  273. package/src/ssr/app-badges.ts +31 -7
  274. package/src/ssr/app-launchpad.tsx +6 -1
  275. package/src/ssr/index.ts +8 -0
  276. package/src/ssr/page-trail-runtime.ts +3 -1
  277. package/src/ssr/platform-messages.ts +11 -1
  278. package/src/ssr/profile-actions.ts +3 -6
  279. package/src/ssr/pwa-messages.ts +2 -2
  280. package/src/ssr/rail-navigation.ts +5 -1
  281. package/src/ssr/settings-draft.ts +153 -0
  282. package/src/ssr/shell-data.tsx +3 -1
  283. package/src/styles/global.css +1 -0
  284. package/src/styles/profile-picture.css +270 -0
  285. package/src/styles/utilities-navigation.css +6 -0
  286. package/src/workflows/ai/policy.ts +49 -0
  287. package/src/workflows/ai/runtime.ts +131 -21
  288. package/src/workflows/ai/store.ts +283 -35
  289. package/src/workflows/ai/types.ts +8 -2
  290. package/src/workflows/ai-actions.ts +148 -120
  291. package/src/workflows/authoring.ts +31 -0
  292. package/src/workflows/contracts.ts +1 -0
  293. package/src/workflows/definition.ts +2 -0
  294. package/src/workflows/editor.ts +15 -0
  295. package/src/workflows/index.ts +2 -1
  296. package/src/workflows/language/compiler.ts +34 -3
  297. package/src/workflows/language/expressions.ts +3 -2
  298. package/src/workflows/runtime/executor.ts +134 -34
  299. package/src/workflows/runtime/index.ts +2 -0
  300. package/src/workflows/runtime/ports.ts +5 -1
  301. package/src/workflows/store/actions.ts +1 -1
  302. package/src/workflows/store/definitions.ts +5 -0
  303. package/src/workflows/store/runs.ts +5 -3
  304. package/src/workflows/store/worker.ts +7 -2
  305. package/src/ai/model-pricing.ts +0 -43
  306. package/src/ai/model-request-settings.ts +0 -98
  307. package/src/ai/settings-messages.ts +0 -129
  308. package/src/shared/ai-model-request-settings.ts +0 -21
@@ -0,0 +1,53 @@
1
+ import type { AccessSubject, RequestActor } from "../server";
2
+ import { hasPermission, type PermissionLevel } from "../server/services/access";
3
+
4
+ /** Resource operations retain the actor's credential alongside the grant subject. */
5
+ export type AiResourceContext = { actor: RequestActor; accessSubject: AccessSubject };
6
+
7
+ export const aiResourceAccessSubject = (subject: AiResourceContext | null): AccessSubject | null => subject?.accessSubject ?? null;
8
+
9
+ /** Projects and Skills have no supported resource-bound credential contract. */
10
+ export const aiResourcePermissionCap = (subject: AiResourceContext | null): PermissionLevel => {
11
+ if (!subject?.actor || !subject.accessSubject) return "none";
12
+ const { actor, accessSubject } = subject;
13
+ if (actor.kind === "user") {
14
+ return accessSubject.type === "user" && accessSubject.userId === actor.user.id ? "admin" : "none";
15
+ }
16
+ if (actor.serviceAccount.kind === "resource_bound") return "none";
17
+ if (actor.delegatedUser) {
18
+ return actor.serviceAccount.kind === "user_delegated" &&
19
+ accessSubject.type === "user" &&
20
+ accessSubject.userId === actor.delegatedUser.id
21
+ ? "admin"
22
+ : "none";
23
+ }
24
+ if (
25
+ (actor.serviceAccount.kind !== "standalone" && actor.serviceAccount.kind !== "agent") ||
26
+ accessSubject.type !== "service_account" ||
27
+ accessSubject.serviceAccountId !== actor.serviceAccount.id
28
+ )
29
+ return "none";
30
+ return actor.scopes.includes("admin")
31
+ ? "admin"
32
+ : actor.scopes.includes("write")
33
+ ? "write"
34
+ : actor.scopes.includes("read")
35
+ ? "read"
36
+ : "none";
37
+ };
38
+
39
+ export const capAiResourcePermission = (granted: PermissionLevel, subject: AiResourceContext | null): PermissionLevel => {
40
+ const cap = aiResourcePermissionCap(subject);
41
+ return hasPermission(granted, cap) ? cap : granted;
42
+ };
43
+
44
+ export class AiResourceCredentialError extends Error {
45
+ constructor() {
46
+ super("The credential does not permit creating Projects or Skills.");
47
+ this.name = "AiResourceCredentialError";
48
+ }
49
+ }
50
+
51
+ export const requireAiResourceCreation = (subject: AiResourceContext): void => {
52
+ if (!hasPermission(aiResourcePermissionCap(subject), "write")) throw new AiResourceCredentialError();
53
+ };
@@ -1,4 +1,5 @@
1
- import { Hono, type MiddlewareHandler } from "hono";
1
+ import { type Context, Hono, type MiddlewareHandler } from "hono";
2
+ import { HTTPException } from "hono/http-exception";
2
3
  import { z } from "zod";
3
4
  import { getCapability } from "../_internal/registry";
4
5
  import { CloudResourceRefSchema, cloudResourceRefAppId, resolveCapabilityResourceReader } from "../contracts/capabilities";
@@ -6,6 +7,7 @@ import { AuthenticatedPrincipalSchema } from "../contracts/shared";
6
7
  import { type AuthContext, auth, err, fail, getLocale, ok, rateLimit, respond, v } from "../server";
7
8
  import { noTransform } from "../server/middleware/no-transform";
8
9
  import { ImageMetadataError } from "../services/image-metadata";
10
+ import { AiModelRequestSchema } from "../shared/ai-models";
9
11
  import { aiChatMessages } from "./chat/messages";
10
12
  import { decodeAiFileContent } from "./files-store";
11
13
  import {
@@ -21,16 +23,23 @@ import {
21
23
  type AiProjectReference,
22
24
  aiProjects,
23
25
  } from "./projects";
26
+ import { AiResourceCredentialError } from "./projects-authorization";
24
27
 
25
28
  const ProjectFieldsSchema = z.object({
26
29
  name: z.string().trim().min(1).max(AI_PROJECT_NAME_MAX_CHARS),
27
30
  description: z.string().trim().max(AI_PROJECT_DESCRIPTION_MAX_CHARS).default(""),
28
31
  icon: z.string().trim().min(1).max(80).default("ti ti-folders"),
29
32
  instructions: z.string().trim().max(AI_PROJECT_INSTRUCTIONS_MAX_CHARS).default(""),
30
- defaultModelProfileId: z.string().trim().min(1).max(120).nullable().optional(),
33
+ defaultModel: AiModelRequestSchema.nullable().optional(),
31
34
  });
32
35
 
33
- const UpdateProjectSchema = ProjectFieldsSchema.partial().refine((input) => Object.keys(input).length > 0, "No changes supplied.");
36
+ const UpdateProjectSchema = ProjectFieldsSchema.extend({
37
+ description: ProjectFieldsSchema.shape.description.removeDefault(),
38
+ icon: ProjectFieldsSchema.shape.icon.removeDefault(),
39
+ instructions: ProjectFieldsSchema.shape.instructions.removeDefault(),
40
+ })
41
+ .partial()
42
+ .refine((input) => Object.keys(input).length > 0, "No changes supplied.");
34
43
  const ProjectAccessSchema = z.object({ principal: AuthenticatedPrincipalSchema, permission: z.enum(["read", "write", "admin"]) });
35
44
  const ProjectAccessUpdateSchema = z.object({ permission: z.enum(["read", "write", "admin"]) });
36
45
  const KnowledgeSchema = z.object({
@@ -64,6 +73,11 @@ const publicReference = (reference: AiProjectReference, projectId: string): AiPr
64
73
  projectId,
65
74
  });
66
75
 
76
+ const resourceSubject = (c: Context<AuthContext>) => ({
77
+ actor: c.get("actor"),
78
+ accessSubject: c.get("accessSubject"),
79
+ });
80
+
67
81
  type AiProjectsRouteDependencies = {
68
82
  limit?: MiddlewareHandler<AuthContext>;
69
83
  authenticate?: MiddlewareHandler<AuthContext>;
@@ -72,56 +86,54 @@ type AiProjectsRouteDependencies = {
72
86
 
73
87
  const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =>
74
88
  new Hono<AuthContext>()
89
+ .onError((error, c) => {
90
+ if (error instanceof AiResourceCredentialError) return respond(c, fail(err.forbidden(error.message)));
91
+ if (error instanceof HTTPException) return error.getResponse();
92
+ throw error;
93
+ })
75
94
  // The list combines projects from separate grants; the writer of one can rename it next to another project's instructions.
76
95
  .use("*", noTransform())
77
96
  .use(dependencies.limit ?? rateLimit())
78
97
  .use("*", dependencies.authenticate ?? auth.requireRole("authenticated"))
79
- .get("/", async (c) => respond(c, ok({ projects: (await aiProjects.list(c.get("accessSubject") ?? null)).map(publicProject) })))
98
+ .get("/", async (c) => respond(c, ok({ projects: (await aiProjects.list(resourceSubject(c))).map(publicProject) })))
80
99
  .post("/", dependencies.authenticate ?? auth.requireRole("authenticated"), v("json", ProjectFieldsSchema), async (c) =>
81
100
  respond(
82
101
  c,
83
102
  ok({
84
- project: publicProject(await aiProjects.create({ subject: c.get("accessSubject"), ...c.req.valid("json") })),
103
+ project: publicProject(await aiProjects.create({ subject: resourceSubject(c), ...c.req.valid("json") })),
85
104
  }),
86
105
  201,
87
106
  ),
88
107
  )
89
108
  .get("/:projectId", async (c) => {
90
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null);
109
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c));
91
110
  return project ? respond(c, ok({ project: publicProject(project) })) : notFound(c);
92
111
  })
93
112
  .patch("/:projectId", v("json", UpdateProjectSchema), async (c) => {
94
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
113
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
95
114
  if (!project) return notFound(c);
96
- const updated = await aiProjects.update(project.id, c.get("accessSubject") ?? null, c.req.valid("json"));
115
+ const updated = await aiProjects.update(project.id, resourceSubject(c), c.req.valid("json"));
97
116
  return updated ? respond(c, ok({ project: publicProject(updated) })) : notFound(c);
98
117
  })
99
118
  .delete("/:projectId", async (c) => {
100
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "admin");
101
- return project && (await aiProjects.delete(project.id, c.get("accessSubject") ?? null))
102
- ? respond(c, ok({ deleted: true }))
103
- : notFound(c);
119
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "admin");
120
+ return project && (await aiProjects.delete(project.id, resourceSubject(c))) ? respond(c, ok({ deleted: true })) : notFound(c);
104
121
  })
105
122
  .get("/:projectId/access", async (c) => {
106
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "admin");
107
- const access = project ? await aiProjects.listAccess(project.id, c.get("accessSubject") ?? null) : null;
123
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "admin");
124
+ const access = project ? await aiProjects.listAccess(project.id, resourceSubject(c)) : null;
108
125
  return access ? respond(c, ok({ access })) : notFound(c);
109
126
  })
110
127
  .post("/:projectId/access", v("json", ProjectAccessSchema), async (c) => {
111
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "admin");
112
- const access = project ? await aiProjects.grantAccess(project.id, c.get("accessSubject") ?? null, c.req.valid("json")) : null;
128
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "admin");
129
+ const access = project ? await aiProjects.grantAccess(project.id, resourceSubject(c), c.req.valid("json")) : null;
113
130
  return access ? respond(c, ok({ access }), 201) : notFound(c);
114
131
  })
115
132
  .patch("/:projectId/access/:accessId", v("json", ProjectAccessUpdateSchema), async (c) => {
116
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "admin");
133
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "admin");
117
134
  try {
118
135
  return project &&
119
- (await aiProjects.updateAccess(
120
- project.id,
121
- c.req.param("accessId")!,
122
- c.get("accessSubject") ?? null,
123
- c.req.valid("json").permission,
124
- ))
136
+ (await aiProjects.updateAccess(project.id, c.req.param("accessId")!, resourceSubject(c), c.req.valid("json").permission))
125
137
  ? respond(c, ok({ updated: true }))
126
138
  : notFound(c, "Access entry");
127
139
  } catch (error) {
@@ -130,9 +142,9 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
130
142
  }
131
143
  })
132
144
  .delete("/:projectId/access/:accessId", async (c) => {
133
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "admin");
145
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "admin");
134
146
  try {
135
- return project && (await aiProjects.revokeAccess(project.id, c.req.param("accessId")!, c.get("accessSubject") ?? null))
147
+ return project && (await aiProjects.revokeAccess(project.id, c.req.param("accessId")!, resourceSubject(c)))
136
148
  ? respond(c, ok({ deleted: true }))
137
149
  : notFound(c, "Access entry");
138
150
  } catch (error) {
@@ -141,51 +153,50 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
141
153
  }
142
154
  })
143
155
  .get("/:projectId/knowledge", v("query", KnowledgeQuerySchema), async (c) => {
144
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null);
156
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c));
145
157
  if (!project) return notFound(c);
146
158
  return respond(
147
159
  c,
148
160
  ok({
149
- knowledge: (await aiProjects.listKnowledge(project.id, c.get("accessSubject") ?? null, c.req.valid("query").q)).map((item) =>
161
+ knowledge: (await aiProjects.listKnowledge(project.id, resourceSubject(c), c.req.valid("query").q)).map((item) =>
150
162
  publicKnowledge(item, project.shortId),
151
163
  ),
152
164
  }),
153
165
  );
154
166
  })
155
167
  .post("/:projectId/knowledge", v("json", KnowledgeSchema), async (c) => {
156
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
157
- const knowledge = project ? await aiProjects.createKnowledge(project.id, c.get("accessSubject") ?? null, c.req.valid("json")) : null;
168
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
169
+ const knowledge = project ? await aiProjects.createKnowledge(project.id, resourceSubject(c), c.req.valid("json")) : null;
158
170
  return knowledge ? respond(c, ok({ knowledge: publicKnowledge(knowledge, project!.shortId) }), 201) : notFound(c);
159
171
  })
160
172
  .patch("/:projectId/knowledge/:knowledgeId", v("json", UpdateKnowledgeSchema), async (c) => {
161
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
173
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
162
174
  const knowledge =
163
- project &&
164
- (await aiProjects.updateKnowledge(project.id, c.req.param("knowledgeId")!, c.get("accessSubject") ?? null, c.req.valid("json")));
175
+ project && (await aiProjects.updateKnowledge(project.id, c.req.param("knowledgeId")!, resourceSubject(c), c.req.valid("json")));
165
176
  return knowledge ? respond(c, ok({ knowledge: publicKnowledge(knowledge, project!.shortId) })) : notFound(c, "Knowledge entry");
166
177
  })
167
178
  .delete("/:projectId/knowledge/:knowledgeId", async (c) => {
168
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
169
- return project && (await aiProjects.deleteKnowledge(project.id, c.req.param("knowledgeId")!, c.get("accessSubject") ?? null))
179
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
180
+ return project && (await aiProjects.deleteKnowledge(project.id, c.req.param("knowledgeId")!, resourceSubject(c)))
170
181
  ? respond(c, ok({ deleted: true }))
171
182
  : notFound(c, "Knowledge entry");
172
183
  })
173
184
  .get("/:projectId/files", async (c) => {
174
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null);
185
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c));
175
186
  if (!project) return notFound(c);
176
187
  return respond(
177
188
  c,
178
189
  ok({
179
- files: (await aiProjects.listFiles(project.id, c.get("accessSubject") ?? null)).map((file) => publicFile(file, project.shortId)),
190
+ files: (await aiProjects.listFiles(project.id, resourceSubject(c))).map((file) => publicFile(file, project.shortId)),
180
191
  }),
181
192
  );
182
193
  })
183
194
  .post("/:projectId/files", v("json", ProjectFileSchema), async (c) => {
184
195
  const body = c.req.valid("json");
185
196
  try {
186
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
197
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
187
198
  const file = project
188
- ? await aiProjects.writeFile(project.id, c.get("accessSubject") ?? null, {
199
+ ? await aiProjects.writeFile(project.id, resourceSubject(c), {
189
200
  path: body.path,
190
201
  mediaType: body.mediaType,
191
202
  bytes: decodeAiFileContent(body.content, body.encoding),
@@ -199,8 +210,8 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
199
210
  }
200
211
  })
201
212
  .get("/:projectId/files/:fileId", async (c) => {
202
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null);
203
- const file = project ? await aiProjects.readFile(project.id, c.req.param("fileId")!, c.get("accessSubject") ?? null) : null;
213
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c));
214
+ const file = project ? await aiProjects.readFile(project.id, c.req.param("fileId")!, resourceSubject(c)) : null;
204
215
  if (!file) return notFound(c, "Project file");
205
216
  return respond(
206
217
  c,
@@ -212,18 +223,18 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
212
223
  );
213
224
  })
214
225
  .delete("/:projectId/files/:fileId", async (c) => {
215
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
216
- return project && (await aiProjects.deleteFile(project.id, c.req.param("fileId")!, c.get("accessSubject") ?? null))
226
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
227
+ return project && (await aiProjects.deleteFile(project.id, c.req.param("fileId")!, resourceSubject(c)))
217
228
  ? respond(c, ok({ deleted: true }))
218
229
  : notFound(c, "Project file");
219
230
  })
220
231
  .get("/:projectId/references", async (c) => {
221
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null);
232
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c));
222
233
  if (!project) return notFound(c);
223
234
  return respond(
224
235
  c,
225
236
  ok({
226
- references: (await aiProjects.listReferences(project.id, c.get("accessSubject") ?? null)).map((reference) =>
237
+ references: (await aiProjects.listReferences(project.id, resourceSubject(c))).map((reference) =>
227
238
  publicReference(reference, project.shortId),
228
239
  ),
229
240
  }),
@@ -231,7 +242,7 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
231
242
  })
232
243
  .post("/:projectId/references", v("json", ReferenceSchema), async (c) => {
233
244
  const body = c.req.valid("json");
234
- const subject = c.get("accessSubject") ?? null;
245
+ const subject = resourceSubject(c);
235
246
  const project = await aiProjects.getByShortId(c.req.param("projectId")!, subject, "write");
236
247
  if (!project) return notFound(c);
237
248
  let entry: Awaited<ReturnType<typeof getCapability>>;
@@ -247,8 +258,8 @@ const buildAiProjectsRoutes = (dependencies: AiProjectsRouteDependencies = {}) =
247
258
  return reference ? respond(c, ok({ reference: publicReference(reference, project.shortId) }), 201) : notFound(c);
248
259
  })
249
260
  .delete("/:projectId/references/:referenceId", async (c) => {
250
- const project = await aiProjects.getByShortId(c.req.param("projectId")!, c.get("accessSubject") ?? null, "write");
251
- return project && (await aiProjects.deleteReference(project.id, c.req.param("referenceId")!, c.get("accessSubject") ?? null))
261
+ const project = await aiProjects.getByShortId(c.req.param("projectId")!, resourceSubject(c), "write");
262
+ return project && (await aiProjects.deleteReference(project.id, c.req.param("referenceId")!, resourceSubject(c)))
252
263
  ? respond(c, ok({ deleted: true }))
253
264
  : notFound(c, "Project reference");
254
265
  });