@valbuild/server 0.122.0 → 0.123.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 CHANGED
@@ -1,5 +1,97 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.123.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#613](https://github.com/valbuild/val/pull/613) [`c5e7dfd`](https://github.com/valbuild/val/commit/c5e7dfd12aa1371195be642e1c2fb72b6f3e3ce2) Thanks [@freekh](https://github.com/freekh)! - Val's MCP endpoint moves to its own package, and can now upload images
8
+
9
+ Everything that serves Val's content tools over MCP — the tool registry, the
10
+ write path behind it, the request guards and the access-token verification —
11
+ now lives in **`@valbuild/mcp`** instead of being split between
12
+ `@valbuild/server` and `@valbuild/next`.
13
+
14
+ **Nothing changes for an app that already mounts it.** `initValMcp` is still
15
+ exported from `@valbuild/next/server` and behaves exactly as before; it is now a
16
+ ten-line binding over `@valbuild/mcp`, supplying the Next version that
17
+ `initHandlerOptions` asks for. A host that is not Next can call
18
+ `initValMcp` from `@valbuild/mcp` directly.
19
+
20
+ If you built your own host on `createValTools`, import it from `@valbuild/mcp`
21
+ rather than `@valbuild/server`; the tool types moved with it.
22
+
23
+ ## Image uploads
24
+
25
+ An agent can now add an image, with a new `upload_image` tool. It takes a path
26
+ to a file on the machine your app runs on, or the image inline as base64, and
27
+ puts it in an `s.image()` field or an `s.images()` gallery.
28
+
29
+ Uploads are converted **only where the Studio would convert them**: `encode` is
30
+ off unless the schema asks for it (`s.image({ encode: { type: "webp" } })`), and
31
+ when it does, which images are converted, how far they are scaled and when the
32
+ original wins are the same decisions the browser makes — the same code, now
33
+ shared. An upload to a schema without `encode` is stored exactly as it arrived,
34
+ whatever its size.
35
+
36
+ One thing the tool does that the Studio does not: it refuses an image the
37
+ schema's `accept` does not cover, checked on the bytes that would actually be
38
+ stored. The Studio does not need to — its file picker carries `accept` — and
39
+ validation reports a mismatch as server-repairable, so nothing downstream would
40
+ stop it. An agent has no picker. Note the ordering:
41
+ `s.image({ accept: "image/webp", encode: { type: "webp" } })` still takes a PNG,
42
+ because the conversion happens first and it is the result that is checked.
43
+
44
+ It is the one tool you construct yourself, because it needs an image library
45
+ and `sharp` ships a compiled binary per platform. Val does not put one in every
46
+ project that installs it, so you decide:
47
+
48
+ ```sh
49
+ npm install sharp
50
+ ```
51
+
52
+ ```ts
53
+ import sharp from "sharp";
54
+ import { createValImageTools } from "@valbuild/mcp";
55
+ import { sharpImageProcessor } from "@valbuild/mcp/sharp";
56
+
57
+ const { valMcpAuthorize, valMcpTools } = initValMcp(valModules, config, {
58
+ extraTools: createValImageTools(sharpImageProcessor(sharp)),
59
+ });
60
+ ```
61
+
62
+ Leave `extraTools` out and everything else works as before — the agent can read,
63
+ validate and edit content, it just cannot add an image. `sharp` is passed in
64
+ rather than imported, so you can supply another encoder: `ValImageProcessor` is
65
+ two functions, `read` and `encode`.
66
+
67
+ Remotely stored images work too — `s.image().remote()` and
68
+ `s.images({ remote: true })` — and they need nothing extra from the MCP client.
69
+ Adding one does not upload anything to Val's content host: the bytes go into the
70
+ patch store like any other unpublished change, and the push to
71
+ `remote.val.build` happens when you publish, exactly as it does for an image
72
+ added through the Studio. All the tool has to do first is ask the project which
73
+ bucket to name in the ref, and the credential for that is the one your app
74
+ already has — its API key when it has one, and in local development the
75
+ `val login` token in your project, the same one `val validate --fix` uses. If
76
+ you have not logged in, it says so and writes nothing.
77
+
78
+ ## `npm create @valbuild` asks
79
+
80
+ The starter template now ships the MCP endpoint, and `npm create @valbuild`
81
+ asks whether you want it — and, if you do, whether agents should be able to
82
+ upload images, saying that this adds `sharp`. Both default to yes, and both can
83
+ be answered up front for a scripted setup:
84
+
85
+ ```sh
86
+ pnpm create @valbuild my-app --mcp --no-image-uploads
87
+ ```
88
+
89
+ ### Patch Changes
90
+
91
+ - Updated dependencies [[`c5e7dfd`](https://github.com/valbuild/val/commit/c5e7dfd12aa1371195be642e1c2fb72b6f3e3ce2), [`53f670c`](https://github.com/valbuild/val/commit/53f670c0cf2d7a03a6d068c78b7874ce77652c2a)]:
92
+ - @valbuild/shared@0.123.0
93
+ - @valbuild/ui@0.123.0
94
+
3
95
  ## 0.122.0
4
96
 
5
97
  ### Minor Changes
@@ -2,10 +2,9 @@ export { createService, Service } from "./Service.js";
2
2
  export { defineExternal, ok, err, isExternalResult, EXTERNAL_RESULT, } from "./externalRecords.js";
3
3
  export type { AdapterFor, BoundExternalRecord, ExternalAuthor, ExternalBuilder, ExternalCtx, ExternalDefinition, ExternalFile, ExternalIssue, ExternalKeyPage, ExternalRecords, ExternalResult, ExternalSearchHit, ExternalSearchPage, ExternalSort, ItemOfModule, ReadonlyRecordHasNoWrites, Returns, } from "./externalRecords.js";
4
4
  export { createValApiRouter, createValServer, safeReadGit } from "./ValRouter.js";
5
- export { createValTools } from "./tools/index.js";
6
- export { VAL_SCOPE_READ, VAL_SCOPE_WRITE, authorIdFromVerifiedSubject, } from "./tools/index.js";
7
- export type { ValScope, ValToolAuth, ValToolContext, ValToolDefinition, ValToolDefinitionJson, ValToolErrorCode, ValToolResult, ValTools, ValToolsOptions, } from "./tools/index.js";
8
5
  export { initHandlerOptions, createValOps } from "./valServerConfig.js";
6
+ export { resolveRemoteFileAuth } from "./valServerConfig.js";
7
+ export type { RemoteFileAuth, ResolveRemoteFileAuthResult, } from "./valServerConfig.js";
9
8
  export { ValModuleLoader } from "./ValModuleLoader.js";
10
9
  export { getCompilerOptions } from "./getCompilerOptions.js";
11
10
  export { ValSourceFileHandler } from "./ValSourceFileHandler.js";
@@ -47,6 +46,9 @@ export { formatPatchSourceError } from "./ValOps.js";
47
46
  export { compareWithCapturedReport, readCapturedReport, replaySnapshot, } from "./debug/replaySnapshot.js";
48
47
  export type { ReplayComparison, ReplayResult } from "./debug/replaySnapshot.js";
49
48
  export type { OrderedPatches, PatchAnalysis, PatchSourceError, PreparedCommit, } from "./ValOps.js";
49
+ export type { ValOps } from "./ValOps.js";
50
+ export type { AuthorId, BinaryFileType, MetadataOfType, Schemas, Sources, } from "./ValOps.js";
51
+ export type { ValServerConfig } from "./ValServer.js";
50
52
  /**
51
53
  * The local-dev patch store, exported so the CLI's debug tooling can read a
52
54
  * snapshot back with the same code the server uses rather than a second
@@ -81,4 +81,41 @@ type CredentialBearingUrl = "valBuildUrl" | "valContentUrl";
81
81
  * internal http host today.
82
82
  */
83
83
  export declare function insecureUrlWarning(name: CredentialBearingUrl, url: string): string | null;
84
+ /**
85
+ * Which credential talks to the content host about REMOTE FILES.
86
+ *
87
+ * A separate question from the one `createValOps` answers, and it has to be:
88
+ * `ValOps` is authenticated per caller, but remote files are project-level —
89
+ * looking up a project's public id and its buckets, and later pushing bytes to
90
+ * them, is the same operation whoever asked for it.
91
+ *
92
+ * The rule, in order:
93
+ *
94
+ * 1. The app's API key, if there is one. Proxy mode always has one; fs mode has
95
+ * one when `VAL_API_KEY` is set.
96
+ * 2. In fs mode, the developer's own `val login` token, read off disk. This is
97
+ * the same file `val validate --fix` reads, and it is why local remote
98
+ * uploads work with no configuration beyond having logged in.
99
+ * 3. Nothing, which is an error rather than a fallback.
100
+ *
101
+ * Lives here rather than inside `createValServer` because the MCP image tool
102
+ * needs the same answer, and this is the file that exists so that two callers
103
+ * cannot disagree about how a project is configured. A registry that decided it
104
+ * had no credential while the Studio in the same process had one would be a
105
+ * genuinely confusing afternoon.
106
+ */
107
+ export type RemoteFileAuth = {
108
+ apiKey: string;
109
+ } | {
110
+ pat: string;
111
+ };
112
+ export type ResolveRemoteFileAuthResult = {
113
+ status: "success";
114
+ auth: RemoteFileAuth;
115
+ } | {
116
+ status: "error";
117
+ errorCode: "project-not-configured" | "pat-error";
118
+ message: string;
119
+ };
120
+ export declare function resolveRemoteFileAuth(options: ValServerConfig): Promise<ResolveRemoteFileAuthResult>;
84
121
  export {};