@agent-native/core 0.212.0 → 0.213.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 (90) hide show
  1. package/dist/a2a/anthropic-managed-agents.js +1 -0
  2. package/dist/a2a/caller-auth.js +7 -2
  3. package/dist/a2a/client.d.ts +1 -0
  4. package/dist/a2a/client.js +27 -0
  5. package/dist/a2a/handlers.js +15 -3
  6. package/dist/a2a/organization-identity.d.ts +4 -1
  7. package/dist/a2a/organization-identity.js +3 -1
  8. package/dist/a2a/server.d.ts +6 -5
  9. package/dist/a2a/server.js +79 -6
  10. package/dist/a2a-claims.d.ts +1 -0
  11. package/dist/a2a-claims.js +1 -0
  12. package/dist/agent/actions/manage-provider-key-policy.js +4 -2
  13. package/dist/agent/app-model-defaults.js +2 -10
  14. package/dist/agent/loop-settings.js +2 -10
  15. package/dist/audit/actions/export-audit-events.js +1 -0
  16. package/dist/audit/attribution.d.ts +5 -4
  17. package/dist/audit/attribution.js +2 -1
  18. package/dist/audit/index.d.ts +1 -1
  19. package/dist/audit/ocsf.js +1 -0
  20. package/dist/audit/read-scope.js +2 -12
  21. package/dist/audit/record.js +1 -0
  22. package/dist/audit/store.js +12 -3
  23. package/dist/audit/types.d.ts +4 -0
  24. package/dist/automation/index.d.ts +1 -1
  25. package/dist/automations/service.js +3 -10
  26. package/dist/client/org/hooks.d.ts +3 -0
  27. package/dist/client/org/hooks.js +12 -0
  28. package/dist/collab/awareness.d.ts +2 -2
  29. package/dist/collab/struct-routes.d.ts +1 -1
  30. package/dist/connections/catalog.d.ts +1 -1
  31. package/dist/connections/catalog.js +7 -1
  32. package/dist/credentials/index.js +18 -2
  33. package/dist/db/schema-snapshot.generated.js +5 -2
  34. package/dist/feature-flags/a2a-action-route.js +1 -0
  35. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  36. package/dist/file-upload/storage-settings.js +2 -9
  37. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  38. package/dist/jobs/tools.js +2 -12
  39. package/dist/mcp/actions/service-token-access.js +15 -11
  40. package/dist/mcp/credential-issuance.js +9 -2
  41. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  42. package/dist/notifications/routes.d.ts +6 -6
  43. package/dist/org/actions.d.ts +1 -1
  44. package/dist/org/actions.js +3 -7
  45. package/dist/org/app-roles.js +10 -1
  46. package/dist/org/context.d.ts +1 -0
  47. package/dist/org/context.js +122 -24
  48. package/dist/org/federation.d.ts +1 -1
  49. package/dist/org/federation.js +2 -2
  50. package/dist/org/handlers.d.ts +4 -0
  51. package/dist/org/handlers.js +142 -44
  52. package/dist/org/index.d.ts +2 -1
  53. package/dist/org/membership.d.ts +6 -4
  54. package/dist/org/membership.js +7 -5
  55. package/dist/org/migrations.js +6 -0
  56. package/dist/org/plugin.d.ts +1 -0
  57. package/dist/org/plugin.js +9 -1
  58. package/dist/org/private-icon-handlers.js +4 -10
  59. package/dist/org/types.d.ts +2 -0
  60. package/dist/org/workspace-app-access-outcome.d.ts +1 -1
  61. package/dist/org/workspace-app-access.js +77 -14
  62. package/dist/progress/routes.d.ts +1 -1
  63. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  64. package/dist/provider-api/actions/provider-api.d.ts +3 -3
  65. package/dist/resources/handlers.d.ts +1 -1
  66. package/dist/secrets/routes.d.ts +10 -10
  67. package/dist/server/action-routes.d.ts +1 -0
  68. package/dist/server/action-routes.js +13 -1
  69. package/dist/server/agent-chat/prompt-resources.js +1 -1
  70. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  71. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  72. package/dist/server/index.d.ts +1 -0
  73. package/dist/server/index.js +1 -0
  74. package/dist/server/org-admin.js +3 -2
  75. package/dist/server/personal-provider-key-holders.d.ts +1 -1
  76. package/dist/server/personal-provider-key-holders.js +7 -2
  77. package/dist/server/personal-provider-key-policy.d.ts +2 -0
  78. package/dist/server/personal-provider-key-policy.js +21 -5
  79. package/dist/server/request-context.d.ts +2 -0
  80. package/dist/server/request-context.js +7 -0
  81. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  82. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -13
  83. package/dist/triggers/actions/manage-automation.d.ts +5 -5
  84. package/dist/triggers/routes.js +2 -9
  85. package/dist/usage/alerts-store.js +2 -9
  86. package/dist/usage/metrics-store.js +2 -9
  87. package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +1 -1
  88. package/dist/workspace-connections/groups.js +2 -11
  89. package/package.json +3 -3
  90. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -13
@@ -6,6 +6,7 @@ import { deleteAutomationRunsWithDb, ensureAutomationRunHistoryReady, prepareAut
6
6
  import { applyJobResourceEdit } from "../jobs/update-job-resource.js";
7
7
  import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
8
8
  import { organizationIdFromResourceOwner, organizationResourceOwner, ensureResourceStoreReady, prepareResourceBatchAssertion, prepareResourceCreate, prepareResourceDelete, prepareResourceUpdate, resourceGetByPath, resourceList, resourcePutWithDb, resourceDelete, SHARED_OWNER, } from "../resources/store.js";
9
+ import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
9
10
  import { isReasoningEffort, } from "../shared/reasoning-effort.js";
10
11
  import { deleteAutomationWebhookToken, readAutomationWebhookPath, saveAutomationWebhookToken, } from "../triggers/webhook-store.js";
11
12
  import { createAutomationWebhookToken, automationWebhookPath, } from "../triggers/webhook.js";
@@ -61,16 +62,8 @@ function ownerForScope(actor, scope) {
61
62
  return organizationResourceOwner(actor.orgId);
62
63
  }
63
64
  async function readOrganizationMembership(orgId, email) {
64
- const result = await getDbExec().execute({
65
- sql: `SELECT role FROM org_members
66
- WHERE org_id = ? AND LOWER(email) = ?
67
- AND federation_removal_pending_at IS NULL
68
- LIMIT 1`,
69
- args: [orgId, email.toLowerCase()],
70
- });
71
- if (!result.rows.length)
72
- return null;
73
- return { role: String(result.rows[0]?.role ?? "").toLowerCase() };
65
+ const role = await readOrgMemberRole(orgId, email);
66
+ return role ? { role } : null;
74
67
  }
75
68
  async function requireOrganizationMembership(actor) {
76
69
  if (!actor.orgId) {
@@ -235,6 +235,9 @@ export declare function useSetA2ASecret(): import("@tanstack/react-query").UseMu
235
235
  a2aSecret: string;
236
236
  previousSecret: string | null;
237
237
  }, Error, string | undefined, unknown>;
238
+ export declare function useSetA2AMemberDelegation(): import("@tanstack/react-query").UseMutationResult<{
239
+ enabled: boolean;
240
+ }, Error, boolean, unknown>;
238
241
  export interface SyncA2ASecretResult {
239
242
  total: number;
240
243
  succeeded: number;
@@ -486,6 +486,18 @@ export function useSetA2ASecret() {
486
486
  },
487
487
  });
488
488
  }
489
+ export function useSetA2AMemberDelegation() {
490
+ const qc = useQueryClient();
491
+ return useMutation({
492
+ mutationFn: (enabled) => apiFetch(`${orgBasePath()}/a2a-member-delegation`, {
493
+ method: "PUT",
494
+ body: JSON.stringify({ enabled }),
495
+ }),
496
+ onSuccess: async () => {
497
+ await qc.invalidateQueries({ queryKey: ["org-me"] });
498
+ },
499
+ });
500
+ }
489
501
  export function useSyncA2ASecret() {
490
502
  return useMutation({
491
503
  mutationFn: (vars) => apiFetch(`${orgBasePath()}/a2a-secret/sync`, {
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
- error?: undefined;
42
41
  states: {
43
42
  clientId: number;
44
43
  state: string;
45
44
  }[];
45
+ error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
- error?: undefined;
52
51
  users: {
53
52
  clientId: number;
54
53
  lastSeen: number;
55
54
  }[];
55
+ error?: undefined;
56
56
  }>>;
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- error: string;
3
2
  ok?: undefined;
3
+ error: string;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -65,7 +65,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
65
65
  readonly scopes: readonly ["repo", "read:org", "read:user", "user:email"];
66
66
  };
67
67
  readonly capabilities: readonly ["search", "import", "code", "docs"];
68
- readonly recommendedTemplateUses: readonly ["brain", "analytics", "dispatch", "factory"];
68
+ readonly recommendedTemplateUses: readonly ["brain", "analytics", "content", "dispatch", "factory"];
69
69
  }, {
70
70
  readonly id: "figma";
71
71
  readonly label: "Figma";
@@ -59,7 +59,13 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
59
59
  scopes: ["repo", "read:org", "read:user", "user:email"],
60
60
  },
61
61
  capabilities: ["search", "import", "code", "docs"],
62
- recommendedTemplateUses: ["brain", "analytics", "dispatch", "factory"],
62
+ recommendedTemplateUses: [
63
+ "brain",
64
+ "analytics",
65
+ "content",
66
+ "dispatch",
67
+ "factory",
68
+ ],
63
69
  }),
64
70
  defineWorkspaceConnectionProvider({
65
71
  id: "figma",
@@ -5,6 +5,7 @@ import { deleteAppSecret, readAppSecret, } from "../secrets/storage.js";
5
5
  import { assertCredentialStoreReadable } from "../server/credential-provider.js";
6
6
  import { isPersonalCredentialScope, readsOrgCredentialFirst, } from "../server/credential-read-order.js";
7
7
  import { isPersonalProviderKeyUseRestricted, isPersonalProviderPolicyKey, readOrgMemberRole, } from "../server/personal-provider-key-policy.js";
8
+ import { getRequestContext } from "../server/request-context.js";
8
9
  import { getSetting, putSetting, deleteSetting } from "../settings/store.js";
9
10
  const SETTING_PREFIX = "credential:";
10
11
  export class CredentialEndpointMismatchError extends Error {
@@ -239,7 +240,20 @@ export async function resolveCredential(key, ctx) {
239
240
  export async function describeCredentialScopeGap(keys, ctx) {
240
241
  if (!ctx?.userEmail)
241
242
  return null;
242
- const orgLookup = await resolveEffectiveOrgId(ctx);
243
+ const requestContext = getRequestContext();
244
+ const isDelegatedOrgMember = requestContext?.a2aIdentityAssurance === "org-member";
245
+ const delegatedEmail = requestContext?.userEmail?.trim().toLowerCase();
246
+ const delegatedOrgId = requestContext?.orgId?.trim();
247
+ if (isDelegatedOrgMember &&
248
+ (!delegatedEmail ||
249
+ delegatedEmail !== ctx.userEmail.trim().toLowerCase() ||
250
+ !delegatedOrgId ||
251
+ (ctx.orgId && ctx.orgId.trim() !== delegatedOrgId))) {
252
+ return null;
253
+ }
254
+ const orgLookup = isDelegatedOrgMember
255
+ ? { orgId: delegatedOrgId, lookupFailed: false }
256
+ : await resolveEffectiveOrgId(ctx);
243
257
  if (orgLookup.lookupFailed || !orgLookup.orgId)
244
258
  return null;
245
259
  const scopedCtx = { ...ctx, orgId: orgLookup.orgId };
@@ -251,7 +265,9 @@ export async function describeCredentialScopeGap(keys, ctx) {
251
265
  `integration, job, or automation — so it needs "${key}" saved with ` +
252
266
  `Workspace or Organization scope instead.`);
253
267
  }
254
- const holder = await findMemberOrgHoldingCredential(key, scopedCtx);
268
+ const holder = isDelegatedOrgMember
269
+ ? null
270
+ : await findMemberOrgHoldingCredential(key, scopedCtx);
255
271
  if (holder) {
256
272
  return (`A "${key}" key is saved in the ${holder} organization, but this ` +
257
273
  `request resolved to a different organization you also belong to. ` +
@@ -16,7 +16,7 @@ export const SCHEMA_SNAPSHOT = {
16
16
  'CREATE TABLE "a2a_approvals" (\n "id" text NOT NULL,\n "task_id" text NOT NULL,\n "owner_email" text NOT NULL,\n "org_id" text,\n "tool_name" text NOT NULL,\n "tool_input" text NOT NULL,\n "approval_key" text NOT NULL,\n "call_id" text NOT NULL,\n "status" text DEFAULT \'pending\'::text NOT NULL,\n "result" text,\n "expires_at" bigint NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
17
17
  'CREATE TABLE "a2a_tasks" (\n "id" text NOT NULL,\n "context_id" text,\n "status_state" text DEFAULT \'submitted\'::text NOT NULL,\n "status_message" text,\n "status_timestamp" text NOT NULL,\n "history" text DEFAULT \'[]\'::text NOT NULL,\n "artifacts" text DEFAULT \'[]\'::text NOT NULL,\n "metadata" text,\n "owner_email" text,\n "owner_scope" text DEFAULT \'\'::text NOT NULL,\n "idempotency_key" text,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
18
18
  'CREATE TABLE "account" (\n "id" text NOT NULL,\n "account_id" text NOT NULL,\n "provider_id" text NOT NULL,\n "user_id" text NOT NULL,\n "access_token" text,\n "refresh_token" text,\n "id_token" text,\n "access_token_expires_at" timestamp with time zone,\n "refresh_token_expires_at" timestamp with time zone,\n "scope" text,\n "password" text,\n "created_at" timestamp with time zone NOT NULL,\n "updated_at" timestamp with time zone NOT NULL\n);',
19
- 'CREATE TABLE "agent_audit_log" (\n "id" text NOT NULL,\n "created_at" bigint NOT NULL,\n "action" text NOT NULL,\n "caller" text NOT NULL,\n "actor_kind" text NOT NULL,\n "actor_email" text,\n "org_id" text,\n "thread_id" text,\n "turn_id" text,\n "target_type" text,\n "target_id" text,\n "status" text DEFAULT \'success\'::text NOT NULL,\n "summary" text,\n "input" text,\n "error_code" text,\n "owner_email" text,\n "visibility" text DEFAULT \'private\'::text NOT NULL,\n "run_id" text,\n "task_id" text,\n "parent_task_id" text,\n "source_kind" text,\n "source_platform" text,\n "source_id" text,\n "source_url" text,\n "network_protocol" text,\n "network_id" text,\n "network_peer" text,\n "app" text,\n "reported_client_name" text,\n "reported_client_version" text,\n "oauth_client_id" text,\n "approval" text\n);',
19
+ 'CREATE TABLE "agent_audit_log" (\n "id" text NOT NULL,\n "created_at" bigint NOT NULL,\n "action" text NOT NULL,\n "caller" text NOT NULL,\n "actor_kind" text NOT NULL,\n "actor_email" text,\n "org_id" text,\n "thread_id" text,\n "turn_id" text,\n "target_type" text,\n "target_id" text,\n "status" text DEFAULT \'success\'::text NOT NULL,\n "summary" text,\n "input" text,\n "error_code" text,\n "owner_email" text,\n "visibility" text DEFAULT \'private\'::text NOT NULL,\n "run_id" text,\n "task_id" text,\n "parent_task_id" text,\n "source_kind" text,\n "source_platform" text,\n "source_id" text,\n "source_url" text,\n "network_protocol" text,\n "network_id" text,\n "network_peer" text,\n "app" text,\n "reported_client_name" text,\n "reported_client_version" text,\n "oauth_client_id" text,\n "approval" text,\n "identity_assurance" text\n);',
20
20
  'CREATE TABLE "agent_chat_submission_inbox" (\n "thread_id" text NOT NULL,\n "message_id" text NOT NULL,\n "state" text NOT NULL,\n "actor_email" text NOT NULL,\n "actor_auth_user_id" text,\n "actor_identity_authenticated_at_ms" bigint,\n "actor_name" text,\n "actor_org_id" text,\n "actor_org_scope" text,\n "actor_anonymous" boolean DEFAULT false NOT NULL,\n "payload_hash" text NOT NULL,\n "payload_json" text NOT NULL,\n "interrupt_active_run" boolean DEFAULT false NOT NULL,\n "submitted_run_id" text,\n "queue_order" bigint DEFAULT nextval(\'agent_chat_submission_inbox_queue_order_seq\'::regclass) NOT NULL,\n "move_to_top_at" bigint,\n "retry_after" bigint,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "interrupt_run_id" text\n);',
21
21
  'CREATE TABLE "agent_checkpoints" (\n "id" text NOT NULL,\n "thread_id" text NOT NULL,\n "run_id" text,\n "commit_sha" text NOT NULL,\n "message" text DEFAULT \'\'::text NOT NULL,\n "created_at" bigint NOT NULL\n);',
22
22
  'CREATE TABLE "agent_eval_datasets" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "description" text DEFAULT \'\'::text NOT NULL,\n "entries" text DEFAULT \'[]\'::text NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "user_id" text,\n "idempotency_key" text\n);',
@@ -121,7 +121,7 @@ export const SCHEMA_SNAPSHOT = {
121
121
  'CREATE TABLE "org_members" (\n "id" text NOT NULL,\n "org_id" text NOT NULL,\n "email" text NOT NULL,\n "role" text NOT NULL,\n "joined_at" bigint NOT NULL,\n "federation_removal_pending_at" bigint\n);',
122
122
  'CREATE TABLE "org_scim_memberships" (\n "id" text NOT NULL,\n "org_id" text NOT NULL,\n "user_id" text NOT NULL,\n "created_membership" boolean DEFAULT false NOT NULL,\n "created_at" bigint NOT NULL,\n "member_id" text\n);',
123
123
  'CREATE TABLE "organization" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "slug" text NOT NULL,\n "logo" text,\n "metadata" text,\n "created_at" timestamp with time zone NOT NULL,\n "updated_at" timestamp with time zone NOT NULL\n);',
124
- 'CREATE TABLE "organizations" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "created_by" text NOT NULL,\n "created_at" bigint NOT NULL,\n "allowed_domain" text,\n "a2a_secret" text,\n "workspace_url" text,\n "required_auth_provider" text,\n "identity_authority" text,\n "identity_id" text,\n "federation_roster_initialized_at" bigint,\n "icon_json" text,\n "icon_revision" bigint DEFAULT 0 NOT NULL\n);',
124
+ 'CREATE TABLE "organizations" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "created_by" text NOT NULL,\n "created_at" bigint NOT NULL,\n "allowed_domain" text,\n "a2a_secret" text,\n "workspace_url" text,\n "required_auth_provider" text,\n "identity_authority" text,\n "identity_id" text,\n "federation_roster_initialized_at" bigint,\n "icon_json" text,\n "icon_revision" bigint DEFAULT 0 NOT NULL,\n "a2a_member_delegation_enabled" boolean DEFAULT false NOT NULL\n);',
125
125
  'CREATE TABLE "private_icon_assets" (\n "id" text NOT NULL,\n "owner_email" text NOT NULL,\n "org_id" text,\n "mime_type" text NOT NULL,\n "filename" text,\n "alt" text,\n "size" bigint NOT NULL,\n "sha256" text NOT NULL,\n "blob_handle_json" text NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
126
126
  'CREATE TABLE "progress_runs" (\n "id" text NOT NULL,\n "owner" text NOT NULL,\n "title" text NOT NULL,\n "step" text,\n "percent" bigint,\n "status" text DEFAULT \'running\'::text NOT NULL,\n "metadata" text,\n "started_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "completed_at" bigint\n);',
127
127
  'CREATE TABLE "provider_api_cooldowns" (\n "quota_key" text NOT NULL,\n "provider_id" text NOT NULL,\n "scope_key" text NOT NULL,\n "cooldown_until" bigint NOT NULL,\n "status" bigint,\n "reason" text,\n "updated_at" bigint NOT NULL\n);',
@@ -866,6 +866,7 @@ export const SCHEMA_SNAPSHOT = {
866
866
  ["application_state", "baseline", null],
867
867
  ["application_state", "indexes", null],
868
868
  ["application_state", "widen-bigint", null],
869
+ ["audit", "a2a-identity-assurance", "5ebfefc25224eaa5"],
869
870
  ["audit", "baseline", null],
870
871
  ["audit", "mcp-client-attribution", "bc0ea72722e10241"],
871
872
  ["auth_sessions", "baseline", null],
@@ -1038,6 +1039,7 @@ export const SCHEMA_SNAPSHOT = {
1038
1039
  ["org", "org-scim-membership-member-id", "cd1c4fb7479507d3"],
1039
1040
  ["org", "org-scim-membership-ownership", "09ca1c03026cda83"],
1040
1041
  ["org", "org-tables-timestamps-bigint", "a71b72b885bd5585"],
1042
+ ["org", "organization-a2a-member-delegation", "3d01bcd4e7c259b0"],
1041
1043
  ["org", "organization-federation-removal-pending", "47fe40eb2ea33753"],
1042
1044
  ["org", "organization-federation-roster-initialized", "3307d4d99818c2f0"],
1043
1045
  ["org", "organization-identity-federation", "e24bac924c2d4c7a"],
@@ -1182,5 +1184,6 @@ export const SCHEMA_SNAPSHOT = {
1182
1184
  ["_org_migrations", 1032, "agent-audit-log-base-table"],
1183
1185
  ["_org_migrations", 1033, "organization-visual-identity"],
1184
1186
  ["_org_migrations", 1034, "private-icon-assets"],
1187
+ ["_org_migrations", 1035, "organization-a2a-member-delegation"],
1185
1188
  ],
1186
1189
  };
@@ -46,6 +46,7 @@ export function createFeatureFlagA2AActionRouteAuth(actionName) {
46
46
  owner: claims.email,
47
47
  orgId,
48
48
  anonymous: false,
49
+ identityAssurance: claims.identityAssurance,
49
50
  delegationJti: claims.jti,
50
51
  delegationIssuer: claims.issuer,
51
52
  };
@@ -42,8 +42,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
42
42
  url: string;
43
43
  id: string;
44
44
  provider: string;
45
- error?: undefined;
46
45
  configured?: undefined;
46
+ error?: undefined;
47
47
  } | {
48
48
  url?: undefined;
49
49
  id?: undefined;
@@ -8,8 +8,8 @@
8
8
  * keep uploading to the old bucket.
9
9
  */
10
10
  import { fail } from "../action.js";
11
- import { getDbExec } from "../db/client.js";
12
11
  import { deleteAppSecret, readAppSecrets, writeAppSecret, } from "../secrets/storage.js";
12
+ import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
13
13
  import { getActiveFileUploadProviderForRequest, listFileUploadProviders, } from "./registry.js";
14
14
  import { getPrivateStorageReadinessForUser, } from "./storage-readiness.js";
15
15
  export const FILE_STORAGE_SECRET_KEYS = {
@@ -46,14 +46,7 @@ export async function resolveFileStorageAccess(ctx) {
46
46
  // matching `canMutateWorkspaceScope` in the secrets routes.
47
47
  if (!orgId)
48
48
  return { scopeId: `solo:${email}`, canManage: true };
49
- const { rows } = await getDbExec().execute({
50
- sql: `SELECT role FROM org_members
51
- WHERE org_id = ? AND LOWER(email) = LOWER(?)
52
- AND federation_removal_pending_at IS NULL
53
- LIMIT 1`,
54
- args: [orgId, email],
55
- });
56
- const role = rows[0]?.role;
49
+ const role = await readOrgMemberRole(orgId, email);
57
50
  return { scopeId: orgId, canManage: role === "owner" || role === "admin" };
58
51
  }
59
52
  export function inferFileStorageProvider(endpoint) {
@@ -13,10 +13,10 @@ declare const _default: import("../../action.js").ActionDefinition<{
13
13
  enabled?: undefined;
14
14
  nextRun?: undefined;
15
15
  } | {
16
+ deleted?: undefined;
16
17
  resourceId: string;
17
18
  name: string;
18
19
  enabled: boolean;
19
20
  nextRun: string;
20
- deleted?: undefined;
21
21
  }>;
22
22
  export default _default;
@@ -1,8 +1,8 @@
1
1
  import { resolveAutomationAccess } from "../automations/access.js";
2
2
  import { DEFAULT_AUTOMATION_SCHEDULE } from "../automations/service.js";
3
- import { getDbExec } from "../db/client.js";
4
3
  import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
5
4
  import { organizationIdFromResourceOwner, resourcePutIfAbsent, resourceGetByPath, resourceList, resourceDelete, SHARED_OWNER, sharedResourceOwner, } from "../resources/store.js";
5
+ import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
6
6
  import { getRequestUserEmail, getRequestOrgId, getIntegrationRequestContext, } from "../server/request-context.js";
7
7
  import { isReasoningEffort, REASONING_EFFORTS, } from "../shared/reasoning-effort.js";
8
8
  import { RESUME_AUTOMATION_PATCH } from "./automation-outcome.js";
@@ -27,17 +27,7 @@ async function isCurrentUserOrgAdmin(orgId) {
27
27
  if (!email)
28
28
  return false;
29
29
  try {
30
- const client = getDbExec();
31
- const { rows } = await client.execute({
32
- sql: `SELECT role FROM org_members
33
- WHERE org_id = ? AND LOWER(email) = ?
34
- AND federation_removal_pending_at IS NULL
35
- LIMIT 1`,
36
- args: [orgId, email.toLowerCase()],
37
- });
38
- if (rows.length === 0)
39
- return false;
40
- const role = String(rows[0].role ?? "").toLowerCase();
30
+ const role = await readOrgMemberRole(orgId, email);
41
31
  return role === "owner" || role === "admin";
42
32
  }
43
33
  catch {
@@ -14,6 +14,8 @@
14
14
  import { getDbExec } from "../../db/client.js";
15
15
  import { isMissingOrganizationTableError } from "../../org/membership.js";
16
16
  import { CREDENTIAL_MEMBERSHIP_UNAVAILABLE_MESSAGE } from "../../server/credential-membership-unavailable.js";
17
+ import { readOrgMemberRole } from "../../server/personal-provider-key-policy.js";
18
+ import { getRequestContext } from "../../server/request-context.js";
17
19
  export const SERVICE_TOKEN_MANAGE_FORBIDDEN_MESSAGE = "Only org owners or admins can create or revoke service tokens.";
18
20
  export class ServiceTokenError extends Error {
19
21
  statusCode;
@@ -24,17 +26,7 @@ export class ServiceTokenError extends Error {
24
26
  }
25
27
  }
26
28
  async function readOrgRole(orgId, email) {
27
- const { rows } = await getDbExec().execute({
28
- sql: `SELECT role FROM org_members
29
- WHERE org_id = ? AND LOWER(email) = ?
30
- AND federation_removal_pending_at IS NULL
31
- LIMIT 1`,
32
- args: [orgId, email.toLowerCase()],
33
- });
34
- const role = rows[0]?.role;
35
- return role === "owner" || role === "admin" || role === "member"
36
- ? role
37
- : null;
29
+ return readOrgMemberRole(orgId, email);
38
30
  }
39
31
  export async function getOrgRoleForEmail(orgId, email) {
40
32
  try {
@@ -76,6 +68,18 @@ export async function requireServiceTokenCaller(params) {
76
68
  throw new ServiceTokenError("Sign in to manage org service tokens.", 401);
77
69
  }
78
70
  let orgId = params.orgId?.trim() || "";
71
+ const requestContext = getRequestContext();
72
+ if (requestContext?.a2aIdentityAssurance === "org-member") {
73
+ const delegatedEmail = requestContext.userEmail?.trim().toLowerCase();
74
+ const delegatedOrgId = requestContext.orgId?.trim();
75
+ if (!delegatedEmail ||
76
+ delegatedEmail !== email.toLowerCase() ||
77
+ !delegatedOrgId ||
78
+ (orgId && orgId !== delegatedOrgId)) {
79
+ throw new ServiceTokenError("You are not a member of this organization.", 403);
80
+ }
81
+ orgId = delegatedOrgId;
82
+ }
79
83
  if (!orgId) {
80
84
  const memberOrgs = await lookupMembership(() => readOrgIds(email), []);
81
85
  if (memberOrgs.length === 0) {
@@ -1,5 +1,7 @@
1
1
  import { getDbExec } from "../db/client.js";
2
2
  import { identityCredentialLockKey, readEmailRetiredAt, } from "../identity/retired-emails.js";
3
+ import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
4
+ import { getRequestContext } from "../server/request-context.js";
3
5
  import { checkCredentialOrgMembership } from "./credential-membership.js";
4
6
  export class McpCredentialIssuanceError extends Error {
5
7
  reason;
@@ -19,6 +21,11 @@ export async function withMcpCredentialIssuance(input, run) {
19
21
  const email = input.email.trim().toLowerCase();
20
22
  const human = input.kind !== "service";
21
23
  const requiresMembership = orgId !== null && human;
24
+ if (getRequestContext()?.a2aIdentityAssurance === "org-member") {
25
+ if (!orgId || !effectiveOrgMemberRole("member", orgId, email)) {
26
+ throw new McpCredentialIssuanceError("not-member");
27
+ }
28
+ }
22
29
  if (requiresMembership) {
23
30
  // Federation validation may update membership on another connection.
24
31
  // Finish it before acquiring the local offboarding lock.
@@ -60,9 +67,9 @@ export async function withMcpCredentialIssuance(input, run) {
60
67
  FOR UPDATE`,
61
68
  args: [orgId, email],
62
69
  });
70
+ const role = effectiveOrgMemberRole(rows[0]?.role, orgId, email);
63
71
  if (rows.length === 0 ||
64
- (input.roles &&
65
- !input.roles.includes(String(rows[0].role)))) {
72
+ (input.roles && !input.roles.includes(role))) {
66
73
  throw new McpCredentialIssuanceError("not-member");
67
74
  }
68
75
  }
@@ -140,13 +140,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
140
140
  clientHint?: undefined;
141
141
  timestamp?: undefined;
142
142
  chapterId?: undefined;
143
- count?: undefined;
144
143
  startAt?: undefined;
145
144
  endAt?: undefined;
146
145
  reason?: undefined;
147
146
  includeMicrophone?: undefined;
148
147
  includeSystemAudio?: undefined;
149
148
  requestId?: undefined;
149
+ count?: undefined;
150
150
  };
151
151
  required?: undefined;
152
152
  };
@@ -171,13 +171,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
171
171
  clientHint?: undefined;
172
172
  timestamp?: undefined;
173
173
  chapterId?: undefined;
174
- count?: undefined;
175
174
  startAt?: undefined;
176
175
  endAt?: undefined;
177
176
  reason?: undefined;
178
177
  includeMicrophone?: undefined;
179
178
  includeSystemAudio?: undefined;
180
179
  requestId?: undefined;
180
+ count?: undefined;
181
181
  };
182
182
  required?: undefined;
183
183
  };
@@ -196,13 +196,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
196
196
  clientHint?: undefined;
197
197
  timestamp?: undefined;
198
198
  chapterId?: undefined;
199
- count?: undefined;
200
199
  startAt?: undefined;
201
200
  endAt?: undefined;
202
201
  reason?: undefined;
203
202
  includeMicrophone?: undefined;
204
203
  includeSystemAudio?: undefined;
205
204
  requestId?: undefined;
205
+ count?: undefined;
206
206
  };
207
207
  required?: undefined;
208
208
  };
@@ -231,13 +231,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
231
231
  };
232
232
  timestamp?: undefined;
233
233
  chapterId?: undefined;
234
- count?: undefined;
235
234
  startAt?: undefined;
236
235
  endAt?: undefined;
237
236
  reason?: undefined;
238
237
  includeMicrophone?: undefined;
239
238
  includeSystemAudio?: undefined;
240
239
  requestId?: undefined;
240
+ count?: undefined;
241
241
  };
242
242
  };
243
243
  } | {
@@ -260,12 +260,12 @@ export declare function screenMemoryMcpToolDefinitions(): ({
260
260
  description: string;
261
261
  };
262
262
  chapterId?: undefined;
263
- count?: undefined;
264
263
  startAt?: undefined;
265
264
  endAt?: undefined;
266
265
  includeMicrophone?: undefined;
267
266
  includeSystemAudio?: undefined;
268
267
  requestId?: undefined;
268
+ count?: undefined;
269
269
  };
270
270
  };
271
271
  } | {
@@ -317,7 +317,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
317
317
  clientHint?: undefined;
318
318
  timestamp?: undefined;
319
319
  chapterId?: undefined;
320
- count?: undefined;
321
320
  startAt: {
322
321
  type: string;
323
322
  description: string;
@@ -337,6 +336,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
337
336
  type: string;
338
337
  };
339
338
  requestId?: undefined;
339
+ count?: undefined;
340
340
  };
341
341
  };
342
342
  } | {
@@ -352,7 +352,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
352
352
  clientHint?: undefined;
353
353
  timestamp?: undefined;
354
354
  chapterId?: undefined;
355
- count?: undefined;
356
355
  startAt?: undefined;
357
356
  endAt?: undefined;
358
357
  reason?: undefined;
@@ -361,6 +360,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
361
360
  requestId: {
362
361
  type: string;
363
362
  };
363
+ count?: undefined;
364
364
  };
365
365
  };
366
366
  })[];
@@ -1,21 +1,21 @@
1
1
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
2
- error?: undefined;
3
2
  count: number;
4
- ok?: undefined;
5
3
  updated?: undefined;
6
- } | {
7
4
  error?: undefined;
5
+ ok?: undefined;
6
+ } | {
8
7
  count?: undefined;
9
8
  updated: number;
9
+ error?: undefined;
10
10
  ok?: undefined;
11
11
  } | {
12
12
  count?: undefined;
13
+ updated?: undefined;
13
14
  error: string;
14
15
  ok?: undefined;
15
- updated?: undefined;
16
16
  } | {
17
- error?: undefined;
18
17
  count?: undefined;
19
- ok: boolean;
20
18
  updated?: undefined;
19
+ ok: boolean;
20
+ error?: undefined;
21
21
  }>>;
@@ -2,5 +2,5 @@ import { type ActionRunContext } from "../action.js";
2
2
  export declare function requireOrgMember(ctx?: ActionRunContext, admin?: boolean): Promise<{
3
3
  email: string;
4
4
  orgId: string;
5
- role: string;
5
+ role: import("./types.js").OrgRole;
6
6
  }>;
@@ -1,5 +1,5 @@
1
1
  import { fail } from "../action.js";
2
- import { getDbExec } from "../db/client.js";
2
+ import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
3
3
  export async function requireOrgMember(ctx, admin = false) {
4
4
  const email = ctx?.userEmail?.trim();
5
5
  const orgId = ctx?.orgId?.trim();
@@ -8,11 +8,7 @@ export async function requireOrgMember(ctx, admin = false) {
8
8
  errorCode: "unauthorized",
9
9
  statusCode: 401,
10
10
  });
11
- const { rows } = await getDbExec().execute({
12
- sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = LOWER(?) AND federation_removal_pending_at IS NULL LIMIT 1`,
13
- args: [orgId, email],
14
- });
15
- const role = rows[0]?.role;
11
+ const role = await readOrgMemberRole(orgId, email);
16
12
  if (!role)
17
13
  fail("You are not a member of the active organization.", {
18
14
  errorCode: "forbidden",
@@ -23,5 +19,5 @@ export async function requireOrgMember(ctx, admin = false) {
23
19
  errorCode: "forbidden",
24
20
  statusCode: 403,
25
21
  });
26
- return { email, orgId, role: String(role) };
22
+ return { email, orgId, role };
27
23
  }
@@ -1,5 +1,6 @@
1
1
  import { getDbExec } from "../db/client.js";
2
- import { getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
2
+ import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
3
+ import { getRequestContext, getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
3
4
  import { ForbiddenError } from "../sharing/access.js";
4
5
  import { isMissingOrganizationTableError } from "./membership.js";
5
6
  const registry = new Map();
@@ -137,6 +138,9 @@ export async function resolveAppRole(descriptor, caller) {
137
138
  return { status: "no-identity" };
138
139
  if (!orgId)
139
140
  return { status: "no-org" };
141
+ if (!effectiveOrgMemberRole("member", orgId, email)) {
142
+ return { status: "not-a-member", orgId };
143
+ }
140
144
  let rows;
141
145
  try {
142
146
  rows = (await getDbExec().execute({
@@ -187,6 +191,11 @@ export async function resolveAppRole(descriptor, caller) {
187
191
  return { status: "not-a-member", orgId };
188
192
  orgRole = membership.role;
189
193
  }
194
+ const isDelegatedOrgMember = getRequestContext()?.a2aIdentityAssurance === "org-member";
195
+ orgRole = effectiveOrgMemberRole(orgRole, orgId, email) ?? undefined;
196
+ if (isDelegatedOrgMember && !orgRole) {
197
+ return { status: "not-a-member", orgId };
198
+ }
190
199
  const raw = row.roles ?? row.appRoles ?? row.approles;
191
200
  const roles = Array.isArray(raw) ? raw.map(String) : [];
192
201
  const validRoles = [
@@ -85,5 +85,6 @@ export declare function resolveA2AOrganizationCredentialsByDomain(domain: string
85
85
  orgId: string;
86
86
  orgDomain: string;
87
87
  secret: string;
88
+ a2aMemberDelegationEnabled: boolean;
88
89
  } | null>;
89
90
  export declare function isSoleOrgDomain(domain: string): Promise<boolean>;