@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 +92 -0
- package/dist/declarations/src/index.d.ts +5 -3
- package/dist/declarations/src/valServerConfig.d.ts +37 -0
- package/dist/valbuild-server.cjs.dev.js +138 -1372
- package/dist/valbuild-server.cjs.prod.js +138 -1372
- package/dist/valbuild-server.esm.js +138 -1369
- package/package.json +3 -3
- package/dist/declarations/src/tools/createValTools.d.ts +0 -41
- package/dist/declarations/src/tools/defineTool.d.ts +0 -69
- package/dist/declarations/src/tools/index.d.ts +0 -3
- package/dist/declarations/src/tools/types.d.ts +0 -163
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"./package.json": "./package.json"
|
|
17
17
|
},
|
|
18
18
|
"types": "dist/valbuild-server.cjs.d.ts",
|
|
19
|
-
"version": "0.
|
|
19
|
+
"version": "0.123.0",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@prettier/sync": "^0.6.1",
|
|
22
22
|
"@types/jest": "^30.0.0"
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
31
|
"zod-validation-error": "^5.0.0",
|
|
32
32
|
"@valbuild/core": "0.121.0",
|
|
33
|
-
"@valbuild/shared": "0.
|
|
34
|
-
"@valbuild/ui": "0.
|
|
33
|
+
"@valbuild/shared": "0.123.0",
|
|
34
|
+
"@valbuild/ui": "0.123.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": "^20.19.0 || >=22"
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { ValModules } from "@valbuild/core";
|
|
2
|
-
import type { ValServerConfig } from "../ValServer.js";
|
|
3
|
-
import type { ValOps } from "../ValOps.js";
|
|
4
|
-
import type { ValToolState } from "./defineTool.js";
|
|
5
|
-
import { type ValToolResult, type ValTools } from "./types.js";
|
|
6
|
-
export type ValToolsOptions = ValServerConfig;
|
|
7
|
-
/**
|
|
8
|
-
* Val's server-side tool registry.
|
|
9
|
-
*
|
|
10
|
-
* This is the piece Val did not have: the Studio's chat tools are defined *and
|
|
11
|
-
* executed in the browser*, against its client stores, so nothing here could be
|
|
12
|
-
* re-exposed. These tools run against {@link ValOps} instead, which is what lets
|
|
13
|
-
* an MCP server — or a stdio transport, or anything else — drive Val content
|
|
14
|
-
* without a browser.
|
|
15
|
-
*
|
|
16
|
-
* Transport-agnostic on purpose: nothing under `tools/` imports an MCP SDK. A
|
|
17
|
-
* host adapts {@link ValToolResult} at its own edge.
|
|
18
|
-
*/
|
|
19
|
-
export declare function createValTools(valModules: ValModules, options: ValToolsOptions): ValTools;
|
|
20
|
-
/**
|
|
21
|
-
* The content as the caller should see it, loaded once per call.
|
|
22
|
-
*
|
|
23
|
-
* Pending patches are applied, because an agent looking at a project mid-edit
|
|
24
|
-
* should see what the Studio would show rather than the last published state.
|
|
25
|
-
*
|
|
26
|
-
* Deliberately not cached across calls. In fs mode a save recomputes the base
|
|
27
|
-
* sha within the same process, so a cached view would go stale silently — and
|
|
28
|
-
* the cost of being wrong here is an agent writing a patch against content that
|
|
29
|
-
* has already moved.
|
|
30
|
-
*
|
|
31
|
-
* Exported for `toolsFixture`, not for consumers: `tools/index.ts` re-exports by
|
|
32
|
-
* name, so this stays inside the package. A test that assembled its own state
|
|
33
|
-
* would be asserting against a view no real call ever sees.
|
|
34
|
-
*/
|
|
35
|
-
export declare function loadState(ops: ValOps): Promise<{
|
|
36
|
-
status: "ok";
|
|
37
|
-
state: ValToolState;
|
|
38
|
-
} | {
|
|
39
|
-
status: "error";
|
|
40
|
-
result: ValToolResult;
|
|
41
|
-
}>;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { Json, ModuleFilePath, PatchId, SerializedSchema } from "@valbuild/core";
|
|
2
|
-
import type { z } from "zod";
|
|
3
|
-
import type { ValOps, OrderedPatches, PatchAnalysis, Schemas, Sources } from "../ValOps.js";
|
|
4
|
-
import type { ValToolContext, ValToolDefinition, ValToolErrorCode, ValToolResult } from "./types.js";
|
|
5
|
-
/**
|
|
6
|
-
* How a tool is written, and what it is handed.
|
|
7
|
-
*
|
|
8
|
-
* Tools are defined with {@link defineTool} so that the handler's `args` are
|
|
9
|
-
* inferred from the tool's own `inputSchema`. Without that the array of tools
|
|
10
|
-
* would have to be typed at its widest and every handler would start by
|
|
11
|
-
* re-narrowing `unknown`, which is exactly where a tool and its schema drift
|
|
12
|
-
* apart unnoticed.
|
|
13
|
-
*/
|
|
14
|
-
/** Everything a tool is allowed to reach. Deliberately narrow. */
|
|
15
|
-
export type ValToolDeps = {
|
|
16
|
-
/**
|
|
17
|
-
* The data layer for *this call*. In proxy mode it is authenticated as the
|
|
18
|
-
* caller, so a tool must never reach for an ambient instance instead.
|
|
19
|
-
*/
|
|
20
|
-
ops: ValOps;
|
|
21
|
-
ctx: ValToolContext;
|
|
22
|
-
/**
|
|
23
|
-
* The content as the caller should see it: base sources with pending patches
|
|
24
|
-
* applied, plus the schemas and the patch analysis that produced them.
|
|
25
|
-
*
|
|
26
|
-
* Loaded once per call and shared, because a tool that re-derived it would
|
|
27
|
-
* both pay for it again and risk reading a different revision than the one it
|
|
28
|
-
* validated against.
|
|
29
|
-
*/
|
|
30
|
-
state: ValToolState;
|
|
31
|
-
};
|
|
32
|
-
export type ValToolState = {
|
|
33
|
-
schemas: Schemas;
|
|
34
|
-
serializedSchemas: Record<ModuleFilePath, SerializedSchema>;
|
|
35
|
-
sources: Sources;
|
|
36
|
-
patches: OrderedPatches;
|
|
37
|
-
analysis: PatchAnalysis;
|
|
38
|
-
/**
|
|
39
|
-
* Pending patches that would not apply, by the module they belong to.
|
|
40
|
-
*
|
|
41
|
-
* A module listed here has `sources` that silently lack those changes, so its
|
|
42
|
-
* content is not what publishing would produce. Reads still return it — it is
|
|
43
|
-
* what the Studio would show too, and a project has to stay diagnosable — but
|
|
44
|
-
* a write to such a module is refused, because it would be based on a state
|
|
45
|
-
* that does not exist.
|
|
46
|
-
*/
|
|
47
|
-
unappliedPatches: Record<ModuleFilePath, {
|
|
48
|
-
patchId: PatchId;
|
|
49
|
-
skipped: boolean;
|
|
50
|
-
error: {
|
|
51
|
-
message: string;
|
|
52
|
-
};
|
|
53
|
-
}[]>;
|
|
54
|
-
};
|
|
55
|
-
export type ValToolImpl = ValToolDefinition & {
|
|
56
|
-
handler: (args: unknown, deps: ValToolDeps) => Promise<ValToolResult>;
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Declare a tool, binding its handler to its input schema.
|
|
60
|
-
*
|
|
61
|
-
* The handler receives already-parsed arguments: the registry validates against
|
|
62
|
-
* `inputSchema` before calling, so a handler never sees input its schema would
|
|
63
|
-
* have rejected.
|
|
64
|
-
*/
|
|
65
|
-
export declare function defineTool<S extends z.ZodType>(definition: Omit<ValToolDefinition, "inputSchema"> & {
|
|
66
|
-
inputSchema: S;
|
|
67
|
-
}, handler: (args: z.infer<S>, deps: ValToolDeps) => Promise<ValToolResult>): ValToolImpl;
|
|
68
|
-
export declare function ok(data: Json): ValToolResult;
|
|
69
|
-
export declare function err(code: ValToolErrorCode, message: string): ValToolResult;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export { createValTools, type ValToolsOptions } from "./createValTools.js";
|
|
2
|
-
export { VAL_SCOPE_READ, VAL_SCOPE_WRITE, authorIdFromVerifiedSubject, } from "./types.js";
|
|
3
|
-
export type { ValScope, ValToolAuth, ValToolContext, ValToolDefinition, ValToolDefinitionJson, ValToolErrorCode, ValToolResult, ValTools, } from "./types.js";
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import type { AuthorId } from "../ValOps.js";
|
|
2
|
-
import type { Json } from "@valbuild/core";
|
|
3
|
-
import type { z } from "zod";
|
|
4
|
-
/**
|
|
5
|
-
* The public surface of Val's server-side tool registry.
|
|
6
|
-
*
|
|
7
|
-
* Types only, deliberately: this file is the contract that the MCP hosts, the
|
|
8
|
-
* CLI's stdio transport and the tools themselves are all written against, and
|
|
9
|
-
* keeping it free of implementation means those can be built in any order
|
|
10
|
-
* without one of them owning the shape.
|
|
11
|
-
*
|
|
12
|
-
* The design this implements is `docs/plans/mcp.md`, Part A. Two constraints
|
|
13
|
-
* from it are load-bearing and easy to break by accident:
|
|
14
|
-
*
|
|
15
|
-
* 1. **Nothing here may import an MCP SDK.** That is what lets hosts other
|
|
16
|
-
* than the template consume these tools, and it is not hypothetical
|
|
17
|
-
* hygiene — the TypeScript SDK reorganised itself at v2.0.0, and a registry
|
|
18
|
-
* coupled to it would have moved with it.
|
|
19
|
-
* 2. **The result type is deliberately not MCP's `CallToolResult`.** Each host
|
|
20
|
-
* adapts {@link ValToolResult} at its own edge, which is also where an
|
|
21
|
-
* error becomes an in-band `isError` result the model can recover from
|
|
22
|
-
* rather than a transport failure.
|
|
23
|
-
*/
|
|
24
|
-
/** Why a tool call failed, in a form a host can map onto its own errors. */
|
|
25
|
-
export type ValToolErrorCode =
|
|
26
|
-
/** No tool of that name is registered. */
|
|
27
|
-
"unknown-tool"
|
|
28
|
-
/** The arguments did not satisfy the tool's `inputSchema`. */
|
|
29
|
-
| "invalid-args"
|
|
30
|
-
/** The path, module or key the arguments name does not exist. */
|
|
31
|
-
| "not-found"
|
|
32
|
-
/** The caller is not allowed to do this — wrong credential, or none. */
|
|
33
|
-
| "forbidden"
|
|
34
|
-
/**
|
|
35
|
-
* The write was rejected because applying it would leave content invalid.
|
|
36
|
-
* Nothing was stored. See `docs/plans/mcp.md` Part C on speculative
|
|
37
|
-
* validation.
|
|
38
|
-
*/
|
|
39
|
-
| "validation-failed"
|
|
40
|
-
/**
|
|
41
|
-
* Another writer moved the patch chain first. Callers may re-derive the
|
|
42
|
-
* parent ref and retry once; the registry does that itself before
|
|
43
|
-
* surfacing this.
|
|
44
|
-
*/
|
|
45
|
-
| "conflict"
|
|
46
|
-
/** The tool exists but is not available in this mode (e.g. fs vs http). */
|
|
47
|
-
| "unsupported"
|
|
48
|
-
/** Anything else, including an upstream failure. */
|
|
49
|
-
| "internal";
|
|
50
|
-
export type ValToolDefinition = {
|
|
51
|
-
name: string;
|
|
52
|
-
title?: string;
|
|
53
|
-
description: string;
|
|
54
|
-
/** zod v4 — a Standard Schema, which is what the MCP SDKs consume. */
|
|
55
|
-
inputSchema: z.ZodType;
|
|
56
|
-
/**
|
|
57
|
-
* MCP tool annotations. Hints, not enforcement: a host may show them to a
|
|
58
|
-
* user or use them to decide what to auto-approve, so they have to be
|
|
59
|
-
* honest about what the tool does.
|
|
60
|
-
*/
|
|
61
|
-
annotations?: {
|
|
62
|
-
readOnlyHint?: boolean;
|
|
63
|
-
destructiveHint?: boolean;
|
|
64
|
-
idempotentHint?: boolean;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* The same definition with `inputSchema` as JSON Schema, for hosts that want the
|
|
69
|
-
* wire shape rather than a Standard Schema.
|
|
70
|
-
*
|
|
71
|
-
* Typed as whatever zod's own converter produces, so deriving it needs no cast
|
|
72
|
-
* and no second hand-written description of the same input.
|
|
73
|
-
*/
|
|
74
|
-
export type ValToolDefinitionJson = Omit<ValToolDefinition, "inputSchema"> & {
|
|
75
|
-
inputSchema: ReturnType<typeof z.toJSONSchema<z.ZodType>>;
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* How the caller was established, and there is one acceptable answer: the host
|
|
79
|
-
* **checked a signature**.
|
|
80
|
-
*
|
|
81
|
-
* A union of one, deliberately. It carried a second variant — a personal access
|
|
82
|
-
* token relayed to the backend unchecked, on the reasoning that the app cannot
|
|
83
|
-
* resolve one and the backend can. The reasoning held; the shape did not. A
|
|
84
|
-
* credential the host cannot check is one it also cannot refuse, so accepting
|
|
85
|
-
* one made "a deployed endpoint that authenticates nobody" a supported
|
|
86
|
-
* configuration, and it let a host serve these tools without ever being told
|
|
87
|
-
* where callers should authorize. The discriminant stays so that adding a
|
|
88
|
-
* second *verified* kind stays a one-line change at every call site.
|
|
89
|
-
*/
|
|
90
|
-
export type ValToolAuth = {
|
|
91
|
-
type: "verified-profile";
|
|
92
|
-
/**
|
|
93
|
-
* The profile the host **verified** — the `sub` of an access token whose
|
|
94
|
-
* signature, issuer, audience and expiry were all checked against the
|
|
95
|
-
* authorization server's published key.
|
|
96
|
-
*
|
|
97
|
-
* This field is why an identity field exists at all, and an earlier version
|
|
98
|
-
* of this file argued none should. That argument was about a specific case
|
|
99
|
-
* and stated too broadly: an id the host *asserts* on the strength of a
|
|
100
|
-
* credential it cannot check is an unverified claim dressed as a checked one,
|
|
101
|
-
* and that is still refused — it is why a relayed token never carried a
|
|
102
|
-
* profile, and now cannot reach here at all. An id the host *verified*
|
|
103
|
-
* cryptographically is a different thing, and it is the same standing the
|
|
104
|
-
* Studio has when it re-signs a session it established itself.
|
|
105
|
-
*/
|
|
106
|
-
profileId: AuthorId;
|
|
107
|
-
/**
|
|
108
|
-
* The token's granted scopes, as the authorization server issued them.
|
|
109
|
-
*
|
|
110
|
-
* Enforced here as well as by the backend, deliberately. Two checks on one
|
|
111
|
-
* grant is not redundancy for its own sake: this one can refuse a write
|
|
112
|
-
* before it is attempted, so a token that may only read never reaches the
|
|
113
|
-
* code that builds a patch.
|
|
114
|
-
*/
|
|
115
|
-
scopes: string[];
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* Who is calling, established once per request by the host.
|
|
119
|
-
*
|
|
120
|
-
* `null` means local fs mode, where there is no credential to hold and patches
|
|
121
|
-
* are written with no author, exactly as the Studio does locally (D.1). In
|
|
122
|
-
* proxy mode `null` is refused rather than falling back to the app's own API
|
|
123
|
-
* key: that key can do more than any single user, and quietly substituting it
|
|
124
|
-
* would turn a missing credential into full access.
|
|
125
|
-
*/
|
|
126
|
-
export type ValToolContext = {
|
|
127
|
-
auth: ValToolAuth | null;
|
|
128
|
-
/** Groups a run of related edits, when the host has such a notion. */
|
|
129
|
-
sessionId: string | null;
|
|
130
|
-
};
|
|
131
|
-
/**
|
|
132
|
-
* Brand a verified subject as an {@link AuthorId}.
|
|
133
|
-
*
|
|
134
|
-
* `AuthorId` is a branded string so that an id cannot be conjured from any
|
|
135
|
-
* string that happens to be lying around — which is exactly the mistake this
|
|
136
|
-
* type is guarding against. That makes one assertion unavoidable at the boundary
|
|
137
|
-
* where a real id enters the system, so it lives here, once, with a name that
|
|
138
|
-
* says what makes it legitimate: the caller has *verified* this subject, not
|
|
139
|
-
* received it.
|
|
140
|
-
*
|
|
141
|
-
* Do not reach for this to satisfy a type. If you are holding a string you did
|
|
142
|
-
* not verify, the honest value is `null`.
|
|
143
|
-
*/
|
|
144
|
-
export declare function authorIdFromVerifiedSubject(subject: string): AuthorId;
|
|
145
|
-
/** Read access. Every call needs it, the writes included. */
|
|
146
|
-
export declare const VAL_SCOPE_READ = "val:read";
|
|
147
|
-
/** Write access. Needed *in addition* by any tool not marked `readOnlyHint`. */
|
|
148
|
-
export declare const VAL_SCOPE_WRITE = "val:write";
|
|
149
|
-
export type ValScope = typeof VAL_SCOPE_READ | typeof VAL_SCOPE_WRITE;
|
|
150
|
-
export type ValToolResult = {
|
|
151
|
-
status: "ok";
|
|
152
|
-
data: Json;
|
|
153
|
-
} | {
|
|
154
|
-
status: "error";
|
|
155
|
-
code: ValToolErrorCode;
|
|
156
|
-
message: string;
|
|
157
|
-
};
|
|
158
|
-
export type ValTools = {
|
|
159
|
-
list(): ValToolDefinition[];
|
|
160
|
-
listJsonSchema(): ValToolDefinitionJson[];
|
|
161
|
-
call(name: string, args: unknown, ctx: ValToolContext): Promise<ValToolResult>;
|
|
162
|
-
dispose(): Promise<void>;
|
|
163
|
-
};
|