@stacksjs/defaults 0.75.187 → 0.75.189

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.
@@ -393,3 +393,56 @@ Tests: `storage/framework/core/ai/tests/usage-and-tokens.test.ts`,
393
393
  `tool-calls.test.ts` and `client.test.ts`. Verify chosen model/provider
394
394
  capabilities from config and registry rather than assuming a marketing model name
395
395
  is usable for every API.
396
+
397
+ ## Serving MCP tools
398
+
399
+ Use the native server subpath so serving a tool does not load AI provider drivers:
400
+
401
+ ```typescript
402
+ import { createMCPServer, mcpTextResult } from '@stacksjs/ai/mcp-server'
403
+ import { route } from '@stacksjs/router'
404
+
405
+ const server = createMCPServer({
406
+ name: 'example', version: '1.0.0',
407
+ authenticate: async request => authenticateIntegrationKey(request),
408
+ tools: [{
409
+ name: 'account', description: 'Read the connected account',
410
+ inputSchema: { type: 'object', additionalProperties: false },
411
+ annotations: { readOnlyHint: true, openWorldHint: false },
412
+ execute: async (args, { principal }) => mcpTextResult({ id: principal.id }),
413
+ }],
414
+ })
415
+ route.post('/mcp', server.handle).parseBody(false).skipCsrf()
416
+ route.get('/mcp', server.handle)
417
+ route.delete('/mcp', server.handle).skipCsrf()
418
+ ```
419
+
420
+ `authenticateIntegrationKey` is application-owned: return a principal or an HTTP
421
+ 401/403 `Response`. Authenticate every request, enforce scopes and quotas, and
422
+ never accept ambient login cookies as integration credentials. Tool `available`
423
+ filters discovery and execution; domain operations must still check authorization.
424
+ `@stacksjs/api/operation` supplies `defineApiOperation({ authorize, handle })` for
425
+ sharing that check across HTTP, MCP and background invocations.
426
+
427
+ This transport is stateless Streamable HTTP with JSON replies. It supports
428
+ 2025-11-25, 2025-06-18 and 2025-03-26; GET/DELETE return 405. Clients send both
429
+ application/json and text/event-stream in Accept. It implements tools, static
430
+ resources, prompts and discovery pagination; it does not claim SSE subscriptions,
431
+ tasks, server requests, session ids, stdio or JSON-RPC batch support. `parseBody(false)`
432
+ is essential: the protocol owns its bounded read and error envelope. The router
433
+ keeps middleware, CSRF policy, CORS, security and request-id headers. JSON-RPC
434
+ error bodies keep their envelope instead of receiving a top-level request_id.
435
+
436
+ Schemas use an explicitly bounded vocabulary: type, enum, const, properties,
437
+ required, additionalProperties (boolean), items, minimum/maximum, min/maxLength,
438
+ min/maxItems and pattern, plus descriptive metadata. Unsupported keywords fail
439
+ registration; put additional domain validation in the authorized operation.
440
+ Use object schemas for input and optional structured output. `mcpTextResult`
441
+ serializes the same data in both text and structuredContent. Tool exceptions are
442
+ redacted, with server-side `onError` diagnostics. Expected domain failures may
443
+ return `mcpTextResult(data, true)`. Do not advertise idempotency for a write unless
444
+ the underlying operation guarantees it. `responseHeaders(principal)` can expose
445
+ per-key rate limits. Exact allowedOrigins supplement the request URL's origin.
446
+
447
+ Tests: `core/ai/tests/mcp-server.test.ts`, `core/router/tests/body.test.ts`,
448
+ `core/router/tests/protocol-body.test.ts` and `core/api/tests/operation.test.ts`.
@@ -838,3 +838,12 @@ the foreign-key attributes derived from `belongsTo`. For example,
838
838
  - CORS headers (`Access-Control-Allow-Origin: http://localhost:5173`) are only added in development mode for error responses
839
839
  - Body parsing happens once per request (tracked via `_bodyParsed` flag) -- JSON, URL-encoded, and multipart/form-data are all supported
840
840
  - `response.json()` catches circular reference errors and returns `{ error: 'Response data could not be serialized' }` instead of throwing
841
+
842
+ ## Sharing an authorized operation across transports
843
+
844
+ `defineApiOperation({ authorize, handle })` from `@stacksjs/api/operation` returns
845
+ an immutable operation with `execute(context)`. Every execution awaits authorize
846
+ before invoking handle. Authenticate the context at each transport boundary;
847
+ keep scope and resource-ownership checks in the operation and its domain helpers.
848
+ This lets HTTP routes, native MCP tools and jobs share behavior without an HTTP
849
+ loopback or a second implementation of the same business rules.
@@ -12,10 +12,10 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
12
12
  |---|---|---|---|
13
13
  | `@stacksjs/action-runner` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/action-runner/src/index.ts) | 1 |
14
14
  | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 70 |
15
- | `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 15 |
15
+ | `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 16 |
16
16
  | `@stacksjs/alias` | [`stacks-alias`](../stacks-alias/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/alias/src/index.ts) | 1 |
17
17
  | `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 6 |
18
- | `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 7 |
18
+ | `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 8 |
19
19
  | `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 6 |
20
20
  | `@stacksjs/audio` | [`stacks-audio`](../stacks-audio/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/audio/src/index.ts) | 2 |
21
21
  | `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 114 |
@@ -35,7 +35,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
35
35
  | `@stacksjs/composables` | [`stacks-composables`](../stacks-composables/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/composables/src/index.ts) | 18 |
36
36
  | `@stacksjs/config` | [`stacks-config`](../stacks-config/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/config/src/index.ts) | 16 |
37
37
  | `@stacksjs/cron` | [`stacks-cron`](../stacks-cron/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cron/src/index.ts) | 4 |
38
- | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 121 |
38
+ | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 123 |
39
39
  | `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 12 |
40
40
  | `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 1 |
41
41
  | `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
@@ -68,24 +68,24 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
68
68
  | `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 61 |
69
69
  | `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
70
70
  | `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 10 |
71
- | `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 23 |
71
+ | `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 24 |
72
72
  | `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 6 |
73
73
  | `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 6 |
74
74
  | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 48 |
75
75
  | `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 11 |
76
76
  | `@stacksjs/registry` | [`stacks-registry`](../stacks-registry/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/registry/src/index.ts) | 1 |
77
77
  | `@stacksjs/repl` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/repl/src/index.ts) | 2 |
78
- | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 87 |
78
+ | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 89 |
79
79
  | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 13 |
80
80
  | `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 10 |
81
- | `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 8 |
81
+ | `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 10 |
82
82
  | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 21 |
83
83
  | `@stacksjs/shell` | [`stacks-shell`](../stacks-shell/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/shell/src/index.ts) | 1 |
84
84
  | `@stacksjs/sites` | [`stacks-sites`](../stacks-sites/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sites/src/index.ts) | 3 |
85
85
  | `@stacksjs/skills` | [`stacks-skills`](../stacks-skills/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/skills/src/index.ts) | 1 |
86
86
  | `@stacksjs/slug` | [`stacks-slug`](../stacks-slug/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/index.ts) | 4 |
87
87
  | `@stacksjs/sms` | [`stacks-sms`](../stacks-sms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sms/src/index.ts) | 5 |
88
- | `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 12 |
88
+ | `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 15 |
89
89
  | `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) | 37 |
90
90
  | `@stacksjs/strings` | [`stacks-strings`](../stacks-strings/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/index.ts) | 7 |
91
91
  | `@stacksjs/testing` | [`stacks-testing`](../stacks-testing/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/index.ts) | 11 |
@@ -127,9 +127,9 @@ Guidance: [`stacks-ai`](../stacks-ai/SKILL.md). Source: [storage/framework/core/
127
127
 
128
128
  Declared runtime exports: `assistantTurn`, `buildMessageWithImages`, `clearUsageReporters`, `estimateMessageTokens`, `estimateTokens`, `fetchWithRetry`, `listUsageReporters`, `normalizeMessagesForProvider`, `onUsage`, `recordUsage`, `sanitizePrompt`, `toolResultsTurn`.
129
129
 
130
- Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
130
+ Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp-server.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
131
131
 
132
- Evidence directory: [15 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
132
+ Evidence directory: [16 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
133
133
 
134
134
  ### @stacksjs/alias
135
135
 
@@ -155,9 +155,9 @@ Guidance: [`stacks-api`](../stacks-api/SKILL.md). Source: [storage/framework/cor
155
155
 
156
156
  Read the entrypoint and package export map for re-exported or type-only surfaces.
157
157
 
158
- Local source modules: [src/fetcher.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/fetcher.ts), [src/generate-client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-client.ts), [src/generate-openapi.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-openapi.ts), [src/generate-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-types.ts), [src/resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/resource.ts).
158
+ Local source modules: [src/fetcher.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/fetcher.ts), [src/generate-client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-client.ts), [src/generate-openapi.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-openapi.ts), [src/generate-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/generate-types.ts), [src/operation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/operation.ts), [src/resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/resource.ts).
159
159
 
160
- Evidence directory: [7 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
160
+ Evidence directory: [8 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
161
161
 
162
162
  ### @stacksjs/arrays
163
163
 
@@ -351,7 +351,7 @@ Declared runtime exports: `BUN_BROKEN_MYSQL_POOL_MESSAGE`, `BUN_BROKEN_POSTGRES_
351
351
 
352
352
  Local source modules: [src/affected-rows.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/affected-rows.ts), [src/auth-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/auth-tables.ts), [src/broken-pool.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/broken-pool.ts), [src/custom/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/custom/index.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/database.ts), [src/datetime-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/datetime-columns.ts), [src/ddl-constraints.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ddl-constraints.ts), [src/defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/defaults.ts), [src/dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/dialect.ts), [src/driver-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/driver-config.ts), [src/drivers/dynamodb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/dynamodb.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/index.ts), [src/ensure-database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ensure-database.ts), [src/erd.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/erd.ts), [src/fk-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/fk-audit.ts), [src/framework-renames.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-renames.ts), [src/hand-written-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/hand-written-migrations.ts), [src/ignored-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ignored-migrations.ts), [src/index-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index-shape.ts), [src/managed-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/managed-columns.ts), [src/migration-dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-dialect.ts), [src/migration-ledger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-ledger.ts), [src/migration-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-names.ts), [src/migration-path.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-path.ts), [src/migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migrations.ts), [src/model-sources.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/model-sources.ts), [src/notification-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/notification-tables.ts), [src/package-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-migrations.ts), [src/package-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-models.ts), [src/query-logger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/query-logger.ts), [src/rbac-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/rbac-tables.ts), [src/relation-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/relation-columns.ts), [src/replicas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/replicas.ts), [src/row-lock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lock.ts), [src/safe-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/safe-migrations.ts), [src/schema-align.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-align.ts), [src/schema-drift.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-drift.ts), [src/seeder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/seeder.ts), [src/shadowed-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/shadowed-models.ts), [src/sql-helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/sql-helpers.ts), [src/trait-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/trait-tables.ts), [src/transaction-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-context.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/types.ts), [src/unique-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/unique-audit.ts), [src/utc-defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utc-defaults.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utils.ts), [src/uuid-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/uuid-columns.ts), [src/vschema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/vschema.ts).
353
353
 
354
- Evidence directory: [121 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
354
+ Evidence directory: [123 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
355
355
 
356
356
  ### @stacksjs/datetime
357
357
 
@@ -657,7 +657,7 @@ Declared runtime exports: `Payment`, `freshIdempotencyKey`, `stacksIdempotencyKe
657
657
 
658
658
  Local source modules: [src/billable/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/billable/index.ts), [src/connect/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/connect/index.ts), [src/direct-debit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/direct-debit.ts), [src/driver/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/driver/index.ts), [src/drivers/stripe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/drivers/stripe.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/idempotency.ts), [src/payment.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/payment.ts), [src/subscription-state.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/subscription-state.ts), [src/terminal.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/terminal.ts).
659
659
 
660
- Evidence directory: [23 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
660
+ Evidence directory: [24 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
661
661
 
662
662
  ### @stacksjs/push
663
663
 
@@ -717,11 +717,11 @@ Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/m
717
717
 
718
718
  Guidance: [`stacks-router`](../stacks-router/SKILL.md). Source: [storage/framework/core/router/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts).
719
719
 
720
- Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `rateLimit`, `rateLimitStatus`, `request`, `resetBootHooks`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `url`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withTraceId`, `wrapAction`.
720
+ Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `rateLimit`, `rateLimitStatus`, `readJsonBody`, `request`, `resetBootHooks`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `url`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withTraceId`, `wrapAction`.
721
721
 
722
- Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
722
+ Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/body.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
723
723
 
724
- Evidence directory: [87 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
724
+ Evidence directory: [89 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
725
725
 
726
726
  ### @stacksjs/scheduler
727
727
 
@@ -751,7 +751,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
751
751
 
752
752
  Local source modules: [src/api-key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/api-key.ts), [src/crypt.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/crypt.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/hash.ts), [src/key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/key.ts), [src/outbound.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/outbound.ts), [src/webhook.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/webhook.ts).
753
753
 
754
- Evidence directory: [8 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
754
+ Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
755
755
 
756
756
  ### @stacksjs/server
757
757
 
@@ -819,7 +819,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
819
819
 
820
820
  Local source modules: [src/abstract.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/abstract.ts), [src/authorize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/authorize.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/drivers/index.ts), [src/exceptions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/exceptions.ts), [src/handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/handoff.ts), [src/identities.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/identities.ts), [src/meta-graph.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/meta-graph.ts), [src/publish.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/publish.ts), [src/registry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/registry.ts), [src/token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/token.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/types.ts).
821
821
 
822
- Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
822
+ Evidence directory: [15 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
823
823
 
824
824
  ### @stacksjs/storage
825
825
 
@@ -8,7 +8,17 @@ allowed-tools: Read Edit Write Bash Grep Glob
8
8
 
9
9
  # Stacks Payments
10
10
 
11
- Full Stripe integration via the Payment facade. Uses Stripe API version `2026-01-28.clover`. The Stripe SDK is initialized from `services.stripe.secretKey` (sourced from `config/payment.ts`).
11
+ Full Stripe integration via the Payment facade. The Stripe SDK is initialized from `services.stripe.secretKey` (sourced from `config/payment.ts`), at the API version the installed SDK declares (`Stripe.API_VERSION`), not a version written down here.
12
+
13
+ ## The Stripe SDK is the app's dependency, not the framework's
14
+
15
+ `stripe` is an **optional peer** of `@stacksjs/payments`, and Bun does not install optional peers. An app that uses Stripe has to declare it: `bun add stripe`, **pinned to an exact version, not a range**. The driver refuses to start when `services.stripe.apiVersion` does not equal the installed SDK's `Stripe.API_VERSION`, so a range that resolves to a new major on the next `bun install` breaks billing (stacksjs/stacks#2911).
16
+
17
+ Nothing throws at import, by design, so an app missing the SDK starts clean and every health check passes. Ask before using it rather than finding out inside a webhook handler:
18
+
19
+ - `isStripeConfigured()` - true only when a secret key is set **and** the SDK resolves. It used to check only the key, and answered true on a tree where every Stripe call would throw.
20
+ - `stripeAvailability()` - `{ key, sdk }`, to tell the two apart. They are fixed in different places: one in the environment, one in the app's package.json.
21
+ - `describeStripeAvailability(available)` - one sentence naming everything missing, or null when Stripe is usable. Suitable for a boot log or a health endpoint.
12
22
 
13
23
  ## Payment Drivers (provider-neutral)
14
24
 
@@ -385,3 +385,14 @@ url('user.show', { id: 42 }) // '/users/42'
385
385
  - Query tracking is for debug/profiling — call `clearTrackedQueries()` to free memory
386
386
  - The dev server writes a route manifest to `storage/framework/stx/routes.ts` (stx's `stateDir`, set in `config/ui.ts`); it is a build artifact, not a file to edit
387
387
  - The health endpoint returns uptime, memory, PID, and Bun version info
388
+
389
+ ## Protocol-owned request bodies
390
+
391
+ For MCP or another wire protocol with its own validation and error envelope,
392
+ `route.post('/mcp', handler).parseBody(false)` leaves the body unread for the
393
+ handler. This does not disable middleware or CSRF: choose authentication and CSRF
394
+ policy explicitly. Duplicate registrations cannot change the live route's policy.
395
+ Use `readJsonBody(request, maxBytes)` from `@stacksjs/router/body` for a streamed
396
+ byte limit, media-type and strict UTF-8 checks. `RequestBodyError.status` is
397
+ 400, 413 or 415. Normal app routes continue using the standard request macros.
398
+ JSON-RPC error envelopes keep their shape; X-Request-ID remains in the headers.
@@ -169,11 +169,23 @@ the receiver's check (tolerance applies both ways). `generateWebhookSecret()`
169
169
  mints a `whsec_` secret; store it encrypted, since signing needs the plaintext.
170
170
 
171
171
  Outbound requests to a URL a user typed (webhook endpoints, import-from-URL)
172
- go through `outboundUrlProblem(url, { allowHttp?, allowPrivate? })` when the
173
- URL is saved and `await assertPublicOutboundUrl(url, opts)` right before the
174
- request: https only, no credentials, and every resolved address public
175
- (`isPrivateAddress` covers loopback, RFC 1918, CGNAT, link-local metadata,
176
- IPv4-mapped/NAT64/6to4 forms). It throws `OutboundUrlError` with a `reason`.
172
+ go through `await fetchPublicUrl(url, init?, opts?)`, which makes the request
173
+ rather than blessing it: https only, no credentials, every resolved address
174
+ public (`isPrivateAddress` covers loopback, RFC 1918, CGNAT, link-local
175
+ metadata, IPv4-mapped/NAT64/6to4 forms), **every redirect hop re-checked by
176
+ the same rules**, the connection pinned to an address that was checked (name
177
+ kept in `Host` and TLS SNI), `Authorization`/`Cookie` dropped across an
178
+ origin change, and the body and duration capped. It throws `OutboundUrlError`
179
+ with a `reason`.
180
+
181
+ `outboundUrlProblem(url, opts)` is the cheap check for when the URL is saved,
182
+ and `assertPublicOutboundUrl(url, opts)` the check alone. **Checking is not
183
+ fetching.** A caller that validates and then calls `fetch` has given the
184
+ guarantee back: `fetch` defaults to `redirect: 'follow'`, so a validated host
185
+ answering `302 Location: http://169.254.169.254/...` is followed unchecked,
186
+ and `fetch` resolves the name a second time, so the address that was approved
187
+ is not the address connected to (stacksjs/stacks#2909). Use `fetchPublicUrl`
188
+ unless you know you want only the check.
177
189
  API keys handed to integrations: `generateApiKey('myapp_live_')` returns
178
190
  `{ key, hash, hint }`; show `key` once, store `hash` (`hashApiKey`), list `hint`.
179
191
 
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.187",
5
+ "version": "0.75.189",
6
6
  "description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.187",
5
+ "version": "0.75.189",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@iconify-json/f7": "^1.2.2",
57
57
  "@iconify-json/hugeicons": "^1.2.35",
58
- "@stacksjs/mobile": "0.75.187",
58
+ "@stacksjs/mobile": "0.75.189",
59
59
  "@stacksjs/sanitizer": "^0.2.534",
60
60
  "@xterm/addon-fit": "^0.11.0",
61
61
  "@xterm/xterm": "^6.0.0",