ftown 0.20.6 → 0.20.8

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.
Files changed (84) hide show
  1. package/dist/attention-prompt-protocol.d.ts +2 -2
  2. package/dist/attention-prompt-protocol.js +1 -1
  3. package/dist/centrifugo-client.js +0 -1
  4. package/dist/centrifugo-client.js.map +1 -1
  5. package/dist/command-rpc.d.ts +0 -1
  6. package/dist/command-rpc.js +3 -24
  7. package/dist/command-rpc.js.map +1 -1
  8. package/dist/index.js +4 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/rotating-token-refresher.d.ts +17 -0
  11. package/dist/rotating-token-refresher.js +39 -0
  12. package/dist/rotating-token-refresher.js.map +1 -1
  13. package/dist/security/account-crypto.d.ts +1 -1
  14. package/dist/security/account-crypto.js +1 -1
  15. package/dist/security/account-crypto.js.map +1 -1
  16. package/dist/security/account-protocol.d.ts +1 -1
  17. package/dist/security/bridge/account-state.d.ts +0 -4
  18. package/dist/security/bridge/direct.js +0 -2
  19. package/dist/security/bridge/direct.js.map +1 -1
  20. package/dist/security/bridge/execute.js +1 -6
  21. package/dist/security/bridge/execute.js.map +1 -1
  22. package/dist/security/bridge/identity.d.ts +0 -3
  23. package/dist/security/bridge/metadata.d.ts +0 -2
  24. package/dist/security/bridge/metadata.js +1 -1
  25. package/dist/security/bridge/metadata.js.map +1 -1
  26. package/dist/security/bridge/permissions.js +3 -11
  27. package/dist/security/bridge/permissions.js.map +1 -1
  28. package/dist/security/bridge/policy.d.ts +4 -7
  29. package/dist/security/bridge/policy.js +35 -90
  30. package/dist/security/bridge/policy.js.map +1 -1
  31. package/dist/security/bridge/security.d.ts +9 -14
  32. package/dist/security/bridge/security.js +27 -86
  33. package/dist/security/bridge/security.js.map +1 -1
  34. package/dist/security/crypto.js +2 -2
  35. package/dist/security/crypto.js.map +1 -1
  36. package/dist/security/protocol.d.ts +5 -126
  37. package/dist/types.d.ts +1 -1
  38. package/dist/update-effects.js +1 -1
  39. package/dist/update-effects.js.map +1 -1
  40. package/package.json +4 -12
  41. package/skills/ftown/SKILL.md +9 -13
  42. package/skills/ftown/references/sessions.md +4 -20
  43. package/dist/mcp/fleet.d.ts +0 -67
  44. package/dist/mcp/fleet.js +0 -298
  45. package/dist/mcp/fleet.js.map +0 -1
  46. package/dist/mcp/http.d.ts +0 -42
  47. package/dist/mcp/http.js +0 -350
  48. package/dist/mcp/http.js.map +0 -1
  49. package/dist/mcp/legacy-relay.d.ts +0 -3
  50. package/dist/mcp/legacy-relay.js +0 -6
  51. package/dist/mcp/legacy-relay.js.map +0 -1
  52. package/dist/mcp/mcp-key-store.d.ts +0 -52
  53. package/dist/mcp/mcp-key-store.js +0 -207
  54. package/dist/mcp/mcp-key-store.js.map +0 -1
  55. package/dist/mcp/oauth-store.d.ts +0 -17
  56. package/dist/mcp/oauth-store.js +0 -58
  57. package/dist/mcp/oauth-store.js.map +0 -1
  58. package/dist/mcp/oauth.d.ts +0 -83
  59. package/dist/mcp/oauth.js +0 -311
  60. package/dist/mcp/oauth.js.map +0 -1
  61. package/dist/mcp/relay-handler.d.ts +0 -2
  62. package/dist/mcp/relay-handler.js +0 -8
  63. package/dist/mcp/relay-handler.js.map +0 -1
  64. package/dist/mcp/relay.d.ts +0 -13
  65. package/dist/mcp/relay.js +0 -95
  66. package/dist/mcp/relay.js.map +0 -1
  67. package/dist/mcp/secure-client.d.ts +0 -23
  68. package/dist/mcp/secure-client.js +0 -124
  69. package/dist/mcp/secure-client.js.map +0 -1
  70. package/dist/mcp/security-events.d.ts +0 -49
  71. package/dist/mcp/security-events.js +0 -211
  72. package/dist/mcp/security-events.js.map +0 -1
  73. package/dist/mcp/server.d.ts +0 -13
  74. package/dist/mcp/server.js +0 -858
  75. package/dist/mcp/server.js.map +0 -1
  76. package/dist/mcp/test-support.d.ts +0 -32
  77. package/dist/mcp/test-support.js +0 -120
  78. package/dist/mcp/test-support.js.map +0 -1
  79. package/dist/mcp-cli.d.ts +0 -2
  80. package/dist/mcp-cli.js +0 -105
  81. package/dist/mcp-cli.js.map +0 -1
  82. package/dist/security/bridge/audit.d.ts +0 -37
  83. package/dist/security/bridge/audit.js +0 -186
  84. package/dist/security/bridge/audit.js.map +0 -1
package/dist/mcp/oauth.js DELETED
@@ -1,311 +0,0 @@
1
- import { legacyDateTimeSchema } from '../zod-compat.js';
2
- import { createHash, randomBytes } from "node:crypto";
3
- import jwt from "jsonwebtoken";
4
- import { InvalidGrantError, InvalidTokenError, InvalidRequestError, InvalidScopeError, } from "@modelcontextprotocol/sdk/server/auth/errors.js";
5
- import { z } from 'zod';
6
- import { open, parseSecureEnvelope } from '../security/crypto.js';
7
- const secretToken = () => randomBytes(32).toString("base64url");
8
- const hash = (s) => createHash("sha256").update(s).digest("hex");
9
- const now = () => Math.floor(Date.now() / 1000);
10
- export const MCP_SCOPES = ["mcp:read", "mcp:control"];
11
- export class FtownOAuthProvider {
12
- store;
13
- options;
14
- keys;
15
- resource;
16
- constructor(store, options, keys) {
17
- this.store = store;
18
- this.options = options;
19
- this.keys = keys;
20
- this.resource = new URL("/mcp", options.publicUrl).href;
21
- }
22
- currentMachines(subject) {
23
- return (this.options.access.find((a) => a.subject === subject)?.machines ?? []);
24
- }
25
- clientsStore = {
26
- getClient: (id) => this.store.transaction((tx) => tx.get("client", id)),
27
- registerClient: async (input) => {
28
- // Public clients only: PKCE is mandatory; never persist an unneeded client secret.
29
- if (input.token_endpoint_auth_method &&
30
- input.token_endpoint_auth_method !== "none")
31
- throw new InvalidRequestError("Only public PKCE clients are supported");
32
- if (input.redirect_uris.length > 10 ||
33
- input.redirect_uris.some((uri) => {
34
- const u = new URL(uri);
35
- return (!!(u.hash || u.username || u.password) ||
36
- !(u.protocol === "https:" ||
37
- (u.protocol === "http:" &&
38
- ["127.0.0.1", "[::1]", "localhost"].includes(u.hostname))));
39
- }))
40
- throw new InvalidRequestError("Redirect URIs require HTTPS or loopback HTTP");
41
- const client = {
42
- client_id: secretToken(),
43
- client_id_issued_at: now(),
44
- client_name: input.client_name?.slice(0, 200),
45
- redirect_uris: input.redirect_uris,
46
- token_endpoint_auth_method: "none",
47
- grant_types: ["authorization_code", "refresh_token"],
48
- response_types: ["code"],
49
- };
50
- await this.store.transaction((tx) => tx.put("client", client.client_id, client, now() + 365 * 86400));
51
- return client;
52
- },
53
- };
54
- async authorize(client, params, res) {
55
- if (params.resource?.href !== this.resource)
56
- throw new InvalidRequestError("resource must identify this MCP endpoint");
57
- if (!/^[A-Za-z0-9_-]{43}$/.test(params.codeChallenge))
58
- throw new InvalidRequestError("S256 PKCE challenge required");
59
- const scopes = params.scopes?.length
60
- ? [...new Set(params.scopes)]
61
- : ["mcp:read"];
62
- if (!scopes.includes("mcp:read") ||
63
- scopes.some((s) => !MCP_SCOPES.includes(s)))
64
- throw new InvalidScopeError("Supported scopes: mcp:read and mcp:control");
65
- const id = secretToken();
66
- const pending = {
67
- clientId: client.client_id,
68
- clientName: client.client_name ?? client.client_id,
69
- redirectUri: params.redirectUri,
70
- challenge: params.codeChallenge,
71
- state: params.state,
72
- scopes,
73
- resource: this.resource,
74
- expiresAt: now() + 600,
75
- };
76
- await this.store.transaction((tx) => tx.put("pending", id, pending, now() + 600));
77
- const consent = new URL("/mcp/consent", this.options.loginUrl);
78
- consent.searchParams.set("request", id);
79
- res.redirect(consent.href);
80
- }
81
- assertion(token, purpose) {
82
- const value = jwt.verify(token, this.options.approvalSecret, {
83
- algorithms: ["HS256"],
84
- audience: this.options.publicUrl,
85
- issuer: this.options.loginUrl,
86
- maxAge: "60s",
87
- });
88
- if (typeof value === "string" ||
89
- typeof value.sub !== "string" ||
90
- typeof value.request !== "string" ||
91
- value.purpose !== purpose)
92
- throw new InvalidRequestError("Invalid approval assertion");
93
- return value;
94
- }
95
- async consentDetails(assertion) {
96
- const claims = this.assertion(assertion, "inspect");
97
- const { pending, owned } = await this.store.transaction(async (tx) => ({
98
- pending: await tx.get("pending", claims.request),
99
- owned: await tx.ownedMachines(claims.sub),
100
- }));
101
- if (!pending || pending.resource !== this.resource || !pending.expiresAt || (pending.subject && pending.subject !== claims.sub))
102
- throw new InvalidRequestError("Authorization request expired");
103
- if (!this.keys)
104
- throw new InvalidRequestError('Encrypted MCP identities must be configured');
105
- const security = await this.keys.ensurePendingIdentity(claims.request, claims.sub, pending.scopes.includes('mcp:control') ? ['read', 'control'] : ['read']);
106
- await this.store.transaction(async (tx) => {
107
- const current = await tx.get('pending', claims.request);
108
- if (!current || (current.subject && current.subject !== claims.sub))
109
- throw new InvalidRequestError('Authorization request expired');
110
- await tx.put('pending', claims.request, { ...current, subject: claims.sub, grantId: security.grantId }, current.expiresAt);
111
- });
112
- return {
113
- clientName: pending.clientName,
114
- redirectUri: pending.redirectUri,
115
- scopes: pending.scopes,
116
- machines: this.currentMachines(claims.sub).filter((m) => owned.includes(m)),
117
- security,
118
- };
119
- }
120
- async approve(assertion, deny = false) {
121
- const claims = this.assertion(assertion, deny ? "deny" : "approve");
122
- // Never hold an OAuth pool connection while the key store acquires another.
123
- const { pending, owned } = await this.store.transaction(async (tx) => ({
124
- pending: await tx.get('pending', claims.request),
125
- owned: deny ? [] : await tx.ownedMachines(claims.sub),
126
- }));
127
- if (!pending || pending.resource !== this.resource)
128
- throw new InvalidRequestError('Authorization request expired or already handled');
129
- const redirect = new URL(pending.redirectUri);
130
- if (pending.state !== undefined)
131
- redirect.searchParams.set('state', pending.state);
132
- redirect.searchParams.set('iss', this.options.publicUrl);
133
- if (deny) {
134
- await this.store.transaction(async (tx) => {
135
- if (!await tx.take('pending', claims.request))
136
- throw new InvalidRequestError('Authorization request expired or already handled');
137
- });
138
- redirect.searchParams.set('error', 'access_denied');
139
- return redirect.href;
140
- }
141
- if (!this.keys || pending.subject !== claims.sub || !pending.grantId)
142
- throw new InvalidRequestError('Inspect and approve the encrypted endpoint before continuing');
143
- const machines = claims.machines;
144
- const allowed = this.currentMachines(claims.sub).filter(machine => owned.includes(machine));
145
- if (!Array.isArray(machines) || !machines.length || machines.some(machine => typeof machine !== 'string' || !allowed.includes(machine)))
146
- throw new InvalidRequestError('No authorized machines selected');
147
- const selected = [...new Set(machines)];
148
- if (selected.length > 64)
149
- throw new InvalidRequestError('Select at most 64 computers');
150
- const identity = await this.keys.loadByRequest(claims.sub, claims.request);
151
- if (identity.grantId !== pending.grantId || identity.state !== 'pending' || Date.parse(identity.pendingExpiresAt) <= Date.now())
152
- throw new InvalidRequestError('Encrypted endpoint approval expired');
153
- const pins = await this.approvalPins(claims.approvals, selected, identity);
154
- // The row-locked transition permits one winner. If code persistence fails,
155
- // the orphan approval has no usable OAuth token and fresh consent is required.
156
- await this.keys.approve(claims.sub, claims.request, pins);
157
- const code = secretToken();
158
- await this.store.transaction(async (tx) => {
159
- const current = await tx.take('pending', claims.request);
160
- if (!current || current.subject !== claims.sub || current.grantId !== identity.grantId || JSON.stringify(current) !== JSON.stringify(pending))
161
- throw new InvalidRequestError('Authorization request expired or already handled');
162
- const currentOwned = await tx.ownedMachines(claims.sub);
163
- if (selected.some(machine => !currentOwned.includes(machine) || !this.currentMachines(claims.sub).includes(machine)))
164
- throw new InvalidRequestError('Machine access revoked');
165
- await tx.put('code', hash(code), { ...current, subject: claims.sub, machines: selected, grantId: identity.grantId, activeExpiresAt: identity.activeExpiresAt }, now() + 120);
166
- });
167
- redirect.searchParams.set('code', code);
168
- return redirect.href;
169
- }
170
- async approvalPins(value, machines, identity) {
171
- const endpoint = z.object({ version: z.literal(1), id: z.string().regex(/^[A-Za-z0-9_-]{43}$/), ownerId: z.string().guid(), kind: z.literal('bridge'), publicKey: z.string().regex(/^[A-Za-z0-9_-]{87}$/) }).strict();
172
- const approvals = z.array(z.object({ bridgeId: z.string().regex(/^[A-Za-z0-9_-]{1,200}$/), bridge: endpoint, receipt: z.unknown().optional() }).strict()).min(1).max(64).safeParse(value);
173
- if (!approvals.success || approvals.data.length !== machines.length || new Set(approvals.data.map(approval => approval.bridgeId)).size !== machines.length)
174
- throw new InvalidRequestError('Every selected bridge must return encrypted approval');
175
- const pins = [];
176
- for (const approval of approvals.data) {
177
- if (!machines.includes(approval.bridgeId) || approval.bridge.ownerId !== identity.ownerId)
178
- throw new InvalidRequestError('Bridge approval does not match this account');
179
- let receipt;
180
- try {
181
- const envelope = parseSecureEnvelope(approval.receipt);
182
- receipt = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(await open(identity.identity, approval.bridge, envelope, { ownerId: identity.ownerId, bridgeId: approval.bridgeId, channel: `mcp-approval:${approval.bridgeId}:${identity.requestId}`, recipientId: identity.identity.endpoint.id, purpose: 'mcp-approval' })));
183
- }
184
- catch {
185
- throw new InvalidRequestError('Bridge encrypted approval could not be verified');
186
- }
187
- const parsed = z.object({ type: z.literal('mcp-approval'), approvalId: z.string().min(1).max(200), requestId: z.literal(identity.requestId), ownerId: z.literal(identity.ownerId), grantId: z.literal(identity.grantId), candidateEndpointId: z.literal(identity.identity.endpoint.id), bridgeId: z.literal(approval.bridgeId), bridge: endpoint, permissions: z.array(z.enum(['read', 'control'])).min(1).max(2), expiresAt: legacyDateTimeSchema, activeExpiresAt: z.literal(identity.activeExpiresAt) }).strict().safeParse(receipt);
188
- if (!parsed.success || parsed.data.bridge.id !== approval.bridge.id || parsed.data.bridge.publicKey !== approval.bridge.publicKey
189
- || [...parsed.data.permissions].sort().join(' ') !== [...identity.permissions].sort().join(' ')
190
- || Date.parse(parsed.data.expiresAt) <= Date.now() || Date.parse(parsed.data.expiresAt) > Date.parse(identity.pendingExpiresAt))
191
- throw new InvalidRequestError('Bridge approval does not match this consent');
192
- pins.push({ bridgeId: approval.bridgeId, endpoint: approval.bridge, permissions: parsed.data.permissions });
193
- }
194
- return pins;
195
- }
196
- async challengeForAuthorizationCode(client, code) {
197
- const record = await this.store.transaction((tx) => tx.get("code", hash(code)));
198
- if (!record || record.clientId !== client.client_id)
199
- throw new InvalidGrantError("Invalid authorization code");
200
- return record.challenge;
201
- }
202
- async tokens(tx, grantId, grant, scopes) {
203
- const access = secretToken(), refresh = secretToken();
204
- await tx.put("access", hash(access), { grantId, clientId: grant.clientId, expiresAt: now() + 900, scopes }, now() + 900);
205
- await tx.put("refresh", hash(refresh), { grantId, clientId: grant.clientId, expiresAt: grant.expiresAt, scopes }, grant.expiresAt);
206
- return {
207
- access_token: access,
208
- token_type: "Bearer",
209
- expires_in: 900,
210
- refresh_token: refresh,
211
- scope: scopes.join(" "),
212
- };
213
- }
214
- async exchangeAuthorizationCode(client, code, _verifier, redirectUri, resource) {
215
- const prepared = await this.store.transaction(tx => tx.get('code', hash(code)));
216
- if (!prepared || prepared.clientId !== client.client_id || prepared.redirectUri !== redirectUri || prepared.resource !== this.resource || resource?.href !== this.resource)
217
- throw new InvalidGrantError('Invalid code, redirect URI or resource');
218
- if (!this.keys || !prepared.grantId || !prepared.activeExpiresAt)
219
- throw new InvalidGrantError('Renew consent to authorize an encrypted endpoint');
220
- const identity = await this.keys.loadGrantIdentity(prepared.subject, prepared.grantId);
221
- if (identity.state !== 'approved' || identity.activeExpiresAt !== prepared.activeExpiresAt)
222
- throw new InvalidGrantError('Encrypted endpoint consent is unavailable');
223
- return this.store.transaction(async (tx) => {
224
- const record = await tx.take('code', hash(code));
225
- if (!record || JSON.stringify(record) !== JSON.stringify(prepared))
226
- throw new InvalidGrantError('Invalid or already used authorization code');
227
- const grantId = record.grantId;
228
- const grant = {
229
- resource: this.resource,
230
- subject: record.subject,
231
- machines: record.machines,
232
- scopes: record.scopes,
233
- clientId: client.client_id,
234
- expiresAt: Math.floor(Date.parse(record.activeExpiresAt) / 1000),
235
- revoked: false,
236
- };
237
- await tx.put("grant", grantId, grant, grant.expiresAt);
238
- return this.tokens(tx, grantId, grant, grant.scopes);
239
- });
240
- }
241
- async exchangeRefreshToken(client, token, scopes, resource) {
242
- if (resource?.href !== this.resource)
243
- throw new InvalidGrantError("Wrong resource");
244
- const result = await this.store.transaction(async (tx) => {
245
- const record = await tx.get("refresh", hash(token));
246
- if (!record || record.clientId !== client.client_id)
247
- throw new InvalidGrantError("Invalid refresh token");
248
- await tx.lock(record.grantId);
249
- const current = await tx.get("refresh", hash(token));
250
- const grant = await tx.get("grant", record.grantId);
251
- if (!grant || grant.revoked || grant.resource !== this.resource)
252
- throw new InvalidGrantError("Grant revoked or expired");
253
- if (current?.used) {
254
- await tx.put("grant", record.grantId, { ...grant, revoked: true }, grant.expiresAt);
255
- return null; // Commit replay revocation before returning the error.
256
- }
257
- const requested = scopes ?? record.scopes;
258
- if (!requested.includes("mcp:read") ||
259
- requested.some((s) => !record.scopes.includes(s)))
260
- throw new InvalidScopeError("Refresh cannot expand scope");
261
- await tx.put("refresh", hash(token), { ...record, used: true }, record.expiresAt);
262
- return this.tokens(tx, record.grantId, grant, requested);
263
- });
264
- if (!result)
265
- throw new InvalidGrantError("Refresh token reused; authorization revoked");
266
- return result;
267
- }
268
- async verifyAccessToken(token) {
269
- const result = await this.store.transaction(async (tx) => {
270
- const record = await tx.get("access", hash(token));
271
- const grant = record && (await tx.get("grant", record.grantId));
272
- if (!record || !grant || grant.revoked || grant.resource !== this.resource)
273
- throw new InvalidTokenError("Invalid, expired or revoked access token");
274
- const owned = await tx.ownedMachines(grant.subject);
275
- const machines = grant.machines.filter((m) => this.currentMachines(grant.subject).includes(m) && owned.includes(m));
276
- if (!machines.length)
277
- throw new InvalidTokenError("Machine access revoked");
278
- return {
279
- token,
280
- clientId: record.clientId,
281
- scopes: record.scopes,
282
- expiresAt: record.expiresAt,
283
- resource: new URL(this.resource),
284
- extra: { subject: grant.subject, machines, grantId: record.grantId },
285
- };
286
- });
287
- if (!this.keys)
288
- throw new InvalidTokenError('Renew consent to authorize an encrypted endpoint');
289
- let identity;
290
- try {
291
- identity = await this.keys.loadGrantIdentity(result.extra.subject, result.extra.grantId);
292
- }
293
- catch {
294
- throw new InvalidTokenError('Encrypted endpoint approval expired or requires renewed consent');
295
- }
296
- return { ...result, extra: { ...result.extra, endpointId: identity.identity.endpoint.id } };
297
- }
298
- async revokeToken(client, request) {
299
- await this.store.transaction(async (tx) => {
300
- const record = (await tx.get("access", hash(request.token))) ??
301
- (await tx.get("refresh", hash(request.token)));
302
- if (!record || record.clientId !== client.client_id)
303
- return;
304
- await tx.lock(record.grantId);
305
- const grant = await tx.get("grant", record.grantId);
306
- if (grant && grant.resource === this.resource)
307
- await tx.put("grant", record.grantId, { ...grant, revoked: true }, grant.expiresAt);
308
- });
309
- }
310
- }
311
- //# sourceMappingURL=oauth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/mcp/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,GAAG,MAAM,cAAc,CAAC;AAW/B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,iDAAiD,CAAC;AAGzD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAChE,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzE,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAyCtD,MAAM,OAAO,kBAAkB;IAGlB;IACA;IACA;IAJF,QAAQ,CAAS;IAC1B,YACW,KAAiB,EACjB,OAAqB,EACrB,IAAuB;QAFvB,UAAK,GAAL,KAAK,CAAY;QACjB,YAAO,GAAP,OAAO,CAAc;QACrB,SAAI,GAAJ,IAAI,CAAmB;QAEhC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;IAC1D,CAAC;IACO,eAAe,CAAC,OAAe;QACrC,OAAO,CACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,QAAQ,IAAI,EAAE,CACvE,CAAC;IACJ,CAAC;IACQ,YAAY,GAAG;QACtB,SAAS,EAAE,CAAC,EAAU,EAAE,EAAE,CACxB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAC5B,EAAE,CAAC,GAAG,CAA6B,QAAQ,EAAE,EAAE,CAAC,CACjD;QACH,cAAc,EAAE,KAAK,EACnB,KAGC,EACoC,EAAE;YACvC,mFAAmF;YACnF,IACE,KAAK,CAAC,0BAA0B;gBAChC,KAAK,CAAC,0BAA0B,KAAK,MAAM;gBAE3C,MAAM,IAAI,mBAAmB,CAAC,wCAAwC,CAAC,CAAC;YAC1E,IACE,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,EAAE;gBAC/B,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC/B,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;oBACvB,OAAO,CACL,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC;wBACtC,CAAC,CACC,CAAC,CAAC,QAAQ,KAAK,QAAQ;4BACvB,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO;gCACrB,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAC5D,CACF,CAAC;gBACJ,CAAC,CAAC;gBAEF,MAAM,IAAI,mBAAmB,CAC3B,8CAA8C,CAC/C,CAAC;YACJ,MAAM,MAAM,GAA+B;gBACzC,SAAS,EAAE,WAAW,EAAE;gBACxB,mBAAmB,EAAE,GAAG,EAAE;gBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBAC7C,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,0BAA0B,EAAE,MAAM;gBAClC,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;gBACpD,cAAc,EAAE,CAAC,MAAM,CAAC;aACzB,CAAC;YACF,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAClC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,KAAK,CAAC,CAChE,CAAC;YACF,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;IACF,KAAK,CAAC,SAAS,CACb,MAAkC,EAClC,MAA2B,EAC3B,GAAa;QAEb,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,QAAQ;YACzC,MAAM,IAAI,mBAAmB,CAAC,0CAA0C,CAAC,CAAC;QAC5E,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;YACnD,MAAM,IAAI,mBAAmB,CAAC,8BAA8B,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM;YAClC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACjB,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAE3C,MAAM,IAAI,iBAAiB,CAAC,4CAA4C,CAAC,CAAC;QAC5E,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,OAAO,GAAY;YACvB,QAAQ,EAAE,MAAM,CAAC,SAAS;YAC1B,UAAU,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS;YAClD,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,SAAS,EAAE,MAAM,CAAC,aAAa;YAC/B,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM;YACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,GAAG,EAAE,GAAG,GAAG;SACvB,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAClC,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAC5C,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACxC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACO,SAAS,CAAC,KAAa,EAAE,OAAuC;QACtE,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;YAC3D,UAAU,EAAE,CAAC,OAAO,CAAC;YACrB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAChC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAC7B,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QACH,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;YAC7B,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;YACjC,KAAK,CAAC,OAAO,KAAK,OAAO;YAEzB,MAAM,IAAI,mBAAmB,CAAC,4BAA4B,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,SAAiB;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACrE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAU,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;YACzD,KAAK,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,GAAI,CAAC;SAC3C,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,GAAG,CAAC;YAC7H,MAAM,IAAI,mBAAmB,CAAC,+BAA+B,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,mBAAmB,CAAC,6CAA6C,CAAC,CAAC;QAC7F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAI,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7J,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;YACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,GAAG,CAAU,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,mBAAmB,CAAC,+BAA+B,CAAC,CAAC;YACpI,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAC7H,CAAC,CAAC,CAAC;QACH,OAAO;YACL,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvD,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAClB;YACD,QAAQ;SACT,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,IAAI,GAAG,KAAK;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpE,4EAA4E;QAC5E,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAU,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;YACzD,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,GAAI,CAAC;SACvD,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,mBAAmB,CAAC,kDAAkD,CAAC,CAAC;QACtI,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACnF,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;gBACtC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAU,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;oBAAE,MAAM,IAAI,mBAAmB,CAAC,kDAAkD,CAAC,CAAC;YAC5I,CAAC,CAAC,CAAC;YACH,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YACpD,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,mBAAmB,CAAC,8DAA8D,CAAC,CAAC;QACpK,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7F,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAAE,MAAM,IAAI,mBAAmB,CAAC,iCAAiC,CAAC,CAAC;QAC1M,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAa,CAAC;QACpD,IAAI,QAAQ,CAAC,MAAM,GAAG,EAAE;YAAE,MAAM,IAAI,mBAAmB,CAAC,6BAA6B,CAAC,CAAC;QACvF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5E,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE;YAAE,MAAM,IAAI,mBAAmB,CAAC,qCAAqC,CAAC,CAAC;QACtM,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC3E,2EAA2E;QAC3E,+EAA+E;QAC/E,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAI,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;YACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,CAAU,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAClE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,mBAAmB,CAAC,kDAAkD,CAAC,CAAC;YACjO,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;YACzD,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAAE,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,CAAC,CAAC;YAC/K,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,GAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,eAAe,EAAiB,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;QAC/L,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IACO,KAAK,CAAC,YAAY,CAAC,KAAc,EAAE,QAAkB,EAAE,QAAgE;QAC7H,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;QACtN,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1L,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM;YAAE,MAAM,IAAI,mBAAmB,CAAC,sDAAsD,CAAC,CAAC;QAClP,MAAM,IAAI,GAAqB,EAAE,CAAC;QAClC,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO;gBAAE,MAAM,IAAI,mBAAmB,CAAC,6CAA6C,CAAC,CAAC;YACxK,IAAI,OAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACvD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,gBAAgB,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;YACxU,CAAC;YAAC,MAAM,CAAC;gBAAC,MAAM,IAAI,mBAAmB,CAAC,iDAAiD,CAAC,CAAC;YAAC,CAAC;YAC7F,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACxgB,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,SAAS;mBAC5H,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;mBAC5F,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAE,MAAM,IAAI,mBAAmB,CAAC,6CAA6C,CAAC,CAAC;YAChN,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9G,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,6BAA6B,CACjC,MAAkC,EAClC,IAAY;QAEZ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CACjD,EAAE,CAAC,GAAG,CAAO,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CACjC,CAAC;QACF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS;YACjD,MAAM,IAAI,iBAAiB,CAAC,4BAA4B,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,SAAS,CAAC;IAC1B,CAAC;IACO,KAAK,CAAC,MAAM,CAClB,EAAoB,EACpB,OAAe,EACf,KAAY,EACZ,MAAgB;QAEhB,MAAM,MAAM,GAAG,WAAW,EAAE,EAC1B,OAAO,GAAG,WAAW,EAAE,CAAC;QAC1B,MAAM,EAAE,CAAC,GAAG,CACV,QAAQ,EACR,IAAI,CAAC,MAAM,CAAC,EACZ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,EACrE,GAAG,EAAE,GAAG,GAAG,CACZ,CAAC;QACF,MAAM,EAAE,CAAC,GAAG,CACV,SAAS,EACT,IAAI,CAAC,OAAO,CAAC,EACb,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EACzE,KAAK,CAAC,SAAS,CAChB,CAAC;QACF,OAAO;YACL,YAAY,EAAE,MAAM;YACpB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,GAAG;YACf,aAAa,EAAE,OAAO;YACtB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SACxB,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,yBAAyB,CAC7B,MAAkC,EAClC,IAAY,EACZ,SAAkB,EAClB,WAAoB,EACpB,QAAc;QAEd,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAO,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,IAAI,QAAQ,CAAC,WAAW,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,iBAAiB,CAAC,wCAAwC,CAAC,CAAC;QAClP,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe;YAAE,MAAM,IAAI,iBAAiB,CAAC,kDAAkD,CAAC,CAAC;QAClJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvF,IAAI,QAAQ,CAAC,KAAK,KAAK,UAAU,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ,CAAC,eAAe;YAAE,MAAM,IAAI,iBAAiB,CAAC,2CAA2C,CAAC,CAAC;QACrK,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAO,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;gBAAE,MAAM,IAAI,iBAAiB,CAAC,4CAA4C,CAAC,CAAC;YAC9I,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAC/B,MAAM,KAAK,GAAU;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,SAAS;gBAC1B,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;gBAChE,OAAO,EAAE,KAAK;aACf,CAAC;YACF,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,oBAAoB,CACxB,MAAkC,EAClC,KAAa,EACb,MAAiB,EACjB,QAAc;QAEd,IAAI,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,QAAQ;YAClC,MAAM,IAAI,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACvD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CAAc,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS;gBACjD,MAAM,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;YACvD,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,GAAG,CAAc,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,GAAG,CAAQ,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;gBAC7D,MAAM,IAAI,iBAAiB,CAAC,0BAA0B,CAAC,CAAC;YAC1D,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;gBAClB,MAAM,EAAE,CAAC,GAAG,CACV,OAAO,EACP,MAAM,CAAC,OAAO,EACd,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAC3B,KAAK,CAAC,SAAS,CAChB,CAAC;gBACF,OAAO,IAAI,CAAC,CAAC,uDAAuD;YACtE,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;YAC1C,IACE,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC/B,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAEjD,MAAM,IAAI,iBAAiB,CAAC,6BAA6B,CAAC,CAAC;YAC7D,MAAM,EAAE,CAAC,GAAG,CACV,SAAS,EACT,IAAI,CAAC,KAAK,CAAC,EACX,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EACzB,MAAM,CAAC,SAAS,CACjB,CAAC;YACF,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,iBAAiB,CACzB,6CAA6C,CAC9C,CAAC;QACJ,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,iBAAiB,CAAC,KAAa;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACvD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CAAc,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAQ,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;gBACxE,MAAM,IAAI,iBAAiB,CAAC,0CAA0C,CAAC,CAAC;YAC1E,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CACvE,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,MAAM;gBAClB,MAAM,IAAI,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;YACxD,OAAO;gBACL,KAAK;gBACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,QAAQ,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAChC,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;aACrE,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,iBAAiB,CAAC,kDAAkD,CAAC,CAAC;QAChG,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QACjG,MAAM,CAAC;YAAC,MAAM,IAAI,iBAAiB,CAAC,iEAAiE,CAAC,CAAC;QAAC,CAAC;QACzG,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAC9F,CAAC;IACD,KAAK,CAAC,WAAW,CACf,MAAkC,EAClC,OAAoC;QAEpC,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACxC,MAAM,MAAM,GACV,CAAC,MAAM,EAAE,CAAC,GAAG,CAAc,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC1D,CAAC,MAAM,EAAE,CAAC,GAAG,CAAc,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS;gBAAE,OAAO;YAC5D,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,GAAG,CAAQ,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3D,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;gBAC3C,MAAM,EAAE,CAAC,GAAG,CACV,OAAO,EACP,MAAM,CAAC,OAAO,EACd,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAC3B,KAAK,CAAC,SAAS,CAChB,CAAC;QACN,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -1,2 +0,0 @@
1
- /** Legacy plaintext relay has no execution capability. Native ciphertext uses the verified dispatcher. */
2
- export declare function createRelayHandler(_port: number, _token: string): (_id: string, _payload: Record<string, unknown>) => Promise<never>;
@@ -1,8 +0,0 @@
1
- import { FleetError } from './fleet.js';
2
- /** Legacy plaintext relay has no execution capability. Native ciphertext uses the verified dispatcher. */
3
- export function createRelayHandler(_port, _token) {
4
- return async (_id, _payload) => {
5
- throw new FleetError('upgrade_required', 'Encrypted endpoint approval is required');
6
- };
7
- }
8
- //# sourceMappingURL=relay-handler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"relay-handler.js","sourceRoot":"","sources":["../../src/mcp/relay-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,0GAA0G;AAC1G,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAAc;IAC9D,OAAO,KAAK,EAAE,GAAW,EAAE,QAAiC,EAAkB,EAAE;QAC9E,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAC;IACtF,CAAC,CAAC;AACJ,CAAC"}
@@ -1,13 +0,0 @@
1
- import { type BridgeRequest } from "./fleet.js";
2
- import { type McpRequestContext } from "./secure-client.js";
3
- /** Renewable routing connections carry ciphertext only; identities stay request-bound. */
4
- export declare class FleetRelay {
5
- private url;
6
- private tokenSecret;
7
- private clients;
8
- constructor(url: string, tokenSecret: string);
9
- private connection;
10
- request(userId: string, machineId: string, request: BridgeRequest, signal?: AbortSignal, context?: McpRequestContext): Promise<unknown>;
11
- private exchange;
12
- close(): void;
13
- }
package/dist/mcp/relay.js DELETED
@@ -1,95 +0,0 @@
1
- import { Centrifuge } from "centrifuge";
2
- import WebSocket from "ws";
3
- import jwt from "jsonwebtoken";
4
- import { FleetError, requestSchema } from "./fleet.js";
5
- import { parseSecureEnvelope } from "../security/crypto.js";
6
- import { SecureMcpClient } from "./secure-client.js";
7
- /** Renewable routing connections carry ciphertext only; identities stay request-bound. */
8
- export class FleetRelay {
9
- url;
10
- tokenSecret;
11
- clients = new Map();
12
- constructor(url, tokenSecret) {
13
- this.url = url;
14
- this.tokenSecret = tokenSecret;
15
- }
16
- connection(userId) {
17
- const cached = this.clients.get(userId);
18
- if (cached)
19
- return cached;
20
- const mint = () => jwt.sign({}, this.tokenSecret, { subject: userId, audience: "ftown:centrifugo", expiresIn: "10m" });
21
- const client = new Centrifuge(this.url, { websocket: WebSocket, token: mint(), getToken: async () => mint(), timeout: 10000 });
22
- const sub = client.newSubscription(`commands:rpc#${userId}`);
23
- const pending = new Map();
24
- sub.on("publication", ctx => {
25
- if (ctx.info?.user !== userId)
26
- return;
27
- try {
28
- const packet = parseSecureEnvelope(ctx.data);
29
- pending.get(packet.messageId)?.accept(packet);
30
- }
31
- catch { /* Plaintext/unknown/oversized traffic never enters the application. */ }
32
- });
33
- sub.subscribe();
34
- client.connect();
35
- const entry = { client, sub, pending };
36
- this.clients.set(userId, entry);
37
- return entry;
38
- }
39
- async request(userId, machineId, request, signal, context) {
40
- if (!context)
41
- throw new FleetError("approval_required", "An encrypted MCP grant is required");
42
- const client = new SecureMcpClient(context, machineId, `commands:rpc#${userId}`, (packet, deadline, mutating, abort) => this.exchange(userId, packet, deadline, mutating, abort));
43
- return client.request(requestSchema.parse(request), signal);
44
- }
45
- async exchange(userId, packet, deadline, mutating, signal) {
46
- if (Date.now() >= deadline)
47
- throw new FleetError("timeout", "Encrypted request expired before publication");
48
- if (signal?.aborted)
49
- throw new FleetError("cancelled", "Encrypted request cancelled");
50
- const { sub, pending } = this.connection(userId);
51
- const id = packet.messageId;
52
- return new Promise((resolve, reject) => {
53
- let sent = false, settled = false;
54
- const finish = (error, value) => {
55
- if (settled)
56
- return;
57
- settled = true;
58
- clearTimeout(timer);
59
- pending.delete(id);
60
- signal?.removeEventListener("abort", cancel);
61
- if (error)
62
- reject(error);
63
- else if (value)
64
- resolve(value);
65
- };
66
- const cancel = () => finish(new FleetError("cancelled", "Encrypted relay request cancelled", sent && mutating));
67
- const timer = setTimeout(() => finish(new FleetError("timeout", "Encrypted bridge did not respond before the deadline", sent && mutating)), Math.max(1, deadline - Date.now()));
68
- signal?.addEventListener("abort", cancel, { once: true });
69
- if (signal?.aborted) {
70
- cancel();
71
- return;
72
- }
73
- pending.set(id, { accept: value => {
74
- // Other concurrent gateways/endpoints can publish the same visible ID; only accept the exact route here.
75
- if (value.senderId === packet.recipientId && value.recipientId === packet.senderId && value.ownerId === packet.ownerId && value.bridgeId === packet.bridgeId && value.channel === packet.channel)
76
- finish(undefined, value);
77
- }, reject: () => finish(new FleetError("connection_error", "Encrypted relay is closing", sent && mutating)) });
78
- void sub.ready(Math.max(1, deadline - Date.now())).then(async () => {
79
- if (settled)
80
- return;
81
- sent = true;
82
- await sub.publish(packet);
83
- }).catch(() => finish(new FleetError("connection_error", "Encrypted relay connection unavailable", sent && mutating)));
84
- });
85
- }
86
- close() {
87
- for (const entry of this.clients.values()) {
88
- for (const pending of [...entry.pending.values()])
89
- pending.reject();
90
- entry.client.disconnect();
91
- }
92
- this.clients.clear();
93
- }
94
- }
95
- //# sourceMappingURL=relay.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/mcp/relay.ts"],"names":[],"mappings":"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"}
@@ -1,23 +0,0 @@
1
- import type { McpActionContext, SecureEnvelope } from '../security/protocol.js';
2
- import type { McpGrantIdentity } from './mcp-key-store.js';
3
- import { type BridgeRequest } from './fleet.js';
4
- export interface McpRequestContext {
5
- grant: McpGrantIdentity;
6
- action: McpActionContext;
7
- revalidate?: () => Promise<void>;
8
- }
9
- export type SecureExchange = (envelope: SecureEnvelope, deadline: number, mutating: boolean, signal?: AbortSignal) => Promise<SecureEnvelope>;
10
- /** Both endpoint adapters use the same semantic allowlist. */
11
- export declare function isMcpMutation(request: Pick<BridgeRequest, 'method' | 'path'>): boolean;
12
- /** An immutable grant-bound endpoint; no state is shared across callers or grants. */
13
- export declare class SecureMcpClient {
14
- private context;
15
- private bridgeId;
16
- private channel;
17
- private exchange;
18
- constructor(context: McpRequestContext, bridgeId: string, channel: string, exchange: SecureExchange);
19
- private pin;
20
- private header;
21
- private send;
22
- request(request: BridgeRequest, signal?: AbortSignal): Promise<unknown>;
23
- }
@@ -1,124 +0,0 @@
1
- import { randomBytes, randomUUID } from 'node:crypto';
2
- import { z } from 'zod';
3
- import { seal, open, SecurityError } from '../security/crypto.js';
4
- import { FleetError } from './fleet.js';
5
- import { classifyHttp } from '../security/bridge/permissions.js';
6
- /** Both endpoint adapters use the same semantic allowlist. */
7
- export function isMcpMutation(request) {
8
- try {
9
- return classifyHttp(request.method, request.path).mutating;
10
- }
11
- catch {
12
- throw new FleetError('permission_denied', 'MCP request is outside the bridge semantic allowlist');
13
- }
14
- }
15
- const responseSchema = z.object({ type: z.literal('application'), route: z.object({ kind: z.literal('response'), requestId: z.string() }).strict(), data: z.unknown().optional(), mcp: z.unknown().nullable().optional() }).strict();
16
- const welcomeSchema = z.object({ type: z.literal('welcome'), challenge: z.string(), receiverEpoch: z.string().regex(/^[A-Za-z0-9_-]{1,128}$/) }).strict();
17
- function json(bytes) {
18
- try {
19
- return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
20
- }
21
- catch {
22
- throw new SecurityError('invalid_envelope', 'Bridge returned an invalid encrypted response');
23
- }
24
- }
25
- function applicationJson(value, depth = 0) {
26
- if (depth > 32)
27
- throw new FleetError('invalid_request', 'MCP request nesting exceeds the encrypted transport limit');
28
- if (value === null || typeof value === 'boolean' || typeof value === 'string')
29
- return value;
30
- if (typeof value === 'number' && Number.isFinite(value))
31
- return value;
32
- if (Array.isArray(value))
33
- return value.map(item => applicationJson(item, depth + 1));
34
- if (typeof value === 'object' && value !== null)
35
- return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined).map(([key, item]) => [key, applicationJson(item, depth + 1)]));
36
- throw new FleetError('invalid_request', 'MCP request must contain JSON values');
37
- }
38
- /** An immutable grant-bound endpoint; no state is shared across callers or grants. */
39
- export class SecureMcpClient {
40
- context;
41
- bridgeId;
42
- channel;
43
- exchange;
44
- constructor(context, bridgeId, channel, exchange) {
45
- this.context = context;
46
- this.bridgeId = bridgeId;
47
- this.channel = channel;
48
- this.exchange = exchange;
49
- }
50
- pin() {
51
- const pin = this.context.grant.bridges.find(candidate => candidate.bridgeId === this.bridgeId);
52
- if (!pin || pin.endpoint.ownerId !== this.context.grant.ownerId || !pin.permissions.includes('read'))
53
- throw new FleetError('approval_required', 'Bridge encryption approval is required; configure machine.id as the actual bridgeId and use label for aliases');
54
- if (Date.parse(this.context.grant.activeExpiresAt) <= Date.now())
55
- throw new FleetError('expired', 'Bridge encryption approval has expired');
56
- return pin;
57
- }
58
- header(id, purpose, epoch, deadline) {
59
- return {
60
- type: 'ftown_encrypted', version: 1, senderId: this.context.grant.identity.endpoint.id,
61
- recipientId: this.pin().endpoint.id, ownerId: this.context.grant.ownerId, bridgeId: this.bridgeId,
62
- channel: this.channel, purpose, messageId: id, createdAt: Date.now(), expiresAt: Math.min(deadline, Date.now() + 120_000), receiverEpoch: epoch,
63
- };
64
- }
65
- async send(header, value, mutating, deadline, signal) {
66
- if (signal?.aborted || Date.now() >= deadline)
67
- throw new FleetError('cancelled', 'Encrypted request cancelled before dispatch');
68
- const packet = await seal(this.context.grant.identity, this.pin().endpoint, header, new TextEncoder().encode(JSON.stringify(value)));
69
- const reply = await this.exchange(packet, deadline, mutating, signal);
70
- if (reply.messageId !== header.messageId)
71
- throw new FleetError('bridge_error', 'Bridge response correlation failed', mutating);
72
- const expected = { ownerId: this.context.grant.ownerId, bridgeId: this.bridgeId, channel: this.channel, recipientId: this.context.grant.identity.endpoint.id, purpose: header.purpose === 'hello' ? 'welcome' : 'application' };
73
- try {
74
- return json(await open(this.context.grant.identity, this.pin().endpoint, reply, expected));
75
- }
76
- catch {
77
- throw new FleetError('authentication_failed', 'Bridge encrypted response authentication failed', mutating);
78
- }
79
- }
80
- async request(request, signal) {
81
- await this.context.revalidate?.();
82
- const deadline = Date.now() + request.timeoutMs;
83
- const pin = this.pin();
84
- const mutating = isMcpMutation(request);
85
- if (mutating && (!pin.permissions.includes('control') || !this.context.grant.permissions.includes('control')))
86
- throw new FleetError('permission_denied', 'This MCP grant cannot control the bridge');
87
- const challenge = randomBytes(32).toString('base64url');
88
- const hello = await this.send(this.header(randomUUID(), 'hello', null, deadline), { type: 'hello', challenge }, false, deadline, signal);
89
- const welcome = welcomeSchema.safeParse(hello);
90
- if (!welcome.success || welcome.data.challenge !== challenge)
91
- throw new FleetError('authentication_failed', 'Bridge encryption handshake failed');
92
- const activationId = randomUUID();
93
- const activation = {
94
- type: 'application', route: { kind: 'command', command: 'security_activate_mcp', requestId: activationId, sessionId: null },
95
- data: { type: 'security_activate_mcp', requestId: activationId, payload: { bridgeId: this.bridgeId, grantId: this.context.grant.grantId } }, mcp: this.context.action,
96
- };
97
- const activated = responseSchema.safeParse(await this.send(this.header(activationId, 'application', welcome.data.receiverEpoch, deadline), activation, false, deadline, signal));
98
- if (!activated.success || activated.data.route.requestId !== activationId)
99
- throw new FleetError('bridge_error', 'Bridge activation response is invalid');
100
- const activationResponse = z.object({ type: z.literal('command_response'), response: z.object({ requestId: z.literal(activationId), success: z.boolean(), error: z.string().optional(), data: z.unknown().optional() }) }).safeParse(activated.data.data);
101
- if (!activationResponse.success || !activationResponse.data.response.success)
102
- throw new FleetError('approval_required', 'Bridge MCP approval could not be activated');
103
- await this.context.revalidate?.();
104
- const requestId = randomUUID();
105
- const application = {
106
- type: 'application', route: { kind: 'http', requestId, method: request.method, path: request.path },
107
- data: applicationJson({ timeoutMs: Math.max(1000, deadline - Date.now()), ...(request.body === undefined ? {} : { body: request.body }) }), mcp: this.context.action,
108
- };
109
- const result = responseSchema.safeParse(await this.send(this.header(requestId, 'application', welcome.data.receiverEpoch, deadline), application, mutating, deadline, signal));
110
- if (!result.success || result.data.route.requestId !== requestId)
111
- throw new FleetError('bridge_error', 'Bridge response is invalid', mutating);
112
- const http = z.object({ status: z.number().int().min(100).max(599), body: z.unknown().optional() }).strict().safeParse(result.data.data);
113
- if (!http.success)
114
- throw new FleetError('bridge_error', 'Bridge HTTP response is invalid', mutating);
115
- if (http.data.status < 200 || http.data.status >= 300) {
116
- const error = z.object({ code: z.string().optional(), outcomeUnknown: z.boolean().optional() }).passthrough().safeParse(http.data.body);
117
- const allowed = ['unknown_session', 'invalid_cursor', 'unknown_attention', 'permission_denied', 'endpoint_revoked', 'upgrade_required', 'audit_unavailable', 'outcome_unknown'];
118
- const code = error.success && error.data.code && allowed.includes(error.data.code) ? error.data.code : 'bridge_error';
119
- throw new FleetError(code, 'Bridge rejected the encrypted request', mutating && (http.data.status >= 500 || (error.success && error.data.outcomeUnknown === true)), http.data.status);
120
- }
121
- return http.data.body;
122
- }
123
- }
124
- //# sourceMappingURL=secure-client.js.map