@k2b/cloud 0.48.0 → 0.50.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 (206) hide show
  1. package/package.json +3 -3
  2. package/src/_internal/app-access-resources.ts +2 -1
  3. package/src/_internal/app-capabilities.ts +73 -0
  4. package/src/_internal/app-event-catalog.ts +1 -1
  5. package/src/_internal/app-queries.ts +1 -1
  6. package/src/_internal/application-package.ts +2 -1
  7. package/src/_internal/capabilities.ts +17 -2
  8. package/src/_internal/define-app.ts +2 -0
  9. package/src/ai/app-skill-store.ts +2 -1
  10. package/src/ai/app-skills.ts +2 -1
  11. package/src/ai/approvals.ts +2 -1
  12. package/src/ai/chat-tasks.ts +2 -1
  13. package/src/ai/credentials.ts +2 -1
  14. package/src/ai/dictation-runtime.ts +1 -1
  15. package/src/ai/dictations.ts +1 -1
  16. package/src/ai/files-store.ts +2 -1
  17. package/src/ai/inference-calls.ts +2 -1
  18. package/src/ai/map-store.ts +1 -1
  19. package/src/ai/map-tool.ts +1 -1
  20. package/src/ai/memories.ts +1 -1
  21. package/src/ai/memory-learning-runs.ts +1 -1
  22. package/src/ai/memory-learning.ts +1 -1
  23. package/src/ai/memory-workflow-evidence.ts +1 -1
  24. package/src/ai/message-queue.ts +2 -1
  25. package/src/ai/migrate.ts +1 -1
  26. package/src/ai/model-access-migrate.ts +1 -1
  27. package/src/ai/model-access.ts +1 -1
  28. package/src/ai/model-catalog.ts +1 -1
  29. package/src/ai/model-delete.ts +1 -1
  30. package/src/ai/model-usage.ts +2 -1
  31. package/src/ai/open-questions.ts +1 -1
  32. package/src/ai/openai-api-slots.ts +2 -1
  33. package/src/ai/prefs.ts +2 -1
  34. package/src/ai/projects.ts +2 -1
  35. package/src/ai/provider-connections.ts +1 -1
  36. package/src/ai/quota-limits.ts +2 -1
  37. package/src/ai/quota-provider.ts +2 -1
  38. package/src/ai/quota-report.ts +2 -1
  39. package/src/ai/quotas-migrate.ts +2 -1
  40. package/src/ai/quotas.ts +2 -1
  41. package/src/ai/request-headers.ts +2 -1
  42. package/src/ai/review-content.ts +2 -1
  43. package/src/ai/skill-search.ts +2 -1
  44. package/src/ai/skills.ts +2 -1
  45. package/src/ai/store.ts +2 -1
  46. package/src/ai/structured-runs.ts +2 -1
  47. package/src/ai/tool-audit.ts +2 -1
  48. package/src/ai/turn-timing.ts +1 -1
  49. package/src/ai/usage.ts +2 -1
  50. package/src/ai/web-provenance.ts +2 -1
  51. package/src/api/admin-ai-quotas.ts +1 -1
  52. package/src/api/admin-ai.ts +1 -1
  53. package/src/api/admin-app-keys.ts +47 -3
  54. package/src/api/admin-core-settings.ts +1 -1
  55. package/src/api/admin-outgoing-mail.ts +1 -1
  56. package/src/api/app-bootstrap.ts +23 -1
  57. package/src/api/app-events.ts +1 -1
  58. package/src/api/auth.ts +1 -1
  59. package/src/api/authenticate-app-request.ts +129 -0
  60. package/src/api/capabilities.ts +79 -5
  61. package/src/api/index.ts +2 -0
  62. package/src/api/me.ts +1 -1
  63. package/src/api/search.bench.ts +1 -1
  64. package/src/app-pwa/service.ts +2 -1
  65. package/src/app-pwa/transaction.ts +4 -2
  66. package/src/capabilities/claims.ts +2 -1
  67. package/src/capabilities/executions.ts +8 -4
  68. package/src/capabilities/geo-client.ts +1 -1
  69. package/src/capabilities/migrate.ts +3 -1
  70. package/src/capabilities/resource-readers.ts +2 -2
  71. package/src/capabilities/server-invoke.ts +45 -18
  72. package/src/capabilities/server.ts +2 -1
  73. package/src/cli/admin/app-keys.ts +25 -3
  74. package/src/config/env.ts +4 -4
  75. package/src/contracts/capabilities.ts +15 -2
  76. package/src/contracts/outgoing-mail.ts +1 -1
  77. package/src/events/app-event-delivery.ts +1 -1
  78. package/src/events/live-delivery.ts +2 -1
  79. package/src/runtime/bootstrap-protocol.ts +11 -4
  80. package/src/runtime/clients.ts +6 -2
  81. package/src/server/index.ts +1 -0
  82. package/src/server/ratelimit.ts +1 -1
  83. package/src/server/services/access.ts +2 -1
  84. package/src/services/account-category-policy.ts +1 -1
  85. package/src/services/account-lifecycle/audit.ts +1 -1
  86. package/src/services/account-lifecycle/index.ts +1 -1
  87. package/src/services/account-lifecycle/ipa-backfill.ts +2 -1
  88. package/src/services/accounts/app.ts +1 -1
  89. package/src/services/accounts/avatar.ts +1 -1
  90. package/src/services/accounts/base-group.ts +1 -1
  91. package/src/services/accounts/directory-shares.ts +1 -1
  92. package/src/services/accounts/duplicate-emails.ts +1 -1
  93. package/src/services/accounts/entities.ts +2 -1
  94. package/src/services/accounts/group-sql.ts +2 -1
  95. package/src/services/accounts/groups.ts +1 -1
  96. package/src/services/accounts/identities.ts +13 -11
  97. package/src/services/accounts/ipa-data.ts +1 -1
  98. package/src/services/accounts/local-groups.ts +2 -1
  99. package/src/services/accounts/machine-group-management.ts +2 -1
  100. package/src/services/accounts/posix.ts +13 -12
  101. package/src/services/accounts/request-policy.ts +2 -1
  102. package/src/services/accounts/switching.ts +1 -1
  103. package/src/services/accounts/users.ts +2 -1
  104. package/src/services/announcements/index.ts +1 -1
  105. package/src/services/app-access-management.ts +2 -1
  106. package/src/services/app-access.ts +2 -1
  107. package/src/services/app-admin-facts.ts +11 -3
  108. package/src/services/app-approval.ts +34 -30
  109. package/src/services/app-bootstrap.ts +104 -21
  110. package/src/services/app-details.ts +3 -2
  111. package/src/services/app-events/accept.ts +5 -5
  112. package/src/services/app-events/admin.ts +15 -15
  113. package/src/services/app-events/declarations.ts +6 -3
  114. package/src/services/app-events/deliver.ts +6 -6
  115. package/src/services/app-events.ts +3 -2
  116. package/src/services/app-keys.ts +42 -11
  117. package/src/services/approvals/content.ts +1 -1
  118. package/src/services/approvals/index.ts +2 -1
  119. package/src/services/approvals/list.ts +1 -1
  120. package/src/services/approvals/migrate.ts +1 -1
  121. package/src/services/audit/index.ts +2 -1
  122. package/src/services/auth-flows/ipa.ts +1 -1
  123. package/src/services/auth-flows/magic-link.ts +1 -1
  124. package/src/services/auth-flows/password-reset.ts +1 -1
  125. package/src/services/auth-flows/proxy-return.ts +1 -1
  126. package/src/services/geo/admin.ts +13 -12
  127. package/src/services/geo/identity.ts +46 -0
  128. package/src/services/geo/ledger.ts +118 -106
  129. package/src/services/geo/migrate.ts +2 -1
  130. package/src/services/geo/route-chain.ts +3 -3
  131. package/src/services/geo/service.ts +4 -24
  132. package/src/services/geoip/index.ts +5 -5
  133. package/src/services/geoip/store.ts +24 -21
  134. package/src/services/help/index.ts +2 -1
  135. package/src/services/help/store.ts +2 -1
  136. package/src/services/identity/app-request.ts +44 -0
  137. package/src/services/identity/constants.ts +1 -0
  138. package/src/services/identity/index.ts +1 -0
  139. package/src/services/identity/invocation-actor.ts +2 -1
  140. package/src/services/identity/invocation-token.ts +112 -0
  141. package/src/services/identity/key-ring.ts +2 -2
  142. package/src/services/identity/resource-readers.ts +1 -1
  143. package/src/services/identity/routes.ts +11 -3
  144. package/src/services/identity/runtime-config.ts +14 -3
  145. package/src/services/identity/workload-auth.ts +2 -0
  146. package/src/services/identity/workload-runtime.ts +1 -1
  147. package/src/services/ipa/groups.ts +1 -1
  148. package/src/services/ipa/profile.ts +1 -1
  149. package/src/services/ipa/search.ts +1 -1
  150. package/src/services/ipa/sync.ts +1 -1
  151. package/src/services/ipa/users.ts +1 -1
  152. package/src/services/known-browsers.ts +2 -1
  153. package/src/services/legal-consent.ts +1 -1
  154. package/src/services/logging/index.ts +6 -3
  155. package/src/services/logging/trace.ts +1 -1
  156. package/src/services/logging/web-vitals.ts +1 -1
  157. package/src/services/mandates/index.ts +2 -1
  158. package/src/services/notifications/batches.ts +1 -1
  159. package/src/services/notifications/browser.ts +1 -1
  160. package/src/services/notifications/catalog.ts +1 -1
  161. package/src/services/notifications/dispatcher.ts +1 -1
  162. package/src/services/notifications/index.ts +1 -1
  163. package/src/services/notifications/observability.ts +2 -1
  164. package/src/services/notifications/platform.ts +1 -1
  165. package/src/services/notifications/quiet.ts +1 -1
  166. package/src/services/notifications/user.ts +1 -1
  167. package/src/services/oauth-tokens.ts +1 -1
  168. package/src/services/outbox.ts +15 -14
  169. package/src/services/outgoing-mail/admin.ts +1 -1
  170. package/src/services/outgoing-mail/dispatcher.ts +1 -1
  171. package/src/services/outgoing-mail/drain.ts +2 -1
  172. package/src/services/outgoing-mail/enqueue.ts +2 -1
  173. package/src/services/outgoing-mail/messages.ts +2 -1
  174. package/src/services/outgoing-mail/retention.ts +1 -1
  175. package/src/services/outgoing-mail/send.ts +1 -1
  176. package/src/services/outgoing-mail/store.ts +2 -1
  177. package/src/services/panel-context-consent.ts +32 -28
  178. package/src/services/providers/local/auth.ts +1 -1
  179. package/src/services/providers/local/users.ts +1 -1
  180. package/src/services/pwa-devices.ts +2 -1
  181. package/src/services/rail-preferences.ts +16 -12
  182. package/src/services/rail-shortcuts.ts +12 -10
  183. package/src/services/request-cache-redis.ts +3 -3
  184. package/src/services/service-account-credentials.ts +2 -1
  185. package/src/services/service-accounts.ts +2 -1
  186. package/src/services/session/index.ts +2 -1
  187. package/src/services/session/user.ts +2 -1
  188. package/src/services/settings/index.ts +1 -1
  189. package/src/services/settings/store.ts +1 -1
  190. package/src/services/settings/versions.ts +2 -1
  191. package/src/services/weather/forecast.ts +2 -1
  192. package/src/services/weather/locations.ts +1 -1
  193. package/src/services/weather/migrate.ts +2 -1
  194. package/src/services/weather/short-id.ts +2 -1
  195. package/src/services/webauthn.ts +1 -1
  196. package/src/shared-text/documents.ts +2 -2
  197. package/src/ssr/compact-shell.browser-harness.ts +2 -0
  198. package/src/workflows/ai/store.ts +2 -1
  199. package/src/workflows/store/budget.ts +2 -1
  200. package/src/workflows/store/definitions.ts +2 -1
  201. package/src/workflows/store/events.ts +2 -1
  202. package/src/workflows/store/observability.ts +2 -1
  203. package/src/workflows/store/retention.ts +2 -1
  204. package/src/workflows/store/runs.ts +2 -1
  205. package/src/workflows/store/transaction.ts +2 -1
  206. package/src/workflows/store/worker.ts +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k2b/cloud",
3
- "version": "0.48.0",
3
+ "version": "0.50.0",
4
4
  "description": "Application platform library for independently deployed Hono and SolidJS services behind a dynamic gateway.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {
@@ -131,7 +131,7 @@
131
131
  "@tailwindcss/typography": "0.5.20",
132
132
  "@k2b/nessi": "0.18.0",
133
133
  "@k2b/ssr": "0.20.2",
134
- "@k2b/ui": "0.38.0",
134
+ "@k2b/ui": "0.39.0",
135
135
  "@k2b/stdlib": "0.30.0",
136
136
  "@k2b/sync": "7.0.1",
137
137
  "@nats-io/jetstream": "3.4.0",
@@ -163,7 +163,7 @@
163
163
  "hash-wasm": "4.12.0",
164
164
  "@types/sanitize-html": "2.16.1",
165
165
  "@types/web-push": "3.6.4",
166
- "@k2b/editor": "0.1.1"
166
+ "@k2b/editor": "0.3.0"
167
167
  },
168
168
  "devDependencies": {
169
169
  "@babel/core": "8.0.6",
@@ -1,8 +1,9 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import { type SQL, sql } from "bun";
2
+ import type { SQL } from "bun";
3
3
  import { waitWithin } from "../api/fanout";
4
4
  import type { AppMeta } from "../contracts/app";
5
5
  import { type AppAccessDeclaration, type AppAccessRule, AppAccessRuleSchema, type ResourceAppAccessAdapter } from "../contracts/app-access";
6
+ import { sql } from "../runtime/clients";
6
7
  import type { RequestAuthority } from "../server/middleware/auth";
7
8
  import { coreOrigin } from "../services/identity/core-origin";
8
9
  import { invocationAuthorityFromRequest } from "../services/identity/invocation-authority";
@@ -0,0 +1,73 @@
1
+ import { Hono } from "hono";
2
+ import { CAPABILITY_MAX_REQUEST_BYTES } from "../contracts/capabilities";
3
+ import { resolveLocale } from "../server/locale";
4
+ import { getActiveAppKey } from "../services/app-keys";
5
+ import { verifyAppCapabilityInvocation } from "../services/identity/invocation-token";
6
+ import { get } from "../services/settings";
7
+ import { readBoundedJson } from "./bounded-json";
8
+ import { type CompiledCapabilities, invokeCompiledCapability, serializeCapabilityProviderResult } from "./capabilities";
9
+ import { withCapabilityRequestTimeout } from "./capability-timeout";
10
+
11
+ /** Separate from ordinary auth: application authority never becomes a grant-bearing person. */
12
+ export const createAppCapabilityRoutes = (compiled: CompiledCapabilities) => {
13
+ const router = new Hono();
14
+ for (const kind of ["query", "action"] as const) {
15
+ router.post(`/${kind === "query" ? "queries" : "actions"}/:capabilityId`, (c) =>
16
+ withCapabilityRequestTimeout(c, kind, async () => {
17
+ const operation = (kind === "query" ? compiled.queries : compiled.actions).get(c.req.param("capabilityId"));
18
+ const deny = () => c.json({ code: "FORBIDDEN", message: "A permitted signed app capability invocation is required" }, 403);
19
+ if (!operation?.manifest.appPermission || operation.manifest.stream) return deny();
20
+ const body = await readBoundedJson(c.req.raw, CAPABILITY_MAX_REQUEST_BYTES);
21
+ if (
22
+ !body.ok ||
23
+ !body.data ||
24
+ typeof body.data !== "object" ||
25
+ Array.isArray(body.data) ||
26
+ Object.keys(body.data).length !== 1 ||
27
+ !("input" in body.data)
28
+ )
29
+ return c.json({ code: "VALIDATION_FAILED", message: "Expected a bounded input object" }, 400);
30
+ const token = c.req.header("authorization")?.match(/^Bearer (\S+)$/)?.[1];
31
+ if (!token) return deny();
32
+ try {
33
+ const claims = await verifyAppCapabilityInvocation(token, {
34
+ appId: compiled.manifest.appId,
35
+ kind,
36
+ capabilityId: operation.manifest.localId,
37
+ schemaHash: operation.manifest.schemaHash,
38
+ permission: operation.manifest.appPermission,
39
+ input: body.data.input,
40
+ });
41
+ if (!claims) return deny();
42
+ const locale = resolveLocale(c.req.raw.headers, await get<string>("app.locale"));
43
+ if (!(await getActiveAppKey({ appId: claims.sub, keyId: claims.key_id }))) return deny();
44
+ const result = await invokeCompiledCapability({
45
+ compiled,
46
+ kind,
47
+ localId: operation.manifest.localId,
48
+ input: body.data.input,
49
+ expectedSchemaHash: claims.schema_hash,
50
+ context: {
51
+ actor: { kind: "app", appId: claims.sub, keyId: claims.key_id },
52
+ accessSubject: { type: "none" },
53
+ user: null,
54
+ locale,
55
+ requestId: claims.request_id,
56
+ origin: "app",
57
+ signal: c.req.raw.signal,
58
+ ...(c.req.header("idempotency-key") ? { idempotencyKey: c.req.header("idempotency-key") } : {}),
59
+ },
60
+ });
61
+ const response = serializeCapabilityProviderResult(result);
62
+ return new Response(response.body, {
63
+ status: response.status,
64
+ headers: { "content-type": "application/json", "cache-control": "no-store" },
65
+ });
66
+ } catch {
67
+ return c.json({ code: "APP_UNAVAILABLE", message: "App invocation verification unavailable" }, 503);
68
+ }
69
+ }),
70
+ );
71
+ }
72
+ return router;
73
+ };
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import type { CapabilityEventCatalogEntry, CapabilityManifest } from "../contracts/capabilities";
2
+ import { sql } from "../runtime/clients";
3
3
 
4
4
  export type CatalogSubscription = CapabilityEventCatalogEntry["subscribers"][number] & { eventType: string; version: number };
5
5
 
@@ -1,6 +1,6 @@
1
- import { sql } from "bun";
2
1
  import { Hono } from "hono";
3
2
  import { CAPABILITY_MAX_REQUEST_BYTES } from "../contracts/capabilities";
3
+ import { sql } from "../runtime/clients";
4
4
  import { resolveLocale } from "../server/locale";
5
5
  import { verifyAppQueryInvocation } from "../services/identity/invocation-token";
6
6
  import { get } from "../services/settings";
@@ -1,4 +1,5 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
+ import { sql } from "../runtime/clients";
2
3
  import { ensureSchema } from "../services/postgres";
3
4
  import builtInAppIds from "./built-in-app-ids.json";
4
5
 
@@ -133,6 +133,7 @@ const TYPE_FIELDS = {
133
133
  access: true,
134
134
  } satisfies DefinedFields<CapabilityResourceTypeDefinition>;
135
135
  const QUERY_FIELDS = {
136
+ app: true,
136
137
  appOnly: true,
137
138
  title: true,
138
139
  description: true,
@@ -144,6 +145,7 @@ const QUERY_FIELDS = {
144
145
  run: true,
145
146
  } satisfies DefinedFields<CapabilityQueryDefinition>;
146
147
  const ACTION_FIELDS = {
148
+ app: true,
147
149
  title: true,
148
150
  description: true,
149
151
  input: true,
@@ -682,6 +684,11 @@ const compileOperationSchemas = (definition: QueryDefinition | CapabilityActionD
682
684
  ) {
683
685
  throw new Error(`${label} input field "idempotencyKey" is reserved for capability transports`);
684
686
  }
687
+ if (definition.app !== undefined) {
688
+ assertDefinedFields(definition.app, { permission: true, run: true }, `${label} app`);
689
+ if (typeof definition.app.run !== "function") throw new Error(`${label} app.run must be a function`);
690
+ if (definition.stream) throw new Error(`${label} app calls cannot use streams`);
691
+ }
685
692
  const resultZodSchema = capabilityResultSchema(definition.data);
686
693
  const dataSchema = projectSchema(definition.data, `${label} data`, "output");
687
694
  return {
@@ -691,6 +698,7 @@ const compileOperationSchemas = (definition: QueryDefinition | CapabilityActionD
691
698
  schemaHash: capabilityHash({
692
699
  inputSchema,
693
700
  dataSchema,
701
+ ...(definition.app ? { appPermission: definition.app.permission } : {}),
694
702
  ...("appOnly" in definition && definition.appOnly !== undefined ? { appOnly: definition.appOnly } : {}),
695
703
  ...(definition.stream ? { stream: { direction: definition.stream.direction, maxBytes: definition.stream.maxBytes } } : {}),
696
704
  }),
@@ -843,6 +851,7 @@ export const compileCapabilities = (
843
851
  inputSchema: schemas.inputSchema,
844
852
  dataSchema: schemas.dataSchema,
845
853
  schemaHash: schemas.schemaHash,
854
+ ...(definition.app ? { appPermission: definition.app.permission } : {}),
846
855
  ...(definition.stream ? { stream: { direction: definition.stream.direction, maxBytes: definition.stream.maxBytes } } : {}),
847
856
  openWorld: definition.openWorld,
848
857
  universalSearch: normalizeSearchTags(definition, label),
@@ -927,6 +936,7 @@ export const compileCapabilities = (
927
936
  inputSchema: schemas.inputSchema,
928
937
  dataSchema: schemas.dataSchema,
929
938
  schemaHash: schemas.schemaHash,
939
+ ...(definition.app ? { appPermission: definition.app.permission } : {}),
930
940
  ...(definition.stream ? { stream: { direction: definition.stream.direction, maxBytes: definition.stream.maxBytes } } : {}),
931
941
  destructive: definition.destructive,
932
942
  openWorld: definition.openWorld,
@@ -1280,6 +1290,7 @@ const assertUsableOperation = (operation: CapabilityQueryManifest | CapabilityAc
1280
1290
  const expectedSchemaHash = capabilityHash({
1281
1291
  inputSchema: operation.inputSchema,
1282
1292
  dataSchema: operation.dataSchema,
1293
+ ...(operation.appPermission ? { appPermission: operation.appPermission } : {}),
1283
1294
  ...("appOnly" in operation && operation.appOnly !== undefined ? { appOnly: operation.appOnly } : {}),
1284
1295
  ...(operation.stream ? { stream: operation.stream } : {}),
1285
1296
  });
@@ -1782,9 +1793,13 @@ export const invokeCompiledCapability = async (params: {
1782
1793
  let invoked: CapabilityInvocationResult<unknown>;
1783
1794
  if (isAppCapabilityContext(context)) {
1784
1795
  const definition = operation.definition;
1785
- if (params.kind !== "query" || !("appOnly" in definition) || definition.appOnly !== true)
1796
+ if (definition.app && context.actor.keyId) {
1797
+ invoked = await definition.app.run(input.data, context);
1798
+ } else if (params.kind === "query" && "appOnly" in definition && definition.appOnly === true) {
1799
+ invoked = await definition.run(input.data, context);
1800
+ } else {
1786
1801
  return { ok: false, error: { code: "FORBIDDEN", message: "App caller is not allowed", status: 403 } };
1787
- invoked = await definition.run(input.data, context);
1802
+ }
1788
1803
  } else {
1789
1804
  if (operation.definition.appOnly) return { ok: false, error: { code: "FORBIDDEN", message: "App authority required", status: 403 } };
1790
1805
  invoked = await operation.definition.run(input.data, context);
@@ -13,6 +13,7 @@ import { registerPageSwap } from "../ssr/page-swap";
13
13
  import { preloadPanelConsent } from "../ssr/panel-consent";
14
14
  import { appAccessManagementPath } from "./app-access-path";
15
15
  import { bindResourceAppAccess, RESOURCE_ACCESS_PATH } from "./app-access-resources";
16
+ import { createAppCapabilityRoutes } from "./app-capabilities";
16
17
  import { createAppQueryRoutes } from "./app-queries";
17
18
  import { registerApplicationPackage, resolveApplicationPackage } from "./application-package";
18
19
  import { invokeCapabilityStream } from "./capability-streams";
@@ -956,6 +957,7 @@ export const defineApp = <
956
957
 
957
958
  if (compiledCapabilities) {
958
959
  server.route("/api/_internal/capabilities/v1/app-queries", createAppQueryRoutes(compiledCapabilities));
960
+ server.route("/api/_internal/capabilities/v1/app-capabilities", createAppCapabilityRoutes(compiledCapabilities));
959
961
  const invoke = async (c: Context<AuthContext>, kind: "query" | "action" | "review") =>
960
962
  withCapabilityRequestTimeout(c, kind, async () => {
961
963
  // Framework-owned endpoints run before the app's settings middleware,
@@ -1,8 +1,9 @@
1
- import { type SQL, sql, type TransactionSQL } from "bun";
1
+ import type { SQL, TransactionSQL } from "bun";
2
2
  import { z } from "zod";
3
3
  import { appAudienceRoles } from "../_internal/app-roles";
4
4
  import { APP_REGISTRY_TTL_MS } from "../_internal/registry";
5
5
  import type { AppRegistryEntry } from "../contracts/registry";
6
+ import { sql } from "../runtime/clients";
6
7
  import { logger } from "../services/logging";
7
8
  import { toPgTextArray } from "../services/postgres";
8
9
  import { type AppSkillDefinition, parseStoredAppSkill } from "./app-skills";
@@ -1,5 +1,6 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
2
  import { z } from "zod";
3
+ import { sql } from "../runtime/clients";
3
4
  import { logger } from "../services/logging";
4
5
  import { AI_SKILL_CATALOG_MAX_CHARS, aiSkillCatalogChars } from "./skill-catalog";
5
6
  import { type AiSkillContent, canonicalHash, contentHash, validateSkillContent } from "./skill-content";
@@ -1,5 +1,6 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
2
  import type { AccessSubject } from "../contracts/shared";
3
+ import { sql } from "../runtime/clients";
3
4
  import type { RequestActor } from "../server/middleware/auth";
4
5
  import { type AuditActor, type AuditRecordParams, audit } from "../services/audit";
5
6
  import { toPgTextArray } from "../services/postgres";
@@ -1,7 +1,8 @@
1
1
  import type { Message } from "@k2b/nessi";
2
- import { type SQL, sql } from "bun";
2
+ import type { SQL } from "bun";
3
3
  import { getCapability } from "../_internal/registry";
4
4
  import { type CapabilityActionPolicy, capabilityActionPolicy } from "../contracts/capabilities";
5
+ import { sql } from "../runtime/clients";
5
6
  import { logger } from "../services/logging";
6
7
  import {
7
8
  createMandate,
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { decryptValue, encryptValue } from "../services/settings/crypto";
3
4
 
4
5
  type SqlClient = typeof sql;
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { lazySync } from "../_internal/process-sync";
2
+ import { sql } from "../runtime/clients";
3
3
  import { get as getUser } from "../services/accounts/users";
4
4
  import { logger, trace } from "../services/logging";
5
5
  import { superviseRuntimeTask } from "../services/runtime-lifecycle";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
2
+ import { sql } from "../runtime/clients";
3
3
  import { inspectAiAudio } from "./audio-format";
4
4
  import { createUniqueAiFileInTransaction } from "./files-store";
5
5
  import { AiSaveConversationDraftInputSchema } from "./http";
@@ -1,4 +1,5 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
+ import { sql } from "../runtime/clients";
2
3
  import { stripImageMetadata } from "../services/image-metadata";
3
4
  import { AiFileVersionConflict, AiFileWriteError, aiFileContentVersion } from "./file-content-version";
4
5
  import { isAiImage } from "./file-media-type";
@@ -1,4 +1,5 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
+ import { sql } from "../runtime/clients";
2
3
  import type { AccessSubject } from "../server/services/access";
3
4
  import { aiBudgetUnits, aiCostDecimal, aiCostUnits, aiDecimalUnits, hasBillableAiPricing } from "../shared/ai-costs";
4
5
  import { AiQuotaError, aiQuotas, quotaWindow } from "./quotas";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
2
+ import { sql } from "../runtime/clients";
3
3
  import { toPgTextArray } from "../services/postgres";
4
4
  import type { AiMap, AiMapCommand } from "./map-contracts";
5
5
  import { AiMapSchema, aiMapToolResult } from "./map-contracts";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import type { CapabilityCaller } from "../capabilities/server";
2
+ import { sql } from "../runtime/clients";
3
3
  import { resolveAiCapabilityActor } from "./capability-execution";
4
4
  import { AiMapToolInputSchema, AiMapToolResultSchema, aiMapToolResult } from "./map-contracts";
5
5
  import { executeStoredAiMap } from "./map-execution";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { type CloudResourceRef, CloudResourceRefSchema } from "../contracts/capabilities";
2
+ import { sql } from "../runtime/clients";
3
3
  import { logger } from "../services/logging";
4
4
  import { withAiShortId } from "./short-id";
5
5
 
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import type { CloudResourceRef } from "../contracts/capabilities";
2
+ import { sql } from "../runtime/clients";
3
3
  import type { AiMemoryKind } from "./memories";
4
4
  import { withAiShortId } from "./short-id";
5
5
 
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
- import { sql } from "bun";
3
2
  import { z } from "zod";
4
3
  import { CloudResourceRefSchema } from "../contracts/capabilities";
4
+ import { sql } from "../runtime/clients";
5
5
  import { coreSettings } from "../services";
6
6
  import { logger } from "../services/logging";
7
7
  import { normalizeLocale } from "../shared/locale";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { type CloudResourceRef, CloudResourceRefSchema } from "../contracts/capabilities";
2
+ import { sql } from "../runtime/clients";
3
3
  import { AI_MEMORY_LEARNING_DEFAULT_ENABLED } from "./prefs";
4
4
 
5
5
  const MAX_RECEIPT_RESOURCES = 20;
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { logger } from "../services/logging";
3
4
  import { aiChatAccessSubject, isAssistantChatTurn } from "./assistant-models";
4
5
  import { editAiDraftText } from "./draft-content";
package/src/ai/migrate.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { CapabilityActionReviewDataSchema } from "../contracts/capabilities";
2
+ import { sql } from "../runtime/clients";
3
3
  import { APPROVAL_MAX_WAIT_MS, approvalAssurance, approvalScopeFromToolName, approvals, migrateApprovals } from "../services/approvals";
4
4
  import { migrateChatTaskReasons } from "./chat-task-reasons-migrate";
5
5
  import { migrateAiMaps } from "./map-store";
@@ -1,4 +1,4 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
2
 
3
3
  export const migrateAiModelAccess = async (): Promise<void> => {
4
4
  await sql.begin(async (tx) => {
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import type { AccessEntry, Principal, ServiceAccountKind } from "../contracts/shared";
2
+ import { sql } from "../runtime/clients";
3
3
  import { type AccessSubject, buildAccessPrincipalCondition, createAccess } from "../server/services/access";
4
4
  import { toPgTextArray } from "../services/postgres";
5
5
  import type { AiModelAccessDraft } from "../shared/ai-models";
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
2
+ import { sql } from "../runtime/clients";
3
3
  import { ConfigConflict } from "../services/config-conflict";
4
4
  import { stripImageDataUrlMetadata } from "../services/image-metadata";
5
5
  import {
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
2
+ import { sql } from "../runtime/clients";
3
3
  import { recursiveGroupIdsSubquery } from "../services/accounts/group-sql";
4
4
  import { toPgTextArray } from "../services/postgres";
5
5
  import { type AiDeleteModelInput, type AiModel, type AiModelSlot, type AiProvider, aiReplacementProblem } from "../shared/ai-models";
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { toPgTextArray } from "../services/postgres";
3
4
  import type { AiModelUsage } from "../shared/ai-models";
4
5
  import { aiModelCatalog } from "./model-catalog";
@@ -1,7 +1,7 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
3
2
  import { APPROVALS_PAGE_SIZE } from "../contracts/approvals";
4
3
  import { CapabilityActionReviewPresentationSchema, CapabilitySemanticLinkSchema } from "../contracts/capabilities";
4
+ import { sql } from "../runtime/clients";
5
5
  import { openRequests } from "../services/approvals/content";
6
6
  import { logger } from "../services/logging";
7
7
  import { reviewShortText, toolActionCard, toolBlockReview } from "./chat/action-card";
@@ -1,4 +1,5 @@
1
- import { redis } from "bun";
1
+ import { redis } from "../runtime/clients";
2
+
2
3
  import type { AccessSubject } from "../server/services/access";
3
4
  import { logger } from "../services/logging";
4
5
 
package/src/ai/prefs.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import type { RequestActor } from "../server";
3
4
  import { type AiModelRequest, AiModelRequestSchema } from "../shared/ai-models";
4
5
 
@@ -1,6 +1,7 @@
1
- import { type SQL, type SQLQuery, sql } from "bun";
1
+ import type { SQL, SQLQuery } from "bun";
2
2
  import type { CloudResourceRef } from "../contracts/capabilities";
3
3
  import { AuthenticatedPrincipalSchema, type ServiceAccountKind } from "../contracts/shared";
4
+ import { sql } from "../runtime/clients";
4
5
  import {
5
6
  buildAccessPrincipalCondition,
6
7
  createAccess,
@@ -1,5 +1,5 @@
1
- import { sql } from "bun";
2
1
  import { z } from "zod";
2
+ import { sql } from "../runtime/clients";
3
3
  import type { AiProvider } from "../shared/ai-models";
4
4
  import { getAiCredential } from "./credentials";
5
5
  import { getAiRequestHeaders } from "./request-headers";
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { recursiveGroupIdsSubquery } from "../services/accounts/group-sql";
3
4
  import { toPgTextArray } from "../services/postgres";
4
5
  import { hasBillableAiPricing } from "../shared/ai-costs";
@@ -1,6 +1,7 @@
1
1
  import { setTimeout as delay } from "node:timers/promises";
2
2
  import { estimateTokens, type Provider } from "@k2b/nessi";
3
- import { sql } from "bun";
3
+ import { sql } from "../runtime/clients";
4
+
4
5
  import type { AccessSubject } from "../server/services/access";
5
6
  import { logger } from "../services/logging";
6
7
  import type { AiResolvedModelRef } from "../shared/ai-models";
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { resolveDisplayNames } from "../server/services/access";
3
4
  import { recursiveGroupIdsSubquery } from "../services/accounts/group-sql";
4
5
  import { toPgTextArray } from "../services/postgres";
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  export async function migrateAiQuotas() {
3
4
  await sql.begin(async (db) => {
4
5
  await db`CREATE TABLE IF NOT EXISTS ai.cost_config (
package/src/ai/quotas.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
+ import { sql } from "../runtime/clients";
2
3
  import { type AccessSubject, buildAccessPrincipalCondition } from "../server/services/access";
3
4
  import { hasBillableAiPricing } from "../shared/ai-costs";
4
5
  import { type AiQuotaConfig, AiQuotaConfigSchema, type AiQuotaIdentity, type AiQuotaSnapshot } from "../shared/ai-quotas";
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { decryptValue, encryptValue } from "../services/settings/crypto";
3
4
  import { AiRequestHeadersSchema, patchAiRequestHeaders } from "../shared/ai-request-options";
4
5
 
@@ -1,7 +1,8 @@
1
- import { type SQL, sql } from "bun";
1
+ import type { SQL } from "bun";
2
2
  import { capabilityRequestHash } from "../capabilities/claims";
3
3
  import { parseStoredReviewContent } from "../capabilities/review-storage";
4
4
  import { CAPABILITY_MAX_REVIEW_CONTENT_BYTES, type CapabilityActionReviewPresentation } from "../contracts/capabilities";
5
+ import { sql } from "../runtime/clients";
5
6
  import type { AiStoredActionReview } from "./action-review";
6
7
 
7
8
  export type ReviewContentLocation = { conversationId: string; turnId: string; callId: string };
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { toPgTextArray } from "../services/postgres";
3
4
 
4
5
  const BM25_INDEX = "ai.skills_search_bm25_idx";
package/src/ai/skills.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { type SQL, type SQLQuery, sql } from "bun";
1
+ import type { SQL, SQLQuery } from "bun";
2
2
  import { listApps } from "../_internal/registry";
3
3
  import { AuthenticatedPrincipalSchema, type ServiceAccountKind } from "../contracts/shared";
4
+ import { sql } from "../runtime/clients";
4
5
  import type { RequestAuthority } from "../server/middleware/auth";
5
6
  import {
6
7
  buildAccessPrincipalCondition,
package/src/ai/store.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import type { DoneReason, InboundEvent, LoopAggregate, Message, SessionStore, StoreEntry } from "@k2b/nessi";
2
2
  import type { Usage } from "@k2b/nessi/ai";
3
- import { type SQL, sql } from "bun";
3
+ import type { SQL } from "bun";
4
4
  import { capabilityRequestHash } from "../capabilities/claims";
5
5
  import { restoreReviewSnapshot, serializeReviewSnapshot } from "../capabilities/review-storage";
6
6
  import { type CapabilityActionReviewPresentation, CapabilityActionReviewPresentationSchema } from "../contracts/capabilities";
7
+ import { sql } from "../runtime/clients";
7
8
  import { logger } from "../services/logging";
8
9
  import { toPgTextArray } from "../services/postgres";
9
10
  import { AI_TOOL_CHECK_STALE_MS, type AiActionCheck, type AiStoredActionReview } from "./action-review";
@@ -1,5 +1,6 @@
1
1
  import type { Usage } from "@k2b/nessi";
2
- import { sql } from "bun";
2
+ import { sql } from "../runtime/clients";
3
+
3
4
  import { logger } from "../services/logging";
4
5
 
5
6
  export type AiUsageAttribution = {
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import type { ApprovalDecisionChannel } from "../services/approvals";
3
4
 
4
5
  /**
@@ -1,5 +1,5 @@
1
1
  import type { LoopAggregate, OutboundEvent } from "@k2b/nessi";
2
- import { sql } from "bun";
2
+ import { sql } from "../runtime/clients";
3
3
 
4
4
  export type TimingInterval = { start: number; end: number };
5
5
  const union = (intervals: TimingInterval[]): TimingInterval[] => {
package/src/ai/usage.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { sql } from "bun";
1
+ import { sql } from "../runtime/clients";
2
+
2
3
  import { type AiUsageQuery, AiUsageQuerySchema } from "../shared/ai-usage";
3
4
  import { aiQuotas } from "./quotas";
4
5
 
@@ -1,5 +1,6 @@
1
1
  import { domainToUnicode } from "node:url";
2
- import { sql } from "bun";
2
+ import { sql } from "../runtime/clients";
3
+
3
4
  import { toPgTextArray } from "../services/postgres";
4
5
 
5
6
  /** The longest address web_extract and fetch_file accept; a longer one can never be read, so it is never recorded. */
@@ -1,9 +1,9 @@
1
- import { sql } from "bun";
2
1
  import { Hono, type MiddlewareHandler } from "hono";
3
2
  import { AiBackgroundCostError, backgroundCostState, releaseBackgroundCostStop } from "../ai/inference-calls";
4
3
  import { quotaAdminConfig, quotaReport } from "../ai/quota-report";
5
4
  import { AiQuotaError, aiQuotas } from "../ai/quotas";
6
5
  import { readAiSettingsState } from "../ai/settings";
6
+ import { sql } from "../runtime/clients";
7
7
  import { type AuthContext, auth, v } from "../server";
8
8
  import { hasBillableAiPricing } from "../shared/ai-costs";
9
9
  import {