@agent-native/core 0.201.1-nightly-20261005213104 → 0.201.1

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 (54) hide show
  1. package/dist/a2a/handlers.js +96 -44
  2. package/dist/a2a/organization-identity.d.ts +9 -0
  3. package/dist/a2a/organization-identity.js +34 -0
  4. package/dist/a2a/server.d.ts +13 -7
  5. package/dist/a2a/server.js +187 -88
  6. package/dist/a2a/task-store.d.ts +7 -2
  7. package/dist/a2a/task-store.js +23 -8
  8. package/dist/a2a-claims.js +12 -2
  9. package/dist/app-config/mcp.d.ts +4 -0
  10. package/dist/app-config/mcp.js +7 -0
  11. package/dist/app-config/schema.d.ts +3 -0
  12. package/dist/app-config/schema.js +2 -0
  13. package/dist/automation/index.d.ts +1 -1
  14. package/dist/client/route-chunk-recovery.js +75 -11
  15. package/dist/client/route-warmup.d.ts +2 -0
  16. package/dist/client/route-warmup.js +3 -0
  17. package/dist/client/vite-dev-recovery-script.js +85 -17
  18. package/dist/collab/awareness.d.ts +2 -2
  19. package/dist/collab/struct-routes.d.ts +1 -1
  20. package/dist/deploy/build.js +3 -1
  21. package/dist/feature-flags/a2a-action-route.js +3 -4
  22. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  23. package/dist/mcp/build-server.d.ts +4 -0
  24. package/dist/mcp/build-server.js +133 -39
  25. package/dist/mcp/server.js +21 -8
  26. package/dist/notifications/routes.d.ts +3 -3
  27. package/dist/observability/routes.d.ts +9 -9
  28. package/dist/onboarding/app-profile.js +2 -1
  29. package/dist/onboarding/workspace-services.js +3 -0
  30. package/dist/org/context.d.ts +13 -0
  31. package/dist/org/context.js +60 -0
  32. package/dist/org/index.d.ts +1 -1
  33. package/dist/org/membership.d.ts +6 -0
  34. package/dist/org/membership.js +23 -5
  35. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  36. package/dist/provider-api/actions/provider-api.d.ts +6 -6
  37. package/dist/resources/handlers.d.ts +1 -1
  38. package/dist/secrets/routes.d.ts +11 -11
  39. package/dist/server/action-routes.js +12 -5
  40. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  41. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  42. package/dist/server/builder-browser.d.ts +4 -2
  43. package/dist/server/builder-browser.js +147 -9
  44. package/dist/server/core-routes-plugin.js +13 -6
  45. package/dist/server/entry-server.js +43 -2
  46. package/dist/server/sentry.js +9 -1
  47. package/dist/server/ssr-handler.d.ts +1 -1
  48. package/dist/server/ssr-handler.js +3 -7
  49. package/dist/shared/cache-control.d.ts +4 -1
  50. package/dist/shared/cache-control.js +11 -6
  51. package/dist/shared/route-chunk-recovery-bootstrap.d.ts +7 -0
  52. package/dist/shared/route-chunk-recovery-bootstrap.js +38 -0
  53. package/dist/triggers/actions/manage-automation.d.ts +5 -5
  54. package/package.json +6 -4
@@ -1,4 +1,5 @@
1
1
  import "../authorization/check-action.js";
2
+ import { verifyA2AOrganizationIdentity } from "../a2a/organization-identity.js";
2
3
  import { actionCallEmitsChange, actionChangeResource, } from "../action-call-classification.js";
3
4
  import { MCP_APP_EXTENSION_ID, MCP_APP_MIME_TYPE, MCP_APP_RESOURCE_URI_META_KEY, } from "../action.js";
4
5
  import { isActionContractError, isActionExposedToExternalAgents, } from "../action.js";
@@ -7,6 +8,7 @@ import { getAppConfig } from "../app-config/store.js";
7
8
  import { isMcpActionResult } from "../mcp-client/app-result.js";
8
9
  import { writeActionChangeMarker } from "../server/action-change-marker-write.js";
9
10
  import { getConfiguredAppBasePath } from "../server/app-base-path.js";
11
+ import { readDeployCredentialEnv } from "../server/credential-provider.js";
10
12
  import { buildDeepLink, isAgentNativeOpenUrl, isSameOriginUrl, toAbsoluteOpenUrl, toDesktopOpenUrl, toVsCodeOpenUrl, } from "../server/deep-link.js";
11
13
  import { getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
12
14
  import { agentNativeMcpInstructions, agentNativeToolTitle, } from "../shared/agent-mcp-metadata.js";
@@ -1940,11 +1942,13 @@ export function getBearerToken(authHeader) {
1940
1942
  const match = /^Bearer\s+(.+)$/i.exec(authHeader.trim());
1941
1943
  return match?.[1]?.trim() || undefined;
1942
1944
  }
1943
- function addSecretCandidate(candidates, secret) {
1944
- const trimmed = secret?.trim();
1945
- if (!trimmed || candidates.includes(trimmed))
1946
- return;
1947
- candidates.push(trimmed);
1945
+ export class McpIdentityVerificationUnavailableError extends Error {
1946
+ cause;
1947
+ constructor(cause) {
1948
+ super("MCP identity verification is temporarily unavailable");
1949
+ this.name = "McpIdentityVerificationUnavailableError";
1950
+ this.cause = cause;
1951
+ }
1948
1952
  }
1949
1953
  async function verifyA2AJwtForMcp(token, resourceUrl) {
1950
1954
  const jose = await import("jose");
@@ -1955,37 +1959,96 @@ async function verifyA2AJwtForMcp(token, resourceUrl) {
1955
1959
  catch {
1956
1960
  return null;
1957
1961
  }
1958
- const candidateSecrets = [];
1959
- addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);
1960
1962
  const orgDomain = typeof unverifiedPayload.org_domain === "string"
1961
- ? unverifiedPayload.org_domain
1963
+ ? unverifiedPayload.org_domain.trim().toLowerCase()
1962
1964
  : undefined;
1963
- if (orgDomain) {
1964
- try {
1965
- const { getA2ASecretByDomain } = await import("../org/context.js");
1966
- addSecretCandidate(candidateSecrets, await getA2ASecretByDomain(orgDomain));
1967
- }
1968
- catch {
1969
- // DB not ready or org lookup unavailable — fall back to other candidates.
1970
- }
1971
- }
1972
1965
  const firstPartyMcp = unverifiedPayload.agent_native_first_party_mcp === true;
1973
1966
  const audiences = firstPartyMcp ? mcpAudienceList(resourceUrl) : null;
1974
1967
  if (firstPartyMcp && !audiences?.length)
1975
1968
  return null;
1976
- for (const secret of candidateSecrets) {
1977
- const encodedSecret = new TextEncoder().encode(secret);
1969
+ const verifyWithSecret = async (secret) => {
1978
1970
  for (const audience of audiences ?? [undefined]) {
1979
1971
  try {
1980
- const { payload } = await jose.jwtVerify(token, encodedSecret, audience ? { audience } : undefined);
1972
+ const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(secret), audience ? { audience } : undefined);
1981
1973
  return payload;
1982
1974
  }
1983
1975
  catch {
1984
- // Try the next candidate without exposing which secret matched.
1976
+ // coercion-ok: bad signature or audience rejects this candidate; credential lookup failures throw separately.
1977
+ }
1978
+ }
1979
+ return null;
1980
+ };
1981
+ const globalSecret = readDeployCredentialEnv("A2A_SECRET")?.trim();
1982
+ if (globalSecret) {
1983
+ const payload = await verifyWithSecret(globalSecret);
1984
+ if (payload) {
1985
+ const tokenScope = typeof payload.scope === "string" ? payload.scope : undefined;
1986
+ const firstPartyMcp = payload.agent_native_first_party_mcp === true;
1987
+ const hasOrganizationClaim = Object.prototype.hasOwnProperty.call(payload, "org_id") &&
1988
+ payload.org_id !== null;
1989
+ const locallyIssuedConnectToken = tokenScope === MCP_CONNECT_SCOPE && !firstPartyMcp;
1990
+ const unclaimedFirstPartyToken = firstPartyMcp && !hasOrganizationClaim;
1991
+ if (locallyIssuedConnectToken || unclaimedFirstPartyToken) {
1992
+ return payload;
1993
+ }
1994
+ let verifiedOrganization;
1995
+ try {
1996
+ verifiedOrganization = await verifyA2AOrganizationIdentity(payload);
1985
1997
  }
1998
+ catch (error) {
1999
+ throw new McpIdentityVerificationUnavailableError(error);
2000
+ }
2001
+ if (verifiedOrganization === null)
2002
+ return null;
2003
+ return verifiedOrganization
2004
+ ? {
2005
+ ...payload,
2006
+ org_id: verifiedOrganization.orgId,
2007
+ org_domain: verifiedOrganization.orgDomain,
2008
+ }
2009
+ : payload;
1986
2010
  }
1987
2011
  }
1988
- return null;
2012
+ if (!orgDomain)
2013
+ return null;
2014
+ let organization;
2015
+ try {
2016
+ const { resolveA2AOrganizationCredentialsByDomain } = await import("../org/context.js");
2017
+ organization = await resolveA2AOrganizationCredentialsByDomain(orgDomain);
2018
+ }
2019
+ catch (error) {
2020
+ throw new McpIdentityVerificationUnavailableError(error);
2021
+ }
2022
+ if (!organization)
2023
+ return null;
2024
+ const payload = await verifyWithSecret(organization.secret);
2025
+ if (!payload)
2026
+ return null;
2027
+ const verifiedDomain = typeof payload.org_domain === "string"
2028
+ ? payload.org_domain.trim().toLowerCase()
2029
+ : "";
2030
+ const email = typeof payload.sub === "string" ? payload.sub.trim() : "";
2031
+ const claimedOrgId = payload.org_id;
2032
+ if (!email ||
2033
+ verifiedDomain !== organization.orgDomain ||
2034
+ (typeof claimedOrgId !== "undefined" &&
2035
+ (typeof claimedOrgId !== "string" ||
2036
+ claimedOrgId.trim() !== organization.orgId))) {
2037
+ return null;
2038
+ }
2039
+ try {
2040
+ const { isOrgMemberForA2A } = await import("../org/membership.js");
2041
+ if (!(await isOrgMemberForA2A(organization.orgId, email)))
2042
+ return null;
2043
+ }
2044
+ catch (error) {
2045
+ throw new McpIdentityVerificationUnavailableError(error);
2046
+ }
2047
+ return {
2048
+ ...payload,
2049
+ org_id: organization.orgId,
2050
+ org_domain: organization.orgDomain,
2051
+ };
1989
2052
  }
1990
2053
  function mcpAudienceList(resource) {
1991
2054
  const raw = Array.isArray(resource) ? resource : resource ? [resource] : [];
@@ -2058,13 +2121,24 @@ function orgIdFromConnectTokenResolution(resolution) {
2058
2121
  if (resolution.status === "claimed" || resolution.status === "found") {
2059
2122
  return resolution.orgId;
2060
2123
  }
2061
- // A connect token with no row here was not issued for any org this app
2062
- // knows. Its `org_domain` claim must not grant that domain's org, so it
2063
- // runs Personal.
2124
+ // A first-party cross-app token with no row here was not issued for any org
2125
+ // this app knows. Its `org_domain` claim must not grant that domain's org.
2064
2126
  if (resolution.status === "missing")
2065
2127
  return null;
2066
2128
  return undefined;
2067
2129
  }
2130
+ function matchesStoredConnectTokenIdentity(resolution, input) {
2131
+ const stored = resolution.status === "found"
2132
+ ? resolution
2133
+ : resolution.status === "claimed"
2134
+ ? resolution.storedConnectToken
2135
+ : undefined;
2136
+ if (!stored || !input.ownerEmail?.trim())
2137
+ return false;
2138
+ return (stored.ownerEmail.trim().toLowerCase() ===
2139
+ input.ownerEmail.trim().toLowerCase() &&
2140
+ (input.orgId === undefined || stored.orgId === input.orgId));
2141
+ }
2068
2142
  /**
2069
2143
  * Credentials this app issues (MCP OAuth access tokens and connect tokens)
2070
2144
  * carry the organization chosen when they were issued: the signed `org_id`
@@ -2076,9 +2150,10 @@ function orgIdFromConnectTokenResolution(resolution) {
2076
2150
  * They also carry the subject's address, which an email change retires; a
2077
2151
  * credential signed for it before the change is refused, Personal or not.
2078
2152
  *
2079
- * Cross-app A2A JWTs, first-party MCP tokens included, are not checked: their
2080
- * `org_id`, like `org_domain`, is the signing app's assertion, and the caller
2081
- * may have no membership row in this app's database.
2153
+ * Shared-secret A2A org claims must resolve against local metadata before they
2154
+ * become request scope. A sibling app's user roster is not this app's roster;
2155
+ * locally issued connect credentials instead use their stored JTI owner and
2156
+ * organization.
2082
2157
  */
2083
2158
  async function admitIssuedCredential(result, requestOrigin, orgResolution, issuedAt) {
2084
2159
  const { checkCredentialEmailRetirement, checkCredentialOrgMembership } = await import("./credential-membership.js");
@@ -2139,7 +2214,7 @@ async function admitIssuedCredential(result, requestOrigin, orgResolution, issue
2139
2214
  */
2140
2215
  export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
2141
2216
  const accessTokens = getAccessTokens();
2142
- const hasA2ASecret = !!process.env.A2A_SECRET?.trim();
2217
+ const hasA2ASecret = !!readDeployCredentialEnv("A2A_SECRET")?.trim();
2143
2218
  const token = getBearerToken(authHeader);
2144
2219
  if (token) {
2145
2220
  const oauthIdentity = await verifyMcpOAuthAccessToken(token, options.resourceUrl);
@@ -2155,6 +2230,13 @@ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
2155
2230
  if (orgResolution.status === "unavailable") {
2156
2231
  return { authed: false, unavailable: true };
2157
2232
  }
2233
+ if (oauthIdentity.clientId === MCP_CONNECT_OAUTH_CLIENT_ID &&
2234
+ !matchesStoredConnectTokenIdentity(orgResolution, {
2235
+ ownerEmail: oauthIdentity.userEmail,
2236
+ orgId: oauthIdentity.orgId,
2237
+ })) {
2238
+ return { authed: false };
2239
+ }
2158
2240
  const orgId = orgIdFromConnectTokenResolution(orgResolution);
2159
2241
  const admitted = await admitIssuedCredential({
2160
2242
  authed: true,
@@ -2187,7 +2269,16 @@ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
2187
2269
  }
2188
2270
  if (!token)
2189
2271
  return { authed: false };
2190
- const payload = await verifyA2AJwtForMcp(token, options.resourceUrl);
2272
+ let payload;
2273
+ try {
2274
+ payload = await verifyA2AJwtForMcp(token, options.resourceUrl);
2275
+ }
2276
+ catch (error) {
2277
+ if (error instanceof McpIdentityVerificationUnavailableError) {
2278
+ return { authed: false, unavailable: true };
2279
+ }
2280
+ throw error;
2281
+ }
2191
2282
  if (payload) {
2192
2283
  const tokenScope = typeof payload.scope === "string" ? payload.scope : undefined;
2193
2284
  if (tokenScope && tokenScope !== MCP_CONNECT_SCOPE) {
@@ -2213,6 +2304,14 @@ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
2213
2304
  if (orgResolution.status === "unavailable") {
2214
2305
  return { authed: false, unavailable: true };
2215
2306
  }
2307
+ if (tokenScope === MCP_CONNECT_SCOPE && !firstPartyMcp) {
2308
+ if (!matchesStoredConnectTokenIdentity(orgResolution, {
2309
+ ownerEmail: typeof payload.sub === "string" ? payload.sub : undefined,
2310
+ orgId: orgIdClaim.orgId,
2311
+ })) {
2312
+ return { authed: false };
2313
+ }
2314
+ }
2216
2315
  const orgId = orgIdFromConnectTokenResolution(orgResolution);
2217
2316
  const verified = {
2218
2317
  authed: true,
@@ -2237,15 +2336,10 @@ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
2237
2336
  }
2238
2337
  return admitted;
2239
2338
  }
2240
- if (accessTokens.length === 0 && !hasA2ASecret) {
2241
- if (options.allowDevOpen === false) {
2242
- return { authed: false };
2243
- }
2244
- return {
2245
- authed: true,
2246
- identity: deriveStaticTokenIdentity(ownerEmailHeader),
2247
- fullSurface: !!(ownerEmailHeader && ownerEmailHeader.trim()),
2248
- };
2339
+ if (accessTokens.length === 0) {
2340
+ // A supplied bearer that failed JWT verification must not fall through to
2341
+ // dev-open auth or reuse a forwarded owner-email hint.
2342
+ return { authed: false };
2249
2343
  }
2250
2344
  // Try ACCESS_TOKEN / ACCESS_TOKENS exact match. Static tokens carry no
2251
2345
  // per-caller claims, so derive identity from the forwarded owner-email
@@ -7,7 +7,7 @@ import { getH3App } from "../server/framework-request-handler.js";
7
7
  import { getOrigin } from "../server/google-oauth.js";
8
8
  import { readBody } from "../server/h3-helpers.js";
9
9
  import { trackMcpInitialize } from "./analytics.js";
10
- import { createMCPServerForRequest, verifyAuth, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, McpDirectoryProfileValidationError, validateMcpDirectoryProfile, validateMcpDirectoryWidgetDomain, selectMcpActionSurface, } from "./build-server.js";
10
+ import { createMCPServerForRequest, verifyAuth, McpIdentityVerificationUnavailableError, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, McpDirectoryProfileValidationError, validateMcpDirectoryProfile, validateMcpDirectoryWidgetDomain, selectMcpActionSurface, } from "./build-server.js";
11
11
  import { buildMcpOAuthChallenge, getMcpOAuthAudiences, getMcpOAuthIssuer, getMcpOAuthProtectedResourceMetadataUrl, getMcpOAuthResource, } from "./oauth-route.js";
12
12
  import { MCP_DIRECTORY_ROUTE_PREFIX, MCP_PUBLIC_ROUTE_PREFIX, MCP_ROUTE_PREFIXES, joinMcpRoute, } from "./route-paths.js";
13
13
  export { createMCPServerForRequest, verifyAuth, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, };
@@ -228,13 +228,26 @@ async function handleMcpRequestInternal(event, config, routePath = MCP_PUBLIC_RO
228
228
  widgetDomain: requestMeta.origin,
229
229
  }
230
230
  : config;
231
- const authResult = await verifyAuth(authHeader, ownerEmailHeader, {
232
- allowDevOpen: isLoopbackRequest(event) &&
233
- isLoopbackOrigin(requestMeta.origin) &&
234
- (hasLocalOwnerHint || process.env.AGENT_NATIVE_MCP_DEV_OPEN === "1"),
235
- resourceUrl: getMcpOAuthAudiences(event, routePath),
236
- requestOrigin: getOrigin(event),
237
- });
231
+ let authResult;
232
+ try {
233
+ authResult = await verifyAuth(authHeader, ownerEmailHeader, {
234
+ allowDevOpen: isLoopbackRequest(event) &&
235
+ isLoopbackOrigin(requestMeta.origin) &&
236
+ (hasLocalOwnerHint || getAppConfig().mcp.allowDevOpen),
237
+ resourceUrl: getMcpOAuthAudiences(event, routePath),
238
+ requestOrigin: getOrigin(event),
239
+ });
240
+ }
241
+ catch (error) {
242
+ if (!(error instanceof McpIdentityVerificationUnavailableError))
243
+ throw error;
244
+ setResponseStatus(event, 503);
245
+ setResponseHeader(event, "Retry-After", "5");
246
+ return {
247
+ error: "Service Unavailable",
248
+ message: CREDENTIAL_MEMBERSHIP_UNAVAILABLE_MESSAGE,
249
+ };
250
+ }
238
251
  if (!authResult.authed && authResult.unavailable) {
239
252
  // The token is valid but its org membership could not be checked. No auth
240
253
  // challenge: re-authenticating would not help, and the client must keep
@@ -1,13 +1,13 @@
1
1
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
2
2
  count: number;
3
3
  updated?: undefined;
4
- error?: undefined;
5
4
  ok?: undefined;
5
+ error?: undefined;
6
6
  } | {
7
7
  count?: undefined;
8
8
  updated: number;
9
- error?: undefined;
10
9
  ok?: undefined;
10
+ error?: undefined;
11
11
  } | {
12
12
  count?: undefined;
13
13
  updated?: undefined;
@@ -16,6 +16,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  } | {
17
17
  count?: undefined;
18
18
  updated?: undefined;
19
- error?: undefined;
20
19
  ok: boolean;
20
+ error?: undefined;
21
21
  }>>;
@@ -27,38 +27,38 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
27
27
  thumbsUpRate: number;
28
28
  avgEvalScore: number;
29
29
  } | {
30
- id?: undefined;
31
- ok?: undefined;
32
30
  error: string;
33
31
  message: string;
34
32
  summary?: undefined;
35
33
  spans?: undefined;
36
- } | {
37
34
  id?: undefined;
38
- error?: undefined;
39
35
  ok?: undefined;
36
+ } | {
40
37
  message?: undefined;
41
38
  summary: import("./types.js").TraceSummary;
42
39
  spans: import("./types.js").TraceSpan[];
43
- } | {
40
+ id?: undefined;
44
41
  error?: undefined;
45
42
  ok?: undefined;
43
+ } | {
46
44
  message?: undefined;
47
45
  summary?: undefined;
48
46
  spans?: undefined;
49
47
  id: string;
50
- } | {
51
- id?: undefined;
48
+ error?: undefined;
52
49
  ok?: undefined;
50
+ } | {
53
51
  message?: undefined;
54
52
  summary?: undefined;
55
53
  spans?: undefined;
54
+ id?: undefined;
56
55
  error: any;
56
+ ok?: undefined;
57
57
  } | {
58
- id?: undefined;
59
- error?: undefined;
60
58
  message?: undefined;
61
59
  summary?: undefined;
62
60
  spans?: undefined;
61
+ id?: undefined;
62
+ error?: undefined;
63
63
  ok: boolean;
64
64
  }>>;
@@ -7,7 +7,8 @@ const SYSTEM_ONE_CAPABILITY = {
7
7
  suggested: true,
8
8
  builderIncluded: true,
9
9
  keySummary: "Jev decision model key",
10
- why: "Jev is an optional decision model that helps choose relevant tools and skills before the agent's first model request. Use Builder-managed access when available, or add a direct JEV_API_KEY.",
10
+ whyKey: "agentChat.onboarding.capability.systemOne.why",
11
+ why: "Jev is an optional decision model that helps choose relevant tools and skills before the agent's first model request.",
11
12
  };
12
13
  const PROFILES = {
13
14
  analytics: {
@@ -15,6 +15,7 @@ export const LLM_CAPABILITY = {
15
15
  keySummary: "Connect your own AI model",
16
16
  labelKey: "agentChat.settingsInfra.aiModel",
17
17
  keySummaryKey: "agentChat.onboarding.capability.llm.keySummary",
18
+ whyKey: "agentChat.onboarding.capability.llm.why",
18
19
  why: "The agent uses a language model to understand requests and produce answers.",
19
20
  };
20
21
  export const FILE_UPLOAD_STORAGE_CAPABILITY = {
@@ -26,6 +27,7 @@ export const FILE_UPLOAD_STORAGE_CAPABILITY = {
26
27
  keySummary: "File uploads and storage",
27
28
  labelKey: "agentChat.settingsShell.search.fileUploads",
28
29
  keySummaryKey: "agentChat.onboarding.capability.fileStorage.keySummary",
30
+ whyKey: "agentChat.onboarding.capability.fileStorage.why",
29
31
  why: "Uploaded images and files need durable object storage so the agent can reuse them throughout a thread.",
30
32
  };
31
33
  export const VOICE_INPUT_CAPABILITY = {
@@ -70,6 +72,7 @@ export const DESIGN_SYSTEM_INTELLIGENCE_CAPABILITY = {
70
72
  builderIncluded: true,
71
73
  keySummary: "Builder Design System Intelligence",
72
74
  labelKey: "agentChat.settingsInfra.designSystem",
75
+ whyKey: "agentChat.settingsInfra.whyDesignSystem",
73
76
  why: "Uses your brand and design-system guidance to keep generated work on brand.",
74
77
  };
75
78
  export const BACKGROUND_AGENTS_CAPABILITY = {
@@ -47,4 +47,17 @@ export declare function resolveOrgByDomain(domain: string): Promise<{
47
47
  orgId: string;
48
48
  orgName: string;
49
49
  } | null>;
50
+ export declare function resolveA2AOrganizationMetadataByDomain(domain: string): Promise<{
51
+ orgId: string;
52
+ orgDomain: string | null;
53
+ } | null>;
54
+ export declare function resolveA2AOrganizationMetadataById(orgId: string): Promise<{
55
+ orgId: string;
56
+ orgDomain: string | null;
57
+ } | null>;
58
+ export declare function resolveA2AOrganizationCredentialsByDomain(domain: string): Promise<{
59
+ orgId: string;
60
+ orgDomain: string;
61
+ secret: string;
62
+ } | null>;
50
63
  export declare function isSoleOrgDomain(domain: string): Promise<boolean>;
@@ -743,6 +743,66 @@ export async function resolveOrgByDomain(domain) {
743
743
  return null;
744
744
  }
745
745
  }
746
+ export async function resolveA2AOrganizationMetadataByDomain(domain) {
747
+ const normalizedDomain = domain.trim().toLowerCase();
748
+ if (!normalizedDomain)
749
+ return null;
750
+ const { rows } = await getDbExec().execute({
751
+ sql: `SELECT id, allowed_domain
752
+ FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 1`,
753
+ args: [normalizedDomain],
754
+ });
755
+ const row = rows[0];
756
+ if (!row)
757
+ return null;
758
+ const orgId = String(row.id ?? "").trim();
759
+ const orgDomain = String(row.allowed_domain ?? "")
760
+ .trim()
761
+ .toLowerCase();
762
+ if (!orgId || !orgDomain || orgDomain !== normalizedDomain)
763
+ return null;
764
+ return { orgId, orgDomain };
765
+ }
766
+ export async function resolveA2AOrganizationMetadataById(orgId) {
767
+ const normalizedOrgId = orgId.trim();
768
+ if (!normalizedOrgId)
769
+ return null;
770
+ const { rows } = await getDbExec().execute({
771
+ sql: `SELECT id, allowed_domain FROM organizations WHERE id = ? LIMIT 1`,
772
+ args: [normalizedOrgId],
773
+ });
774
+ const row = rows[0];
775
+ if (!row)
776
+ return null;
777
+ const resolvedOrgId = String(row.id ?? "").trim();
778
+ if (!resolvedOrgId || resolvedOrgId !== normalizedOrgId)
779
+ return null;
780
+ const rawDomain = String(row.allowed_domain ?? "")
781
+ .trim()
782
+ .toLowerCase();
783
+ return { orgId: resolvedOrgId, orgDomain: rawDomain || null };
784
+ }
785
+ export async function resolveA2AOrganizationCredentialsByDomain(domain) {
786
+ const normalizedDomain = domain.trim().toLowerCase();
787
+ if (!normalizedDomain)
788
+ return null;
789
+ const { rows } = await getDbExec().execute({
790
+ sql: `SELECT id, allowed_domain, a2a_secret
791
+ FROM organizations WHERE LOWER(allowed_domain) = ? LIMIT 1`,
792
+ args: [normalizedDomain],
793
+ });
794
+ const row = rows[0];
795
+ if (!row)
796
+ return null;
797
+ const orgId = String(row.id ?? "").trim();
798
+ const orgDomain = String(row.allowed_domain ?? "")
799
+ .trim()
800
+ .toLowerCase();
801
+ const secret = String(row.a2a_secret ?? "").trim();
802
+ if (!orgId || orgDomain !== normalizedDomain || !secret)
803
+ return null;
804
+ return { orgId, orgDomain, secret };
805
+ }
746
806
  export async function isSoleOrgDomain(domain) {
747
807
  try {
748
808
  const exec = getDbExec();
@@ -179,8 +179,8 @@ export declare const getMyOrgHandler: import("h3").EventHandlerWithFetch<import(
179
179
  export declare const createOrgHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
180
180
  name?: undefined;
181
181
  success: boolean;
182
- role?: undefined;
183
182
  id?: undefined;
183
+ role?: undefined;
184
184
  } | {
185
185
  success?: undefined;
186
186
  id: string;
@@ -2,3 +2,9 @@ export declare function isMissingOrganizationTableError(error: unknown): boolean
2
2
  export declare function isOrgMember(orgId: string, email: string, options?: {
3
3
  requireOrganizationMetadata?: boolean;
4
4
  }): Promise<boolean>;
5
+ /**
6
+ * Checks membership for an A2A identity authenticated by an organization
7
+ * secret. Unlike legacy callers, this requires readable organization metadata
8
+ * as well as the membership row before the token subject can become an owner.
9
+ */
10
+ export declare function isOrgMemberForA2A(orgId: string, email: string): Promise<boolean>;
@@ -17,7 +17,7 @@ export function isMissingOrganizationTableError(error) {
17
17
  }
18
18
  return false;
19
19
  }
20
- export async function isOrgMember(orgId, email, options = {}) {
20
+ async function isOrgMemberWithPolicy(orgId, email, options) {
21
21
  const normalized = email.trim().toLowerCase();
22
22
  if (!orgId || !normalized)
23
23
  return false;
@@ -41,13 +41,14 @@ export async function isOrgMember(orgId, email, options = {}) {
41
41
  })).rows;
42
42
  }
43
43
  catch (error) {
44
- if (options.requireOrganizationMetadata ||
45
- !isMissingOrganizationTableError(error))
44
+ if (!isMissingOrganizationTableError(error))
46
45
  throw error;
47
- return true;
46
+ if (options.allowMissingOrganizationTable)
47
+ return true;
48
+ throw error;
48
49
  }
49
50
  const organization = organizationRows[0];
50
- if (!organization && options.requireOrganizationMetadata)
51
+ if (!organization && options.requireOrganizationRecord)
51
52
  return false;
52
53
  const linked = String(organization?.identity_authority ?? "").trim() ||
53
54
  String(organization?.identity_id ?? "").trim();
@@ -67,3 +68,20 @@ export async function isOrgMember(orgId, email, options = {}) {
67
68
  });
68
69
  return validation.active;
69
70
  }
71
+ export function isOrgMember(orgId, email, options = {}) {
72
+ return isOrgMemberWithPolicy(orgId, email, {
73
+ allowMissingOrganizationTable: !options.requireOrganizationMetadata,
74
+ requireOrganizationRecord: !!options.requireOrganizationMetadata,
75
+ });
76
+ }
77
+ /**
78
+ * Checks membership for an A2A identity authenticated by an organization
79
+ * secret. Unlike legacy callers, this requires readable organization metadata
80
+ * as well as the membership row before the token subject can become an owner.
81
+ */
82
+ export function isOrgMemberForA2A(orgId, email) {
83
+ return isOrgMemberWithPolicy(orgId, email, {
84
+ allowMissingOrganizationTable: false,
85
+ requireOrganizationRecord: true,
86
+ });
87
+ }
@@ -75,9 +75,10 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
75
75
  user: "user";
76
76
  }>>;
77
77
  }, z.core.$strip>>, {
78
+ message?: undefined;
78
79
  id?: undefined;
79
- deleted?: undefined;
80
80
  provider?: undefined;
81
+ deleted?: undefined;
81
82
  providers: {
82
83
  id: string;
83
84
  label: string;
@@ -91,8 +92,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
91
92
  found?: undefined;
92
93
  registered?: undefined;
93
94
  label?: undefined;
94
- message?: undefined;
95
95
  } | {
96
+ message?: undefined;
96
97
  id?: undefined;
97
98
  deleted?: undefined;
98
99
  providers?: undefined;
@@ -101,18 +102,18 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
101
102
  provider: import("../custom-registry.js").CustomProviderConfig;
102
103
  registered?: undefined;
103
104
  label?: undefined;
104
- message?: undefined;
105
105
  } | {
106
- deleted?: undefined;
106
+ message?: undefined;
107
107
  provider?: undefined;
108
+ deleted?: undefined;
108
109
  providers?: undefined;
109
110
  count?: undefined;
110
111
  found: boolean;
111
112
  id: string;
112
113
  registered?: undefined;
113
114
  label?: undefined;
114
- message?: undefined;
115
115
  } | {
116
+ message?: undefined;
116
117
  provider?: undefined;
117
118
  providers?: undefined;
118
119
  count?: undefined;
@@ -121,10 +122,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
121
122
  id: string;
122
123
  registered?: undefined;
123
124
  label?: undefined;
124
- message?: undefined;
125
125
  } | {
126
- deleted?: undefined;
127
126
  provider?: undefined;
127
+ deleted?: undefined;
128
128
  providers?: undefined;
129
129
  count?: undefined;
130
130
  found?: undefined;