@novorb/mcp-core 2.1.2 → 3.0.1
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 +77 -163
- package/bin/mcp-core-jest.mjs +112 -0
- package/dist/auth.d.ts +57 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +74 -0
- package/dist/auth.js.map +1 -0
- package/dist/bootstrap.d.ts +129 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +206 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/client-input.d.ts +72 -0
- package/dist/client-input.d.ts.map +1 -0
- package/dist/client-input.js +109 -0
- package/dist/client-input.js.map +1 -0
- package/dist/credential-checks.d.ts +80 -0
- package/dist/credential-checks.d.ts.map +1 -0
- package/dist/credential-checks.js +189 -0
- package/dist/credential-checks.js.map +1 -0
- package/dist/credential-health.d.ts +12 -0
- package/dist/credential-health.d.ts.map +1 -0
- package/dist/credential-health.js +12 -0
- package/dist/credential-health.js.map +1 -0
- package/dist/credential-report.d.ts +46 -0
- package/dist/credential-report.d.ts.map +1 -0
- package/dist/credential-report.js +135 -0
- package/dist/credential-report.js.map +1 -0
- package/dist/credential-status-tool.d.ts +20 -0
- package/dist/credential-status-tool.d.ts.map +1 -0
- package/dist/credential-status-tool.js +33 -0
- package/dist/credential-status-tool.js.map +1 -0
- package/dist/credentials.d.ts +288 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +652 -0
- package/dist/credentials.js.map +1 -0
- package/dist/express-peers.d.ts +29 -0
- package/dist/express-peers.d.ts.map +1 -0
- package/dist/express-peers.js +36 -0
- package/dist/express-peers.js.map +1 -0
- package/dist/express.d.ts +74 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +164 -0
- package/dist/express.js.map +1 -0
- package/dist/http-client.d.ts +277 -42
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +620 -180
- package/dist/http-client.js.map +1 -1
- package/dist/index.d.ts +27 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -8
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +28 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +37 -0
- package/dist/limits.js.map +1 -0
- package/dist/list-pagination.d.ts +41 -0
- package/dist/list-pagination.d.ts.map +1 -0
- package/dist/list-pagination.js +104 -0
- package/dist/list-pagination.js.map +1 -0
- package/dist/net.d.ts +112 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +490 -0
- package/dist/net.js.map +1 -0
- package/dist/notifications.d.ts +78 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +173 -0
- package/dist/notifications.js.map +1 -0
- package/dist/pagination.d.ts +236 -5
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +393 -6
- package/dist/pagination.js.map +1 -1
- package/dist/prompts.d.ts +70 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +109 -0
- package/dist/prompts.js.map +1 -0
- package/dist/protocol-errors.d.ts +15 -0
- package/dist/protocol-errors.d.ts.map +1 -0
- package/dist/protocol-errors.js +28 -0
- package/dist/protocol-errors.js.map +1 -0
- package/dist/protocol-logging.d.ts +37 -0
- package/dist/protocol-logging.d.ts.map +1 -0
- package/dist/protocol-logging.js +77 -0
- package/dist/protocol-logging.js.map +1 -0
- package/dist/rate-limiter.d.ts +36 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +79 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/request-state.d.ts +74 -0
- package/dist/request-state.d.ts.map +1 -0
- package/dist/request-state.js +190 -0
- package/dist/request-state.js.map +1 -0
- package/dist/resources.d.ts +181 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +302 -0
- package/dist/resources.js.map +1 -0
- package/dist/result-limits.d.ts +80 -0
- package/dist/result-limits.d.ts.map +1 -0
- package/dist/result-limits.js +248 -0
- package/dist/result-limits.js.map +1 -0
- package/dist/retry.d.ts +79 -23
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +170 -57
- package/dist/retry.js.map +1 -1
- package/dist/sdk/client-stdio.d.ts +6 -0
- package/dist/sdk/client-stdio.d.ts.map +1 -0
- package/dist/sdk/client-stdio.js +6 -0
- package/dist/sdk/client-stdio.js.map +1 -0
- package/dist/sdk/client.d.ts +6 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +6 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/express.d.ts +3 -0
- package/dist/sdk/express.d.ts.map +1 -0
- package/dist/sdk/express.js +11 -0
- package/dist/sdk/express.js.map +1 -0
- package/dist/sdk/node.d.ts +6 -0
- package/dist/sdk/node.d.ts.map +1 -0
- package/dist/sdk/node.js +6 -0
- package/dist/sdk/node.js.map +1 -0
- package/dist/sdk/server-stdio.d.ts +6 -0
- package/dist/sdk/server-stdio.d.ts.map +1 -0
- package/dist/sdk/server-stdio.js +6 -0
- package/dist/sdk/server-stdio.js.map +1 -0
- package/dist/sdk/server.d.ts +6 -0
- package/dist/sdk/server.d.ts.map +1 -0
- package/dist/sdk/server.js +6 -0
- package/dist/sdk/server.js.map +1 -0
- package/dist/server.d.ts +88 -35
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +98 -44
- package/dist/server.js.map +1 -1
- package/dist/task-request.d.ts +20 -0
- package/dist/task-request.d.ts.map +1 -0
- package/dist/task-request.js +43 -0
- package/dist/task-request.js.map +1 -0
- package/dist/task-store.d.ts +230 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +459 -0
- package/dist/task-store.js.map +1 -0
- package/dist/task-tools.d.ts +115 -0
- package/dist/task-tools.d.ts.map +1 -0
- package/dist/task-tools.js +397 -0
- package/dist/task-tools.js.map +1 -0
- package/dist/testing/client.d.ts +25 -0
- package/dist/testing/client.d.ts.map +1 -0
- package/dist/testing/client.js +11 -0
- package/dist/testing/client.js.map +1 -0
- package/dist/testing/in-memory.d.ts +26 -0
- package/dist/testing/in-memory.d.ts.map +1 -0
- package/dist/testing/in-memory.js +41 -0
- package/dist/testing/in-memory.js.map +1 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +20 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/isolated-dirs.d.ts +27 -0
- package/dist/testing/isolated-dirs.d.ts.map +1 -0
- package/dist/testing/isolated-dirs.js +67 -0
- package/dist/testing/isolated-dirs.js.map +1 -0
- package/dist/testing/logs.d.ts +61 -0
- package/dist/testing/logs.d.ts.map +1 -0
- package/dist/testing/logs.js +113 -0
- package/dist/testing/logs.js.map +1 -0
- package/dist/testing/raw-http.d.ts +25 -0
- package/dist/testing/raw-http.d.ts.map +1 -0
- package/dist/testing/raw-http.js +41 -0
- package/dist/testing/raw-http.js.map +1 -0
- package/dist/testing/raw-peer.d.ts +43 -0
- package/dist/testing/raw-peer.d.ts.map +1 -0
- package/dist/testing/raw-peer.js +101 -0
- package/dist/testing/raw-peer.js.map +1 -0
- package/dist/testing/recording-server.d.ts +38 -0
- package/dist/testing/recording-server.d.ts.map +1 -0
- package/dist/testing/recording-server.js +38 -0
- package/dist/testing/recording-server.js.map +1 -0
- package/dist/testing/server-process.d.ts +76 -0
- package/dist/testing/server-process.d.ts.map +1 -0
- package/dist/testing/server-process.js +241 -0
- package/dist/testing/server-process.js.map +1 -0
- package/dist/testing/tools.d.ts +53 -0
- package/dist/testing/tools.d.ts.map +1 -0
- package/dist/testing/tools.js +98 -0
- package/dist/testing/tools.js.map +1 -0
- package/dist/testing/unit.d.ts +52 -0
- package/dist/testing/unit.d.ts.map +1 -0
- package/dist/testing/unit.js +95 -0
- package/dist/testing/unit.js.map +1 -0
- package/dist/tools.d.ts +205 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +370 -0
- package/dist/tools.js.map +1 -0
- package/dist/transport.d.ts +143 -52
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +292 -123
- package/dist/transport.js.map +1 -1
- package/dist/url-path.d.ts +49 -0
- package/dist/url-path.d.ts.map +1 -0
- package/dist/url-path.js +165 -0
- package/dist/url-path.js.map +1 -0
- package/dist/utils/dataStore.d.ts +143 -0
- package/dist/utils/dataStore.d.ts.map +1 -0
- package/dist/utils/dataStore.js +429 -0
- package/dist/utils/dataStore.js.map +1 -0
- package/dist/utils/envLoader.d.ts +129 -0
- package/dist/utils/envLoader.d.ts.map +1 -0
- package/dist/utils/envLoader.js +399 -0
- package/dist/utils/envLoader.js.map +1 -0
- package/dist/utils/logger.d.ts +181 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +664 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/redact.d.ts +50 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +318 -0
- package/dist/utils/redact.js.map +1 -0
- package/docs/api-reference.md +29 -0
- package/docs/building-a-server.md +63 -0
- package/docs/credentials.md +131 -0
- package/docs/data-store.md +37 -0
- package/docs/env.md +38 -0
- package/docs/features.md +28 -0
- package/docs/http-client.md +116 -0
- package/docs/logger.md +100 -0
- package/docs/migrating-to-v3.md +45 -0
- package/docs/outbound-urls.md +104 -0
- package/docs/pagination.md +45 -0
- package/docs/protocol-features.md +62 -0
- package/docs/resources-prompts-tasks.md +95 -0
- package/docs/sdk.md +33 -0
- package/docs/server.md +68 -0
- package/docs/testing-harness.md +139 -0
- package/docs/testing.md +151 -0
- package/docs/tools.md +88 -0
- package/docs/transport.md +85 -0
- package/examples/testing/tools.integration.test.example.ts +312 -0
- package/examples/testing/tools.unit.test.example.ts +149 -0
- package/package.json +130 -17
- package/dist/logger.d.ts +0 -80
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -237
- package/dist/logger.js.map +0 -1
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @novorb/mcp-core - Data store
|
|
3
|
+
*
|
|
4
|
+
* The one module an MCP server uses to write to disk (discovery caches, downloads, persisted settings).
|
|
5
|
+
*
|
|
6
|
+
* - Directory: `DATA_PATH` (absolute, or relative to rootDir), default `<rootDir>/.data`. Created
|
|
7
|
+
* lazily on the first write, never at import time and never relative to cwd.
|
|
8
|
+
* - `DATA_STORAGE=false` runs the server STATELESS: nothing is written, no directory is created;
|
|
9
|
+
* `jsonCache` falls back to process memory and `downloadToFile` returns the bytes instead of a path.
|
|
10
|
+
* - `downloadToFile` fetches a URL source through `guardedFetch` (`../net.ts`): public addresses only
|
|
11
|
+
* unless the caller passes `allowPrivate: true`, every redirect hop re-validated.
|
|
12
|
+
* - Every path goes through `resolveInside`, which refuses `..`, absolute segments, drive letters, NUL
|
|
13
|
+
* and symlink escapes. Names that come from tool arguments or remote APIs go through `safeName` first.
|
|
14
|
+
*
|
|
15
|
+
* const store = createDataStore({ rootDir, env });
|
|
16
|
+
* const cache = store.jsonCache<Discovery>({ name: 'discovery', ttlMs: 3_600_000 });
|
|
17
|
+
* const hit = await cache.read();
|
|
18
|
+
*/
|
|
19
|
+
import { randomBytes } from 'node:crypto';
|
|
20
|
+
import { realpathSync } from 'node:fs';
|
|
21
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
import { GuardedFetchError, guardedFetch } from '../net.js';
|
|
24
|
+
import { sleep } from '../retry.js';
|
|
25
|
+
import { toolError } from '../tools.js';
|
|
26
|
+
import { getLogger } from './logger.js';
|
|
27
|
+
/** A path that would leave the data directory (or is malformed). */
|
|
28
|
+
export class DataPathError extends Error {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = 'DataPathError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** A write was attempted while DATA_STORAGE=false. */
|
|
35
|
+
export class DataStorageDisabledError extends Error {
|
|
36
|
+
constructor(feature) {
|
|
37
|
+
super(storageDisabledMessage(feature));
|
|
38
|
+
this.name = 'DataStorageDisabledError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** A download failed: bad status, too large, too slow, too many redirects. */
|
|
42
|
+
export class DownloadError extends Error {
|
|
43
|
+
/**
|
|
44
|
+
* `blocked`: the SSRF guard refused the URL or a redirect hop (invalid URL, userinfo, origin off
|
|
45
|
+
* `allowedOrigins`, private address); `content-type`: off `allowedContentTypes`.
|
|
46
|
+
*/
|
|
47
|
+
reason;
|
|
48
|
+
status;
|
|
49
|
+
constructor(reason, message, status) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = 'DownloadError';
|
|
52
|
+
this.reason = reason;
|
|
53
|
+
if (status !== undefined)
|
|
54
|
+
this.status = status;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function storageDisabledMessage(feature) {
|
|
58
|
+
return `data storage is disabled (DATA_STORAGE=false): ${feature} needs it`;
|
|
59
|
+
}
|
|
60
|
+
const WINDOWS_RESERVED = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
|
61
|
+
const MAX_NAME_LENGTH = 200;
|
|
62
|
+
/**
|
|
63
|
+
* Turn an untrusted name (a tool argument, a remote file name) into one safe path segment: separators
|
|
64
|
+
* and characters outside `[A-Za-z0-9._ -]` become `_`, leading dots and trailing dots/spaces are
|
|
65
|
+
* removed, Windows reserved device names are prefixed with `_`, length is capped. Never empty.
|
|
66
|
+
*/
|
|
67
|
+
export function safeName(name) {
|
|
68
|
+
let out = name
|
|
69
|
+
.replace(/[^A-Za-z0-9._ -]/g, '_')
|
|
70
|
+
.replace(/^[.\s]+/, '')
|
|
71
|
+
.replace(/[.\s]+$/, '');
|
|
72
|
+
if (WINDOWS_RESERVED.test(out))
|
|
73
|
+
out = `_${out}`;
|
|
74
|
+
if (out.length > MAX_NAME_LENGTH)
|
|
75
|
+
out = out.slice(0, MAX_NAME_LENGTH).replace(/[.\s]+$/, '');
|
|
76
|
+
return out || '_';
|
|
77
|
+
}
|
|
78
|
+
function checkSegment(segment) {
|
|
79
|
+
if (segment.includes('\0'))
|
|
80
|
+
throw new DataPathError('path segment contains a NUL character');
|
|
81
|
+
if (/^[A-Za-z]:/.test(segment))
|
|
82
|
+
throw new DataPathError('path segment has a drive letter');
|
|
83
|
+
if (path.posix.isAbsolute(segment) || path.win32.isAbsolute(segment)) {
|
|
84
|
+
throw new DataPathError('path segment is absolute');
|
|
85
|
+
}
|
|
86
|
+
const parts = segment.split(/[\\/]+/).filter((p) => p !== '' && p !== '.');
|
|
87
|
+
if (parts.some((p) => p === '..'))
|
|
88
|
+
throw new DataPathError('path segment contains ".."');
|
|
89
|
+
return parts;
|
|
90
|
+
}
|
|
91
|
+
function isInside(base, target) {
|
|
92
|
+
const rel = path.relative(base, target);
|
|
93
|
+
// `..` or `../x` escapes; a name that merely starts with dots (`..foo`) is inside.
|
|
94
|
+
const escapes = rel === '..' || rel.startsWith(`..${path.sep}`);
|
|
95
|
+
return rel === '' || (!escapes && !path.isAbsolute(rel));
|
|
96
|
+
}
|
|
97
|
+
/** The realpath of the deepest existing ancestor of `target` (symlink escapes are caught on it). */
|
|
98
|
+
function realAncestor(target) {
|
|
99
|
+
let current = target;
|
|
100
|
+
for (;;) {
|
|
101
|
+
try {
|
|
102
|
+
return realpathSync.native(current);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
const parent = path.dirname(current);
|
|
106
|
+
if (parent === current)
|
|
107
|
+
return undefined;
|
|
108
|
+
current = parent;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Join `segments` under `baseDir`, throwing `DataPathError` if the result would escape it. */
|
|
113
|
+
export function resolveInside(baseDir, ...segments) {
|
|
114
|
+
const base = path.resolve(baseDir);
|
|
115
|
+
const parts = segments.flatMap(checkSegment);
|
|
116
|
+
if (parts.length === 0)
|
|
117
|
+
throw new DataPathError('empty path');
|
|
118
|
+
const target = path.join(base, ...parts);
|
|
119
|
+
if (!isInside(base, target))
|
|
120
|
+
throw new DataPathError('path escapes the data directory');
|
|
121
|
+
// Symlink escape: the deepest existing ancestor of the target, resolved, must stay inside the resolved
|
|
122
|
+
// base (when the base does not exist yet both resolve to the same existing ancestor).
|
|
123
|
+
const realBase = realAncestor(base);
|
|
124
|
+
const realTarget = realAncestor(target);
|
|
125
|
+
if (realBase && realTarget && !isInside(realBase, realTarget)) {
|
|
126
|
+
throw new DataPathError('path escapes the data directory through a symlink');
|
|
127
|
+
}
|
|
128
|
+
return target;
|
|
129
|
+
}
|
|
130
|
+
function isCwdDependent(p) {
|
|
131
|
+
if (/^[A-Za-z]:(?![\\/])/.test(p))
|
|
132
|
+
return true;
|
|
133
|
+
return process.platform === 'win32' && /^[\\/](?![\\/])/.test(p);
|
|
134
|
+
}
|
|
135
|
+
function resolveDataDir(rootDir, dataPath) {
|
|
136
|
+
if (dataPath === undefined)
|
|
137
|
+
return path.join(path.resolve(rootDir), '.data');
|
|
138
|
+
if (isCwdDependent(dataPath))
|
|
139
|
+
throw new DataPathError(`DATA_PATH "${dataPath}" is drive- or root-relative`);
|
|
140
|
+
return path.isAbsolute(dataPath) ? path.resolve(dataPath) : path.resolve(rootDir, dataPath);
|
|
141
|
+
}
|
|
142
|
+
const DEFAULT_MAX_BYTES = 50 * 1024 * 1024;
|
|
143
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
144
|
+
const DEFAULT_MAX_REDIRECTS = 3;
|
|
145
|
+
/**
|
|
146
|
+
* A URL source through the SSRF guard: http(s) only, no userinfo, public addresses only (unless
|
|
147
|
+
* `allowPrivate`) checked in the socket lookup, every redirect hop re-validated, headers dropped across
|
|
148
|
+
* origins. The data store's own signal carries the time cap; the guard's cap is the same budget.
|
|
149
|
+
*/
|
|
150
|
+
function fetchGuarded(source, opts, maxBytes, signal) {
|
|
151
|
+
const guard = {
|
|
152
|
+
redirects: opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS,
|
|
153
|
+
maxBytes,
|
|
154
|
+
timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
155
|
+
signal,
|
|
156
|
+
};
|
|
157
|
+
if (opts.headers)
|
|
158
|
+
guard.headers = opts.headers;
|
|
159
|
+
if (opts.allowPrivate !== undefined)
|
|
160
|
+
guard.allowPrivate = opts.allowPrivate;
|
|
161
|
+
if (opts.allowedOrigins)
|
|
162
|
+
guard.allowedOrigins = opts.allowedOrigins;
|
|
163
|
+
if (opts.allowedContentTypes)
|
|
164
|
+
guard.allowedContentTypes = opts.allowedContentTypes;
|
|
165
|
+
if (opts.lookup)
|
|
166
|
+
guard.lookup = opts.lookup;
|
|
167
|
+
if (opts.isAllowedAddress)
|
|
168
|
+
guard.isAllowedAddress = opts.isAllowedAddress;
|
|
169
|
+
return guardedFetch(source, guard);
|
|
170
|
+
}
|
|
171
|
+
/** A download cap as a finite number at least `min`; a TypeError naming the option otherwise. */
|
|
172
|
+
function requireCap(name, value, min) {
|
|
173
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < min) {
|
|
174
|
+
throw new TypeError(`downloadToFile: ${name} must be a finite number >= ${min}`);
|
|
175
|
+
}
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
const GUARD_REASONS = {
|
|
179
|
+
url: 'blocked',
|
|
180
|
+
protocol: 'protocol',
|
|
181
|
+
credentials: 'blocked',
|
|
182
|
+
origin: 'blocked',
|
|
183
|
+
address: 'blocked',
|
|
184
|
+
redirect: 'redirects',
|
|
185
|
+
redirects: 'redirects',
|
|
186
|
+
'content-type': 'content-type',
|
|
187
|
+
'too-large': 'too-large',
|
|
188
|
+
timeout: 'timeout',
|
|
189
|
+
aborted: 'aborted',
|
|
190
|
+
network: 'network',
|
|
191
|
+
};
|
|
192
|
+
/** `reader.read()` that rejects once `signal` aborts (a source that ignores the signal stays bounded). */
|
|
193
|
+
function readOrAbort(reader, signal) {
|
|
194
|
+
if (!signal)
|
|
195
|
+
return reader.read();
|
|
196
|
+
if (signal.aborted)
|
|
197
|
+
return Promise.reject(signal.reason);
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
const onAbort = () => reject(signal.reason);
|
|
200
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
201
|
+
reader.read().then((r) => {
|
|
202
|
+
signal.removeEventListener('abort', onAbort);
|
|
203
|
+
resolve(r);
|
|
204
|
+
}, (e) => {
|
|
205
|
+
signal.removeEventListener('abort', onAbort);
|
|
206
|
+
reject(e);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async function readCapped(res, maxBytes, signal) {
|
|
211
|
+
const declared = Number(res.headers.get('content-length'));
|
|
212
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
213
|
+
await res.body?.cancel().catch(() => undefined);
|
|
214
|
+
throw new DownloadError('too-large', `body exceeds ${maxBytes} bytes`);
|
|
215
|
+
}
|
|
216
|
+
if (!res.body)
|
|
217
|
+
return Buffer.alloc(0);
|
|
218
|
+
const reader = res.body.getReader();
|
|
219
|
+
const chunks = [];
|
|
220
|
+
let size = 0;
|
|
221
|
+
for (;;) {
|
|
222
|
+
const { done, value } = await readOrAbort(reader, signal);
|
|
223
|
+
if (done)
|
|
224
|
+
break;
|
|
225
|
+
size += value.byteLength;
|
|
226
|
+
if (size > maxBytes) {
|
|
227
|
+
await reader.cancel().catch(() => undefined);
|
|
228
|
+
throw new DownloadError('too-large', `body exceeds ${maxBytes} bytes`);
|
|
229
|
+
}
|
|
230
|
+
chunks.push(Buffer.from(value));
|
|
231
|
+
}
|
|
232
|
+
return Buffer.concat(chunks);
|
|
233
|
+
}
|
|
234
|
+
function describeFailure(err, timeout, caller) {
|
|
235
|
+
if (err instanceof DownloadError)
|
|
236
|
+
return err;
|
|
237
|
+
if (caller?.aborted)
|
|
238
|
+
return new DownloadError('aborted', 'download aborted');
|
|
239
|
+
if (timeout.aborted)
|
|
240
|
+
return new DownloadError('timeout', 'download timed out');
|
|
241
|
+
if (err instanceof GuardedFetchError) {
|
|
242
|
+
const reason = GUARD_REASONS[err.reason];
|
|
243
|
+
const verb = reason === 'blocked' || reason === 'protocol' || reason === 'content-type'
|
|
244
|
+
? 'download refused'
|
|
245
|
+
: 'download failed';
|
|
246
|
+
return new DownloadError(reason, `${verb}: ${err.message}`);
|
|
247
|
+
}
|
|
248
|
+
return new DownloadError('network', `download failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
249
|
+
}
|
|
250
|
+
/** The transient rename failures Windows raises while another handle (a reader, AV, the indexer) has the target open. */
|
|
251
|
+
const TRANSIENT_RENAME_CODES = new Set(['EPERM', 'EACCES', 'EBUSY']);
|
|
252
|
+
/**
|
|
253
|
+
* `rename(from, to)` with the Windows replace race handled: on win32 an EPERM/EACCES/EBUSY (the target is
|
|
254
|
+
* open in another handle, for example a poller reading it) is retried with a short growing backoff
|
|
255
|
+
* within `budgetMs`, then rethrown. Other platforms and other errors fail at once.
|
|
256
|
+
*/
|
|
257
|
+
export async function renameWithRetry(from, to, options = {}) {
|
|
258
|
+
const doRename = options.rename ?? rename;
|
|
259
|
+
const retries = (options.platform ?? process.platform) === 'win32';
|
|
260
|
+
const deadline = Date.now() + (options.budgetMs ?? 2000);
|
|
261
|
+
for (let delay = 10;; delay = Math.min(delay * 2, 200)) {
|
|
262
|
+
try {
|
|
263
|
+
await doRename(from, to);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
const code = e?.code;
|
|
268
|
+
if (!retries || code === undefined || !TRANSIENT_RENAME_CODES.has(code) || Date.now() + delay > deadline)
|
|
269
|
+
throw e;
|
|
270
|
+
await sleep(delay);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/** Create the data store for a server (see the module header). */
|
|
275
|
+
export function createDataStore(opts) {
|
|
276
|
+
// Fail closed: an invalid DATA_STORAGE value (a typo of "false") disables writes instead of enabling them.
|
|
277
|
+
const raw = opts.env.get('DATA_STORAGE');
|
|
278
|
+
const parsed = opts.env.bool('DATA_STORAGE');
|
|
279
|
+
const enabled = raw === undefined ? true : parsed === true;
|
|
280
|
+
if (raw !== undefined && parsed === undefined) {
|
|
281
|
+
(opts.logger ?? getLogger()).warn('env DATA_STORAGE is not a boolean; disk storage is disabled', 'DataStore');
|
|
282
|
+
}
|
|
283
|
+
const dir = enabled ? resolveDataDir(opts.rootDir, opts.env.get('DATA_PATH')) : null;
|
|
284
|
+
const memory = new Map();
|
|
285
|
+
const inside = (...segments) => {
|
|
286
|
+
if (!dir)
|
|
287
|
+
throw new DataStorageDisabledError('a file path');
|
|
288
|
+
return resolveInside(dir, ...segments);
|
|
289
|
+
};
|
|
290
|
+
const atomicWrite = async (target, data) => {
|
|
291
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
292
|
+
const temp = `${target}.tmp-${randomBytes(6).toString('hex')}`;
|
|
293
|
+
try {
|
|
294
|
+
await writeFile(temp, data);
|
|
295
|
+
await renameWithRetry(temp, target);
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
await rm(temp, { force: true }).catch(() => undefined);
|
|
299
|
+
throw e;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const store = {
|
|
303
|
+
enabled,
|
|
304
|
+
dir,
|
|
305
|
+
resolveInside: inside,
|
|
306
|
+
async writeFile(relPath, data) {
|
|
307
|
+
if (!dir)
|
|
308
|
+
throw new DataStorageDisabledError('writing a file');
|
|
309
|
+
const target = inside(relPath);
|
|
310
|
+
await atomicWrite(target, data);
|
|
311
|
+
return target;
|
|
312
|
+
},
|
|
313
|
+
async readFile(relPath) {
|
|
314
|
+
if (!dir)
|
|
315
|
+
return null;
|
|
316
|
+
try {
|
|
317
|
+
return await readFile(inside(relPath));
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
if (e.code === 'ENOENT')
|
|
321
|
+
return null;
|
|
322
|
+
throw e;
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
async remove(relPath) {
|
|
326
|
+
if (!dir)
|
|
327
|
+
return false;
|
|
328
|
+
const target = inside(relPath);
|
|
329
|
+
try {
|
|
330
|
+
await rm(target, { recursive: true });
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
if (e.code === 'ENOENT')
|
|
335
|
+
return false;
|
|
336
|
+
throw e;
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
async ensureDir(relPath) {
|
|
340
|
+
if (!dir)
|
|
341
|
+
throw new DataStorageDisabledError('a data directory');
|
|
342
|
+
const target = inside(relPath);
|
|
343
|
+
await mkdir(target, { recursive: true });
|
|
344
|
+
return target;
|
|
345
|
+
},
|
|
346
|
+
jsonCache({ name, ttlMs }) {
|
|
347
|
+
const file = `cache/${safeName(name)}.json`;
|
|
348
|
+
const fresh = (savedAt) => {
|
|
349
|
+
const ageMs = Date.now() - savedAt;
|
|
350
|
+
return ageMs <= ttlMs ? Math.max(0, ageMs) : null;
|
|
351
|
+
};
|
|
352
|
+
return {
|
|
353
|
+
async read() {
|
|
354
|
+
if (!dir) {
|
|
355
|
+
const hit = memory.get(file);
|
|
356
|
+
const ageMs = hit ? fresh(hit.savedAt) : null;
|
|
357
|
+
return hit && ageMs !== null ? { data: hit.data, ageMs } : null;
|
|
358
|
+
}
|
|
359
|
+
const raw = await store.readFile(file);
|
|
360
|
+
if (!raw)
|
|
361
|
+
return null;
|
|
362
|
+
try {
|
|
363
|
+
const parsed = JSON.parse(raw.toString('utf8'));
|
|
364
|
+
if (typeof parsed.savedAt !== 'number')
|
|
365
|
+
return null;
|
|
366
|
+
const ageMs = fresh(parsed.savedAt);
|
|
367
|
+
return ageMs === null ? null : { data: parsed.data, ageMs };
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
opts.logger?.warn(`cache ${safeName(name)} is unreadable; ignoring it`, 'DataStore');
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
async write(data) {
|
|
375
|
+
const entry = { savedAt: Date.now(), data };
|
|
376
|
+
if (!dir)
|
|
377
|
+
memory.set(file, entry);
|
|
378
|
+
else
|
|
379
|
+
await store.writeFile(file, JSON.stringify(entry));
|
|
380
|
+
},
|
|
381
|
+
async clear() {
|
|
382
|
+
if (!dir)
|
|
383
|
+
memory.delete(file);
|
|
384
|
+
else
|
|
385
|
+
await store.remove(file);
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
},
|
|
389
|
+
async downloadToFile(source, relPath, dl = {}) {
|
|
390
|
+
// The path is validated in both modes, so a call valid when stateless is valid when stateful.
|
|
391
|
+
checkSegment(relPath);
|
|
392
|
+
const target = dir ? inside(relPath) : null;
|
|
393
|
+
// A non-finite or negative cap would silently disable it: refuse it before anything is fetched.
|
|
394
|
+
const maxBytes = requireCap('maxBytes', dl.maxBytes ?? DEFAULT_MAX_BYTES, 0);
|
|
395
|
+
requireCap('maxRedirects', dl.maxRedirects ?? DEFAULT_MAX_REDIRECTS, 0);
|
|
396
|
+
const timeout = AbortSignal.timeout(requireCap('timeoutMs', dl.timeoutMs ?? DEFAULT_TIMEOUT_MS, 1));
|
|
397
|
+
const signal = dl.signal ? AbortSignal.any([timeout, dl.signal]) : timeout;
|
|
398
|
+
let body;
|
|
399
|
+
let contentType;
|
|
400
|
+
try {
|
|
401
|
+
const res = typeof source === 'function' ? await source({ signal }) : await fetchGuarded(source, dl, maxBytes, signal);
|
|
402
|
+
if (res.status < 200 || res.status >= 300) {
|
|
403
|
+
await res.body?.cancel().catch(() => undefined);
|
|
404
|
+
throw new DownloadError('status', `download failed with status ${res.status}`, res.status);
|
|
405
|
+
}
|
|
406
|
+
contentType = res.headers.get('content-type') ?? undefined;
|
|
407
|
+
body = await readCapped(res, maxBytes, signal);
|
|
408
|
+
}
|
|
409
|
+
catch (e) {
|
|
410
|
+
throw describeFailure(e, timeout, dl.signal);
|
|
411
|
+
}
|
|
412
|
+
const result = { bytes: body.byteLength, path: target };
|
|
413
|
+
if (contentType)
|
|
414
|
+
result.contentType = contentType;
|
|
415
|
+
if (!target) {
|
|
416
|
+
result.data = body;
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
await atomicWrite(target, body);
|
|
420
|
+
opts.logger?.debug('download stored', 'DataStore', { bytes: body.byteLength });
|
|
421
|
+
return result;
|
|
422
|
+
},
|
|
423
|
+
requireEnabled(feature) {
|
|
424
|
+
return enabled ? undefined : toolError(storageDisabledMessage(feature));
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
return store;
|
|
428
|
+
}
|
|
429
|
+
//# sourceMappingURL=dataStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataStore.js","sourceRoot":"","sources":["../../src/utils/dataStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @novorb/mcp-core - Env loader
|
|
3
|
+
*
|
|
4
|
+
* Every MCP server declares its own env schema (`EnvSchema`) and loads its environment through
|
|
5
|
+
* `loadEnv` (no dotenv). mcp-core's own keys (`CORE_ENV_SCHEMA`: transport,
|
|
6
|
+
* auth, logger, data storage) are merged in, so a server declares only its own keys.
|
|
7
|
+
*
|
|
8
|
+
* Sources, highest first: the real process env > `<rootDir>/.env` > the spec `value` default.
|
|
9
|
+
* `MCP_ENV_FILE` (read from the real env only) overrides the file path (absolute, or relative to
|
|
10
|
+
* rootDir); `MCP_ENV_FILE=none` disables the file. The file is parsed with Node's `util.parseEnv`.
|
|
11
|
+
*
|
|
12
|
+
* const env = loadEnv([
|
|
13
|
+
* { key: 'GITLAB_URL', type: 'url', value: 'https://gitlab.com', description: 'GitLab base URL' },
|
|
14
|
+
* { key: 'GITLAB_PERSONAL_ACCESS_TOKEN', required: true, secret: true, description: 'API token' },
|
|
15
|
+
* ], { rootDir: packageRootFrom(import.meta.url) });
|
|
16
|
+
* if (!env.isConfigured()) getLogger().warn(`not configured: set ${env.missing.join(', ')}`);
|
|
17
|
+
*
|
|
18
|
+
* Values are never logged, never returned by `describe()`, and every set `secret: true` value is
|
|
19
|
+
* registered with the logger so it is masked verbatim in every log entry.
|
|
20
|
+
*/
|
|
21
|
+
import type { CredentialCheck } from '../credential-checks.js';
|
|
22
|
+
export type EnvVarType = 'string' | 'int' | 'bool' | 'url' | 'enum';
|
|
23
|
+
export interface EnvVarSpec {
|
|
24
|
+
/** The variable name, or the base name of a `multi` family (`KEY`, `KEY_1`, `KEY_EU`, ...). */
|
|
25
|
+
key: string;
|
|
26
|
+
/** Default value when the variable is unset. */
|
|
27
|
+
value?: string;
|
|
28
|
+
/** Required for the server to be fully configured (reported by `missing` / `isConfigured`). */
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/** Collect `KEY` plus every `KEY_<suffix>` into an ordered list (`getAll`). */
|
|
31
|
+
multi?: boolean;
|
|
32
|
+
/** A secret: never logged, never rendered, masked verbatim by the logger. A spec with a `check` is always a secret. */
|
|
33
|
+
secret?: boolean;
|
|
34
|
+
/** Validation type (default `string`). */
|
|
35
|
+
type?: EnvVarType;
|
|
36
|
+
/** The allowed values of an `enum`. */
|
|
37
|
+
values?: readonly string[];
|
|
38
|
+
/** Documentation; feeds `renderEnvTable` and `renderEnvExample`. */
|
|
39
|
+
description?: string;
|
|
40
|
+
/**
|
|
41
|
+
* A credential probe the server supplies (see "Credential health"): run once at startup per set
|
|
42
|
+
* value (each member of a `multi` family on its own) and answering the key's status. A server's own
|
|
43
|
+
* `secret` keys are tracked as credentials even without one (status `unknown` until used). A spec
|
|
44
|
+
* with a `check` is treated as `secret: true` (masked, never rendered) whether or not it says so.
|
|
45
|
+
*/
|
|
46
|
+
check?: CredentialCheck;
|
|
47
|
+
/**
|
|
48
|
+
* With a `check`: the other declared keys that are parts of the same multi-part credential (read in the
|
|
49
|
+
* check through `ctx.get`). Their status follows this key's (check result, re-check, recorded runtime
|
|
50
|
+
* outcome), so no part stays `unknown`; the check's `reason` still names the rejected part.
|
|
51
|
+
*/
|
|
52
|
+
covers?: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
export type EnvSchema = readonly EnvVarSpec[];
|
|
55
|
+
/** Where a value came from. */
|
|
56
|
+
export type EnvSource = 'env' | 'file' | 'default';
|
|
57
|
+
/** One validation problem, by key name (never the value). */
|
|
58
|
+
export interface EnvError {
|
|
59
|
+
key: string;
|
|
60
|
+
message: string;
|
|
61
|
+
}
|
|
62
|
+
/** `describe()` row: names and state only, never a value. */
|
|
63
|
+
export interface EnvKeyState {
|
|
64
|
+
key: string;
|
|
65
|
+
set: boolean;
|
|
66
|
+
source?: EnvSource;
|
|
67
|
+
required: boolean;
|
|
68
|
+
secret: boolean;
|
|
69
|
+
/** multi families: how many members are set. */
|
|
70
|
+
count?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface LoadEnvOptions {
|
|
73
|
+
/** The server's package root; `.env` and relative MCP_ENV_FILE paths resolve against it. */
|
|
74
|
+
rootDir: string;
|
|
75
|
+
/** The environment to read and populate (default `process.env`). */
|
|
76
|
+
env?: NodeJS.ProcessEnv;
|
|
77
|
+
/** Throw on validation errors instead of collecting them. */
|
|
78
|
+
strict?: boolean;
|
|
79
|
+
/** Merge `CORE_ENV_SCHEMA` (default true). */
|
|
80
|
+
includeCore?: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface LoadedEnv {
|
|
83
|
+
/** The merged schema (core keys first, then the server's). */
|
|
84
|
+
readonly schema: EnvSchema;
|
|
85
|
+
/** The env file that was read, or null (none found, or MCP_ENV_FILE=none). */
|
|
86
|
+
readonly envFile: string | null;
|
|
87
|
+
/** Required keys that are not set. */
|
|
88
|
+
readonly missing: readonly string[];
|
|
89
|
+
/** Validation errors (bad int, bool, url, enum, unreadable env file), by key name. */
|
|
90
|
+
readonly errors: readonly EnvError[];
|
|
91
|
+
/** Key names found in the env file that no schema declares (not loaded). */
|
|
92
|
+
readonly unknownFileKeys: readonly string[];
|
|
93
|
+
/** The resolved value (env > file > default); undefined when unset or empty. */
|
|
94
|
+
get(key: string): string | undefined;
|
|
95
|
+
/** A multi family: KEY first, then numeric suffixes in numeric order, then other suffixes A-Z. */
|
|
96
|
+
getAll(key: string): string[];
|
|
97
|
+
/** The NAMES of the set members of a key (a multi family's members in `getAll` order; else the key when set). */
|
|
98
|
+
members(key: string): string[];
|
|
99
|
+
/** The value parsed as an integer; undefined when unset or invalid. */
|
|
100
|
+
int(key: string): number | undefined;
|
|
101
|
+
/** The value parsed as a boolean (true/false, 1/0, yes/no, on/off); undefined when unset or invalid. */
|
|
102
|
+
bool(key: string): boolean | undefined;
|
|
103
|
+
/** Whether the key (or, for a multi family, any member) has a non-empty value. */
|
|
104
|
+
has(key: string): boolean;
|
|
105
|
+
/** Whether every key in `keys` (default: every required key) is set. */
|
|
106
|
+
isConfigured(keys?: readonly string[]): boolean;
|
|
107
|
+
/** Names, set/unset and source per declared key. Never a value. */
|
|
108
|
+
describe(): EnvKeyState[];
|
|
109
|
+
}
|
|
110
|
+
/** mcp-core's own variables (transport, auth, logger, data storage), merged into every schema. */
|
|
111
|
+
export declare const CORE_ENV_SCHEMA: EnvSchema;
|
|
112
|
+
/** A secret spec: `secret: true`, or any credential with a `check` (its value is a credential too). */
|
|
113
|
+
export declare function isSecret(spec: EnvVarSpec): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Load the environment for `schema` (merged with `CORE_ENV_SCHEMA`). Collects validation errors by key
|
|
116
|
+
* name (throws only with `strict: true`), warns once about undeclared env-file keys (names only),
|
|
117
|
+
* populates `env` for keys resolved from the file or a default (never overriding a set variable), and
|
|
118
|
+
* registers every set secret with the logger for verbatim masking.
|
|
119
|
+
*/
|
|
120
|
+
export declare function loadEnv(schema: EnvSchema, options: LoadEnvOptions): LoadedEnv;
|
|
121
|
+
export interface RenderOptions {
|
|
122
|
+
/** Include `CORE_ENV_SCHEMA` before the server's keys (default false). */
|
|
123
|
+
includeCore?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/** A markdown table (key, type, required, multi, secret, default, description) for READMEs. */
|
|
126
|
+
export declare function renderEnvTable(schema: EnvSchema, options?: RenderOptions): string;
|
|
127
|
+
/** `.env.example` text: a comment per key, the default as the value, secrets always empty. */
|
|
128
|
+
export declare function renderEnvExample(schema: EnvSchema, options?: RenderOptions): string;
|
|
129
|
+
//# sourceMappingURL=envLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envLoader.d.ts","sourceRoot":"","sources":["../../src/utils/envLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG/D,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,+FAA+F;IAC/F,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uHAAuH;IACvH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,UAAU,EAAE,CAAC;AAE9C,+BAA+B;AAC/B,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAEnD,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,gFAAgF;IAChF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,kGAAkG;IAClG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B,iHAAiH;IACjH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/B,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,wGAAwG;IACxG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACvC,kFAAkF;IAClF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,wEAAwE;IACxE,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IAChD,mEAAmE;IACnE,QAAQ,IAAI,WAAW,EAAE,CAAC;CAC3B;AAED,kGAAkG;AAClG,eAAO,MAAM,eAAe,EAAE,SA2F7B,CAAC;AAIF,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAElD;AAwFD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,SAAS,CAgJ7E;AAED,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAWD,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAerF;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAcvF"}
|