@dbx-tools/databricks 0.6.183 → 0.6.185
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 +34 -3
- package/index.ts +2 -1
- package/lib/index.js +2730 -15
- package/package.json +20 -38
- package/src/_bindings-ffi.ts +859 -0
- package/src/_bindings.ts +2501 -0
- package/src/bindings.ts +12 -0
- package/lib/index.d.ts +0 -15
- package/lib/src/cloud.d.ts +0 -80
- package/lib/src/cloud.js +0 -240
- package/lib/src/databricks-fs.d.ts +0 -93
- package/lib/src/databricks-fs.js +0 -327
- package/lib/src/databricks-path.d.ts +0 -67
- package/lib/src/databricks-path.js +0 -113
- package/lib/src/net.d.ts +0 -29
- package/lib/src/net.js +0 -68
- package/lib/src/workspace.d.ts +0 -43
- package/lib/src/workspace.js +0 -110
- package/lib/tsconfig.tsbuildinfo +0 -1
package/src/bindings.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// GENERATED by UniFFI binding generation - DO NOT EDIT.
|
|
2
|
+
// Regenerated from the dbx-tools-databricks Rust exports.
|
|
3
|
+
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
|
+
|
|
5
|
+
/* eslint-disable */
|
|
6
|
+
// @ts-nocheck
|
|
7
|
+
export * from './_bindings.ts';
|
|
8
|
+
import uniffiModule from './_bindings.ts';
|
|
9
|
+
uniffiModule.initialize();
|
|
10
|
+
export { uniffiModule };
|
|
11
|
+
export async function uniffiInitAsync() {}
|
|
12
|
+
export type { PersistentAuthLike, ProviderAuthLike, StorageAdapter, StorageHandleLike } from './_bindings.ts';
|
package/lib/index.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const PACKAGE_IDENTIFIER = "@dbx-tools/databricks";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.6.183";
|
|
3
|
-
export * as cloud from "./src/cloud.ts";
|
|
4
|
-
export * as databricksFS from "./src/databricks-fs.ts";
|
|
5
|
-
export * as databricksPath from "./src/databricks-path.ts";
|
|
6
|
-
export * as net from "./src/net.ts";
|
|
7
|
-
export * as workspace from "./src/workspace.ts";
|
|
8
|
-
export { RANGE_CACHE_TTL_MS, CloudProvider } from "./src/cloud.ts";
|
|
9
|
-
export type { CloudLocation } from "./src/cloud.ts";
|
|
10
|
-
export { DatabricksFileSystem } from "./src/databricks-fs.ts";
|
|
11
|
-
export type { DatabricksFileSystemOptions } from "./src/databricks-fs.ts";
|
|
12
|
-
export { isHomeRelativePath } from "./src/databricks-path.ts";
|
|
13
|
-
export type { DatabricksFilesBackend, NormalizeDatabricksRootOptions, ResolveDatabricksRootOptions } from "./src/databricks-path.ts";
|
|
14
|
-
export { getPublicIp } from "./src/net.ts";
|
|
15
|
-
export type { WorkspaceClient } from "./src/workspace.ts";
|
package/lib/src/cloud.d.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Best-effort geolocation of a host to the cloud provider and region it
|
|
3
|
-
* runs in. Resolves the host to its IP address(es) via DNS, then matches
|
|
4
|
-
* those addresses against the public IP-range feeds each hyperscaler
|
|
5
|
-
* publishes (AWS, Azure, GCP). Handy for placing a Databricks workspace
|
|
6
|
-
* URL, but works for any host.
|
|
7
|
-
*
|
|
8
|
-
* The range feeds are large and change slowly, so each provider's feed
|
|
9
|
-
* is cached for {@link RANGE_CACHE_TTL_MS} (24 hours) at two layers: an
|
|
10
|
-
* on-disk copy under the OS temp dir (survives process restarts, shared
|
|
11
|
-
* across processes) plus an in-process memoized parse. A provider whose
|
|
12
|
-
* feed fails to load is skipped rather than failing the whole lookup -
|
|
13
|
-
* the other providers still answer.
|
|
14
|
-
*
|
|
15
|
-
* Server-only: DNS resolution needs `node:dns` (via `./net.ts`), the
|
|
16
|
-
* disk cache needs `node:fs` / `node:os` / `node:path`, and the feeds
|
|
17
|
-
* are fetched with the global `fetch`.
|
|
18
|
-
*
|
|
19
|
-
* @module
|
|
20
|
-
*/
|
|
21
|
-
import { net } from "@dbx-tools/shared-core";
|
|
22
|
-
/** How long a fetched provider IP-range feed is reused before refetch. */
|
|
23
|
-
export declare const RANGE_CACHE_TTL_MS: number;
|
|
24
|
-
/** Cloud hyperscaler a host resolves into. */
|
|
25
|
-
export declare enum CloudProvider {
|
|
26
|
-
Aws = "aws",
|
|
27
|
-
Azure = "azure",
|
|
28
|
-
Gcp = "gcp"
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Where a host lives: the {@link CloudProvider}, the provider-native
|
|
32
|
-
* `region` string (whatever the provider's feed calls it, e.g.
|
|
33
|
-
* `"us-east-1"` on AWS, `"eastus2"` on Azure, `"us-east1"` on GCP), the
|
|
34
|
-
* resolved `ip` that matched, and the `cidr` block it fell in.
|
|
35
|
-
*/
|
|
36
|
-
export interface CloudLocation {
|
|
37
|
-
provider: CloudProvider;
|
|
38
|
-
region: string;
|
|
39
|
-
ip: string;
|
|
40
|
-
cidr: string;
|
|
41
|
-
}
|
|
42
|
-
/** A parsed CIDR block tagged with the region it belongs to. */
|
|
43
|
-
interface RegionCidr extends net.Cidr {
|
|
44
|
-
region: string;
|
|
45
|
-
}
|
|
46
|
-
/** One provider's parsed, region-tagged range table. */
|
|
47
|
-
interface ProviderRanges {
|
|
48
|
-
provider: CloudProvider;
|
|
49
|
-
ranges: RegionCidr[];
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Resolve `input`'s host to a {@link CloudLocation}, or `null` when the
|
|
53
|
-
* host can't be resolved or none of its IPs match a known cloud range.
|
|
54
|
-
* `input` is any {@link net.UrlLike} - a URL, a bare host, or a `{ url }`
|
|
55
|
-
* wrapper.
|
|
56
|
-
*
|
|
57
|
-
* The provider range feeds are cached for {@link RANGE_CACHE_TTL_MS}, so
|
|
58
|
-
* only the first call in a 24-hour window pays the fetch cost; the DNS
|
|
59
|
-
* lookup happens on every call.
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* await resolveCloudLocation("https://adb-1234567890.7.azuredatabricks.net");
|
|
63
|
-
* // { provider: CloudProvider.Azure,
|
|
64
|
-
* // region: "eastus2", ip: "...", cidr: "..." }
|
|
65
|
-
*
|
|
66
|
-
* await resolveCloudLocation("dbc-abc123.cloud.databricks.com");
|
|
67
|
-
* // { provider: CloudProvider.Aws,
|
|
68
|
-
* // region: "us-west-2", ip: "...", cidr: "..." }
|
|
69
|
-
*/
|
|
70
|
-
export declare function resolveCloudLocation(input: net.UrlLike): Promise<CloudLocation | null>;
|
|
71
|
-
/**
|
|
72
|
-
* Load every provider's region-tagged range table, each cached for
|
|
73
|
-
* {@link RANGE_CACHE_TTL_MS}. Providers are loaded in parallel and a
|
|
74
|
-
* feed that fails to fetch or parse is dropped (logged, not thrown) so
|
|
75
|
-
* a single flaky feed never sinks the whole lookup. Exposed for callers
|
|
76
|
-
* that want to match many IPs against one cached snapshot without a DNS
|
|
77
|
-
* step per address.
|
|
78
|
-
*/
|
|
79
|
-
export declare function loadProviderRanges(): Promise<ProviderRanges[]>;
|
|
80
|
-
export {};
|
package/lib/src/cloud.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Best-effort geolocation of a host to the cloud provider and region it
|
|
3
|
-
* runs in. Resolves the host to its IP address(es) via DNS, then matches
|
|
4
|
-
* those addresses against the public IP-range feeds each hyperscaler
|
|
5
|
-
* publishes (AWS, Azure, GCP). Handy for placing a Databricks workspace
|
|
6
|
-
* URL, but works for any host.
|
|
7
|
-
*
|
|
8
|
-
* The range feeds are large and change slowly, so each provider's feed
|
|
9
|
-
* is cached for {@link RANGE_CACHE_TTL_MS} (24 hours) at two layers: an
|
|
10
|
-
* on-disk copy under the OS temp dir (survives process restarts, shared
|
|
11
|
-
* across processes) plus an in-process memoized parse. A provider whose
|
|
12
|
-
* feed fails to load is skipped rather than failing the whole lookup -
|
|
13
|
-
* the other providers still answer.
|
|
14
|
-
*
|
|
15
|
-
* Server-only: DNS resolution needs `node:dns` (via `./net.ts`), the
|
|
16
|
-
* disk cache needs `node:fs` / `node:os` / `node:path`, and the feeds
|
|
17
|
-
* are fetched with the global `fetch`.
|
|
18
|
-
*
|
|
19
|
-
* @module
|
|
20
|
-
*/
|
|
21
|
-
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
22
|
-
import { tmpdir } from "node:os";
|
|
23
|
-
import { dirname, join } from "node:path";
|
|
24
|
-
import { file } from "@dbx-tools/core";
|
|
25
|
-
import { error, functionModule, hash, http, json, log, net } from "@dbx-tools/shared-core";
|
|
26
|
-
import { resolveHostIps } from "./net.js";
|
|
27
|
-
const logger = log.logger("cloud");
|
|
28
|
-
/** How long a fetched provider IP-range feed is reused before refetch. */
|
|
29
|
-
export const RANGE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
30
|
-
/** AWS publishes a single stable, unauthenticated ranges feed. */
|
|
31
|
-
const AWS_RANGES_URL = "https://ip-ranges.amazonaws.com/ip-ranges.json";
|
|
32
|
-
/** GCP publishes a single stable, unauthenticated ranges feed. */
|
|
33
|
-
const GCP_RANGES_URL = "https://www.gstatic.com/ipranges/cloud.json";
|
|
34
|
-
/**
|
|
35
|
-
* Azure has no stable feed URL - the JSON download link (with a
|
|
36
|
-
* rotating date stamp) lives on this human-facing download page and
|
|
37
|
-
* must be scraped out. See {@link fetchAzureRanges}.
|
|
38
|
-
*/
|
|
39
|
-
const AZURE_DOWNLOAD_PAGE = "https://www.microsoft.com/en-us/download/details.aspx?id=56519";
|
|
40
|
-
/** Regex that plucks the current `ServiceTags_Public_<date>.json` link off the Azure page. */
|
|
41
|
-
const AZURE_JSON_LINK = /https:\/\/download\.microsoft\.com\/download\/[^"']*ServiceTags_Public_\d+\.json/;
|
|
42
|
-
/** Cloud hyperscaler a host resolves into. */
|
|
43
|
-
export var CloudProvider;
|
|
44
|
-
(function (CloudProvider) {
|
|
45
|
-
CloudProvider["Aws"] = "aws";
|
|
46
|
-
CloudProvider["Azure"] = "azure";
|
|
47
|
-
CloudProvider["Gcp"] = "gcp";
|
|
48
|
-
})(CloudProvider || (CloudProvider = {}));
|
|
49
|
-
/**
|
|
50
|
-
* Resolve `input`'s host to a {@link CloudLocation}, or `null` when the
|
|
51
|
-
* host can't be resolved or none of its IPs match a known cloud range.
|
|
52
|
-
* `input` is any {@link net.UrlLike} - a URL, a bare host, or a `{ url }`
|
|
53
|
-
* wrapper.
|
|
54
|
-
*
|
|
55
|
-
* The provider range feeds are cached for {@link RANGE_CACHE_TTL_MS}, so
|
|
56
|
-
* only the first call in a 24-hour window pays the fetch cost; the DNS
|
|
57
|
-
* lookup happens on every call.
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* await resolveCloudLocation("https://adb-1234567890.7.azuredatabricks.net");
|
|
61
|
-
* // { provider: CloudProvider.Azure,
|
|
62
|
-
* // region: "eastus2", ip: "...", cidr: "..." }
|
|
63
|
-
*
|
|
64
|
-
* await resolveCloudLocation("dbc-abc123.cloud.databricks.com");
|
|
65
|
-
* // { provider: CloudProvider.Aws,
|
|
66
|
-
* // region: "us-west-2", ip: "...", cidr: "..." }
|
|
67
|
-
*/
|
|
68
|
-
export async function resolveCloudLocation(input) {
|
|
69
|
-
const ips = await resolveHostIps(input);
|
|
70
|
-
if (ips.length === 0) {
|
|
71
|
-
logger.debug("no ips resolved", { input: String(input) });
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
const providers = await loadProviderRanges();
|
|
75
|
-
for (const ip of ips) {
|
|
76
|
-
const parsed = net.parseIp(ip);
|
|
77
|
-
if (!parsed)
|
|
78
|
-
continue;
|
|
79
|
-
for (const { provider, ranges } of providers) {
|
|
80
|
-
const match = net.findContainingCidr(parsed, ranges);
|
|
81
|
-
if (match) {
|
|
82
|
-
return { provider, region: match.region, ip, cidr: match.cidr };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
logger.debug("no cloud range matched", { ips });
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Load every provider's region-tagged range table, each cached for
|
|
91
|
-
* {@link RANGE_CACHE_TTL_MS}. Providers are loaded in parallel and a
|
|
92
|
-
* feed that fails to fetch or parse is dropped (logged, not thrown) so
|
|
93
|
-
* a single flaky feed never sinks the whole lookup. Exposed for callers
|
|
94
|
-
* that want to match many IPs against one cached snapshot without a DNS
|
|
95
|
-
* step per address.
|
|
96
|
-
*/
|
|
97
|
-
export async function loadProviderRanges() {
|
|
98
|
-
const settled = await Promise.allSettled([loadAwsRanges(), loadAzureRanges(), loadGcpRanges()]);
|
|
99
|
-
const out = [];
|
|
100
|
-
for (const result of settled) {
|
|
101
|
-
if (result.status === "fulfilled")
|
|
102
|
-
out.push(result.value);
|
|
103
|
-
else
|
|
104
|
-
logger.warn("provider range load failed", { error: error.errorMessage(result.reason) });
|
|
105
|
-
}
|
|
106
|
-
return out;
|
|
107
|
-
}
|
|
108
|
-
// ────────────────────────────────────────────────────────────────
|
|
109
|
-
// Per-provider cached loaders
|
|
110
|
-
// ────────────────────────────────────────────────────────────────
|
|
111
|
-
const loadAwsRanges = functionModule.memoize(fetchAwsRanges, { ttlMs: RANGE_CACHE_TTL_MS });
|
|
112
|
-
const loadAzureRanges = functionModule.memoize(fetchAzureRanges, { ttlMs: RANGE_CACHE_TTL_MS });
|
|
113
|
-
const loadGcpRanges = functionModule.memoize(fetchGcpRanges, { ttlMs: RANGE_CACHE_TTL_MS });
|
|
114
|
-
/**
|
|
115
|
-
* AWS `ip-ranges.json`: a flat list of IPv4 (`prefixes`) and IPv6
|
|
116
|
-
* (`ipv6_prefixes`) blocks, each already tagged with a `region` such
|
|
117
|
-
* as `"us-east-1"` (or `"GLOBAL"` for edge ranges).
|
|
118
|
-
*/
|
|
119
|
-
async function fetchAwsRanges() {
|
|
120
|
-
const feed = await fetchJson(AWS_RANGES_URL);
|
|
121
|
-
const ranges = [];
|
|
122
|
-
for (const entry of feed.prefixes ?? []) {
|
|
123
|
-
addRange(ranges, entry.ip_prefix, entry.region);
|
|
124
|
-
}
|
|
125
|
-
for (const entry of feed.ipv6_prefixes ?? []) {
|
|
126
|
-
addRange(ranges, entry.ipv6_prefix, entry.region);
|
|
127
|
-
}
|
|
128
|
-
logger.debug("loaded aws ranges", { count: ranges.length });
|
|
129
|
-
return { provider: CloudProvider.Aws, ranges };
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* GCP `cloud.json`: a list of blocks each carrying an `ipv4Prefix` or
|
|
133
|
-
* `ipv6Prefix` and a `scope` that is the region (`"us-east1"`) or
|
|
134
|
-
* `"global"` for non-regional ranges.
|
|
135
|
-
*/
|
|
136
|
-
async function fetchGcpRanges() {
|
|
137
|
-
const feed = await fetchJson(GCP_RANGES_URL);
|
|
138
|
-
const ranges = [];
|
|
139
|
-
for (const entry of feed.prefixes ?? []) {
|
|
140
|
-
addRange(ranges, entry.ipv4Prefix ?? entry.ipv6Prefix, entry.scope);
|
|
141
|
-
}
|
|
142
|
-
logger.debug("loaded gcp ranges", { count: ranges.length });
|
|
143
|
-
return { provider: CloudProvider.Gcp, ranges };
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Azure service tags: Microsoft ships no stable feed URL, so scrape the
|
|
147
|
-
* current `ServiceTags_Public_<date>.json` link off the download page
|
|
148
|
-
* and fetch it. Only the regional `AzureCloud.<region>` aggregates
|
|
149
|
-
* (which have a non-empty `region`) are kept; the cloud-wide
|
|
150
|
-
* `AzureCloud` tag and per-service tags are ignored so an address maps
|
|
151
|
-
* cleanly to one region.
|
|
152
|
-
*/
|
|
153
|
-
async function fetchAzureRanges() {
|
|
154
|
-
const page = await fetchText(AZURE_DOWNLOAD_PAGE);
|
|
155
|
-
const jsonUrl = page.match(AZURE_JSON_LINK)?.[0];
|
|
156
|
-
if (!jsonUrl) {
|
|
157
|
-
throw new Error("could not find ServiceTags JSON link on Azure download page");
|
|
158
|
-
}
|
|
159
|
-
const feed = await fetchJson(jsonUrl);
|
|
160
|
-
const ranges = [];
|
|
161
|
-
for (const value of feed.values ?? []) {
|
|
162
|
-
const region = value.properties?.region;
|
|
163
|
-
if (!region || !value.name?.startsWith("AzureCloud."))
|
|
164
|
-
continue;
|
|
165
|
-
for (const prefix of value.properties?.addressPrefixes ?? []) {
|
|
166
|
-
addRange(ranges, prefix, region);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
logger.debug("loaded azure ranges", { count: ranges.length });
|
|
170
|
-
return { provider: CloudProvider.Azure, ranges };
|
|
171
|
-
}
|
|
172
|
-
// ────────────────────────────────────────────────────────────────
|
|
173
|
-
// Helpers
|
|
174
|
-
// ────────────────────────────────────────────────────────────────
|
|
175
|
-
/** Parse `cidr` and, when valid and `region` is set, push a tagged range. */
|
|
176
|
-
function addRange(ranges, cidr, region) {
|
|
177
|
-
if (!cidr || !region)
|
|
178
|
-
return;
|
|
179
|
-
const parsed = net.parseCidr(cidr);
|
|
180
|
-
if (parsed)
|
|
181
|
-
ranges.push({ ...parsed, region });
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Fetch and parse a provider feed. A parse failure names the URL rather than
|
|
185
|
-
* surfacing an opaque `Unexpected token` - the text may come from the on-disk
|
|
186
|
-
* cache, so "which feed" is the part worth knowing. {@link loadProviderRanges}
|
|
187
|
-
* turns the throw into a per-provider warning.
|
|
188
|
-
*/
|
|
189
|
-
async function fetchJson(url) {
|
|
190
|
-
const text = await fetchText(url);
|
|
191
|
-
const parsed = json.parse(text);
|
|
192
|
-
if (parsed === undefined) {
|
|
193
|
-
throw new Error(`range feed returned non-JSON content: ${url}`);
|
|
194
|
-
}
|
|
195
|
-
return parsed;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Fetch `url` as text with a 24h on-disk cache under the OS temp dir
|
|
199
|
-
* (keyed by an FNV hash of the URL). A fresh cache file is returned
|
|
200
|
-
* directly; a miss/expiry fetches, writes to a unique temp file, and
|
|
201
|
-
* atomically renames it into place so concurrent callers never observe
|
|
202
|
-
* a half-written cache entry.
|
|
203
|
-
*/
|
|
204
|
-
async function fetchText(url) {
|
|
205
|
-
const cacheDir = join(tmpdir(), "dbx-tools", "shared", "cloud");
|
|
206
|
-
const cacheDirCreated = await mkdir(cacheDir, { recursive: true });
|
|
207
|
-
const cachePath = join(cacheDir, `fetch-${hash.fnvHash(url)}.txt`);
|
|
208
|
-
const createdAt = cacheDirCreated ? undefined : await getCreated(cachePath);
|
|
209
|
-
if (createdAt) {
|
|
210
|
-
const expiresAt = new Date(createdAt.getTime() + RANGE_CACHE_TTL_MS);
|
|
211
|
-
if (expiresAt > new Date()) {
|
|
212
|
-
logger.debug("cached fetch hit", { url, cachePath });
|
|
213
|
-
return readFile(cachePath, "utf8");
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
let tempPath = join(cacheDir, `${hash.id()}.txt`);
|
|
217
|
-
try {
|
|
218
|
-
const response = await fetch(url);
|
|
219
|
-
if (!response.ok) {
|
|
220
|
-
throw await http.createFetchError(response, url);
|
|
221
|
-
}
|
|
222
|
-
const responseText = await response.text();
|
|
223
|
-
await mkdir(dirname(tempPath), { recursive: true });
|
|
224
|
-
await writeFile(tempPath, responseText);
|
|
225
|
-
await rename(tempPath, cachePath);
|
|
226
|
-
logger.debug("cached fetch load", { url, cachePath });
|
|
227
|
-
tempPath = null;
|
|
228
|
-
return responseText;
|
|
229
|
-
}
|
|
230
|
-
finally {
|
|
231
|
-
if (tempPath) {
|
|
232
|
-
await unlink(tempPath);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
/** Birth time of `path`, or `undefined` when it doesn't exist yet. */
|
|
237
|
-
async function getCreated(path) {
|
|
238
|
-
return (await file.statSync(path))?.birthtime;
|
|
239
|
-
}
|
|
240
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xvdWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFMUMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMzRixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRTFDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7QUFFbkMsMEVBQTBFO0FBQzFFLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUV0RCxrRUFBa0U7QUFDbEUsTUFBTSxjQUFjLEdBQUcsZ0RBQWdELENBQUM7QUFDeEUsa0VBQWtFO0FBQ2xFLE1BQU0sY0FBYyxHQUFHLDZDQUE2QyxDQUFDO0FBQ3JFOzs7O0dBSUc7QUFDSCxNQUFNLG1CQUFtQixHQUFHLGdFQUFnRSxDQUFDO0FBQzdGLDhGQUE4RjtBQUM5RixNQUFNLGVBQWUsR0FDbkIsa0ZBQWtGLENBQUM7QUFFckYsOENBQThDO0FBQzlDLE1BQU0sQ0FBTixJQUFZLGFBSVg7QUFKRCxXQUFZLGFBQWE7SUFDdkIsNEJBQVcsQ0FBQTtJQUNYLGdD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QVEsQ0FBQyxDQUFDO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0FBQ0gsQ0FBQztBQUVELHNFQUFzRTtBQUN0RSxLQUFLLFVBQVUsVUFBVSxDQUFDLElBQVk7SUFDcEMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQztBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCZXN0LWVmZm9ydCBnZW9sb2NhdGlvbiBvZiBhIGhvc3QgdG8gdGhlIGNsb3VkIHByb3ZpZGVyIGFuZCByZWdpb24gaXRcbiAqIHJ1bnMgaW4uIFJlc29sdmVzIHRoZSBob3N0IHRvIGl0cyBJUCBhZGRyZXNzKGVzKSB2aWEgRE5TLCB0aGVuIG1hdGNoZXNcbiAqIHRob3NlIGFkZHJlc3NlcyBhZ2FpbnN0IHRoZSBwdWJsaWMgSVAtcmFuZ2UgZmVlZHMgZWFjaCBoeXBlcnNjYWxlclxuICogcHVibGlzaGVzIChBV1MsIEF6dXJlLCBHQ1ApLiBIYW5keSBmb3IgcGxhY2luZyBhIERhdGFicmlja3Mgd29ya3NwYWNlXG4gKiBVUkwsIGJ1dCB3b3JrcyBmb3IgYW55IGhvc3QuXG4gKlxuICogVGhlIHJhbmdlIGZlZWRzIGFyZSBsYXJnZSBhbmQgY2hhbmdlIHNsb3dseSwgc28gZWFjaCBwcm92aWRlcidzIGZlZWRcbiAqIGlzIGNhY2hlZCBmb3Ige0BsaW5rIFJBTkdFX0NBQ0hFX1RUTF9NU30gKDI0IGhvdXJzKSBhdCB0d28gbGF5ZXJzOiBhblxuICogb24tZGlzayBjb3B5IHVuZGVyIHRoZSBPUyB0ZW1wIGRpciAoc3Vydml2ZXMgcHJvY2VzcyByZXN0YXJ0cywgc2hhcmVkXG4gKiBhY3Jvc3MgcHJvY2Vzc2VzKSBwbHVzIGFuIGluLXByb2Nlc3MgbWVtb2l6ZWQgcGFyc2UuIEEgcHJvdmlkZXIgd2hvc2VcbiAqIGZlZWQgZmFpbHMgdG8gbG9hZCBpcyBza2lwcGVkIHJhdGhlciB0aGFuIGZhaWxpbmcgdGhlIHdob2xlIGxvb2t1cCAtXG4gKiB0aGUgb3RoZXIgcHJvdmlkZXJzIHN0aWxsIGFuc3dlci5cbiAqXG4gKiBTZXJ2ZXItb25seTogRE5TIHJlc29sdXRpb24gbmVlZHMgYG5vZGU6ZG5zYCAodmlhIGAuL25ldC50c2ApLCB0aGVcbiAqIGRpc2sgY2FjaGUgbmVlZHMgYG5vZGU6ZnNgIC8gYG5vZGU6b3NgIC8gYG5vZGU6cGF0aGAsIGFuZCB0aGUgZmVlZHNcbiAqIGFyZSBmZXRjaGVkIHdpdGggdGhlIGdsb2JhbCBgZmV0Y2hgLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBta2RpciwgcmVhZEZpbGUsIHJlbmFtZSwgdW5saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwibm9kZTpmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm5vZGU6b3NcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5cbmltcG9ydCB7IGZpbGUgfSBmcm9tIFwiQGRieC10b29scy9jb3JlXCI7XG5pbXBvcnQgeyBlcnJvciwgZnVuY3Rpb25Nb2R1bGUsIGhhc2gsIGh0dHAsIGpzb24sIGxvZywgbmV0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IHJlc29sdmVIb3N0SXBzIH0gZnJvbSBcIi4vbmV0LnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJjbG91ZFwiKTtcblxuLyoqIEhvdyBsb25nIGEgZmV0Y2hlZCBwcm92aWRlciBJUC1yYW5nZSBmZWVkIGlzIHJldXNlZCBiZWZvcmUgcmVmZXRjaC4gKi9cbmV4cG9ydCBjb25zdCBSQU5HRV9DQUNIRV9UVExfTVMgPSAyNCAqIDYwICogNjAgKiAxMDAwO1xuXG4vKiogQVdTIHB1Ymxpc2hlcyBhIHNpbmdsZSBzdGFibGUsIHVuYXV0aGVudGljYXRlZCByYW5nZXMgZmVlZC4gKi9cbmNvbnN0IEFXU19SQU5HRVNfVVJMID0gXCJodHRwczovL2lwLXJhbmdlcy5hbWF6b25hd3MuY29tL2lwLXJhbmdlcy5qc29uXCI7XG4vKiogR0NQIHB1Ymxpc2hlcyBhIHNpbmdsZSBzdGFibGUsIHVuYXV0aGVudGljYXRlZCByYW5nZXMgZmVlZC4gKi9cbmNvbnN0IEdDUF9SQU5HRVNfVVJMID0gXCJodHRwczovL3d3dy5nc3RhdGljLmNvbS9pcHJhbmdlcy9jbG91ZC5qc29uXCI7XG4vKipcbiAqIEF6dXJlIGhhcyBubyBzdGFibGUgZmVlZCBVUkwgLSB0aGUgSlNPTiBkb3dubG9hZCBsaW5rICh3aXRoIGFcbiAqIHJvdGF0aW5nIGRhdGUgc3RhbXApIGxpdmVzIG9uIHRoaXMgaHVtYW4tZmFjaW5nIGRvd25sb2FkIHBhZ2UgYW5kXG4gKiBtdXN0IGJlIHNjcmFwZWQgb3V0LiBTZWUge0BsaW5rIGZldGNoQXp1cmVSYW5nZXN9LlxuICovXG5jb25zdCBBWlVSRV9ET1dOTE9BRF9QQUdFID0gXCJodHRwczovL3d3dy5taWNyb3NvZnQuY29tL2VuLXVzL2Rvd25sb2FkL2RldGFpbHMuYXNweD9pZD01NjUxOVwiO1xuLyoqIFJlZ2V4IHRoYXQgcGx1Y2tzIHRoZSBjdXJyZW50IGBTZXJ2aWNlVGFnc19QdWJsaWNfPGRhdGU+Lmpzb25gIGxpbmsgb2ZmIHRoZSBBenVyZSBwYWdlLiAqL1xuY29uc3QgQVpVUkVfSlNPTl9MSU5LID1cbiAgL2h0dHBzOlxcL1xcL2Rvd25sb2FkXFwubWljcm9zb2Z0XFwuY29tXFwvZG93bmxvYWRcXC9bXlwiJ10qU2VydmljZVRhZ3NfUHVibGljX1xcZCtcXC5qc29uLztcblxuLyoqIENsb3VkIGh5cGVyc2NhbGVyIGEgaG9zdCByZXNvbHZlcyBpbnRvLiAqL1xuZXhwb3J0IGVudW0gQ2xvdWRQcm92aWRlciB7XG4gIEF3cyA9IFwiYXdzXCIsXG4gIEF6dXJlID0gXCJhenVyZVwiLFxuICBHY3AgPSBcImdjcFwiLFxufVxuXG4vKipcbiAqIFdoZXJlIGEgaG9zdCBsaXZlczogdGhlIHtAbGluayBDbG91ZFByb3ZpZGVyfSwgdGhlIHByb3ZpZGVyLW5hdGl2ZVxuICogYHJlZ2lvbmAgc3RyaW5nICh3aGF0ZXZlciB0aGUgcHJvdmlkZXIncyBmZWVkIGNhbGxzIGl0LCBlLmcuXG4gKiBgXCJ1cy1lYXN0LTFcImAgb24gQVdTLCBgXCJlYXN0dXMyXCJgIG9uIEF6dXJlLCBgXCJ1cy1lYXN0MVwiYCBvbiBHQ1ApLCB0aGVcbiAqIHJlc29sdmVkIGBpcGAgdGhhdCBtYXRjaGVkLCBhbmQgdGhlIGBjaWRyYCBibG9jayBpdCBmZWxsIGluLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkTG9jYXRpb24ge1xuICBwcm92aWRlcjogQ2xvdWRQcm92aWRlcjtcbiAgcmVnaW9uOiBzdHJpbmc7XG4gIGlwOiBzdHJpbmc7XG4gIGNpZHI6IHN0cmluZztcbn1cblxuLyoqIEEgcGFyc2VkIENJRFIgYmxvY2sgdGFnZ2VkIHdpdGggdGhlIHJlZ2lvbiBpdCBiZWxvbmdzIHRvLiAqL1xuaW50ZXJmYWNlIFJlZ2lvbkNpZHIgZXh0ZW5kcyBuZXQuQ2lkciB7XG4gIHJlZ2lvbjogc3RyaW5nO1xufVxuXG4vKiogT25lIHByb3ZpZGVyJ3MgcGFyc2VkLCByZWdpb24tdGFnZ2VkIHJhbmdlIHRhYmxlLiAqL1xuaW50ZXJmYWNlIFByb3ZpZGVyUmFuZ2VzIHtcbiAgcHJvdmlkZXI6IENsb3VkUHJvdmlkZXI7XG4gIHJhbmdlczogUmVnaW9uQ2lkcltdO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYGlucHV0YCdzIGhvc3QgdG8gYSB7QGxpbmsgQ2xvdWRMb2NhdGlvbn0sIG9yIGBudWxsYCB3aGVuIHRoZVxuICogaG9zdCBjYW4ndCBiZSByZXNvbHZlZCBvciBub25lIG9mIGl0cyBJUHMgbWF0Y2ggYSBrbm93biBjbG91ZCByYW5nZS5cbiAqIGBpbnB1dGAgaXMgYW55IHtAbGluayBuZXQuVXJsTGlrZX0gLSBhIFVSTCwgYSBiYXJlIGhvc3QsIG9yIGEgYHsgdXJsIH1gXG4gKiB3cmFwcGVyLlxuICpcbiAqIFRoZSBwcm92aWRlciByYW5nZSBmZWVkcyBhcmUgY2FjaGVkIGZvciB7QGxpbmsgUkFOR0VfQ0FDSEVfVFRMX01TfSwgc29cbiAqIG9ubHkgdGhlIGZpcnN0IGNhbGwgaW4gYSAyNC1ob3VyIHdpbmRvdyBwYXlzIHRoZSBmZXRjaCBjb3N0OyB0aGUgRE5TXG4gKiBsb29rdXAgaGFwcGVucyBvbiBldmVyeSBjYWxsLlxuICpcbiAqIEBleGFtcGxlXG4gKiBhd2FpdCByZXNvbHZlQ2xvdWRMb2NhdGlvbihcImh0dHBzOi8vYWRiLTEyMzQ1Njc4OTAuNy5henVyZWRhdGFicmlja3MubmV0XCIpO1xuICogLy8geyBwcm92aWRlcjogQ2xvdWRQcm92aWRlci5BenVyZSxcbiAqIC8vICAgcmVnaW9uOiBcImVhc3R1czJcIiwgaXA6IFwiLi4uXCIsIGNpZHI6IFwiLi4uXCIgfVxuICpcbiAqIGF3YWl0IHJlc29sdmVDbG91ZExvY2F0aW9uKFwiZGJjLWFiYzEyMy5jbG91ZC5kYXRhYnJpY2tzLmNvbVwiKTtcbiAqIC8vIHsgcHJvdmlkZXI6IENsb3VkUHJvdmlkZXIuQXdzLFxuICogLy8gICByZWdpb246IFwidXMtd2VzdC0yXCIsIGlwOiBcIi4uLlwiLCBjaWRyOiBcIi4uLlwiIH1cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVDbG91ZExvY2F0aW9uKGlucHV0OiBuZXQuVXJsTGlrZSk6IFByb21pc2U8Q2xvdWRMb2NhdGlvbiB8IG51bGw+IHtcbiAgY29uc3QgaXBzID0gYXdhaXQgcmVzb2x2ZUhvc3RJcHMoaW5wdXQpO1xuICBpZiAoaXBzLmxlbmd0aCA9PT0gMCkge1xuICAgIGxvZ2dlci5kZWJ1ZyhcIm5vIGlwcyByZXNvbHZlZFwiLCB7IGlucHV0OiBTdHJpbmcoaW5wdXQpIH0pO1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGNvbnN0IHByb3ZpZGVycyA9IGF3YWl0IGxvYWRQcm92aWRlclJhbmdlcygpO1xuICBmb3IgKGNvbnN0IGlwIG9mIGlwcykge1xuICAgIGNvbnN0IHBhcnNlZCA9IG5ldC5wYXJzZUlwKGlwKTtcbiAgICBpZiAoIXBhcnNlZCkgY29udGludWU7XG4gICAgZm9yIChjb25zdCB7IHByb3ZpZGVyLCByYW5nZXMgfSBvZiBwcm92aWRlcnMpIHtcbiAgICAgIGNvbnN0IG1hdGNoID0gbmV0LmZpbmRDb250YWluaW5nQ2lkcihwYXJzZWQsIHJhbmdlcyk7XG4gICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIHsgcHJvdmlkZXIsIHJlZ2lvbjogbWF0Y2gucmVnaW9uLCBpcCwgY2lkcjogbWF0Y2guY2lkciB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBsb2dnZXIuZGVidWcoXCJubyBjbG91ZCByYW5nZSBtYXRjaGVkXCIsIHsgaXBzIH0pO1xuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBMb2FkIGV2ZXJ5IHByb3ZpZGVyJ3MgcmVnaW9uLXRhZ2dlZCByYW5nZSB0YWJsZSwgZWFjaCBjYWNoZWQgZm9yXG4gKiB7QGxpbmsgUkFOR0VfQ0FDSEVfVFRMX01TfS4gUHJvdmlkZXJzIGFyZSBsb2FkZWQgaW4gcGFyYWxsZWwgYW5kIGFcbiAqIGZlZWQgdGhhdCBmYWlscyB0byBmZXRjaCBvciBwYXJzZSBpcyBkcm9wcGVkIChsb2dnZWQsIG5vdCB0aHJvd24pIHNvXG4gKiBhIHNpbmdsZSBmbGFreSBmZWVkIG5ldmVyIHNpbmtzIHRoZSB3aG9sZSBsb29rdXAuIEV4cG9zZWQgZm9yIGNhbGxlcnNcbiAqIHRoYXQgd2FudCB0byBtYXRjaCBtYW55IElQcyBhZ2FpbnN0IG9uZSBjYWNoZWQgc25hcHNob3Qgd2l0aG91dCBhIEROU1xuICogc3RlcCBwZXIgYWRkcmVzcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRQcm92aWRlclJhbmdlcygpOiBQcm9taXNlPFByb3ZpZGVyUmFuZ2VzW10+IHtcbiAgY29uc3Qgc2V0dGxlZCA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbbG9hZEF3c1JhbmdlcygpLCBsb2FkQXp1cmVSYW5nZXMoKSwgbG9hZEdjcFJhbmdlcygpXSk7XG4gIGNvbnN0IG91dDogUHJvdmlkZXJSYW5nZXNbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHJlc3VsdCBvZiBzZXR0bGVkKSB7XG4gICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09IFwiZnVsZmlsbGVkXCIpIG91dC5wdXNoKHJlc3VsdC52YWx1ZSk7XG4gICAgZWxzZSBsb2dnZXIud2FybihcInByb3ZpZGVyIHJhbmdlIGxvYWQgZmFpbGVkXCIsIHsgZXJyb3I6IGVycm9yLmVycm9yTWVzc2FnZShyZXN1bHQucmVhc29uKSB9KTtcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbi8vIFBlci1wcm92aWRlciBjYWNoZWQgbG9hZGVyc1xuLy8g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbmNvbnN0IGxvYWRBd3NSYW5nZXMgPSBmdW5jdGlvbk1vZHVsZS5tZW1vaXplKGZldGNoQXdzUmFuZ2VzLCB7IHR0bE1zOiBSQU5HRV9DQUNIRV9UVExfTVMgfSk7XG5jb25zdCBsb2FkQXp1cmVSYW5nZXMgPSBmdW5jdGlvbk1vZHVsZS5tZW1vaXplKGZldGNoQXp1cmVSYW5nZXMsIHsgdHRsTXM6IFJBTkdFX0NBQ0hFX1RUTF9NUyB9KTtcbmNvbnN0IGxvYWRHY3BSYW5nZXMgPSBmdW5jdGlvbk1vZHVsZS5tZW1vaXplKGZldGNoR2NwUmFuZ2VzLCB7IHR0bE1zOiBSQU5HRV9DQUNIRV9UVExfTVMgfSk7XG5cbi8vIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuLy8gUHJvdmlkZXIgZmVlZCBmZXRjaCArIHBhcnNlXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuaW50ZXJmYWNlIEF3c0ZlZWQge1xuICBwcmVmaXhlcz86IHsgaXBfcHJlZml4Pzogc3RyaW5nOyByZWdpb24/OiBzdHJpbmcgfVtdO1xuICBpcHY2X3ByZWZpeGVzPzogeyBpcHY2X3ByZWZpeD86IHN0cmluZzsgcmVnaW9uPzogc3RyaW5nIH1bXTtcbn1cblxuLyoqXG4gKiBBV1MgYGlwLXJhbmdlcy5qc29uYDogYSBmbGF0IGxpc3Qgb2YgSVB2NCAoYHByZWZpeGVzYCkgYW5kIElQdjZcbiAqIChgaXB2Nl9wcmVmaXhlc2ApIGJsb2NrcywgZWFjaCBhbHJlYWR5IHRhZ2dlZCB3aXRoIGEgYHJlZ2lvbmAgc3VjaFxuICogYXMgYFwidXMtZWFzdC0xXCJgIChvciBgXCJHTE9CQUxcImAgZm9yIGVkZ2UgcmFuZ2VzKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmV0Y2hBd3NSYW5nZXMoKTogUHJvbWlzZTxQcm92aWRlclJhbmdlcz4ge1xuICBjb25zdCBmZWVkID0gYXdhaXQgZmV0Y2hKc29uPEF3c0ZlZWQ+KEFXU19SQU5HRVNfVVJMKTtcbiAgY29uc3QgcmFuZ2VzOiBSZWdpb25DaWRyW10gPSBbXTtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBmZWVkLnByZWZpeGVzID8/IFtdKSB7XG4gICAgYWRkUmFuZ2UocmFuZ2VzLCBlbnRyeS5pcF9wcmVmaXgsIGVudHJ5LnJlZ2lvbik7XG4gIH1cbiAgZm9yIChjb25zdCBlbnRyeSBvZiBmZWVkLmlwdjZfcHJlZml4ZXMgPz8gW10pIHtcbiAgICBhZGRSYW5nZShyYW5nZXMsIGVudHJ5LmlwdjZfcHJlZml4LCBlbnRyeS5yZWdpb24pO1xuICB9XG4gIGxvZ2dlci5kZWJ1ZyhcImxvYWRlZCBhd3MgcmFuZ2VzXCIsIHsgY291bnQ6IHJhbmdlcy5sZW5ndGggfSk7XG4gIHJldHVybiB7IHByb3ZpZGVyOiBDbG91ZFByb3ZpZGVyLkF3cywgcmFuZ2VzIH07XG59XG5cbmludGVyZmFjZSBHY3BGZWVkIHtcbiAgcHJlZml4ZXM/OiB7IGlwdjRQcmVmaXg/OiBzdHJpbmc7IGlwdjZQcmVmaXg/OiBzdHJpbmc7IHNjb3BlPzogc3RyaW5nIH1bXTtcbn1cblxuLyoqXG4gKiBHQ1AgYGNsb3VkLmpzb25gOiBhIGxpc3Qgb2YgYmxvY2tzIGVhY2ggY2FycnlpbmcgYW4gYGlwdjRQcmVmaXhgIG9yXG4gKiBgaXB2NlByZWZpeGAgYW5kIGEgYHNjb3BlYCB0aGF0IGlzIHRoZSByZWdpb24gKGBcInVzLWVhc3QxXCJgKSBvclxuICogYFwiZ2xvYmFsXCJgIGZvciBub24tcmVnaW9uYWwgcmFuZ2VzLlxuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaEdjcFJhbmdlcygpOiBQcm9taXNlPFByb3ZpZGVyUmFuZ2VzPiB7XG4gIGNvbnN0IGZlZWQgPSBhd2FpdCBmZXRjaEpzb248R2NwRmVlZD4oR0NQX1JBTkdFU19VUkwpO1xuICBjb25zdCByYW5nZXM6IFJlZ2lvbkNpZHJbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGZlZWQucHJlZml4ZXMgPz8gW10pIHtcbiAgICBhZGRSYW5nZShyYW5nZXMsIGVudHJ5LmlwdjRQcmVmaXggPz8gZW50cnkuaXB2NlByZWZpeCwgZW50cnkuc2NvcGUpO1xuICB9XG4gIGxvZ2dlci5kZWJ1ZyhcImxvYWRlZCBnY3AgcmFuZ2VzXCIsIHsgY291bnQ6IHJhbmdlcy5sZW5ndGggfSk7XG4gIHJldHVybiB7IHByb3ZpZGVyOiBDbG91ZFByb3ZpZGVyLkdjcCwgcmFuZ2VzIH07XG59XG5cbmludGVyZmFjZSBBenVyZUZlZWQge1xuICB2YWx1ZXM/OiB7XG4gICAgbmFtZT86IHN0cmluZztcbiAgICBwcm9wZXJ0aWVzPzogeyByZWdpb24/OiBzdHJpbmc7IGFkZHJlc3NQcmVmaXhlcz86IHN0cmluZ1tdIH07XG4gIH1bXTtcbn1cblxuLyoqXG4gKiBBenVyZSBzZXJ2aWNlIHRhZ3M6IE1pY3Jvc29mdCBzaGlwcyBubyBzdGFibGUgZmVlZCBVUkwsIHNvIHNjcmFwZSB0aGVcbiAqIGN1cnJlbnQgYFNlcnZpY2VUYWdzX1B1YmxpY188ZGF0ZT4uanNvbmAgbGluayBvZmYgdGhlIGRvd25sb2FkIHBhZ2VcbiAqIGFuZCBmZXRjaCBpdC4gT25seSB0aGUgcmVnaW9uYWwgYEF6dXJlQ2xvdWQuPHJlZ2lvbj5gIGFnZ3JlZ2F0ZXNcbiAqICh3aGljaCBoYXZlIGEgbm9uLWVtcHR5IGByZWdpb25gKSBhcmUga2VwdDsgdGhlIGNsb3VkLXdpZGVcbiAqIGBBenVyZUNsb3VkYCB0YWcgYW5kIHBlci1zZXJ2aWNlIHRhZ3MgYXJlIGlnbm9yZWQgc28gYW4gYWRkcmVzcyBtYXBzXG4gKiBjbGVhbmx5IHRvIG9uZSByZWdpb24uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZldGNoQXp1cmVSYW5nZXMoKTogUHJvbWlzZTxQcm92aWRlclJhbmdlcz4ge1xuICBjb25zdCBwYWdlID0gYXdhaXQgZmV0Y2hUZXh0KEFaVVJFX0RPV05MT0FEX1BBR0UpO1xuICBjb25zdCBqc29uVXJsID0gcGFnZS5tYXRjaChBWlVSRV9KU09OX0xJTkspPy5bMF07XG4gIGlmICghanNvblVybCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcImNvdWxkIG5vdCBmaW5kIFNlcnZpY2VUYWdzIEpTT04gbGluayBvbiBBenVyZSBkb3dubG9hZCBwYWdlXCIpO1xuICB9XG4gIGNvbnN0IGZlZWQgPSBhd2FpdCBmZXRjaEpzb248QXp1cmVGZWVkPihqc29uVXJsKTtcbiAgY29uc3QgcmFuZ2VzOiBSZWdpb25DaWRyW10gPSBbXTtcbiAgZm9yIChjb25zdCB2YWx1ZSBvZiBmZWVkLnZhbHVlcyA/PyBbXSkge1xuICAgIGNvbnN0IHJlZ2lvbiA9IHZhbHVlLnByb3BlcnRpZXM/LnJlZ2lvbjtcbiAgICBpZiAoIXJlZ2lvbiB8fCAhdmFsdWUubmFtZT8uc3RhcnRzV2l0aChcIkF6dXJlQ2xvdWQuXCIpKSBjb250aW51ZTtcbiAgICBmb3IgKGNvbnN0IHByZWZpeCBvZiB2YWx1ZS5wcm9wZXJ0aWVzPy5hZGRyZXNzUHJlZml4ZXMgPz8gW10pIHtcbiAgICAgIGFkZFJhbmdlKHJhbmdlcywgcHJlZml4LCByZWdpb24pO1xuICAgIH1cbiAgfVxuICBsb2dnZXIuZGVidWcoXCJsb2FkZWQgYXp1cmUgcmFuZ2VzXCIsIHsgY291bnQ6IHJhbmdlcy5sZW5ndGggfSk7XG4gIHJldHVybiB7IHByb3ZpZGVyOiBDbG91ZFByb3ZpZGVyLkF6dXJlLCByYW5nZXMgfTtcbn1cblxuLy8g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4vLyBIZWxwZXJzXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqIFBhcnNlIGBjaWRyYCBhbmQsIHdoZW4gdmFsaWQgYW5kIGByZWdpb25gIGlzIHNldCwgcHVzaCBhIHRhZ2dlZCByYW5nZS4gKi9cbmZ1bmN0aW9uIGFkZFJhbmdlKHJhbmdlczogUmVnaW9uQ2lkcltdLCBjaWRyPzogc3RyaW5nLCByZWdpb24/OiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKCFjaWRyIHx8ICFyZWdpb24pIHJldHVybjtcbiAgY29uc3QgcGFyc2VkID0gbmV0LnBhcnNlQ2lkcihjaWRyKTtcbiAgaWYgKHBhcnNlZCkgcmFuZ2VzLnB1c2goeyAuLi5wYXJzZWQsIHJlZ2lvbiB9KTtcbn1cblxuLyoqXG4gKiBGZXRjaCBhbmQgcGFyc2UgYSBwcm92aWRlciBmZWVkLiBBIHBhcnNlIGZhaWx1cmUgbmFtZXMgdGhlIFVSTCByYXRoZXIgdGhhblxuICogc3VyZmFjaW5nIGFuIG9wYXF1ZSBgVW5leHBlY3RlZCB0b2tlbmAgLSB0aGUgdGV4dCBtYXkgY29tZSBmcm9tIHRoZSBvbi1kaXNrXG4gKiBjYWNoZSwgc28gXCJ3aGljaCBmZWVkXCIgaXMgdGhlIHBhcnQgd29ydGgga25vd2luZy4ge0BsaW5rIGxvYWRQcm92aWRlclJhbmdlc31cbiAqIHR1cm5zIHRoZSB0aHJvdyBpbnRvIGEgcGVyLXByb3ZpZGVyIHdhcm5pbmcuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZldGNoSnNvbjxUPih1cmw6IHN0cmluZyk6IFByb21pc2U8VD4ge1xuICBjb25zdCB0ZXh0ID0gYXdhaXQgZmV0Y2hUZXh0KHVybCk7XG4gIGNvbnN0IHBhcnNlZCA9IGpzb24ucGFyc2U8VD4odGV4dCk7XG4gIGlmIChwYXJzZWQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgcmFuZ2UgZmVlZCByZXR1cm5lZCBub24tSlNPTiBjb250ZW50OiAke3VybH1gKTtcbiAgfVxuICByZXR1cm4gcGFyc2VkO1xufVxuXG4vKipcbiAqIEZldGNoIGB1cmxgIGFzIHRleHQgd2l0aCBhIDI0aCBvbi1kaXNrIGNhY2hlIHVuZGVyIHRoZSBPUyB0ZW1wIGRpclxuICogKGtleWVkIGJ5IGFuIEZOViBoYXNoIG9mIHRoZSBVUkwpLiBBIGZyZXNoIGNhY2hlIGZpbGUgaXMgcmV0dXJuZWRcbiAqIGRpcmVjdGx5OyBhIG1pc3MvZXhwaXJ5IGZldGNoZXMsIHdyaXRlcyB0byBhIHVuaXF1ZSB0ZW1wIGZpbGUsIGFuZFxuICogYXRvbWljYWxseSByZW5hbWVzIGl0IGludG8gcGxhY2Ugc28gY29uY3VycmVudCBjYWxsZXJzIG5ldmVyIG9ic2VydmVcbiAqIGEgaGFsZi13cml0dGVuIGNhY2hlIGVudHJ5LlxuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaFRleHQodXJsOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBjYWNoZURpciA9IGpvaW4odG1wZGlyKCksIFwiZGJ4LXRvb2xzXCIsIFwic2hhcmVkXCIsIFwiY2xvdWRcIik7XG4gIGNvbnN0IGNhY2hlRGlyQ3JlYXRlZCA9IGF3YWl0IG1rZGlyKGNhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihjYWNoZURpciwgYGZldGNoLSR7aGFzaC5mbnZIYXNoKHVybCl9LnR4dGApO1xuICBjb25zdCBjcmVhdGVkQXQgPSBjYWNoZURpckNyZWF0ZWQgPyB1bmRlZmluZWQgOiBhd2FpdCBnZXRDcmVhdGVkKGNhY2hlUGF0aCk7XG4gIGlmIChjcmVhdGVkQXQpIHtcbiAgICBjb25zdCBleHBpcmVzQXQgPSBuZXcgRGF0ZShjcmVhdGVkQXQuZ2V0VGltZSgpICsgUkFOR0VfQ0FDSEVfVFRMX01TKTtcbiAgICBpZiAoZXhwaXJlc0F0ID4gbmV3IERhdGUoKSkge1xuICAgICAgbG9nZ2VyLmRlYnVnKFwiY2FjaGVkIGZldGNoIGhpdFwiLCB7IHVybCwgY2FjaGVQYXRoIH0pO1xuICAgICAgcmV0dXJuIHJlYWRGaWxlKGNhY2hlUGF0aCwgXCJ1dGY4XCIpO1xuICAgIH1cbiAgfVxuICBsZXQgdGVtcFBhdGg6IHN0cmluZyB8IG51bGwgPSBqb2luKGNhY2hlRGlyLCBgJHtoYXNoLmlkKCl9LnR4dGApO1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsKTtcbiAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICB0aHJvdyBhd2FpdCBodHRwLmNyZWF0ZUZldGNoRXJyb3IocmVzcG9uc2UsIHVybCk7XG4gICAgfVxuICAgIGNvbnN0IHJlc3BvbnNlVGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICBhd2FpdCBta2RpcihkaXJuYW1lKHRlbXBQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgYXdhaXQgd3JpdGVGaWxlKHRlbXBQYXRoLCByZXNwb25zZVRleHQpO1xuXG4gICAgYXdhaXQgcmVuYW1lKHRlbXBQYXRoLCBjYWNoZVBhdGgpO1xuICAgIGxvZ2dlci5kZWJ1ZyhcImNhY2hlZCBmZXRjaCBsb2FkXCIsIHsgdXJsLCBjYWNoZVBhdGggfSk7XG4gICAgdGVtcFBhdGggPSBudWxsO1xuICAgIHJldHVybiByZXNwb25zZVRleHQ7XG4gIH0gZmluYWxseSB7XG4gICAgaWYgKHRlbXBQYXRoKSB7XG4gICAgICBhd2FpdCB1bmxpbmsodGVtcFBhdGgpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogQmlydGggdGltZSBvZiBgcGF0aGAsIG9yIGB1bmRlZmluZWRgIHdoZW4gaXQgZG9lc24ndCBleGlzdCB5ZXQuICovXG5hc3luYyBmdW5jdGlvbiBnZXRDcmVhdGVkKHBhdGg6IHN0cmluZyk6IFByb21pc2U8RGF0ZSB8IHVuZGVmaW5lZD4ge1xuICByZXR1cm4gKGF3YWl0IGZpbGUuc3RhdFN5bmMocGF0aCkpPy5iaXJ0aHRpbWU7XG59XG4iXX0=
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Databricks {@link FileSystem} backed by {@link WorkspaceClient}.
|
|
3
|
-
*
|
|
4
|
-
* Extends {@link BaseFileSystem}. Routes I/O by absolute path:
|
|
5
|
-
* - `/Workspace`, `/Users`, `/Repos`, `/Shared` → workspace objects API
|
|
6
|
-
* - `/Volumes/...` (or `catalog.schema.volume` roots) → Unity Catalog Files API
|
|
7
|
-
* - `/dbfs/...` → DBFS API
|
|
8
|
-
*
|
|
9
|
-
* Every primitive picks its API through {@link DatabricksFileSystem.dispatch}
|
|
10
|
-
* rather than re-branching by hand, and error normalization is inherited from
|
|
11
|
-
* {@link BaseFileSystem}, so a primitive here is just the SDK call.
|
|
12
|
-
*
|
|
13
|
-
* @module
|
|
14
|
-
*/
|
|
15
|
-
import { BaseFileSystem, type CopyOptions, type FileEntry, type FileStat, type WriteFileOptions } from "@dbx-tools/shared-fs";
|
|
16
|
-
import { type WorkspaceClient } from "./workspace.ts";
|
|
17
|
-
/** Options for {@link DatabricksFileSystem}. */
|
|
18
|
-
export interface DatabricksFileSystemOptions {
|
|
19
|
-
/** Unique identifier. Defaults to a stable hash of the normalized root. */
|
|
20
|
-
id?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Filesystem root. Accepts:
|
|
23
|
-
* - `/Volumes/catalog/schema/volume` (also `/Volume/...`)
|
|
24
|
-
* - `catalog.schema.volume`
|
|
25
|
-
* - `~` / `~/...` → `/Workspace/Users/<userName>/...` (needs {@link userName},
|
|
26
|
-
* or use {@link DatabricksFileSystem.create})
|
|
27
|
-
* - `/Workspace/...`, `/Users/...`, `/Repos/...`, `/Shared/...`
|
|
28
|
-
* - `/dbfs/...`
|
|
29
|
-
*/
|
|
30
|
-
root: string;
|
|
31
|
-
/**
|
|
32
|
-
* Username for expanding `~`. When omitted and {@link root} is home-relative,
|
|
33
|
-
* prefer {@link DatabricksFileSystem.create} which resolves it via
|
|
34
|
-
* `getCurrentUserName`.
|
|
35
|
-
*/
|
|
36
|
-
userName?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Databricks workspace client. Defaults to `tryGetWorkspaceClient()`, otherwise
|
|
39
|
-
* a default {@link WorkspaceClient} from env / profile auth.
|
|
40
|
-
*/
|
|
41
|
-
client?: WorkspaceClient;
|
|
42
|
-
/** Block all write operations. Defaults to false. */
|
|
43
|
-
readOnly?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Create {@link root} (and parents) during init. Defaults to false (volume
|
|
46
|
-
* and workspace roots are usually provisioned out of band).
|
|
47
|
-
*/
|
|
48
|
-
createRoot?: boolean;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* {@link FileSystem} implementation over Databricks workspace files, UC
|
|
52
|
-
* volumes, and DBFS.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* const fs = new DatabricksFileSystem({ root: "main.default.assets" });
|
|
57
|
-
* await fs.writeFile("notes/hello.txt", "hi");
|
|
58
|
-
*
|
|
59
|
-
* const home = await DatabricksFileSystem.create({ root: "~" });
|
|
60
|
-
* const listing = await home.readdir(".");
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
export declare class DatabricksFileSystem extends BaseFileSystem<"databricks"> {
|
|
64
|
-
private client;
|
|
65
|
-
private readonly clientOption;
|
|
66
|
-
constructor(options: DatabricksFileSystemOptions);
|
|
67
|
-
/**
|
|
68
|
-
* Construct a {@link DatabricksFileSystem}, resolving `~` roots via the
|
|
69
|
-
* workspace current user when needed.
|
|
70
|
-
*/
|
|
71
|
-
static create(options: DatabricksFileSystemOptions): Promise<DatabricksFileSystem>;
|
|
72
|
-
protected onInit(): Promise<void>;
|
|
73
|
-
/** Run the handler for `absolutePath`'s Databricks API with the live client. */
|
|
74
|
-
private dispatch;
|
|
75
|
-
protected createRootDirectory(): Promise<void>;
|
|
76
|
-
protected readBytesAt(resolvedPath: string): Promise<Uint8Array>;
|
|
77
|
-
protected writeBytesAt(resolvedPath: string, content: Uint8Array, options: Required<WriteFileOptions>): Promise<void>;
|
|
78
|
-
protected deleteFileAt(resolvedPath: string): Promise<void>;
|
|
79
|
-
protected createDirectoryAt(resolvedPath: string): Promise<void>;
|
|
80
|
-
protected removeDirectoryAt(resolvedPath: string): Promise<void>;
|
|
81
|
-
protected listDirectoryAt(resolvedPath: string): Promise<FileEntry[]>;
|
|
82
|
-
protected statAt(resolvedPath: string): Promise<Omit<FileStat, "path">>;
|
|
83
|
-
protected tryMoveFileAt(sourcePath: string, destinationPath: string, _options: Required<CopyOptions>): Promise<boolean>;
|
|
84
|
-
/**
|
|
85
|
-
* UC `createDirectory` is single-level, so walk the path creating each level
|
|
86
|
-
* below the volume itself. A level that already exists is not an error.
|
|
87
|
-
*/
|
|
88
|
-
private createVolumeDirectories;
|
|
89
|
-
/** Stat a UC path: file metadata first, then a directory probe. */
|
|
90
|
-
private statVolumePath;
|
|
91
|
-
private readDbfsFile;
|
|
92
|
-
private writeDbfsFile;
|
|
93
|
-
}
|