@dbx-tools/auth 0.9.51 → 0.9.58
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 +11 -3
- package/index.ts +3 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -2
- package/lib/src/_profile-config.js +37 -22
- package/lib/src/client.js +15 -1
- package/lib/src/profile.d.ts +2 -2
- package/lib/src/profile.js +22 -3
- package/lib/src/runtime-auth.d.ts +21 -0
- package/lib/src/runtime-auth.js +139 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -4
- package/src/_profile-config.ts +43 -22
- package/src/client.ts +15 -0
- package/src/profile.ts +23 -3
- package/src/runtime-auth.ts +209 -0
package/lib/src/profile.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface ListProfilesOptions {
|
|
|
5
5
|
configFile?: string;
|
|
6
6
|
refresh?: boolean;
|
|
7
7
|
}
|
|
8
|
-
/** Resolve one
|
|
9
|
-
export declare function resolveProfile(options?: DatabricksAuthOptions): DatabricksProfileSummary;
|
|
8
|
+
/** Resolve one configured profile without exposing credentials, or `null` when none exists. */
|
|
9
|
+
export declare function resolveProfile(options?: DatabricksAuthOptions): DatabricksProfileSummary | null;
|
|
10
10
|
/** List configured profiles without exposing credentials. */
|
|
11
11
|
export declare function listProfiles(options?: ListProfilesOptions): DatabricksProfileSummary[];
|
package/lib/src/profile.js
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
import { AuthError } from "./_errors.js";
|
|
1
2
|
import { listDatabricksProfiles, resolveDatabricksProfile } from "./_profile-config.js";
|
|
2
|
-
/** Resolve one
|
|
3
|
+
/** Resolve one configured profile without exposing credentials, or `null` when none exists. */
|
|
3
4
|
export function resolveProfile(options = {}) {
|
|
4
|
-
|
|
5
|
+
const configured = listDatabricksProfiles(options.configFile);
|
|
6
|
+
if (configured.length === 0)
|
|
7
|
+
return null;
|
|
8
|
+
const environment = options.configFile
|
|
9
|
+
? { DATABRICKS_CONFIG_FILE: options.configFile }
|
|
10
|
+
: process.env;
|
|
11
|
+
try {
|
|
12
|
+
const resolved = resolveDatabricksProfile(options, environment);
|
|
13
|
+
if (!resolved.selectedProfile ||
|
|
14
|
+
!configured.some(({ name }) => name === resolved.selectedProfile)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return toProfileSummary(resolved);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof AuthError && error.kind === "config")
|
|
21
|
+
return null;
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
5
24
|
}
|
|
6
25
|
/** List configured profiles without exposing credentials. */
|
|
7
26
|
export function listProfiles(options = {}) {
|
|
@@ -18,4 +37,4 @@ function toProfileSummary(profile) {
|
|
|
18
37
|
principal: profile.principal,
|
|
19
38
|
};
|
|
20
39
|
}
|
|
21
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
40
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZmlsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9maWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDekMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLHdCQUF3QixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFVeEYsK0ZBQStGO0FBQy9GLE1BQU0sVUFBVSxjQUFjLENBQzVCLFVBQWlDLEVBQUU7SUFFbkMsTUFBTSxVQUFVLEdBQUcsc0JBQXNCLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzlELElBQUksVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDekMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLFVBQVU7UUFDcEMsQ0FBQyxDQUFDLEVBQUUsc0JBQXNCLEVBQUUsT0FBTyxDQUFDLFVBQVUsRUFBRTtRQUNoRCxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUNoQixJQUFJLENBQUM7UUFDSCxNQUFNLFFBQVEsR0FBRyx3QkFBd0IsQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDaEUsSUFDRSxDQUFDLFFBQVEsQ0FBQyxlQUFlO1lBQ3pCLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksS0FBSyxRQUFRLENBQUMsZUFBZSxDQUFDLEVBQ2pFLENBQUM7WUFDRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxLQUFLLFlBQVksU0FBUyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssUUFBUTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3ZFLE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsTUFBTSxVQUFVLFlBQVksQ0FBQyxVQUErQixFQUFFO0lBQzVELE9BQU8sc0JBQXNCLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDckUsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsT0FBMEI7SUFDbEQsT0FBTztRQUNMLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtRQUNsQixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7UUFDbEIsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzlELEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNwRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07UUFDdEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1FBQzFCLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztLQUM3QixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRGF0YWJyaWNrc1Byb2ZpbGVTdW1tYXJ5IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWF1dGgvcHJvZmlsZVwiO1xuXG5pbXBvcnQgeyBBdXRoRXJyb3IgfSBmcm9tIFwiLi9fZXJyb3JzLnRzXCI7XG5pbXBvcnQgeyBsaXN0RGF0YWJyaWNrc1Byb2ZpbGVzLCByZXNvbHZlRGF0YWJyaWNrc1Byb2ZpbGUgfSBmcm9tIFwiLi9fcHJvZmlsZS1jb25maWcudHNcIjtcbmltcG9ydCB0eXBlIHsgRGF0YWJyaWNrc1Byb2ZpbGUgfSBmcm9tIFwiLi9fdHlwZXMudHNcIjtcbmltcG9ydCB0eXBlIHsgRGF0YWJyaWNrc0F1dGhPcHRpb25zIH0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5cbi8qKiBQcm9maWxlLWxpc3RpbmcgY29udHJvbHMuICovXG5leHBvcnQgaW50ZXJmYWNlIExpc3RQcm9maWxlc09wdGlvbnMge1xuICBjb25maWdGaWxlPzogc3RyaW5nO1xuICByZWZyZXNoPzogYm9vbGVhbjtcbn1cblxuLyoqIFJlc29sdmUgb25lIGNvbmZpZ3VyZWQgcHJvZmlsZSB3aXRob3V0IGV4cG9zaW5nIGNyZWRlbnRpYWxzLCBvciBgbnVsbGAgd2hlbiBub25lIGV4aXN0cy4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUHJvZmlsZShcbiAgb3B0aW9uczogRGF0YWJyaWNrc0F1dGhPcHRpb25zID0ge30sXG4pOiBEYXRhYnJpY2tzUHJvZmlsZVN1bW1hcnkgfCBudWxsIHtcbiAgY29uc3QgY29uZmlndXJlZCA9IGxpc3REYXRhYnJpY2tzUHJvZmlsZXMob3B0aW9ucy5jb25maWdGaWxlKTtcbiAgaWYgKGNvbmZpZ3VyZWQubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgZW52aXJvbm1lbnQgPSBvcHRpb25zLmNvbmZpZ0ZpbGVcbiAgICA/IHsgREFUQUJSSUNLU19DT05GSUdfRklMRTogb3B0aW9ucy5jb25maWdGaWxlIH1cbiAgICA6IHByb2Nlc3MuZW52O1xuICB0cnkge1xuICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZURhdGFicmlja3NQcm9maWxlKG9wdGlvbnMsIGVudmlyb25tZW50KTtcbiAgICBpZiAoXG4gICAgICAhcmVzb2x2ZWQuc2VsZWN0ZWRQcm9maWxlIHx8XG4gICAgICAhY29uZmlndXJlZC5zb21lKCh7IG5hbWUgfSkgPT4gbmFtZSA9PT0gcmVzb2x2ZWQuc2VsZWN0ZWRQcm9maWxlKVxuICAgICkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiB0b1Byb2ZpbGVTdW1tYXJ5KHJlc29sdmVkKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBBdXRoRXJyb3IgJiYgZXJyb3Iua2luZCA9PT0gXCJjb25maWdcIikgcmV0dXJuIG51bGw7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuLyoqIExpc3QgY29uZmlndXJlZCBwcm9maWxlcyB3aXRob3V0IGV4cG9zaW5nIGNyZWRlbnRpYWxzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3RQcm9maWxlcyhvcHRpb25zOiBMaXN0UHJvZmlsZXNPcHRpb25zID0ge30pOiBEYXRhYnJpY2tzUHJvZmlsZVN1bW1hcnlbXSB7XG4gIHJldHVybiBsaXN0RGF0YWJyaWNrc1Byb2ZpbGVzKG9wdGlvbnMuY29uZmlnRmlsZSwgb3B0aW9ucy5yZWZyZXNoKTtcbn1cblxuZnVuY3Rpb24gdG9Qcm9maWxlU3VtbWFyeShwcm9maWxlOiBEYXRhYnJpY2tzUHJvZmlsZSk6IERhdGFicmlja3NQcm9maWxlU3VtbWFyeSB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogcHJvZmlsZS5uYW1lLFxuICAgIGhvc3Q6IHByb2ZpbGUuaG9zdCxcbiAgICAuLi4ocHJvZmlsZS5hY2NvdW50SWQgPyB7IGFjY291bnRJZDogcHJvZmlsZS5hY2NvdW50SWQgfSA6IHt9KSxcbiAgICAuLi4ocHJvZmlsZS53b3Jrc3BhY2VJZCA/IHsgd29ya3NwYWNlSWQ6IHByb2ZpbGUud29ya3NwYWNlSWQgfSA6IHt9KSxcbiAgICB0YXJnZXQ6IHByb2ZpbGUudGFyZ2V0LFxuICAgIGF1dGhUeXBlOiBwcm9maWxlLmF1dGhUeXBlLFxuICAgIHByaW5jaXBhbDogcHJvZmlsZS5wcmluY2lwYWwsXG4gIH07XG59XG4iXX0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AuthClient } from "./client.ts";
|
|
2
|
+
import { type DatabricksAuthOptions } from "./config.ts";
|
|
3
|
+
/** Python runtime authentication operations backed by one SDK WorkspaceClient. */
|
|
4
|
+
export interface DatabricksRuntimeAuthClient {
|
|
5
|
+
/** Resolved Databricks workspace URL. */
|
|
6
|
+
readonly host: string;
|
|
7
|
+
/** Resolved workspace identifier when the Python SDK provides one. */
|
|
8
|
+
readonly workspaceId?: string;
|
|
9
|
+
/** Resolved caller identifier when the Python SDK provides one. */
|
|
10
|
+
readonly principal?: string;
|
|
11
|
+
/** Return the Python SDK's directly configured token, when present. */
|
|
12
|
+
token(): Promise<string | undefined>;
|
|
13
|
+
/** Return fresh authentication headers from the Python SDK. */
|
|
14
|
+
authenticate(): Promise<Record<string, string>>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Return auth installed by the shared Python Node runtime, when available.
|
|
18
|
+
*/
|
|
19
|
+
export declare function _databricksRuntimeAuthClient(): Promise<DatabricksRuntimeAuthClient | undefined>;
|
|
20
|
+
/** Create an auth facade over a Python runtime WorkspaceClient. */
|
|
21
|
+
export declare function createDatabricksRuntimeAuthClient(runtime: DatabricksRuntimeAuthClient, options: DatabricksAuthOptions): AuthClient;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { RUNTIME_AUTH_TYPE } from "@dbx-tools/shared-auth/client";
|
|
2
|
+
import { TargetKind } from "@dbx-tools/shared-auth/config";
|
|
3
|
+
import { getAccessTokenPayload, getAccessTokenScopes } from "@dbx-tools/shared-core/token";
|
|
4
|
+
import { AuthError } from "./_errors.js";
|
|
5
|
+
import { TokenLifecycle } from "./_lifecycle.js";
|
|
6
|
+
import { normalizeHost } from "./_profile-config.js";
|
|
7
|
+
import { MemoryCredentialStore } from "./_storage.js";
|
|
8
|
+
import { AUTH_DEFAULTS, DEFAULT_ACCESS_TOKEN_HEADER, WORKSPACE_ID_HEADER, } from "./config.js";
|
|
9
|
+
const MINIMUM_RUNTIME_TOKEN_TTL_MS = 60_000;
|
|
10
|
+
const RUNTIME_PRINCIPAL = "runtime";
|
|
11
|
+
/**
|
|
12
|
+
* Return auth installed by the shared Python Node runtime, when available.
|
|
13
|
+
*/
|
|
14
|
+
export async function _databricksRuntimeAuthClient() {
|
|
15
|
+
const runtime = globalThis[Symbol.for("@dbx-tools/node-runtime/runtime")];
|
|
16
|
+
return runtime?.databricksRuntimeAuthClient?.();
|
|
17
|
+
}
|
|
18
|
+
/** Create an auth facade over a Python runtime WorkspaceClient. */
|
|
19
|
+
export function createDatabricksRuntimeAuthClient(runtime, options) {
|
|
20
|
+
const lifecycleOptions = {
|
|
21
|
+
...AUTH_DEFAULTS,
|
|
22
|
+
...options.auth,
|
|
23
|
+
};
|
|
24
|
+
const provider = new DatabricksRuntimeTokenProvider(runtime, lifecycleOptions.refreshBufferMs);
|
|
25
|
+
const lifecycle = new TokenLifecycle(runtimeCacheKey(runtime), provider, new MemoryCredentialStore(), lifecycleOptions);
|
|
26
|
+
return new DefaultDatabricksRuntimeAuthClient(runtime, provider, lifecycle);
|
|
27
|
+
}
|
|
28
|
+
function runtimeCacheKey(runtime) {
|
|
29
|
+
return [
|
|
30
|
+
RUNTIME_AUTH_TYPE,
|
|
31
|
+
normalizeHost(runtime.host, RUNTIME_PRINCIPAL),
|
|
32
|
+
runtime.workspaceId ?? "",
|
|
33
|
+
runtime.principal ?? "",
|
|
34
|
+
].join(":");
|
|
35
|
+
}
|
|
36
|
+
function normalizedHeaders(headers) {
|
|
37
|
+
return Object.fromEntries(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), value]));
|
|
38
|
+
}
|
|
39
|
+
function runtimeToken(headers, refreshBufferMs, configuredToken) {
|
|
40
|
+
const authorization = headers[DEFAULT_ACCESS_TOKEN_HEADER];
|
|
41
|
+
const match = authorization?.trim().match(/^(\S+)\s+(.+)$/);
|
|
42
|
+
const accessToken = match?.[2]?.trim() || configuredToken?.trim();
|
|
43
|
+
if (!accessToken) {
|
|
44
|
+
throw new AuthError("oauth", "Databricks Python runtime authentication did not provide an access token");
|
|
45
|
+
}
|
|
46
|
+
const payload = getAccessTokenPayload(accessToken);
|
|
47
|
+
const jwtExpiry = typeof payload.exp === "number" && Number.isFinite(payload.exp)
|
|
48
|
+
? new Date(payload.exp * 1000).toISOString()
|
|
49
|
+
: undefined;
|
|
50
|
+
// Opaque runtime credentials still need a bounded Node cache. Reacquire them
|
|
51
|
+
// from the Python SDK after one refresh-buffer interval.
|
|
52
|
+
const expiry = jwtExpiry ??
|
|
53
|
+
new Date(Date.now() + Math.max(refreshBufferMs * 2, MINIMUM_RUNTIME_TOKEN_TTL_MS)).toISOString();
|
|
54
|
+
return {
|
|
55
|
+
accessToken,
|
|
56
|
+
tokenType: match?.[1] || "Bearer",
|
|
57
|
+
...(expiry ? { expiry } : {}),
|
|
58
|
+
scopes: [...getAccessTokenScopes(accessToken)],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
class DatabricksRuntimeTokenProvider {
|
|
62
|
+
runtime;
|
|
63
|
+
refreshBufferMs;
|
|
64
|
+
#accessToken;
|
|
65
|
+
#headers;
|
|
66
|
+
constructor(runtime, refreshBufferMs) {
|
|
67
|
+
this.runtime = runtime;
|
|
68
|
+
this.refreshBufferMs = refreshBufferMs;
|
|
69
|
+
}
|
|
70
|
+
authenticate() {
|
|
71
|
+
return this.acquire();
|
|
72
|
+
}
|
|
73
|
+
login() {
|
|
74
|
+
return this.acquire();
|
|
75
|
+
}
|
|
76
|
+
refresh() {
|
|
77
|
+
return this.acquire();
|
|
78
|
+
}
|
|
79
|
+
canAuthenticateSilently() {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
headers(token) {
|
|
83
|
+
if (this.#accessToken === token.accessToken && this.#headers) {
|
|
84
|
+
return { ...this.#headers };
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
[DEFAULT_ACCESS_TOKEN_HEADER]: `${token.tokenType} ${token.accessToken}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
clear() {
|
|
91
|
+
this.#accessToken = undefined;
|
|
92
|
+
this.#headers = undefined;
|
|
93
|
+
}
|
|
94
|
+
async acquire() {
|
|
95
|
+
const headers = normalizedHeaders(await this.runtime.authenticate());
|
|
96
|
+
const token = runtimeToken(headers, this.refreshBufferMs, await this.runtime.token());
|
|
97
|
+
this.#accessToken = token.accessToken;
|
|
98
|
+
this.#headers = {
|
|
99
|
+
...headers,
|
|
100
|
+
[DEFAULT_ACCESS_TOKEN_HEADER]: `${token.tokenType} ${token.accessToken}`,
|
|
101
|
+
};
|
|
102
|
+
return token;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
class DefaultDatabricksRuntimeAuthClient {
|
|
106
|
+
provider;
|
|
107
|
+
lifecycle;
|
|
108
|
+
profile = undefined;
|
|
109
|
+
host;
|
|
110
|
+
accountId = undefined;
|
|
111
|
+
workspaceId;
|
|
112
|
+
target = TargetKind.Workspace;
|
|
113
|
+
authType = RUNTIME_AUTH_TYPE;
|
|
114
|
+
principal;
|
|
115
|
+
constructor(runtime, provider, lifecycle) {
|
|
116
|
+
this.provider = provider;
|
|
117
|
+
this.lifecycle = lifecycle;
|
|
118
|
+
this.host = normalizeHost(runtime.host, RUNTIME_PRINCIPAL);
|
|
119
|
+
this.workspaceId = runtime.workspaceId;
|
|
120
|
+
this.principal = runtime.principal || RUNTIME_PRINCIPAL;
|
|
121
|
+
}
|
|
122
|
+
token(options = {}) {
|
|
123
|
+
return options.refresh
|
|
124
|
+
? this.lifecycle.forceRefresh(options.login ?? true)
|
|
125
|
+
: this.lifecycle.tokenWithLogin(options.login);
|
|
126
|
+
}
|
|
127
|
+
async headers(options = {}) {
|
|
128
|
+
const headers = this.provider.headers(await this.token(options));
|
|
129
|
+
if (this.workspaceId && headers[WORKSPACE_ID_HEADER] === undefined) {
|
|
130
|
+
headers[WORKSPACE_ID_HEADER] = this.workspaceId;
|
|
131
|
+
}
|
|
132
|
+
return headers;
|
|
133
|
+
}
|
|
134
|
+
async logout() {
|
|
135
|
+
await this.lifecycle.logout();
|
|
136
|
+
this.provider.clear();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS1hdXRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUtYXV0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNsRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLHFCQUFxQixFQUFFLG9CQUFvQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFM0YsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUd0RCxPQUFPLEVBQ0wsYUFBYSxFQUViLDJCQUEyQixFQUMzQixtQkFBbUIsR0FDcEIsTUFBTSxhQUFhLENBQUM7QUFFckIsTUFBTSw0QkFBNEIsR0FBRyxNQUFNLENBQUM7QUFDNUMsTUFBTSxpQkFBaUIsR0FBRyxTQUFTLENBQUM7QUFvQnBDOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSw0QkFBNEI7SUFHaEQsTUFBTSxPQUFPLEdBQ1gsVUFHRCxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQyxDQUFDO0lBQ2pELE9BQU8sT0FBTyxFQUFFLDJCQUEyQixFQUFFLEVBQUUsQ0FBQztBQUNsRCxDQUFDO0FBRUQsbUVBQW1FO0FBQ25FLE1BQU0sVUFBVSxpQ0FBaUMsQ0FDL0MsT0FBb0MsRUFDcEMsT0FBOEI7SUFFOUIsTUFBTSxnQkFBZ0IsR0FBRztRQUN2QixHQUFHLGFBQWE7UUFDaEIsR0FBRyxPQUFPLENBQUMsSUFBSTtLQUNoQixDQUFDO0lBQ0YsTUFBTSxRQUFRLEdBQUcsSUFBSSw4QkFB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QUksSUFBSSxDQUFDLFdBQVcsSUFBSSxPQUFPLENBQUMsbUJBQW1CLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuRSxPQUFPLENBQUMsbUJBQW1CLENBQUMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO1FBQ2xELENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsS0FBSyxDQUFDLE1BQU07UUFDVixNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSVU5USU1FX0FVVEhfVFlQRSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1hdXRoL2NsaWVudFwiO1xuaW1wb3J0IHsgVGFyZ2V0S2luZCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1hdXRoL2NvbmZpZ1wiO1xuaW1wb3J0IHsgZ2V0QWNjZXNzVG9rZW5QYXlsb2FkLCBnZXRBY2Nlc3NUb2tlblNjb3BlcyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlL3Rva2VuXCI7XG5cbmltcG9ydCB7IEF1dGhFcnJvciB9IGZyb20gXCIuL19lcnJvcnMudHNcIjtcbmltcG9ydCB7IFRva2VuTGlmZWN5Y2xlIH0gZnJvbSBcIi4vX2xpZmVjeWNsZS50c1wiO1xuaW1wb3J0IHsgbm9ybWFsaXplSG9zdCB9IGZyb20gXCIuL19wcm9maWxlLWNvbmZpZy50c1wiO1xuaW1wb3J0IHsgTWVtb3J5Q3JlZGVudGlhbFN0b3JlIH0gZnJvbSBcIi4vX3N0b3JhZ2UudHNcIjtcbmltcG9ydCB0eXBlIHsgVG9rZW4sIFRva2VuUHJvdmlkZXIgfSBmcm9tIFwiLi9fdHlwZXMudHNcIjtcbmltcG9ydCB0eXBlIHsgQWNjZXNzVG9rZW4sIEF1dGhDbGllbnQsIFRva2VuT3B0aW9ucyB9IGZyb20gXCIuL2NsaWVudC50c1wiO1xuaW1wb3J0IHtcbiAgQVVUSF9ERUZBVUxUUyxcbiAgdHlwZSBEYXRhYnJpY2tzQXV0aE9wdGlvbnMsXG4gIERFRkFVTFRfQUNDRVNTX1RPS0VOX0hFQURFUixcbiAgV09SS1NQQUNFX0lEX0hFQURFUixcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5cbmNvbnN0IE1JTklNVU1fUlVOVElNRV9UT0tFTl9UVExfTVMgPSA2MF8wMDA7XG5jb25zdCBSVU5USU1FX1BSSU5DSVBBTCA9IFwicnVudGltZVwiO1xuXG4vKiogUHl0aG9uIHJ1bnRpbWUgYXV0aGVudGljYXRpb24gb3BlcmF0aW9ucyBiYWNrZWQgYnkgb25lIFNESyBXb3Jrc3BhY2VDbGllbnQuICovXG5leHBvcnQgaW50ZXJmYWNlIERhdGFicmlja3NSdW50aW1lQXV0aENsaWVudCB7XG4gIC8qKiBSZXNvbHZlZCBEYXRhYnJpY2tzIHdvcmtzcGFjZSBVUkwuICovXG4gIHJlYWRvbmx5IGhvc3Q6IHN0cmluZztcbiAgLyoqIFJlc29sdmVkIHdvcmtzcGFjZSBpZGVudGlmaWVyIHdoZW4gdGhlIFB5dGhvbiBTREsgcHJvdmlkZXMgb25lLiAqL1xuICByZWFkb25seSB3b3Jrc3BhY2VJZD86IHN0cmluZztcbiAgLyoqIFJlc29sdmVkIGNhbGxlciBpZGVudGlmaWVyIHdoZW4gdGhlIFB5dGhvbiBTREsgcHJvdmlkZXMgb25lLiAqL1xuICByZWFkb25seSBwcmluY2lwYWw/OiBzdHJpbmc7XG4gIC8qKiBSZXR1cm4gdGhlIFB5dGhvbiBTREsncyBkaXJlY3RseSBjb25maWd1cmVkIHRva2VuLCB3aGVuIHByZXNlbnQuICovXG4gIHRva2VuKCk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPjtcbiAgLyoqIFJldHVybiBmcmVzaCBhdXRoZW50aWNhdGlvbiBoZWFkZXJzIGZyb20gdGhlIFB5dGhvbiBTREsuICovXG4gIGF1dGhlbnRpY2F0ZSgpOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+O1xufVxuXG5pbnRlcmZhY2UgUHl0aG9uTm9kZVJ1bnRpbWUge1xuICBkYXRhYnJpY2tzUnVudGltZUF1dGhDbGllbnQ/KCk6IFByb21pc2U8RGF0YWJyaWNrc1J1bnRpbWVBdXRoQ2xpZW50IHwgdW5kZWZpbmVkPjtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYXV0aCBpbnN0YWxsZWQgYnkgdGhlIHNoYXJlZCBQeXRob24gTm9kZSBydW50aW1lLCB3aGVuIGF2YWlsYWJsZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIF9kYXRhYnJpY2tzUnVudGltZUF1dGhDbGllbnQoKTogUHJvbWlzZTxcbiAgRGF0YWJyaWNrc1J1bnRpbWVBdXRoQ2xpZW50IHwgdW5kZWZpbmVkXG4+IHtcbiAgY29uc3QgcnVudGltZSA9IChcbiAgICBnbG9iYWxUaGlzIGFzIHR5cGVvZiBnbG9iYWxUaGlzICYge1xuICAgICAgW2tleTogc3ltYm9sXTogUHl0aG9uTm9kZVJ1bnRpbWUgfCB1bmRlZmluZWQ7XG4gICAgfVxuICApW1N5bWJvbC5mb3IoXCJAZGJ4LXRvb2xzL25vZGUtcnVudGltZS9ydW50aW1lXCIpXTtcbiAgcmV0dXJuIHJ1bnRpbWU/LmRhdGFicmlja3NSdW50aW1lQXV0aENsaWVudD8uKCk7XG59XG5cbi8qKiBDcmVhdGUgYW4gYXV0aCBmYWNhZGUgb3ZlciBhIFB5dGhvbiBydW50aW1lIFdvcmtzcGFjZUNsaWVudC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVEYXRhYnJpY2tzUnVudGltZUF1dGhDbGllbnQoXG4gIHJ1bnRpbWU6IERhdGFicmlja3NSdW50aW1lQXV0aENsaWVudCxcbiAgb3B0aW9uczogRGF0YWJyaWNrc0F1dGhPcHRpb25zLFxuKTogQXV0aENsaWVudCB7XG4gIGNvbnN0IGxpZmVjeWNsZU9wdGlvbnMgPSB7XG4gICAgLi4uQVVUSF9ERUZBVUxUUyxcbiAgICAuLi5vcHRpb25zLmF1dGgsXG4gIH07XG4gIGNvbnN0IHByb3ZpZGVyID0gbmV3IERhdGFicmlja3NSdW50aW1lVG9rZW5Qcm92aWRlcihydW50aW1lLCBsaWZlY3ljbGVPcHRpb25zLnJlZnJlc2hCdWZmZXJNcyk7XG4gIGNvbnN0IGxpZmVjeWNsZSA9IG5ldyBUb2tlbkxpZmVjeWNsZShcbiAgICBydW50aW1lQ2FjaGVLZXkocnVudGltZSksXG4gICAgcHJvdmlkZXIsXG4gICAgbmV3IE1lbW9yeUNyZWRlbnRpYWxTdG9yZSgpLFxuICAgIGxpZmVjeWNsZU9wdGlvbnMsXG4gICk7XG4gIHJldHVybiBuZXcgRGVmYXVsdERhdGFicmlja3NSdW50aW1lQXV0aENsaWVudChydW50aW1lLCBwcm92aWRlciwgbGlmZWN5Y2xlKTtcbn1cblxuZnVuY3Rpb24gcnVudGltZUNhY2hlS2V5KHJ1bnRpbWU6IERhdGFicmlja3NSdW50aW1lQXV0aENsaWVudCk6IHN0cmluZyB7XG4gIHJldHVybiBbXG4gICAgUlVOVElNRV9BVVRIX1RZUEUsXG4gICAgbm9ybWFsaXplSG9zdChydW50aW1lLmhvc3QsIFJVTlRJTUVfUFJJTkNJUEFMKSxcbiAgICBydW50aW1lLndvcmtzcGFjZUlkID8/IFwiXCIsXG4gICAgcnVudGltZS5wcmluY2lwYWwgPz8gXCJcIixcbiAgXS5qb2luKFwiOlwiKTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplZEhlYWRlcnMoaGVhZGVyczogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBPYmplY3QuZW50cmllcyhoZWFkZXJzKS5tYXAoKFtuYW1lLCB2YWx1ZV0pID0+IFtuYW1lLnRvTG93ZXJDYXNlKCksIHZhbHVlXSksXG4gICk7XG59XG5cbmZ1bmN0aW9uIHJ1bnRpbWVUb2tlbihcbiAgaGVhZGVyczogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4sXG4gIHJlZnJlc2hCdWZmZXJNczogbnVtYmVyLFxuICBjb25maWd1cmVkVG9rZW4/OiBzdHJpbmcsXG4pOiBUb2tlbiB7XG4gIGNvbnN0IGF1dGhvcml6YXRpb24gPSBoZWFkZXJzW0RFRkFVTFRfQUNDRVNTX1RPS0VOX0hFQURFUl07XG4gIGNvbnN0IG1hdGNoID0gYXV0aG9yaXphdGlvbj8udHJpbSgpLm1hdGNoKC9eKFxcUyspXFxzKyguKykkLyk7XG4gIGNvbnN0IGFjY2Vzc1Rva2VuID0gbWF0Y2g/LlsyXT8udHJpbSgpIHx8IGNvbmZpZ3VyZWRUb2tlbj8udHJpbSgpO1xuICBpZiAoIWFjY2Vzc1Rva2VuKSB7XG4gICAgdGhyb3cgbmV3IEF1dGhFcnJvcihcbiAgICAgIFwib2F1dGhcIixcbiAgICAgIFwiRGF0YWJyaWNrcyBQeXRob24gcnVudGltZSBhdXRoZW50aWNhdGlvbiBkaWQgbm90IHByb3ZpZGUgYW4gYWNjZXNzIHRva2VuXCIsXG4gICAgKTtcbiAgfVxuICBjb25zdCBwYXlsb2FkID0gZ2V0QWNjZXNzVG9rZW5QYXlsb2FkKGFjY2Vzc1Rva2VuKTtcbiAgY29uc3Qgand0RXhwaXJ5ID1cbiAgICB0eXBlb2YgcGF5bG9hZC5leHAgPT09IFwibnVtYmVyXCIgJiYgTnVtYmVyLmlzRmluaXRlKHBheWxvYWQuZXhwKVxuICAgICAgPyBuZXcgRGF0ZShwYXlsb2FkLmV4cCAqIDEwMDApLnRvSVNPU3RyaW5nKClcbiAgICAgIDogdW5kZWZpbmVkO1xuICAvLyBPcGFxdWUgcnVudGltZSBjcmVkZW50aWFscyBzdGlsbCBuZWVkIGEgYm91bmRlZCBOb2RlIGNhY2hlLiBSZWFjcXVpcmUgdGhlbVxuICAvLyBmcm9tIHRoZSBQeXRob24gU0RLIGFmdGVyIG9uZSByZWZyZXNoLWJ1ZmZlciBpbnRlcnZhbC5cbiAgY29uc3QgZXhwaXJ5ID1cbiAgICBqd3RFeHBpcnkgPz9cbiAgICBuZXcgRGF0ZShcbiAgICAgIERhdGUubm93KCkgKyBNYXRoLm1heChyZWZyZXNoQnVmZmVyTXMgKiAyLCBNSU5JTVVNX1JVTlRJTUVfVE9LRU5fVFRMX01TKSxcbiAgICApLnRvSVNPU3RyaW5nKCk7XG4gIHJldHVybiB7XG4gICAgYWNjZXNzVG9rZW4sXG4gICAgdG9rZW5UeXBlOiBtYXRjaD8uWzFdIHx8IFwiQmVhcmVyXCIsXG4gICAgLi4uKGV4cGlyeSA/IHsgZXhwaXJ5IH0gOiB7fSksXG4gICAgc2NvcGVzOiBbLi4uZ2V0QWNjZXNzVG9rZW5TY29wZXMoYWNjZXNzVG9rZW4pXSxcbiAgfTtcbn1cblxuY2xhc3MgRGF0YWJyaWNrc1J1bnRpbWVUb2tlblByb3ZpZGVyIGltcGxlbWVudHMgVG9rZW5Qcm92aWRlciB7XG4gICNhY2Nlc3NUb2tlbj86IHN0cmluZztcbiAgI2hlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcnVudGltZTogRGF0YWJyaWNrc1J1bnRpbWVBdXRoQ2xpZW50LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcmVmcmVzaEJ1ZmZlck1zOiBudW1iZXIsXG4gICkge31cblxuICBhdXRoZW50aWNhdGUoKTogUHJvbWlzZTxUb2tlbj4ge1xuICAgIHJldHVybiB0aGlzLmFjcXVpcmUoKTtcbiAgfVxuXG4gIGxvZ2luKCk6IFByb21pc2U8VG9rZW4+IHtcbiAgICByZXR1cm4gdGhpcy5hY3F1aXJlKCk7XG4gIH1cblxuICByZWZyZXNoKCk6IFByb21pc2U8VG9rZW4+IHtcbiAgICByZXR1cm4gdGhpcy5hY3F1aXJlKCk7XG4gIH1cblxuICBjYW5BdXRoZW50aWNhdGVTaWxlbnRseSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGhlYWRlcnModG9rZW46IEFjY2Vzc1Rva2VuKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuI2FjY2Vzc1Rva2VuID09PSB0b2tlbi5hY2Nlc3NUb2tlbiAmJiB0aGlzLiNoZWFkZXJzKSB7XG4gICAgICByZXR1cm4geyAuLi50aGlzLiNoZWFkZXJzIH07XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBbREVGQVVMVF9BQ0NFU1NfVE9LRU5fSEVBREVSXTogYCR7dG9rZW4udG9rZW5UeXBlfSAke3Rva2VuLmFjY2Vzc1Rva2VufWAsXG4gICAgfTtcbiAgfVxuXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMuI2FjY2Vzc1Rva2VuID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuI2hlYWRlcnMgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGFjcXVpcmUoKTogUHJvbWlzZTxUb2tlbj4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBub3JtYWxpemVkSGVhZGVycyhhd2FpdCB0aGlzLnJ1bnRpbWUuYXV0aGVudGljYXRlKCkpO1xuICAgIGNvbnN0IHRva2VuID0gcnVudGltZVRva2VuKGhlYWRlcnMsIHRoaXMucmVmcmVzaEJ1ZmZlck1zLCBhd2FpdCB0aGlzLnJ1bnRpbWUudG9rZW4oKSk7XG4gICAgdGhpcy4jYWNjZXNzVG9rZW4gPSB0b2tlbi5hY2Nlc3NUb2tlbjtcbiAgICB0aGlzLiNoZWFkZXJzID0ge1xuICAgICAgLi4uaGVhZGVycyxcbiAgICAgIFtERUZBVUxUX0FDQ0VTU19UT0tFTl9IRUFERVJdOiBgJHt0b2tlbi50b2tlblR5cGV9ICR7dG9rZW4uYWNjZXNzVG9rZW59YCxcbiAgICB9O1xuICAgIHJldHVybiB0b2tlbjtcbiAgfVxufVxuXG5jbGFzcyBEZWZhdWx0RGF0YWJyaWNrc1J1bnRpbWVBdXRoQ2xpZW50IGltcGxlbWVudHMgQXV0aENsaWVudCB7XG4gIHJlYWRvbmx5IHByb2ZpbGUgPSB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IGhvc3Q6IHN0cmluZztcbiAgcmVhZG9ubHkgYWNjb3VudElkID0gdW5kZWZpbmVkO1xuICByZWFkb25seSB3b3Jrc3BhY2VJZD86IHN0cmluZztcbiAgcmVhZG9ubHkgdGFyZ2V0ID0gVGFyZ2V0S2luZC5Xb3Jrc3BhY2U7XG4gIHJlYWRvbmx5IGF1dGhUeXBlID0gUlVOVElNRV9BVVRIX1RZUEU7XG4gIHJlYWRvbmx5IHByaW5jaXBhbDogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHJ1bnRpbWU6IERhdGFicmlja3NSdW50aW1lQXV0aENsaWVudCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHByb3ZpZGVyOiBEYXRhYnJpY2tzUnVudGltZVRva2VuUHJvdmlkZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBsaWZlY3ljbGU6IFRva2VuTGlmZWN5Y2xlLFxuICApIHtcbiAgICB0aGlzLmhvc3QgPSBub3JtYWxpemVIb3N0KHJ1bnRpbWUuaG9zdCwgUlVOVElNRV9QUklOQ0lQQUwpO1xuICAgIHRoaXMud29ya3NwYWNlSWQgPSBydW50aW1lLndvcmtzcGFjZUlkO1xuICAgIHRoaXMucHJpbmNpcGFsID0gcnVudGltZS5wcmluY2lwYWwgfHwgUlVOVElNRV9QUklOQ0lQQUw7XG4gIH1cblxuICB0b2tlbihvcHRpb25zOiBUb2tlbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8QWNjZXNzVG9rZW4+IHtcbiAgICByZXR1cm4gb3B0aW9ucy5yZWZyZXNoXG4gICAgICA/IHRoaXMubGlmZWN5Y2xlLmZvcmNlUmVmcmVzaChvcHRpb25zLmxvZ2luID8/IHRydWUpXG4gICAgICA6IHRoaXMubGlmZWN5Y2xlLnRva2VuV2l0aExvZ2luKG9wdGlvbnMubG9naW4pO1xuICB9XG5cbiAgYXN5bmMgaGVhZGVycyhvcHRpb25zOiBUb2tlbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSB0aGlzLnByb3ZpZGVyLmhlYWRlcnMoYXdhaXQgdGhpcy50b2tlbihvcHRpb25zKSk7XG4gICAgaWYgKHRoaXMud29ya3NwYWNlSWQgJiYgaGVhZGVyc1tXT1JLU1BBQ0VfSURfSEVBREVSXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBoZWFkZXJzW1dPUktTUEFDRV9JRF9IRUFERVJdID0gdGhpcy53b3Jrc3BhY2VJZDtcbiAgICB9XG4gICAgcmV0dXJuIGhlYWRlcnM7XG4gIH1cblxuICBhc3luYyBsb2dvdXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5saWZlY3ljbGUubG9nb3V0KCk7XG4gICAgdGhpcy5wcm92aWRlci5jbGVhcigpO1xuICB9XG59XG4iXX0=
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/_databricks-cli.ts","../src/_errors.ts","../src/_lifecycle.ts","../src/_logging.ts","../src/_personal-access-token.ts","../src/_profile-config.ts","../src/_service-principal.ts","../src/_storage.ts","../src/_types.ts","../src/bindings.ts","../src/client.ts","../src/config.ts","../src/profile.ts","../index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/_databricks-cli.ts","../src/_errors.ts","../src/_lifecycle.ts","../src/_logging.ts","../src/_personal-access-token.ts","../src/_profile-config.ts","../src/_service-principal.ts","../src/_storage.ts","../src/_types.ts","../src/bindings.ts","../src/client.ts","../src/config.ts","../src/profile.ts","../src/runtime-auth.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"typescript": "^5.9.3"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@dbx-tools/core": "^0.9.
|
|
28
|
-
"@dbx-tools/shared-auth": "^0.9.
|
|
29
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
27
|
+
"@dbx-tools/core": "^0.9.58",
|
|
28
|
+
"@dbx-tools/shared-auth": "^0.9.58",
|
|
29
|
+
"@dbx-tools/shared-core": "^0.9.58",
|
|
30
30
|
"ini": "^6.0.0",
|
|
31
31
|
"oauth4webapi": "^3.8.8",
|
|
32
32
|
"zod": "4.3.6"
|
|
@@ -58,10 +58,14 @@
|
|
|
58
58
|
"types": "./lib/src/profile.d.ts",
|
|
59
59
|
"default": "./lib/src/profile.js"
|
|
60
60
|
},
|
|
61
|
+
"./runtime-auth": {
|
|
62
|
+
"types": "./lib/src/runtime-auth.d.ts",
|
|
63
|
+
"default": "./lib/src/runtime-auth.js"
|
|
64
|
+
},
|
|
61
65
|
"./package.json": "./package.json"
|
|
62
66
|
}
|
|
63
67
|
},
|
|
64
|
-
"version": "0.9.
|
|
68
|
+
"version": "0.9.58",
|
|
65
69
|
"types": "./lib/index.d.ts",
|
|
66
70
|
"dbxToolsConfig": {
|
|
67
71
|
"tags": [
|
|
@@ -90,6 +94,10 @@
|
|
|
90
94
|
"types": "./lib/src/profile.d.ts",
|
|
91
95
|
"default": "./lib/src/profile.js"
|
|
92
96
|
},
|
|
97
|
+
"./runtime-auth": {
|
|
98
|
+
"types": "./lib/src/runtime-auth.d.ts",
|
|
99
|
+
"default": "./lib/src/runtime-auth.js"
|
|
100
|
+
},
|
|
93
101
|
"./package.json": "./package.json"
|
|
94
102
|
},
|
|
95
103
|
"files": [
|
package/src/_profile-config.ts
CHANGED
|
@@ -106,14 +106,29 @@ export function parseDatabricksConfig(source: string): IniConfig {
|
|
|
106
106
|
if (!name.trim() || !object.isRecord(value)) {
|
|
107
107
|
throw new AuthError("config", "Databricks configuration values must belong to a profile");
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
_appendConfigSections(config, [name.trim()], value);
|
|
110
|
+
}
|
|
111
|
+
return config;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function _appendConfigSections(
|
|
115
|
+
config: IniConfig,
|
|
116
|
+
path: readonly string[],
|
|
117
|
+
value: Record<string, unknown>,
|
|
118
|
+
): void {
|
|
119
|
+
const section = new Map<string, string>();
|
|
120
|
+
let nested = false;
|
|
121
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
122
|
+
if (object.isRecord(entry)) {
|
|
123
|
+
nested = true;
|
|
124
|
+
_appendConfigSections(config, [...path, key], entry);
|
|
125
|
+
} else if (entry !== undefined && entry !== null) {
|
|
112
126
|
section.set(key.trim().toLowerCase(), String(entry).trim());
|
|
113
127
|
}
|
|
114
|
-
config.set(name.trim(), section);
|
|
115
128
|
}
|
|
116
|
-
|
|
129
|
+
if (section.size || !nested) {
|
|
130
|
+
config.set(path.join("."), section);
|
|
131
|
+
}
|
|
117
132
|
}
|
|
118
133
|
|
|
119
134
|
export function loadRawProfile(config: IniConfig | undefined, name: string): RawProfile {
|
|
@@ -366,19 +381,26 @@ export function resolveDatabricksProfile(
|
|
|
366
381
|
environment: Environment = process.env,
|
|
367
382
|
): DatabricksProfile {
|
|
368
383
|
const inApp = environmentUtils.isDatabricksAppEnv({ ...environment });
|
|
369
|
-
const
|
|
370
|
-
const
|
|
371
|
-
|
|
384
|
+
const configPath = resolveConfigFile(options.configFile, environment);
|
|
385
|
+
const config = loadConfig(options.configFile, false, environment);
|
|
386
|
+
const optionProfile = stringUtils.trimToUndefined(options.profile);
|
|
387
|
+
const configuredEnvironmentProfile = stringUtils.trimToUndefined(
|
|
388
|
+
environment.DATABRICKS_CONFIG_PROFILE,
|
|
372
389
|
);
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
390
|
+
const environmentProfile =
|
|
391
|
+
configuredEnvironmentProfile && config?.has(configuredEnvironmentProfile)
|
|
392
|
+
? configuredEnvironmentProfile
|
|
393
|
+
: undefined;
|
|
377
394
|
const appServicePrincipal = [
|
|
378
395
|
environment.DATABRICKS_HOST,
|
|
379
396
|
environment.DATABRICKS_CLIENT_ID,
|
|
380
397
|
environment.DATABRICKS_CLIENT_SECRET,
|
|
381
398
|
].every((value) => Boolean(stringUtils.trimToUndefined(value)));
|
|
399
|
+
const explicitProfile = Boolean(optionProfile ?? environmentProfile);
|
|
400
|
+
const requestToken = requestOboToken(options.requestHeaders, options.accessTokenHeader);
|
|
401
|
+
const explicitAuthType =
|
|
402
|
+
options.authType ??
|
|
403
|
+
(!inApp && !explicitProfile ? parseAuthType(environment.DATABRICKS_AUTH_TYPE) : undefined);
|
|
382
404
|
const selectedAuthType =
|
|
383
405
|
!inApp || explicitProfile || explicitAuthType
|
|
384
406
|
? explicitAuthType
|
|
@@ -391,9 +413,7 @@ export function resolveDatabricksProfile(
|
|
|
391
413
|
selectedAuthType === AuthType.AppOnBehalfOf ||
|
|
392
414
|
selectedAuthType === AuthType.AppServicePrincipal;
|
|
393
415
|
const ignoreAmbientCredentials = explicitProfile && !appAuth;
|
|
394
|
-
const
|
|
395
|
-
const config = loadConfig(options.configFile, false, environment);
|
|
396
|
-
const requestedName = stringUtils.trimToUndefined(options.profile) ?? environmentProfile;
|
|
416
|
+
const requestedName = optionProfile ?? environmentProfile;
|
|
397
417
|
const profileName = resolveProfileName(
|
|
398
418
|
requestedName,
|
|
399
419
|
explicitProfile,
|
|
@@ -410,12 +430,13 @@ export function resolveDatabricksProfile(
|
|
|
410
430
|
].some((value) => Boolean(stringUtils.trimToUndefined(value)));
|
|
411
431
|
const selectedProfile =
|
|
412
432
|
explicitProfile || (!ambientCredentials && config?.has(profileName)) ? profileName : undefined;
|
|
413
|
-
const configured = loadRawProfile(config, profileName);
|
|
433
|
+
const configured = selectedProfile ? loadRawProfile(config, profileName) : {};
|
|
434
|
+
const credentialName = selectedProfile ?? "ambient";
|
|
414
435
|
const ambient = (name: keyof NodeJS.ProcessEnv): string | undefined =>
|
|
415
436
|
ignoreAmbientCredentials ? undefined : stringUtils.trimToUndefined(environment[name]);
|
|
416
437
|
const host = normalizeHost(
|
|
417
438
|
options.host ?? ambient("DATABRICKS_HOST") ?? configured.host,
|
|
418
|
-
|
|
439
|
+
credentialName,
|
|
419
440
|
);
|
|
420
441
|
const accountId =
|
|
421
442
|
stringUtils.trimToUndefined(options.accountId) ??
|
|
@@ -448,7 +469,7 @@ export function resolveDatabricksProfile(
|
|
|
448
469
|
authType === AuthType.DatabricksCli
|
|
449
470
|
? (clientIdValue ?? DEFAULT_CLIENT_ID)
|
|
450
471
|
: authType === AuthType.OAuthM2M || authType === AuthType.AppServicePrincipal
|
|
451
|
-
? (clientIdValue ?? missing(
|
|
472
|
+
? (clientIdValue ?? missing(credentialName, "client_id"))
|
|
452
473
|
: (clientIdValue ?? "");
|
|
453
474
|
const scopes = options.scopes?.length
|
|
454
475
|
? stringUtils.parseList(options.scopes)
|
|
@@ -461,9 +482,9 @@ export function resolveDatabricksProfile(
|
|
|
461
482
|
const principal =
|
|
462
483
|
authType === AuthType.OAuthM2M || authType === AuthType.AppServicePrincipal
|
|
463
484
|
? clientId
|
|
464
|
-
:
|
|
485
|
+
: credentialName;
|
|
465
486
|
const cacheKey = credentialCacheKey({
|
|
466
|
-
name:
|
|
487
|
+
name: credentialName,
|
|
467
488
|
host,
|
|
468
489
|
accountId,
|
|
469
490
|
workspaceId,
|
|
@@ -474,7 +495,7 @@ export function resolveDatabricksProfile(
|
|
|
474
495
|
accessToken,
|
|
475
496
|
});
|
|
476
497
|
logger.debug("resolved Databricks profile", {
|
|
477
|
-
profile:
|
|
498
|
+
profile: credentialName,
|
|
478
499
|
host,
|
|
479
500
|
authType,
|
|
480
501
|
target,
|
|
@@ -488,7 +509,7 @@ export function resolveDatabricksProfile(
|
|
|
488
509
|
configPath,
|
|
489
510
|
});
|
|
490
511
|
return {
|
|
491
|
-
name:
|
|
512
|
+
name: credentialName,
|
|
492
513
|
...(selectedProfile ? { selectedProfile } : {}),
|
|
493
514
|
host,
|
|
494
515
|
...(accountId ? { accountId } : {}),
|
package/src/client.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
DEFAULT_ACCESS_TOKEN_HEADER,
|
|
16
16
|
WORKSPACE_ID_HEADER,
|
|
17
17
|
} from "./config.ts";
|
|
18
|
+
import { _databricksRuntimeAuthClient, createDatabricksRuntimeAuthClient } from "./runtime-auth.ts";
|
|
18
19
|
|
|
19
20
|
const logger = authLogger("databricks");
|
|
20
21
|
|
|
@@ -126,6 +127,16 @@ export async function createAuthClient(
|
|
|
126
127
|
options: DatabricksAuthOptions = {},
|
|
127
128
|
dependencies: DatabricksAuthDependencies = {},
|
|
128
129
|
): Promise<AuthClient> {
|
|
130
|
+
if (usesDefaultCredentialSource(options)) {
|
|
131
|
+
const runtime = await _databricksRuntimeAuthClient();
|
|
132
|
+
if (runtime) {
|
|
133
|
+
logger.debug("selected Databricks Python runtime authentication", {
|
|
134
|
+
host: runtime.host,
|
|
135
|
+
hasWorkspaceId: Boolean(runtime.workspaceId),
|
|
136
|
+
});
|
|
137
|
+
return createDatabricksRuntimeAuthClient(runtime, options);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
129
140
|
return createResolvedAuth(options, dependencies);
|
|
130
141
|
}
|
|
131
142
|
|
|
@@ -289,3 +300,7 @@ function cliEnvironment(profile: DatabricksProfile, configFile: string): Record<
|
|
|
289
300
|
function stringValue(value: unknown): string | undefined {
|
|
290
301
|
return typeof value === "string" && value.trim() ? value : undefined;
|
|
291
302
|
}
|
|
303
|
+
|
|
304
|
+
function usesDefaultCredentialSource(options: DatabricksAuthOptions): boolean {
|
|
305
|
+
return Object.values(options).every((value) => value === undefined);
|
|
306
|
+
}
|
package/src/profile.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DatabricksProfileSummary } from "@dbx-tools/shared-auth/profile";
|
|
2
2
|
|
|
3
|
+
import { AuthError } from "./_errors.ts";
|
|
3
4
|
import { listDatabricksProfiles, resolveDatabricksProfile } from "./_profile-config.ts";
|
|
4
5
|
import type { DatabricksProfile } from "./_types.ts";
|
|
5
6
|
import type { DatabricksAuthOptions } from "./config.ts";
|
|
@@ -10,9 +11,28 @@ export interface ListProfilesOptions {
|
|
|
10
11
|
refresh?: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
/** Resolve one
|
|
14
|
-
export function resolveProfile(
|
|
15
|
-
|
|
14
|
+
/** Resolve one configured profile without exposing credentials, or `null` when none exists. */
|
|
15
|
+
export function resolveProfile(
|
|
16
|
+
options: DatabricksAuthOptions = {},
|
|
17
|
+
): DatabricksProfileSummary | null {
|
|
18
|
+
const configured = listDatabricksProfiles(options.configFile);
|
|
19
|
+
if (configured.length === 0) return null;
|
|
20
|
+
const environment = options.configFile
|
|
21
|
+
? { DATABRICKS_CONFIG_FILE: options.configFile }
|
|
22
|
+
: process.env;
|
|
23
|
+
try {
|
|
24
|
+
const resolved = resolveDatabricksProfile(options, environment);
|
|
25
|
+
if (
|
|
26
|
+
!resolved.selectedProfile ||
|
|
27
|
+
!configured.some(({ name }) => name === resolved.selectedProfile)
|
|
28
|
+
) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return toProfileSummary(resolved);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof AuthError && error.kind === "config") return null;
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
16
36
|
}
|
|
17
37
|
|
|
18
38
|
/** List configured profiles without exposing credentials. */
|