@zackbart/connecta 0.29.0 → 0.31.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 (116) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +126 -134
  3. package/bin/connecta.mjs +13 -2
  4. package/bin/version.mjs +1 -1
  5. package/dist/argument-redaction.js +230 -0
  6. package/dist/auth-elicitation.js +14 -9
  7. package/dist/authorization-handoff.js +111 -0
  8. package/dist/call-recovery.js +25 -0
  9. package/dist/catalog-cache.js +2 -2
  10. package/dist/catalog-service.js +103 -63
  11. package/dist/config-schema.d.ts +14 -7
  12. package/dist/config-schema.js +29 -10
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.js +12 -7
  15. package/dist/connectors/guarded-fetch.d.ts +9 -1
  16. package/dist/connectors/guarded-fetch.js +17 -5
  17. package/dist/connectors/negotiation-cache.js +1 -1
  18. package/dist/downstream-input-context.js +9 -0
  19. package/dist/downstream-input.js +13 -11
  20. package/dist/errors.d.ts +38 -12
  21. package/dist/errors.js +19 -9
  22. package/dist/execute.js +375 -43
  23. package/dist/executor-result.js +11 -9
  24. package/dist/executors/quickjs-child.js +12 -5
  25. package/dist/executors/quickjs-protocol.js +5 -6
  26. package/dist/executors/quickjs-runtime.js +6 -1
  27. package/dist/executors/quickjs.js +20 -4
  28. package/dist/guest-runtime.js +52 -2
  29. package/dist/guest-types.d.ts +47 -5
  30. package/dist/index.d.ts +1 -1
  31. package/dist/invocation.js +72 -14
  32. package/dist/meta-output.js +0 -15
  33. package/dist/meta-tools.js +166 -95
  34. package/dist/oauth-handoff.js +88 -11
  35. package/dist/operator-ui/generated.js +2 -2
  36. package/dist/operator-ui/view.d.ts +9 -0
  37. package/dist/operator-ui/view.js +11 -0
  38. package/dist/program-result.js +5 -0
  39. package/dist/program-writes.js +7 -48
  40. package/dist/provider.d.ts +8 -6
  41. package/dist/provider.js +3 -4
  42. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  43. package/dist/providers/_shared/request-token.js +83 -0
  44. package/dist/providers/_shared/rest/dispatch.js +41 -0
  45. package/dist/providers/_shared/rest/operation-index.d.ts +133 -0
  46. package/dist/providers/_shared/rest/operation-index.js +527 -0
  47. package/dist/providers/_shared/rest/tools.d.ts +141 -0
  48. package/dist/providers/_shared/rest/tools.js +569 -0
  49. package/dist/providers/_shared/rest/value-safety.d.ts +151 -0
  50. package/dist/providers/_shared/rest/value-safety.js +580 -0
  51. package/dist/providers/cloudflare/graphql.js +385 -0
  52. package/dist/providers/cloudflare/index.d.ts +47 -51
  53. package/dist/providers/cloudflare/index.js +188 -1997
  54. package/dist/providers/cloudflare/openapi.generated.js +3347 -0
  55. package/dist/providers/cloudflare/rest.d.ts +37 -0
  56. package/dist/providers/cloudflare/rest.js +1056 -0
  57. package/dist/providers/cloudflare/skill.generated.js +7 -4
  58. package/dist/providers/cloudflare/value-safety.js +1247 -0
  59. package/dist/providers/infisical/index.d.ts +7 -0
  60. package/dist/providers/infisical/index.js +713 -0
  61. package/dist/providers/infisical/skill.generated.js +8 -0
  62. package/dist/providers/notion/index.d.ts +35 -31
  63. package/dist/providers/notion/index.js +60 -1499
  64. package/dist/providers/notion/openapi.generated.js +75 -0
  65. package/dist/providers/notion/rest.d.ts +24 -0
  66. package/dist/providers/notion/rest.js +1067 -0
  67. package/dist/providers/notion/skill.generated.js +5 -4
  68. package/dist/providers/notion/value-safety.js +31 -0
  69. package/dist/providers/stripe/index.d.ts +26 -20
  70. package/dist/providers/stripe/index.js +103 -130
  71. package/dist/providers/stripe/openapi.generated.js +649 -0
  72. package/dist/providers/stripe/rest.d.ts +14 -0
  73. package/dist/providers/stripe/rest.js +395 -0
  74. package/dist/providers/stripe/skill.generated.js +7 -5
  75. package/dist/providers/stripe/value-safety.js +705 -0
  76. package/dist/providers/vercel/index.d.ts +31 -22
  77. package/dist/providers/vercel/index.js +96 -853
  78. package/dist/providers/vercel/openapi.generated.js +456 -0
  79. package/dist/providers/vercel/rest.d.ts +20 -0
  80. package/dist/providers/vercel/rest.js +1002 -0
  81. package/dist/providers/vercel/skill.generated.js +4 -5
  82. package/dist/providers/vercel/value-safety.js +328 -0
  83. package/dist/registry.d.ts +8 -6
  84. package/dist/registry.js +134 -61
  85. package/dist/resource-read.js +4 -1
  86. package/dist/routes/mcp.js +11 -2
  87. package/dist/sent-secrets.d.ts +54 -13
  88. package/dist/sent-secrets.js +770 -231
  89. package/dist/skills.js +26 -16
  90. package/dist/sqlite.js +21 -6
  91. package/dist/storage/keys.js +20 -5
  92. package/dist/storage/memory.js +9 -4
  93. package/dist/storage/sql.js +18 -9
  94. package/dist/types.d.ts +17 -3
  95. package/dist/usage-guide.js +49 -40
  96. package/dist/version.d.ts +1 -1
  97. package/dist/version.js +1 -1
  98. package/dist/worker.js +2 -1
  99. package/dist/write-outcome.js +47 -0
  100. package/documentation/README.md +64 -0
  101. package/documentation/architecture.md +241 -97
  102. package/documentation/auth.md +138 -5
  103. package/documentation/code-mode.md +224 -107
  104. package/documentation/deploying.md +146 -0
  105. package/documentation/integrating.md +170 -0
  106. package/documentation/meta-tools.md +142 -30
  107. package/documentation/operating.md +135 -0
  108. package/documentation/operator-tests.md +4 -0
  109. package/documentation/operator-ui.md +132 -0
  110. package/documentation/provider-auth-migration.md +307 -0
  111. package/documentation/provider-migration-0.29.md +22 -5
  112. package/examples/worker/README.md +9 -2
  113. package/package.json +9 -2
  114. package/templates/node/README.md +9 -2
  115. package/templates/node/package.json +1 -1
  116. package/dist/providers/vercel/mcp-ownership.js +0 -212
@@ -1,11 +1,10 @@
1
1
  // Generated by scripts/generate-providers.mjs; do not edit.
2
2
  export const skill = {
3
- "content": "`. Every named account-scoped tool accepts a `teamId` override; pass `null` to target the token owner's personal account.\n## REST complement routing\n\nHosted MCP is the default. Configure this complement with `surface: \"api\"`\nand a separate connector id and access-token credential. OAuth and API-token\nstores are independent; failures never switch identity or replay a write.\nTeam defaults route calls and do not constrain the token's permissions.\n\nUse hosted `list_teams`, `list_projects`, `get_project`, `list_deployments`,\n`get_deployment`, `get_deployment_build_logs` or `list_deployment_events`,\n`get_runtime_logs`, `list_project_domains`, `add_project_domain`, and\n`cancel_deployment` for the corresponding operations. Follow their live schemas,\nnot the removed REST argument shapes. Read deployment status before logs and\nnarrow log windows.\n\nThis complement retains `verify_project_domain`, `remove_project_domain`,\nand `delete_deployment` because the reviewed category\npages do not publish equivalent tools. Hosted `request_promote` moves an existing\nbuild to production and does not rebuild it (the rolling-releases category\nprovides the equivalent that the deployments category does not list). New deployments use hosted\n`create_deployment` or `deploy_to_vercel`.\n\n## Environment values\n\n`list_project_env_vars` never decrypts or returns values. Set `upsert: false` on\n`upsert_project_env_var` for create-only writes that refuse to overwrite. `upsert_project_env_var`,\n`update_project_env_var`, and `delete_project_env_var` return metadata without\nvalues. Create/update values are write input only. The hosted connector excludes\n`filter_project_envs`, `get_project_env`, `create_project_env`, and\n`edit_project_env`, whose published contracts lack these response protections.\nEnvironment changes apply to future deployments.\n\n## REST gaps and uploads\n\n`vercel_api_get` and `vercel_api_mutate` reach uncovered endpoints. They refuse\npaths owned by the canonical hosted or value-safe named tools, including\nproject creation/update, pause/unpause and protection bypass. Ownership covers\nthe published tool categories, not just the old reviewed classifier names;\nunreviewed live tools remain fail-closed writes. Do not use a\nraw hatch to restore a removed duplicate. `upload_file` on MCP owns deployment\nfile uploads; `vercel_api_upload` retains other raw-body endpoints and explicit\nheaders. It never reads a local file. Paths include the API version and cannot\nbe absolute URLs. Query parameters are name/value pairs; `personalAccount: true`\nomits this connection's default team. Rate-limit failures carry vendor retry timing.\n# Vercel MCP usage\n\nOfficial MCP surface: tool names, descriptions, argument schemas, and result\nschemas come from Vercel's live server. Connecta preserves retained vendor contracts and\napplies release-reviewed classification. Reviewed writes stay writes even when Vercel claims they only read.\n\nAccount purpose: \n\n- Hosted MCP owns discovery, deployments, logs, project-domain listing/adding,\n cancellation and file uploads. Use the separately configured REST complement\n for value-safe project environment variables, uncovered lifecycle/domain\n operations and REST gaps. It has its own connector id and credential.\n- Discover the live catalog before assuming a tool exists. Vercel can change\n the surface independently of a Connecta release, and account features may\n affect what the authorization can reach.\n- Complete authorization and grant access to the owning team before acting. Listing this server does not prove team access. A configured API `teamId` is a routing default, not an authorization boundary.\n- MCP pagination and arguments follow the live MCP schemas; do not apply API pagination or argument shapes to them.\n- Resolve team, project, deployment, run, thread, and order ids with the list\n and get tools. Do not guess opaque ids.\n- Diagnose deployments with `get_deployment`, then build logs, runtime error\n clusters, and runtime logs. Narrow time windows before raising result limits.\n- Purchase tools change billing. Read a quote first and carry its price,\n idempotency key, and requested term into the confirmed purchase unchanged.\n- `get_access_to_vercel_url` creates a temporary access grant. Treat the URL\n it returns as a credential and do not expose it outside the requested task.\n- `deploy_to_vercel` and `import-claude-design-from-url` can create or update\n live projects. Read the target and deployment mode before invoking them.\n- An `auth_required` failure means this connector's OAuth grant is missing or\n expired. Run `authorize_connector` for this connector id, then retry.\n",
3
+ "content": "- Resolve team, project, and deployment ids with list reads; never guess one. Team ids begin `team_`, project ids `prj_`, and deployment ids `dpl_`.\n- Diagnose a deployment by reading its state first (`readyState`, `errorCode`, `errorMessage`), then its build logs, then runtime logs for a deployment that built. Narrow time windows before raising limits.\n- Environment variable changes apply only to future deployments; a new deployment is a separate write. Promoting an existing deployment to production does not rebuild it.\n- Treat every create, update, delete, promotion, cancellation, and purchase as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n",
4
4
  "instructionsHeading": "Account instructions",
5
5
  "fragments": {
6
- "guide_0": "`. Every named account-scoped tool accepts a `teamId` override; pass `null` to target the token owner's personal account.",
7
- "guide_1": "\n## REST complement routing\n\nHosted MCP is the default. Configure this complement with `surface: \"api\"`\nand a separate connector id and access-token credential. OAuth and API-token\nstores are independent; failures never switch identity or replay a write.\nTeam defaults route calls and do not constrain the token's permissions.\n\nUse hosted `list_teams`, `list_projects`, `get_project`, `list_deployments`,\n`get_deployment`, `get_deployment_build_logs` or `list_deployment_events`,\n`get_runtime_logs`, `list_project_domains`, `add_project_domain`, and\n`cancel_deployment` for the corresponding operations. Follow their live schemas,\nnot the removed REST argument shapes. Read deployment status before logs and\nnarrow log windows.\n\nThis complement retains `verify_project_domain`, `remove_project_domain`,\nand `delete_deployment` because the reviewed category\npages do not publish equivalent tools. Hosted `request_promote` moves an existing\nbuild to production and does not rebuild it (the rolling-releases category\nprovides the equivalent that the deployments category does not list). New deployments use hosted\n`create_deployment` or `deploy_to_vercel`.\n\n## Environment values\n\n`list_project_env_vars` never decrypts or returns values. Set `upsert: false` on\n`upsert_project_env_var` for create-only writes that refuse to overwrite. `upsert_project_env_var`,\n`update_project_env_var`, and `delete_project_env_var` return metadata without\nvalues. Create/update values are write input only. The hosted connector excludes\n`filter_project_envs`, `get_project_env`, `create_project_env`, and\n`edit_project_env`, whose published contracts lack these response protections.\nEnvironment changes apply to future deployments.\n\n## REST gaps and uploads\n\n`vercel_api_get` and `vercel_api_mutate` reach uncovered endpoints. They refuse\npaths owned by the canonical hosted or value-safe named tools, including\nproject creation/update, pause/unpause and protection bypass. Ownership covers\nthe published tool categories, not just the old reviewed classifier names;\nunreviewed live tools remain fail-closed writes. Do not use a\nraw hatch to restore a removed duplicate. `upload_file` on MCP owns deployment\nfile uploads; `vercel_api_upload` retains other raw-body endpoints and explicit\nheaders. It never reads a local file. Paths include the API version and cannot\nbe absolute URLs. Query parameters are name/value pairs; `personalAccount: true`\nomits this connection's default team. Rate-limit failures carry vendor retry timing.\n",
8
- "guide_2": "# Vercel MCP usage\n\nOfficial MCP surface: tool names, descriptions, argument schemas, and result\nschemas come from Vercel's live server. Connecta preserves retained vendor contracts and\napplies release-reviewed classification. Reviewed writes stay writes even when Vercel claims they only read.\n\nAccount purpose: ",
9
- "guide_3": "\n\n- Hosted MCP owns discovery, deployments, logs, project-domain listing/adding,\n cancellation and file uploads. Use the separately configured REST complement\n for value-safe project environment variables, uncovered lifecycle/domain\n operations and REST gaps. It has its own connector id and credential.\n- Discover the live catalog before assuming a tool exists. Vercel can change\n the surface independently of a Connecta release, and account features may\n affect what the authorization can reach.\n- Complete authorization and grant access to the owning team before acting. Listing this server does not prove team access. A configured API `teamId` is a routing default, not an authorization boundary.\n- MCP pagination and arguments follow the live MCP schemas; do not apply API pagination or argument shapes to them.\n- Resolve team, project, deployment, run, thread, and order ids with the list\n and get tools. Do not guess opaque ids.\n- Diagnose deployments with `get_deployment`, then build logs, runtime error\n clusters, and runtime logs. Narrow time windows before raising result limits.\n- Purchase tools change billing. Read a quote first and carry its price,\n idempotency key, and requested term into the confirmed purchase unchanged.\n- `get_access_to_vercel_url` creates a temporary access grant. Treat the URL\n it returns as a credential and do not expose it outside the requested task.\n- `deploy_to_vercel` and `import-claude-design-from-url` can create or update\n live projects. Read the target and deployment mode before invoking them.\n- An `auth_required` failure means this connector's OAuth grant is missing or\n expired. Run `authorize_connector` for this connector id, then retry.\n"
6
+ "oauth": "\n\nTool names, descriptions, argument schemas, and result schemas come from Vercel's live server. Connecta applies release-reviewed classification; reviewed writes stay writes even when Vercel claims they only read.\n\n- Discover the live catalog before assuming a tool exists. Vercel can change the surface independently of a Connecta release, and account features may affect what the authorization can reach.\n- Complete authorization and grant access to the owning team before acting. Listing this server does not prove team access.\n- MCP pagination and arguments follow the live MCP schemas; do not apply REST pagination or argument shapes to them.\n- Diagnose deployments with `get_deployment`, then build logs, runtime error clusters, and runtime logs.\n- `get_project_env` and `filter_project_envs` can return decrypted environment values, so Connecta reviews them as writes and the pool's trust policy gates them. Prefer reading variable keys and targets without values.\n- Purchase tools change billing. Read a quote first and carry its price, idempotency key, and requested term into the confirmed purchase unchanged.\n- `get_access_to_vercel_url` creates a temporary access grant. Treat the URL it returns as a credential and do not expose it outside the requested task.\n- `deploy_to_vercel` and `import-claude-design-from-url` can create or update live projects. Read the target and deployment mode before invoking them.\n- An `auth_required` failure means this connector's OAuth grant is missing or expired. Run `authorize_connector` for this connector id, then retry.\n",
7
+ "key": "\n\n- This is Connecta's REST connector to `api.vercel.com`, holding one operator-managed access token. A default team routes calls; it does not narrow what the token can reach.\n- `vercel_api_search` finds API operations, not records: it searches the pinned API index and names the tool that calls each operation. `vercel_api_details` returns one operation's parameters with types, enums, and required names. Neither sends a request.\n- `vercel_api_read` calls GET operations, plus reviewed POSTs that only read: `POST /v2/observability/query`, registrar availability, price, and search, and `POST /v8/artifacts`. `vercel_api_write` calls every other POST, PUT, PATCH, and DELETE, with `method` and `path` stated; execution follows the configured pool trust policy.\n- Paths are concrete and carry the version search returned: `/v13/deployments/dpl_123`, not `/deployments/dpl_123`. Pass `query` and `body` as JSON objects named as `vercel_api_details` lists them. Every call is checked against the pinned index before it is sent: an unknown path returns the nearest operations, and an unknown or missing parameter returns `validation.issues` with the accepted names. Nothing reached Vercel, so fix the call from that answer.\n- Results arrive as `{ status, data, page? }`. On a list, `page.next` is the cursor and `page.param` the query parameter to pass it as: `until` (a millisecond timestamp from `pagination.next`) on most lists, `cursor` on newer ones. Lists belong inside `execute_code`; pass `select` (dot paths such as `deployments.uid` and `deployments.state`) to keep only the fields the question needs.\n- `list_teams` returns team ids and slugs and the connection's default team. `get_deployment_build_logs` reads a deployment's build events without following live output. `get_runtime_logs` collects the runtime log stream for at most `waitMs` or `maxRows`, then stops and says why. Generic reads refuse `follow` and the runtime-log stream, which never end on their own.\n- `vercel_api_upload` sends explicit text or base64 bytes to an octet-stream operation, such as `POST /v2/files` before a deployment (Connecta computes `x-vercel-digest`). `vercel_api_write` sends JSON only.\n- Environment values never come back. `list_project_env_vars` never decrypts. `upsert_project_env_var` (`upsert: false` for create-only), `update_project_env_var`, and `delete_project_env_var` return metadata without values; values are write input only. Generic reads refuse `GET /v1/projects/{idOrName}/env/{id}`, `GET /v10/projects/{idOrName}/env`, `GET /v1/env/{id}`, and any `decrypt`, and Connecta replaces the value of every environment variable in any result with `\"[redacted]\"`, including project reads, shared variables, and audit events.\n- Other secrets read as `[redacted]` in every result: credential-named fields and their whole contents (`token`, `secret`, `password`, `jwt`, `credentials`, `Authorization`, …), protection-bypass secrets (each bypass's metadata stays under a numbered placeholder), deploy hook URLs, drain and webhook headers and signing secrets (including the one a new webhook or drain returns), drain and webhook destination URLs and external route, rewrite, and redirect destinations beyond their scheme and host, the args and values of every header, cookie, and query rule (route transforms and conditions, firewall conditions), team invite codes, synced Global Config items, and credentials inside other URLs. Failures of every reviewed operation, and of any operation whose request takes a credential-named field, say only the status and a reviewed code. Read or rotate withheld secrets in the Vercel dashboard. A `[redacted]` field is never the real value; do not send it back.\n- Refused by design: endpoints that mint credentials (access tokens, AI Gateway API keys, project OIDC and trace tokens, Connect and SSO tokens, Edge Config tokens, KMS-signed tokens, Flags SDK keys, protection-bypass secrets, installation credential rotation), Connect authorization requests, project transfer requests (the code lets another team claim the project), KMS signing, a domain move-out (its answer is a transfer token), Global Config items, backups, and tokens, and domain transfer auth codes. Each refusal names its reason.\n- The hosted OAuth connection's documentation search, runtime error clusters, toolbar threads, agent runs, web analytics summaries, purchase quotes, `deploy_to_vercel`, and access grants for protected URLs do not exist with a token. Configure an OAuth connector for those.\n- A `429` carries Vercel's reset time; Vercel meters endpoints separately, so wait before retrying the same operation. An `auth_required` failure means the token is missing, expired, or outside this team: an operator must replace it in this connection in the operator UI, and `authorize_connector` returns that handoff. A rejected argument comes back in Vercel's own words; read it rather than replacing the token.\n",
8
+ "shared": "- Resolve team, project, and deployment ids with list reads; never guess one. Team ids begin `team_`, project ids `prj_`, and deployment ids `dpl_`.\n- Diagnose a deployment by reading its state first (`readyState`, `errorCode`, `errorMessage`), then its build logs, then runtime logs for a deployment that built. Narrow time windows before raising limits.\n- Environment variable changes apply only to future deployments; a new deployment is a separate write. Promoting an existing deployment to production does not rebuild it.\n- Treat every create, update, delete, promotion, cancellation, and purchase as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n"
10
9
  }
11
10
  };
@@ -0,0 +1,328 @@
1
+ // Vercel's reviewed value-safety table (decision 0005, "Value safety"), on the
2
+ // shared mechanism in `../_shared/rest/value-safety.ts`.
3
+ //
4
+ // No tool response, success or error, returns a credential (API, service, or
5
+ // bypass tokens, signing secrets, deploy-hook and other bearer URLs, private
6
+ // keys, authorization verifiers, auth headers) or a stored secret value
7
+ // (environment variables, Global Config items), unless a reviewed named tool
8
+ // exists to return it. Three layers, strongest first:
9
+ //
10
+ // 1. Refuse by operation. `scripts/value-safety.mjs` flags every operation in
11
+ // the pinned spec whose response may carry one (committed as
12
+ // `value-safety.candidates.json`); each needs a verdict here, and
13
+ // `value-safety.node.test.ts` runs the shared harness over this table.
14
+ // 2. Reviewed field paths for `redact` verdicts, applied to every success body
15
+ // on every path (generic tools, HEAD data, named tools, logs, uploads)
16
+ // before cursors or `select` read it. Every reviewed operation, and every
17
+ // one whose request accepts a credential-named field, also answers
18
+ // failures with fixed messages, never the vendor's text.
19
+ // 3. The shared key-name heuristic, defense in depth only, over every body:
20
+ // any subtree under a credential-named key, labelled key/value records
21
+ // whose label is credential-named, environment-variable containers, and
22
+ // URLs with userinfo or credential query parameters.
23
+ //
24
+ // Residual risk, as with Infisical: a secret a person typed into a free-text
25
+ // name, description, log line, or identifier is out of scope.
26
+ import { redact, refuse as refusal, safe, under, } from "../_shared/rest/value-safety.js";
27
+ /** A refusal's reason reads as a sentence about the operation: "It mints …". */
28
+ const refuse = (reason) => refusal(`It ${reason}`);
29
+ /** A project object: env values, deploy hooks, and protection-bypass secrets. */
30
+ const PROJECT = [
31
+ "env[].value",
32
+ "env[].vsmValue",
33
+ "env[].legacyValue",
34
+ "link.deployHooks[].url",
35
+ "protectionBypass@keys",
36
+ // Header, cookie, and query conditions on internal and firewall routes.
37
+ "internalRoutes[].has[?header].value",
38
+ "internalRoutes[].missing[?header].value",
39
+ "security.firewallRoutes[].has[?header].value",
40
+ "security.firewallRoutes[].missing[?header].value",
41
+ ];
42
+ /** Project metadata whose names contain a credential word. */
43
+ const PROJECT_ALLOW = [
44
+ "protectionBypass",
45
+ "oidcTokenConfig",
46
+ "security.firewallBypassIps",
47
+ "usageStatus.bypassThrottleUntil",
48
+ "dismissedToasts[].value",
49
+ ];
50
+ const DRAIN = [
51
+ "delivery.secret",
52
+ "delivery.headers{}",
53
+ "origin:delivery.endpoint",
54
+ "origin:delivery.endpoint.traces",
55
+ "secret",
56
+ "headers{}",
57
+ "origin:url",
58
+ ];
59
+ const SHARED_ENV = ["data[].value", "created[].value", "updated[].value", "failed[].error.value"];
60
+ const PROJECT_ENV = ["value", "legacyValue", "vsmValue", "[].value", "[].legacyValue"];
61
+ const CONNECTOR_ALLOW = ["appTokens", "userTokens"];
62
+ const PROJECT_REASON = "Project objects embed environment values, deploy hook URLs, and protection-bypass secrets.";
63
+ const DRAIN_REASON = "Drains store destination credentials (headers, URLs whose path or query can be a bearer secret) and a signing secret.";
64
+ const WEBHOOK = ["secret", "origin:url"];
65
+ const WEBHOOK_REASON = "Webhooks carry a signing secret and a destination URL whose path can be a bearer secret.";
66
+ /** Route rules: a transform that sets a credential-named header carries the credential in `args`. */
67
+ /**
68
+ * Route rules: every header, cookie, or query transform's `args` and every
69
+ * header, cookie, or query condition's `value` go, whatever the target key's
70
+ * form (a string, or a predicate object such as `{ eq: "Authorization" }`);
71
+ * a header-name list would always miss one (`X-Auth-Key`).
72
+ */
73
+ const ROUTE_TRANSFORMS = [
74
+ "transforms[].args",
75
+ "has[?header].value",
76
+ "missing[?header].value",
77
+ // Headers a route sets, and the locale cookie it reads (its name is credential vocabulary).
78
+ "headers{}",
79
+ "locale.cookie",
80
+ ];
81
+ const DEPLOYMENT = [
82
+ ...under(["routes[]", "services[].routes[]", "services[].rewrites[]", "services[].redirects[]"], ROUTE_TRANSFORMS),
83
+ "services[].headers[].headers[].value",
84
+ "services[].headers[].has[?header].value",
85
+ "services[].headers[].missing[?header].value",
86
+ ];
87
+ const DEPLOYMENT_REASON = "Deployment routes can set credential-named headers (transforms with target.key Authorization) whose args are the credential.";
88
+ const ROUTE_REASON = "Route transforms can set credential-named headers whose args are the credential.";
89
+ const ENV_REASON = "Environment-variable bodies carry decrypted or encrypted values.";
90
+ const NO_SECRET_REASON = "Answers status or nothing; the flag is the operation's name, not its response.";
91
+ const EDGE_ITEMS = "returns Global Config item values, which may be secrets; read them from your application with the Edge Config SDK.";
92
+ const MINT = "mints a credential and returns it in cleartext.";
93
+ const MODEL_CONFIG = "AI Gateway routing configuration; its descriptions mention tokens as model usage units.";
94
+ const KMS_POLICY = "Issuer policies name environments and claims; signing keys stay with Vercel.";
95
+ /** A firewall rule's header, cookie, and query conditions: their values can be credentials (an `X-Auth-Key` match). */
96
+ const FIREWALL_CONDITIONS = [
97
+ "conditionGroup[].conditions[?header].value",
98
+ "conditionGroup[].conditions[?header].values",
99
+ ];
100
+ /** Every firewall config shape: rules, rulesets, and top-level conditions, active, draft, and versions. */
101
+ const FIREWALL = under(["rules[]", "rulesets[]", "conditions[]"], FIREWALL_CONDITIONS);
102
+ const FIREWALL_REASON = "Firewall rules match header, cookie, and query values, which can be credentials a rule checks for (an X-Auth-Key).";
103
+ const TEAM_INVITE = "Teams carry inviteCode, which lets its holder join the team (visible to owners).";
104
+ /**
105
+ * The reviewed verdict for every flagged operation, keyed `METHOD /path`.
106
+ * `refuse` is never sent by the generic tools; named tools that need one of
107
+ * these operations project it themselves (value-safe environment variables).
108
+ */
109
+ const VALUE_SAFETY = {
110
+ "PATCH /aliases/{id}/protection-bypass": refuse("creates a shareable link that bypasses Deployment Protection."),
111
+ "POST /api-keys": refuse("mints an AI Gateway API key and returns it in cleartext."),
112
+ "POST /v1/connect/authorize/{connector}": refuse("starts a Connect authorization for a caller-chosen subject and returns its verifier and device code."),
113
+ "POST /v1/connect/connectors": safe("Connector capability metadata; appTokens and userTokens describe grants, not tokens.", CONNECTOR_ALLOW),
114
+ "GET /v1/connect/connectors/{connector}": safe("Connector capability metadata.", CONNECTOR_ALLOW),
115
+ "POST /v1/connect/connectors/{connector}/managed/eject": safe("Connector capability metadata.", CONNECTOR_ALLOW),
116
+ "PATCH /v1/connect/connectors/{connector}/trigger-destinations": safe("Connector capability metadata.", CONNECTOR_ALLOW),
117
+ "GET /v2/connect/connectors": safe("Connector capability metadata.", under(["connectors[]"], CONNECTOR_ALLOW)),
118
+ "PATCH /v2/connect/connectors/{connector}": safe("Connector capability metadata.", under(["connector"], CONNECTOR_ALLOW)),
119
+ "POST /v1/connect/token/{connector}": refuse("mints a token for a Connect connector."),
120
+ "GET /v1/drains": redact(DRAIN_REASON, under(["drains[]"], DRAIN)),
121
+ "POST /v1/drains": redact(DRAIN_REASON, DRAIN),
122
+ "POST /v1/drains/test": redact("Answers a delivery test; treated as part of the drain family.", DRAIN),
123
+ "GET /v1/drains/{id}": redact(DRAIN_REASON, DRAIN),
124
+ "PATCH /v1/drains/{id}": redact(DRAIN_REASON, DRAIN),
125
+ "DELETE /v1/drains/{id}": safe(NO_SECRET_REASON),
126
+ "GET /v1/log-drains": redact(DRAIN_REASON, under(["drains[]", "[]"], DRAIN)),
127
+ "POST /v1/log-drains": redact(DRAIN_REASON, DRAIN),
128
+ "GET /v1/log-drains/{id}": redact(DRAIN_REASON, DRAIN),
129
+ "DELETE /v1/log-drains/{id}": safe(NO_SECRET_REASON),
130
+ "GET /v2/integrations/log-drains": redact(DRAIN_REASON, under(["[]"], DRAIN)),
131
+ "POST /v2/integrations/log-drains": redact(DRAIN_REASON, DRAIN),
132
+ "DELETE /v1/integrations/log-drains/{id}": safe(NO_SECRET_REASON),
133
+ "GET /v1/webhooks": redact(WEBHOOK_REASON, under(["[]", "webhooks[]"], WEBHOOK)),
134
+ "POST /v1/webhooks": redact(WEBHOOK_REASON, WEBHOOK),
135
+ "GET /v1/webhooks/{id}": redact(WEBHOOK_REASON, WEBHOOK),
136
+ "DELETE /v1/webhooks/{id}": safe(NO_SECRET_REASON),
137
+ "GET /v1/env": redact(ENV_REASON, SHARED_ENV),
138
+ "POST /v1/env": redact(ENV_REASON, SHARED_ENV),
139
+ "PATCH /v1/env": redact(ENV_REASON, SHARED_ENV),
140
+ "DELETE /v1/env": redact(ENV_REASON, SHARED_ENV),
141
+ "GET /v1/env/{id}": refuse("returns a shared environment variable's decrypted value."),
142
+ "PATCH /v1/env/{id}/unlink/{projectId}": redact(ENV_REASON, ["value"]),
143
+ "GET /v1/global-config": safe("Global Config metadata: ids, slugs, sizes, and digests, without items."),
144
+ "POST /v1/global-config": safe("Answers the created Global Config's metadata."),
145
+ "GET /v1/global-config/{edgeConfigId}": safe("Global Config metadata without items."),
146
+ "PUT /v1/global-config/{edgeConfigId}": safe("Answers the updated Global Config's metadata."),
147
+ "DELETE /v1/global-config/{edgeConfigId}": safe(NO_SECRET_REASON),
148
+ "GET /v1/global-config/{edgeConfigId}/backups": safe("Lists backup versions and sizes, without items."),
149
+ "GET /v1/global-config/{edgeConfigId}/backups/{edgeConfigBackupVersionId}": refuse(EDGE_ITEMS),
150
+ "POST /v1/global-config/{edgeConfigId}/backups/{edgeConfigBackupVersionId}/restore": safe(NO_SECRET_REASON),
151
+ "GET /v1/global-config/{edgeConfigId}/item/{edgeConfigItemKey}": refuse(EDGE_ITEMS),
152
+ "GET /v1/global-config/{edgeConfigId}/items": refuse(EDGE_ITEMS),
153
+ "PATCH /v1/global-config/{edgeConfigId}/items": safe("Answers a status; item values are write input only."),
154
+ "GET /v1/global-config/{edgeConfigId}/schema": safe("A JSON Schema for items, without values."),
155
+ "POST /v1/global-config/{edgeConfigId}/schema": safe("Answers the schema, without values."),
156
+ "DELETE /v1/global-config/{edgeConfigId}/schema": safe(NO_SECRET_REASON),
157
+ "POST /v1/global-config/{edgeConfigId}/token": refuse(MINT),
158
+ "GET /v1/global-config/{edgeConfigId}/token/{token}": refuse("returns a Global Config read token."),
159
+ "GET /v1/global-config/{edgeConfigId}/tokens": refuse("returns every Global Config read token in cleartext."),
160
+ "DELETE /v1/global-config/{edgeConfigId}/tokens": safe(NO_SECRET_REASON),
161
+ "GET /v1/installations/{integrationConfigurationId}/resources/{resourceId}/experimentation/global-config": refuse(EDGE_ITEMS),
162
+ "PUT /v1/installations/{integrationConfigurationId}/resources/{resourceId}/experimentation/global-config": redact("Answers the synced Global Config, items included; item values can be secrets.", ["items"]),
163
+ "HEAD /v1/installations/{integrationConfigurationId}/resources/{resourceId}/experimentation/global-config": safe("Headers only; the heuristic still covers them."),
164
+ "POST /v1/installations/{integrationConfigurationId}/credentials/revoke": safe(NO_SECRET_REASON),
165
+ "POST /v1/installations/{integrationConfigurationId}/credentials/rotate": refuse("rotates an installation credential and returns the new access token."),
166
+ "PUT /v1/installations/{integrationConfigurationId}/resources/{resourceId}/secrets": safe("Answers nothing; secrets are write input only."),
167
+ "POST /v1/integrations/sso/token": refuse("exchanges an integration SSO code for access, ID, and refresh tokens."),
168
+ "POST /v1/kms/issuers/{issuerId}/keys": safe("Answers public key material and key metadata; private keys stay with Vercel."),
169
+ "POST /v1/kms/issuers/{issuerId}/keys/{keyId}/activate": safe("Answers key metadata."),
170
+ "POST /v1/kms/issuers/{issuerId}/keys/{keyId}/revoke": safe("Answers issuer metadata; tokenClaims are policy, not tokens."),
171
+ "POST /v1/kms/issuers/{issuerId}/sign/message": refuse("signs a message with the issuer's private key, acting as the organization."),
172
+ "POST /v1/kms/issuers/{issuerId}/sign/token": refuse("signs a token with the issuer's private key."),
173
+ "GET /v1/microfrontends/groups/{groupId}/projects": redact(PROJECT_REASON, under(["projects[]"], PROJECT), under(["projects[]"], PROJECT_ALLOW)),
174
+ "POST /v1/projects/traces/session": refuse("mints a trace session token for a deployment."),
175
+ "POST /v1/projects/{idOrName}/avatar": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
176
+ "DELETE /v1/projects/{idOrName}/avatar": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
177
+ "DELETE /v1/projects/{idOrName}/env": redact(ENV_REASON, PROJECT_ENV),
178
+ "GET /v1/projects/{idOrName}/env/{id}": refuse("returns one environment variable's decrypted value. Read its metadata with list_project_env_vars."),
179
+ "PATCH /v1/projects/{idOrName}/protection-bypass": refuse("generates Protection Bypass for Automation secrets."),
180
+ "POST /v1/projects/{idOrName}/token": refuse("mints a project OIDC token."),
181
+ "GET /v1/projects/{projectIdOrName}/feature-flags/sdk-keys": safe("Lists SDK key metadata with masked partialKeyValue."),
182
+ "PUT /v1/projects/{projectIdOrName}/feature-flags/sdk-keys": refuse("mints a Flags SDK key and returns it in cleartext."),
183
+ "DELETE /v1/projects/{projectIdOrName}/feature-flags/sdk-keys/{hashKey}": safe(NO_SECRET_REASON),
184
+ "PATCH /v1/projects/{projectId}/microfrontends": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
185
+ "GET /v1/projects/{projectId}/routes": redact(ROUTE_REASON, under(["routes[].route"], ROUTE_TRANSFORMS)),
186
+ "POST /v1/projects/{projectId}/routes": redact(ROUTE_REASON, under(["route.route"], ROUTE_TRANSFORMS)),
187
+ "POST /v1/projects/{projectId}/routes/generate": redact(ROUTE_REASON, [
188
+ ...under(["route"], ROUTE_TRANSFORMS),
189
+ "route.actions[].headers[].value",
190
+ "route.conditions[?header].value",
191
+ ]),
192
+ "PATCH /v1/projects/{projectId}/routes/{routeId}": redact(ROUTE_REASON, under(["route.route"], ROUTE_TRANSFORMS)),
193
+ "GET /v1/registrar/domains/{domain}/auth-code": refuse("returns the domain's transfer authorization code, which lets its holder move the domain to another registrar."),
194
+ "GET /v1/security/firewall/bypass": safe("IP bypass rules are firewall configuration: addresses, not secrets."),
195
+ "POST /v1/security/firewall/bypass": safe("IP bypass rules are firewall configuration."),
196
+ "DELETE /v1/security/firewall/bypass": safe("IP bypass rules are firewall configuration."),
197
+ "GET /v1/security/firewall/config": redact(FIREWALL_REASON, under(["active", "draft", "versions[]"], FIREWALL)),
198
+ "PUT /v1/security/firewall/config": redact(FIREWALL_REASON, under(["active", "draft", "versions[]"], FIREWALL)),
199
+ "POST /v1/security/firewall/config/generate-rule": redact(FIREWALL_REASON, under(["rule"], FIREWALL_CONDITIONS)),
200
+ "GET /v1/security/firewall/config/{configVersion}": redact(FIREWALL_REASON, FIREWALL),
201
+ "POST /v1/security/firewall/config/{configVersion}/activate": redact(FIREWALL_REASON, FIREWALL),
202
+ "POST /v1/storage/stores/integration/direct": safe("store.secrets lists secret names and lengths, never values.", [
203
+ "store.secrets",
204
+ "store.secretRotationRequestedBy",
205
+ "store.secretRotationRequestedReason",
206
+ ]),
207
+ "GET /v1/vcr/repository/{idOrName}/images/{imageIdOrDigest}": redact("Image layer environment entries are build-time NAME=value pairs.", ["image.layers[].env"]),
208
+ "GET /v10/projects": redact(PROJECT_REASON, under(["projects[]", "[]"], PROJECT), under(["projects[]", "[]"], PROJECT_ALLOW)),
209
+ "GET /v10/projects/{idOrName}/env": refuse("returns environment values beside their metadata. Use list_project_env_vars, which never decrypts or returns a value."),
210
+ "POST /v10/projects/{idOrName}/env": redact(ENV_REASON, [
211
+ "created.value",
212
+ "created.vsmValue",
213
+ "created.legacyValue",
214
+ "created[].value",
215
+ "created[].vsmValue",
216
+ "created[].legacyValue",
217
+ "failed[].error.value",
218
+ ]),
219
+ "POST /v11/projects": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
220
+ "PATCH /v12/deployments/{id}/cancel": redact(DEPLOYMENT_REASON, DEPLOYMENT),
221
+ "POST /v13/deployments": redact(DEPLOYMENT_REASON, DEPLOYMENT),
222
+ "GET /v13/deployments/{idOrUrl}": redact(DEPLOYMENT_REASON, DEPLOYMENT),
223
+ "GET /v2/deployments/{id}/aliases": redact("Aliases carry protection-bypass secrets as map keys.", ["aliases[].protectionBypass@keys"], ["aliases[].protectionBypass"]),
224
+ "POST /v2/deployments/{id}/aliases": safe("Answers the alias assignment."),
225
+ "GET /v2/user": safe("ipBypass lists firewall IP rules, not secrets.", ["user.resourceConfig.security.ipBypass"]),
226
+ "PATCH /v3/domains/{domain}": redact("A move-out answers a transfer token; Connecta refuses move-out by body, and redacts any token.", ["token"]),
227
+ "GET /v3/events": redact("Audit events carry environment variables (with or without key or type) and credential metadata in payloads.", [
228
+ "events[].payload.newEnvVar.value",
229
+ "events[].payload.oldEnvVar.value",
230
+ "events[?env].payload.value",
231
+ "events[?env].payload.vsmValue",
232
+ "events[].payload.apiKey",
233
+ "events[].payload.credential",
234
+ "events[].payload.inviteCode",
235
+ "events[].payload.gitCredentialSource",
236
+ ]),
237
+ "POST /v3/user/tokens": refuse("mints a Vercel access token."),
238
+ "DELETE /v3/user/tokens/{tokenId}": safe(NO_SECRET_REASON),
239
+ "GET /v4/aliases": redact("Aliases carry protection-bypass secrets as map keys.", ["aliases[].protectionBypass@keys"], ["aliases[].protectionBypass"]),
240
+ "GET /v4/aliases/{idOrAlias}": redact("Aliases carry protection-bypass secrets as map keys.", ["protectionBypass@keys"], ["protectionBypass"]),
241
+ "GET /v5/user/tokens/{tokenId}": safe("Answers token metadata (`token` is an object of ids, prefix, suffix, and scopes).", ["token"]),
242
+ "GET /v6/user/tokens": safe("Lists token metadata, never token values.", ["tokens"]),
243
+ "GET /v9/projects/{idOrName}": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
244
+ "PATCH /v9/projects/{idOrName}": redact(PROJECT_REASON, PROJECT, PROJECT_ALLOW),
245
+ "PATCH /v9/projects/{idOrName}/env/{id}": redact(ENV_REASON, PROJECT_ENV),
246
+ "DELETE /v9/projects/{idOrName}/env/{id}": redact(ENV_REASON, PROJECT_ENV),
247
+ // Flagged by description or a transfer/claim/invite family (round 3).
248
+ "POST /projects/{idOrName}/transfer-request": refuse("returns a code that lets another team claim the project for 24 hours."),
249
+ "PUT /projects/transfer-request/{code}": safe("Accepts a transfer with a code the caller holds; answers transfer results."),
250
+ "GET /ai-gateway/virtual-model-configs": safe(MODEL_CONFIG),
251
+ "POST /ai-gateway/virtual-model-configs": safe(MODEL_CONFIG),
252
+ "PATCH /ai-gateway/virtual-model-configs": safe(MODEL_CONFIG),
253
+ "GET /ai-gateway/virtual-model-configs/list": safe(MODEL_CONFIG),
254
+ "GET /ai-gateway/virtual-model-configs/{vmcSlug}": safe(MODEL_CONFIG),
255
+ "PATCH /ai-gateway/virtual-model-configs/{vmcSlug}": safe(MODEL_CONFIG),
256
+ "GET /v1/ai-gateway/routers": safe(MODEL_CONFIG),
257
+ "POST /storage/stores/blob": safe("store.kind names the store type; no token is returned."),
258
+ "GET /storage/stores/{id}": safe("A store's metadata; projectsMetadata lists environment variable names, not values."),
259
+ "GET /v1/installations/{integrationConfigurationId}/resources/{resourceId}": safe("customClaims are OIDC claim configuration, not tokens."),
260
+ "GET /v1/integrations/configuration/{id}/products": redact("protocols.authentication describes supported auth flows, not credentials; a product's log and trace drain protocols carry destination headers.", [
261
+ "products[].protocols.logDrain.headers{}",
262
+ "products[].protocols.traceDrain.headers{}",
263
+ "origin:products[].protocols.logDrain.endpoint",
264
+ "origin:products[].protocols.traceDrain.endpoint",
265
+ ]),
266
+ "GET /v1/kms/issuers": safe(KMS_POLICY),
267
+ "POST /v1/kms/issuers": safe(KMS_POLICY),
268
+ "GET /v1/kms/issuers/{issuerId}": safe(KMS_POLICY),
269
+ "PATCH /v1/kms/issuers/{issuerId}": safe(KMS_POLICY),
270
+ "POST /v1/kms/issuers/{issuerId}/policies": safe(KMS_POLICY),
271
+ "PATCH /v1/kms/issuers/{issuerId}/policies/{kind}/{policyKey}": safe(KMS_POLICY),
272
+ "GET /v1/registrar/domains/{domain}/transfer": safe("Answers a transfer-in status only."),
273
+ "POST /v1/registrar/domains/{domain}/transfer": safe("Answers an order id; the auth code is request input only."),
274
+ "DELETE /v1/teams/{teamId}/invites/{inviteId}": safe(NO_SECRET_REASON),
275
+ "GET /v2/teams": redact(TEAM_INVITE, ["teams[].inviteCode"]),
276
+ "GET /v2/teams/{teamId}": redact(TEAM_INVITE, ["inviteCode"]),
277
+ "PATCH /v2/teams/{teamId}": redact(TEAM_INVITE, ["inviteCode"]),
278
+ "GET /v3/teams/{teamId}/members": safe("emailInviteCodes lists pending invitations (email, role, expiry) without codes.", ["emailInviteCodes"]),
279
+ "POST /v2/teams/{teamId}/members": safe("Answers the invited email, role, and permissions; no invite link or code."),
280
+ "POST /v7/domains": safe("Answers the added domain's metadata."),
281
+ "POST /v9/domains/{domain}/claim": safe("Claims by verified TXT record and answers domain metadata; issues nothing."),
282
+ };
283
+ /**
284
+ * Vercel's reviewed table. Environment-variable endpoints answer bodies that
285
+ * are environment variables whether or not each carries a `key`, so their
286
+ * values go whole; `permissions` maps list action scopes under resource
287
+ * names, which the heuristic leaves.
288
+ */
289
+ export const VERCEL_VALUE_SAFETY = {
290
+ title: "Vercel",
291
+ operations: VALUE_SAFETY,
292
+ envBodies: /^\/v\d+\/(?:env(?:\/|$)|projects\/\{[^}]+\}\/env(?:\/|$))/,
293
+ scopeMaps: ["permissions"],
294
+ fields: Object.fromEntries([
295
+ ["env", "Environment names and variable-name lists; values inside environment containers go structurally."],
296
+ ["environments", "Environment slugs or ids a policy or variable applies to."],
297
+ ["environmentVariables", "Environment variable names a store connects, never values."],
298
+ ["type", "A variable's or record's type (plain, encrypted, sensitive, secret)."],
299
+ ["visibility", "A variable's visibility setting."],
300
+ ["keys", "Rate-limit key kinds (ip, ja4) and changed variable names."],
301
+ ["logHeaders", "Header names a firewall rule logs."],
302
+ ["log_headers", "Header names the firewall logs."],
303
+ ["signingKeys", "KMS signing key metadata and public key material; private keys stay with Vercel."],
304
+ ["bindings", "Service-to-service binding names and targets."],
305
+ ["canaryResponseHeader", "Whether a canary response sets a header; a boolean."],
306
+ ["inferenceRegion", "An AI Gateway routing region."],
307
+ ["providerTimeouts", "Provider timeouts in milliseconds."],
308
+ ["redirectUri", "A connector's registered OAuth redirect URI, public by design."],
309
+ ["supportsRevocation", "Whether a connector can revoke tokens; a boolean."],
310
+ ["claims", "OIDC claim matchers a policy requires, not tokens."],
311
+ ["customClaims", "OIDC claim configuration, not tokens."],
312
+ ["limited", "Whether a record is limited by the token's privileges; a boolean."],
313
+ ["enforced", "Whether SAML is enforced; a boolean."],
314
+ ["kind", "A store or record kind."],
315
+ ["budget", "An AI Gateway key's spend budget."],
316
+ ["origin", "How a token was issued (manual, oauth)."],
317
+ ["scope", "A token's scope (user, team, project)."],
318
+ ["issuedBefore", "A revocation cutoff timestamp."],
319
+ ["issuerUrl", "The OIDC issuer URL, public by design."],
320
+ ["oidcSubject", "The OIDC subject claim, an identifier."],
321
+ ["next", "A pagination cursor; it grants nothing."],
322
+ ["partialKeyValue", "A masked SDK key preview."],
323
+ ["appUrlRegistrationSupport", "Whether a partner accepts app URLs; a boolean."],
324
+ ["disjunctiveProductionSecretPolicy", "A team policy setting."],
325
+ ["sensitiveEnvironmentVariablePolicy", "A team policy setting."],
326
+ ["strictPasswordProtectionSettings", "A team policy setting."],
327
+ ].map(([name, reason]) => [name, { verdict: "keep", reason }])),
328
+ };
@@ -112,7 +112,7 @@ export interface RegistryView {
112
112
  resultsStorage(): KVStorage;
113
113
  resultIdentity(): ResultIdentity;
114
114
  /** Recheck live auth/grants and pool admission before exposing stored data. */
115
- recheckResultAccess(address: string, classification: "read" | "write", signal?: AbortSignal): Promise<boolean>;
115
+ recheckResultAccess(address: string | undefined, classification: "read" | "write", signal?: AbortSignal, access?: "catalog"): Promise<boolean>;
116
116
  /** Reserve deployment-wide capacity before writing a paging envelope's chunks. */
117
117
  stashResult(id: string, chunks: readonly string[], ttlSeconds: number): Promise<boolean>;
118
118
  /** Local declared-vs-stored credential mismatch, with no downstream I/O. */
@@ -142,7 +142,7 @@ export interface RegistryScope {
142
142
  principalKey?: string;
143
143
  endpoint?: string;
144
144
  origin?: string | null;
145
- currentResultAccess?: (address: string, classification: "read" | "write", signal?: AbortSignal) => Promise<boolean>;
145
+ currentResultAccess?: (address: string | undefined, classification: "read" | "write", signal?: AbortSignal, access?: "catalog") => Promise<boolean>;
146
146
  /** The admitted caller, readable only by built-in connectors; see connector-caller.ts. */
147
147
  caller?: ConnectorCaller;
148
148
  }
@@ -241,9 +241,11 @@ export declare class Registry implements RegistryView {
241
241
  * The bounds are the deployment's, not this isolate's. Every charge is a
242
242
  * row in one ledger record in storage, booked by compare-and-set before any
243
243
  * chunk is written, so every isolate and process sharing the store sees the
244
- * same entries and bytes. A charge leaves the ledger just after its
245
- * result's deadline, which every chunk's TTL ends by; the storage TTL
246
- * reclaims the rows themselves.
244
+ * same entries and bytes. A pending write keeps its finite charge reserved.
245
+ * Writes stop after 30 seconds; absolute chunk expiries cannot pass the
246
+ * booked deadline even on late commit. Rejected responses leave writes
247
+ * unconfirmed and retain their charge. Cleanup/release and settlement each
248
+ * stop waiting after 15 seconds. Storage TTL reclaims the rows.
247
249
  */
248
250
  stashResult(id: string, chunks: readonly string[], ttlSeconds: number, partition?: string): Promise<boolean>;
249
251
  /**
@@ -251,7 +253,7 @@ export declare class Registry implements RegistryView {
251
253
  * connector's namespace. Backs connecta.result.
252
254
  */
253
255
  resultIdentity(): ResultIdentity;
254
- recheckResultAccess(_address: string, _classification: "read" | "write", _signal?: AbortSignal): Promise<boolean>;
256
+ recheckResultAccess(_address: string | undefined, _classification: "read" | "write", _signal?: AbortSignal, _access?: "catalog"): Promise<boolean>;
255
257
  resultsStorage(): KVStorage;
256
258
  credentialUiAvailable(): boolean;
257
259
  bindOAuthHandoff(id: string, authorizationUrl: string, principalKey?: string): Promise<void>;