@capxul/mcp 4.1.4 → 4.2.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 +6 -3
- package/dist/main.mjs +430 -70
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -104,9 +104,12 @@ vp run --filter @capxul/mcp build
|
|
|
104
104
|
|
|
105
105
|
The tests are hermetic: a real HTTP server, a fake token exchange, and a fake
|
|
106
106
|
SDK client. They do not prove a live OAuth flow against a deployed backend, a
|
|
107
|
-
chain path, or settlement.
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
chain path, or settlement.
|
|
108
|
+
[#922](https://github.com/Xelmar-tech/infrastructure/issues/922) records the
|
|
109
|
+
historical packed-install gap. The current
|
|
110
|
+
`scripts/__tests__/pack-install-smoke.test.mjs` installs MCP and Sandbox
|
|
111
|
+
tarballs in a clean project and invokes their bins with `--help`. Run it
|
|
112
|
+
against the current artifacts before claiming installed-bin proof.
|
|
110
113
|
|
|
111
114
|
A live staging run in #1812 proves browser login, `account:write` consent,
|
|
112
115
|
Person onboarding, a ready Account, OAuth scope step-up, and the Account tools. A
|
package/dist/main.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { createHash } from "node:crypto";
|
|
|
8
8
|
import { createServer } from "node:http";
|
|
9
9
|
import { localhostHostValidation, localhostOriginValidation, toNodeHandler } from "@modelcontextprotocol/node";
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, Layer, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Tracer } from "effect";
|
|
11
|
+
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
|
|
12
12
|
import { FetchHttpClient, Headers, HttpClient } from "effect/unstable/http";
|
|
13
13
|
import { OtlpExporter, OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
14
14
|
import { resolve } from "path";
|
|
@@ -24,39 +24,275 @@ import zlib from "zlib";
|
|
|
24
24
|
import { McpServer, createMcpHandler } from "@modelcontextprotocol/server";
|
|
25
25
|
import { instrument } from "@posthog/mcp";
|
|
26
26
|
//#region ../../packages/errors/src/secret-material.ts
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
const CREDENTIAL_FIELDS = /* @__PURE__ */ new Set([
|
|
28
|
+
"password",
|
|
29
|
+
"passwd",
|
|
30
|
+
"pwd",
|
|
31
|
+
"pass",
|
|
32
|
+
"passphrase",
|
|
33
|
+
"currentpassword",
|
|
34
|
+
"newpassword",
|
|
35
|
+
"confirmpassword",
|
|
36
|
+
"passwordconfirmation",
|
|
37
|
+
"passwordhash",
|
|
38
|
+
"hashedpassword",
|
|
39
|
+
"pin",
|
|
40
|
+
"privatekey",
|
|
41
|
+
"walletprivatekey",
|
|
42
|
+
"secretkey",
|
|
43
|
+
"signingkey",
|
|
44
|
+
"signingsecret",
|
|
45
|
+
"seed",
|
|
46
|
+
"seedphrase",
|
|
47
|
+
"mnemonic",
|
|
48
|
+
"recoveryphrase",
|
|
49
|
+
"recovery",
|
|
50
|
+
"recoverycode",
|
|
51
|
+
"recoverycodes",
|
|
52
|
+
"keyshare",
|
|
53
|
+
"signingmaterial",
|
|
54
|
+
"recoverymaterial",
|
|
55
|
+
"privatekeybytes",
|
|
56
|
+
"signingprivatekey",
|
|
57
|
+
"encryptionkey",
|
|
58
|
+
"decryptionkey",
|
|
59
|
+
"authtoken",
|
|
60
|
+
"apitoken",
|
|
61
|
+
"bearertoken",
|
|
62
|
+
"oauthtoken",
|
|
63
|
+
"csrftoken",
|
|
64
|
+
"clientassertion",
|
|
65
|
+
"token",
|
|
66
|
+
"accesstoken",
|
|
67
|
+
"refreshtoken",
|
|
68
|
+
"idtoken",
|
|
69
|
+
"sessiontoken",
|
|
70
|
+
"session",
|
|
71
|
+
"sessionkey",
|
|
72
|
+
"sessionsecret",
|
|
73
|
+
"authsessionid",
|
|
74
|
+
"sessioncredential",
|
|
75
|
+
"sessioncredentials",
|
|
76
|
+
"sessioncookie",
|
|
77
|
+
"auth",
|
|
78
|
+
"authentication",
|
|
79
|
+
"authorization",
|
|
80
|
+
"proxyauthorization",
|
|
81
|
+
"cookie",
|
|
82
|
+
"cookies",
|
|
83
|
+
"setcookie",
|
|
84
|
+
"apikey",
|
|
85
|
+
"xapikey",
|
|
86
|
+
"xauthtoken",
|
|
87
|
+
"clientsecret",
|
|
88
|
+
"secret",
|
|
89
|
+
"secrets",
|
|
90
|
+
"credential",
|
|
91
|
+
"credentials",
|
|
92
|
+
"signature",
|
|
93
|
+
"otp",
|
|
94
|
+
"otpcode",
|
|
95
|
+
"totpsecret",
|
|
96
|
+
"onetimecode",
|
|
97
|
+
"onetimepassword",
|
|
98
|
+
"verificationcode",
|
|
99
|
+
"authcode",
|
|
100
|
+
"authorizationcode",
|
|
101
|
+
"oauthcode",
|
|
102
|
+
"codeverifier"
|
|
103
|
+
]);
|
|
104
|
+
/** Match credential fields by meaning, without hiding token addresses or replay IDs. */
|
|
105
|
+
function isCredentialField(name, context) {
|
|
106
|
+
const normalized = name.toLowerCase().replace(/[^a-z0-9]/gu, "");
|
|
107
|
+
return CREDENTIAL_FIELDS.has(normalized) || /(?:password(?:hash)?|passwd|passphrase|privatekey|signingkey|apikey|clientsecret|accesstoken|refreshtoken|sessiontoken)$/u.test(normalized) || context === "authentication" && (normalized === "code" || normalized === "sessionid") || context === "header" && /(?:token|secret|apikey|privatekey|signingkey|password|authorization|cookie|session)$/u.test(normalized);
|
|
108
|
+
}
|
|
109
|
+
function decodeUrlComponent(text) {
|
|
110
|
+
try {
|
|
111
|
+
return decodeURIComponent(text);
|
|
112
|
+
} catch {
|
|
113
|
+
return text;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Preserve URL diagnostics while removing credentials from their declared components. */
|
|
117
|
+
function redactUrlSecrets(value, source) {
|
|
118
|
+
try {
|
|
119
|
+
const absolute = /^[a-z][a-z0-9+.-]*:/iu.test(value);
|
|
120
|
+
const protocolRelative = value.startsWith("//");
|
|
121
|
+
const url = new URL(value, "https://redaction.invalid");
|
|
122
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return maskText(value);
|
|
123
|
+
let changed = url.username.length > 0 || url.password.length > 0;
|
|
124
|
+
const maskParams = (params) => new URLSearchParams(Array.from(params, ([name, entry]) => {
|
|
125
|
+
const safeName = maskText(name);
|
|
126
|
+
const safeEntry = isCredentialField(name) || /^(?:code|draft|__posthog)$/iu.test(name) ? "[REDACTED]" : maskText(entry);
|
|
127
|
+
changed ||= safeName !== name || safeEntry !== entry;
|
|
128
|
+
return [safeName, safeEntry];
|
|
129
|
+
})).toString();
|
|
130
|
+
const provider = source !== void 0 || /(?:^|\.)(?:alchemy\.com|alchemyapi\.io|infura\.io)$/iu.test(url.hostname);
|
|
131
|
+
const segments = (absolute || protocolRelative ? url.pathname : value.split(/[?#]/u)[0] ?? "").split("/");
|
|
132
|
+
const path = segments.map((segment, index) => {
|
|
133
|
+
const decoded = decodeUrlComponent(segment);
|
|
134
|
+
const masked = provider && /^v[23]$/u.test(decodeUrlComponent(segments[index - 1] ?? "")) && decoded.length > 0 ? "[REDACTED]" : maskText(decoded);
|
|
135
|
+
changed ||= masked !== decoded;
|
|
136
|
+
return masked === decoded ? segment : encodeURIComponent(masked);
|
|
137
|
+
}).join("/");
|
|
138
|
+
const query = maskParams(url.searchParams);
|
|
139
|
+
const fragment = url.hash.slice(1);
|
|
140
|
+
const decodedFragment = decodeUrlComponent(fragment);
|
|
141
|
+
const maskedFragment = maskText(decodedFragment);
|
|
142
|
+
changed ||= maskedFragment !== decodedFragment;
|
|
143
|
+
const fragmentQuery = fragment.indexOf("?");
|
|
144
|
+
const fragmentPath = fragment.slice(0, fragmentQuery);
|
|
145
|
+
const maskedFragmentPath = maskText(decodeUrlComponent(fragmentPath));
|
|
146
|
+
changed ||= maskedFragmentPath !== decodeUrlComponent(fragmentPath);
|
|
147
|
+
const hash = fragmentQuery >= 0 ? `${maskedFragmentPath === decodeUrlComponent(fragmentPath) ? fragmentPath : encodeURIComponent(maskedFragmentPath)}?${maskParams(new URLSearchParams(fragment.slice(fragmentQuery + 1)))}` : fragment.includes("=") ? maskParams(new URLSearchParams(fragment)) : maskedFragment === decodedFragment ? fragment : encodeURIComponent(maskedFragment);
|
|
148
|
+
const origin = absolute ? url.origin : protocolRelative ? `//${url.host}` : "";
|
|
149
|
+
if (!changed) return value;
|
|
150
|
+
return `${origin}${path}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}`;
|
|
151
|
+
} catch {
|
|
152
|
+
return maskText(value.replace(/(https?:\/\/)[^/\s@]+@/giu, "$1[REDACTED]@").replace(/([?&#])([^=&#]+)=([^&#]*)/gu, (whole, separator, name) => isCredentialField(decodeUrlComponent(name)) || /^(?:code|draft|__posthog)$/iu.test(decodeUrlComponent(name)) ? `${separator}${name}=[REDACTED]` : whole));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const JSON_FIELD = /("(?:[^"\\]|\\.)*")(\s*:\s*)("(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/gu;
|
|
156
|
+
const PROSE_FIELD = /(?=(\b([A-Za-z][A-Za-z0-9_-]*(?:[ \t]+[A-Za-z][A-Za-z0-9_-]*){0,3})\s*[:=]\s*((?:Bearer|Basic)[ \t]+[^\s,;"']+|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^\s,;&"']+)))/gu;
|
|
157
|
+
const EMBEDDED_URL = /(https?:\/\/[^\s"<>]*)/giu;
|
|
158
|
+
function isSecretLabel(name) {
|
|
159
|
+
return isCredentialField(name) || /^request[ _-]?body$/iu.test(name);
|
|
160
|
+
}
|
|
161
|
+
const JSON_ENCODING_MAX = 8;
|
|
162
|
+
const JSON_NESTING_MAX = 64;
|
|
163
|
+
const JSON_KEY = /("(?:[^"\\]|\\.)*")\s*:/gu;
|
|
164
|
+
const JSON_CONTAINER_START = /(?:\{\s*["}]|\[\s*[[\]{}"0-9tfn-])/uy;
|
|
165
|
+
function hasSecretJsonKey(value) {
|
|
166
|
+
for (const match of value.matchAll(JSON_KEY)) try {
|
|
167
|
+
if (match[1] !== void 0 && isSecretLabel(JSON.parse(match[1]))) return true;
|
|
168
|
+
} catch {}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
/** Project a complete fragment once. Never retry all of its nested substrings. */
|
|
172
|
+
function projectJsonFragment(value, encodingDepth, overDepth) {
|
|
173
|
+
if (overDepth || encodingDepth >= JSON_ENCODING_MAX) return "[REDACTED]";
|
|
174
|
+
let parsed;
|
|
175
|
+
try {
|
|
176
|
+
parsed = JSON.parse(value);
|
|
177
|
+
} catch {
|
|
178
|
+
return hasSecretJsonKey(value) ? "[REDACTED]" : value;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
let changed = false;
|
|
182
|
+
const masked = JSON.stringify(parsed, (name, nested) => {
|
|
183
|
+
if (isSecretLabel(name)) {
|
|
184
|
+
changed ||= nested !== "[REDACTED]";
|
|
185
|
+
return "[REDACTED]";
|
|
186
|
+
}
|
|
187
|
+
if (typeof nested === "string") {
|
|
188
|
+
const projected = maskJsonFragments(nested, encodingDepth + 1);
|
|
189
|
+
changed ||= projected !== nested;
|
|
190
|
+
return projected;
|
|
191
|
+
}
|
|
192
|
+
return nested;
|
|
193
|
+
});
|
|
194
|
+
return changed ? masked : value;
|
|
195
|
+
} catch {
|
|
196
|
+
return "[REDACTED]";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** Scan balanced object/array fragments once, respecting JSON quotes and escapes. */
|
|
200
|
+
function maskJsonFragments(value, encodingDepth = 0) {
|
|
201
|
+
if (value.trimStart().startsWith("\"")) try {
|
|
202
|
+
const decoded = JSON.parse(value);
|
|
203
|
+
if (typeof decoded === "string") {
|
|
204
|
+
if (encodingDepth >= JSON_ENCODING_MAX) return "\"[REDACTED]\"";
|
|
205
|
+
const masked = maskJsonFragments(decoded, encodingDepth + 1);
|
|
206
|
+
return masked === decoded ? value : JSON.stringify(masked);
|
|
207
|
+
}
|
|
208
|
+
} catch {}
|
|
209
|
+
let output = "";
|
|
210
|
+
let cursor = 0;
|
|
211
|
+
let start = -1;
|
|
212
|
+
let depth = 0;
|
|
213
|
+
let overDepth = false;
|
|
214
|
+
let quoted = false;
|
|
215
|
+
let escaped = false;
|
|
216
|
+
for (let index = 0; index < value.length; index++) {
|
|
217
|
+
const character = value[index];
|
|
218
|
+
if (start < 0) {
|
|
219
|
+
JSON_CONTAINER_START.lastIndex = index;
|
|
220
|
+
if (!JSON_CONTAINER_START.test(value)) continue;
|
|
221
|
+
start = index;
|
|
222
|
+
depth = 1;
|
|
223
|
+
overDepth = false;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (quoted) {
|
|
227
|
+
if (escaped) escaped = false;
|
|
228
|
+
else if (character === "\\") escaped = true;
|
|
229
|
+
else if (character === "\"") quoted = false;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (character === "\"") quoted = true;
|
|
233
|
+
else if (character === "{" || character === "[") {
|
|
234
|
+
depth++;
|
|
235
|
+
overDepth ||= depth > JSON_NESTING_MAX;
|
|
236
|
+
} else if (character === "}" || character === "]") {
|
|
237
|
+
depth--;
|
|
238
|
+
if (depth !== 0) continue;
|
|
239
|
+
output += value.slice(cursor, start) + projectJsonFragment(value.slice(start, index + 1), encodingDepth, overDepth);
|
|
240
|
+
cursor = index + 1;
|
|
241
|
+
start = -1;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (start >= 0) {
|
|
245
|
+
const fragment = value.slice(start);
|
|
246
|
+
output += value.slice(cursor, start) + (overDepth || hasSecretJsonKey(fragment) ? "[REDACTED]" : fragment);
|
|
247
|
+
cursor = value.length;
|
|
248
|
+
}
|
|
249
|
+
return output + value.slice(cursor);
|
|
250
|
+
}
|
|
251
|
+
function maskLabelledText(value) {
|
|
252
|
+
const jsonMasked = maskJsonFragments(value).replace(JSON_FIELD, (whole, quotedName, separator) => {
|
|
253
|
+
try {
|
|
254
|
+
return isSecretLabel(JSON.parse(quotedName)) ? `${quotedName}${separator}"[REDACTED]"` : whole;
|
|
255
|
+
} catch {
|
|
256
|
+
return whole;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
let output = "";
|
|
260
|
+
let cursor = 0;
|
|
261
|
+
for (const match of jsonMasked.matchAll(PROSE_FIELD)) {
|
|
262
|
+
const [, whole, label, entry] = match;
|
|
263
|
+
if (whole === void 0 || label === void 0 || entry === void 0 || match.index < cursor || /^Bearer[ \t]+/iu.test(entry)) continue;
|
|
264
|
+
const words = label.split(/[ \t]+/u);
|
|
265
|
+
for (let index = 0; index < words.length; index++) {
|
|
266
|
+
const name = words.slice(index).join(" ");
|
|
267
|
+
if (isSecretLabel(name)) {
|
|
268
|
+
const prefix = words.slice(0, index).join(" ");
|
|
269
|
+
output += jsonMasked.slice(cursor, match.index) + `${prefix ? `${prefix} ` : ""}${name}=[REDACTED]`;
|
|
270
|
+
cursor = match.index + whole.length;
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return output + jsonMasked.slice(cursor);
|
|
276
|
+
}
|
|
277
|
+
const TOKEN_MASKS = [
|
|
278
|
+
[/\bBearer\s+(?!(?:realm|error|error_description|scope|authorization_uri|resource|claims)\s*=)[^\s,;"']+/giu, "Bearer [REDACTED]"],
|
|
37
279
|
[/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]"],
|
|
38
280
|
[/(^|[^a-fA-F0-9])(?<!0[xX])[a-fA-F0-9]{64}(?=$|[^a-fA-F0-9])/gu, "$1[REDACTED]"],
|
|
39
|
-
[/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/giu, "[REDACTED]"]
|
|
40
|
-
[/(https?:\/\/[^\s"']+?\/v[0-9]\/)[A-Za-z0-9_-]{16,}/giu, "$1[REDACTED]"],
|
|
41
|
-
[/\b(api[ _-]?key|access[ _-]?token|token|secret|password|passphrase|private[ _-]?key|authorization|cookie|signature|request[ _-]?body|credential|otp|one[ _-]?time[ _-]?(?:password|code)|verification[ _-]?code)\b\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;&]+)/giu, "$1=[REDACTED]"]
|
|
281
|
+
[/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/giu, "[REDACTED]"]
|
|
42
282
|
];
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
283
|
+
/** URL components and malformed URLs use this non-recursive masking layer. */
|
|
284
|
+
function maskText(value) {
|
|
285
|
+
let text = maskLabelledText(value);
|
|
286
|
+
for (const [pattern, replacement] of TOKEN_MASKS) text = text.replace(pattern, replacement);
|
|
287
|
+
return text;
|
|
288
|
+
}
|
|
289
|
+
/** Reject only when the same semantic sanitizer removes credential material. */
|
|
48
290
|
function containsSensitiveMaterial(value) {
|
|
49
|
-
return
|
|
291
|
+
return redactSecrets(value) !== value;
|
|
50
292
|
}
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* lines, provider messages, PostHog rows) but must not carry live credentials.
|
|
55
|
-
*/
|
|
56
|
-
function redactSecrets(value) {
|
|
57
|
-
let text = value;
|
|
58
|
-
for (const [pattern, replacement] of MASKS) text = text.replace(pattern, replacement);
|
|
59
|
-
return text;
|
|
293
|
+
/** Mask credential fields and embedded URLs while preserving surrounding evidence. */
|
|
294
|
+
function redactSecrets(value, source) {
|
|
295
|
+
return maskLabelledText(value).split(EMBEDDED_URL).map((part, index) => index % 2 === 1 ? redactUrlSecrets(part, source).replaceAll("%5BREDACTED%5D", "[REDACTED]") : maskText(part)).join("");
|
|
60
296
|
}
|
|
61
297
|
//#endregion
|
|
62
298
|
//#region ../../packages/errors/src/chain-cause.ts
|
|
@@ -11568,7 +11804,7 @@ const moneyExecutionContract = {
|
|
|
11568
11804
|
};
|
|
11569
11805
|
//#endregion
|
|
11570
11806
|
//#region ../../packages/sdk/package.json
|
|
11571
|
-
var version$1 = "4.
|
|
11807
|
+
var version$1 = "4.2.0";
|
|
11572
11808
|
//#endregion
|
|
11573
11809
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
11574
11810
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -11747,8 +11983,6 @@ function evidenceText(value) {
|
|
|
11747
11983
|
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
11748
11984
|
return redactSecrets(value).slice(0, MAX_EVIDENCE_TEXT);
|
|
11749
11985
|
}
|
|
11750
|
-
/** A field whose NAME says credential is masked whatever its value looks like. */
|
|
11751
|
-
const CREDENTIAL_FIELD_NAME = /(?:otp|pass(?:word|wd|phrase)?|token|secret|credential|api[_-]?key|private[_-]?key|authorization|cookie|session)/iu;
|
|
11752
11986
|
/** Copy a details object into a JSON-safe shape with every string masked. */
|
|
11753
11987
|
function evidenceValue(value, depth = 0) {
|
|
11754
11988
|
if (typeof value === "string") return evidenceText(value);
|
|
@@ -11759,7 +11993,7 @@ function evidenceValue(value, depth = 0) {
|
|
|
11759
11993
|
if (Array.isArray(value)) return value.slice(0, 50).map((item) => evidenceValue(item, depth + 1));
|
|
11760
11994
|
const copy = {};
|
|
11761
11995
|
for (const [key, nested] of Object.entries(value)) {
|
|
11762
|
-
if (
|
|
11996
|
+
if (isCredentialField(key)) {
|
|
11763
11997
|
copy[key] = "[REDACTED]";
|
|
11764
11998
|
continue;
|
|
11765
11999
|
}
|
|
@@ -13526,21 +13760,8 @@ const ENGINEERING_CAPXUL_ENVS = [
|
|
|
13526
13760
|
"production",
|
|
13527
13761
|
"local"
|
|
13528
13762
|
];
|
|
13529
|
-
const
|
|
13530
|
-
|
|
13531
|
-
"content-type",
|
|
13532
|
-
"traceparent",
|
|
13533
|
-
"tracestate",
|
|
13534
|
-
"x-request-id"
|
|
13535
|
-
];
|
|
13536
|
-
const ENGINEERING_REDACTED_HEADER_NAMES = Object.freeze([
|
|
13537
|
-
"authorization",
|
|
13538
|
-
"cookie",
|
|
13539
|
-
"set-cookie",
|
|
13540
|
-
"x-api-key",
|
|
13541
|
-
/auth|email|key|otp|secret|session|token|wallet/i
|
|
13542
|
-
]);
|
|
13543
|
-
const traceHeaderFilter = (name) => SAFE_TRACED_HEADER_NAMES.includes(name.toLowerCase());
|
|
13763
|
+
const traceHeaderFilter = (_name) => true;
|
|
13764
|
+
const credentialHeaderPattern = Object.assign(/./u, { test: (name) => isCredentialField(name, "header") });
|
|
13544
13765
|
const postHogOtlpEndpoints = (host) => {
|
|
13545
13766
|
const base = host.replace(/\/+$/, "");
|
|
13546
13767
|
return {
|
|
@@ -13572,23 +13793,79 @@ const validateEngineeringTelemetryConfig = (config) => {
|
|
|
13572
13793
|
headers: Object.freeze({ authorization: headerEntries[0][1] })
|
|
13573
13794
|
};
|
|
13574
13795
|
};
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13796
|
+
const failureText = (failure, key, limit, source) => {
|
|
13797
|
+
if (failure === null || typeof failure !== "object") return void 0;
|
|
13798
|
+
try {
|
|
13799
|
+
let owner = failure;
|
|
13800
|
+
let descriptor;
|
|
13801
|
+
for (let depth = 0; owner !== null && depth < 4; depth += 1) {
|
|
13802
|
+
descriptor = Object.getOwnPropertyDescriptor(owner, key);
|
|
13803
|
+
if (descriptor !== void 0 || key !== "name") break;
|
|
13804
|
+
owner = Object.getPrototypeOf(owner);
|
|
13805
|
+
}
|
|
13806
|
+
const value = descriptor?.value;
|
|
13807
|
+
return typeof value === "string" || key === "code" && typeof value === "number" ? redactSecrets(String(value), source).slice(0, limit) : void 0;
|
|
13808
|
+
} catch {
|
|
13809
|
+
return;
|
|
13810
|
+
}
|
|
13811
|
+
};
|
|
13812
|
+
const exportFailure = (failure, source) => {
|
|
13813
|
+
const message = failureText(failure, "message", 2048, source) ?? (typeof failure === "string" ? redactSecrets(failure, source).slice(0, 2048) : "Engineering operation failed");
|
|
13814
|
+
const code = failureText(failure, "code", 128);
|
|
13815
|
+
const error = new Error((code === void 0 ? message : `${message} [code=${code}]`).slice(0, 2048));
|
|
13816
|
+
error.name = failureText(failure, "_tag", 128) ?? failureText(failure, "name", 128) ?? "Error";
|
|
13817
|
+
error.stack = failureText(failure, "stack", 8192, source) ?? `${error.name}: ${error.message}`;
|
|
13818
|
+
return error;
|
|
13819
|
+
};
|
|
13820
|
+
const exportFailureExit = (cause, source) => Exit.failCause(Cause.fromReasons(cause.reasons.filter((reason) => !Cause.isInterruptReason(reason)).slice(0, 8).map((reason) => Cause.isFailReason(reason) ? Cause.makeFailReason(exportFailure(reason.error, source)) : Cause.makeDieReason(exportFailure(reason.defect, source)))));
|
|
13821
|
+
const BROWSER_KEEPALIVE_BYTES = 65536;
|
|
13822
|
+
let unfinishedBrowserExportBytes = 0;
|
|
13823
|
+
const hasBrowserDocument = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
13824
|
+
const browserExportClient = (client) => HttpClient.transform(client, (response, request) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
13825
|
+
const bytes = "contentLength" in request.body ? request.body.contentLength : void 0;
|
|
13826
|
+
if (request.body._tag === "Stream" || request.body._tag === "FormData" || bytes === void 0 || !Number.isSafeInteger(bytes) || bytes < 0 || unfinishedBrowserExportBytes + bytes > BROWSER_KEEPALIVE_BYTES) return;
|
|
13827
|
+
unfinishedBrowserExportBytes += bytes;
|
|
13828
|
+
return bytes;
|
|
13829
|
+
}), (bytes) => response.pipe(Effect.provideService(FetchHttpClient.RequestInit, { keepalive: bytes !== void 0 }), Effect.tap((result) => bytes === void 0 ? Effect.void : Stream.runDrain(result.stream).pipe(Effect.catch((error) => error.reason._tag === "EmptyBodyError" ? Effect.void : Effect.fail(error))))), (bytes) => Effect.sync(() => {
|
|
13830
|
+
if (bytes !== void 0) unfinishedBrowserExportBytes -= bytes;
|
|
13831
|
+
})));
|
|
13832
|
+
const spanUpstream = (span) => {
|
|
13833
|
+
let current = span;
|
|
13834
|
+
while (current?._tag === "Span") {
|
|
13835
|
+
const upstream = current.attributes.get("chain.upstream");
|
|
13836
|
+
if (upstream === "alchemy" || upstream === "infura") return upstream;
|
|
13837
|
+
current = current.parent._tag === "Some" ? current.parent.value : void 0;
|
|
13580
13838
|
}
|
|
13581
13839
|
};
|
|
13582
|
-
const REDACTED_SPAN_FAILURE = Exit.fail(new RedactedEngineeringSpanFailure());
|
|
13583
13840
|
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
13584
13841
|
const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
|
|
13585
13842
|
span(options) {
|
|
13586
13843
|
const span = delegate.span(options);
|
|
13587
13844
|
const wrapped = Object.create(span);
|
|
13845
|
+
Object.defineProperty(wrapped, "attribute", { value: (name, value) => {
|
|
13846
|
+
const source = spanUpstream(span);
|
|
13847
|
+
const header = /^http\.(?:request|response)\.header\.(.+)$/u.exec(name)?.[1];
|
|
13848
|
+
if (header !== void 0 && isCredentialField(header, "header")) span.attribute(name, "[REDACTED]");
|
|
13849
|
+
else if (typeof value === "string" && name === "url.query") span.attribute(name, redactUrlSecrets(`?${value}`).slice(1, 2049));
|
|
13850
|
+
else if (typeof value === "string" && name === "url.path") {
|
|
13851
|
+
const fullUrl = span.attributes.get("url.full");
|
|
13852
|
+
const path = typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
|
|
13853
|
+
span.attribute(name, redactUrlSecrets(path, source).slice(0, 2048));
|
|
13854
|
+
} else if (typeof value === "string" && (name === "url.full" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
|
|
13855
|
+
else if (header !== void 0 && typeof value === "string") span.attribute(name, redactSecrets(value, source).slice(0, 2048));
|
|
13856
|
+
else span.attribute(name, value);
|
|
13857
|
+
} });
|
|
13588
13858
|
Object.defineProperty(wrapped, "end", {
|
|
13589
13859
|
configurable: false,
|
|
13590
13860
|
enumerable: false,
|
|
13591
|
-
value: (endTime, exit) =>
|
|
13861
|
+
value: (endTime, exit) => {
|
|
13862
|
+
if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) {
|
|
13863
|
+
const first = exit.cause.reasons.find((reason) => !Cause.isInterruptReason(reason));
|
|
13864
|
+
const code = failureText(first === void 0 ? void 0 : Cause.isFailReason(first) ? first.error : first.defect, "code", 128);
|
|
13865
|
+
if (code !== void 0) span.attribute("error.code", code);
|
|
13866
|
+
span.end(endTime, exportFailureExit(exit.cause, spanUpstream(span)));
|
|
13867
|
+
} else span.end(endTime, exit);
|
|
13868
|
+
},
|
|
13592
13869
|
writable: false
|
|
13593
13870
|
});
|
|
13594
13871
|
return wrapped;
|
|
@@ -13619,8 +13896,29 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
13619
13896
|
resource,
|
|
13620
13897
|
mergeWithExisting: true
|
|
13621
13898
|
});
|
|
13622
|
-
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames,
|
|
13623
|
-
|
|
13899
|
+
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, [credentialHeaderPattern]));
|
|
13900
|
+
const browserLifecycle = Layer.effectDiscard(Effect.gen(function* () {
|
|
13901
|
+
if (validated.producer !== "browser" || !hasBrowserDocument()) return;
|
|
13902
|
+
const browserWindow = window;
|
|
13903
|
+
const browserDocument = document;
|
|
13904
|
+
const flusher = yield* OtlpExporter.Flusher;
|
|
13905
|
+
const run = yield* FiberSet.makeRuntime();
|
|
13906
|
+
const flush = () => {
|
|
13907
|
+
run(flusher.flush);
|
|
13908
|
+
};
|
|
13909
|
+
const visibilityChanged = () => {
|
|
13910
|
+
if (browserDocument.visibilityState === "hidden") flush();
|
|
13911
|
+
};
|
|
13912
|
+
yield* Effect.acquireRelease(Effect.sync(() => {
|
|
13913
|
+
browserDocument.addEventListener("visibilitychange", visibilityChanged);
|
|
13914
|
+
browserWindow.addEventListener("pagehide", flush);
|
|
13915
|
+
}), () => Effect.sync(() => {
|
|
13916
|
+
browserDocument.removeEventListener("visibilitychange", visibilityChanged);
|
|
13917
|
+
browserWindow.removeEventListener("pagehide", flush);
|
|
13918
|
+
}));
|
|
13919
|
+
}));
|
|
13920
|
+
const transport = Layer.effect(HttpClient.HttpClient, Effect.map(HttpClient.HttpClient, (client) => validated.producer === "browser" && hasBrowserDocument() ? browserExportClient(client) : client)).pipe(Layer.provide(FetchHttpClient.layer));
|
|
13921
|
+
return browserLifecycle.pipe(Layer.provideMerge(Layer.mergeAll(tracing, logging, headerPolicy)), Layer.provide(OtlpSerialization.layerJson), Layer.provide(transport));
|
|
13624
13922
|
};
|
|
13625
13923
|
//#endregion
|
|
13626
13924
|
//#region ../../packages/sdk/src/ports/auth-client.ts
|
|
@@ -17949,6 +18247,12 @@ function isTransportError(err) {
|
|
|
17949
18247
|
}
|
|
17950
18248
|
//#endregion
|
|
17951
18249
|
//#region ../../packages/sdk/src/ports/identity.ts
|
|
18250
|
+
/** The chain families a payout address may name (#1955). */
|
|
18251
|
+
const PAYOUT_CHAINS = [
|
|
18252
|
+
"evm",
|
|
18253
|
+
"solana",
|
|
18254
|
+
"starknet"
|
|
18255
|
+
];
|
|
17952
18256
|
var IdentityError = class extends Data.TaggedError("IdentityError") {};
|
|
17953
18257
|
function identityErrorFromCapxul(operation, error, cause = error) {
|
|
17954
18258
|
return new IdentityError({
|
|
@@ -19965,7 +20269,7 @@ AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED = "ERR_FORM_DATA_DEPTH_EXCEEDED";
|
|
|
19965
20269
|
//#endregion
|
|
19966
20270
|
//#region ../../node_modules/.pnpm/delayed-stream@1.0.0/node_modules/delayed-stream/lib/delayed_stream.js
|
|
19967
20271
|
var require_delayed_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
19968
|
-
var Stream$
|
|
20272
|
+
var Stream$3 = __require("stream").Stream;
|
|
19969
20273
|
var util$4 = __require("util");
|
|
19970
20274
|
module.exports = DelayedStream;
|
|
19971
20275
|
function DelayedStream() {
|
|
@@ -19977,7 +20281,7 @@ var require_delayed_stream = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
19977
20281
|
this._released = false;
|
|
19978
20282
|
this._bufferedEvents = [];
|
|
19979
20283
|
}
|
|
19980
|
-
util$4.inherits(DelayedStream, Stream$
|
|
20284
|
+
util$4.inherits(DelayedStream, Stream$3);
|
|
19981
20285
|
DelayedStream.create = function(source, options) {
|
|
19982
20286
|
var delayedStream = new this();
|
|
19983
20287
|
options = options || {};
|
|
@@ -20017,7 +20321,7 @@ var require_delayed_stream = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
20017
20321
|
this._bufferedEvents = [];
|
|
20018
20322
|
};
|
|
20019
20323
|
DelayedStream.prototype.pipe = function() {
|
|
20020
|
-
var r = Stream$
|
|
20324
|
+
var r = Stream$3.prototype.pipe.apply(this, arguments);
|
|
20021
20325
|
this.resume();
|
|
20022
20326
|
return r;
|
|
20023
20327
|
};
|
|
@@ -20044,7 +20348,7 @@ var require_delayed_stream = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
20044
20348
|
//#region ../../node_modules/.pnpm/combined-stream@1.0.8/node_modules/combined-stream/lib/combined_stream.js
|
|
20045
20349
|
var require_combined_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
20046
20350
|
var util$3 = __require("util");
|
|
20047
|
-
var Stream$
|
|
20351
|
+
var Stream$2 = __require("stream").Stream;
|
|
20048
20352
|
var DelayedStream = require_delayed_stream();
|
|
20049
20353
|
module.exports = CombinedStream;
|
|
20050
20354
|
function CombinedStream() {
|
|
@@ -20059,7 +20363,7 @@ var require_combined_stream = /* @__PURE__ */ __commonJSMin(((exports, module) =
|
|
|
20059
20363
|
this._insideLoop = false;
|
|
20060
20364
|
this._pendingNext = false;
|
|
20061
20365
|
}
|
|
20062
|
-
util$3.inherits(CombinedStream, Stream$
|
|
20366
|
+
util$3.inherits(CombinedStream, Stream$2);
|
|
20063
20367
|
CombinedStream.create = function(options) {
|
|
20064
20368
|
var combinedStream = new this();
|
|
20065
20369
|
options = options || {};
|
|
@@ -20086,7 +20390,7 @@ var require_combined_stream = /* @__PURE__ */ __commonJSMin(((exports, module) =
|
|
|
20086
20390
|
return this;
|
|
20087
20391
|
};
|
|
20088
20392
|
CombinedStream.prototype.pipe = function(dest, options) {
|
|
20089
|
-
Stream$
|
|
20393
|
+
Stream$2.prototype.pipe.call(this, dest, options);
|
|
20090
20394
|
this.resume();
|
|
20091
20395
|
return dest;
|
|
20092
20396
|
};
|
|
@@ -28334,7 +28638,7 @@ var FormData_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin((
|
|
|
28334
28638
|
var https$2 = __require("https");
|
|
28335
28639
|
var parseUrl$1 = __require("url").parse;
|
|
28336
28640
|
var fs = __require("fs");
|
|
28337
|
-
var Stream = __require("stream").Stream;
|
|
28641
|
+
var Stream$1 = __require("stream").Stream;
|
|
28338
28642
|
var crypto$2 = __require("crypto");
|
|
28339
28643
|
var mime = require_mime_types();
|
|
28340
28644
|
var asynckit = require_asynckit();
|
|
@@ -28384,7 +28688,7 @@ var FormData_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin((
|
|
|
28384
28688
|
else if (typeof value === "string") valueLength = Buffer.byteLength(value);
|
|
28385
28689
|
this._valueLength += valueLength;
|
|
28386
28690
|
this._overheadLength += Buffer.byteLength(header) + FormData.LINE_BREAK.length;
|
|
28387
|
-
if (!value || !value.path && !(value.readable && hasOwn(value, "httpVersion")) && !(value instanceof Stream)) return;
|
|
28691
|
+
if (!value || !value.path && !(value.readable && hasOwn(value, "httpVersion")) && !(value instanceof Stream$1)) return;
|
|
28388
28692
|
if (!options.knownLength) this._valuesToMeasure.push(value);
|
|
28389
28693
|
};
|
|
28390
28694
|
FormData.prototype._lengthRetriever = function(value, callback) {
|
|
@@ -43067,8 +43371,52 @@ const loadIdentityProgram = Effect.gen(function* () {
|
|
|
43067
43371
|
if (authUserId === void 0) return null;
|
|
43068
43372
|
return yield* deps.identityPort.loadByAuthUserId(authUserId).pipe(Effect.catchDefect((cause) => Effect.fail(identityErrorFromCapxul("loadByAuthUserId", cause instanceof CapxulError ? cause : Errors.unknown(cause), cause))), Effect.mapError((failure) => failure.publicError));
|
|
43069
43373
|
});
|
|
43070
|
-
|
|
43071
|
-
|
|
43374
|
+
/**
|
|
43375
|
+
* THE ONE boundary grammar for those optional fields. Both `completeProfile`
|
|
43376
|
+
* entry points — the method bundle here and the identity runtime in
|
|
43377
|
+
* `create-capxul-client.ts` — run it, so a malformed value is refused the same
|
|
43378
|
+
* way at each and never reaches the port.
|
|
43379
|
+
*/
|
|
43380
|
+
function checkProfileCarriage(profile) {
|
|
43381
|
+
const carriage = {};
|
|
43382
|
+
if (profile.imageStorageId !== void 0) {
|
|
43383
|
+
if (typeof profile.imageStorageId !== "string" || profile.imageStorageId.trim().length === 0) return {
|
|
43384
|
+
ok: false,
|
|
43385
|
+
field: "imageStorageId",
|
|
43386
|
+
message: "must be a non-empty storage id"
|
|
43387
|
+
};
|
|
43388
|
+
carriage.imageStorageId = profile.imageStorageId.trim();
|
|
43389
|
+
}
|
|
43390
|
+
if (profile.payoutAddresses !== void 0) {
|
|
43391
|
+
if (!Array.isArray(profile.payoutAddresses)) return {
|
|
43392
|
+
ok: false,
|
|
43393
|
+
field: "payoutAddresses",
|
|
43394
|
+
message: "must be an array"
|
|
43395
|
+
};
|
|
43396
|
+
if (profile.payoutAddresses.length > 10) return {
|
|
43397
|
+
ok: false,
|
|
43398
|
+
field: "payoutAddresses",
|
|
43399
|
+
message: `must carry at most 10 addresses`
|
|
43400
|
+
};
|
|
43401
|
+
const entries = [];
|
|
43402
|
+
for (const entry of profile.payoutAddresses) {
|
|
43403
|
+
if (typeof entry !== "object" || entry === null || !PAYOUT_CHAINS.some((chain) => chain === entry.chain) || typeof entry.address !== "string" || entry.address.trim().length === 0) return {
|
|
43404
|
+
ok: false,
|
|
43405
|
+
field: "payoutAddresses",
|
|
43406
|
+
message: `each entry needs a chain of ${PAYOUT_CHAINS.join(", ")} and an address`
|
|
43407
|
+
};
|
|
43408
|
+
entries.push({
|
|
43409
|
+
chain: entry.chain,
|
|
43410
|
+
address: entry.address.trim()
|
|
43411
|
+
});
|
|
43412
|
+
}
|
|
43413
|
+
carriage.payoutAddresses = entries;
|
|
43414
|
+
}
|
|
43415
|
+
return {
|
|
43416
|
+
ok: true,
|
|
43417
|
+
carriage
|
|
43418
|
+
};
|
|
43419
|
+
}
|
|
43072
43420
|
function makeIdentityMethods(deps) {
|
|
43073
43421
|
const convexCall = deps.convexCall;
|
|
43074
43422
|
return {
|
|
@@ -43107,6 +43455,11 @@ function makeIdentityMethods(deps) {
|
|
|
43107
43455
|
error: Errors.invalidInput("country", "unsupported country")
|
|
43108
43456
|
};
|
|
43109
43457
|
}
|
|
43458
|
+
const carried = checkProfileCarriage(profile);
|
|
43459
|
+
if (!carried.ok) return {
|
|
43460
|
+
ok: false,
|
|
43461
|
+
error: Errors.invalidInput(carried.field, carried.message)
|
|
43462
|
+
};
|
|
43110
43463
|
const session = deps.actor?.authSession();
|
|
43111
43464
|
if (session === void 0 || session === null) return {
|
|
43112
43465
|
ok: false,
|
|
@@ -43117,7 +43470,8 @@ function makeIdentityMethods(deps) {
|
|
|
43117
43470
|
email: session.email,
|
|
43118
43471
|
displayName,
|
|
43119
43472
|
country,
|
|
43120
|
-
handle
|
|
43473
|
+
handle,
|
|
43474
|
+
...carried.carriage
|
|
43121
43475
|
}), options, CAPXUL_OPERATIONS.identity.completeProfile);
|
|
43122
43476
|
},
|
|
43123
43477
|
async handleAvailable(handle, options) {
|
|
@@ -45211,6 +45565,11 @@ function assembleCapxulClient(input) {
|
|
|
45211
45565
|
ok: false,
|
|
45212
45566
|
reason: "INVALID_INPUT"
|
|
45213
45567
|
};
|
|
45568
|
+
const carried = checkProfileCarriage(profile);
|
|
45569
|
+
if (!carried.ok) return {
|
|
45570
|
+
ok: false,
|
|
45571
|
+
reason: "INVALID_INPUT"
|
|
45572
|
+
};
|
|
45214
45573
|
const session = actor.authSession();
|
|
45215
45574
|
if (session === null) return {
|
|
45216
45575
|
ok: false,
|
|
@@ -45221,7 +45580,8 @@ function assembleCapxulClient(input) {
|
|
|
45221
45580
|
email: session.email,
|
|
45222
45581
|
displayName,
|
|
45223
45582
|
country,
|
|
45224
|
-
handle
|
|
45583
|
+
handle,
|
|
45584
|
+
...carried.carriage
|
|
45225
45585
|
}), controls, CAPXUL_OPERATIONS.identity.completeProfile, effectRunner.runPromise);
|
|
45226
45586
|
return result.ok ? { ok: true } : {
|
|
45227
45587
|
ok: false,
|
|
@@ -46715,7 +47075,7 @@ function stdioIdentity(env = process.env, options = {}) {
|
|
|
46715
47075
|
}
|
|
46716
47076
|
//#endregion
|
|
46717
47077
|
//#region package.json
|
|
46718
|
-
var version = "4.
|
|
47078
|
+
var version = "4.2.0";
|
|
46719
47079
|
//#endregion
|
|
46720
47080
|
//#region src/deps.ts
|
|
46721
47081
|
const NO_IDENTITY = async () => void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Capxul MCP server for auth, Account readiness, identity, Organizations, relationships, requests, destinations, and testnet funding over Streamable HTTP.",
|
|
6
6
|
"keywords": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
|
|
52
52
|
"vite-plus": "0.3.0",
|
|
53
53
|
"@capxul/config": "0.3.0",
|
|
54
|
-
"@capxul/sdk": "4.
|
|
54
|
+
"@capxul/sdk": "4.2.0",
|
|
55
55
|
"@capxul/typescript-config": "0.0.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|