@buildbase/sdk 0.0.53 → 0.0.54
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.
- package/AGENTS.md +11 -5
- package/CHANGELOG.md +46 -0
- package/README.md +87 -52
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +393 -33
- package/dist/index.mjs +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.d.ts +562 -8
- package/dist/mcp/index.mjs +1 -1
- package/dist/react/chunks/{SettingsDialog-Dy8W3NA6.cjs → SettingsDialog-B28WJsAr.cjs} +1 -1
- package/dist/react/chunks/{SettingsDialog-BxDYsie6.mjs → SettingsDialog-blhppbNm.mjs} +1 -1
- package/dist/react/chunks/{SubscriptionDialog-6c5dHoQd.mjs → SubscriptionDialog-BTWVX3cH.mjs} +1 -1
- package/dist/react/chunks/{SubscriptionDialog-CpVnnXJg.cjs → SubscriptionDialog-QKmwvJU1.cjs} +1 -1
- package/dist/react/chunks/react-6QJCOE-D.cjs +2 -0
- package/dist/react/chunks/react-CC6T7Zky.mjs +2 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +60 -12
- package/dist/react/index.mjs +1 -1
- package/package.json +4 -2
- package/dist/react/chunks/react-4SlWxHdh.cjs +0 -2
- package/dist/react/chunks/react-OL1uSkpr.mjs +0 -2
package/AGENTS.md
CHANGED
|
@@ -72,8 +72,8 @@ Config also accepts: `timeout`, `maxRetries`, `debug`, `headers`, `onError(err,
|
|
|
72
72
|
- **Factory:** `BuildBase` (also default export) → `{ auth, workspace, subscription, usage, credits, plans, invoices, users, features, settings, notification, permissions, withSession, client }`.
|
|
73
73
|
- **API classes:** `BaseApi` (extend for custom APIs), `AuthApi`, `UserApi`, `WorkspaceApi`, `SettingsApi`, `PushApi`.
|
|
74
74
|
- **Webhook verification (runtime-agnostic — Node, edge, Deno, Bun, browsers):** `verifyWebhookSignature`, `parseWebhookEvent`. Verify against the **raw** request body (`await req.text()`), not the parsed JSON.
|
|
75
|
-
- **Agent readiness (framework-agnostic, returns plain `DiscoveryDocument`):** **App owns discovery content, platform owns auth.** All content — `llms.txt`, `robots.txt`, `sitemap`, `protectedResources` (RFC 9728), API catalog, skills — is defined locally in `AgentReadyConfig` and served with no platform round-trip. The platform bundle (`fetchAgentReadiness`, fail-soft/cached) supplies ONLY `{ enabled, authorizationServer }` (the OAuth AS pointer). Functions: `resolveAgentPath` (dispatch ALL agent paths — root docs + `.well-known/*`; prefer for new wiring), `resolveWellKnown` (`.well-known/*` only), `clearAgentReadinessCache`, `buildAgentCard`, `buildProtectedResourceMetadata(path, config)` (local), `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt(config)` (from `config.llmsTxt`), `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildAuthMd`, `buildDiscoveryLinkHeader`, `wantsMarkdown`/`negotiateMarkdown`, `sha256Digest`, `AI_BOT_USER_AGENTS`. Types: `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `ApiCatalogApi`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `DiscoveryDocument`.
|
|
76
|
-
- **OAuth2 app-bridge:** `handleAppTokenRequest`, `handleAppRevokeRequest` (one-call handlers), `bearerChallenge` (RFC 9728/6750 401; header values are quoted-string-escaped + CR/LF-stripped), `verifyAppTokenRequest`, `verifyAppRevokeRequest`, `verifyClientJwt`, `signClientJwt` (HS256 mint — symmetric counterpart of verify), `extractBearerToken`, `appTokenSuccess`, `appTokenFailure`, `AppBridgeError`. Types: `AppTokenRequestClaims`, `AppRevokeRequestClaims`, `AppTokenResult`, `AppTokenResponseBody`, `HandlerResult`, `VerifyClientJwtOptions`. `verifyClientJwt(token, secret, opts
|
|
75
|
+
- **Agent readiness (framework-agnostic, returns plain `DiscoveryDocument`):** **App owns discovery content, platform owns auth.** All content — `llms.txt`, `robots.txt`, `sitemap`, `protectedResources` (RFC 9728), API catalog, skills — is defined locally in `AgentReadyConfig` and served with no platform round-trip. The platform bundle (`fetchAgentReadiness`, fail-soft/cached) supplies ONLY `{ enabled, authorizationServer }` (the OAuth AS pointer). Functions: `resolveAgentPath` (dispatch ALL agent paths — root docs + `.well-known/*`; prefer for new wiring), `resolveWellKnown` (`.well-known/*` only), `clearAgentReadinessCache`, `buildAgentCard`, `buildA2AAgentCard` (A2A card at `/.well-known/agent-card.json`; served by DEFAULT, derived from `site`+`skills`; `a2aCard: false` disables, object overrides), `buildProtectedResourceMetadata(path, config)` (local), `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt(config)` (from `config.llmsTxt`), `buildLlmsFullTxt` (from `config.llmsFullTxt`), `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildAuthMd`, `buildWebBotAuthDirectory` (JWKS at `/.well-known/http-message-signatures-directory` from `config.webBotAuth.keys`; opt-in), `buildDnsAidRecords` (suggested `_agents` DNS records — publish at your DNS provider, can't be served over HTTP), `buildDiscoveryLinkHeader`, `wantsMarkdown`/`negotiateMarkdown`, `sha256Digest`, `AI_BOT_USER_AGENTS`. `config.extraPaths` serves ANY literal document by exact path (commerce discovery: x402/UCP/ACP/MPP, `/openapi.json`, future `.well-known` docs) and takes precedence over built-ins. Types: `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `ApiCatalogApi`, `A2ACardConfig`, `A2ACardSkill`, `DnsAidRecord`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `DiscoveryDocument`.
|
|
76
|
+
- **OAuth2 app-bridge:** `handleAppTokenRequest`, `handleAppRevokeRequest` (one-call handlers), `bearerChallenge` (RFC 9728/6750 401; header values are quoted-string-escaped + CR/LF-stripped), `verifyAppTokenRequest`, `verifyAppRevokeRequest`, `verifyClientJwt`, `signClientJwt` (HS256 mint — symmetric counterpart of verify), `extractBearerToken`, `appTokenSuccess`, `appTokenFailure`, `AppBridgeError`. Types: `AppTokenRequestClaims`, `AppRevokeRequestClaims`, `AppTokenResult`, `AppTokenResponseBody`, `HandlerResult`, `VerifyClientJwtOptions`. `verifyClientJwt(token, secret, opts?: VerifyClientJwtOptions)` **requires a numeric `exp` by default** (`requireExp: false` to allow non-expiring tokens); optional `clockToleranceSec` / `issuer` / `audience`. **Presets** (also in core): `mintAgentToken` (the whole mint in one call — HS256 with the app's secret, `aud` from the grant's resource, encrypted `sid`) + `buildbaseAuth` (the whole verify) + `createSessionRefCrypto`. Security invariant: the platform relays the minted token but never sees the app secret — it can neither forge nor decode app tokens, and the BuildBase session is never stored and never plaintext in a token.
|
|
77
77
|
- **Currency & pricing utils (pure):** `formatCents`, `formatOverageRate`, `formatOverageRateWithLabel`, `formatQuotaIncludedOverage`, `formatQuotaWithPrice`, `getCurrencySymbol`, `getCurrencyFlag`, `getQuotaUnitLabelFromName`, `getQuotaDisplayValue`, `CURRENCY_DISPLAY`, `CURRENCY_FLAG`, `PLAN_CURRENCY_CODES`, `PLAN_CURRENCY_OPTIONS`.
|
|
78
78
|
- **Pricing variants (multi-currency):** `getPricingVariant`, `getBasePriceCents`, `getStripePriceIdForInterval`, `getQuotaOverageCents`, `getQuotaDisplayWithVariant`, `getAvailableCurrenciesFromPlans`, `getDisplayCurrency`, `getBillingIntervalAndCurrencyFromPriceId`.
|
|
79
79
|
- **Seat pricing:** `calculateBillableSeats`, `calculateSeatOverageCents`, `calculateTotalSubscriptionCents`, `getPerSeatPriceCents`, `getSeatPricing`.
|
|
@@ -109,12 +109,18 @@ Config also accepts: `timeout`, `maxRetries`, `debug`, `headers`, `onError(err,
|
|
|
109
109
|
|
|
110
110
|
### `@buildbase/sdk/mcp` — MCP server (server-only, zero React)
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
**Full guide: `docs/MCP-AND-AGENT-READINESS.md`** (mental model, fast path, auth, scope/resource customization).
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
Expose a live MCP server (stateless Streamable HTTP; Node 18+/edge) with built-in BuildBase tools + custom zod-schema tools. **Spec-compliant to MCP 2025-06-18**: server card SEP-1649 v1.0 (`$schema`, `version:"1.0"`, `protocolVersion`, `transport:{type,url}`, boolean caps), discovery manifest SEP-1960, auth via RFC 9728→8414→8707+PKCE. The platform issues **public clients** (RFC 7591 `token_endpoint_auth_method:"none"`, no secret, PKCE-only) so Claude Desktop/Cursor/ChatGPT/Inspector connect with zero manual config.
|
|
115
|
+
|
|
116
|
+
- **Handler:** `createMcpHandler({ buildbase?, auth, tools?, builtinTools?, context?, serverInfo?, instructions?, allowedOrigins?, maxRequestBytes?, rateLimit?, formatToolError?, onError? })` → `{ handle(McpHttpRequest), fetch(Request), listTools(), serverCard({ endpoint }) }`. `fetch(Request)` is the Web adapter (Next.js App Router, Hono, Bun, Deno, Cloudflare Workers, edge); `handle({method,headers,body})` is the pure form (Express, Fastify, Next.js Pages Router, Node http). Per-framework copy-paste recipes + mint route + production checklist in `docs/MCP-AND-AGENT-READINESS.md`. `auth.verify(token) → McpAuthInfo { sessionId, userId?, workspaceId?, scopes? }` maps the app's Bearer token (any format) to the BuildBase session tools run under; `auth.resourceMetadataUrl` makes 401s carry the RFC 9728 challenge. `auth: false` = dev only. **Hardening:** `maxRequestBytes` (default 1 MiB → 413), `rateLimit(auth, req)` gate (after auth; `false`/`{ok:false,retryAfter}` → 429, fails closed), `allowedOrigins` (non-matching browser Origin → 403; also drives CORS — `OPTIONS` preflight → 204 + `Access-Control-*`, matching Origin echoed on responses), `formatToolError(err, {tool})` (redact client-facing tool-error text; full error still hits `onError`). **No lock-in:** `buildbase` is optional (standalone server, only your tools); `context(auth, req)` injects your own per-request context as `ctx.custom`; custom tools override same-named built-ins; raw JSON Schema tools skip zod.
|
|
115
117
|
- **Tools:** `defineMcpTool` (typed custom tools), `builtinMcpTools`, `selectBuiltinTools`. Built-ins cover the **full BuildBase surface** (42 tools: workspaces/users/subscription/plans/invoices/usage/credits/features/permissions/settings — reads + writes + destructive). **Default `builtinTools: 'readonly'`** (least privilege) — reads only until you opt into `'all'` (or `{ include }`); narrow further with `false` | `{ exclude }`. Every tool runs under the user's session → platform enforces the user's real permissions (agent can't exceed the user). Built-ins carry **no** scope requirement (agent = authenticated app user; read/write boundary is `builtinTools`, not agent scopes). Per-scope gating is opt-in on custom tools via `requiredScopes` + the `scopes` returned from `auth.verify` (your scope names); a token with no scopes sees only tools that require none.
|
|
118
|
+
- **One-config stack:** `createAgentStack({ serverUrl, orgId, siteUrl, site, secret, mcp?, discovery? })` → `{ mcp, mcpEndpoint, config, linkHeader, resolvePath, serveAgentPath, routes }` — derives the MCP endpoint, server card, RFC 9728 protected resource, API catalog entry, BuildBase client, `buildbaseAuth`, and CORS from ONE object. Next.js wiring: `export const { GET, POST, DELETE, OPTIONS } = agent.routes` for `/api/mcp`, `export const GET = agent.serveAgentPath` for discovery routes. Everything derived is overridable via `mcp.*` / `discovery.*`.
|
|
119
|
+
- **BuildBase auth presets** (pure local crypto — the app's secret and tokens NEVER reach the platform): `mintAgentToken({ claims, secret, expiresInSec?, extraClaims? })` (drop into `handleAppTokenRequest.mintToken`; signs HS256 with YOUR secret, binds `aud` to the RFC 8707 resource, embeds the per-user session as an encrypted `sid` claim) and `buildbaseAuth({ secret, resource?, resourceMetadataUrl?, requireAudience?, verify? })` (the `auth` config for `createMcpHandler`: verify + RFC 8707 audience binding + `sid` decryption + derived `resourceMetadataUrl`; `resource` accepts `string|string[]`; `MCP_AUTH_DEBUG=1` logs received-vs-expected `aud` on rejection). `createSessionRefCrypto(secret)` exposes the underlying AES-256-GCM `sid` crypto (WebCrypto; wire format `base64url(iv|tag|ciphertext)`, key `SHA-256(secret+":bb-session")` — byte-compatible with Node `createCipheriv` implementations of the same layout).
|
|
120
|
+
- **Scopes & resources (restrict or open up) — ALL app-owned; the shared AS is scope/resource-agnostic:** THREE scope levers — (1) declare a catalog `scopes:[{name,description}]` on `AgentReadyConfig`/`createAgentStack` → `scopes_supported` in the app's OWN RFC 9728 protected-resource metadata (served from the app origin); (2) gate per custom tool via `requiredScopes` (hidden/refused unless the token carries all — YOUR scope names); (3) the floor — every tool runs under the user's session so the platform enforces the user's real permissions (agent ⊆ user). Built-ins are restricted by `builtinTools`, not scopes. TWO resource levers — declare `protectedResources` (RFC 9728: stack derives root + `<host>/mcp` + endpoint) and bind the token `aud` via `buildbaseAuth({ resource, requireAudience })` (RFC 8707) — the audience check at YOUR resource is the whole gate (token for A rejected at B); the AS just passes `resource` through opaquely (no per-org scope/resource lists, no `invalid_target`). Defaults are least-privilege; widen deliberately. RFC 9728 convention: canonical MCP resource is `<host>/mcp` (metadata at `/.well-known/oauth-protected-resource/mcp`), 401 `WWW-Authenticate` points there.
|
|
121
|
+
- **CORS:** on by default (`Access-Control-Allow-Origin: *` — safe for a Bearer-token API; reflects `allowedOrigins` when set). Narrow with `cors: [origins]` or disable with `cors: false`. Preflight answered automatically — never wrap the route in your own CORS.
|
|
116
122
|
- **Auth helpers re-exported:** `signClientJwt`, `verifyClientJwt`, `extractBearerToken`, `bearerChallenge`, `AppBridgeError`.
|
|
117
|
-
- Types: `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`.
|
|
123
|
+
- Types: `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`, `AgentStack`, `AgentStackConfig`, `BuildBaseAuthOptions`, `MintAgentTokenOptions`, `SessionRefCrypto`.
|
|
118
124
|
|
|
119
125
|
## Server actions cheat-sheet
|
|
120
126
|
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,52 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.0.54] - 2026-07-10
|
|
11
|
+
|
|
12
|
+
MCP + agent-readiness brought to **MCP 2025-06-18** compliance, a one-config setup path, first-class auth presets, and a full per-framework guide. **Behavior changes** are marked ⚠️.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`createAgentStack(config)` — the whole MCP + agent-readiness surface from one config object** (`@buildbase/sdk/mcp`). Derives the MCP handler, the SEP-1649 server card, the RFC 9728 protected-resource metadata (root + canonical `<host>/mcp` + endpoint), the API-catalog entry, the BuildBase client, `buildbaseAuth`, CORS, and the discovery `Link` header. Returns `{ mcp, mcpEndpoint, config, linkHeader, resolvePath, serveAgentPath, routes }` — Next.js wires `export const { GET, POST, DELETE, OPTIONS } = agent.routes` + `export const GET = agent.serveAgentPath`. Everything derived is overridable via `mcp.*` / `discovery.*`.
|
|
17
|
+
- **Auth presets — the app mints & verifies its own tokens with pure local crypto; the platform never sees the secret.** `mintAgentToken({ claims, secret })` (drop into `handleAppTokenRequest.mintToken` — HS256 with your secret, `aud` from the granted RFC 8707 resource, per-user BuildBase session embedded as an encrypted `sid`), `buildbaseAuth({ secret, resource, requireAudience })` (the `auth` config for `createMcpHandler` — verify + audience binding + `sid` decrypt + derived `resourceMetadataUrl`; `resource` accepts `string | string[]`), and `createSessionRefCrypto(secret)` (the underlying AES-256-GCM `sid` crypto, WebCrypto, wire-format `base64url(iv|tag|ciphertext)`, key `SHA-256(secret+":bb-session")` — byte-compatible with a Node `createCipheriv` layout). Also exported from the core entry. `MCP_AUTH_DEBUG=1` logs received-vs-expected `aud` on rejection.
|
|
18
|
+
- **A2A Agent Card** at `/.well-known/agent-card.json` (`buildA2AAgentCard`) — served **by default**, derived from `site` + `skills`; `a2aCard: false` disables, an object overrides. Advertised on the Agent Card capabilities and the discovery `Link` header.
|
|
19
|
+
- **`AgentReadyConfig.scopes` — an app scope catalog** (`AppScope[]`, `{ name, description }`) that drives `scopes_supported` in your RFC 9728 protected-resource metadata. Scopes are app-owned.
|
|
20
|
+
- **More discovery builders / paths:** `buildLlmsFullTxt` (`/llms-full.txt`), `buildWebBotAuthDirectory` (JWKS at `/.well-known/http-message-signatures-directory`, opt-in), `buildMcpDiscoveryManifest` (SEP-1960 `/.well-known/mcp.json`), `buildDnsAidRecords` (suggested `_agents` DNS records to publish at your DNS provider), and `config.extraPaths` (serve any literal document by exact path — commerce discovery x402/UCP/ACP/MPP, `/openapi.json`, future well-knowns; takes precedence over built-ins).
|
|
21
|
+
- **Per-framework guide** — `docs/MCP-AND-AGENT-READINESS.md`: the complete flows (cold-start, mint, verify), the scope/resource model, and copy-paste recipes for Next.js (App + Pages Router), Express, Fastify, Hono, Bun, Deno, Cloudflare Workers, and React/SPA (WebMCP), plus a production checklist.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **MCP Server Card is now SEP-1649 v1.0.** ⚠️ **Output shape change.** `/.well-known/mcp/server-card.json` now emits `$schema`, `version: "1.0"`, `protocolVersion: "2025-06-18"`, `transport: { type, url }` (was `transport.endpoint`), and **boolean** `capabilities` (`{ tools: true, resources: false, prompts: false }`; a legacy `{ tools: {} }`-style object is normalized). `/.well-known/mcp.json` (SEP-1960) gains `$schema` + `version: "1.0"` and a per-server `transport` object. `McpServerCard` gains an optional `protocolVersion`.
|
|
26
|
+
- **CORS is on by default on `createMcpHandler`.** ⚠️ **Behavior change.** Responses now carry `Access-Control-Allow-Origin: *` (safe for a Bearer-token API — no cookies) and `OPTIONS` is answered automatically, so browser MCP clients work with zero config. New `cors` option: `cors: [origins]` narrows to those origins (reflected), `cors: false` disables. `allowedOrigins`, when set, still restricts and drives reflection.
|
|
27
|
+
- **`buildbaseAuth` audience binding accepts multiple resources** and takes an explicit `resourceMetadataUrl`; `createAgentStack` binds both the canonical `<host>/mcp` and the literal endpoint URL and points the 401 challenge at `/.well-known/oauth-protected-resource/mcp`.
|
|
28
|
+
|
|
29
|
+
### Security
|
|
30
|
+
|
|
31
|
+
- **API retries are restricted to idempotent methods.** ⚠️ **Behavior change.** Automatic retries (network error / 5xx) now apply only to GET/HEAD/OPTIONS/PUT/DELETE. POST/PATCH are never replayed — the server may have processed a request whose response was lost, so replaying `purchase_credits`, `consume_credits`, or `create_checkout_session` risked double-charging. The retry backoff also respects the abort signal now (an unmount or timeout ends the wait immediately).
|
|
32
|
+
- **Open-redirect hardening in `validateRedirectUrl` / `safeRedirect`.** Relative paths (`/dashboard`) are now accepted (protocol-relative `//host` and backslash `/\host` forms are not); new `RedirectValidationOptions` (`{ sameOrigin, allowedOrigins }`) restricts absolute URLs; `safeRedirect` validates its fallback URL too. ⚠️ Auth return URLs (`saveAuthIntent`/`consumeAuthIntent`) are now **same-origin only** — a tampered localStorage intent can no longer redirect off-site. Stripe/OAuth cross-origin `https:` targets are unaffected by default. Also fixed: the `http://[::1]` localhost allowance never matched (`URL.hostname` includes the brackets).
|
|
33
|
+
- **`verifyClientJwt` pins the JWT `alg` before computing the HMAC** (was checked after) — hardens the verifier against algorithm-confusion if it is ever extended beyond HS256.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **Zero-decimal currencies (JPY, KRW, …) format correctly.** `formatCents(1000, 'jpy')` now renders `¥1,000` (was `¥10.00` — a ÷100 on a currency with no minor unit). Fixed across `formatCents`, `formatOverageRate`, `formatOverageRateWithLabel`, `formatQuotaWithPrice`, and `getQuotaDisplayParts`; new `isZeroDecimalCurrency(currency)` and `minorAmountToDisplay(amount, currency)` are exported.
|
|
38
|
+
- **Stale-response races in the workspace data hooks.** All 15 read hooks (`useSubscription`, `useAllQuotaUsage`, `useCreditBalance`, `usePlanGroup`, `useInvoices`, `useUsageLogs`, `usePublicPlans`, and the rest of the subscription/credit read surface) now drop superseded responses — a workspace switch can no longer render the previous workspace's subscription, quotas, credits, or invoices. Only the latest request clears `loading`; unmount aborts.
|
|
39
|
+
- **`useSaaSSettings` no longer loses org settings for the session under React StrictMode.** The deduplicated global settings fetch was bound to the first caller's abort signal, so StrictMode's throwaway first mount aborted it for every waiter with no retry. The shared fetch is now detached — its result lands in the global store regardless of any one component's lifetime.
|
|
40
|
+
- **`UserProvider` state split per resource.** Attributes and features now have independent loading/error (`attributesLoading`/`featuresLoading`, `attributesError`/`featuresError`; the combined `isLoading`/`error` remain for back-compat) — a features failure no longer surfaces as an attributes error, stale errors clear when a new request starts, and `useUserFeatures().isLoading/error` now reflect the features pipeline only, as documented.
|
|
41
|
+
- **`createBBUrl` throws on an invalid explicit base URL** instead of silently substituting `https://localhost` (which sent Stripe success/cancel URLs to localhost with no error). The localhost default remains only for the no-argument server-side case.
|
|
42
|
+
- **`createWorkspace`'s delayed plan-picker open is cancelled on unmount** — it can no longer pop open after the user navigated away or signed out during the 300ms delay.
|
|
43
|
+
- **`workspaceSettingsManager.clearParams()` notifies subscribers** (React state no longer diverges from the manager), and `getState()` returns a stable snapshot reference.
|
|
44
|
+
|
|
45
|
+
### Removed
|
|
46
|
+
|
|
47
|
+
- **`verifyClientJwt`'s legacy bare-`number` third argument.** ⚠️ **Behavior change.** The third parameter is now `VerifyClientJwtOptions` only (`{ clockToleranceSec?, requireExp?, issuer?, audience? }`); pass `{ clockToleranceSec: n }` instead of a bare number.
|
|
48
|
+
|
|
49
|
+
### Internal
|
|
50
|
+
|
|
51
|
+
- Centralized the duplicated base64url codec into `src/lib/base64url.ts` (was copied in `agent-bridge.ts` and `agent-auth.ts`).
|
|
52
|
+
- **Test infrastructure (vitest): 113 tests** across sha256/HMAC vectors, webhook verification, agent-bridge JWT (round-trip, alg-confusion, exp/nbf, issuer/audience pinning, header-injection escaping), agent-auth session crypto (Node-crypto compatibility both directions), agent stack, permissions revoke/unknown-role semantics, redirect validation, URL params, API retry idempotency + abortable backoff, zero-decimal currency math — plus a **packaging test** asserting every value declared in each entry point's `.d.ts` exists in the runtime bundle (would have auto-caught the 0.0.51 `/react` phantom-exports bug). `@types/node` added; test files are now typechecked (`tsconfig.json` no longer excludes them; the build still does via `tsconfig.build.json`).
|
|
53
|
+
|
|
8
54
|
## [0.0.53] - 2026-07-09
|
|
9
55
|
|
|
10
56
|
Production-readiness pass — MCP + agent-bridge hardening, permission-resolution correctness, auth-session teardown, and settings/a11y/i18n fixes. **Behavior changes** are marked ⚠️ (`builtinTools` default; permission-override semantics); the rest are additive or internal.
|
package/README.md
CHANGED
|
@@ -2935,7 +2935,11 @@ app.post('/webhooks/buildbase', (req, res) => {
|
|
|
2935
2935
|
|
|
2936
2936
|
## Agent Readiness (Discovery)
|
|
2937
2937
|
|
|
2938
|
-
|
|
2938
|
+
> **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md) covers the whole surface — the fast path, the auth model, and the scope/resource customization spectrum. This section is the overview.
|
|
2939
|
+
|
|
2940
|
+
Make a consuming app [agent ready](https://isitagentready.com) by serving the machine-readable discovery documents an AI client looks for — Agent Card, A2A card, OAuth metadata (RFC 8414/9728), Agent Skills, API Catalog (RFC 9727), MCP Server Card (SEP-1649 v1.0) + discovery manifest (SEP-1960), `robots.txt` with AI-bot rules + Content Signals, `sitemap.xml`, `security.txt`, `llms.txt`/`llms-full.txt`, and `auth.md`. Framework-agnostic and zero React: every function returns a plain `DiscoveryDocument` (`{ status, contentType, body, cacheControl, vary? }`).
|
|
2941
|
+
|
|
2942
|
+
The fast path is [`createAgentStack`](docs/MCP-AND-AGENT-READINESS.md#fast-path--createagentstack) — one config derives the MCP handler **and** the whole discovery surface. To wire the discovery layer on its own, use `resolveAgentPath`:
|
|
2939
2943
|
|
|
2940
2944
|
```ts
|
|
2941
2945
|
// lib/agent-ready.ts
|
|
@@ -2947,11 +2951,15 @@ export const agentConfig: AgentReadyConfig = {
|
|
|
2947
2951
|
siteUrl: 'https://imejis.io',
|
|
2948
2952
|
site: { name: 'Imejis', description: 'Generate images from templates via API.' },
|
|
2949
2953
|
// Discovery content is YOURS — defined here in code, not in the platform:
|
|
2954
|
+
scopes: [
|
|
2955
|
+
{ name: 'designs:read', description: 'View designs' },
|
|
2956
|
+
{ name: 'render:execute', description: 'Render images' },
|
|
2957
|
+
],
|
|
2950
2958
|
llmsTxt: '# Imejis\n\n> Generate images from templates via API.',
|
|
2951
2959
|
robots: { contentSignals: { search: true, aiInput: true, aiTrain: false } },
|
|
2952
2960
|
sitemap: { urls: ['/', '/pricing'] }, // omit if you already generate sitemaps
|
|
2953
|
-
protectedResources: [{
|
|
2954
|
-
// skills, security, apiCatalog, mcpServerCard,
|
|
2961
|
+
protectedResources: [{ resource: 'https://imejis.io/mcp' }], // scopes inherited from catalog
|
|
2962
|
+
// skills, security, apiCatalog, mcpServerCard, a2aCard, extraPaths — all optional
|
|
2955
2963
|
};
|
|
2956
2964
|
|
|
2957
2965
|
export async function serveAgentPath(req: Request): Promise<Response> {
|
|
@@ -3031,21 +3039,61 @@ Clean split, no duplication: **your app owns discovery content, the platform own
|
|
|
3031
3039
|
| llms.txt | `buildLlmsTxt` |
|
|
3032
3040
|
| MCP Server Card + live MCP server | `buildMcpServerCard` + [`@buildbase/sdk/mcp`](#mcp-server-buildbasesdkmcp) |
|
|
3033
3041
|
| Agent Skills / API Catalog | `buildAgentSkillsIndex` / `buildApiCatalog` |
|
|
3042
|
+
| A2A Agent Card | `buildA2AAgentCard` (served by default from `site` + `skills`) |
|
|
3034
3043
|
| OAuth discovery (RFC 8414) + protected resource (RFC 9728) | `resolveAgentPath` (platform-backed) |
|
|
3035
|
-
|
|
|
3036
|
-
|
|
|
3044
|
+
| Web Bot Auth | `buildWebBotAuthDirectory` (opt-in — publish your JWKS) |
|
|
3045
|
+
| DNS-AID | `buildDnsAidRecords` (returns records — publish at your DNS provider) |
|
|
3046
|
+
| Commerce (x402/ACP/UCP/MPP), openapi.json | `config.extraPaths` (serve any literal document by path) |
|
|
3037
3047
|
|
|
3038
|
-
**Functions:** `resolveAgentPath`, `resolveWellKnown`, `fetchAgentReadiness`, `clearAgentReadinessCache`, `buildAgentCard`, `buildProtectedResourceMetadata`, `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt`, `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildAuthMd`, `buildDiscoveryLinkHeader`, `wantsMarkdown`, `negotiateMarkdown`, `provideWebMcpTools`, `sha256Digest`. **Constants:** `AI_BOT_USER_AGENTS`. **Types:** `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `ApiCatalogApi`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `WebMcpTool`, `DiscoveryDocument`.
|
|
3048
|
+
**Functions:** `resolveAgentPath`, `resolveWellKnown`, `fetchAgentReadiness`, `clearAgentReadinessCache`, `buildAgentCard`, `buildA2AAgentCard`, `buildProtectedResourceMetadata`, `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt`, `buildLlmsFullTxt`, `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildMcpDiscoveryManifest`, `buildAuthMd`, `buildWebBotAuthDirectory`, `buildDnsAidRecords`, `buildDiscoveryLinkHeader`, `wantsMarkdown`, `negotiateMarkdown`, `provideWebMcpTools`, `sha256Digest`. **Constants:** `AI_BOT_USER_AGENTS`. **Types:** `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `AppScope`, `ApiCatalogApi`, `A2ACardConfig`, `A2ACardSkill`, `DnsAidRecord`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `WebMcpTool`, `DiscoveryDocument`.
|
|
3039
3049
|
|
|
3040
3050
|
## MCP Server (`@buildbase/sdk/mcp`)
|
|
3041
3051
|
|
|
3042
|
-
|
|
3052
|
+
> **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md).
|
|
3053
|
+
|
|
3054
|
+
Turn your app into a **live MCP server** so AI agents can operate it: the built-in tools expose your BuildBase state (workspaces, subscription, quotas, credits, feature flags, permissions) and you add your own product tools with zod schemas. Stateless Streamable HTTP (MCP 2025-06-18) — pure functions plus a Web-standard `Request`/`Response` adapter, so it runs on Node 18+, edge, Deno, and Bun. Server-only, zero React; split from the core entry because it uses `zod` at runtime.
|
|
3055
|
+
|
|
3056
|
+
The fast path bundles the server + the whole discovery surface from one config:
|
|
3057
|
+
|
|
3058
|
+
```ts
|
|
3059
|
+
// lib/agent.ts
|
|
3060
|
+
import { createAgentStack, defineMcpTool } from '@buildbase/sdk/mcp';
|
|
3061
|
+
import { z } from 'zod';
|
|
3062
|
+
|
|
3063
|
+
export const agent = createAgentStack({
|
|
3064
|
+
serverUrl: process.env.NEXT_PUBLIC_BUILDBASE_SERVER_URL!,
|
|
3065
|
+
orgId: process.env.NEXT_PUBLIC_BUILDBASE_ORG_ID!,
|
|
3066
|
+
siteUrl: 'https://imejis.io',
|
|
3067
|
+
site: { name: 'Imejis', description: 'Generate images from templates via API.' },
|
|
3068
|
+
secret: process.env.SYSTEM_SECRET!, // derives buildbaseAuth (verify + aud + sid decrypt)
|
|
3069
|
+
scopes: [{ name: 'render:execute', description: 'Render images' }],
|
|
3070
|
+
mcp: {
|
|
3071
|
+
builtinTools: 'readonly',
|
|
3072
|
+
tools: [
|
|
3073
|
+
defineMcpTool({
|
|
3074
|
+
name: 'generate_image',
|
|
3075
|
+
description: 'Render an image from a template',
|
|
3076
|
+
inputSchema: z.object({ templateId: z.string(), data: z.record(z.string(), z.any()) }),
|
|
3077
|
+
requiredScopes: ['render:execute'],
|
|
3078
|
+
execute: async (input, { bb, workspaceId }) => {
|
|
3079
|
+
await bb.usage.record(workspaceId!, { quotaSlug: 'images', quantity: 1 });
|
|
3080
|
+
return renderTemplate(input.templateId, input.data);
|
|
3081
|
+
},
|
|
3082
|
+
}),
|
|
3083
|
+
],
|
|
3084
|
+
},
|
|
3085
|
+
});
|
|
3086
|
+
|
|
3087
|
+
// app/api/mcp/route.ts
|
|
3088
|
+
export const { GET, POST, DELETE, OPTIONS } = agent.routes;
|
|
3089
|
+
```
|
|
3090
|
+
|
|
3091
|
+
Prefer the primitives (own token format, unified web+agent auth)? Wire `createMcpHandler` + `buildbaseAuth` directly — `buildbaseAuth` does the full verify (HS256, RFC 8707 audience binding, `sid` decrypt) so you never hand-roll it:
|
|
3043
3092
|
|
|
3044
3093
|
```ts
|
|
3045
3094
|
// lib/mcp.ts
|
|
3046
3095
|
import BuildBase from '@buildbase/sdk';
|
|
3047
|
-
import { createMcpHandler, defineMcpTool,
|
|
3048
|
-
import { z } from 'zod';
|
|
3096
|
+
import { createMcpHandler, defineMcpTool, buildbaseAuth } from '@buildbase/sdk/mcp';
|
|
3049
3097
|
|
|
3050
3098
|
const buildbase = BuildBase({
|
|
3051
3099
|
serverUrl: process.env.BUILDBASE_URL!,
|
|
@@ -3055,50 +3103,29 @@ const buildbase = BuildBase({
|
|
|
3055
3103
|
export const mcp = createMcpHandler({
|
|
3056
3104
|
buildbase,
|
|
3057
3105
|
serverInfo: { name: 'imejis', version: '1.0.0' },
|
|
3058
|
-
auth: {
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
},
|
|
3065
|
-
// Unauthenticated requests get a 401 whose WWW-Authenticate header points
|
|
3066
|
-
// here, so agents bootstrap the whole OAuth discovery flow (RFC 9728).
|
|
3067
|
-
resourceMetadataUrl: 'https://imejis.io/.well-known/oauth-protected-resource',
|
|
3068
|
-
},
|
|
3069
|
-
builtinTools: 'readonly', // default; 'all' opts into the mutating tools
|
|
3106
|
+
auth: buildbaseAuth({
|
|
3107
|
+
secret: process.env.SYSTEM_SECRET!,
|
|
3108
|
+
resource: ['https://imejis.io/mcp', 'https://imejis.io/api/mcp'],
|
|
3109
|
+
requireAudience: true,
|
|
3110
|
+
}),
|
|
3111
|
+
builtinTools: 'readonly',
|
|
3070
3112
|
tools: [
|
|
3071
|
-
defineMcpTool(
|
|
3072
|
-
name: 'generate_image',
|
|
3073
|
-
description: 'Render an image from a template',
|
|
3074
|
-
inputSchema: z.object({ templateId: z.string(), data: z.record(z.string(), z.any()) }),
|
|
3075
|
-
annotations: { readOnlyHint: false },
|
|
3076
|
-
execute: async (input, { bb, workspaceId }) => {
|
|
3077
|
-
await bb.usage.record(workspaceId!, { quotaSlug: 'images', quantity: 1 });
|
|
3078
|
-
return renderTemplate(input.templateId, input.data);
|
|
3079
|
-
},
|
|
3080
|
-
}),
|
|
3113
|
+
/* defineMcpTool(...) */
|
|
3081
3114
|
],
|
|
3082
3115
|
});
|
|
3083
3116
|
```
|
|
3084
3117
|
|
|
3085
3118
|
```ts
|
|
3086
|
-
//
|
|
3087
|
-
import { mcp } from '@/lib/mcp';
|
|
3088
|
-
export const POST = (req: Request) => mcp.fetch(req);
|
|
3089
|
-
export const GET = (req: Request) => mcp.fetch(req); // 405 per spec (no SSE)
|
|
3090
|
-
export const DELETE = (req: Request) => mcp.fetch(req); // 405 (stateless)
|
|
3091
|
-
```
|
|
3092
|
-
|
|
3093
|
-
```ts
|
|
3094
|
-
// Express — the pure form
|
|
3119
|
+
// Express / Fastify / Node — the pure form
|
|
3095
3120
|
app.post('/mcp', async (req, res) => {
|
|
3096
3121
|
const r = await mcp.handle({ method: req.method, headers: req.headers, body: req.body });
|
|
3097
3122
|
res.status(r.status).set(r.headers).send(r.body);
|
|
3098
3123
|
});
|
|
3099
3124
|
```
|
|
3100
3125
|
|
|
3101
|
-
|
|
3126
|
+
> **Copy-paste recipes for every framework** — Next.js (App + Pages Router), Express, Fastify, Hono, Bun, Deno, Cloudflare Workers, and React/SPA (WebMCP) — plus the per-framework mint route and a production checklist: [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md#framework-recipes). Two adapters cover them all: `mcp.fetch(Request)` (web standard — App Router, Hono, Bun, Deno, edge) and `mcp.handle({method,headers,body})` (pure — Express, Fastify, Pages Router).
|
|
3127
|
+
|
|
3128
|
+
Advertise it via the server card so agents find the endpoint (the stack sets this automatically):
|
|
3102
3129
|
|
|
3103
3130
|
```ts
|
|
3104
3131
|
export const agentConfig: AgentReadyConfig = {
|
|
@@ -3187,21 +3214,25 @@ The SDK accelerates; it never gates. Everything BuildBase-specific is optional:
|
|
|
3187
3214
|
|
|
3188
3215
|
### Auth in one line of plumbing
|
|
3189
3216
|
|
|
3190
|
-
The OAuth2 app-bridge flow
|
|
3217
|
+
The OAuth2 app-bridge flow mints your app's Bearer tokens (see [OAuth2 App Bridge](#oauth2-app-bridge)). Use the presets and neither the mint nor the verify is hand-rolled — the per-user BuildBase session rides as an **encrypted `sid`** claim (JWTs are signed, not encrypted), never stored, expiring with the token:
|
|
3191
3218
|
|
|
3192
3219
|
```ts
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
}),
|
|
3220
|
+
// mint (applicationTokenUrl) — HS256 with your secret, aud from the grant, encrypted sid
|
|
3221
|
+
import { mintAgentToken } from '@buildbase/sdk';
|
|
3222
|
+
mintToken: (claims) => mintAgentToken({ claims, secret: process.env.SYSTEM_SECRET! }),
|
|
3223
|
+
|
|
3224
|
+
// verify (MCP server) — HS256 + RFC 8707 audience + sid decrypt → McpAuthInfo
|
|
3225
|
+
import { buildbaseAuth } from '@buildbase/sdk/mcp';
|
|
3226
|
+
auth: buildbaseAuth({ secret: process.env.SYSTEM_SECRET!, resource: 'https://imejis.io/mcp' }),
|
|
3200
3227
|
```
|
|
3201
3228
|
|
|
3202
|
-
Set `auth: false` to disable auth
|
|
3229
|
+
Bringing your own token format? `auth.verify(token, req) → McpAuthInfo` accepts any Bearer token; set `auth.resourceMetadataUrl` so 401s carry the RFC 9728 challenge. Set `auth: false` to disable auth (local dev only). Debug audience mismatches with `MCP_AUTH_DEBUG=1`. Test with the MCP Inspector: `npx @modelcontextprotocol/inspector --cli http://localhost:3000/api/mcp --transport http --header "Authorization: Bearer <token>" --method tools/list`.
|
|
3203
3230
|
|
|
3204
|
-
**Exports:** `createMcpHandler`, `defineMcpTool`, `builtinMcpTools`, `selectBuiltinTools`, plus re-exported auth helpers (`signClientJwt`, `verifyClientJwt`, `extractBearerToken`, `bearerChallenge`, `AppBridgeError`). **Types:** `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`, `McpServerCard`, `ScopedActions`.
|
|
3231
|
+
**Exports:** `createAgentStack`, `createMcpHandler`, `defineMcpTool`, `builtinMcpTools`, `selectBuiltinTools`, `buildbaseAuth`, `mintAgentToken`, `createSessionRefCrypto`, plus re-exported auth helpers (`signClientJwt`, `verifyClientJwt`, `extractBearerToken`, `bearerChallenge`, `AppBridgeError`). **Types:** `AgentStack`, `AgentStackConfig`, `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`, `BuildBaseAuthOptions`, `MintAgentTokenOptions`, `SessionRefCrypto`, `McpServerCard`, `ScopedActions`.
|
|
3232
|
+
|
|
3233
|
+
### Scopes & resources — restrict or open up
|
|
3234
|
+
|
|
3235
|
+
Scopes and resources are **app-owned** — the shared BuildBase authorization server stays scope/resource-agnostic. Scopes have three levers: **declare** a catalog (`scopes: [{ name, description }]` → `scopes_supported` in your own RFC 9728 protected-resource metadata), **gate per tool** (`requiredScopes` on a custom tool → hidden/refused unless the token carries them), and the **floor** (every tool runs under the user's BuildBase session, so the platform enforces the user's real permissions — an agent never exceeds the user). Resources have two: **declare** `protectedResources` (RFC 9728) and **bind** the token audience via `buildbaseAuth({ resource, requireAudience })` (RFC 8707) — the audience check at your resource is the whole gate. Built-ins are restricted with `builtinTools`, not scopes. Public clients (Claude Desktop, Cursor, Inspector) self-register with PKCE and no secret. Full model: [the guide](docs/MCP-AND-AGENT-READINESS.md#scopes--resources-restrict-or-open-up).
|
|
3205
3236
|
|
|
3206
3237
|
## OAuth2 App Bridge
|
|
3207
3238
|
|
|
@@ -3212,6 +3243,8 @@ BuildBase runs the full OAuth2 authorization flow (login, consent, code, PKCE, r
|
|
|
3212
3243
|
|
|
3213
3244
|
Both requests carry `Authorization: Bearer <JWT>`, an HS256 JWT signed with your client secret. This toolkit verifies those requests (timing-safe, no `alg` confusion) and shapes the exact response body the platform expects, so you write only the part that's yours: minting/invalidating a token in your own format.
|
|
3214
3245
|
|
|
3246
|
+
> For the common case, `mintToken: (claims) => mintAgentToken({ claims, secret })` is the preset — it signs HS256 with your secret, binds `aud` to the granted RFC 8707 resource, and embeds the encrypted `sid`. The examples below show the hand-rolled equivalent, for apps that mint their own token format (e.g. one shared with their web sessions). See [the guide](docs/MCP-AND-AGENT-READINESS.md#auth-minting--verifying-the-token).
|
|
3247
|
+
|
|
3215
3248
|
```ts
|
|
3216
3249
|
// applicationTokenUrl handler (Next.js Pages Router)
|
|
3217
3250
|
import { handleAppTokenRequest } from '@buildbase/sdk';
|
|
@@ -3295,7 +3328,9 @@ return res.json({ id: claims.id, email: claims.email /* … */ });
|
|
|
3295
3328
|
|
|
3296
3329
|
The one-call handlers cover the common path; the underlying pieces are exported for custom flows: `verifyAppTokenRequest` / `verifyAppRevokeRequest` (verify → claims), `verifyClientJwt`, `extractBearerToken`, and the response builders `appTokenSuccess` / `appTokenFailure`. Verification throws `AppBridgeError` (with a machine-readable `code` like `invalid_signature`, `token_expired`, `invalid_algorithm`). HMAC verification uses the SDK's dependency-free pure-JS HMAC-SHA256, so it behaves identically under ESM, CJS, a bundler, or bare Node.
|
|
3297
3330
|
|
|
3298
|
-
**
|
|
3331
|
+
**Presets** (also on the core entry): `mintAgentToken` (the whole mint — HS256 + `aud` + encrypted `sid`), `buildbaseAuth` (the whole verify), `createSessionRefCrypto` (the `sid` AES-256-GCM crypto). The platform relays the minted token but never sees your secret — it can neither forge nor decode your tokens.
|
|
3332
|
+
|
|
3333
|
+
**Exports:** `handleAppTokenRequest`, `handleAppRevokeRequest`, `verifyAppTokenRequest`, `verifyAppRevokeRequest`, `verifyClientJwt`, `signClientJwt`, `extractBearerToken`, `bearerChallenge`, `appTokenSuccess`, `appTokenFailure`, `mintAgentToken`, `buildbaseAuth`, `createSessionRefCrypto`, `AppBridgeError`. **Types:** `AppTokenRequestClaims`, `AppRevokeRequestClaims`, `AppTokenResult`, `AppTokenResponseBody`, `HandlerResult`, `VerifyClientJwtOptions`, `BuildBaseAuthOptions`, `MintAgentTokenOptions`, `SessionRefCrypto`.
|
|
3299
3334
|
|
|
3300
3335
|
## 🤝 Contributing
|
|
3301
3336
|
|