@vymalo/opencode-oauth2 0.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/dist/cache.d.ts +9 -0
  4. package/dist/cache.js +91 -0
  5. package/dist/cache.js.map +1 -0
  6. package/dist/config.d.ts +97 -0
  7. package/dist/config.js +179 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.js +8 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/logging.d.ts +11 -0
  13. package/dist/logging.js +59 -0
  14. package/dist/logging.js.map +1 -0
  15. package/dist/model-discovery.d.ts +9 -0
  16. package/dist/model-discovery.js +74 -0
  17. package/dist/model-discovery.js.map +1 -0
  18. package/dist/model-normalization.d.ts +4 -0
  19. package/dist/model-normalization.js +86 -0
  20. package/dist/model-normalization.js.map +1 -0
  21. package/dist/oauth/browser.d.ts +1 -0
  22. package/dist/oauth/browser.js +29 -0
  23. package/dist/oauth/browser.js.map +1 -0
  24. package/dist/oauth/client.d.ts +56 -0
  25. package/dist/oauth/client.js +436 -0
  26. package/dist/oauth/client.js.map +1 -0
  27. package/dist/oauth/device-code.d.ts +22 -0
  28. package/dist/oauth/device-code.js +240 -0
  29. package/dist/oauth/device-code.js.map +1 -0
  30. package/dist/oauth/discovery.d.ts +8 -0
  31. package/dist/oauth/discovery.js +38 -0
  32. package/dist/oauth/discovery.js.map +1 -0
  33. package/dist/oauth/http-utils.d.ts +33 -0
  34. package/dist/oauth/http-utils.js +129 -0
  35. package/dist/oauth/http-utils.js.map +1 -0
  36. package/dist/oauth/local-callback.d.ts +10 -0
  37. package/dist/oauth/local-callback.js +82 -0
  38. package/dist/oauth/local-callback.js.map +1 -0
  39. package/dist/oauth/pkce.d.ts +5 -0
  40. package/dist/oauth/pkce.js +13 -0
  41. package/dist/oauth/pkce.js.map +1 -0
  42. package/dist/oauth/subject-token.d.ts +20 -0
  43. package/dist/oauth/subject-token.js +86 -0
  44. package/dist/oauth/subject-token.js.map +1 -0
  45. package/dist/opencode.d.ts +11 -0
  46. package/dist/opencode.js +347 -0
  47. package/dist/opencode.js.map +1 -0
  48. package/dist/plugin.d.ts +47 -0
  49. package/dist/plugin.js +220 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/dist/scheduler.d.ts +11 -0
  52. package/dist/scheduler.js +44 -0
  53. package/dist/scheduler.js.map +1 -0
  54. package/dist/types.d.ts +37 -0
  55. package/dist/types.js +2 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +53 -0
@@ -0,0 +1,86 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { DEFAULT_K8S_SA_TOKEN_PATH } from "../config.js";
3
+ import { readResponseBodyPreview, scrubSecrets } from "./http-utils.js";
4
+ /**
5
+ * Read the platform-supplied JWT that the plugin will present as the subject
6
+ * token (or assertion) for the `jwt_bearer` and `token_exchange` flows.
7
+ *
8
+ * Each source resolves fresh on every call — we never cache the JWT itself,
9
+ * only the OIDC access token it gets exchanged for. K8s projected SA tokens
10
+ * rotate; GHA OIDC tokens are short-lived (~10 min); both are cheap to
11
+ * re-fetch on demand.
12
+ */
13
+ export async function resolveSubjectToken(source, options = {}) {
14
+ switch (source.type) {
15
+ case "github_actions":
16
+ return resolveGithubActionsToken(source.audience, options);
17
+ case "kubernetes_sa":
18
+ return readJwtFile(source.tokenPath ?? DEFAULT_K8S_SA_TOKEN_PATH, "kubernetes_sa");
19
+ case "file":
20
+ return readJwtFile(source.path, "file");
21
+ case "env":
22
+ return resolveEnvToken(source.var, options.env ?? process.env);
23
+ }
24
+ }
25
+ async function readJwtFile(path, sourceLabel) {
26
+ let raw;
27
+ try {
28
+ raw = await readFile(path, "utf8");
29
+ }
30
+ catch (error) {
31
+ const code = error.code;
32
+ if (code === "ENOENT") {
33
+ throw new Error(`subjectTokenSource (${sourceLabel}): no file at ${path} — check the mount/path`);
34
+ }
35
+ throw new Error(`subjectTokenSource (${sourceLabel}): failed to read ${path}: ${error instanceof Error ? error.message : String(error)}`);
36
+ }
37
+ const trimmed = raw.trim();
38
+ if (trimmed.length === 0) {
39
+ throw new Error(`subjectTokenSource (${sourceLabel}): file at ${path} is empty`);
40
+ }
41
+ return trimmed;
42
+ }
43
+ function resolveEnvToken(name, env) {
44
+ const value = env[name];
45
+ if (typeof value !== "string" || value.trim().length === 0) {
46
+ throw new Error(`subjectTokenSource (env): ${name} is not set or is empty`);
47
+ }
48
+ return value.trim();
49
+ }
50
+ async function resolveGithubActionsToken(audience, options) {
51
+ const env = options.env ?? process.env;
52
+ const requestUrl = env.ACTIONS_ID_TOKEN_REQUEST_URL;
53
+ const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
54
+ if (!requestUrl || !requestToken) {
55
+ throw new Error(`subjectTokenSource (github_actions): ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN must be set — this only works inside a GitHub Actions job with \`permissions: { id-token: write }\``);
56
+ }
57
+ const url = new URL(requestUrl);
58
+ url.searchParams.set("audience", audience);
59
+ const fetchImpl = options.fetchImpl ?? fetch;
60
+ const controller = new AbortController();
61
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);
62
+ let response;
63
+ try {
64
+ response = await fetchImpl(url.toString(), {
65
+ method: "GET",
66
+ headers: {
67
+ Authorization: `Bearer ${requestToken}`,
68
+ Accept: "application/json"
69
+ },
70
+ signal: controller.signal
71
+ });
72
+ }
73
+ finally {
74
+ clearTimeout(timer);
75
+ }
76
+ if (!response.ok) {
77
+ const preview = await readResponseBodyPreview(response, 500);
78
+ throw new Error(`subjectTokenSource (github_actions): OIDC token request failed (${response.status})${preview ? `: ${scrubSecrets(preview)}` : ""}`);
79
+ }
80
+ const payload = (await response.json());
81
+ if (typeof payload.value !== "string" || payload.value.length === 0) {
82
+ throw new Error("subjectTokenSource (github_actions): response had no `value` field — GitHub may have changed the API shape");
83
+ }
84
+ return payload.value;
85
+ }
86
+ //# sourceMappingURL=subject-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subject-token.js","sourceRoot":"","sources":["../../src/oauth/subject-token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ import { type Logger } from "./logging.js";
3
+ export interface OpenCodePluginFactoryOptions {
4
+ logger?: Logger;
5
+ fetchImpl?: typeof fetch;
6
+ onAuthorizationUrl?: (url: string) => Promise<void> | void;
7
+ cacheDir?: string;
8
+ }
9
+ export declare function createOpencodeOauth2Plugin(factoryOptions?: OpenCodePluginFactoryOptions): Plugin;
10
+ export declare const OpencodeOauth2Plugin: Plugin;
11
+ export default OpencodeOauth2Plugin;
@@ -0,0 +1,347 @@
1
+ import { createJsonConsoleLogger } from "./logging.js";
2
+ import { OAuth2ModelSyncPlugin } from "./plugin.js";
3
+ const OPENAI_COMPATIBLE_NPM = "@ai-sdk/openai-compatible";
4
+ const OAUTH_OPTIONS_KEYS = ["oauth2", "oauth2ModelSync"];
5
+ const PLUGIN_SERVICE_NAME = "opencode-oauth2-plugin";
6
+ function asAuthFlow(value, source) {
7
+ if (value === undefined || value === null) {
8
+ return undefined;
9
+ }
10
+ if (value === "authorization_code" ||
11
+ value === "device_code" ||
12
+ value === "client_credentials" ||
13
+ value === "jwt_bearer" ||
14
+ value === "token_exchange") {
15
+ return value;
16
+ }
17
+ throw new Error(`${source}.authFlow must be one of "authorization_code" | "device_code" | "client_credentials" | "jwt_bearer" | "token_exchange" (received ${JSON.stringify(value)})`);
18
+ }
19
+ function asClientSecret(value, source) {
20
+ if (value === undefined || value === null) {
21
+ return undefined;
22
+ }
23
+ if (typeof value !== "string" || value.length === 0) {
24
+ throw new Error(`${source}.clientSecret must be a non-empty string when provided`);
25
+ }
26
+ return value;
27
+ }
28
+ function asRedirectPort(value, source) {
29
+ if (value === undefined || value === null) {
30
+ return undefined;
31
+ }
32
+ if (typeof value === "number" && Number.isInteger(value) && value > 0 && value < 65536) {
33
+ return value;
34
+ }
35
+ throw new Error(`${source}.redirectPort must be an integer in [1, 65535] (received ${JSON.stringify(value)})`);
36
+ }
37
+ function asRecord(value) {
38
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
39
+ return undefined;
40
+ }
41
+ return value;
42
+ }
43
+ function asString(value) {
44
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
45
+ }
46
+ function asStringArray(value) {
47
+ if (Array.isArray(value)) {
48
+ const normalized = value
49
+ .map((entry) => asString(entry))
50
+ .filter((entry) => Boolean(entry));
51
+ return normalized.length > 0 ? normalized : undefined;
52
+ }
53
+ if (typeof value === "string") {
54
+ const normalized = value
55
+ .split(/[\s,]+/g)
56
+ .map((entry) => entry.trim())
57
+ .filter((entry) => entry.length > 0);
58
+ return normalized.length > 0 ? normalized : undefined;
59
+ }
60
+ return undefined;
61
+ }
62
+ function asStringMap(value) {
63
+ const record = asRecord(value);
64
+ if (!record) {
65
+ return undefined;
66
+ }
67
+ const normalized = {};
68
+ for (const [key, raw] of Object.entries(record)) {
69
+ const text = asString(raw);
70
+ if (!text) {
71
+ continue;
72
+ }
73
+ normalized[key] = text;
74
+ }
75
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
76
+ }
77
+ function parseOAuthExtension(provider) {
78
+ const options = asRecord(provider.options);
79
+ if (!options) {
80
+ return undefined;
81
+ }
82
+ let raw;
83
+ for (const key of OAUTH_OPTIONS_KEYS) {
84
+ raw = asRecord(options[key]);
85
+ if (raw) {
86
+ break;
87
+ }
88
+ }
89
+ if (!raw) {
90
+ return undefined;
91
+ }
92
+ const issuer = asString(raw.issuer);
93
+ const clientId = asString(raw.clientId);
94
+ const scopes = asStringArray(raw.scopes);
95
+ if (!issuer || !clientId || !scopes) {
96
+ return undefined;
97
+ }
98
+ const syncIntervalMinutes = typeof raw.syncIntervalMinutes === "number" &&
99
+ Number.isFinite(raw.syncIntervalMinutes) &&
100
+ raw.syncIntervalMinutes > 0
101
+ ? raw.syncIntervalMinutes
102
+ : undefined;
103
+ return {
104
+ issuer,
105
+ clientId,
106
+ clientSecret: asClientSecret(raw.clientSecret, "provider.options.oauth2"),
107
+ scopes,
108
+ syncIntervalMinutes,
109
+ nameOverrides: asStringMap(raw.nameOverrides),
110
+ authorizationEndpoint: asString(raw.authorizationEndpoint),
111
+ tokenEndpoint: asString(raw.tokenEndpoint),
112
+ deviceAuthorizationEndpoint: asString(raw.deviceAuthorizationEndpoint),
113
+ jwksUri: asString(raw.jwksUri),
114
+ redirectPort: asRedirectPort(raw.redirectPort, "provider.options.oauth2"),
115
+ authFlow: asAuthFlow(raw.authFlow, "provider.options.oauth2"),
116
+ // Deep validation of subjectTokenSource happens in validateConfig — this
117
+ // layer just passes the raw value through so error messages reference
118
+ // the canonical config path.
119
+ subjectTokenSource: raw.subjectTokenSource,
120
+ tokenExchangeAudience: asString(raw.tokenExchangeAudience)
121
+ };
122
+ }
123
+ function parsePluginConfigServers(config, logger) {
124
+ const root = asRecord(config);
125
+ const pluginConfig = asRecord(root?.pluginConfig);
126
+ const oauth2ModelSync = asRecord(pluginConfig?.oauth2ModelSync);
127
+ const servers = oauth2ModelSync?.servers;
128
+ if (!Array.isArray(servers)) {
129
+ return [];
130
+ }
131
+ const parsed = [];
132
+ for (const [index, rawServer] of servers.entries()) {
133
+ const entry = asRecord(rawServer);
134
+ if (!entry) {
135
+ logger.warn("plugin_config_server_invalid", { index });
136
+ continue;
137
+ }
138
+ const id = asString(entry.id);
139
+ const name = asString(entry.name) ?? id;
140
+ const issuer = asString(entry.issuer);
141
+ const baseURL = asString(entry.baseURL);
142
+ const clientId = asString(entry.clientId);
143
+ const scopes = asStringArray(entry.scopes);
144
+ if (!id || !issuer || !baseURL || !clientId || !scopes) {
145
+ logger.warn("plugin_config_server_missing_fields", { index, id: id ?? "unknown" });
146
+ continue;
147
+ }
148
+ const syncIntervalMinutes = typeof entry.syncIntervalMinutes === "number" &&
149
+ Number.isFinite(entry.syncIntervalMinutes) &&
150
+ entry.syncIntervalMinutes > 0
151
+ ? entry.syncIntervalMinutes
152
+ : undefined;
153
+ const sourceLabel = `pluginConfig.oauth2ModelSync.servers[${index}] (id=${id})`;
154
+ parsed.push({
155
+ id,
156
+ name: name ?? id,
157
+ issuer,
158
+ baseURL,
159
+ clientId,
160
+ clientSecret: asClientSecret(entry.clientSecret, sourceLabel),
161
+ scopes,
162
+ syncIntervalMinutes,
163
+ nameOverrides: asStringMap(entry.nameOverrides),
164
+ authorizationEndpoint: asString(entry.authorizationEndpoint),
165
+ tokenEndpoint: asString(entry.tokenEndpoint),
166
+ deviceAuthorizationEndpoint: asString(entry.deviceAuthorizationEndpoint),
167
+ jwksUri: asString(entry.jwksUri),
168
+ redirectPort: asRedirectPort(entry.redirectPort, sourceLabel),
169
+ authFlow: asAuthFlow(entry.authFlow, sourceLabel),
170
+ subjectTokenSource: entry.subjectTokenSource,
171
+ tokenExchangeAudience: asString(entry.tokenExchangeAudience)
172
+ });
173
+ }
174
+ return parsed;
175
+ }
176
+ function collectManagedProviders(config, logger) {
177
+ const providers = (config.provider ??= {});
178
+ const byId = new Map();
179
+ for (const server of parsePluginConfigServers(config, logger)) {
180
+ const providerConfig = (providers[server.id] ??= {});
181
+ const providerOptions = asRecord(providerConfig.options) ?? {};
182
+ providerConfig.npm = OPENAI_COMPATIBLE_NPM;
183
+ providerConfig.name = asString(providerConfig.name) ?? server.name ?? server.id;
184
+ providerConfig.options = {
185
+ ...providerOptions,
186
+ baseURL: server.baseURL
187
+ };
188
+ byId.set(server.id, {
189
+ ...server,
190
+ name: providerConfig.name ?? server.name ?? server.id
191
+ });
192
+ }
193
+ for (const [providerId, providerConfig] of Object.entries(providers)) {
194
+ const extension = parseOAuthExtension(providerConfig);
195
+ if (!extension) {
196
+ continue;
197
+ }
198
+ const options = asRecord(providerConfig.options) ?? {};
199
+ const baseURL = asString(options.baseURL);
200
+ if (!baseURL) {
201
+ logger.warn("provider_skipped_missing_baseurl", { providerId });
202
+ continue;
203
+ }
204
+ const providerName = asString(providerConfig.name) ?? providerId;
205
+ providerConfig.npm = OPENAI_COMPATIBLE_NPM;
206
+ providerConfig.name = providerName;
207
+ providerConfig.options = {
208
+ ...options,
209
+ baseURL
210
+ };
211
+ byId.set(providerId, {
212
+ id: providerId,
213
+ name: providerName,
214
+ issuer: extension.issuer,
215
+ baseURL,
216
+ clientId: extension.clientId,
217
+ clientSecret: extension.clientSecret,
218
+ scopes: extension.scopes,
219
+ syncIntervalMinutes: extension.syncIntervalMinutes,
220
+ nameOverrides: extension.nameOverrides,
221
+ authorizationEndpoint: extension.authorizationEndpoint,
222
+ tokenEndpoint: extension.tokenEndpoint,
223
+ deviceAuthorizationEndpoint: extension.deviceAuthorizationEndpoint,
224
+ jwksUri: extension.jwksUri,
225
+ redirectPort: extension.redirectPort,
226
+ authFlow: extension.authFlow,
227
+ subjectTokenSource: extension.subjectTokenSource,
228
+ tokenExchangeAudience: extension.tokenExchangeAudience
229
+ });
230
+ }
231
+ return { servers: [...byId.values()] };
232
+ }
233
+ function runtimeSignature(config) {
234
+ const sorted = [...config.servers].sort((a, b) => a.id.localeCompare(b.id));
235
+ return JSON.stringify(sorted);
236
+ }
237
+ function mergeDiscoveredModels(providerConfig, models) {
238
+ const existingModels = (providerConfig.models ?? {});
239
+ const merged = { ...existingModels };
240
+ for (const model of models) {
241
+ const existingModel = existingModels[model.id] ?? {};
242
+ merged[model.id] = {
243
+ ...existingModel,
244
+ id: model.id,
245
+ name: model.displayName
246
+ };
247
+ }
248
+ providerConfig.models = merged;
249
+ }
250
+ function createOpenCodeLogger(client) {
251
+ const fallback = createJsonConsoleLogger("info");
252
+ const write = (level, event, fields) => {
253
+ fallback[level](event, fields);
254
+ void client.app
255
+ .log({
256
+ body: {
257
+ service: PLUGIN_SERVICE_NAME,
258
+ level,
259
+ message: event,
260
+ extra: fields
261
+ }
262
+ })
263
+ .catch(() => {
264
+ // Best-effort forwarding; console logger is the reliable fallback.
265
+ });
266
+ };
267
+ return {
268
+ debug(event, fields) {
269
+ write("debug", event, fields);
270
+ },
271
+ info(event, fields) {
272
+ write("info", event, fields);
273
+ },
274
+ warn(event, fields) {
275
+ write("warn", event, fields);
276
+ },
277
+ error(event, fields) {
278
+ write("error", event, fields);
279
+ }
280
+ };
281
+ }
282
+ export function createOpencodeOauth2Plugin(factoryOptions = {}) {
283
+ return async ({ client }) => {
284
+ const logger = factoryOptions.logger ?? createOpenCodeLogger(client);
285
+ const state = {
286
+ runtime: undefined,
287
+ signature: undefined,
288
+ managedProviderIds: new Set()
289
+ };
290
+ return {
291
+ config: async (config) => {
292
+ const managed = collectManagedProviders(config, logger);
293
+ if (managed.servers.length === 0) {
294
+ state.runtime?.stop();
295
+ state.runtime = undefined;
296
+ state.signature = undefined;
297
+ state.managedProviderIds = new Set();
298
+ return;
299
+ }
300
+ const pluginConfig = {
301
+ servers: managed.servers,
302
+ cacheNamespace: "opencode-oauth2-model-sync"
303
+ };
304
+ const signature = runtimeSignature(pluginConfig);
305
+ if (!state.runtime || state.signature !== signature) {
306
+ state.runtime?.stop();
307
+ state.runtime = new OAuth2ModelSyncPlugin(pluginConfig, {
308
+ logger,
309
+ fetchImpl: factoryOptions.fetchImpl,
310
+ onAuthorizationUrl: factoryOptions.onAuthorizationUrl,
311
+ cacheDir: factoryOptions.cacheDir
312
+ });
313
+ await state.runtime.initialize();
314
+ await state.runtime.start({ warmup: true });
315
+ state.signature = signature;
316
+ }
317
+ state.managedProviderIds = new Set(managed.servers.map((server) => server.id));
318
+ const providers = (config.provider ??= {});
319
+ for (const providerId of state.managedProviderIds) {
320
+ const providerConfig = providers[providerId];
321
+ if (!providerConfig) {
322
+ continue;
323
+ }
324
+ const models = state.runtime.getServerModels(providerId);
325
+ if (models.length === 0) {
326
+ continue;
327
+ }
328
+ mergeDiscoveredModels(providerConfig, models);
329
+ }
330
+ },
331
+ "chat.headers": async (input, output) => {
332
+ const providerId = input.model?.providerID ?? input.provider?.info?.id;
333
+ if (!providerId || !state.runtime || !state.managedProviderIds.has(providerId)) {
334
+ return;
335
+ }
336
+ const token = await state.runtime.ensureAccessToken(providerId);
337
+ output.headers.Authorization = `${token.tokenType || "Bearer"} ${token.accessToken}`;
338
+ if (state.runtime.getServerModels(providerId).length === 0) {
339
+ void state.runtime.syncServer(providerId);
340
+ }
341
+ }
342
+ };
343
+ };
344
+ }
345
+ export const OpencodeOauth2Plugin = createOpencodeOauth2Plugin();
346
+ export default OpencodeOauth2Plugin;
347
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,uBAAuB,EAA+B,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAC1D,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,CAAU,CAAC;AAClE,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAwBrD,SAAS,UAAU,CAAC,KAAc,EAAE,MAAc;IAChD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IACE,KAAK,KAAK,oBAAoB;QAC9B,KAAK,KAAK,aAAa;QACvB,KAAK,KAAK,oBAAoB;QAC9B,KAAK,KAAK,YAAY;QACtB,KAAK,KAAK,gBAAgB,EAC1B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,KAAK,CACb,GAAG,MAAM,oIAAoI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CACtK,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAc,EAAE,MAAc;IACpD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,wDAAwD,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,KAAc,EAAE,MAAc;IACpD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;QACvF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,KAAK,CACb,GAAG,MAAM,4DAA4D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAC9F,CAAC;AACJ,CAAC;AAmBD,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAgC,CAAC;AAC1C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACzF,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,KAAK;aACrB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aAC/B,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAEtD,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,KAAK;aACrB,KAAK,CAAC,SAAS,CAAC;aAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;aAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEvC,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,SAAS;QACX,CAAC;QAED,UAAU,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgC;IAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,GAAwC,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,GAAG,EAAE,CAAC;YACR,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEzC,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,mBAAmB,GACvB,OAAO,GAAG,CAAC,mBAAmB,KAAK,QAAQ;QAC3C,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACxC,GAAG,CAAC,mBAAmB,GAAG,CAAC;QACzB,CAAC,CAAC,GAAG,CAAC,mBAAmB;QACzB,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,MAAM;QACN,QAAQ;QACR,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,yBAAyB,CAAC;QACzE,MAAM;QACN,mBAAmB;QACnB,aAAa,EAAE,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC;QAC7C,qBAAqB,EAAE,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC;QAC1D,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1C,2BAA2B,EAAE,QAAQ,CAAC,GAAG,CAAC,2BAA2B,CAAC;QACtE,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9B,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,yBAAyB,CAAC;QACzE,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,yBAAyB,CAAC;QAC7D,yEAAyE;QACzE,sEAAsE;QACtE,6BAA6B;QAC7B,kBAAkB,EAAE,GAAG,CAAC,kBAAoD;QAC5E,qBAAqB,EAAE,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC;KAC3D,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAC/B,MAAsB,EACtB,MAAc;IAEd,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAClD,MAAM,eAAe,GAAG,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,eAAe,EAAE,OAAO,CAAC;IAEzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACvD,SAAS;QACX,CAAC;QAED,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAE3C,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,SAAS,EAAE,CAAC,CAAC;YACnF,SAAS;QACX,CAAC;QAED,MAAM,mBAAmB,GACvB,OAAO,KAAK,CAAC,mBAAmB,KAAK,QAAQ;YAC7C,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;YAC1C,KAAK,CAAC,mBAAmB,GAAG,CAAC;YAC3B,CAAC,CAAC,KAAK,CAAC,mBAAmB;YAC3B,CAAC,CAAC,SAAS,CAAC;QAEhB,MAAM,WAAW,GAAG,wCAAwC,KAAK,SAAS,EAAE,GAAG,CAAC;QAEhF,MAAM,CAAC,IAAI,CAAC;YACV,EAAE;YACF,IAAI,EAAE,IAAI,IAAI,EAAE;YAChB,MAAM;YACN,OAAO;YACP,QAAQ;YACR,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC,YAAY,EAAE,WAAW,CAAC;YAC7D,MAAM;YACN,mBAAmB;YACnB,aAAa,EAAE,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC;YAC/C,qBAAqB,EAAE,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC;YAC5D,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC;YAC5C,2BAA2B,EAAE,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC;YACxE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;YAChC,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC,YAAY,EAAE,WAAW,CAAC;YAC7D,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC;YACjD,kBAAkB,EAAE,KAAK,CAAC,kBAAoD;YAC9E,qBAAqB,EAAE,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAsB,EAAE,MAAc;IACrE,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkC,CAAC;IAEvD,KAAK,MAAM,MAAM,IAAI,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QAC9D,MAAM,cAAc,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;QACrD,MAAM,eAAe,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAE/D,cAAc,CAAC,GAAG,GAAG,qBAAqB,CAAC;QAC3C,cAAc,CAAC,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC;QAChF,cAAc,CAAC,OAAO,GAAG;YACvB,GAAG,eAAe;YAClB,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE;YAClB,GAAG,MAAM;YACT,IAAI,EAAE,cAAc,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE;SACtD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrE,MAAM,SAAS,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YAChE,SAAS;QACX,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC;QACjE,cAAc,CAAC,GAAG,GAAG,qBAAqB,CAAC;QAC3C,cAAc,CAAC,IAAI,GAAG,YAAY,CAAC;QACnC,cAAc,CAAC,OAAO,GAAG;YACvB,GAAG,OAAO;YACV,OAAO;SACR,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE;YACnB,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,OAAO;YACP,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,mBAAmB,EAAE,SAAS,CAAC,mBAAmB;YAClD,aAAa,EAAE,SAAS,CAAC,aAAa;YACtC,qBAAqB,EAAE,SAAS,CAAC,qBAAqB;YACtD,aAAa,EAAE,SAAS,CAAC,aAAa;YACtC,2BAA2B,EAAE,SAAS,CAAC,2BAA2B;YAClE,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;YAChD,qBAAqB,EAAE,SAAS,CAAC,qBAAqB;SACvD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAkC;IAC1D,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,qBAAqB,CAC5B,cAAsC,EACtC,MAAkD;IAElD,MAAM,cAAc,GAAG,CAAC,cAAc,CAAC,MAAM,IAAI,EAAE,CAAwC,CAAC;IAC5F,MAAM,MAAM,GAAwC,EAAE,GAAG,cAAc,EAAE,CAAC;IAE1E,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;YACjB,GAAG,aAAa;YAChB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,WAAW;SACxB,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC;AACjC,CAAC;AAED,SAAS,oBAAoB,CAAC,MAA6B;IACzD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,CAAC,KAA0C,EAAE,KAAa,EAAE,MAAkB,EAAE,EAAE;QAC9F,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAE/B,KAAK,MAAM,CAAC,GAAG;aACZ,GAAG,CAAC;YACH,IAAI,EAAE;gBACJ,OAAO,EAAE,mBAAmB;gBAC5B,KAAK;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,MAAM;aACd;SACF,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,mEAAmE;QACrE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,KAAK,EAAE,MAAM;YACjB,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,MAAM;YAChB,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,MAAM;YAChB,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,KAAK,EAAE,MAAM;YACjB,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,iBAA+C,EAAE;IAEjD,OAAO,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAErE,MAAM,KAAK,GAAiB;YAC1B,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,SAAS;YACpB,kBAAkB,EAAE,IAAI,GAAG,EAAU;SACtC,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACvB,MAAM,OAAO,GAAG,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAExD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACjC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;oBACtB,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;oBAC1B,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;oBAC5B,KAAK,CAAC,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;oBAC7C,OAAO;gBACT,CAAC;gBAED,MAAM,YAAY,GAA+B;oBAC/C,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,cAAc,EAAE,4BAA4B;iBAC7C,CAAC;gBAEF,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;gBACjD,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBACpD,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;oBAEtB,KAAK,CAAC,OAAO,GAAG,IAAI,qBAAqB,CAAC,YAAY,EAAE;wBACtD,MAAM;wBACN,SAAS,EAAE,cAAc,CAAC,SAAS;wBACnC,kBAAkB,EAAE,cAAc,CAAC,kBAAkB;wBACrD,QAAQ,EAAE,cAAc,CAAC,QAAQ;qBAClC,CAAC,CAAC;oBAEH,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;oBACjC,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC5C,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;gBAC9B,CAAC;gBAED,KAAK,CAAC,kBAAkB,GAAG,IAAI,GAAG,CAAS,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBAEvF,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;gBAC3C,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;oBAClD,MAAM,cAAc,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;oBAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;wBACpB,SAAS;oBACX,CAAC;oBAED,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;oBACzD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACxB,SAAS;oBACX,CAAC;oBAED,qBAAqB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;YACD,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACtC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;gBACvE,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/E,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;gBAChE,MAAM,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,QAAQ,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;gBAErF,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3D,KAAK,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,0BAA0B,EAAE,CAAC;AAEjE,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { type OAuth2ModelSyncConfigInput } from "./config.js";
2
+ import { type Logger } from "./logging.js";
3
+ import type { NormalizedModel, ServerSnapshot, TokenSet } from "./types.js";
4
+ interface StartOptions {
5
+ warmup?: boolean;
6
+ /**
7
+ * Whether warmup is allowed to open a browser / start the device-code poll
8
+ * for first-time auth on uncached `authorization_code` / `device_code`
9
+ * providers. Defaults to "TTY detected" — interactive in real terminals,
10
+ * non-interactive in CI/headless contexts so startup never hangs on a
11
+ * callback that will never arrive.
12
+ */
13
+ interactive?: boolean;
14
+ }
15
+ export interface PluginOptions {
16
+ logger?: Logger;
17
+ fetchImpl?: typeof fetch;
18
+ onAuthorizationUrl?: (url: string) => Promise<void> | void;
19
+ cacheDir?: string;
20
+ }
21
+ export declare class OAuth2ModelSyncPlugin {
22
+ private readonly configInput;
23
+ private readonly options;
24
+ private readonly logger;
25
+ private readonly config;
26
+ private readonly cacheStore;
27
+ private readonly runtimeByServer;
28
+ private initialized;
29
+ private started;
30
+ constructor(configInput: OAuth2ModelSyncConfigInput, options?: PluginOptions);
31
+ initialize(): Promise<void>;
32
+ start(options?: StartOptions): Promise<void>;
33
+ stop(): void;
34
+ syncAll(): Promise<ServerSnapshot[]>;
35
+ syncServer(serverId: string, options?: {
36
+ interactive?: boolean;
37
+ }): Promise<ServerSnapshot>;
38
+ ensureAccessToken(serverId: string): Promise<TokenSet>;
39
+ ensureServerReady(serverId: string): Promise<ServerSnapshot>;
40
+ getServerModels(serverId: string): NormalizedModel[];
41
+ getProviderModelMap(serverId: string): Record<string, {
42
+ name: string;
43
+ }>;
44
+ getCachedToken(serverId: string): TokenSet | undefined;
45
+ private requireServerConfig;
46
+ }
47
+ export {};