@valbuild/next 0.120.4 → 0.122.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.
- package/CHANGELOG.md +167 -0
- package/README.md +19 -0
- package/dist/{ValApp-e17eb734.esm.js → ValApp-074c8289.esm.js} +1 -1
- package/dist/ValApp-17eb6e93.cjs.js +7 -0
- package/dist/{ValApp-90c4171d.cjs.prod.js → ValApp-17eb6e93.cjs.prod.js} +1 -1
- package/dist/{ValApp-c1c3ef55.cjs.dev.js → ValApp-2bdb460a.cjs.dev.js} +1 -1
- package/dist/{ValNextProvider-f206d2ea.cjs.dev.js → ValNextProvider-016a494b.cjs.dev.js} +1 -1
- package/dist/{ValNextProvider-588f2ff0.esm.js → ValNextProvider-32156acd.esm.js} +1 -1
- package/dist/ValNextProvider-72d3561b.cjs.js +7 -0
- package/dist/{ValNextProvider-bd3f89d3.cjs.prod.js → ValNextProvider-72d3561b.cjs.prod.js} +1 -1
- package/dist/declarations/src/server/initValMcp.d.ts +5 -5
- package/dist/{fallbackColors-5ead2c26.esm.js → fallbackColors-77aeedf8.esm.js} +2 -2
- package/dist/{fallbackColors-d4a5b0da.cjs.prod.js → fallbackColors-8842243c.cjs.prod.js} +2 -2
- package/dist/{fallbackColors-9a2ac53a.cjs.dev.js → fallbackColors-a491e700.cjs.dev.js} +2 -2
- package/dist/valbuild-next.cjs.dev.js +2 -2
- package/dist/valbuild-next.cjs.prod.js +2 -2
- package/dist/valbuild-next.esm.js +2 -2
- package/package.json +7 -7
- package/rsc/dist/valbuild-next-rsc.cjs.dev.js +26 -2
- package/rsc/dist/valbuild-next-rsc.cjs.prod.js +26 -2
- package/rsc/dist/valbuild-next-rsc.esm.js +26 -2
- package/server/dist/valbuild-next-server.cjs.dev.js +43 -28
- package/server/dist/valbuild-next-server.cjs.prod.js +43 -28
- package/server/dist/valbuild-next-server.esm.js +43 -28
- package/dist/ValApp-90c4171d.cjs.js +0 -7
- package/dist/ValNextProvider-bd3f89d3.cjs.js +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,172 @@
|
|
|
1
1
|
# @valbuild/next
|
|
2
2
|
|
|
3
|
+
## 0.122.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#597](https://github.com/valbuild/val/pull/597) [`5d14612`](https://github.com/valbuild/val/commit/5d14612f612d657a37338136188f2b3c02b28fe7) Thanks [@freekh](https://github.com/freekh)! - MCP: remove personal access token auth. The endpoint now needs an `oauth`
|
|
8
|
+
config, or local filesystem mode.
|
|
9
|
+
|
|
10
|
+
Until now, an MCP endpoint with no `oauth` config accepted whatever bearer token
|
|
11
|
+
a caller presented and relayed it to the Val content backend unread. The
|
|
12
|
+
reasoning was that without an issuer the app has no key to check a token
|
|
13
|
+
against, so it should not pretend to be the authority on what that token may
|
|
14
|
+
do — and that much was right. The shape was not: a credential the app cannot
|
|
15
|
+
check is one it cannot refuse either, so "a deployed endpoint that authenticates
|
|
16
|
+
nobody" was a supported configuration, and an app could serve content-rewriting
|
|
17
|
+
tools without ever being told where its callers should authorize.
|
|
18
|
+
|
|
19
|
+
**If you run Val in proxy mode**, MCP now requires the `oauth` config that
|
|
20
|
+
shipped in `0.120.0`. Callers authorize as themselves against the Val
|
|
21
|
+
authorization server, this app verifies the token's signature, issuer, audience
|
|
22
|
+
and expiry itself, and patches carry the verified profile as their author:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
initValMcp(valModules, config, {
|
|
26
|
+
oauth: {
|
|
27
|
+
issuer: "https://admin.val.build",
|
|
28
|
+
resource: "https://your-app.com/api/mcp",
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Leave it out and the endpoint answers `500` naming the missing config, rather
|
|
34
|
+
than serving the request.
|
|
35
|
+
|
|
36
|
+
**If you run Val in local filesystem mode**, nothing changes. Local development
|
|
37
|
+
still needs no `oauth` config and no authorization server: there is no backend
|
|
38
|
+
to authenticate to, and patches are written with no author. A token presented
|
|
39
|
+
to such a project is still refused rather than ignored — the endpoint answers
|
|
40
|
+
`400` and says to take the credential out of the client's configuration, since
|
|
41
|
+
what it reached was a working tree with no permission check in front of it.
|
|
42
|
+
|
|
43
|
+
Two API changes if you built your own host on `createValTools`:
|
|
44
|
+
|
|
45
|
+
- `ValToolContext.auth` no longer has a `{ type: "pat", pat }` variant.
|
|
46
|
+
`{ type: "verified-profile", profileId, scopes }` is the only credential the
|
|
47
|
+
registry accepts, and `null` still means local filesystem mode.
|
|
48
|
+
- `createValOps` no longer takes an `auth` argument. `ValOpsHttp` still accepts
|
|
49
|
+
a personal access token directly — that is how `val debug` uses the token from
|
|
50
|
+
`val login` — but no server request builds one.
|
|
51
|
+
|
|
52
|
+
Proxy mode also stops keeping one data layer per credential. Each personal
|
|
53
|
+
access token needed its own `ValOpsHttp` to hold it, each of those cached the
|
|
54
|
+
project's evaluated modules, and the bounded cache that kept the memory in
|
|
55
|
+
check turned an eviction into a re-evaluation of every module on the next call.
|
|
56
|
+
Verified callers all share one instance, because they all reach the backend
|
|
57
|
+
under the app's own API key.
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- Updated dependencies [[`be32261`](https://github.com/valbuild/val/commit/be32261af19db8018bc37b180d903416018c0b79), [`5d14612`](https://github.com/valbuild/val/commit/5d14612f612d657a37338136188f2b3c02b28fe7), [`da6794f`](https://github.com/valbuild/val/commit/da6794f3dbd77d49ccfe780b359bab1689ee1b11), [`1c8b7fd`](https://github.com/valbuild/val/commit/1c8b7fda1e84cd8bd32a03a85d2789598b98c3fb)]:
|
|
62
|
+
- @valbuild/server@0.122.0
|
|
63
|
+
- @valbuild/shared@0.122.0
|
|
64
|
+
- @valbuild/ui@0.122.0
|
|
65
|
+
- @valbuild/language-server@0.122.0
|
|
66
|
+
- @valbuild/react@0.122.0
|
|
67
|
+
|
|
68
|
+
## 0.121.0
|
|
69
|
+
|
|
70
|
+
### Minor Changes
|
|
71
|
+
|
|
72
|
+
- [#605](https://github.com/valbuild/val/pull/605) [`6794d29`](https://github.com/valbuild/val/commit/6794d2980bc81284ab7f2cc667f01cc21c9e3a79) Thanks [@freekh](https://github.com/freekh)! - `s.settings()`: the project's settings, as content.
|
|
73
|
+
|
|
74
|
+
A settings module is one per project, at the root of the content tree:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// settings.val.ts
|
|
78
|
+
export default c.define("/settings.val.ts", s.settings(), {});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Register it in `val.modules.ts` like any other module, and it shows up in the
|
|
82
|
+
Studio under the cog at the foot of the left rail. Everything in it is content:
|
|
83
|
+
it is edited as a draft, it appears in the publish diff, and it is the same for
|
|
84
|
+
everyone working on the project.
|
|
85
|
+
|
|
86
|
+
Every key is optional, at every level, so `{}` is a complete settings module —
|
|
87
|
+
and stays one as sections are added. What it holds today is the assistant:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
export default c.define("/settings.val.ts", s.settings(), {
|
|
91
|
+
assistant: {
|
|
92
|
+
enabled: true,
|
|
93
|
+
context: "A CMS for developers, run by a team of four in Oslo.",
|
|
94
|
+
tone: "Plain and direct. British English, sentence case in headings.",
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`context` is background the assistant would otherwise guess at; `tone` is how it
|
|
100
|
+
should write when it writes content. Both are sent with every message it makes.
|
|
101
|
+
|
|
102
|
+
`enabled` decides whether editors have an assistant, and it has **three** states
|
|
103
|
+
rather than two:
|
|
104
|
+
|
|
105
|
+
- `true` — they do.
|
|
106
|
+
- `false` — they do not, and every trace of it goes: no button in the top bar,
|
|
107
|
+
no row in the quick actions, no panel, nothing sent.
|
|
108
|
+
- unset — nobody has decided. The assistant is still **shown**, and asks to be
|
|
109
|
+
turned on before it is used. Hiding an assistant nobody has decided about
|
|
110
|
+
means nobody discovers it; quietly enabling one means a project starts sending
|
|
111
|
+
its content to a model because it did not know to say no.
|
|
112
|
+
|
|
113
|
+
A project with no settings module at all has an assistant, as before: there is
|
|
114
|
+
nowhere to record a decision, and nowhere for the prompt to write the answer.
|
|
115
|
+
|
|
116
|
+
**Breaking: `ai.chat` is gone from `val.config.ts`.** Whether the assistant is
|
|
117
|
+
available is a decision about the project's content, made by the people who edit
|
|
118
|
+
it, so it moved to settings — turning the chat on used to take a developer, a
|
|
119
|
+
deploy and a code review of a boolean. Remove the whole block:
|
|
120
|
+
|
|
121
|
+
```diff
|
|
122
|
+
const { s, c, val, config } = initVal({
|
|
123
|
+
- ai: {
|
|
124
|
+
- chat: {
|
|
125
|
+
- experimental: { enable: true },
|
|
126
|
+
- suggestions: ["Summarize", "Fix typos at this page"],
|
|
127
|
+
- title: "Ask me anything",
|
|
128
|
+
- description: "Val can answer questions about the content.",
|
|
129
|
+
- },
|
|
130
|
+
- },
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`experimental.enable` becomes `assistant.enabled` in the settings module.
|
|
135
|
+
`suggestions`, `title` and `description` are removed with nothing replacing
|
|
136
|
+
them: the assistant now opens with its own copy. A project that had the chat
|
|
137
|
+
enabled and wants it to stay on for everyone should write
|
|
138
|
+
`assistant: { enabled: true }` — otherwise editors are offered it and asked.
|
|
139
|
+
|
|
140
|
+
`ai.commitMessages` stays in `val.config.ts`, and is unaffected.
|
|
141
|
+
|
|
142
|
+
Two settings modules, or one in a subdirectory, is a module error: the dev
|
|
143
|
+
server refuses to serve sources, `npx val validate` reports it against the file,
|
|
144
|
+
and the Studio says so rather than picking one.
|
|
145
|
+
|
|
146
|
+
### Patch Changes
|
|
147
|
+
|
|
148
|
+
- [#607](https://github.com/valbuild/val/pull/607) [`2bcbee1`](https://github.com/valbuild/val/commit/2bcbee1be682c2bbd5b7bc7d152ddd4204162fd2) Thanks [@freekh](https://github.com/freekh)! - `.readonly()` and `.hidden()` now take the flag as an argument, so a schema can
|
|
149
|
+
decide these from a variable instead of only from whether the call was written at
|
|
150
|
+
all:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
s.string().readonly(!canEdit);
|
|
154
|
+
s.image().hidden(hideMedia);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The argument defaults to `true`, so `.readonly()` and `.readonly(true)` are the
|
|
158
|
+
same thing and nothing about existing schemas changes. Passing `false` leaves the
|
|
159
|
+
field editable or visible, which is also what a schema is without the call - it
|
|
160
|
+
is there so the flag can come from a variable.
|
|
161
|
+
|
|
162
|
+
- Updated dependencies [[`105479b`](https://github.com/valbuild/val/commit/105479b84a08846f1fe5971916f6a54275198d12), [`55ec736`](https://github.com/valbuild/val/commit/55ec73651394908b6f440e360d181b95a91c0a93), [`2bcc6fd`](https://github.com/valbuild/val/commit/2bcc6fdff8d668123e07e3c5e81ac6fa1436e47b), [`2bcbee1`](https://github.com/valbuild/val/commit/2bcbee1be682c2bbd5b7bc7d152ddd4204162fd2), [`6794d29`](https://github.com/valbuild/val/commit/6794d2980bc81284ab7f2cc667f01cc21c9e3a79), [`2db27d5`](https://github.com/valbuild/val/commit/2db27d555441bee2dd31817acc8c92b7b718ee55)]:
|
|
163
|
+
- @valbuild/ui@0.121.0
|
|
164
|
+
- @valbuild/shared@0.121.0
|
|
165
|
+
- @valbuild/server@0.121.0
|
|
166
|
+
- @valbuild/core@0.121.0
|
|
167
|
+
- @valbuild/react@0.121.0
|
|
168
|
+
- @valbuild/language-server@0.121.0
|
|
169
|
+
|
|
3
170
|
## 0.120.4
|
|
4
171
|
|
|
5
172
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
- [Number](#number)
|
|
49
49
|
- [Boolean](#boolean)
|
|
50
50
|
- [Nullable](#nullable)
|
|
51
|
+
- [Read-only and hidden fields](#read-only-and-hidden-fields)
|
|
51
52
|
- [Array](#array)
|
|
52
53
|
- [Record](#record)
|
|
53
54
|
- [Router](#router)
|
|
@@ -384,6 +385,24 @@ import { s } from "./val.config";
|
|
|
384
385
|
s.string().nullable(); // <- Schema<string | null>
|
|
385
386
|
```
|
|
386
387
|
|
|
388
|
+
## Read-only and hidden fields
|
|
389
|
+
|
|
390
|
+
`.readonly()` renders a field disabled in the Val editor, and `.hidden()` leaves
|
|
391
|
+
it out of the editor entirely. Both are UI-only: the value is still stored,
|
|
392
|
+
validated and serialized as normal.
|
|
393
|
+
|
|
394
|
+
Both take an optional flag which defaults to `true`, so `.readonly()` and
|
|
395
|
+
`.readonly(true)` are the same thing. Pass it when the decision comes from a
|
|
396
|
+
variable rather than being written out:
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
import { s } from "./val.config";
|
|
400
|
+
|
|
401
|
+
s.string().readonly(); // same as .readonly(true)
|
|
402
|
+
s.string().readonly(!canEdit);
|
|
403
|
+
s.image().hidden(hideMedia);
|
|
404
|
+
```
|
|
405
|
+
|
|
387
406
|
## Description
|
|
388
407
|
|
|
389
408
|
All schema types can be given a human-readable description with `.describe(text)`. Descriptions are shown in the Val editor UI as muted helper text under the field label, helping editors understand what a field is for without leaving the page.
|
|
@@ -3,7 +3,7 @@ import { _ as _slicedToArray } from './slicedToArray-aa291011.esm.js';
|
|
|
3
3
|
import { VERSION, VAL_APP_PATH, VAL_APP_ID } from '@valbuild/ui';
|
|
4
4
|
import Script from 'next/script';
|
|
5
5
|
import { useState, useRef, useEffect } from 'react';
|
|
6
|
-
import { u as useConfigStorageSave, v as valPrefixedClass, c as cn, a as canvasDarkBg, b as canvasLightBg } from './fallbackColors-
|
|
6
|
+
import { u as useConfigStorageSave, v as valPrefixedClass, c as cn, a as canvasDarkBg, b as canvasLightBg } from './fallbackColors-77aeedf8.esm.js';
|
|
7
7
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import './unsupportedIterableToArray-5baabfdc.esm.js';
|
|
9
9
|
import '@valbuild/shared/internal';
|
|
@@ -7,7 +7,7 @@ var slicedToArray = require('./slicedToArray-ce613de6.cjs.prod.js');
|
|
|
7
7
|
var ui = require('@valbuild/ui');
|
|
8
8
|
var Script = require('next/script');
|
|
9
9
|
var React = require('react');
|
|
10
|
-
var fallbackColors = require('./fallbackColors-
|
|
10
|
+
var fallbackColors = require('./fallbackColors-8842243c.cjs.prod.js');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
12
|
require('./unsupportedIterableToArray-0d2087a2.cjs.prod.js');
|
|
13
13
|
require('@valbuild/shared/internal');
|
|
@@ -7,7 +7,7 @@ var slicedToArray = require('./slicedToArray-44036a76.cjs.dev.js');
|
|
|
7
7
|
var ui = require('@valbuild/ui');
|
|
8
8
|
var Script = require('next/script');
|
|
9
9
|
var React = require('react');
|
|
10
|
-
var fallbackColors = require('./fallbackColors-
|
|
10
|
+
var fallbackColors = require('./fallbackColors-a491e700.cjs.dev.js');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
12
|
require('./unsupportedIterableToArray-c8ab77c9.cjs.dev.js');
|
|
13
13
|
require('@valbuild/shared/internal');
|
|
@@ -13,7 +13,7 @@ var React = require('react');
|
|
|
13
13
|
var ValOverlayContext = require('./ValOverlayContext-5bd7628b.cjs.dev.js');
|
|
14
14
|
var stega = require('@valbuild/react/stega');
|
|
15
15
|
var internal = require('@valbuild/shared/internal');
|
|
16
|
-
var fallbackColors = require('./fallbackColors-
|
|
16
|
+
var fallbackColors = require('./fallbackColors-a491e700.cjs.dev.js');
|
|
17
17
|
var createForOfIteratorHelper = require('./createForOfIteratorHelper-0445603c.cjs.dev.js');
|
|
18
18
|
var ValCanvasBridge = require('./ValCanvasBridge-9d148bdd.cjs.dev.js');
|
|
19
19
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -9,7 +9,7 @@ import React, { useEffect } from 'react';
|
|
|
9
9
|
import { ValExternalStore, ValOverlayProvider } from './ValOverlayContext-e42a2e14.esm.js';
|
|
10
10
|
import { SET_AUTO_TAG_JSX_ENABLED } from '@valbuild/react/stega';
|
|
11
11
|
import { VAL_THEME_SESSION_STORAGE_KEY, createValClient, isValCanvasFrame } from '@valbuild/shared/internal';
|
|
12
|
-
import { p as prefixStyles, u as useConfigStorageSave, f as floatDarkBg, d as floatLightBg, v as valPrefixedClass, c as cn } from './fallbackColors-
|
|
12
|
+
import { p as prefixStyles, u as useConfigStorageSave, f as floatDarkBg, d as floatLightBg, v as valPrefixedClass, c as cn } from './fallbackColors-77aeedf8.esm.js';
|
|
13
13
|
import { _ as _createForOfIteratorHelper } from './createForOfIteratorHelper-5758a730.esm.js';
|
|
14
14
|
import { ValCanvasBridge } from './ValCanvasBridge-d9948526.esm.js';
|
|
15
15
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -13,7 +13,7 @@ var React = require('react');
|
|
|
13
13
|
var ValOverlayContext = require('./ValOverlayContext-d690744f.cjs.prod.js');
|
|
14
14
|
var stega = require('@valbuild/react/stega');
|
|
15
15
|
var internal = require('@valbuild/shared/internal');
|
|
16
|
-
var fallbackColors = require('./fallbackColors-
|
|
16
|
+
var fallbackColors = require('./fallbackColors-8842243c.cjs.prod.js');
|
|
17
17
|
var createForOfIteratorHelper = require('./createForOfIteratorHelper-d4afcad8.cjs.prod.js');
|
|
18
18
|
var ValCanvasBridge = require('./ValCanvasBridge-e62125f8.cjs.prod.js');
|
|
19
19
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -52,11 +52,11 @@ export declare function initValMcp(valModules: ValModules, config: ValConfig, op
|
|
|
52
52
|
/**
|
|
53
53
|
* Where to authorize, and what audience to expect.
|
|
54
54
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* needs a verified access token
|
|
59
|
-
* refused rather than ignored
|
|
55
|
+
* Required for proxy mode, and only omittable in local filesystem mode —
|
|
56
|
+
* where there is no authorization server to talk to and no backend to
|
|
57
|
+
* authenticate to, so local development stays a one-liner. Provide it and
|
|
58
|
+
* every call needs a verified access token, including in fs mode, where a
|
|
59
|
+
* token is refused rather than ignored: a host that thinks it is
|
|
60
60
|
* authenticating should never silently get unauthenticated local access.
|
|
61
61
|
*/
|
|
62
62
|
oauth?: ValOAuthConfig;
|
|
@@ -48,11 +48,11 @@ var cn = function cn(className) {
|
|
|
48
48
|
/** `--bg-canvas`, dark. The studio's own background. */
|
|
49
49
|
var canvasDarkBg = "#08080a";
|
|
50
50
|
/** `--bg-canvas`, light. */
|
|
51
|
-
var canvasLightBg = "#
|
|
51
|
+
var canvasLightBg = "#f4f4f5";
|
|
52
52
|
|
|
53
53
|
/** `--bg-float`, dark. Val's chrome, floating over the customer's page. */
|
|
54
54
|
var floatDarkBg = "#131316";
|
|
55
55
|
/** `--bg-float`, light. */
|
|
56
|
-
var floatLightBg = "#
|
|
56
|
+
var floatLightBg = "#fcfcfc";
|
|
57
57
|
|
|
58
58
|
export { canvasDarkBg as a, canvasLightBg as b, cn as c, floatLightBg as d, floatDarkBg as f, prefixStyles as p, useConfigStorageSave as u, valPrefixedClass as v };
|
|
@@ -54,12 +54,12 @@ var cn = function cn(className) {
|
|
|
54
54
|
/** `--bg-canvas`, dark. The studio's own background. */
|
|
55
55
|
var canvasDarkBg = "#08080a";
|
|
56
56
|
/** `--bg-canvas`, light. */
|
|
57
|
-
var canvasLightBg = "#
|
|
57
|
+
var canvasLightBg = "#f4f4f5";
|
|
58
58
|
|
|
59
59
|
/** `--bg-float`, dark. Val's chrome, floating over the customer's page. */
|
|
60
60
|
var floatDarkBg = "#131316";
|
|
61
61
|
/** `--bg-float`, light. */
|
|
62
|
-
var floatLightBg = "#
|
|
62
|
+
var floatLightBg = "#fcfcfc";
|
|
63
63
|
|
|
64
64
|
exports.canvasDarkBg = canvasDarkBg;
|
|
65
65
|
exports.canvasLightBg = canvasLightBg;
|
|
@@ -54,12 +54,12 @@ var cn = function cn(className) {
|
|
|
54
54
|
/** `--bg-canvas`, dark. The studio's own background. */
|
|
55
55
|
var canvasDarkBg = "#08080a";
|
|
56
56
|
/** `--bg-canvas`, light. */
|
|
57
|
-
var canvasLightBg = "#
|
|
57
|
+
var canvasLightBg = "#f4f4f5";
|
|
58
58
|
|
|
59
59
|
/** `--bg-float`, dark. Val's chrome, floating over the customer's page. */
|
|
60
60
|
var floatDarkBg = "#131316";
|
|
61
61
|
/** `--bg-float`, light. */
|
|
62
|
-
var floatLightBg = "#
|
|
62
|
+
var floatLightBg = "#fcfcfc";
|
|
63
63
|
|
|
64
64
|
exports.canvasDarkBg = canvasDarkBg;
|
|
65
65
|
exports.canvasLightBg = canvasLightBg;
|
|
@@ -7,10 +7,10 @@ var objectSpread2 = require('./objectSpread2-58024783.cjs.dev.js');
|
|
|
7
7
|
var core = require('@valbuild/core');
|
|
8
8
|
var stega = require('@valbuild/react/stega');
|
|
9
9
|
var internal = require('@valbuild/react/internal');
|
|
10
|
-
var ValNextProvider = require('./ValNextProvider-
|
|
10
|
+
var ValNextProvider = require('./ValNextProvider-016a494b.cjs.dev.js');
|
|
11
11
|
var NextImage = require('next/image');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
|
-
var ValApp = require('./ValApp-
|
|
13
|
+
var ValApp = require('./ValApp-2bdb460a.cjs.dev.js');
|
|
14
14
|
var ValModulesClient = require('./ValModulesClient-4ecabf99.cjs.dev.js');
|
|
15
15
|
var createForOfIteratorHelper = require('./createForOfIteratorHelper-0445603c.cjs.dev.js');
|
|
16
16
|
require('./defineProperty-f90345d7.cjs.dev.js');
|
|
@@ -7,10 +7,10 @@ var objectSpread2 = require('./objectSpread2-13f847a9.cjs.prod.js');
|
|
|
7
7
|
var core = require('@valbuild/core');
|
|
8
8
|
var stega = require('@valbuild/react/stega');
|
|
9
9
|
var internal = require('@valbuild/react/internal');
|
|
10
|
-
var ValNextProvider = require('./ValNextProvider-
|
|
10
|
+
var ValNextProvider = require('./ValNextProvider-72d3561b.cjs.prod.js');
|
|
11
11
|
var NextImage = require('next/image');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
|
-
var ValApp = require('./ValApp-
|
|
13
|
+
var ValApp = require('./ValApp-17eb6e93.cjs.prod.js');
|
|
14
14
|
var ValModulesClient = require('./ValModulesClient-10c0721c.cjs.prod.js');
|
|
15
15
|
var createForOfIteratorHelper = require('./createForOfIteratorHelper-d4afcad8.cjs.prod.js');
|
|
16
16
|
require('./defineProperty-8951f469.cjs.prod.js');
|
|
@@ -6,10 +6,10 @@ export { core as expr };
|
|
|
6
6
|
export { GenericSelector, Schema, VAL_EXTENSION, derefPatch, modules } from '@valbuild/core';
|
|
7
7
|
import { stegaEncode, stegaDecodeStrings, attrs, raw, autoTagJSX } from '@valbuild/react/stega';
|
|
8
8
|
export { ValRichText } from '@valbuild/react/internal';
|
|
9
|
-
import { ValNextProvider } from './ValNextProvider-
|
|
9
|
+
import { ValNextProvider } from './ValNextProvider-32156acd.esm.js';
|
|
10
10
|
import NextImage from 'next/image';
|
|
11
11
|
import { jsx } from 'react/jsx-runtime';
|
|
12
|
-
export { ValApp } from './ValApp-
|
|
12
|
+
export { ValApp } from './ValApp-074c8289.esm.js';
|
|
13
13
|
export { ValModulesClient, useRegisterValModules } from './ValModulesClient-0dd601a1.esm.js';
|
|
14
14
|
import { _ as _createForOfIteratorHelper } from './createForOfIteratorHelper-5758a730.esm.js';
|
|
15
15
|
import './defineProperty-cca5affa.esm.js';
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"next",
|
|
13
13
|
"react"
|
|
14
14
|
],
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.122.0",
|
|
16
16
|
"main": "dist/valbuild-next.cjs.js",
|
|
17
17
|
"module": "dist/valbuild-next.esm.js",
|
|
18
18
|
"exports": {
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"client-only": "^0.0.1",
|
|
49
49
|
"server-only": "^0.0.1",
|
|
50
|
-
"@valbuild/
|
|
51
|
-
"@valbuild/
|
|
52
|
-
"@valbuild/
|
|
53
|
-
"@valbuild/
|
|
54
|
-
"@valbuild/language-server": "0.
|
|
55
|
-
"@valbuild/ui": "0.
|
|
50
|
+
"@valbuild/core": "0.121.0",
|
|
51
|
+
"@valbuild/react": "0.122.0",
|
|
52
|
+
"@valbuild/server": "0.122.0",
|
|
53
|
+
"@valbuild/shared": "0.122.0",
|
|
54
|
+
"@valbuild/language-server": "0.122.0",
|
|
55
|
+
"@valbuild/ui": "0.122.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@testing-library/react": "^16.3.3",
|
|
@@ -92,7 +92,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
|
|
|
92
92
|
validate_binary_files: false,
|
|
93
93
|
exclude_patches: false,
|
|
94
94
|
// RSC pre-render uses the legacy "server applies patches" path.
|
|
95
|
-
apply_patches: undefined
|
|
95
|
+
apply_patches: undefined,
|
|
96
|
+
/*
|
|
97
|
+
* The caller's own staged work, and nobody else's.
|
|
98
|
+
*
|
|
99
|
+
* A draft render cannot name its group ids — it has no client
|
|
100
|
+
* state — so it asks for "mine" and the server resolves them from
|
|
101
|
+
* the session. Without this a preview shows base + every pending
|
|
102
|
+
* patch on the branch, so one person's half-finished edit appears
|
|
103
|
+
* in another person's draft.
|
|
104
|
+
*
|
|
105
|
+
* `patch_id` stays `undefined`: naming an explicit list is for a
|
|
106
|
+
* caller that already knows what it wants, and it would override
|
|
107
|
+
* the resolution rather than intersect with it.
|
|
108
|
+
*/
|
|
109
|
+
patch_id: undefined,
|
|
110
|
+
own_patch_groups_only: true
|
|
96
111
|
},
|
|
97
112
|
cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(internal.VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
|
|
98
113
|
});
|
|
@@ -408,7 +423,16 @@ function _loadDraftJsonEntry() {
|
|
|
408
423
|
// single-entry shape
|
|
409
424
|
offset: undefined,
|
|
410
425
|
limit: undefined,
|
|
411
|
-
apply_patches: true
|
|
426
|
+
apply_patches: true,
|
|
427
|
+
/*
|
|
428
|
+
* Scoped the same way the module content beside it is.
|
|
429
|
+
*
|
|
430
|
+
* A draft page renders both, and this call was unscoped — so one page
|
|
431
|
+
* showed base + the caller's group for its modules and base + EVERY
|
|
432
|
+
* pending patch on the branch for any `jsonValues` entry, including other
|
|
433
|
+
* authors' half-finished edits. See the same flag on `/sources/~` above.
|
|
434
|
+
*/
|
|
435
|
+
own_patch_groups_only: true
|
|
412
436
|
},
|
|
413
437
|
cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(internal.VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
|
|
414
438
|
});
|
|
@@ -92,7 +92,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
|
|
|
92
92
|
validate_binary_files: false,
|
|
93
93
|
exclude_patches: false,
|
|
94
94
|
// RSC pre-render uses the legacy "server applies patches" path.
|
|
95
|
-
apply_patches: undefined
|
|
95
|
+
apply_patches: undefined,
|
|
96
|
+
/*
|
|
97
|
+
* The caller's own staged work, and nobody else's.
|
|
98
|
+
*
|
|
99
|
+
* A draft render cannot name its group ids — it has no client
|
|
100
|
+
* state — so it asks for "mine" and the server resolves them from
|
|
101
|
+
* the session. Without this a preview shows base + every pending
|
|
102
|
+
* patch on the branch, so one person's half-finished edit appears
|
|
103
|
+
* in another person's draft.
|
|
104
|
+
*
|
|
105
|
+
* `patch_id` stays `undefined`: naming an explicit list is for a
|
|
106
|
+
* caller that already knows what it wants, and it would override
|
|
107
|
+
* the resolution rather than intersect with it.
|
|
108
|
+
*/
|
|
109
|
+
patch_id: undefined,
|
|
110
|
+
own_patch_groups_only: true
|
|
96
111
|
},
|
|
97
112
|
cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(internal.VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
|
|
98
113
|
});
|
|
@@ -408,7 +423,16 @@ function _loadDraftJsonEntry() {
|
|
|
408
423
|
// single-entry shape
|
|
409
424
|
offset: undefined,
|
|
410
425
|
limit: undefined,
|
|
411
|
-
apply_patches: true
|
|
426
|
+
apply_patches: true,
|
|
427
|
+
/*
|
|
428
|
+
* Scoped the same way the module content beside it is.
|
|
429
|
+
*
|
|
430
|
+
* A draft page renders both, and this call was unscoped — so one page
|
|
431
|
+
* showed base + the caller's group for its modules and base + EVERY
|
|
432
|
+
* pending patch on the branch for any `jsonValues` entry, including other
|
|
433
|
+
* authors' half-finished edits. See the same flag on `/sources/~` above.
|
|
434
|
+
*/
|
|
435
|
+
own_patch_groups_only: true
|
|
412
436
|
},
|
|
413
437
|
cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(internal.VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
|
|
414
438
|
});
|
|
@@ -88,7 +88,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
|
|
|
88
88
|
validate_binary_files: false,
|
|
89
89
|
exclude_patches: false,
|
|
90
90
|
// RSC pre-render uses the legacy "server applies patches" path.
|
|
91
|
-
apply_patches: undefined
|
|
91
|
+
apply_patches: undefined,
|
|
92
|
+
/*
|
|
93
|
+
* The caller's own staged work, and nobody else's.
|
|
94
|
+
*
|
|
95
|
+
* A draft render cannot name its group ids — it has no client
|
|
96
|
+
* state — so it asks for "mine" and the server resolves them from
|
|
97
|
+
* the session. Without this a preview shows base + every pending
|
|
98
|
+
* patch on the branch, so one person's half-finished edit appears
|
|
99
|
+
* in another person's draft.
|
|
100
|
+
*
|
|
101
|
+
* `patch_id` stays `undefined`: naming an explicit list is for a
|
|
102
|
+
* caller that already knows what it wants, and it would override
|
|
103
|
+
* the resolution rather than intersect with it.
|
|
104
|
+
*/
|
|
105
|
+
patch_id: undefined,
|
|
106
|
+
own_patch_groups_only: true
|
|
92
107
|
},
|
|
93
108
|
cookies: _defineProperty({}, VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
|
|
94
109
|
});
|
|
@@ -404,7 +419,16 @@ function _loadDraftJsonEntry() {
|
|
|
404
419
|
// single-entry shape
|
|
405
420
|
offset: undefined,
|
|
406
421
|
limit: undefined,
|
|
407
|
-
apply_patches: true
|
|
422
|
+
apply_patches: true,
|
|
423
|
+
/*
|
|
424
|
+
* Scoped the same way the module content beside it is.
|
|
425
|
+
*
|
|
426
|
+
* A draft page renders both, and this call was unscoped — so one page
|
|
427
|
+
* showed base + the caller's group for its modules and base + EVERY
|
|
428
|
+
* pending patch on the branch for any `jsonValues` entry, including other
|
|
429
|
+
* authors' half-finished edits. See the same flag on `/sources/~` above.
|
|
430
|
+
*/
|
|
431
|
+
own_patch_groups_only: true
|
|
408
432
|
},
|
|
409
433
|
cookies: _defineProperty({}, VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
|
|
410
434
|
});
|
|
@@ -924,7 +924,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
924
924
|
},
|
|
925
925
|
valMcpAuthorize: function valMcpAuthorize(request) {
|
|
926
926
|
return version._asyncToGenerator(/*#__PURE__*/version._regenerator().m(function _callee3() {
|
|
927
|
-
var setup, refusal, sessionId, verified, status,
|
|
927
|
+
var setup, refusal, sessionId, verified, status, _t;
|
|
928
928
|
return version._regenerator().w(function (_context3) {
|
|
929
929
|
while (1) switch (_context3.p = _context3.n) {
|
|
930
930
|
case 0:
|
|
@@ -967,20 +967,51 @@ function initValMcp(valModules, config, opts) {
|
|
|
967
967
|
response: refusal
|
|
968
968
|
});
|
|
969
969
|
case 5:
|
|
970
|
-
// Not the MCP session id, in
|
|
970
|
+
// Not the MCP session id, in any branch below. Val's patch `sessionId`
|
|
971
971
|
// names a Val AI session, and putting an unrelated id in it would claim a
|
|
972
972
|
// relationship that does not exist.
|
|
973
973
|
sessionId = null;
|
|
974
|
-
if (
|
|
974
|
+
if (oauth) {
|
|
975
975
|
_context3.n = 8;
|
|
976
976
|
break;
|
|
977
977
|
}
|
|
978
|
-
|
|
979
|
-
|
|
978
|
+
if (!(setup.mode !== "fs")) {
|
|
979
|
+
_context3.n = 6;
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
return _context3.a(2, {
|
|
983
|
+
status: "refused",
|
|
984
|
+
response: jsonResponse(500, {
|
|
985
|
+
error: "Val: this MCP endpoint has no `oauth` config, and this project is configured to talk to the Val content backend. Pass `oauth` to `initValMcp` with the authorization server's URL and this endpoint's own URL, so callers authorize as themselves."
|
|
986
|
+
})
|
|
987
|
+
});
|
|
980
988
|
case 6:
|
|
989
|
+
if (!(readBearerToken(request) !== null)) {
|
|
990
|
+
_context3.n = 7;
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
return _context3.a(2, {
|
|
994
|
+
status: "refused",
|
|
995
|
+
response: jsonResponse(400, {
|
|
996
|
+
error: "Val: this project is running in local filesystem mode, where there is nothing to authenticate against — the tools read and write this working tree directly. Remove the credential from this MCP client's configuration: a token sent here is checked by nothing."
|
|
997
|
+
})
|
|
998
|
+
});
|
|
999
|
+
case 7:
|
|
1000
|
+
return _context3.a(2, {
|
|
1001
|
+
status: "ok",
|
|
1002
|
+
tools: setup.tools,
|
|
1003
|
+
ctx: {
|
|
1004
|
+
auth: null,
|
|
1005
|
+
sessionId: sessionId
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
case 8:
|
|
1009
|
+
_context3.n = 9;
|
|
1010
|
+
return verifyValAccessToken(request, oauth);
|
|
1011
|
+
case 9:
|
|
981
1012
|
verified = _context3.v;
|
|
982
1013
|
if (!(verified.status === "refused")) {
|
|
983
|
-
_context3.n =
|
|
1014
|
+
_context3.n = 10;
|
|
984
1015
|
break;
|
|
985
1016
|
}
|
|
986
1017
|
// 401 for a missing or bad token, 403 once the token is good but does
|
|
@@ -1003,7 +1034,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
1003
1034
|
}
|
|
1004
1035
|
})
|
|
1005
1036
|
});
|
|
1006
|
-
case
|
|
1037
|
+
case 10:
|
|
1007
1038
|
return _context3.a(2, {
|
|
1008
1039
|
status: "ok",
|
|
1009
1040
|
tools: setup.tools,
|
|
@@ -1012,23 +1043,6 @@ function initValMcp(valModules, config, opts) {
|
|
|
1012
1043
|
sessionId: sessionId
|
|
1013
1044
|
}
|
|
1014
1045
|
});
|
|
1015
|
-
case 8:
|
|
1016
|
-
pat = readBearerToken(request);
|
|
1017
|
-
return _context3.a(2, {
|
|
1018
|
-
status: "ok",
|
|
1019
|
-
tools: setup.tools,
|
|
1020
|
-
ctx: {
|
|
1021
|
-
// Passed through unverified, deliberately: without an `oauth` config
|
|
1022
|
-
// this app has no key to check anything against, so it is not the
|
|
1023
|
-
// authority on what the token may do and the registry sends it to the
|
|
1024
|
-
// backend that is. See `docs/plans/mcp.md` D.2.
|
|
1025
|
-
auth: pat === null ? null : {
|
|
1026
|
-
type: "pat",
|
|
1027
|
-
pat: pat
|
|
1028
|
-
},
|
|
1029
|
-
sessionId: sessionId
|
|
1030
|
-
}
|
|
1031
|
-
});
|
|
1032
1046
|
}
|
|
1033
1047
|
}, _callee3, null, [[0, 2]]);
|
|
1034
1048
|
}))();
|
|
@@ -1046,7 +1060,8 @@ function initValMcp(valModules, config, opts) {
|
|
|
1046
1060
|
* that is unauthenticated write access to the site's content for anyone who
|
|
1047
1061
|
* can reach the port. There is no configuration that makes it safe, so there
|
|
1048
1062
|
* is no flag to turn this off — a project that wants MCP in production wants
|
|
1049
|
-
* proxy mode, where every call carries
|
|
1063
|
+
* proxy mode with an `oauth` config, where every call carries an access
|
|
1064
|
+
* token this app verified itself.
|
|
1050
1065
|
*
|
|
1051
1066
|
* 2. **A browser driving the local server.** A page on any origin can `fetch`
|
|
1052
1067
|
* `http://localhost:3000/api/mcp` while a developer has the app running, and
|
|
@@ -1103,9 +1118,9 @@ var LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
|
1103
1118
|
*
|
|
1104
1119
|
* The cost is that behind a proxy that rewrites `Host`, a *browser* request
|
|
1105
1120
|
* whose `Origin` is the public name no longer matches. That is acceptable: such
|
|
1106
|
-
* a request carries no
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1121
|
+
* a request carries no access token, so proxy mode refuses it anyway, and a
|
|
1122
|
+
* non-browser MCP client sends no `Origin` and never reaches the comparison.
|
|
1123
|
+
* Trusting the forwarded header would need an explicit trusted-proxy
|
|
1109
1124
|
* configuration, which is a bigger thing than this needs.
|
|
1110
1125
|
*/
|
|
1111
1126
|
function requestHost(request) {
|
|
@@ -924,7 +924,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
924
924
|
},
|
|
925
925
|
valMcpAuthorize: function valMcpAuthorize(request) {
|
|
926
926
|
return version._asyncToGenerator(/*#__PURE__*/version._regenerator().m(function _callee3() {
|
|
927
|
-
var setup, refusal, sessionId, verified, status,
|
|
927
|
+
var setup, refusal, sessionId, verified, status, _t;
|
|
928
928
|
return version._regenerator().w(function (_context3) {
|
|
929
929
|
while (1) switch (_context3.p = _context3.n) {
|
|
930
930
|
case 0:
|
|
@@ -967,20 +967,51 @@ function initValMcp(valModules, config, opts) {
|
|
|
967
967
|
response: refusal
|
|
968
968
|
});
|
|
969
969
|
case 5:
|
|
970
|
-
// Not the MCP session id, in
|
|
970
|
+
// Not the MCP session id, in any branch below. Val's patch `sessionId`
|
|
971
971
|
// names a Val AI session, and putting an unrelated id in it would claim a
|
|
972
972
|
// relationship that does not exist.
|
|
973
973
|
sessionId = null;
|
|
974
|
-
if (
|
|
974
|
+
if (oauth) {
|
|
975
975
|
_context3.n = 8;
|
|
976
976
|
break;
|
|
977
977
|
}
|
|
978
|
-
|
|
979
|
-
|
|
978
|
+
if (!(setup.mode !== "fs")) {
|
|
979
|
+
_context3.n = 6;
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
return _context3.a(2, {
|
|
983
|
+
status: "refused",
|
|
984
|
+
response: jsonResponse(500, {
|
|
985
|
+
error: "Val: this MCP endpoint has no `oauth` config, and this project is configured to talk to the Val content backend. Pass `oauth` to `initValMcp` with the authorization server's URL and this endpoint's own URL, so callers authorize as themselves."
|
|
986
|
+
})
|
|
987
|
+
});
|
|
980
988
|
case 6:
|
|
989
|
+
if (!(readBearerToken(request) !== null)) {
|
|
990
|
+
_context3.n = 7;
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
return _context3.a(2, {
|
|
994
|
+
status: "refused",
|
|
995
|
+
response: jsonResponse(400, {
|
|
996
|
+
error: "Val: this project is running in local filesystem mode, where there is nothing to authenticate against — the tools read and write this working tree directly. Remove the credential from this MCP client's configuration: a token sent here is checked by nothing."
|
|
997
|
+
})
|
|
998
|
+
});
|
|
999
|
+
case 7:
|
|
1000
|
+
return _context3.a(2, {
|
|
1001
|
+
status: "ok",
|
|
1002
|
+
tools: setup.tools,
|
|
1003
|
+
ctx: {
|
|
1004
|
+
auth: null,
|
|
1005
|
+
sessionId: sessionId
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
case 8:
|
|
1009
|
+
_context3.n = 9;
|
|
1010
|
+
return verifyValAccessToken(request, oauth);
|
|
1011
|
+
case 9:
|
|
981
1012
|
verified = _context3.v;
|
|
982
1013
|
if (!(verified.status === "refused")) {
|
|
983
|
-
_context3.n =
|
|
1014
|
+
_context3.n = 10;
|
|
984
1015
|
break;
|
|
985
1016
|
}
|
|
986
1017
|
// 401 for a missing or bad token, 403 once the token is good but does
|
|
@@ -1003,7 +1034,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
1003
1034
|
}
|
|
1004
1035
|
})
|
|
1005
1036
|
});
|
|
1006
|
-
case
|
|
1037
|
+
case 10:
|
|
1007
1038
|
return _context3.a(2, {
|
|
1008
1039
|
status: "ok",
|
|
1009
1040
|
tools: setup.tools,
|
|
@@ -1012,23 +1043,6 @@ function initValMcp(valModules, config, opts) {
|
|
|
1012
1043
|
sessionId: sessionId
|
|
1013
1044
|
}
|
|
1014
1045
|
});
|
|
1015
|
-
case 8:
|
|
1016
|
-
pat = readBearerToken(request);
|
|
1017
|
-
return _context3.a(2, {
|
|
1018
|
-
status: "ok",
|
|
1019
|
-
tools: setup.tools,
|
|
1020
|
-
ctx: {
|
|
1021
|
-
// Passed through unverified, deliberately: without an `oauth` config
|
|
1022
|
-
// this app has no key to check anything against, so it is not the
|
|
1023
|
-
// authority on what the token may do and the registry sends it to the
|
|
1024
|
-
// backend that is. See `docs/plans/mcp.md` D.2.
|
|
1025
|
-
auth: pat === null ? null : {
|
|
1026
|
-
type: "pat",
|
|
1027
|
-
pat: pat
|
|
1028
|
-
},
|
|
1029
|
-
sessionId: sessionId
|
|
1030
|
-
}
|
|
1031
|
-
});
|
|
1032
1046
|
}
|
|
1033
1047
|
}, _callee3, null, [[0, 2]]);
|
|
1034
1048
|
}))();
|
|
@@ -1046,7 +1060,8 @@ function initValMcp(valModules, config, opts) {
|
|
|
1046
1060
|
* that is unauthenticated write access to the site's content for anyone who
|
|
1047
1061
|
* can reach the port. There is no configuration that makes it safe, so there
|
|
1048
1062
|
* is no flag to turn this off — a project that wants MCP in production wants
|
|
1049
|
-
* proxy mode, where every call carries
|
|
1063
|
+
* proxy mode with an `oauth` config, where every call carries an access
|
|
1064
|
+
* token this app verified itself.
|
|
1050
1065
|
*
|
|
1051
1066
|
* 2. **A browser driving the local server.** A page on any origin can `fetch`
|
|
1052
1067
|
* `http://localhost:3000/api/mcp` while a developer has the app running, and
|
|
@@ -1103,9 +1118,9 @@ var LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
|
1103
1118
|
*
|
|
1104
1119
|
* The cost is that behind a proxy that rewrites `Host`, a *browser* request
|
|
1105
1120
|
* whose `Origin` is the public name no longer matches. That is acceptable: such
|
|
1106
|
-
* a request carries no
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1121
|
+
* a request carries no access token, so proxy mode refuses it anyway, and a
|
|
1122
|
+
* non-browser MCP client sends no `Origin` and never reaches the comparison.
|
|
1123
|
+
* Trusting the forwarded header would need an explicit trusted-proxy
|
|
1109
1124
|
* configuration, which is a bigger thing than this needs.
|
|
1110
1125
|
*/
|
|
1111
1126
|
function requestHost(request) {
|
|
@@ -920,7 +920,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
920
920
|
},
|
|
921
921
|
valMcpAuthorize: function valMcpAuthorize(request) {
|
|
922
922
|
return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
923
|
-
var setup, refusal, sessionId, verified, status,
|
|
923
|
+
var setup, refusal, sessionId, verified, status, _t;
|
|
924
924
|
return _regenerator().w(function (_context3) {
|
|
925
925
|
while (1) switch (_context3.p = _context3.n) {
|
|
926
926
|
case 0:
|
|
@@ -963,20 +963,51 @@ function initValMcp(valModules, config, opts) {
|
|
|
963
963
|
response: refusal
|
|
964
964
|
});
|
|
965
965
|
case 5:
|
|
966
|
-
// Not the MCP session id, in
|
|
966
|
+
// Not the MCP session id, in any branch below. Val's patch `sessionId`
|
|
967
967
|
// names a Val AI session, and putting an unrelated id in it would claim a
|
|
968
968
|
// relationship that does not exist.
|
|
969
969
|
sessionId = null;
|
|
970
|
-
if (
|
|
970
|
+
if (oauth) {
|
|
971
971
|
_context3.n = 8;
|
|
972
972
|
break;
|
|
973
973
|
}
|
|
974
|
-
|
|
975
|
-
|
|
974
|
+
if (!(setup.mode !== "fs")) {
|
|
975
|
+
_context3.n = 6;
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
return _context3.a(2, {
|
|
979
|
+
status: "refused",
|
|
980
|
+
response: jsonResponse(500, {
|
|
981
|
+
error: "Val: this MCP endpoint has no `oauth` config, and this project is configured to talk to the Val content backend. Pass `oauth` to `initValMcp` with the authorization server's URL and this endpoint's own URL, so callers authorize as themselves."
|
|
982
|
+
})
|
|
983
|
+
});
|
|
976
984
|
case 6:
|
|
985
|
+
if (!(readBearerToken(request) !== null)) {
|
|
986
|
+
_context3.n = 7;
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
return _context3.a(2, {
|
|
990
|
+
status: "refused",
|
|
991
|
+
response: jsonResponse(400, {
|
|
992
|
+
error: "Val: this project is running in local filesystem mode, where there is nothing to authenticate against — the tools read and write this working tree directly. Remove the credential from this MCP client's configuration: a token sent here is checked by nothing."
|
|
993
|
+
})
|
|
994
|
+
});
|
|
995
|
+
case 7:
|
|
996
|
+
return _context3.a(2, {
|
|
997
|
+
status: "ok",
|
|
998
|
+
tools: setup.tools,
|
|
999
|
+
ctx: {
|
|
1000
|
+
auth: null,
|
|
1001
|
+
sessionId: sessionId
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
case 8:
|
|
1005
|
+
_context3.n = 9;
|
|
1006
|
+
return verifyValAccessToken(request, oauth);
|
|
1007
|
+
case 9:
|
|
977
1008
|
verified = _context3.v;
|
|
978
1009
|
if (!(verified.status === "refused")) {
|
|
979
|
-
_context3.n =
|
|
1010
|
+
_context3.n = 10;
|
|
980
1011
|
break;
|
|
981
1012
|
}
|
|
982
1013
|
// 401 for a missing or bad token, 403 once the token is good but does
|
|
@@ -999,7 +1030,7 @@ function initValMcp(valModules, config, opts) {
|
|
|
999
1030
|
}
|
|
1000
1031
|
})
|
|
1001
1032
|
});
|
|
1002
|
-
case
|
|
1033
|
+
case 10:
|
|
1003
1034
|
return _context3.a(2, {
|
|
1004
1035
|
status: "ok",
|
|
1005
1036
|
tools: setup.tools,
|
|
@@ -1008,23 +1039,6 @@ function initValMcp(valModules, config, opts) {
|
|
|
1008
1039
|
sessionId: sessionId
|
|
1009
1040
|
}
|
|
1010
1041
|
});
|
|
1011
|
-
case 8:
|
|
1012
|
-
pat = readBearerToken(request);
|
|
1013
|
-
return _context3.a(2, {
|
|
1014
|
-
status: "ok",
|
|
1015
|
-
tools: setup.tools,
|
|
1016
|
-
ctx: {
|
|
1017
|
-
// Passed through unverified, deliberately: without an `oauth` config
|
|
1018
|
-
// this app has no key to check anything against, so it is not the
|
|
1019
|
-
// authority on what the token may do and the registry sends it to the
|
|
1020
|
-
// backend that is. See `docs/plans/mcp.md` D.2.
|
|
1021
|
-
auth: pat === null ? null : {
|
|
1022
|
-
type: "pat",
|
|
1023
|
-
pat: pat
|
|
1024
|
-
},
|
|
1025
|
-
sessionId: sessionId
|
|
1026
|
-
}
|
|
1027
|
-
});
|
|
1028
1042
|
}
|
|
1029
1043
|
}, _callee3, null, [[0, 2]]);
|
|
1030
1044
|
}))();
|
|
@@ -1042,7 +1056,8 @@ function initValMcp(valModules, config, opts) {
|
|
|
1042
1056
|
* that is unauthenticated write access to the site's content for anyone who
|
|
1043
1057
|
* can reach the port. There is no configuration that makes it safe, so there
|
|
1044
1058
|
* is no flag to turn this off — a project that wants MCP in production wants
|
|
1045
|
-
* proxy mode, where every call carries
|
|
1059
|
+
* proxy mode with an `oauth` config, where every call carries an access
|
|
1060
|
+
* token this app verified itself.
|
|
1046
1061
|
*
|
|
1047
1062
|
* 2. **A browser driving the local server.** A page on any origin can `fetch`
|
|
1048
1063
|
* `http://localhost:3000/api/mcp` while a developer has the app running, and
|
|
@@ -1099,9 +1114,9 @@ var LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
|
1099
1114
|
*
|
|
1100
1115
|
* The cost is that behind a proxy that rewrites `Host`, a *browser* request
|
|
1101
1116
|
* whose `Origin` is the public name no longer matches. That is acceptable: such
|
|
1102
|
-
* a request carries no
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1117
|
+
* a request carries no access token, so proxy mode refuses it anyway, and a
|
|
1118
|
+
* non-browser MCP client sends no `Origin` and never reaches the comparison.
|
|
1119
|
+
* Trusting the forwarded header would need an explicit trusted-proxy
|
|
1105
1120
|
* configuration, which is a bigger thing than this needs.
|
|
1106
1121
|
*/
|
|
1107
1122
|
function requestHost(request) {
|