@nyuchi/mzizi-mcp 0.13.0 → 0.15.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/README.md +197 -26
- package/dist/auth/front.d.ts +8 -0
- package/dist/auth/front.d.ts.map +1 -1
- package/dist/auth/front.js +10 -0
- package/dist/auth/front.js.map +1 -1
- package/dist/auth/mcp-api-handler.d.ts +1 -1
- package/dist/auth/mcp-api-handler.d.ts.map +1 -1
- package/dist/auth/mcp-api-handler.js +4 -3
- package/dist/auth/mcp-api-handler.js.map +1 -1
- package/dist/auth/provider-options.d.ts +16 -0
- package/dist/auth/provider-options.d.ts.map +1 -0
- package/dist/auth/provider-options.js +21 -0
- package/dist/auth/provider-options.js.map +1 -0
- package/dist/docs-federation.d.ts +1 -1
- package/dist/docs-federation.d.ts.map +1 -1
- package/dist/docs-federation.js +1 -0
- package/dist/docs-federation.js.map +1 -1
- package/dist/env.d.ts +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/floors.d.ts +117 -0
- package/dist/floors.d.ts.map +1 -0
- package/dist/floors.js +103 -0
- package/dist/floors.js.map +1 -0
- package/dist/fundi-client.d.ts +6 -0
- package/dist/fundi-client.d.ts.map +1 -1
- package/dist/fundi-client.js +14 -3
- package/dist/fundi-client.js.map +1 -1
- package/dist/generated/registry-pin.d.ts +8 -1
- package/dist/generated/registry-pin.d.ts.map +1 -1
- package/dist/generated/registry-pin.js +3 -1
- package/dist/generated/registry-pin.js.map +1 -1
- package/dist/generated/registry.d.ts +2 -2
- package/dist/generated/registry.d.ts.map +1 -1
- package/dist/generated/registry.js +381 -325
- package/dist/generated/registry.js.map +1 -1
- package/dist/generated/skills.d.ts +11 -1
- package/dist/generated/skills.d.ts.map +1 -1
- package/dist/generated/skills.js +216 -21
- package/dist/generated/skills.js.map +1 -1
- package/dist/http.d.ts +32 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +109 -28
- package/dist/http.js.map +1 -1
- package/dist/limits.d.ts +32 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +44 -0
- package/dist/limits.js.map +1 -0
- package/dist/origin.d.ts +55 -0
- package/dist/origin.d.ts.map +1 -0
- package/dist/origin.js +127 -0
- package/dist/origin.js.map +1 -0
- package/dist/rate-limit.d.ts +1 -1
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +3 -2
- package/dist/rate-limit.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +22 -1
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +83 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +109 -10
- package/dist/server.js.map +1 -1
- package/dist/stdio.js +5 -4
- package/dist/stdio.js.map +1 -1
- package/dist/tools.d.ts +21 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +413 -114
- package/dist/tools.js.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +19 -8
- package/dist/worker.js.map +1 -1
- package/package.json +18 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/generated/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAC,QAAQ,EAAC,UAAU,EAAC,OAAO,CAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/generated/skills.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
CHANGED
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
import type { FundiToolContext } from "./fundi-client.js";
|
|
12
12
|
import type { IssueDeskContext } from "./tools.js";
|
|
13
13
|
import type { DocsFederationOptions } from "./docs-federation.js";
|
|
14
|
+
export { originRejection } from "./origin.js";
|
|
15
|
+
/**
|
|
16
|
+
* Add CORS headers: the caller's `Origin` echoed back when it was allowed (see
|
|
17
|
+
* `origin.ts`), never `*`. `Vary` is appended to, not replaced. Exported for
|
|
18
|
+
* tests only.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function withCors(response: Response, origin: string | null, allowed: boolean): Response;
|
|
14
23
|
export interface HttpHandlerOptions {
|
|
15
24
|
/** When set, expose the fundi trigger tool bound to the signed-in user. */
|
|
16
25
|
fundi?: FundiToolContext;
|
|
@@ -25,10 +34,31 @@ export interface HttpHandlerOptions {
|
|
|
25
34
|
};
|
|
26
35
|
/** Docs federation settings, or `false` for none. Defaults to docs.mzizi.dev. */
|
|
27
36
|
docs?: DocsFederationOptions | false;
|
|
37
|
+
/**
|
|
38
|
+
* Browser origins allowed to call the endpoint, by hostname, with the same
|
|
39
|
+
* scheme and port rules as the default list (see `origin.ts`). Omitted, the
|
|
40
|
+
* first-party sites and localhost. The Worker passes the default plus
|
|
41
|
+
* `MZIZI_ALLOWED_ORIGINS`.
|
|
42
|
+
*/
|
|
43
|
+
allowedOrigins?: readonly string[];
|
|
28
44
|
}
|
|
29
45
|
/**
|
|
30
|
-
* Build a fetch handler that serves the Mzizi MCP over Streamable HTTP
|
|
31
|
-
*
|
|
46
|
+
* Build a fetch handler that serves the Mzizi MCP over Streamable HTTP, on the
|
|
47
|
+
* official SDK (v2, `@modelcontextprotocol/server`).
|
|
48
|
+
*
|
|
49
|
+
* Stateless either way: every request gets a fresh `McpServer` from the same
|
|
50
|
+
* factory, with nothing shared between callers.
|
|
51
|
+
*
|
|
52
|
+
* - 2026-07-28 traffic (per-request `_meta`, `server/discover`) is served by
|
|
53
|
+
* the SDK's `createMcpHandler`.
|
|
54
|
+
* - 2025-era traffic (`initialize`) is served by the SDK's
|
|
55
|
+
* `WebStandardStreamableHTTPServerTransport` with JSON responses, exactly as
|
|
56
|
+
* before the migration, routed with the SDK's own `isLegacyRequest` so the
|
|
57
|
+
* two legs cannot disagree about which is which. `createMcpHandler`'s
|
|
58
|
+
* built-in legacy leg would answer the same requests over SSE; keeping JSON
|
|
59
|
+
* keeps every existing client's responses byte-for-byte the same shape.
|
|
60
|
+
* - GET and DELETE (2025 session operations this server has never offered)
|
|
61
|
+
* are answered with 405 rather than holding an SSE stream open.
|
|
32
62
|
*/
|
|
33
63
|
export declare function createMziziHttpHandler(options?: HttpHandlerOptions): (request: Request) => Promise<Response>;
|
|
34
64
|
//# sourceMappingURL=http.d.ts.map
|
package/dist/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAGjE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,CAa9F;AAqBD,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IAC9B,iFAAiF;IACjF,IAAI,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAA;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC;AAiDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,kBAAuB,IAcxC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAsClE"}
|
package/dist/http.js
CHANGED
|
@@ -8,17 +8,28 @@
|
|
|
8
8
|
* anonymous (the free tier) or signed in (WorkOS AuthKit via the OAuth provider)
|
|
9
9
|
* before it reaches this handler.
|
|
10
10
|
*/
|
|
11
|
-
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/
|
|
11
|
+
import { createMcpHandler, isLegacyRequest, WebStandardStreamableHTTPServerTransport, } from "@modelcontextprotocol/server";
|
|
12
|
+
import { corsHeadersFor, forbiddenOrigin, isAllowedOrigin } from "./origin.js";
|
|
12
13
|
import { createMziziMcpServer } from "./server.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
// Part of the public `./http` export since before 0.14.0; kept (same signature).
|
|
15
|
+
export { originRejection } from "./origin.js";
|
|
16
|
+
/**
|
|
17
|
+
* Add CORS headers: the caller's `Origin` echoed back when it was allowed (see
|
|
18
|
+
* `origin.ts`), never `*`. `Vary` is appended to, not replaced. Exported for
|
|
19
|
+
* tests only.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function withCors(response, origin, allowed) {
|
|
19
24
|
const headers = new Headers(response.headers);
|
|
20
|
-
for (const [key, value] of Object.entries(
|
|
21
|
-
|
|
25
|
+
for (const [key, value] of Object.entries(corsHeadersFor(origin, allowed))) {
|
|
26
|
+
if (key === "Vary") {
|
|
27
|
+
if (!/(^|,)\s*origin\s*(,|$)/i.test(headers.get("Vary") ?? ""))
|
|
28
|
+
headers.append(key, value);
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
headers.set(key, value);
|
|
32
|
+
}
|
|
22
33
|
return new Response(response.body, {
|
|
23
34
|
status: response.status,
|
|
24
35
|
statusText: response.statusText,
|
|
@@ -44,32 +55,102 @@ function isOAuthDiscoveryPath(pathname) {
|
|
|
44
55
|
* Build a fetch handler that serves the Mzizi MCP over Streamable HTTP.
|
|
45
56
|
* Stateless — each request creates a fresh transport + server pair.
|
|
46
57
|
*/
|
|
58
|
+
/** Request bodies are small JSON-RPC calls; 1 MiB is generous. */
|
|
59
|
+
const MAX_REQUEST_BODY = 1024 * 1024;
|
|
60
|
+
const onerror = (error) => console.error("mzizi-mcp:", error.message);
|
|
61
|
+
function serverFor(options) {
|
|
62
|
+
return createMziziMcpServer({
|
|
63
|
+
fundi: options.fundi,
|
|
64
|
+
desk: options.desk,
|
|
65
|
+
anonymous: options.anonymous,
|
|
66
|
+
docs: options.docs,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const OPTIONS_KEY = "mzizi-mcp/handler-options";
|
|
70
|
+
/** Wrap per-request options as the SDK's pass-through `authInfo`. */
|
|
71
|
+
function carry(options) {
|
|
72
|
+
return { token: "", clientId: "mzizi-mcp", scopes: [], extra: { [OPTIONS_KEY]: options } };
|
|
73
|
+
}
|
|
74
|
+
let modern;
|
|
75
|
+
/**
|
|
76
|
+
* One `createMcpHandler` per isolate, not per request: it owns an event bus and
|
|
77
|
+
* a listen router, and building it on every request cost both each time. The
|
|
78
|
+
* factory still builds a fresh `McpServer` for every request, from the options
|
|
79
|
+
* that request carried (anonymous, or the signed-in user's fundi and desk).
|
|
80
|
+
*/
|
|
81
|
+
function modernHandler() {
|
|
82
|
+
modern ??= createMcpHandler((ctx) => serverFor(ctx.authInfo?.extra?.[OPTIONS_KEY] ?? {}), {
|
|
83
|
+
legacy: "reject",
|
|
84
|
+
// "auto": a single JSON body unless a tool emits a message first, which
|
|
85
|
+
// none here does. ("json" would log a warning on every construction.)
|
|
86
|
+
maxRequestBodySize: MAX_REQUEST_BODY,
|
|
87
|
+
onerror,
|
|
88
|
+
});
|
|
89
|
+
return modern;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build a fetch handler that serves the Mzizi MCP over Streamable HTTP, on the
|
|
93
|
+
* official SDK (v2, `@modelcontextprotocol/server`).
|
|
94
|
+
*
|
|
95
|
+
* Stateless either way: every request gets a fresh `McpServer` from the same
|
|
96
|
+
* factory, with nothing shared between callers.
|
|
97
|
+
*
|
|
98
|
+
* - 2026-07-28 traffic (per-request `_meta`, `server/discover`) is served by
|
|
99
|
+
* the SDK's `createMcpHandler`.
|
|
100
|
+
* - 2025-era traffic (`initialize`) is served by the SDK's
|
|
101
|
+
* `WebStandardStreamableHTTPServerTransport` with JSON responses, exactly as
|
|
102
|
+
* before the migration, routed with the SDK's own `isLegacyRequest` so the
|
|
103
|
+
* two legs cannot disagree about which is which. `createMcpHandler`'s
|
|
104
|
+
* built-in legacy leg would answer the same requests over SSE; keeping JSON
|
|
105
|
+
* keeps every existing client's responses byte-for-byte the same shape.
|
|
106
|
+
* - GET and DELETE (2025 session operations this server has never offered)
|
|
107
|
+
* are answered with 405 rather than holding an SSE stream open.
|
|
108
|
+
*/
|
|
47
109
|
export function createMziziHttpHandler(options = {}) {
|
|
110
|
+
const factory = () => serverFor(options);
|
|
111
|
+
async function serveLegacy(request) {
|
|
112
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
113
|
+
sessionIdGenerator: undefined,
|
|
114
|
+
enableJsonResponse: true,
|
|
115
|
+
});
|
|
116
|
+
const server = await factory();
|
|
117
|
+
server.server.onerror = onerror;
|
|
118
|
+
await server.connect(transport);
|
|
119
|
+
return transport.handleRequest(request);
|
|
120
|
+
}
|
|
48
121
|
return async function handle(request) {
|
|
122
|
+
const origin = request.headers.get("origin");
|
|
123
|
+
const allowed = isAllowedOrigin(origin, options.allowedOrigins);
|
|
124
|
+
const cors = (response) => withCors(response, origin, allowed);
|
|
125
|
+
// DNS-rebinding / cross-site defence (Streamable HTTP §Security): a
|
|
126
|
+
// request whose Origin is present and not on the allowlist is refused with
|
|
127
|
+
// 403 before anything else, preflight included, and before any server is
|
|
128
|
+
// built. No Origin header (every non-browser client) passes.
|
|
129
|
+
if (!allowed)
|
|
130
|
+
return cors(forbiddenOrigin(origin));
|
|
131
|
+
// (On the Worker the OAuth provider answers OPTIONS on /mcp itself, so this
|
|
132
|
+
// branch serves the embedded `./http` export; see the CHANGELOG, #295.)
|
|
49
133
|
if (request.method === "OPTIONS") {
|
|
50
|
-
return new Response(null, { status: 204
|
|
134
|
+
return cors(new Response(null, { status: 204 }));
|
|
51
135
|
}
|
|
52
136
|
// Answer auth-discovery probes with 404 so compliant MCP clients fall back
|
|
53
|
-
// to anonymous access. Without this the request reaches the
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
// abort the connection instead of connecting unauthenticated.
|
|
137
|
+
// to anonymous access. Without this the request reaches the MCP handler,
|
|
138
|
+
// which cannot answer a discovery GET with metadata, and clients abort the
|
|
139
|
+
// connection instead of connecting unauthenticated.
|
|
57
140
|
if (isOAuthDiscoveryPath(new URL(request.url).pathname)) {
|
|
58
|
-
return
|
|
141
|
+
return cors(new Response("Not Found", { status: 404 }));
|
|
59
142
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await
|
|
71
|
-
const response = await transport.handleRequest(request);
|
|
72
|
-
return withCors(response);
|
|
143
|
+
// Stateless: there is no standalone SSE stream to open and no session to
|
|
144
|
+
// end, so GET and DELETE are 405 rather than held-open connections.
|
|
145
|
+
if (request.method !== "POST") {
|
|
146
|
+
return cors(Response.json({ jsonrpc: "2.0", id: null, error: { code: -32000, message: "Method not allowed. This server is stateless: send every request as a POST." } }, { status: 405, headers: { Allow: "POST, OPTIONS" } }));
|
|
147
|
+
}
|
|
148
|
+
if (await isLegacyRequest(request, undefined, { maxRequestBodySize: MAX_REQUEST_BODY })) {
|
|
149
|
+
return cors(await serveLegacy(request));
|
|
150
|
+
}
|
|
151
|
+
// The per-request options ride to the shared handler's factory on authInfo,
|
|
152
|
+
// which the SDK passes through untouched and never reads itself.
|
|
153
|
+
return cors(await modernHandler().fetch(request, { authInfo: carry(options) }));
|
|
73
154
|
};
|
|
74
155
|
}
|
|
75
156
|
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/limits.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response-size limits for the list and search tools.
|
|
3
|
+
*
|
|
4
|
+
* A tool result is read into a model's context, and the MCP builder guidance is
|
|
5
|
+
* to keep one under 25,000 characters. Before this cap, `mzizi_list_components`
|
|
6
|
+
* answered its default call with 146 KB (measured live 2026-11-01, issue #295).
|
|
7
|
+
*
|
|
8
|
+
* The cap is met by returning FEWER items, never by cutting text: the page
|
|
9
|
+
* shrinks, `next_offset` points at the first item left out, and the JSON text
|
|
10
|
+
* still matches `structuredContent` exactly.
|
|
11
|
+
*/
|
|
12
|
+
/** Characters one list or search result may carry. */
|
|
13
|
+
export declare const CHARACTER_LIMIT = 25000;
|
|
14
|
+
/**
|
|
15
|
+
* The longest prefix of `items` whose page, `render(prefix)`, serialises under
|
|
16
|
+
* `limit`, keeping at least one item (a single oversized item is returned whole
|
|
17
|
+
* rather than as nothing). `render` builds the complete page, pagination fields
|
|
18
|
+
* included, so what is measured is what is sent.
|
|
19
|
+
*
|
|
20
|
+
* A binary search over the prefix length: about log2(n) renders (9 for 400
|
|
21
|
+
* rows) instead of one per item. The page's size only grows with its length,
|
|
22
|
+
* so the search is exact.
|
|
23
|
+
*
|
|
24
|
+
* bushtrade-mcp carries an identical copy in `src/limits.ts` (the packages
|
|
25
|
+
* share no code); keep the two the same.
|
|
26
|
+
*/
|
|
27
|
+
export declare function fitToLimit<T, R>(items: T[], render: (page: T[]) => R, limit?: number): {
|
|
28
|
+
page: T[];
|
|
29
|
+
result: R;
|
|
30
|
+
truncated: boolean;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sDAAsD;AACtD,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,EACxB,KAAK,SAAkB,GACtB;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAa9C"}
|
package/dist/limits.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response-size limits for the list and search tools.
|
|
3
|
+
*
|
|
4
|
+
* A tool result is read into a model's context, and the MCP builder guidance is
|
|
5
|
+
* to keep one under 25,000 characters. Before this cap, `mzizi_list_components`
|
|
6
|
+
* answered its default call with 146 KB (measured live 2026-11-01, issue #295).
|
|
7
|
+
*
|
|
8
|
+
* The cap is met by returning FEWER items, never by cutting text: the page
|
|
9
|
+
* shrinks, `next_offset` points at the first item left out, and the JSON text
|
|
10
|
+
* still matches `structuredContent` exactly.
|
|
11
|
+
*/
|
|
12
|
+
/** Characters one list or search result may carry. */
|
|
13
|
+
export const CHARACTER_LIMIT = 25_000;
|
|
14
|
+
/**
|
|
15
|
+
* The longest prefix of `items` whose page, `render(prefix)`, serialises under
|
|
16
|
+
* `limit`, keeping at least one item (a single oversized item is returned whole
|
|
17
|
+
* rather than as nothing). `render` builds the complete page, pagination fields
|
|
18
|
+
* included, so what is measured is what is sent.
|
|
19
|
+
*
|
|
20
|
+
* A binary search over the prefix length: about log2(n) renders (9 for 400
|
|
21
|
+
* rows) instead of one per item. The page's size only grows with its length,
|
|
22
|
+
* so the search is exact.
|
|
23
|
+
*
|
|
24
|
+
* bushtrade-mcp carries an identical copy in `src/limits.ts` (the packages
|
|
25
|
+
* share no code); keep the two the same.
|
|
26
|
+
*/
|
|
27
|
+
export function fitToLimit(items, render, limit = CHARACTER_LIMIT) {
|
|
28
|
+
const size = (r) => JSON.stringify(r, null, 2).length;
|
|
29
|
+
const full = render(items);
|
|
30
|
+
if (items.length <= 1 || size(full) <= limit)
|
|
31
|
+
return { page: items, result: full, truncated: false };
|
|
32
|
+
let lo = 1; // known to be kept (the floor), whether or not it fits
|
|
33
|
+
let hi = items.length - 1; // the largest length still possible
|
|
34
|
+
while (lo < hi) {
|
|
35
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
36
|
+
if (size(render(items.slice(0, mid))) <= limit)
|
|
37
|
+
lo = mid;
|
|
38
|
+
else
|
|
39
|
+
hi = mid - 1;
|
|
40
|
+
}
|
|
41
|
+
const page = items.slice(0, lo);
|
|
42
|
+
return { page, result: render(page), truncated: true };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,MAAwB,EACxB,KAAK,GAAG,eAAe;IAEvB,MAAM,IAAI,GAAG,CAAC,CAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACrG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,uDAAuD;IACnE,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,oCAAoC;IAC/D,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK;YAAE,EAAE,GAAG,GAAG,CAAC;;YACpD,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACzD,CAAC"}
|
package/dist/origin.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser `Origin` policy for the MCP endpoint (Streamable HTTP §Security, and
|
|
3
|
+
* the fix list in #295, P0 item 1).
|
|
4
|
+
*
|
|
5
|
+
* Servers MUST validate `Origin` against DNS rebinding and answer 403 to an
|
|
6
|
+
* invalid one. The policy:
|
|
7
|
+
*
|
|
8
|
+
* - no `Origin` header allowed: every non-browser client (the SDKs, curl,
|
|
9
|
+
* Claude, Cursor) sends none;
|
|
10
|
+
* - a present `Origin` allowed only if its host is on the list, otherwise
|
|
11
|
+
* 403 before any MCP server is built;
|
|
12
|
+
* - CORS `Access-Control-Allow-Origin` echoes an allowed
|
|
13
|
+
* `Origin` (with `Vary: Origin`). It is never `*`.
|
|
14
|
+
*
|
|
15
|
+
* The list is hostnames. A localhost name matches over `http` or `https` on any
|
|
16
|
+
* port (the MCP Inspector runs at http://localhost:6274). Every other name
|
|
17
|
+
* matches only over `https` on the default port, exactly: no subdomains, no
|
|
18
|
+
* `http`, no `:8443`. The same rule applies to a list the caller supplies.
|
|
19
|
+
*/
|
|
20
|
+
/** The first-party sites: this Worker, the site, the docs and the console. */
|
|
21
|
+
export declare const ALLOWED_ORIGIN_HOSTS: readonly string[];
|
|
22
|
+
/** The default list: the first-party sites and localhost. */
|
|
23
|
+
export declare const DEFAULT_ALLOWED_HOSTS: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* The default list plus the extra origins in `MZIZI_ALLOWED_ORIGINS`
|
|
26
|
+
* (comma-separated `https://host` origins; case and a trailing slash are
|
|
27
|
+
* tolerated). An entry that is not an `https` origin with no path, port or
|
|
28
|
+
* credentials is dropped with a `console.warn`, so a typo cannot open the
|
|
29
|
+
* endpoint wider than named. The result is cached per value, so the Worker pays
|
|
30
|
+
* for the parse once per isolate, not once per request.
|
|
31
|
+
*/
|
|
32
|
+
export declare function allowedHostsFromEnv(env: {
|
|
33
|
+
MZIZI_ALLOWED_ORIGINS?: string;
|
|
34
|
+
}): readonly string[];
|
|
35
|
+
/**
|
|
36
|
+
* True when `origin` may call the endpoint. `null` (no header at all) is
|
|
37
|
+
* allowed; a header that is present is judged, so an empty value and the opaque
|
|
38
|
+
* `"null"` are refused like any other unparseable origin.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isAllowedOrigin(origin: string | null, hosts?: readonly string[]): boolean;
|
|
41
|
+
/** The 403 for a present-but-unlisted `Origin` (a JSON-RPC error body, like the SDK's own). */
|
|
42
|
+
export declare function forbiddenOrigin(origin: string | null): Response;
|
|
43
|
+
/** A 403 for a present-but-unlisted `Origin`, or undefined when the request may proceed. */
|
|
44
|
+
export declare function originRejection(request: Request, hosts?: readonly string[]): Response | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* The CORS headers for a request whose `Origin` is `origin`, already judged
|
|
47
|
+
* `allowed`: the origin echoed back, never `*`. No `Origin`, or one that is not
|
|
48
|
+
* allowed, gets no `Access-Control-Allow-Origin`; `Vary: Origin` is always
|
|
49
|
+
* present so a cache cannot hand one origin's answer to another. Merge `Vary`
|
|
50
|
+
* with `Headers.append`, not `set`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function corsHeadersFor(origin: string | null, allowed: boolean): Record<string, string>;
|
|
53
|
+
/** `corsHeadersFor`, judging the request's own `Origin` against `hosts`. */
|
|
54
|
+
export declare function corsHeaders(request: Request, hosts?: readonly string[]): Record<string, string>;
|
|
55
|
+
//# sourceMappingURL=origin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAMjD,CAAA;AAED,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAA8C,CAAA;AAIjG;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,MAAM,EAAE,CAsB9F;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAE,SAAS,MAAM,EAA0B,GAAG,OAAO,CAahH;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAK/D;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,GAAG,SAAS,CAGjG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS9F;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG/F"}
|
package/dist/origin.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser `Origin` policy for the MCP endpoint (Streamable HTTP §Security, and
|
|
3
|
+
* the fix list in #295, P0 item 1).
|
|
4
|
+
*
|
|
5
|
+
* Servers MUST validate `Origin` against DNS rebinding and answer 403 to an
|
|
6
|
+
* invalid one. The policy:
|
|
7
|
+
*
|
|
8
|
+
* - no `Origin` header allowed: every non-browser client (the SDKs, curl,
|
|
9
|
+
* Claude, Cursor) sends none;
|
|
10
|
+
* - a present `Origin` allowed only if its host is on the list, otherwise
|
|
11
|
+
* 403 before any MCP server is built;
|
|
12
|
+
* - CORS `Access-Control-Allow-Origin` echoes an allowed
|
|
13
|
+
* `Origin` (with `Vary: Origin`). It is never `*`.
|
|
14
|
+
*
|
|
15
|
+
* The list is hostnames. A localhost name matches over `http` or `https` on any
|
|
16
|
+
* port (the MCP Inspector runs at http://localhost:6274). Every other name
|
|
17
|
+
* matches only over `https` on the default port, exactly: no subdomains, no
|
|
18
|
+
* `http`, no `:8443`. The same rule applies to a list the caller supplies.
|
|
19
|
+
*/
|
|
20
|
+
import { localhostAllowedOrigins } from "@modelcontextprotocol/server";
|
|
21
|
+
/** Hostnames that count as local development. */
|
|
22
|
+
const LOCAL_HOSTS = localhostAllowedOrigins();
|
|
23
|
+
/** The first-party sites: this Worker, the site, the docs and the console. */
|
|
24
|
+
export const ALLOWED_ORIGIN_HOSTS = [
|
|
25
|
+
"mzizi.dev",
|
|
26
|
+
"www.mzizi.dev",
|
|
27
|
+
"docs.mzizi.dev",
|
|
28
|
+
"app.mzizi.dev",
|
|
29
|
+
"mcp.mzizi.dev",
|
|
30
|
+
];
|
|
31
|
+
/** The default list: the first-party sites and localhost. */
|
|
32
|
+
export const DEFAULT_ALLOWED_HOSTS = [...ALLOWED_ORIGIN_HOSTS, ...LOCAL_HOSTS];
|
|
33
|
+
const hostsCache = new Map();
|
|
34
|
+
/**
|
|
35
|
+
* The default list plus the extra origins in `MZIZI_ALLOWED_ORIGINS`
|
|
36
|
+
* (comma-separated `https://host` origins; case and a trailing slash are
|
|
37
|
+
* tolerated). An entry that is not an `https` origin with no path, port or
|
|
38
|
+
* credentials is dropped with a `console.warn`, so a typo cannot open the
|
|
39
|
+
* endpoint wider than named. The result is cached per value, so the Worker pays
|
|
40
|
+
* for the parse once per isolate, not once per request.
|
|
41
|
+
*/
|
|
42
|
+
export function allowedHostsFromEnv(env) {
|
|
43
|
+
const raw = env.MZIZI_ALLOWED_ORIGINS;
|
|
44
|
+
if (!raw)
|
|
45
|
+
return DEFAULT_ALLOWED_HOSTS;
|
|
46
|
+
const cached = hostsCache.get(raw);
|
|
47
|
+
if (cached)
|
|
48
|
+
return cached;
|
|
49
|
+
const extra = [];
|
|
50
|
+
for (const entry of raw.split(",")) {
|
|
51
|
+
const value = entry.trim().replace(/\/$/, "").toLowerCase();
|
|
52
|
+
if (!value)
|
|
53
|
+
continue;
|
|
54
|
+
let host;
|
|
55
|
+
try {
|
|
56
|
+
const url = new URL(value);
|
|
57
|
+
if (url.protocol === "https:" && url.origin === value && url.port === "")
|
|
58
|
+
host = url.hostname;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Not an origin: dropped below.
|
|
62
|
+
}
|
|
63
|
+
if (host)
|
|
64
|
+
extra.push(host);
|
|
65
|
+
else
|
|
66
|
+
console.warn(`mzizi-mcp: MZIZI_ALLOWED_ORIGINS entry ignored (not a plain https origin): ${entry.trim()}`);
|
|
67
|
+
}
|
|
68
|
+
const hosts = [...DEFAULT_ALLOWED_HOSTS, ...extra];
|
|
69
|
+
hostsCache.set(raw, hosts);
|
|
70
|
+
return hosts;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* True when `origin` may call the endpoint. `null` (no header at all) is
|
|
74
|
+
* allowed; a header that is present is judged, so an empty value and the opaque
|
|
75
|
+
* `"null"` are refused like any other unparseable origin.
|
|
76
|
+
*/
|
|
77
|
+
export function isAllowedOrigin(origin, hosts = DEFAULT_ALLOWED_HOSTS) {
|
|
78
|
+
if (origin === null)
|
|
79
|
+
return true;
|
|
80
|
+
let url;
|
|
81
|
+
try {
|
|
82
|
+
url = new URL(origin);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
// An Origin is scheme://host[:port] and nothing else.
|
|
88
|
+
if (url.origin !== origin)
|
|
89
|
+
return false;
|
|
90
|
+
if (!hosts.includes(url.hostname))
|
|
91
|
+
return false;
|
|
92
|
+
if (LOCAL_HOSTS.includes(url.hostname))
|
|
93
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
94
|
+
return url.protocol === "https:" && url.port === "";
|
|
95
|
+
}
|
|
96
|
+
/** The 403 for a present-but-unlisted `Origin` (a JSON-RPC error body, like the SDK's own). */
|
|
97
|
+
export function forbiddenOrigin(origin) {
|
|
98
|
+
return Response.json({ jsonrpc: "2.0", id: null, error: { code: -32000, message: `Invalid Origin header: ${origin ?? ""}` } }, { status: 403, headers: { Vary: "Origin" } });
|
|
99
|
+
}
|
|
100
|
+
/** A 403 for a present-but-unlisted `Origin`, or undefined when the request may proceed. */
|
|
101
|
+
export function originRejection(request, hosts) {
|
|
102
|
+
const origin = request.headers.get("origin");
|
|
103
|
+
return isAllowedOrigin(origin, hosts) ? undefined : forbiddenOrigin(origin);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The CORS headers for a request whose `Origin` is `origin`, already judged
|
|
107
|
+
* `allowed`: the origin echoed back, never `*`. No `Origin`, or one that is not
|
|
108
|
+
* allowed, gets no `Access-Control-Allow-Origin`; `Vary: Origin` is always
|
|
109
|
+
* present so a cache cannot hand one origin's answer to another. Merge `Vary`
|
|
110
|
+
* with `Headers.append`, not `set`.
|
|
111
|
+
*/
|
|
112
|
+
export function corsHeadersFor(origin, allowed) {
|
|
113
|
+
const headers = { Vary: "Origin" };
|
|
114
|
+
if (origin && allowed) {
|
|
115
|
+
headers["Access-Control-Allow-Origin"] = origin;
|
|
116
|
+
headers["Access-Control-Allow-Methods"] = "GET, POST, DELETE, OPTIONS";
|
|
117
|
+
headers["Access-Control-Allow-Headers"] =
|
|
118
|
+
"Content-Type, MCP-Protocol-Version, MCP-Session-Id, Mcp-Method, Mcp-Name, apikey";
|
|
119
|
+
}
|
|
120
|
+
return headers;
|
|
121
|
+
}
|
|
122
|
+
/** `corsHeadersFor`, judging the request's own `Origin` against `hosts`. */
|
|
123
|
+
export function corsHeaders(request, hosts) {
|
|
124
|
+
const origin = request.headers.get("origin");
|
|
125
|
+
return corsHeadersFor(origin, isAllowedOrigin(origin, hosts));
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=origin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origin.js","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"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"}
|
package/dist/rate-limit.d.ts
CHANGED
|
@@ -37,5 +37,5 @@ export declare function clientKey(request: Request): string;
|
|
|
37
37
|
* The body is a JSON-RPC error so an MCP client can show it, and it names the
|
|
38
38
|
* way past the limit: signing in.
|
|
39
39
|
*/
|
|
40
|
-
export declare function limitAnonymous(limiter: RateLimiter | undefined, request: Request): Promise<Response | null>;
|
|
40
|
+
export declare function limitAnonymous(limiter: RateLimiter | undefined, request: Request, allowedHosts?: readonly string[]): Promise<Response | null>;
|
|
41
41
|
//# sourceMappingURL=rate-limit.d.ts.map
|
package/dist/rate-limit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAC/B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuB1B"}
|
package/dist/rate-limit.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* free tier down with a missing binding, and the limit is a guard, not a gate.
|
|
17
17
|
*/
|
|
18
18
|
import { ANONYMOUS_RATE_LIMIT, SIGN_IN_MCP_URL } from "./access.js";
|
|
19
|
+
import { corsHeaders } from "./origin.js";
|
|
19
20
|
/**
|
|
20
21
|
* The key for one client: the connecting IP Cloudflare reports.
|
|
21
22
|
*
|
|
@@ -32,7 +33,7 @@ export function clientKey(request) {
|
|
|
32
33
|
* The body is a JSON-RPC error so an MCP client can show it, and it names the
|
|
33
34
|
* way past the limit: signing in.
|
|
34
35
|
*/
|
|
35
|
-
export async function limitAnonymous(limiter, request) {
|
|
36
|
+
export async function limitAnonymous(limiter, request, allowedHosts) {
|
|
36
37
|
if (!limiter)
|
|
37
38
|
return null;
|
|
38
39
|
const { success } = await limiter.limit({ key: clientKey(request) });
|
|
@@ -51,7 +52,7 @@ export async function limitAnonymous(limiter, request) {
|
|
|
51
52
|
headers: {
|
|
52
53
|
"Content-Type": "application/json",
|
|
53
54
|
"Retry-After": String(periodSeconds),
|
|
54
|
-
|
|
55
|
+
...corsHeaders(request, allowedHosts),
|
|
55
56
|
},
|
|
56
57
|
});
|
|
57
58
|
}
|
package/dist/rate-limit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgC,EAChC,OAAgB,EAChB,YAAgC;IAEhC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrE,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,oBAAoB,CAAC;IACtD,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,KAAK;YACZ,OAAO,EAAE,iDAAiD,KAAK,QAAQ,aAAa,iEAAiE,eAAe,gBAAgB;SACrL;KACF,CAAC,EACF;QACE,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC;YACpC,GAAG,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC;SACtC;KACF,CACF,CAAC;AACJ,CAAC"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export type AstroImpl = {
|
|
|
63
63
|
}>;
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
|
-
* A component's Mzizi Roots (Rust
|
|
66
|
+
* A component's Mzizi Roots (Rust) implementation: the registry's
|
|
67
67
|
* `/v1/rs/{name}` body, plus the `CONTRACT` clause block its source declares.
|
|
68
68
|
*/
|
|
69
69
|
export type RustImpl = {
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|