@superblocksteam/gateway 2.0.178-next.3 → 2.0.179-next.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 +4 -1
- package/dist/auth/cli-session.d.ts +24 -0
- package/dist/auth/cli-session.d.ts.map +1 -0
- package/dist/auth/cli-session.js +46 -0
- package/dist/auth/cli-session.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/login.d.ts +18 -0
- package/dist/auth/login.d.ts.map +1 -0
- package/dist/auth/login.js +124 -0
- package/dist/auth/login.js.map +1 -0
- package/dist/auth/mcp-oauth-session.d.ts +46 -0
- package/dist/auth/mcp-oauth-session.d.ts.map +1 -0
- package/dist/auth/mcp-oauth-session.js +247 -0
- package/dist/auth/mcp-oauth-session.js.map +1 -0
- package/dist/auth/mcp-server-selection.d.ts +42 -0
- package/dist/auth/mcp-server-selection.d.ts.map +1 -0
- package/dist/auth/mcp-server-selection.js +179 -0
- package/dist/auth/mcp-server-selection.js.map +1 -0
- package/dist/auth/native-oauth.d.ts +33 -0
- package/dist/auth/native-oauth.d.ts.map +1 -0
- package/dist/auth/native-oauth.js +181 -0
- package/dist/auth/native-oauth.js.map +1 -0
- package/dist/capabilities/branching.d.ts +139 -0
- package/dist/capabilities/branching.d.ts.map +1 -0
- package/dist/capabilities/branching.js +540 -0
- package/dist/capabilities/branching.js.map +1 -0
- package/dist/capabilities/lifecycle.d.ts +19 -0
- package/dist/capabilities/lifecycle.d.ts.map +1 -1
- package/dist/capabilities/lifecycle.js +60 -2
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/types.d.ts +2 -0
- package/dist/capabilities/types.d.ts.map +1 -1
- package/dist/capabilities/types.js.map +1 -1
- package/dist/main.js +21 -3
- package/dist/main.js.map +1 -1
- package/dist/sabs/editor-client-methods.d.ts.map +1 -1
- package/dist/sabs/editor-client-methods.js +11 -1
- package/dist/sabs/editor-client-methods.js.map +1 -1
- package/dist/server/client.d.ts +125 -4
- package/dist/server/client.d.ts.map +1 -1
- package/dist/server/client.js +55 -4
- package/dist/server/client.js.map +1 -1
- package/dist/stdio/index.d.ts +2 -0
- package/dist/stdio/index.d.ts.map +1 -0
- package/dist/stdio/index.js +2 -0
- package/dist/stdio/index.js.map +1 -0
- package/dist/stdio/serve.d.ts +56 -0
- package/dist/stdio/serve.d.ts.map +1 -0
- package/dist/stdio/serve.js +208 -0
- package/dist/stdio/serve.js.map +1 -0
- package/dist/transports/mcp/mount.d.ts.map +1 -1
- package/dist/transports/mcp/mount.js +204 -2
- package/dist/transports/mcp/mount.js.map +1 -1
- package/dist/transports/mcp/tool-names.d.ts +1 -1
- package/dist/transports/mcp/tool-names.d.ts.map +1 -1
- package/dist/transports/mcp/tool-permissions.d.ts +13 -0
- package/dist/transports/mcp/tool-permissions.d.ts.map +1 -1
- package/dist/transports/mcp/tool-permissions.js +14 -0
- package/dist/transports/mcp/tool-permissions.js.map +1 -1
- package/package.json +24 -7
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { MCP_OAUTH_FILE_SUFFIX, McpOAuthStoreReadError, normalizeMcpServerUrl, } from "./mcp-oauth-session.js";
|
|
5
|
+
const PLUGIN_SETTINGS_FILE = "plugin.json";
|
|
6
|
+
/**
|
|
7
|
+
* The Superblocks server this computer's MCP plugin uses, kept as `serverUrl`
|
|
8
|
+
* in the plugin settings file the plugin launcher also reads. It is kept apart
|
|
9
|
+
* from the browser login saved for that server, so a removed, expired, or
|
|
10
|
+
* unreadable login never sends the plugin back to the default server, and a
|
|
11
|
+
* server the user writes into the file is used even while the saved login
|
|
12
|
+
* belongs to another server.
|
|
13
|
+
*/
|
|
14
|
+
export class McpServerSelectionStore {
|
|
15
|
+
filePath;
|
|
16
|
+
legacyFilePath;
|
|
17
|
+
constructor(filePath, legacyFilePath) {
|
|
18
|
+
this.filePath = filePath;
|
|
19
|
+
this.legacyFilePath = legacyFilePath;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The plugin settings file in the browser login file's directory. A
|
|
23
|
+
* selection saved before that file existed is moved into it on first read.
|
|
24
|
+
*/
|
|
25
|
+
static beside(sessionFilePath) {
|
|
26
|
+
const base = sessionFilePath.endsWith(MCP_OAUTH_FILE_SUFFIX)
|
|
27
|
+
? sessionFilePath.slice(0, -MCP_OAUTH_FILE_SUFFIX.length)
|
|
28
|
+
: sessionFilePath;
|
|
29
|
+
return new McpServerSelectionStore(join(dirname(sessionFilePath), PLUGIN_SETTINGS_FILE), `${base}.mcp-server`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The server in use: the one the user chose, else the saved browser
|
|
33
|
+
* login's server, which is recorded as the choice unless the environment
|
|
34
|
+
* pinned it. The record is written under the login's lock so a concurrent
|
|
35
|
+
* sign-in cannot save a newer login between the read and the write.
|
|
36
|
+
*/
|
|
37
|
+
async resolve(sessions) {
|
|
38
|
+
return sessions.withLock(async () => {
|
|
39
|
+
const chosen = await this.read();
|
|
40
|
+
if (chosen)
|
|
41
|
+
return chosen;
|
|
42
|
+
const login = await sessions.read().catch((error) => {
|
|
43
|
+
if (error instanceof McpOAuthStoreReadError)
|
|
44
|
+
return undefined;
|
|
45
|
+
throw error;
|
|
46
|
+
});
|
|
47
|
+
if (login && !login.pinned)
|
|
48
|
+
await this.remember(login.serverUrl);
|
|
49
|
+
return login?.serverUrl;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The server a sign-in uses once the saved browser login is gone. A login
|
|
54
|
+
* the user chose is recorded first; one the environment pinned is not.
|
|
55
|
+
*/
|
|
56
|
+
async withoutLogin(sessions) {
|
|
57
|
+
await this.resolve(sessions);
|
|
58
|
+
return this.read();
|
|
59
|
+
}
|
|
60
|
+
/** The selected origin, or undefined when none is saved or it is unusable. */
|
|
61
|
+
async read() {
|
|
62
|
+
try {
|
|
63
|
+
const settings = await readSettings(this.filePath);
|
|
64
|
+
if (settings?.serverUrl !== undefined) {
|
|
65
|
+
const chosen = McpServerSelectionStore.parse(settings);
|
|
66
|
+
await this.dropLegacySelection();
|
|
67
|
+
return chosen;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logUnreadable(error, this.filePath);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
return this.moveLegacySelection();
|
|
75
|
+
}
|
|
76
|
+
/** Saves the selection without failing the sign-in or switch that made it. */
|
|
77
|
+
async remember(serverUrl) {
|
|
78
|
+
try {
|
|
79
|
+
await this.save(serverUrl);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error("MCP server selection was not saved", {
|
|
83
|
+
errorType: errorType(error),
|
|
84
|
+
filePath: this.filePath,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Writes `serverUrl` and keeps every other plugin setting as it was. */
|
|
89
|
+
async save(serverUrl) {
|
|
90
|
+
const selected = normalizeMcpServerUrl(serverUrl);
|
|
91
|
+
const settings = {
|
|
92
|
+
...(await readSettings(this.filePath)),
|
|
93
|
+
serverUrl: selected,
|
|
94
|
+
};
|
|
95
|
+
await mkdir(dirname(this.filePath), { mode: 0o700, recursive: true });
|
|
96
|
+
const temporaryPath = `${this.filePath}.${randomUUID()}.tmp`;
|
|
97
|
+
try {
|
|
98
|
+
await writeFile(temporaryPath, JSON.stringify(settings, null, 2), {
|
|
99
|
+
flag: "wx",
|
|
100
|
+
mode: 0o600,
|
|
101
|
+
});
|
|
102
|
+
await rename(temporaryPath, this.filePath);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await rm(temporaryPath, { force: true });
|
|
106
|
+
}
|
|
107
|
+
await this.dropLegacySelection();
|
|
108
|
+
}
|
|
109
|
+
/** Once plugin.json names a server, the old file must not bring back an older one. */
|
|
110
|
+
async dropLegacySelection() {
|
|
111
|
+
if (!this.legacyFilePath)
|
|
112
|
+
return;
|
|
113
|
+
await rm(this.legacyFilePath, { force: true }).catch((error) => {
|
|
114
|
+
console.error("Old MCP server selection was not removed", {
|
|
115
|
+
errorType: errorType(error),
|
|
116
|
+
filePath: this.legacyFilePath,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async moveLegacySelection() {
|
|
121
|
+
if (!this.legacyFilePath)
|
|
122
|
+
return undefined;
|
|
123
|
+
let serverUrl;
|
|
124
|
+
try {
|
|
125
|
+
const legacy = await readSettings(this.legacyFilePath);
|
|
126
|
+
if (!legacy)
|
|
127
|
+
return undefined;
|
|
128
|
+
serverUrl = McpServerSelectionStore.parse(legacy);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
logUnreadable(error, this.legacyFilePath);
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
await this.remember(serverUrl);
|
|
135
|
+
return serverUrl;
|
|
136
|
+
}
|
|
137
|
+
static parse(settings) {
|
|
138
|
+
if (typeof settings.serverUrl !== "string")
|
|
139
|
+
throw new TypeError("MCP server selection names no server.");
|
|
140
|
+
return normalizeMcpServerUrl(settings.serverUrl);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** The settings object in a file, or undefined when the file does not exist. */
|
|
144
|
+
async function readSettings(filePath) {
|
|
145
|
+
let contents;
|
|
146
|
+
try {
|
|
147
|
+
contents = await readFile(filePath, "utf8");
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (errorType(error) === "ENOENT")
|
|
151
|
+
return undefined;
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
const settings = JSON.parse(contents);
|
|
155
|
+
if (!isRecord(settings))
|
|
156
|
+
throw new TypeError("MCP plugin settings are not a JSON object.");
|
|
157
|
+
return settings;
|
|
158
|
+
}
|
|
159
|
+
function logUnreadable(error, filePath) {
|
|
160
|
+
console.error("MCP server selection was not read", {
|
|
161
|
+
errorType: errorType(error),
|
|
162
|
+
filePath,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* A system error's code, else the error's name. Never the message, which can
|
|
167
|
+
* quote the file's contents.
|
|
168
|
+
*/
|
|
169
|
+
function errorType(error) {
|
|
170
|
+
if (!(error instanceof Error))
|
|
171
|
+
return typeof error;
|
|
172
|
+
return "code" in error && typeof error.code === "string"
|
|
173
|
+
? error.code
|
|
174
|
+
: error.name;
|
|
175
|
+
}
|
|
176
|
+
function isRecord(value) {
|
|
177
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=mcp-server-selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server-selection.js","sourceRoot":"","sources":["../../src/auth/mcp-server-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EACL,qBAAqB,EAErB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,oBAAoB,GAAG,aAAa,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,OAAO,uBAAuB;IAEvB,QAAQ;IACA,cAAc;IAFjC,YACW,QAAgB,EACR,cAAuB;wBAD/B,QAAQ;8BACA,cAAc;IAC9B,CAAC;IAEJ;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,eAAuB;QACnC,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAC1D,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC;YACzD,CAAC,CAAC,eAAe,CAAC;QACpB,OAAO,IAAI,uBAAuB,CAChC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,oBAAoB,CAAC,EACpD,GAAG,IAAI,aAAa,CACrB,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,QAA8B;QAC1C,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE;YAClC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC3D,IAAI,KAAK,YAAY,sBAAsB;oBAAE,OAAO,SAAS,CAAC;gBAC9D,MAAM,KAAK,CAAC;YACd,CAAC,CAAC,CAAC;YACH,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACjE,OAAO,KAAK,EAAE,SAAS,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAChB,QAA8B;QAE9B,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,8EAA8E;IAC9E,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,IAAI,QAAQ,EAAE,SAAS,KAAK,SAAS,EAAE,CAAC;gBACtC,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACvD,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACjC,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpC,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACpC,CAAC;IAED,8EAA8E;IAC9E,KAAK,CAAC,QAAQ,CAAC,SAAiB;QAC9B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE;gBAClD,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC;gBAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,IAAI,CAAC,SAAiB;QAC1B,MAAM,QAAQ,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,SAAS,EAAE,QAAQ;SACpB,CAAC;QACF,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,MAAM,aAAa,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,UAAU,EAAE,MAAM,CAAC;QAC7D,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;gBAChE,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,KAAK;aACZ,CAAC,CAAC;YACH,MAAM,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACnC,CAAC;IAED,sFAAsF;IAC9E,KAAK,CAAC,mBAAmB;QAC/B,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO;QACjC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACtE,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE;gBACxD,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC;gBAC3B,QAAQ,EAAE,IAAI,CAAC,cAAc;aAC9B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO,SAAS,CAAC;QAC3C,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC9B,SAAS,GAAG,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YAC1C,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,QAAiC;QACpD,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,QAAQ;YACxC,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;QAC/D,OAAO,qBAAqB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;CACF;AAED,gFAAgF;AAChF,KAAK,UAAU,YAAY,CACzB,QAAgB;IAEhB,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACpD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACrB,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;IACpE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,QAAgB;IACrD,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE;QACjD,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC;QAC3B,QAAQ;KACT,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,OAAO,KAAK,CAAC;IACnD,OAAO,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QACtD,CAAC,CAAC,KAAK,CAAC,IAAI;QACZ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface NativeOAuthConfig {
|
|
2
|
+
audience: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
issuerUrl: string;
|
|
5
|
+
organization?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface OAuthTokens {
|
|
8
|
+
accessToken: string;
|
|
9
|
+
expiresAt: number;
|
|
10
|
+
refreshToken?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class OAuthRefreshError extends Error {
|
|
13
|
+
}
|
|
14
|
+
export declare class NativeOAuthClient {
|
|
15
|
+
private readonly config;
|
|
16
|
+
private readonly options;
|
|
17
|
+
constructor(config: NativeOAuthConfig, options?: {
|
|
18
|
+
fetch?: typeof fetch;
|
|
19
|
+
now?: () => number;
|
|
20
|
+
});
|
|
21
|
+
refresh(refreshToken: string): Promise<OAuthTokens>;
|
|
22
|
+
authorize({ forceLogin, openBrowser, redirectPort, timeoutMs, signal, }: {
|
|
23
|
+
forceLogin?: boolean;
|
|
24
|
+
openBrowser: (url: string) => Promise<void>;
|
|
25
|
+
redirectPort?: number;
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}): Promise<OAuthTokens>;
|
|
29
|
+
private configuration;
|
|
30
|
+
private httpsUrl;
|
|
31
|
+
private tokens;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=native-oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-oauth.d.ts","sourceRoot":"","sources":["../../src/auth/native-oauth.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF1B,YACmB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAO,EACzE;IAEE,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAYxD;IAEK,SAAS,CAAC,EACd,UAAkB,EAClB,WAAW,EACX,YAAmB,EACnB,SAAmB,EACnB,MAAM,GACP,EAAE;QACD,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,WAAW,CAAC,CAyGvB;YAEa,aAAa;IAsC3B,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,MAAM;CAwBf"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { once } from "node:events";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import * as oidc from "openid-client";
|
|
4
|
+
export class OAuthRefreshError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export class NativeOAuthClient {
|
|
7
|
+
config;
|
|
8
|
+
options;
|
|
9
|
+
constructor(config, options = {}) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.options = options;
|
|
12
|
+
}
|
|
13
|
+
async refresh(refreshToken) {
|
|
14
|
+
try {
|
|
15
|
+
const configuration = await this.configuration();
|
|
16
|
+
const tokens = await oidc.refreshTokenGrant(configuration, refreshToken);
|
|
17
|
+
return this.tokens(tokens, tokens.refresh_token ?? refreshToken);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error("MCP OAuth refresh failed", {
|
|
21
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
22
|
+
pid: process.pid,
|
|
23
|
+
});
|
|
24
|
+
throw new OAuthRefreshError("OAuth refresh failed. Sign in again.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async authorize({ forceLogin = false, openBrowser, redirectPort = 8485, timeoutMs = 120_000, signal, }) {
|
|
28
|
+
const state = oidc.randomState();
|
|
29
|
+
const callback = Promise.withResolvers();
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
const abort = () => controller.abort();
|
|
32
|
+
const timeout = setTimeout(abort, timeoutMs);
|
|
33
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
34
|
+
if (signal?.aborted)
|
|
35
|
+
abort();
|
|
36
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
37
|
+
const rejectAbort = () => reject(new Error("OAuth sign-in interrupted."));
|
|
38
|
+
if (controller.signal.aborted)
|
|
39
|
+
rejectAbort();
|
|
40
|
+
else
|
|
41
|
+
controller.signal.addEventListener("abort", rejectAbort, {
|
|
42
|
+
once: true,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
let redirectUri = "";
|
|
46
|
+
const server = createServer((request, response) => {
|
|
47
|
+
const url = URL.parse(request.url ?? "/", redirectUri);
|
|
48
|
+
if (!url || url.origin !== new URL(redirectUri).origin) {
|
|
49
|
+
response.writeHead(400).end("Invalid OAuth callback.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (request.method !== "GET" || url.pathname !== "/callback") {
|
|
53
|
+
response.writeHead(404).end();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (url.searchParams.getAll("state").length !== 1 ||
|
|
57
|
+
url.searchParams.get("state") !== state) {
|
|
58
|
+
response.writeHead(400).end("Invalid OAuth callback.");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
callback.resolve(url);
|
|
62
|
+
response.end("Sign-in response received. Return to your MCP client.");
|
|
63
|
+
});
|
|
64
|
+
const signIn = async () => {
|
|
65
|
+
controller.signal.throwIfAborted();
|
|
66
|
+
const configuration = await this.configuration(controller.signal);
|
|
67
|
+
const verifier = oidc.randomPKCECodeVerifier();
|
|
68
|
+
const challenge = await oidc.calculatePKCECodeChallenge(verifier);
|
|
69
|
+
const nonce = oidc.randomNonce();
|
|
70
|
+
controller.signal.throwIfAborted();
|
|
71
|
+
server.listen(redirectPort, "127.0.0.1");
|
|
72
|
+
await once(server, "listening");
|
|
73
|
+
const address = server.address();
|
|
74
|
+
if (!address || typeof address === "string") {
|
|
75
|
+
throw new Error("Unable to start the OAuth callback listener.");
|
|
76
|
+
}
|
|
77
|
+
redirectUri = `http://127.0.0.1:${address.port}/callback`;
|
|
78
|
+
const authorizationUrl = oidc.buildAuthorizationUrl(configuration, {
|
|
79
|
+
audience: this.config.audience,
|
|
80
|
+
code_challenge: challenge,
|
|
81
|
+
code_challenge_method: "S256",
|
|
82
|
+
nonce,
|
|
83
|
+
...(forceLogin ? { prompt: "login" } : {}),
|
|
84
|
+
redirect_uri: redirectUri,
|
|
85
|
+
scope: "openid profile email offline_access",
|
|
86
|
+
state,
|
|
87
|
+
...(this.config.organization && {
|
|
88
|
+
organization: this.config.organization,
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
await openBrowser(authorizationUrl.href);
|
|
92
|
+
controller.signal.throwIfAborted();
|
|
93
|
+
const tokens = await oidc.authorizationCodeGrant(configuration, await callback.promise, {
|
|
94
|
+
expectedNonce: nonce,
|
|
95
|
+
expectedState: state,
|
|
96
|
+
pkceCodeVerifier: verifier,
|
|
97
|
+
});
|
|
98
|
+
if (this.config.organization &&
|
|
99
|
+
tokens.claims()?.org_id !== this.config.organization) {
|
|
100
|
+
throw new Error("OAuth organization does not match this deployment.");
|
|
101
|
+
}
|
|
102
|
+
return tokens;
|
|
103
|
+
};
|
|
104
|
+
let tokens;
|
|
105
|
+
try {
|
|
106
|
+
tokens = await Promise.race([signIn(), interrupted]);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (signal?.aborted)
|
|
110
|
+
throw new Error("OAuth sign-in cancelled.");
|
|
111
|
+
if (controller.signal.aborted)
|
|
112
|
+
throw new Error("OAuth sign-in timed out.");
|
|
113
|
+
console.error("MCP OAuth sign-in failed", {
|
|
114
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
115
|
+
pid: process.pid,
|
|
116
|
+
});
|
|
117
|
+
throw new Error("OAuth sign-in failed. Please try again.");
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
clearTimeout(timeout);
|
|
121
|
+
signal?.removeEventListener("abort", abort);
|
|
122
|
+
abort();
|
|
123
|
+
server.closeAllConnections();
|
|
124
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
125
|
+
}
|
|
126
|
+
return this.tokens(tokens);
|
|
127
|
+
}
|
|
128
|
+
async configuration(signal) {
|
|
129
|
+
const issuer = this.httpsUrl(this.config.issuerUrl);
|
|
130
|
+
if (issuer.search)
|
|
131
|
+
throw new Error("Invalid OAuth issuer URL.");
|
|
132
|
+
const configuration = await oidc.discovery(issuer, this.config.clientId, undefined, oidc.None(), {
|
|
133
|
+
timeout: 30,
|
|
134
|
+
[oidc.customFetch]: (url, options) => (this.options.fetch ?? fetch)(url, {
|
|
135
|
+
...options,
|
|
136
|
+
// lib.dom's BodyInit rejects Uint8Array<ArrayBufferLike>; Node's fetch accepts it.
|
|
137
|
+
body: options.body,
|
|
138
|
+
...(signal && {
|
|
139
|
+
signal: AbortSignal.any([
|
|
140
|
+
signal,
|
|
141
|
+
...(options.signal ? [options.signal] : []),
|
|
142
|
+
]),
|
|
143
|
+
}),
|
|
144
|
+
}),
|
|
145
|
+
});
|
|
146
|
+
const metadata = configuration.serverMetadata();
|
|
147
|
+
for (const endpoint of [
|
|
148
|
+
metadata.authorization_endpoint,
|
|
149
|
+
metadata.token_endpoint,
|
|
150
|
+
metadata.jwks_uri,
|
|
151
|
+
]) {
|
|
152
|
+
this.httpsUrl(endpoint);
|
|
153
|
+
}
|
|
154
|
+
oidc.enableNonRepudiationChecks(configuration);
|
|
155
|
+
return configuration;
|
|
156
|
+
}
|
|
157
|
+
httpsUrl(value) {
|
|
158
|
+
const url = new URL(value ?? "");
|
|
159
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hash) {
|
|
160
|
+
throw new Error("Invalid OAuth provider URL.");
|
|
161
|
+
}
|
|
162
|
+
return url;
|
|
163
|
+
}
|
|
164
|
+
tokens(tokens, refreshToken = tokens.refresh_token) {
|
|
165
|
+
if (refreshToken !== undefined && !refreshToken.trim())
|
|
166
|
+
throw new Error("OAuth response returned an invalid refresh token.");
|
|
167
|
+
if (!tokens.access_token.trim() || tokens.token_type !== "bearer")
|
|
168
|
+
throw new Error("OAuth response did not return a usable bearer token.");
|
|
169
|
+
if (typeof tokens.expires_in !== "number" || tokens.expires_in <= 0)
|
|
170
|
+
throw new Error("OAuth response is missing a valid access token expiration.");
|
|
171
|
+
const expiresAt = (this.options.now ?? Date.now)() + tokens.expires_in * 1000;
|
|
172
|
+
if (!Number.isFinite(expiresAt))
|
|
173
|
+
throw new Error("OAuth response is missing a valid access token expiration.");
|
|
174
|
+
return {
|
|
175
|
+
accessToken: tokens.access_token,
|
|
176
|
+
expiresAt,
|
|
177
|
+
...(refreshToken !== undefined && { refreshToken }),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=native-oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-oauth.js","sourceRoot":"","sources":["../../src/auth/native-oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { type CapabilityContext } from "./lifecycle.js";
|
|
2
|
+
import type { CapabilityResult } from "./types.js";
|
|
3
|
+
export declare function listBranches(ctx: CapabilityContext, input: {
|
|
4
|
+
applicationId?: string;
|
|
5
|
+
}): Promise<CapabilityResult<{
|
|
6
|
+
applicationId: string;
|
|
7
|
+
branch: string;
|
|
8
|
+
branchingEnabled: boolean;
|
|
9
|
+
mainHead: string | null;
|
|
10
|
+
mode: import("@superblocksteam/shared").WorkspaceMode;
|
|
11
|
+
branches: {
|
|
12
|
+
name: string;
|
|
13
|
+
ownerId: string | null;
|
|
14
|
+
ownerName: string | null;
|
|
15
|
+
holderId: string | null;
|
|
16
|
+
holderName: string | null;
|
|
17
|
+
upstream: string | null;
|
|
18
|
+
ahead: number;
|
|
19
|
+
behind: number;
|
|
20
|
+
merged: boolean;
|
|
21
|
+
heldByTeammate: boolean;
|
|
22
|
+
}[];
|
|
23
|
+
}>>;
|
|
24
|
+
export declare function getBranchStatus(ctx: CapabilityContext, input: {
|
|
25
|
+
applicationId?: string;
|
|
26
|
+
}): Promise<CapabilityResult<{
|
|
27
|
+
branch: string;
|
|
28
|
+
branchHead: string | null;
|
|
29
|
+
mainHead: string | null;
|
|
30
|
+
branchingEnabled: boolean;
|
|
31
|
+
upstream: string | null;
|
|
32
|
+
ahead: number;
|
|
33
|
+
behind: number;
|
|
34
|
+
behindMain: number;
|
|
35
|
+
pendingMerge: boolean;
|
|
36
|
+
conflictCount: number;
|
|
37
|
+
conflictPaths: string[];
|
|
38
|
+
landPending: boolean;
|
|
39
|
+
hasUncommittedChanges: boolean;
|
|
40
|
+
upToDateTargets: string[];
|
|
41
|
+
mode: import("@superblocksteam/shared").WorkspaceMode;
|
|
42
|
+
applicationId: string;
|
|
43
|
+
agentInstructions?: string | undefined;
|
|
44
|
+
}>>;
|
|
45
|
+
export declare function enableBranching(ctx: CapabilityContext, input: {
|
|
46
|
+
applicationId?: string;
|
|
47
|
+
name: string;
|
|
48
|
+
}): Promise<CapabilityResult<{
|
|
49
|
+
applicationId: string;
|
|
50
|
+
created: string;
|
|
51
|
+
branch: string;
|
|
52
|
+
}>>;
|
|
53
|
+
export declare function createBranch(ctx: CapabilityContext, input: {
|
|
54
|
+
applicationId?: string;
|
|
55
|
+
base: string;
|
|
56
|
+
name: string;
|
|
57
|
+
}): Promise<CapabilityResult<{
|
|
58
|
+
applicationId: string;
|
|
59
|
+
created: string;
|
|
60
|
+
upstream: string;
|
|
61
|
+
branch: string;
|
|
62
|
+
}>>;
|
|
63
|
+
export declare function pullBranch(ctx: CapabilityContext, input: {
|
|
64
|
+
applicationId?: string;
|
|
65
|
+
target?: string;
|
|
66
|
+
}): Promise<CapabilityResult<{
|
|
67
|
+
outcome: 'up-to-date' | 'clean' | 'conflict';
|
|
68
|
+
commitId?: string;
|
|
69
|
+
contextNote: string;
|
|
70
|
+
incomingCount: number;
|
|
71
|
+
conflicts: string[];
|
|
72
|
+
applicationId: string;
|
|
73
|
+
branch: string;
|
|
74
|
+
agentInstructions?: string | undefined;
|
|
75
|
+
}>>;
|
|
76
|
+
export declare function mergeBranch(ctx: CapabilityContext, input: {
|
|
77
|
+
applicationId?: string;
|
|
78
|
+
source?: string;
|
|
79
|
+
target?: string;
|
|
80
|
+
}): Promise<CapabilityResult<Record<string, unknown>>>;
|
|
81
|
+
export declare function deleteBranch(ctx: CapabilityContext, input: {
|
|
82
|
+
applicationId?: string;
|
|
83
|
+
force: boolean;
|
|
84
|
+
name: string;
|
|
85
|
+
}): Promise<CapabilityResult<{
|
|
86
|
+
applicationId: string;
|
|
87
|
+
deleted: string;
|
|
88
|
+
branch: string;
|
|
89
|
+
}>>;
|
|
90
|
+
export declare function switchBranch(ctx: CapabilityContext, input: {
|
|
91
|
+
applicationId?: string;
|
|
92
|
+
branch: string;
|
|
93
|
+
}): Promise<CapabilityResult<Record<string, unknown>>>;
|
|
94
|
+
export declare function compareBranches(ctx: CapabilityContext, input: {
|
|
95
|
+
applicationId?: string;
|
|
96
|
+
other?: string;
|
|
97
|
+
}): Promise<CapabilityResult<Record<string, unknown>>>;
|
|
98
|
+
export declare function getCurrentPublish(ctx: CapabilityContext, input: {
|
|
99
|
+
applicationId?: string;
|
|
100
|
+
}): Promise<CapabilityResult<{
|
|
101
|
+
applicationId: string;
|
|
102
|
+
active: {
|
|
103
|
+
commitId: string;
|
|
104
|
+
branch: string | null;
|
|
105
|
+
message: string | null;
|
|
106
|
+
by: string | null;
|
|
107
|
+
byTheUser: boolean;
|
|
108
|
+
at: string;
|
|
109
|
+
status: import("@superblocksteam/shared").ActivePublishStatus;
|
|
110
|
+
} | null;
|
|
111
|
+
last: {
|
|
112
|
+
commitId: string;
|
|
113
|
+
branch: string | null;
|
|
114
|
+
message: string | null;
|
|
115
|
+
by: string | null;
|
|
116
|
+
byTheUser: boolean;
|
|
117
|
+
at: string;
|
|
118
|
+
isLive: boolean;
|
|
119
|
+
} | null;
|
|
120
|
+
}>>;
|
|
121
|
+
export declare function listVersions(ctx: CapabilityContext, input: {
|
|
122
|
+
applicationId?: string;
|
|
123
|
+
limit: number;
|
|
124
|
+
}): Promise<CapabilityResult<{
|
|
125
|
+
applicationId: string;
|
|
126
|
+
branch: string;
|
|
127
|
+
versions: {
|
|
128
|
+
commitId: string;
|
|
129
|
+
message: string;
|
|
130
|
+
author: string;
|
|
131
|
+
at: string;
|
|
132
|
+
kind: string;
|
|
133
|
+
}[];
|
|
134
|
+
}>>;
|
|
135
|
+
export declare function restoreVersion(ctx: CapabilityContext, input: {
|
|
136
|
+
applicationId?: string;
|
|
137
|
+
commitId: string;
|
|
138
|
+
}): Promise<CapabilityResult<Record<string, unknown>>>;
|
|
139
|
+
//# sourceMappingURL=branching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branching.d.ts","sourceRoot":"","sources":["../../src/capabilities/branching.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,iBAAiB,EAIvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAqB,MAAM,YAAY,CAAC;AA4HtE,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;IAyBlC;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;IA+BlC;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;IAoBhD;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;IAyB9D;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;IAmCnD;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,sDA2GpE;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;IA8BhE;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,sDAmDlD;AAID,wBAAgB,eAAe,CAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,sDAwFlD;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;IA2BlC;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;IAsBjD;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,sDAmDpD"}
|