@providerkit/core 0.17.2 → 0.21.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 +12 -4
- package/dist/auth/device.d.ts +34 -0
- package/dist/auth/device.d.ts.map +1 -0
- package/dist/auth/device.js +85 -0
- package/dist/auth/device.js.map +1 -0
- package/dist/auth/flows.d.ts +36 -0
- package/dist/auth/flows.d.ts.map +1 -0
- package/dist/auth/flows.js +392 -0
- package/dist/auth/flows.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth.d.ts +92 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +148 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/token-source.d.ts +30 -0
- package/dist/auth/token-source.d.ts.map +1 -0
- package/dist/auth/token-source.js +61 -0
- package/dist/auth/token-source.js.map +1 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +17 -1
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/presets.d.ts +78 -23
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +61 -22
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts +3 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +10 -1
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/factory.d.ts +8 -2
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +46 -9
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +3 -0
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts +8 -2
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +41 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts +7 -1
- package/dist/providers/responses.d.ts.map +1 -1
- package/dist/providers/responses.js +48 -6
- package/dist/providers/responses.js.map +1 -1
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -5
- package/dist/types.js.map +1 -1
- package/package.json +5 -1
- package/src/auth/device.ts +137 -0
- package/src/auth/flows.ts +526 -0
- package/src/auth/index.ts +7 -0
- package/src/auth/oauth.ts +226 -0
- package/src/auth/token-source.ts +76 -0
- package/src/context.ts +16 -1
- package/src/errors.ts +3 -0
- package/src/presets.ts +90 -24
- package/src/providers/anthropic.ts +17 -1
- package/src/providers/factory.ts +76 -11
- package/src/providers/gemini.ts +7 -0
- package/src/providers/openai.ts +50 -2
- package/src/providers/responses.ts +60 -6
- package/src/types.ts +49 -5
package/README.md
CHANGED
|
@@ -88,14 +88,21 @@ const provider = createPresetProvider("opencode-go", { apiKey });
|
|
|
88
88
|
|
|
89
89
|
By default it tries `mimo-v2.6-flash`, then `mimo-v2.5`, `glm-5.3-flash`,
|
|
90
90
|
`qwen3.8-flash` and `longcat-2.0`. Pass `models: [...]` to set your own order, and
|
|
91
|
-
`fallbacks` to add another provider after the last model.
|
|
92
|
-
|
|
91
|
+
`fallbacks` to add another provider after the last model.
|
|
92
|
+
|
|
93
|
+
Go serves three wires, and the preset picks one from the model id: `minimax-` and `qwen`
|
|
94
|
+
models on Anthropic Messages, `gpt-`, `grok-` and `muse-spark-` models on Responses, and
|
|
95
|
+
everything else on chat completions. A chain can mix them:
|
|
93
96
|
|
|
94
97
|
```ts
|
|
95
|
-
const
|
|
98
|
+
const provider = createPresetProvider("opencode-go", {
|
|
99
|
+
apiKey,
|
|
100
|
+
models: ["muse-spark-1.3-contributor", "mimo-v2.5"],
|
|
101
|
+
});
|
|
96
102
|
```
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
A per-call `model` on a different wire than the provider's own is refused with an
|
|
105
|
+
`invalid` error, before any request. Muse Contributor supports text, images, strict JSON
|
|
99
106
|
Schema and parallel tools, but only automatic tool choice; `toolChoice: "none"` is encoded
|
|
100
107
|
by sending no tools. Contributor requests may be used to improve Meta products and require
|
|
101
108
|
the workspace to allow those endpoints.
|
|
@@ -124,6 +131,7 @@ drift.
|
|
|
124
131
|
| [Tools](https://providerkit.dev/guides/tools/) | Tool kernel, truncated-argument salvage, zod |
|
|
125
132
|
| [Context and compaction](https://providerkit.dev/guides/context/) | When to compact, and where to cut |
|
|
126
133
|
| [Usage and cost](https://providerkit.dev/guides/usage/) | Reconciling cache tokens, cost, savings |
|
|
134
|
+
| [Sign in to a subscription](https://providerkit.dev/guides/auth/) | Device code and PKCE sign-in, token refresh |
|
|
127
135
|
| [Jev decisions](https://providerkit.dev/guides/jev/) | TypeSafe's decision model on four hosts |
|
|
128
136
|
|
|
129
137
|
The [API reference](https://providerkit.dev/reference/) is generated from the source, so it
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type AuthHost } from "./oauth.ts";
|
|
2
|
+
/** Where a vendor's device flow lives, and what it wants on the wire. */
|
|
3
|
+
export interface DeviceEndpoint {
|
|
4
|
+
/** POST here to get a user code. */
|
|
5
|
+
deviceUrl: string;
|
|
6
|
+
/** POST here, again and again, until the user approves. */
|
|
7
|
+
tokenUrl: string;
|
|
8
|
+
clientId: string;
|
|
9
|
+
/** Sent with the code request, for vendors that want scopes. */
|
|
10
|
+
scope?: string;
|
|
11
|
+
/** Extra fields on the code request only (xAI wants a `referrer`). */
|
|
12
|
+
extra?: Record<string, string>;
|
|
13
|
+
encode: "form" | "json";
|
|
14
|
+
}
|
|
15
|
+
/** What the user must do, and how long we keep asking. */
|
|
16
|
+
export interface DevicePrompt {
|
|
17
|
+
/** Show it as is: it must match what the vendor's page displays. */
|
|
18
|
+
userCode: string;
|
|
19
|
+
/** The approval page, with the code filled in when the vendor offers that. */
|
|
20
|
+
verificationUrl: string;
|
|
21
|
+
deviceCode: string;
|
|
22
|
+
intervalMs: number;
|
|
23
|
+
expiresAt: number;
|
|
24
|
+
}
|
|
25
|
+
/** Step 1: ask the vendor for a code the user can approve on the web. */
|
|
26
|
+
export declare function requestDeviceCode(host: AuthHost, endpoint: DeviceEndpoint): Promise<DevicePrompt>;
|
|
27
|
+
/**
|
|
28
|
+
* Step 2: poll until the user approves, and return the raw token body. Turning
|
|
29
|
+
* it into a credential is the caller's job, because the bodies differ: GitHub
|
|
30
|
+
* answers with a bare token and no expiry, Meta with an identity token that
|
|
31
|
+
* still has to be traded for a key.
|
|
32
|
+
*/
|
|
33
|
+
export declare function pollDeviceToken(host: AuthHost, endpoint: DeviceEndpoint, prompt: DevicePrompt, signal: AbortSignal): Promise<Record<string, unknown>>;
|
|
34
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/auth/device.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuD,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAShG,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,YAAY,CAAC,CA6BvB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsClC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// RFC 8628 device authorization: the sign-in that shows a code instead of
|
|
2
|
+
// bouncing through a redirect. Kimi, GitHub Copilot, xAI and Meta all use it.
|
|
3
|
+
import { SignInError, authError, num, postToken, str, webUrl } from "./oauth.js";
|
|
4
|
+
/** RFC 8628: a `slow_down` answer adds this to the poll interval. */
|
|
5
|
+
const SLOW_DOWN_STEP_MS = 5000;
|
|
6
|
+
/** The poll never goes faster than this, whatever the vendor says. */
|
|
7
|
+
const MIN_INTERVAL_MS = 1000;
|
|
8
|
+
/** A vendor that leaves out `expires_in` gets this. */
|
|
9
|
+
const DEFAULT_EXPIRES_SEC = 900;
|
|
10
|
+
/** Step 1: ask the vendor for a code the user can approve on the web. */
|
|
11
|
+
export async function requestDeviceCode(host, endpoint) {
|
|
12
|
+
const body = await postToken(host, endpoint.deviceUrl, {
|
|
13
|
+
client_id: endpoint.clientId,
|
|
14
|
+
...(endpoint.scope ? { scope: endpoint.scope } : {}),
|
|
15
|
+
...endpoint.extra,
|
|
16
|
+
}, { encode: endpoint.encode });
|
|
17
|
+
const userCode = str(body.user_code);
|
|
18
|
+
const deviceCode = str(body.device_code);
|
|
19
|
+
// The complete URL carries the code, so there is nothing to type.
|
|
20
|
+
const verificationUrl = webUrl(str(body.verification_uri_complete)) ?? webUrl(str(body.verification_uri));
|
|
21
|
+
if (!userCode || !deviceCode || !verificationUrl) {
|
|
22
|
+
throw authError("device_response_invalid", "The sign-in server's reply has no code, device code or http(s) approval page.");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
userCode,
|
|
26
|
+
verificationUrl,
|
|
27
|
+
deviceCode,
|
|
28
|
+
intervalMs: Math.max(MIN_INTERVAL_MS, (num(body.interval) ?? 5) * 1000),
|
|
29
|
+
expiresAt: Date.now() + (num(body.expires_in) ?? DEFAULT_EXPIRES_SEC) * 1000,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Step 2: poll until the user approves, and return the raw token body. Turning
|
|
34
|
+
* it into a credential is the caller's job, because the bodies differ: GitHub
|
|
35
|
+
* answers with a bare token and no expiry, Meta with an identity token that
|
|
36
|
+
* still has to be traded for a key.
|
|
37
|
+
*/
|
|
38
|
+
export async function pollDeviceToken(host, endpoint, prompt, signal) {
|
|
39
|
+
let waitMs = prompt.intervalMs;
|
|
40
|
+
while (Date.now() < prompt.expiresAt) {
|
|
41
|
+
await sleep(waitMs, signal);
|
|
42
|
+
// Pending is the normal answer for most of the loop, and GitHub sends it
|
|
43
|
+
// as a 200 with an `error` field, so the body decides, never the status.
|
|
44
|
+
const body = await postToken(host, endpoint.tokenUrl, {
|
|
45
|
+
client_id: endpoint.clientId,
|
|
46
|
+
device_code: prompt.deviceCode,
|
|
47
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
48
|
+
}, { encode: endpoint.encode, allowErrorBody: true });
|
|
49
|
+
if (str(body.access_token))
|
|
50
|
+
return body;
|
|
51
|
+
switch (str(body.error)) {
|
|
52
|
+
case "authorization_pending":
|
|
53
|
+
break;
|
|
54
|
+
case "slow_down":
|
|
55
|
+
// Honour the longer of our step and an interval the server names.
|
|
56
|
+
waitMs = Math.max(waitMs + SLOW_DOWN_STEP_MS, (num(body.interval) ?? 0) * 1000);
|
|
57
|
+
break;
|
|
58
|
+
case "access_denied":
|
|
59
|
+
case "authorization_denied":
|
|
60
|
+
throw new SignInError("denied");
|
|
61
|
+
case "expired_token":
|
|
62
|
+
throw new SignInError("expired");
|
|
63
|
+
default:
|
|
64
|
+
throw authError("token_refused", `The sign-in server refused the request: ${str(body.error_description) ?? str(body.error) ?? "no reason given"}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
throw new SignInError("expired");
|
|
68
|
+
}
|
|
69
|
+
/** A delay that a cancelled sign-in cuts short. */
|
|
70
|
+
function sleep(ms, signal) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
if (signal.aborted)
|
|
73
|
+
return reject(new SignInError("cancelled"));
|
|
74
|
+
const onAbort = () => {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
reject(new SignInError("cancelled"));
|
|
77
|
+
};
|
|
78
|
+
const timer = setTimeout(() => {
|
|
79
|
+
signal.removeEventListener("abort", onAbort);
|
|
80
|
+
resolve();
|
|
81
|
+
}, ms);
|
|
82
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/auth/device.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type AuthHost, type Credential } from "./oauth.ts";
|
|
2
|
+
/** What the user must do on the vendor's page to finish signing in. */
|
|
3
|
+
export interface SignInPrompt {
|
|
4
|
+
/** The approval page. The host has already been asked to open it. */
|
|
5
|
+
url: string;
|
|
6
|
+
/** Device-code flows only: the code that page asks for. */
|
|
7
|
+
userCode?: string;
|
|
8
|
+
}
|
|
9
|
+
/** One vendor's two operations: sign in once, then renew. */
|
|
10
|
+
export interface AuthFlow {
|
|
11
|
+
signIn(signal: AbortSignal, onPrompt: (prompt: SignInPrompt) => void): Promise<Credential>;
|
|
12
|
+
/** Trades the stored credential for a fresh one. Both tokens may rotate, so
|
|
13
|
+
* save the result before you use it. */
|
|
14
|
+
refresh(credential: Credential): Promise<Credential>;
|
|
15
|
+
}
|
|
16
|
+
export type AuthFlowId = "chatgpt" | "kimi-plan" | "grok" | "github-copilot" | "meta" | "openrouter";
|
|
17
|
+
export declare function createAuthFlow(id: AuthFlowId, host: AuthHost): AuthFlow;
|
|
18
|
+
/** The authorize URL to open. Exported so a test can pin the exact params. */
|
|
19
|
+
export declare function chatgptAuthorizeUrl(challenge: string, state: string): string;
|
|
20
|
+
/** The `ChatGPT-Account-Id` the Codex backend requires. OpenAI puts it at
|
|
21
|
+
* `chatgpt_account_id`, under `https://api.openai.com/auth`, or as
|
|
22
|
+
* `organizations[0].id`, depending on the token. */
|
|
23
|
+
export declare function chatgptAccountIdFromToken(token?: string): string | undefined;
|
|
24
|
+
/** An individual seat's host. Other plans get their own, named by the token. */
|
|
25
|
+
export declare const COPILOT_DEFAULT_BASE_URL = "https://api.individual.githubcopilot.com";
|
|
26
|
+
/**
|
|
27
|
+
* The editor headers Copilot's gate wants on every call.
|
|
28
|
+
*
|
|
29
|
+
* `turn` matters for the bill. GitHub charges one premium request per
|
|
30
|
+
* user-started turn and lets the agent's own follow-ups ride free, and
|
|
31
|
+
* `X-Initiator` is how a client says which one this is. Leave it off and every
|
|
32
|
+
* tool call in a run bills as a new turn. The `github-copilot` preset sets it
|
|
33
|
+
* for you (`initiatorHeader`); this is for a call you make yourself.
|
|
34
|
+
*/
|
|
35
|
+
export declare function copilotHeaders(appName: string, turn: "user" | "agent"): Record<string, string>;
|
|
36
|
+
//# sourceMappingURL=flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../src/auth/flows.ts"],"names":[],"mappings":"AAMA,OAAO,EAaL,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAGpB,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3F;6CACyC;IACzC,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,UAAU,GACpB,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,gBAAgB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE9E,wBAAgB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAyBvE;AAwDD,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAgB5E;AA+DD;;qDAEqD;AACrD,wBAAgB,yBAAyB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO5E;AAuED,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,6CAA6C,CAAC;AAEnF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU9F"}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
// Each vendor's sign-in and renewal, built on the shared pieces in oauth.ts and
|
|
2
|
+
// device.ts. The client ids are the public ones each vendor's own CLI ships.
|
|
3
|
+
//
|
|
4
|
+
// ponytail: public client ids and fixed redirect ports. The ceiling is that a
|
|
5
|
+
// vendor can rotate a client id, add client attestation or refuse a port, and
|
|
6
|
+
// that vendor's sign-in breaks. Its entry below is then the only thing to fix.
|
|
7
|
+
import { accountFromToken, asRecord, authError, generatePKCE, jwtClaims, num, postToken, randomState, REFRESH_SKEW_MS, str, toCredential, webUrl, } from "./oauth.js";
|
|
8
|
+
import { pollDeviceToken, requestDeviceCode } from "./device.js";
|
|
9
|
+
export function createAuthFlow(id, host) {
|
|
10
|
+
switch (id) {
|
|
11
|
+
case "chatgpt":
|
|
12
|
+
return chatgptFlow(host);
|
|
13
|
+
case "kimi-plan":
|
|
14
|
+
return deviceFlow(host, KIMI_DEVICE, kimiCredential, kimiRefresh(host));
|
|
15
|
+
case "grok":
|
|
16
|
+
return deviceFlow(host, grokDevice(host), grokCredential, grokRefresh(host));
|
|
17
|
+
case "github-copilot":
|
|
18
|
+
return deviceFlow(host, GITHUB_DEVICE, (body) => mintCopilotCredential(host, body), (credential) => refreshCopilot(host, credential));
|
|
19
|
+
case "meta":
|
|
20
|
+
return deviceFlow(host, META_DEVICE, (body) => mintMetaCredential(host, body), (credential) => refreshMeta(host, credential));
|
|
21
|
+
case "openrouter":
|
|
22
|
+
return openrouterFlow(host);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** A device-code sign-in: ask for the code, show it, open the approval page,
|
|
26
|
+
* poll until the user approves, then turn the token body into a credential. */
|
|
27
|
+
function deviceFlow(host, endpoint, toCredentialFrom, refresh) {
|
|
28
|
+
return {
|
|
29
|
+
async signIn(signal, onPrompt) {
|
|
30
|
+
const prompt = await requestDeviceCode(host, endpoint);
|
|
31
|
+
onPrompt({ url: prompt.verificationUrl, userCode: prompt.userCode });
|
|
32
|
+
// If the host can't open it, the code stays on screen as the fallback.
|
|
33
|
+
void Promise.resolve(host.openUrl(prompt.verificationUrl)).catch(() => { });
|
|
34
|
+
return toCredentialFrom(await pollDeviceToken(host, endpoint, prompt, signal));
|
|
35
|
+
},
|
|
36
|
+
refresh,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** Refresh-token renewal that rotates both tokens, shared by Kimi and xAI. */
|
|
40
|
+
function refreshWith(host, endpoint, toCredentialFrom) {
|
|
41
|
+
return async (credential) => toCredentialFrom(await postToken(host, endpoint.tokenUrl, {
|
|
42
|
+
client_id: endpoint.clientId,
|
|
43
|
+
grant_type: "refresh_token",
|
|
44
|
+
refresh_token: credential.refreshToken,
|
|
45
|
+
}, { encode: endpoint.encode }), credential.refreshToken);
|
|
46
|
+
}
|
|
47
|
+
// ── ChatGPT: PKCE through a redirect ──────────────────────────────────────
|
|
48
|
+
const CHATGPT = {
|
|
49
|
+
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
50
|
+
authorizeUrl: "https://auth.openai.com/oauth/authorize",
|
|
51
|
+
tokenUrl: "https://auth.openai.com/oauth/token",
|
|
52
|
+
redirectUri: "http://localhost:1455/auth/callback",
|
|
53
|
+
// The `api.connectors.*` scopes unlock the subscription quota the Codex
|
|
54
|
+
// backend bills against.
|
|
55
|
+
scopes: "openid profile email offline_access api.connectors.read api.connectors.invoke",
|
|
56
|
+
};
|
|
57
|
+
/** The authorize URL to open. Exported so a test can pin the exact params. */
|
|
58
|
+
export function chatgptAuthorizeUrl(challenge, state) {
|
|
59
|
+
const params = new URLSearchParams({
|
|
60
|
+
response_type: "code",
|
|
61
|
+
client_id: CHATGPT.clientId,
|
|
62
|
+
redirect_uri: CHATGPT.redirectUri,
|
|
63
|
+
scope: CHATGPT.scopes,
|
|
64
|
+
code_challenge: challenge,
|
|
65
|
+
code_challenge_method: "S256",
|
|
66
|
+
state,
|
|
67
|
+
// The Codex CLI's own params: the simplified flow skips the consent page
|
|
68
|
+
// behind the subscription upsell.
|
|
69
|
+
codex_cli_simplified_flow: "true",
|
|
70
|
+
originator: "opencodex",
|
|
71
|
+
id_token_add_organizations: "true",
|
|
72
|
+
});
|
|
73
|
+
return `${CHATGPT.authorizeUrl}?${params.toString()}`;
|
|
74
|
+
}
|
|
75
|
+
function chatgptFlow(host) {
|
|
76
|
+
const tokenRequest = (params) => postToken(host, CHATGPT.tokenUrl, { client_id: CHATGPT.clientId, ...params }, { encode: "form" });
|
|
77
|
+
return {
|
|
78
|
+
async signIn(signal, onPrompt) {
|
|
79
|
+
const { verifier, challenge } = await generatePKCE();
|
|
80
|
+
const state = randomState();
|
|
81
|
+
const authorizeUrl = chatgptAuthorizeUrl(challenge, state);
|
|
82
|
+
onPrompt({ url: authorizeUrl });
|
|
83
|
+
const code = await host.captureRedirect({
|
|
84
|
+
authorizeUrl,
|
|
85
|
+
redirectUri: CHATGPT.redirectUri,
|
|
86
|
+
state,
|
|
87
|
+
signal,
|
|
88
|
+
});
|
|
89
|
+
return chatgptCredential(await tokenRequest({
|
|
90
|
+
grant_type: "authorization_code",
|
|
91
|
+
code,
|
|
92
|
+
redirect_uri: CHATGPT.redirectUri,
|
|
93
|
+
code_verifier: verifier,
|
|
94
|
+
}));
|
|
95
|
+
},
|
|
96
|
+
async refresh(credential) {
|
|
97
|
+
const body = await tokenRequest({
|
|
98
|
+
grant_type: "refresh_token",
|
|
99
|
+
refresh_token: credential.refreshToken,
|
|
100
|
+
});
|
|
101
|
+
return chatgptCredential(body, credential.refreshToken, credential.chatgptAccountId);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function chatgptCredential(body, fallbackRefresh, fallbackAccountId) {
|
|
106
|
+
const credential = toCredential(body, fallbackRefresh);
|
|
107
|
+
// The id token has the richer claims. The access token covers a refresh
|
|
108
|
+
// response that leaves it out.
|
|
109
|
+
const idToken = str(body.id_token);
|
|
110
|
+
const account = accountFromToken(idToken, "email") ?? accountFromToken(credential.accessToken, "email");
|
|
111
|
+
const chatgptAccountId = chatgptAccountIdFromToken(idToken) ??
|
|
112
|
+
chatgptAccountIdFromToken(credential.accessToken) ??
|
|
113
|
+
fallbackAccountId;
|
|
114
|
+
return {
|
|
115
|
+
...credential,
|
|
116
|
+
...(account ? { account } : {}),
|
|
117
|
+
...(chatgptAccountId ? { chatgptAccountId } : {}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** The `ChatGPT-Account-Id` the Codex backend requires. OpenAI puts it at
|
|
121
|
+
* `chatgpt_account_id`, under `https://api.openai.com/auth`, or as
|
|
122
|
+
* `organizations[0].id`, depending on the token. */
|
|
123
|
+
export function chatgptAccountIdFromToken(token) {
|
|
124
|
+
const claims = jwtClaims(token);
|
|
125
|
+
if (!claims)
|
|
126
|
+
return undefined;
|
|
127
|
+
const nested = asRecord(claims["https://api.openai.com/auth"]);
|
|
128
|
+
const orgs = claims.organizations;
|
|
129
|
+
const firstOrg = Array.isArray(orgs) ? asRecord(orgs[0]) : {};
|
|
130
|
+
return str(claims.chatgpt_account_id) ?? str(nested.chatgpt_account_id) ?? str(firstOrg.id);
|
|
131
|
+
}
|
|
132
|
+
// ── Kimi and Grok: device code, then a plain refresh token ────────────────
|
|
133
|
+
const KIMI_DEVICE = {
|
|
134
|
+
clientId: "17e5f671-d194-4dfb-9706-5516cb48c098",
|
|
135
|
+
deviceUrl: "https://auth.kimi.ai/api/oauth/device_authorization",
|
|
136
|
+
tokenUrl: "https://auth.kimi.ai/api/oauth/token",
|
|
137
|
+
encode: "form",
|
|
138
|
+
};
|
|
139
|
+
function kimiCredential(body, fallbackRefresh) {
|
|
140
|
+
const credential = toCredential(body, fallbackRefresh);
|
|
141
|
+
const account = accountFromToken(credential.accessToken, "email", "user_id", "sub");
|
|
142
|
+
return account ? { ...credential, account } : credential;
|
|
143
|
+
}
|
|
144
|
+
const kimiRefresh = (host) => refreshWith(host, KIMI_DEVICE, kimiCredential);
|
|
145
|
+
function grokDevice(host) {
|
|
146
|
+
return {
|
|
147
|
+
clientId: "b1a00492-073a-47ea-816f-4c329264a828",
|
|
148
|
+
deviceUrl: "https://auth.x.ai/oauth2/device/code",
|
|
149
|
+
tokenUrl: "https://auth.x.ai/oauth2/token",
|
|
150
|
+
scope: "openid profile email offline_access grok-cli:access api:access",
|
|
151
|
+
// Names the app instead of claiming to be the Grok CLI.
|
|
152
|
+
extra: { referrer: host.appName },
|
|
153
|
+
encode: "form",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/** xAI leaves `expires_in` out of some responses. An hour is what its tokens
|
|
157
|
+
* carry when it does send one. A guess that is too short costs one extra
|
|
158
|
+
* refresh, while no expiry would be a credential nothing ever renews. */
|
|
159
|
+
const GROK_DEFAULT_LIFETIME_SEC = 3600;
|
|
160
|
+
function grokCredential(body, fallbackRefresh) {
|
|
161
|
+
const credential = toCredential({ ...body, expires_in: num(body.expires_in) ?? GROK_DEFAULT_LIFETIME_SEC }, fallbackRefresh);
|
|
162
|
+
const account = accountFromToken(credential.accessToken, "email", "sub");
|
|
163
|
+
return account ? { ...credential, account } : credential;
|
|
164
|
+
}
|
|
165
|
+
const grokRefresh = (host) => refreshWith(host, grokDevice(host), grokCredential);
|
|
166
|
+
// ── GitHub Copilot: device code, then a mint ──────────────────────────────
|
|
167
|
+
// GitHub's device flow ends in a long-lived GitHub token that the Copilot API
|
|
168
|
+
// does not accept. It is traded at `copilot_internal/v2/token` for a Copilot
|
|
169
|
+
// token that lasts about 25 minutes, and trading again IS the refresh. So
|
|
170
|
+
// `refreshToken` holds the GitHub token and `accessToken` the Copilot one.
|
|
171
|
+
//
|
|
172
|
+
// ponytail: github.com only. A GitHub Enterprise Server tenant serves these
|
|
173
|
+
// endpoints on its own domain. Supporting it means threading one domain through
|
|
174
|
+
// these constants.
|
|
175
|
+
const GITHUB_DEVICE = {
|
|
176
|
+
// VS Code's Copilot Chat client id. GitHub issues no self-service Copilot
|
|
177
|
+
// client id, so every third-party client uses this one, and the consent page
|
|
178
|
+
// says "GitHub Copilot Chat". Swap this constant for your own OAuth app's.
|
|
179
|
+
clientId: "Iv1.b507a08c87ecfe98",
|
|
180
|
+
deviceUrl: "https://github.com/login/device/code",
|
|
181
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
182
|
+
// Enough to read the account name. Copilot itself is entitled by the account.
|
|
183
|
+
scope: "read:user",
|
|
184
|
+
encode: "form",
|
|
185
|
+
};
|
|
186
|
+
const COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
187
|
+
const GITHUB_USER_URL = "https://api.github.com/user";
|
|
188
|
+
/** An individual seat's host. Other plans get their own, named by the token. */
|
|
189
|
+
export const COPILOT_DEFAULT_BASE_URL = "https://api.individual.githubcopilot.com";
|
|
190
|
+
/**
|
|
191
|
+
* The editor headers Copilot's gate wants on every call.
|
|
192
|
+
*
|
|
193
|
+
* `turn` matters for the bill. GitHub charges one premium request per
|
|
194
|
+
* user-started turn and lets the agent's own follow-ups ride free, and
|
|
195
|
+
* `X-Initiator` is how a client says which one this is. Leave it off and every
|
|
196
|
+
* tool call in a run bills as a new turn. The `github-copilot` preset sets it
|
|
197
|
+
* for you (`initiatorHeader`); this is for a call you make yourself.
|
|
198
|
+
*/
|
|
199
|
+
export function copilotHeaders(appName, turn) {
|
|
200
|
+
return {
|
|
201
|
+
"Copilot-Integration-Id": "vscode-chat",
|
|
202
|
+
"Editor-Version": appName,
|
|
203
|
+
"Editor-Plugin-Version": appName,
|
|
204
|
+
"X-GitHub-Api-Version": "2026-06-01",
|
|
205
|
+
"Openai-Intent": "conversation-edits",
|
|
206
|
+
"Copilot-Vision-Request": "true",
|
|
207
|
+
"X-Initiator": turn,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async function mintCopilotToken(host, githubToken) {
|
|
211
|
+
const res = await (host.fetchImpl ?? fetch)(COPILOT_TOKEN_URL, {
|
|
212
|
+
headers: {
|
|
213
|
+
Accept: "application/json",
|
|
214
|
+
Authorization: `Bearer ${githubToken}`,
|
|
215
|
+
...copilotHeaders(host.appName, "user"),
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
const text = await res.text().catch(() => "");
|
|
219
|
+
const record = asRecord(parseJson(text));
|
|
220
|
+
if (!res.ok) {
|
|
221
|
+
throw authError("token_refused", `GitHub refused the Copilot token request: ${str(record.message) ?? res.status}`, { status: res.status, body: text.slice(0, 2_000) });
|
|
222
|
+
}
|
|
223
|
+
const accessToken = str(record.token);
|
|
224
|
+
// Absolute epoch seconds here, not the `expires_in` every other vendor sends.
|
|
225
|
+
const expiresAtSec = num(record.expires_at);
|
|
226
|
+
if (!accessToken || expiresAtSec === undefined) {
|
|
227
|
+
throw authError("token_incomplete", "GitHub's Copilot token reply has no token or expiry.");
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
accessToken,
|
|
231
|
+
refreshToken: githubToken,
|
|
232
|
+
expiresAt: expiresAtSec * 1000 - REFRESH_SKEW_MS,
|
|
233
|
+
baseUrl: copilotApiHost(record.endpoints) ??
|
|
234
|
+
copilotHostFromToken(accessToken) ??
|
|
235
|
+
COPILOT_DEFAULT_BASE_URL,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
async function mintCopilotCredential(host, body) {
|
|
239
|
+
const githubToken = str(body.access_token);
|
|
240
|
+
if (!githubToken)
|
|
241
|
+
throw authError("token_incomplete", "GitHub's reply has no access token.");
|
|
242
|
+
const credential = await mintCopilotToken(host, githubToken);
|
|
243
|
+
const account = await githubLogin(host, githubToken);
|
|
244
|
+
return account ? { ...credential, account } : credential;
|
|
245
|
+
}
|
|
246
|
+
async function refreshCopilot(host, credential) {
|
|
247
|
+
const fresh = await mintCopilotToken(host, credential.refreshToken);
|
|
248
|
+
return credential.account ? { ...fresh, account: credential.account } : fresh;
|
|
249
|
+
}
|
|
250
|
+
/** The login for display. A sign-in that worked must not fail because this
|
|
251
|
+
* lookup did, so any failure means no name. */
|
|
252
|
+
async function githubLogin(host, githubToken) {
|
|
253
|
+
try {
|
|
254
|
+
const res = await (host.fetchImpl ?? fetch)(GITHUB_USER_URL, {
|
|
255
|
+
headers: { Accept: "application/json", Authorization: `Bearer ${githubToken}` },
|
|
256
|
+
});
|
|
257
|
+
return res.ok ? str(asRecord(await res.json()).login) : undefined;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** The host a current token response names outright. */
|
|
264
|
+
function copilotApiHost(endpoints) {
|
|
265
|
+
return apiBase(str(asRecord(endpoints).api));
|
|
266
|
+
}
|
|
267
|
+
/** The same host read off the token, for a response with no endpoint map. A
|
|
268
|
+
* Copilot token is a `;`-joined field list with
|
|
269
|
+
* `proxy-ep=proxy.<plan>.githubcopilot.com`, and the API host is that with
|
|
270
|
+
* `proxy.` swapped for `api.`. */
|
|
271
|
+
function copilotHostFromToken(token) {
|
|
272
|
+
const proxy = /(?:^|;)proxy-ep=([^;]+)/.exec(token)?.[1];
|
|
273
|
+
return proxy ? apiBase(`https://${proxy.replace(/^proxy\./, "api.")}`) : undefined;
|
|
274
|
+
}
|
|
275
|
+
const apiBase = (url) => webUrl(url, ["https:"])?.replace(/\/$/, "");
|
|
276
|
+
// ── Meta Muse: device code, then a key mint ───────────────────────────────
|
|
277
|
+
// The device flow's identity token proves who you are and buys nothing. It is
|
|
278
|
+
// traded for a Model API key that lasts about a day, and trading again IS the
|
|
279
|
+
// refresh. The identity token itself cannot be renewed, so a 401 or 403 from
|
|
280
|
+
// the mint means the session is over and the user must sign in again.
|
|
281
|
+
const META_DEVICE = {
|
|
282
|
+
// The Muse Code CLI's client id. Meta issues no self-service one.
|
|
283
|
+
clientId: "1031625952748946",
|
|
284
|
+
deviceUrl: "https://auth.meta.com/oidc/device/authorization/",
|
|
285
|
+
tokenUrl: "https://auth.meta.com/oidc/device/token/",
|
|
286
|
+
encode: "form",
|
|
287
|
+
};
|
|
288
|
+
const META_KEY_URL = "https://api.meta.ai/muse-code/key";
|
|
289
|
+
/** Meta doesn't say how long a key lasts. */
|
|
290
|
+
const META_KEY_LIFETIME_MS = 24 * 60 * 60 * 1000;
|
|
291
|
+
async function mintMetaKey(host, identityToken) {
|
|
292
|
+
const res = await (host.fetchImpl ?? fetch)(META_KEY_URL, {
|
|
293
|
+
method: "POST",
|
|
294
|
+
headers: {
|
|
295
|
+
Accept: "application/json",
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
Authorization: `Bearer ${identityToken}`,
|
|
298
|
+
"x-api-version": "1.0.0",
|
|
299
|
+
},
|
|
300
|
+
body: "{}",
|
|
301
|
+
});
|
|
302
|
+
const text = await res.text().catch(() => "");
|
|
303
|
+
const record = asRecord(parseJson(text));
|
|
304
|
+
if (!res.ok) {
|
|
305
|
+
throw authError("token_refused", `Meta refused the key request: ${str(record.error_description) ?? str(record.detail) ?? res.status}`, { status: res.status, body: text.slice(0, 2_000) });
|
|
306
|
+
}
|
|
307
|
+
const apiKey = str(record.api_key);
|
|
308
|
+
if (!apiKey) {
|
|
309
|
+
// Meta answers 200 with no key when the account exists but Muse was never
|
|
310
|
+
// set up on it. `action_url` points at the page to do that.
|
|
311
|
+
const actionUrl = webUrl(str(record.action_url), ["https:"]);
|
|
312
|
+
throw authError("setup_required", actionUrl
|
|
313
|
+
? `Muse isn't set up on this Meta account. Set it up at ${actionUrl}, then sign in again.`
|
|
314
|
+
: "Muse isn't set up on this Meta account. Set it up with Meta, then sign in again.");
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
accessToken: apiKey,
|
|
318
|
+
refreshToken: identityToken,
|
|
319
|
+
expiresAt: Date.now() + META_KEY_LIFETIME_MS - REFRESH_SKEW_MS,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async function mintMetaCredential(host, body) {
|
|
323
|
+
const identityToken = str(body.access_token);
|
|
324
|
+
if (!identityToken)
|
|
325
|
+
throw authError("token_incomplete", "Meta's reply has no identity token.");
|
|
326
|
+
const credential = await mintMetaKey(host, identityToken);
|
|
327
|
+
// The minted key is opaque. The identity token is the one with claims.
|
|
328
|
+
const account = accountFromToken(identityToken, "email", "preferred_username", "sub");
|
|
329
|
+
return account ? { ...credential, account } : credential;
|
|
330
|
+
}
|
|
331
|
+
async function refreshMeta(host, credential) {
|
|
332
|
+
const fresh = await mintMetaKey(host, credential.refreshToken);
|
|
333
|
+
return credential.account ? { ...fresh, account: credential.account } : fresh;
|
|
334
|
+
}
|
|
335
|
+
// ── OpenRouter: PKCE, ending in an API key ────────────────────────────────
|
|
336
|
+
// The code is traded for an ordinary API key on the user's own account. It
|
|
337
|
+
// never expires and the user can revoke it at openrouter.ai, so there is
|
|
338
|
+
// nothing to refresh. There is no client id: PKCE is the whole proof.
|
|
339
|
+
//
|
|
340
|
+
// ponytail: a fixed redirect port. If something else on the machine serves
|
|
341
|
+
// 54546 it sees the code first. The exchange then fails and the user starts
|
|
342
|
+
// over, which is the right end for a code we can no longer trust.
|
|
343
|
+
const OPENROUTER = {
|
|
344
|
+
authorizeUrl: "https://openrouter.ai/auth",
|
|
345
|
+
keysUrl: "https://openrouter.ai/api/v1/auth/keys",
|
|
346
|
+
redirectUri: "http://localhost:54546/callback",
|
|
347
|
+
};
|
|
348
|
+
/** A key doesn't expire, so its `expiresAt` is as far out as a number goes. */
|
|
349
|
+
const NEVER = Number.MAX_SAFE_INTEGER;
|
|
350
|
+
function openrouterFlow(host) {
|
|
351
|
+
return {
|
|
352
|
+
async signIn(signal, onPrompt) {
|
|
353
|
+
const { verifier, challenge } = await generatePKCE();
|
|
354
|
+
const authorizeUrl = `${OPENROUTER.authorizeUrl}?${new URLSearchParams({
|
|
355
|
+
callback_url: OPENROUTER.redirectUri,
|
|
356
|
+
code_challenge: challenge,
|
|
357
|
+
code_challenge_method: "S256",
|
|
358
|
+
})}`;
|
|
359
|
+
onPrompt({ url: authorizeUrl });
|
|
360
|
+
// No `state`: OpenRouter's authorize endpoint takes none.
|
|
361
|
+
const code = await host.captureRedirect({
|
|
362
|
+
authorizeUrl,
|
|
363
|
+
redirectUri: OPENROUTER.redirectUri,
|
|
364
|
+
signal,
|
|
365
|
+
});
|
|
366
|
+
const res = await (host.fetchImpl ?? fetch)(OPENROUTER.keysUrl, {
|
|
367
|
+
method: "POST",
|
|
368
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
369
|
+
body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" }),
|
|
370
|
+
});
|
|
371
|
+
const text = await res.text().catch(() => "");
|
|
372
|
+
const record = asRecord(parseJson(text));
|
|
373
|
+
const key = str(record.key);
|
|
374
|
+
if (!key) {
|
|
375
|
+
throw authError("token_refused", `OpenRouter refused the key request: ${str(record.message) ?? str(record.error) ?? res.status}`, { status: res.status, body: text.slice(0, 2_000) });
|
|
376
|
+
}
|
|
377
|
+
return { accessToken: key, refreshToken: "", expiresAt: NEVER };
|
|
378
|
+
},
|
|
379
|
+
// Nothing to renew. A revoked key shows up as the call's own 401, and
|
|
380
|
+
// signing in again mints a new one.
|
|
381
|
+
refresh: (credential) => Promise.resolve(credential),
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function parseJson(text) {
|
|
385
|
+
try {
|
|
386
|
+
return JSON.parse(text);
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
//# sourceMappingURL=flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flows.js","sourceRoot":"","sources":["../../src/auth/flows.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,SAAS,EACT,GAAG,EACH,SAAS,EACT,WAAW,EACX,eAAe,EACf,GAAG,EACH,YAAY,EACZ,MAAM,GAGP,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAuB,MAAM,aAAa,CAAC;AAqBtF,MAAM,UAAU,cAAc,CAAC,EAAc,EAAE,IAAc;IAC3D,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,SAAS;YACZ,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3B,KAAK,WAAW;YACd,OAAO,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1E,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/E,KAAK,gBAAgB;YACnB,OAAO,UAAU,CACf,IAAI,EACJ,aAAa,EACb,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,EAC3C,CAAC,UAAU,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CACjD,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,UAAU,CACf,IAAI,EACJ,WAAW,EACX,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,EACxC,CAAC,UAAU,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAC9C,CAAC;QACJ,KAAK,YAAY;YACf,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED;gFACgF;AAChF,SAAS,UAAU,CACjB,IAAc,EACd,QAAwB,EACxB,gBAAqF,EACrF,OAA4B;IAE5B,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ;YAC3B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACvD,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACrE,uEAAuE;YACvE,KAAK,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC3E,OAAO,gBAAgB,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,OAAO;KACR,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAS,WAAW,CAClB,IAAc,EACd,QAAwB,EACxB,gBAAwF;IAExF,OAAO,KAAK,EAAE,UAAU,EAAE,EAAE,CAC1B,gBAAgB,CACd,MAAM,SAAS,CACb,IAAI,EACJ,QAAQ,CAAC,QAAQ,EACjB;QACE,SAAS,EAAE,QAAQ,CAAC,QAAQ;QAC5B,UAAU,EAAE,eAAe;QAC3B,aAAa,EAAE,UAAU,CAAC,YAAY;KACvC,EACD,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAC5B,EACD,UAAU,CAAC,YAAY,CACxB,CAAC;AACN,CAAC;AAED,6EAA6E;AAE7E,MAAM,OAAO,GAAG;IACd,QAAQ,EAAE,8BAA8B;IACxC,YAAY,EAAE,yCAAyC;IACvD,QAAQ,EAAE,qCAAqC;IAC/C,WAAW,EAAE,qCAAqC;IAClD,wEAAwE;IACxE,yBAAyB;IACzB,MAAM,EAAE,+EAA+E;CAC/E,CAAC;AAEX,8EAA8E;AAC9E,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,KAAa;IAClE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,OAAO,CAAC,QAAQ;QAC3B,YAAY,EAAE,OAAO,CAAC,WAAW;QACjC,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,cAAc,EAAE,SAAS;QACzB,qBAAqB,EAAE,MAAM;QAC7B,KAAK;QACL,yEAAyE;QACzE,kCAAkC;QAClC,yBAAyB,EAAE,MAAM;QACjC,UAAU,EAAE,WAAW;QACvB,0BAA0B,EAAE,MAAM;KACnC,CAAC,CAAC;IACH,OAAO,GAAG,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,WAAW,CAAC,IAAc;IACjC,MAAM,YAAY,GAAG,CAAC,MAA8B,EAAE,EAAE,CACtD,SAAS,CACP,IAAI,EACJ,OAAO,CAAC,QAAQ,EAChB,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,EAC1C,EAAE,MAAM,EAAE,MAAM,EAAE,CACnB,CAAC;IACJ,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ;YAC3B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;YACrD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC3D,QAAQ,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC;gBACtC,YAAY;gBACZ,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,KAAK;gBACL,MAAM;aACP,CAAC,CAAC;YACH,OAAO,iBAAiB,CACtB,MAAM,YAAY,CAAC;gBACjB,UAAU,EAAE,oBAAoB;gBAChC,IAAI;gBACJ,YAAY,EAAE,OAAO,CAAC,WAAW;gBACjC,aAAa,EAAE,QAAQ;aACxB,CAAC,CACH,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,UAAU;YACtB,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC;gBAC9B,UAAU,EAAE,eAAe;gBAC3B,aAAa,EAAE,UAAU,CAAC,YAAY;aACvC,CAAC,CAAC;YACH,OAAO,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACvF,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,IAA6B,EAC7B,eAAwB,EACxB,iBAA0B;IAE1B,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACvD,wEAAwE;IACxE,+BAA+B;IAC/B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,OAAO,GACX,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1F,MAAM,gBAAgB,GACpB,yBAAyB,CAAC,OAAO,CAAC;QAClC,yBAAyB,CAAC,UAAU,CAAC,WAAW,CAAC;QACjD,iBAAiB,CAAC;IACpB,OAAO;QACL,GAAG,UAAU;QACb,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAED;;qDAEqD;AACrD,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,OAAO,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,6EAA6E;AAE7E,MAAM,WAAW,GAAmB;IAClC,QAAQ,EAAE,sCAAsC;IAChD,SAAS,EAAE,qDAAqD;IAChE,QAAQ,EAAE,sCAAsC;IAChD,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,SAAS,cAAc,CAAC,IAA6B,EAAE,eAAwB;IAC7E,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACpF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3D,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,IAAc,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAEvF,SAAS,UAAU,CAAC,IAAc;IAChC,OAAO;QACL,QAAQ,EAAE,sCAAsC;QAChD,SAAS,EAAE,sCAAsC;QACjD,QAAQ,EAAE,gCAAgC;QAC1C,KAAK,EAAE,gEAAgE;QACvE,wDAAwD;QACxD,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,MAAM;KACf,CAAC;AACJ,CAAC;AAED;;0EAE0E;AAC1E,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAEvC,SAAS,cAAc,CAAC,IAA6B,EAAE,eAAwB;IAC7E,MAAM,UAAU,GAAG,YAAY,CAC7B,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,yBAAyB,EAAE,EAC1E,eAAe,CAChB,CAAC;IACF,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3D,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,IAAc,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;AAE5F,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,mBAAmB;AAEnB,MAAM,aAAa,GAAmB;IACpC,0EAA0E;IAC1E,6EAA6E;IAC7E,2EAA2E;IAC3E,QAAQ,EAAE,sBAAsB;IAChC,SAAS,EAAE,sCAAsC;IACjD,QAAQ,EAAE,6CAA6C;IACvD,8EAA8E;IAC9E,KAAK,EAAE,WAAW;IAClB,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,MAAM,iBAAiB,GAAG,kDAAkD,CAAC;AAC7E,MAAM,eAAe,GAAG,6BAA6B,CAAC;AACtD,gFAAgF;AAChF,MAAM,CAAC,MAAM,wBAAwB,GAAG,0CAA0C,CAAC;AAEnF;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,IAAsB;IACpE,OAAO;QACL,wBAAwB,EAAE,aAAa;QACvC,gBAAgB,EAAE,OAAO;QACzB,uBAAuB,EAAE,OAAO;QAChC,sBAAsB,EAAE,YAAY;QACpC,eAAe,EAAE,oBAAoB;QACrC,wBAAwB,EAAE,MAAM;QAChC,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAc,EAAE,WAAmB;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,iBAAiB,EAAE;QAC7D,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;SACxC;KACF,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,SAAS,CACb,eAAe,EACf,6CAA6C,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,EAChF,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CACnD,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,8EAA8E;IAC9E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,WAAW,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/C,MAAM,SAAS,CAAC,kBAAkB,EAAE,sDAAsD,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO;QACL,WAAW;QACX,YAAY,EAAE,WAAW;QACzB,SAAS,EAAE,YAAY,GAAG,IAAI,GAAG,eAAe;QAChD,OAAO,EACL,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC;YAChC,oBAAoB,CAAC,WAAW,CAAC;YACjC,wBAAwB;KAC3B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,IAAc,EACd,IAA6B;IAE7B,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,WAAW;QAAE,MAAM,SAAS,CAAC,kBAAkB,EAAE,qCAAqC,CAAC,CAAC;IAC7F,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACrD,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAc,EAAE,UAAsB;IAClE,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IACpE,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAChF,CAAC;AAED;gDACgD;AAChD,KAAK,UAAU,WAAW,CAAC,IAAc,EAAE,WAAmB;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,eAAe,EAAE;YAC3D,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE;SAChF,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,SAAS,cAAc,CAAC,SAAkB;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;mCAGmC;AACnC,SAAS,oBAAoB,CAAC,KAAa;IACzC,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrF,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,GAAuB,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAEzF,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,sEAAsE;AAEtE,MAAM,WAAW,GAAmB;IAClC,kEAAkE;IAClE,QAAQ,EAAE,kBAAkB;IAC5B,SAAS,EAAE,kDAAkD;IAC7D,QAAQ,EAAE,0CAA0C;IACpD,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,MAAM,YAAY,GAAG,mCAAmC,CAAC;AACzD,6CAA6C;AAC7C,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjD,KAAK,UAAU,WAAW,CAAC,IAAc,EAAE,aAAqB;IAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,YAAY,EAAE;QACxD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,aAAa,EAAE;YACxC,eAAe,EAAE,OAAO;SACzB;QACD,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,SAAS,CACb,eAAe,EACf,iCAAiC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,EACpG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CACnD,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,0EAA0E;QAC1E,4DAA4D;QAC5D,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7D,MAAM,SAAS,CACb,gBAAgB,EAChB,SAAS;YACP,CAAC,CAAC,wDAAwD,SAAS,uBAAuB;YAC1F,CAAC,CAAC,kFAAkF,CACvF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,WAAW,EAAE,MAAM;QACnB,YAAY,EAAE,aAAa;QAC3B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,GAAG,eAAe;KAC/D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,IAAc,EACd,IAA6B;IAE7B,MAAM,aAAa,GAAG,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,CAAC,aAAa;QAAE,MAAM,SAAS,CAAC,kBAAkB,EAAE,qCAAqC,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC1D,uEAAuE;IACvE,MAAM,OAAO,GAAG,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE,oBAAoB,EAAE,KAAK,CAAC,CAAC;IACtF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAc,EAAE,UAAsB;IAC/D,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAC/D,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAChF,CAAC;AAED,6EAA6E;AAC7E,2EAA2E;AAC3E,yEAAyE;AACzE,sEAAsE;AACtE,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,kEAAkE;AAElE,MAAM,UAAU,GAAG;IACjB,YAAY,EAAE,4BAA4B;IAC1C,OAAO,EAAE,wCAAwC;IACjD,WAAW,EAAE,iCAAiC;CACtC,CAAC;AAEX,+EAA+E;AAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAEtC,SAAS,cAAc,CAAC,IAAc;IACpC,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ;YAC3B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;YACrD,MAAM,YAAY,GAAG,GAAG,UAAU,CAAC,YAAY,IAAI,IAAI,eAAe,CAAC;gBACrE,YAAY,EAAE,UAAU,CAAC,WAAW;gBACpC,cAAc,EAAE,SAAS;gBACzB,qBAAqB,EAAE,MAAM;aAC9B,CAAC,EAAE,CAAC;YACL,QAAQ,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YAChC,0DAA0D;YAC1D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC;gBACtC,YAAY;gBACZ,WAAW,EAAE,UAAU,CAAC,WAAW;gBACnC,MAAM;aACP,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC9D,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;gBAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC;aACvF,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,SAAS,CACb,eAAe,EACf,uCAAuC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,EAC/F,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CACnD,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAClE,CAAC;QACD,sEAAsE;QACtE,oCAAoC;QACpC,OAAO,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAGA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// `@providerkit/core/auth`: sign in to a subscription and keep the token fresh.
|
|
2
|
+
// Fetch only. The app supplies what a browser or a window must do (open a page,
|
|
3
|
+
// catch a redirect) and where tokens are stored; this package does the protocol.
|
|
4
|
+
export * from "./oauth.js";
|
|
5
|
+
export * from "./device.js";
|
|
6
|
+
export * from "./flows.js";
|
|
7
|
+
export * from "./token-source.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|