@typeship-ax/cli 0.8.0 → 0.9.1
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/AGENTS.md +31 -0
- package/README.md +26 -9
- package/api.json +1875 -684
- package/api.md +352 -500
- package/dist/api-identity.d.ts +40 -0
- package/dist/api-identity.d.ts.map +1 -0
- package/dist/api-identity.js +128 -0
- package/dist/auth-profiles.d.ts +30 -0
- package/dist/auth-profiles.d.ts.map +1 -0
- package/dist/auth-profiles.js +138 -0
- package/dist/cli.js +522 -355
- package/dist/console-login-check.d.ts +21 -0
- package/dist/console-login-check.d.ts.map +1 -0
- package/dist/console-login-check.js +107 -0
- package/dist/console-login-contract.d.ts +45 -0
- package/dist/console-login-contract.d.ts.map +1 -0
- package/dist/console-login-contract.js +40 -0
- package/dist/core/http.d.ts +17 -2
- package/dist/core/http.d.ts.map +1 -1
- package/dist/core/http.js +78 -17
- package/dist/credential-storage.d.ts +24 -0
- package/dist/credential-storage.d.ts.map +1 -0
- package/dist/credential-storage.js +207 -0
- package/dist/docs.d.ts +25 -0
- package/dist/docs.d.ts.map +1 -1
- package/dist/docs.js +144 -0
- package/dist/errors.d.ts +18 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +24 -14
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -4
- package/dist/named-credentials.d.ts +21 -0
- package/dist/named-credentials.d.ts.map +1 -0
- package/dist/named-credentials.js +86 -0
- package/dist/oauth-login.d.ts +39 -0
- package/dist/oauth-login.d.ts.map +1 -0
- package/dist/oauth-login.js +171 -0
- package/dist/oauth-request.d.ts +21 -0
- package/dist/oauth-request.d.ts.map +1 -0
- package/dist/oauth-request.js +119 -0
- package/dist/oauth-session.d.ts +106 -0
- package/dist/oauth-session.d.ts.map +1 -0
- package/dist/oauth-session.js +244 -0
- package/dist/ops.d.ts +14 -1
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +30 -30
- package/dist/polling-login.d.ts +57 -0
- package/dist/polling-login.d.ts.map +1 -0
- package/dist/polling-login.js +204 -0
- package/dist/resources/account.d.ts +2 -2
- package/dist/resources/account.d.ts.map +1 -1
- package/dist/resources/account.js +1 -0
- package/dist/resources/api-keys.d.ts +3 -3
- package/dist/resources/api-keys.d.ts.map +1 -1
- package/dist/resources/api-keys.js +2 -0
- package/dist/resources/definition-revisions.d.ts +5 -5
- package/dist/resources/definition-revisions.d.ts.map +1 -1
- package/dist/resources/definition-revisions.js +4 -0
- package/dist/resources/definitions.d.ts +15 -4
- package/dist/resources/definitions.d.ts.map +1 -1
- package/dist/resources/definitions.js +11 -2
- package/dist/resources/generate.d.ts +14 -3
- package/dist/resources/generate.d.ts.map +1 -1
- package/dist/resources/generate.js +10 -2
- package/dist/resources/generations.d.ts +3 -3
- package/dist/resources/generations.d.ts.map +1 -1
- package/dist/resources/generations.js +2 -0
- package/dist/resources/projects.d.ts +56 -20
- package/dist/resources/projects.d.ts.map +1 -1
- package/dist/resources/projects.js +40 -4
- package/dist/resources/targets.d.ts +20 -9
- package/dist/resources/targets.d.ts.map +1 -1
- package/dist/resources/targets.js +14 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +38 -22
- package/dist/types.d.ts +385 -119
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/package.json +2 -1
- package/src/api-identity.ts +98 -0
- package/src/auth-profiles.ts +114 -0
- package/src/cli.ts +444 -332
- package/src/console-login-check.ts +88 -0
- package/src/console-login-contract.ts +65 -0
- package/src/core/http.ts +88 -19
- package/src/credential-storage.ts +183 -0
- package/src/docs.ts +138 -0
- package/src/errors.ts +26 -15
- package/src/index.ts +29 -4
- package/src/named-credentials.ts +74 -0
- package/src/oauth-login.ts +184 -0
- package/src/oauth-request.ts +90 -0
- package/src/oauth-session.ts +258 -0
- package/src/ops.ts +44 -31
- package/src/polling-login.ts +165 -0
- package/src/resources/account.ts +3 -0
- package/src/resources/api-keys.ts +5 -0
- package/src/resources/definition-revisions.ts +9 -0
- package/src/resources/definitions.ts +25 -0
- package/src/resources/generate.ts +23 -0
- package/src/resources/generations.ts +5 -0
- package/src/resources/projects.ts +95 -7
- package/src/resources/targets.ts +32 -0
- package/src/schemas.ts +38 -22
- package/src/types.ts +404 -119
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Runtime credentials keyed by the API's exact security-scheme names. */
|
|
2
|
+
export type NamedCredential = string | {
|
|
3
|
+
username: string;
|
|
4
|
+
password: string;
|
|
5
|
+
};
|
|
6
|
+
export type NamedCredentials = Record<string, NamedCredential>;
|
|
7
|
+
export type CredentialSchemes = Record<string, {
|
|
8
|
+
kind: string;
|
|
9
|
+
options: string[];
|
|
10
|
+
}>;
|
|
11
|
+
export declare function parseNamedCredentials(value: unknown, schemes: CredentialSchemes): NamedCredentials;
|
|
12
|
+
/** Low-to-high source order. Within a source, exact names beat convenience options. */
|
|
13
|
+
export declare function resolveNamedCredentials(schemes: CredentialSchemes, layers: {
|
|
14
|
+
named?: NamedCredentials;
|
|
15
|
+
options?: Record<string, unknown>;
|
|
16
|
+
}[]): NamedCredentials;
|
|
17
|
+
/** Make convenience and named inputs comparable without expanding combinations. */
|
|
18
|
+
export declare function namedCredentialAvailability(schemes: CredentialSchemes, options: Set<string>, named: NamedCredentials): Set<string>;
|
|
19
|
+
/** Bound file/stdin reads before allocating a full credential document. */
|
|
20
|
+
export declare function readNamedCredentialsFile(input: string, schemes: CredentialSchemes): NamedCredentials;
|
|
21
|
+
//# sourceMappingURL=named-credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-credentials.d.ts","sourceRoot":"","sources":["../src/named-credentials.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAEpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAqBlG;AAED,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,GAAG,gBAAgB,CAa/J;AAED,mFAAmF;AACnF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,CAAC,CAKlI;AAED,2EAA2E;AAC3E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAkBpG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { openSync, readSync, closeSync } from "node:fs";
|
|
2
|
+
export function parseNamedCredentials(value, schemes) {
|
|
3
|
+
if (typeof value === "string") {
|
|
4
|
+
if (new TextEncoder().encode(value).byteLength > 1_048_576)
|
|
5
|
+
throw new Error("Named credentials exceed the 1 MiB limit.");
|
|
6
|
+
try {
|
|
7
|
+
value = JSON.parse(value);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
throw new Error("Named credentials must be a JSON object keyed by security scheme. Credential contents are not included in errors.");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
14
|
+
throw new Error("Named credentials must be a JSON object keyed by security scheme.");
|
|
15
|
+
const result = Object.create(null);
|
|
16
|
+
for (const [name, credential] of Object.entries(value)) {
|
|
17
|
+
if (!Object.hasOwn(schemes, name))
|
|
18
|
+
throw new Error("Named credentials contain an unknown or unsupported security scheme. Check the names listed by login --help.");
|
|
19
|
+
if (schemes[name].kind === "basic") {
|
|
20
|
+
if (!credential || typeof credential !== "object" || Array.isArray(credential) || Object.keys(credential).some((key) => key !== "username" && key !== "password") ||
|
|
21
|
+
typeof credential.username !== "string" || typeof credential.password !== "string" || !credential.username || !credential.password || credential.username.includes(":")) {
|
|
22
|
+
throw new Error("A named Basic credential requires a nonempty username and password; the username cannot contain a colon.");
|
|
23
|
+
}
|
|
24
|
+
result[name] = { username: credential.username, password: credential.password };
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
if (typeof credential !== "string" || !credential || /[\x00-\x1f\x7f]/.test(credential) || (schemes[name].kind === "bearer" && credential.includes(" ")))
|
|
28
|
+
throw new Error("A named token or API key must be a nonempty string without control characters; bearer tokens cannot contain spaces.");
|
|
29
|
+
result[name] = credential;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/** Low-to-high source order. Within a source, exact names beat convenience options. */
|
|
35
|
+
export function resolveNamedCredentials(schemes, layers) {
|
|
36
|
+
const resolved = Object.create(null);
|
|
37
|
+
for (const layer of layers) {
|
|
38
|
+
for (const [name, scheme] of Object.entries(schemes)) {
|
|
39
|
+
for (const option of scheme.options) {
|
|
40
|
+
if (option === "clientCredentials")
|
|
41
|
+
continue;
|
|
42
|
+
const value = layer.options?.[option];
|
|
43
|
+
if (value !== undefined)
|
|
44
|
+
resolved[name] = value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (layer.named)
|
|
48
|
+
Object.assign(resolved, parseNamedCredentials(layer.named, schemes));
|
|
49
|
+
}
|
|
50
|
+
return resolved;
|
|
51
|
+
}
|
|
52
|
+
/** Make convenience and named inputs comparable without expanding combinations. */
|
|
53
|
+
export function namedCredentialAvailability(schemes, options, named) {
|
|
54
|
+
for (const [name, scheme] of Object.entries(schemes)) {
|
|
55
|
+
if (Object.hasOwn(named, name) || scheme.options.some((option) => options.has(option)))
|
|
56
|
+
options.add("credentials." + name);
|
|
57
|
+
}
|
|
58
|
+
return options;
|
|
59
|
+
}
|
|
60
|
+
/** Bound file/stdin reads before allocating a full credential document. */
|
|
61
|
+
export function readNamedCredentialsFile(input, schemes) {
|
|
62
|
+
let fd;
|
|
63
|
+
const chunks = [];
|
|
64
|
+
let total = 0;
|
|
65
|
+
try {
|
|
66
|
+
fd = input === "-" ? 0 : openSync(input.slice(1), "r");
|
|
67
|
+
while (true) {
|
|
68
|
+
const buffer = Buffer.alloc(Math.min(32_768, 1_048_577 - total));
|
|
69
|
+
const size = readSync(fd, buffer, 0, buffer.length, null);
|
|
70
|
+
if (!size)
|
|
71
|
+
break;
|
|
72
|
+
total += size;
|
|
73
|
+
if (total > 1_048_576)
|
|
74
|
+
throw new Error("size");
|
|
75
|
+
chunks.push(buffer.subarray(0, size));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new Error("Cannot read named credentials. Supply a readable JSON file or stdin input of at most 1 MiB.");
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
if (fd !== undefined && input !== "-")
|
|
83
|
+
closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
return parseNamedCredentials(Buffer.concat(chunks).toString("utf8"), schemes);
|
|
86
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface OAuthLoginConfig {
|
|
2
|
+
issuer: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
discoveryUrl?: string;
|
|
5
|
+
authorizationUrl?: string;
|
|
6
|
+
tokenUrl?: string;
|
|
7
|
+
/** Register http://127.0.0.1/callback; an omitted port uses a random port. */
|
|
8
|
+
redirectUri?: string;
|
|
9
|
+
scopes?: string[];
|
|
10
|
+
audience?: string;
|
|
11
|
+
resource?: string;
|
|
12
|
+
/** Explicit runtime selection. The CLI verifies this ID through the API. */
|
|
13
|
+
organization?: {
|
|
14
|
+
parameter: "organization" | "organization_id";
|
|
15
|
+
id: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface OAuthLoginSession {
|
|
19
|
+
accessToken: string;
|
|
20
|
+
refreshToken?: string;
|
|
21
|
+
expiresAt?: number;
|
|
22
|
+
issuer: string;
|
|
23
|
+
clientId: string;
|
|
24
|
+
tokenUrl: string;
|
|
25
|
+
/** The actual native callback used for this exchange, including its port. */
|
|
26
|
+
redirectUri: string;
|
|
27
|
+
revocationUrl?: string;
|
|
28
|
+
scopes?: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface OAuthLoginInteraction {
|
|
31
|
+
/** Open or display the URL. Never send the verifier or returned tokens. */
|
|
32
|
+
authorize(url: string): void | Promise<void>;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Authorization Code + S256 PKCE for a public native client. The listener
|
|
37
|
+
* binds only a loopback IP, verifies state/issuer, and closes on every path. */
|
|
38
|
+
export declare function oauthBrowserLogin(config: OAuthLoginConfig, interaction: OAuthLoginInteraction): Promise<OAuthLoginSession>;
|
|
39
|
+
//# sourceMappingURL=oauth-login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-login.d.ts","sourceRoot":"","sources":["../src/oauth-login.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,YAAY,CAAC,EAAE;QAAE,SAAS,EAAE,cAAc,GAAG,iBAAiB,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9E;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgDD;gFACgF;AAChF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgGhI"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { oauthJsonRequest, OAuthResponseError } from "./oauth-request.js";
|
|
4
|
+
function endpoint(value) {
|
|
5
|
+
const url = new URL(value);
|
|
6
|
+
const loopback = ["127.0.0.1", "[::1]", "localhost"].includes(url.hostname);
|
|
7
|
+
if ((url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) || url.username || url.password || url.hash) {
|
|
8
|
+
throw new Error("OAuth endpoints require HTTPS without credentials or fragments; loopback HTTP is allowed for development.");
|
|
9
|
+
}
|
|
10
|
+
return url;
|
|
11
|
+
}
|
|
12
|
+
async function metadata(config, signal) {
|
|
13
|
+
const issuer = endpoint(config.issuer);
|
|
14
|
+
if (issuer.search)
|
|
15
|
+
throw new Error("The OAuth issuer must not contain a query.");
|
|
16
|
+
const path = issuer.pathname.replace(/\/$/, "");
|
|
17
|
+
const urls = config.discoveryUrl ? [config.discoveryUrl] : [
|
|
18
|
+
issuer.origin + "/.well-known/oauth-authorization-server" + path,
|
|
19
|
+
issuer.origin + path + "/.well-known/openid-configuration",
|
|
20
|
+
];
|
|
21
|
+
for (const url of urls) {
|
|
22
|
+
let response;
|
|
23
|
+
try {
|
|
24
|
+
response = await oauthJsonRequest(endpoint(url), { headers: { Accept: "application/json" }, signal }, 10_000);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (!signal.aborted && error instanceof OAuthResponseError && error.code === "request_failed")
|
|
28
|
+
continue;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
if (response.status !== 200)
|
|
32
|
+
continue;
|
|
33
|
+
const data = response.data;
|
|
34
|
+
if (data.issuer !== config.issuer)
|
|
35
|
+
throw new Error("OAuth discovery returned a different issuer. Check the issuer and discovery URL.");
|
|
36
|
+
if (Array.isArray(data.code_challenge_methods_supported) && !data.code_challenge_methods_supported.includes("S256")) {
|
|
37
|
+
throw new Error("The provider does not advertise S256 PKCE support.");
|
|
38
|
+
}
|
|
39
|
+
const authorizationUrl = config.authorizationUrl ?? data.authorization_endpoint;
|
|
40
|
+
const tokenUrl = config.tokenUrl ?? data.token_endpoint;
|
|
41
|
+
if (typeof authorizationUrl !== "string" || typeof tokenUrl !== "string")
|
|
42
|
+
throw new Error("Browser login requires authorization and token endpoints.");
|
|
43
|
+
return {
|
|
44
|
+
authorizationUrl: endpoint(authorizationUrl), tokenUrl: endpoint(tokenUrl).href,
|
|
45
|
+
...(typeof data.revocation_endpoint === "string" ? { revocationUrl: endpoint(data.revocation_endpoint).href } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Some custom providers publish no metadata. Their explicit endpoints are
|
|
49
|
+
// owner configuration, not endpoints accepted from an unverified document.
|
|
50
|
+
if (config.authorizationUrl && config.tokenUrl)
|
|
51
|
+
return {
|
|
52
|
+
authorizationUrl: endpoint(config.authorizationUrl), tokenUrl: endpoint(config.tokenUrl).href,
|
|
53
|
+
};
|
|
54
|
+
throw new Error("Could not discover OAuth endpoints. Check the issuer or provide explicit authorization and token URLs.");
|
|
55
|
+
}
|
|
56
|
+
/** Authorization Code + S256 PKCE for a public native client. The listener
|
|
57
|
+
* binds only a loopback IP, verifies state/issuer, and closes on every path. */
|
|
58
|
+
export async function oauthBrowserLogin(config, interaction) {
|
|
59
|
+
if (!config.clientId.trim())
|
|
60
|
+
throw new Error("Browser login requires a public client ID.");
|
|
61
|
+
if (config.organization && (!["organization", "organization_id"].includes(config.organization.parameter) || typeof config.organization.id !== "string" || !config.organization.id || config.organization.id.length > 512 || /\s|[\u0000-\u001F\u007F]/.test(config.organization.id)))
|
|
62
|
+
throw new Error("Organization selection requires a supported parameter and a nonempty organization ID without whitespace.");
|
|
63
|
+
const signal = AbortSignal.any([interaction.signal ?? new AbortController().signal, AbortSignal.timeout(interaction.timeoutMs ?? 600_000)]);
|
|
64
|
+
signal.throwIfAborted();
|
|
65
|
+
const endpoints = await metadata(config, signal);
|
|
66
|
+
const redirect = new URL(config.redirectUri ?? "http://127.0.0.1/callback");
|
|
67
|
+
if (redirect.protocol !== "http:" || !["127.0.0.1", "[::1]"].includes(redirect.hostname) || redirect.username || redirect.password || redirect.search || redirect.hash) {
|
|
68
|
+
throw new Error("The OAuth redirect must be an HTTP loopback IP URL without credentials, query, or fragment.");
|
|
69
|
+
}
|
|
70
|
+
const verifier = randomBytes(32).toString("base64url");
|
|
71
|
+
const state = randomBytes(32).toString("base64url");
|
|
72
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
73
|
+
let resolveCode;
|
|
74
|
+
let rejectCode;
|
|
75
|
+
const codeResult = new Promise((resolve, reject) => { resolveCode = resolve; rejectCode = reject; });
|
|
76
|
+
// Observe rejection even if opening the browser or starting the server fails.
|
|
77
|
+
void codeResult.catch(() => undefined);
|
|
78
|
+
let accepted = false;
|
|
79
|
+
const server = createServer((request, response) => {
|
|
80
|
+
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
81
|
+
response.setHeader("Cache-Control", "no-store");
|
|
82
|
+
response.setHeader("Referrer-Policy", "no-referrer");
|
|
83
|
+
response.setHeader("Content-Security-Policy", "default-src 'none'");
|
|
84
|
+
let incoming;
|
|
85
|
+
try {
|
|
86
|
+
incoming = new URL(request.url ?? "/", redirect.origin);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
response.writeHead(400).end("Invalid callback URL.");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (accepted || request.method !== "GET" || request.headers.host !== redirect.host || incoming.pathname !== redirect.pathname) {
|
|
93
|
+
response.writeHead(404).end("Not found.");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const returnedState = Buffer.from(incoming.searchParams.get("state") ?? "");
|
|
97
|
+
const expectedState = Buffer.from(state);
|
|
98
|
+
if (incoming.searchParams.getAll("state").length !== 1 || returnedState.length !== expectedState.length || !timingSafeEqual(returnedState, expectedState)) {
|
|
99
|
+
response.writeHead(400).end("Invalid login state. Return to the terminal and try again.");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const returnedIssuer = incoming.searchParams.get("iss");
|
|
103
|
+
if (returnedIssuer !== null && (incoming.searchParams.getAll("iss").length !== 1 || returnedIssuer !== config.issuer)) {
|
|
104
|
+
response.writeHead(400).end("The login issuer did not match.");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
accepted = true;
|
|
108
|
+
if (incoming.searchParams.has("error")) {
|
|
109
|
+
response.writeHead(400).end("Login was not approved. Return to the terminal.", () => rejectCode(new Error("OAuth authorization was denied or cancelled. Run login again to retry.")));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const code = incoming.searchParams.get("code");
|
|
113
|
+
if (!code || incoming.searchParams.getAll("code").length !== 1) {
|
|
114
|
+
response.writeHead(400).end("The provider returned no authorization code.", () => rejectCode(new Error("OAuth callback did not contain one authorization code.")));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
response.end("Authorization received. Return to the terminal to finish signing in.", () => resolveCode(code));
|
|
118
|
+
});
|
|
119
|
+
server.headersTimeout = 10_000;
|
|
120
|
+
server.requestTimeout = 10_000;
|
|
121
|
+
const aborted = () => rejectCode(new Error("Browser login timed out or was cancelled. Run login again to retry."));
|
|
122
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
123
|
+
try {
|
|
124
|
+
await new Promise((resolve, reject) => {
|
|
125
|
+
server.once("error", reject);
|
|
126
|
+
server.listen(Number(redirect.port) || 0, redirect.hostname === "[::1]" ? "::1" : "127.0.0.1", () => { server.off("error", reject); resolve(); });
|
|
127
|
+
});
|
|
128
|
+
const address = server.address();
|
|
129
|
+
if (!address || typeof address === "string")
|
|
130
|
+
throw new Error("Could not start the OAuth callback listener.");
|
|
131
|
+
redirect.port = String(address.port);
|
|
132
|
+
signal.throwIfAborted();
|
|
133
|
+
const authorization = new URL(endpoints.authorizationUrl);
|
|
134
|
+
if (config.organization) {
|
|
135
|
+
const other = config.organization.parameter === "organization" ? "organization_id" : "organization";
|
|
136
|
+
if (authorization.searchParams.has(other))
|
|
137
|
+
throw new Error("The authorization URL contains a conflicting organization parameter. Update the provider configuration.");
|
|
138
|
+
authorization.searchParams.set(config.organization.parameter, config.organization.id);
|
|
139
|
+
}
|
|
140
|
+
for (const [key, value] of Object.entries({ response_type: "code", client_id: config.clientId, redirect_uri: redirect.href, state, code_challenge: challenge, code_challenge_method: "S256", ...(config.scopes?.length ? { scope: config.scopes.join(" ") } : {}), ...(config.audience ? { audience: config.audience } : {}), ...(config.resource ? { resource: config.resource } : {}) }))
|
|
141
|
+
authorization.searchParams.set(key, value);
|
|
142
|
+
await interaction.authorize(authorization.href);
|
|
143
|
+
const code = await codeResult;
|
|
144
|
+
signal.throwIfAborted();
|
|
145
|
+
const response = await oauthJsonRequest(endpoints.tokenUrl, {
|
|
146
|
+
method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" }, redirect: "error",
|
|
147
|
+
body: new URLSearchParams({ grant_type: "authorization_code", client_id: config.clientId, redirect_uri: redirect.href, code, code_verifier: verifier, ...(config.audience ? { audience: config.audience } : {}), ...(config.resource ? { resource: config.resource } : {}) }),
|
|
148
|
+
signal,
|
|
149
|
+
});
|
|
150
|
+
const data = response.data;
|
|
151
|
+
if (response.status !== 200 || !data || typeof data.access_token !== "string" || !data.access_token || typeof data.token_type !== "string" || data.token_type.toLowerCase() !== "bearer") {
|
|
152
|
+
throw new Error(`OAuth token exchange failed (HTTP ${response.status}). Check the public client registration and run login again.`);
|
|
153
|
+
}
|
|
154
|
+
if (data.expires_in !== undefined && (typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in) || data.expires_in <= 0))
|
|
155
|
+
throw new Error("OAuth provider returned an invalid token lifetime.");
|
|
156
|
+
return {
|
|
157
|
+
accessToken: data.access_token,
|
|
158
|
+
...(typeof data.refresh_token === "string" && data.refresh_token ? { refreshToken: data.refresh_token } : {}),
|
|
159
|
+
...(typeof data.expires_in === "number" ? { expiresAt: Date.now() + data.expires_in * 1000 } : {}),
|
|
160
|
+
issuer: config.issuer, clientId: config.clientId, tokenUrl: endpoints.tokenUrl, redirectUri: redirect.href,
|
|
161
|
+
...(endpoints.revocationUrl ? { revocationUrl: endpoints.revocationUrl } : {}),
|
|
162
|
+
...(typeof data.scope === "string" ? { scopes: data.scope.split(/\s+/).filter(Boolean) } : {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
signal.removeEventListener("abort", aborted);
|
|
167
|
+
server.closeAllConnections();
|
|
168
|
+
if (server.listening)
|
|
169
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class OAuthResponseError extends Error {
|
|
2
|
+
readonly code: "request_failed" | "timed_out" | "cancelled" | "response_too_large" | "invalid_response";
|
|
3
|
+
constructor(code: OAuthResponseError["code"]);
|
|
4
|
+
}
|
|
5
|
+
export type DeviceOAuthError = "authorization_pending" | "slow_down" | "access_denied" | "expired_token";
|
|
6
|
+
interface AuthenticationResponse {
|
|
7
|
+
status: number;
|
|
8
|
+
data?: Record<string, unknown>;
|
|
9
|
+
error?: DeviceOAuthError;
|
|
10
|
+
}
|
|
11
|
+
/** Error bodies and transport causes may contain credentials and are discarded. */
|
|
12
|
+
export declare function oauthJsonRequest(url: string | URL, init?: RequestInit, timeoutMs?: number): Promise<AuthenticationResponse>;
|
|
13
|
+
/** Device polling needs four protocol errors. Return only their exact names,
|
|
14
|
+
* never descriptions, error URIs, arbitrary error codes or other body fields. */
|
|
15
|
+
export declare function oauthDeviceRequest(url: string | URL, init?: RequestInit, timeoutMs?: number): Promise<AuthenticationResponse>;
|
|
16
|
+
/** Revocation may return an empty success body. Do not wait for or parse it. */
|
|
17
|
+
export declare function oauthStatusRequest(url: string | URL, init?: RequestInit, timeoutMs?: number): Promise<{
|
|
18
|
+
status: number;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=oauth-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-request.d.ts","sourceRoot":"","sources":["../src/oauth-request.ts"],"names":[],"mappings":"AACA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,GAAG,WAAW,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;gBAC5F,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;CAY7C;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,WAAW,GAAG,eAAe,GAAG,eAAe,CAAC;AACzG,UAAU,sBAAsB;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;CAAE;AAE7G,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAE/H;AACD;iFACiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAEjI;AACD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAE7H"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export class OAuthResponseError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code) {
|
|
4
|
+
const messages = {
|
|
5
|
+
request_failed: "OAuth request failed. Check the configured provider endpoint.",
|
|
6
|
+
timed_out: "OAuth request timed out. Run login again to retry.",
|
|
7
|
+
cancelled: "OAuth request was cancelled.",
|
|
8
|
+
response_too_large: "OAuth provider response exceeded 1 MiB.",
|
|
9
|
+
invalid_response: "OAuth provider returned an invalid JSON response.",
|
|
10
|
+
};
|
|
11
|
+
super(messages[code]);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = "OAuthResponseError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Error bodies and transport causes may contain credentials and are discarded. */
|
|
17
|
+
export function oauthJsonRequest(url, init = {}, timeoutMs = 30_000) {
|
|
18
|
+
return boundedRequest(url, init, timeoutMs, "json");
|
|
19
|
+
}
|
|
20
|
+
/** Device polling needs four protocol errors. Return only their exact names,
|
|
21
|
+
* never descriptions, error URIs, arbitrary error codes or other body fields. */
|
|
22
|
+
export function oauthDeviceRequest(url, init = {}, timeoutMs = 30_000) {
|
|
23
|
+
return boundedRequest(url, init, timeoutMs, "device");
|
|
24
|
+
}
|
|
25
|
+
/** Revocation may return an empty success body. Do not wait for or parse it. */
|
|
26
|
+
export function oauthStatusRequest(url, init = {}, timeoutMs = 30_000) {
|
|
27
|
+
return boundedRequest(url, init, timeoutMs, "status");
|
|
28
|
+
}
|
|
29
|
+
/** Bound the entire exchange, including decoded response bytes. */
|
|
30
|
+
async function boundedRequest(url, init, timeoutMs, mode) {
|
|
31
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 30_000)
|
|
32
|
+
throw new OAuthResponseError("request_failed");
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
let reader;
|
|
35
|
+
let timer;
|
|
36
|
+
let interrupted;
|
|
37
|
+
let rejectDeadline;
|
|
38
|
+
const deadline = new Promise((_, reject) => { rejectDeadline = reject; });
|
|
39
|
+
const stop = (code) => { interrupted ??= code; rejectDeadline(new OAuthResponseError(interrupted)); controller.abort(); };
|
|
40
|
+
const cancel = () => stop("cancelled");
|
|
41
|
+
init.signal?.addEventListener("abort", cancel, { once: true });
|
|
42
|
+
timer = setTimeout(() => stop("timed_out"), timeoutMs);
|
|
43
|
+
try {
|
|
44
|
+
if (init.signal?.aborted)
|
|
45
|
+
throw new OAuthResponseError("cancelled");
|
|
46
|
+
const request = { ...init, redirect: "error", credentials: "omit", cache: "no-store", signal: controller.signal };
|
|
47
|
+
const response = await Promise.race([
|
|
48
|
+
fetch(url, request).then((value) => {
|
|
49
|
+
// Also dispose a late response from a transport that ignored abort.
|
|
50
|
+
if (controller.signal.aborted)
|
|
51
|
+
void value.body?.cancel().catch(() => { });
|
|
52
|
+
return value;
|
|
53
|
+
}), deadline,
|
|
54
|
+
]);
|
|
55
|
+
if (response.redirected) {
|
|
56
|
+
void response.body?.cancel().catch(() => { });
|
|
57
|
+
throw new OAuthResponseError("request_failed");
|
|
58
|
+
}
|
|
59
|
+
if (mode === "status" || response.status !== 200 && !(mode === "device" && response.status === 400)) {
|
|
60
|
+
void response.body?.cancel().catch(() => { });
|
|
61
|
+
return { status: response.status };
|
|
62
|
+
}
|
|
63
|
+
if (!response.body)
|
|
64
|
+
throw new OAuthResponseError("invalid_response");
|
|
65
|
+
reader = response.body.getReader();
|
|
66
|
+
let size = 0, text = "";
|
|
67
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
68
|
+
while (true) {
|
|
69
|
+
const chunk = await Promise.race([reader.read(), deadline]);
|
|
70
|
+
if (chunk.done)
|
|
71
|
+
break;
|
|
72
|
+
size += chunk.value.byteLength;
|
|
73
|
+
if (size > 1_048_576)
|
|
74
|
+
throw new OAuthResponseError("response_too_large");
|
|
75
|
+
try {
|
|
76
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new OAuthResponseError("invalid_response");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
text += decoder.decode();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new OAuthResponseError("invalid_response");
|
|
87
|
+
}
|
|
88
|
+
let data;
|
|
89
|
+
try {
|
|
90
|
+
data = JSON.parse(text);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
throw new OAuthResponseError("invalid_response");
|
|
94
|
+
}
|
|
95
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
96
|
+
throw new OAuthResponseError("invalid_response");
|
|
97
|
+
if (response.status !== 200) {
|
|
98
|
+
const error = data.error;
|
|
99
|
+
return { status: response.status, ...(["authorization_pending", "slow_down", "access_denied", "expired_token"].includes(String(error)) && typeof error === "string" ? { error: error } : {}) };
|
|
100
|
+
}
|
|
101
|
+
return { status: response.status, data: data };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (interrupted)
|
|
105
|
+
throw new OAuthResponseError(interrupted);
|
|
106
|
+
if (error instanceof OAuthResponseError)
|
|
107
|
+
throw error;
|
|
108
|
+
throw new OAuthResponseError("request_failed");
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
init.signal?.removeEventListener("abort", cancel);
|
|
113
|
+
controller.abort();
|
|
114
|
+
if (reader) {
|
|
115
|
+
void reader.cancel().catch(() => { });
|
|
116
|
+
reader.releaseLock();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type IdentityConfiguration, type VerifiedIdentity } from "./api-identity.js";
|
|
2
|
+
export interface StoredOAuthSession {
|
|
3
|
+
accessToken: string;
|
|
4
|
+
refreshToken?: string;
|
|
5
|
+
expiresAt?: number;
|
|
6
|
+
tokenUrl?: string;
|
|
7
|
+
issuer?: string;
|
|
8
|
+
clientId?: string;
|
|
9
|
+
revocationUrl?: string;
|
|
10
|
+
apiBaseUrl?: string;
|
|
11
|
+
configuredClientId?: string | null;
|
|
12
|
+
scopes?: string[];
|
|
13
|
+
/** New login identity, independent of rotating tokens. */
|
|
14
|
+
sessionId: string;
|
|
15
|
+
binding: string;
|
|
16
|
+
/** Persisted before exchange: an interrupted exchange must not replay a rotating token. */
|
|
17
|
+
refreshPending?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface CredentialDestination {
|
|
20
|
+
apiBaseUrl: string;
|
|
21
|
+
environment?: string;
|
|
22
|
+
profile?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function assertCredentialDestination(credentials: StoredCredentials, destination: CredentialDestination): void;
|
|
25
|
+
export interface StoredCredentials {
|
|
26
|
+
destination?: CredentialDestination;
|
|
27
|
+
named?: Record<string, string | {
|
|
28
|
+
username: string;
|
|
29
|
+
password: string;
|
|
30
|
+
}>;
|
|
31
|
+
scalars?: Record<string, string>;
|
|
32
|
+
basic?: {
|
|
33
|
+
username: string;
|
|
34
|
+
password: string;
|
|
35
|
+
};
|
|
36
|
+
oauth?: StoredOAuthSession;
|
|
37
|
+
identity?: VerifiedIdentity & {
|
|
38
|
+
binding: string;
|
|
39
|
+
};
|
|
40
|
+
minted?: {
|
|
41
|
+
via: "browser";
|
|
42
|
+
key_name: string;
|
|
43
|
+
org_id?: string;
|
|
44
|
+
revocationUrl?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface SessionConfiguration extends CredentialDestination {
|
|
48
|
+
identity?: IdentityConfiguration;
|
|
49
|
+
verifyIdentity?: (accessToken: string) => Promise<VerifiedIdentity>;
|
|
50
|
+
clientId?: string | null;
|
|
51
|
+
issuer?: string | null;
|
|
52
|
+
tokenUrl?: string | null;
|
|
53
|
+
discoveryUrl?: string | null;
|
|
54
|
+
authorizationUrl?: string | null;
|
|
55
|
+
scopes?: string[];
|
|
56
|
+
audience?: string;
|
|
57
|
+
resource?: string;
|
|
58
|
+
organizationParameter?: "organization" | "organization_id";
|
|
59
|
+
}
|
|
60
|
+
/** Bind minimal identity evidence to this credential set and its configured read. */
|
|
61
|
+
export declare function credentialIdentityBinding(credentials: StoredCredentials, identity: IdentityConfiguration): string;
|
|
62
|
+
export declare function assertStoredIdentity(credentials: StoredCredentials, identity?: IdentityConfiguration): void;
|
|
63
|
+
/** Bind the login to effective nonsecret settings. Scope ordering is irrelevant. */
|
|
64
|
+
export declare function sessionBinding(config: SessionConfiguration): string;
|
|
65
|
+
interface LockedCredentials {
|
|
66
|
+
read(): StoredCredentials | null;
|
|
67
|
+
write(credentials: StoredCredentials | null): void;
|
|
68
|
+
}
|
|
69
|
+
export interface CredentialStore {
|
|
70
|
+
read(): StoredCredentials | null;
|
|
71
|
+
withLock<T>(work: (store: LockedCredentials) => Promise<T>): Promise<T>;
|
|
72
|
+
}
|
|
73
|
+
export declare class CredentialStorageError extends Error {
|
|
74
|
+
}
|
|
75
|
+
export interface CredentialCodec {
|
|
76
|
+
readonly name: string;
|
|
77
|
+
prepare(): void;
|
|
78
|
+
encode(plaintext: string): string;
|
|
79
|
+
decode(encoded: string): string;
|
|
80
|
+
}
|
|
81
|
+
/** Private file adapter. All writers (login, refresh and logout) use the same
|
|
82
|
+
* cross-process lock. Credential storage can be replaced independently of OAuth. */
|
|
83
|
+
export declare class FileCredentialStore implements CredentialStore {
|
|
84
|
+
readonly path: string;
|
|
85
|
+
private readonly lockTimeoutMs;
|
|
86
|
+
private readonly codec?;
|
|
87
|
+
constructor(path: string, lockTimeoutMs?: number, codec?: CredentialCodec | undefined);
|
|
88
|
+
get backend(): string;
|
|
89
|
+
/** Check storage access before starting an interactive login. */
|
|
90
|
+
prepare(): Promise<void>;
|
|
91
|
+
read(): StoredCredentials | null;
|
|
92
|
+
private write;
|
|
93
|
+
withLock<T>(work: (store: LockedCredentials) => Promise<T>): Promise<T>;
|
|
94
|
+
private recoverDeadOwner;
|
|
95
|
+
update(change: (current: StoredCredentials) => StoredCredentials): Promise<void>;
|
|
96
|
+
/** Explicit local-only logout can remove an unreadable encrypted session. */
|
|
97
|
+
clear(): Promise<boolean>;
|
|
98
|
+
/** Remove under the refresh lock, then revoke the latest token outside it. */
|
|
99
|
+
take(): Promise<StoredCredentials | null>;
|
|
100
|
+
}
|
|
101
|
+
/** Re-read on every request attempt; only one process may rotate the token.
|
|
102
|
+
* A failed or interrupted exchange requires login, since the server may have
|
|
103
|
+
* consumed its refresh token even when no response reached this process. */
|
|
104
|
+
export declare function oauthSessionToken(store: CredentialStore, config: SessionConfiguration, sessionId: string, tokenParams?: Record<string, string>): Promise<string>;
|
|
105
|
+
export {};
|
|
106
|
+
//# sourceMappingURL=oauth-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-session.d.ts","sourceRoot":"","sources":["../src/oauth-session.ts"],"names":[],"mappings":"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"}
|