@dbx-tools/genie 0.6.61 → 0.6.63
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 +8 -0
- package/lib/src/space.d.ts +19 -0
- package/lib/src/space.js +44 -4
- package/package.json +4 -4
- package/src/space.ts +58 -11
package/README.md
CHANGED
|
@@ -142,6 +142,14 @@ const questions = space.genieSampleQuestions(genieSpace);
|
|
|
142
142
|
metadata by default. `space.genieSampleQuestions()` extracts curated starter
|
|
143
143
|
questions and returns `[]` when none are configured.
|
|
144
144
|
|
|
145
|
+
The serialized blob needs `Can Edit` on the space, while `Can Run` is enough for
|
|
146
|
+
title and description. When the workspace rejects the serialized request for
|
|
147
|
+
lack of permission, `getGenieSpace()` retries once without it and logs
|
|
148
|
+
`serialized-space:forbidden`, so an app service principal holding only `Can Run`
|
|
149
|
+
still resolves the space and simply reports no starter questions. Every other
|
|
150
|
+
failure - a cancelled request, a missing space, a retry that also fails - is
|
|
151
|
+
thrown.
|
|
152
|
+
|
|
145
153
|
## Options
|
|
146
154
|
|
|
147
155
|
`chat.GenieChatOptions` is shared by both drivers:
|
package/lib/src/space.d.ts
CHANGED
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
* workspace client's raw `apiClient` since the typed request shape has no flag
|
|
11
11
|
* for it.
|
|
12
12
|
*
|
|
13
|
+
* The serialized blob is also more privileged than the listing surface: the
|
|
14
|
+
* workspace API requires `Can Edit` on the space to return it, while `Can Run`
|
|
15
|
+
* is enough for title / description. A caller that only holds `Can Run` - an
|
|
16
|
+
* app service principal granted just enough to ask questions is the common case
|
|
17
|
+
* - would otherwise lose the whole space lookup to a `PERMISSION_DENIED` it
|
|
18
|
+
* cannot act on, so the fetch degrades to the unserialized request instead of
|
|
19
|
+
* failing (see {@link getGenieSpace}).
|
|
20
|
+
*
|
|
13
21
|
* @module
|
|
14
22
|
*/
|
|
15
23
|
import { WorkspaceClient } from "@databricks/sdk-experimental";
|
|
@@ -27,6 +35,10 @@ export interface GetGenieSpaceOptions {
|
|
|
27
35
|
* Request the `serialized_space` blob (catalogs, tables, sample questions,
|
|
28
36
|
* prompts). Defaults to `true` - the only reason to skip it is when the
|
|
29
37
|
* caller just needs title / description and wants the smaller payload.
|
|
38
|
+
*
|
|
39
|
+
* Requesting it is best-effort: the blob needs `Can Edit` on the space, so a
|
|
40
|
+
* caller without it gets the unserialized space back rather than an error,
|
|
41
|
+
* and {@link genieSampleQuestions} then reports no suggestions.
|
|
30
42
|
*/
|
|
31
43
|
serialized?: boolean;
|
|
32
44
|
/**
|
|
@@ -41,6 +53,13 @@ export interface GetGenieSpaceOptions {
|
|
|
41
53
|
* through the raw `apiClient`, then validates the response against
|
|
42
54
|
* {@link GenieSpaceSchema} (unknown fields like `etag` /
|
|
43
55
|
* `parent_path` are stripped).
|
|
56
|
+
*
|
|
57
|
+
* When the serialized request is rejected for lack of permission (`403`, or a
|
|
58
|
+
* `PERMISSION_DENIED` / `Can Edit` message - the workspace API gates the blob
|
|
59
|
+
* behind `Can Edit`), it retries once without the flag so the caller still gets
|
|
60
|
+
* the space. Any other failure, and a retry that fails too, is rethrown: a
|
|
61
|
+
* cancelled request or a missing space must not look like an unserialized
|
|
62
|
+
* space.
|
|
44
63
|
*/
|
|
45
64
|
export declare function getGenieSpace(spaceId: string, options?: GetGenieSpaceOptions): Promise<GenieSpace>;
|
|
46
65
|
/**
|
package/lib/src/space.js
CHANGED
|
@@ -10,11 +10,19 @@
|
|
|
10
10
|
* workspace client's raw `apiClient` since the typed request shape has no flag
|
|
11
11
|
* for it.
|
|
12
12
|
*
|
|
13
|
+
* The serialized blob is also more privileged than the listing surface: the
|
|
14
|
+
* workspace API requires `Can Edit` on the space to return it, while `Can Run`
|
|
15
|
+
* is enough for title / description. A caller that only holds `Can Run` - an
|
|
16
|
+
* app service principal granted just enough to ask questions is the common case
|
|
17
|
+
* - would otherwise lose the whole space lookup to a `PERMISSION_DENIED` it
|
|
18
|
+
* cannot act on, so the fetch degrades to the unserialized request instead of
|
|
19
|
+
* failing (see {@link getGenieSpace}).
|
|
20
|
+
*
|
|
13
21
|
* @module
|
|
14
22
|
*/
|
|
15
23
|
import { WorkspaceClient } from "@databricks/sdk-experimental";
|
|
16
24
|
import { databricks } from "@dbx-tools/appkit";
|
|
17
|
-
import { json, log, object, string } from "@dbx-tools/shared-core";
|
|
25
|
+
import { error, json, log, object, string } from "@dbx-tools/shared-core";
|
|
18
26
|
import { genieModel } from "@dbx-tools/shared-genie";
|
|
19
27
|
const logger = log.logger("genie/space");
|
|
20
28
|
/**
|
|
@@ -23,20 +31,52 @@ const logger = log.logger("genie/space");
|
|
|
23
31
|
* through the raw `apiClient`, then validates the response against
|
|
24
32
|
* {@link GenieSpaceSchema} (unknown fields like `etag` /
|
|
25
33
|
* `parent_path` are stripped).
|
|
34
|
+
*
|
|
35
|
+
* When the serialized request is rejected for lack of permission (`403`, or a
|
|
36
|
+
* `PERMISSION_DENIED` / `Can Edit` message - the workspace API gates the blob
|
|
37
|
+
* behind `Can Edit`), it retries once without the flag so the caller still gets
|
|
38
|
+
* the space. Any other failure, and a retry that fails too, is rethrown: a
|
|
39
|
+
* cancelled request or a missing space must not look like an unserialized
|
|
40
|
+
* space.
|
|
26
41
|
*/
|
|
27
42
|
export async function getGenieSpace(spaceId, options) {
|
|
28
43
|
const client = options?.workspaceClient ?? new WorkspaceClient({});
|
|
29
44
|
const serialized = options?.serialized !== false;
|
|
30
45
|
const ctx = options?.context ? databricks.toContext(options.context) : undefined;
|
|
31
|
-
const
|
|
46
|
+
const request = (includeSerialized) => client.apiClient.request({
|
|
32
47
|
path: `/api/2.0/genie/spaces/${encodeURIComponent(spaceId)}`,
|
|
33
48
|
method: "GET",
|
|
34
|
-
query:
|
|
49
|
+
query: includeSerialized ? { include_serialized_space: true } : {},
|
|
35
50
|
headers: new Headers(),
|
|
36
51
|
raw: false,
|
|
37
52
|
}, ctx);
|
|
53
|
+
let raw;
|
|
54
|
+
try {
|
|
55
|
+
raw = await request(serialized);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
if (!serialized || !isSerializedSpaceForbidden(err))
|
|
59
|
+
throw err;
|
|
60
|
+
logger.debug("serialized-space:forbidden", {
|
|
61
|
+
spaceId,
|
|
62
|
+
error: error.errorMessage(err),
|
|
63
|
+
});
|
|
64
|
+
raw = await request(false);
|
|
65
|
+
}
|
|
38
66
|
return genieModel.GenieSpaceSchema.parse(raw);
|
|
39
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* True when a failed space request was rejected for lack of permission, the one
|
|
70
|
+
* failure the unserialized retry can recover from. Matches on `403` and on the
|
|
71
|
+
* `PERMISSION_DENIED` / `Can Edit` wording the workspace API returns, since the
|
|
72
|
+
* SDK surfaces the error code without always carrying a status.
|
|
73
|
+
*/
|
|
74
|
+
function isSerializedSpaceForbidden(err) {
|
|
75
|
+
const context = error.errorContext(err);
|
|
76
|
+
return (context.hasStatusCode(403) ||
|
|
77
|
+
context.hasMessage("permission denied") ||
|
|
78
|
+
context.hasMessage("can edit"));
|
|
79
|
+
}
|
|
40
80
|
/**
|
|
41
81
|
* Extract the curated starter questions an author configured on a Genie space.
|
|
42
82
|
* Reads `serialized_space -> config.sample_questions[*].question`. Returns `[]`
|
|
@@ -66,4 +106,4 @@ export function genieSampleQuestions(space) {
|
|
|
66
106
|
.distinct(),
|
|
67
107
|
];
|
|
68
108
|
}
|
|
69
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUVILE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxVQUFVLEVBQW1CLE1BQU0seUJBQXlCLENBQUM7QUFFdEUsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQXVCekM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQ2pDLE9BQWUsRUFDZixPQUE4QjtJQUU5QixNQUFNLE1BQU0sR0FBRyxPQUFPLEVBQUUsZUFBZSxJQUFJLElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ25FLE1BQU0sVUFBVSxHQUFHLE9BQU8sRUFBRSxVQUFVLEtBQUssS0FBSyxDQUFDO0lBQ2pELE1BQU0sR0FBRyxHQUFHLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDakYsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FDeEM7UUFDRSxJQUFJLEVBQUUseUJBQXlCLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQzVELE1BQU0sRUFBRSxLQUFLO1FBQ2IsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSx3QkFBd0IsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRTtRQUMzRCxPQUFPLEVBQUUsSUFBSSxPQUFPLEVBQUU7UUFDdEIsR0FBRyxFQUFFLEtBQUs7S0FDWCxFQUNELEdBQUcsQ0FDSixDQUFDO0lBQ0YsT0FBTyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ2hELENBQUM7QUFZRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEtBQWlCO0lBQ3BELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztJQUMxQyxJQUFJLENBQUMsVUFBVTtRQUFFLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdEMsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDekIsTUFBTSxDQUFDLElBQUksQ0FBQyw4QkFBOEIsRUFBRSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN6RSxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLGVBQWUsR0FBSSxNQUE2RCxFQUFFLE1BQU07UUFDNUYsRUFBRSxnQkFBZ0IsQ0FBQztJQUNyQixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUUvQyxPQUFPO1FBQ0wsR0FBRyxNQUFNO2FBQ04sUUFBUSxDQUFDLGVBQTZDLENBQUM7YUFDdkQsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQzthQUNyRCxPQUFPLEVBQUU7YUFDVCxRQUFRLEVBQUU7S0FDZCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuaWUgc3BhY2UgbWV0YWRhdGEgaGVscGVycy5cbiAqXG4gKiBGZXRjaGVzIGEgR2VuaWUgc3BhY2UncyBkZWZpbml0aW9uIChpbmNsdWRpbmcgdGhlIG9wdC1pbiBgc2VyaWFsaXplZF9zcGFjZWBcbiAqIGJsb2IpIGFuZCBleHRyYWN0cyB0aGUgY3VyYXRlZCBzdGFydGVyIHF1ZXN0aW9ucyBhbiBhdXRob3IgY29uZmlndXJlZCBvbiB0aGVcbiAqIHNwYWNlLiBUaGUgdHlwZWQgU0RLIGBjbGllbnQuZ2VuaWUuZ2V0U3BhY2VgIG9ubHkgcmV0dXJucyB0aGVcbiAqIGRpcmVjdG9yeS1saXN0aW5nIHN1cmZhY2UgKGB0aXRsZWAgLyBgZGVzY3JpcHRpb25gIC8gYHdhcmVob3VzZV9pZGApOyB0aGVcbiAqIHNhbXBsZSBxdWVzdGlvbnMgbGl2ZSBpbnNpZGUgYHNlcmlhbGl6ZWRfc3BhY2VgLCB3aGljaCB0aGUgUkVTVCBBUEkgcmV0dXJuc1xuICogb25seSB3aGVuIGBpbmNsdWRlX3NlcmlhbGl6ZWRfc3BhY2U9dHJ1ZWAuIFdlIGhpdCB0aGF0IGVuZHBvaW50IHRocm91Z2ggdGhlXG4gKiB3b3Jrc3BhY2UgY2xpZW50J3MgcmF3IGBhcGlDbGllbnRgIHNpbmNlIHRoZSB0eXBlZCByZXF1ZXN0IHNoYXBlIGhhcyBubyBmbGFnXG4gKiBmb3IgaXQuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IFdvcmtzcGFjZUNsaWVudCB9IGZyb20gXCJAZGF0YWJyaWNrcy9zZGstZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBkYXRhYnJpY2tzIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG5pbXBvcnQgeyBqc29uLCBsb2csIG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGdlbmllTW9kZWwsIHR5cGUgR2VuaWVTcGFjZSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1nZW5pZVwiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiZ2VuaWUvc3BhY2VcIik7XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgZ2V0R2VuaWVTcGFjZX0uICovXG5leHBvcnQgaW50ZXJmYWNlIEdldEdlbmllU3BhY2VPcHRpb25zIHtcbiAgLyoqXG4gICAqIEV4cGxpY2l0IGBXb3Jrc3BhY2VDbGllbnRgLiBEZWZhdWx0cyB0byBhIGZyZXNoIGBuZXcgV29ya3NwYWNlQ2xpZW50KHt9KWBcbiAgICogKGVudi12YXIgYXV0aCkuIFNlcnZlciBjYWxsZXJzIHNob3VsZCBwYXNzIHRoZWlyIE9CTy1zY29wZWQgY2xpZW50IHNvIHRoZVxuICAgKiBsb29rdXAgcnVucyBhcyB0aGUgdXNlci5cbiAgICovXG4gIHdvcmtzcGFjZUNsaWVudD86IFdvcmtzcGFjZUNsaWVudDtcbiAgLyoqXG4gICAqIFJlcXVlc3QgdGhlIGBzZXJpYWxpemVkX3NwYWNlYCBibG9iIChjYXRhbG9ncywgdGFibGVzLCBzYW1wbGUgcXVlc3Rpb25zLFxuICAgKiBwcm9tcHRzKS4gRGVmYXVsdHMgdG8gYHRydWVgIC0gdGhlIG9ubHkgcmVhc29uIHRvIHNraXAgaXQgaXMgd2hlbiB0aGVcbiAgICogY2FsbGVyIGp1c3QgbmVlZHMgdGl0bGUgLyBkZXNjcmlwdGlvbiBhbmQgd2FudHMgdGhlIHNtYWxsZXIgcGF5bG9hZC5cbiAgICovXG4gIHNlcmlhbGl6ZWQ/OiBib29sZWFuO1xuICAvKipcbiAgICogRXh0ZXJuYWwgY2FuY2VsbGF0aW9uLiBBY2NlcHRzIGEgV0hBVFdHIGBBYm9ydFNpZ25hbGAgb3IgYSBmdWxseS1idWlsdCBTREtcbiAgICogYENvbnRleHRgIChzZWUgYGRhdGFicmlja3MuQ29udGV4dExpa2VgKS5cbiAgICovXG4gIGNvbnRleHQ/OiBkYXRhYnJpY2tzLkNvbnRleHRMaWtlO1xufVxuXG4vKipcbiAqIEZldGNoIGEgR2VuaWUgc3BhY2UgYnkgaWQsIG9wdGlvbmFsbHkgaW5jbHVkaW5nIGl0cyBzZXJpYWxpemVkIGRlZmluaXRpb24uXG4gKiBIaXRzIGBHRVQgL2FwaS8yLjAvZ2VuaWUvc3BhY2VzLzxpZD5gIHdpdGggYGluY2x1ZGVfc2VyaWFsaXplZF9zcGFjZT10cnVlYFxuICogdGhyb3VnaCB0aGUgcmF3IGBhcGlDbGllbnRgLCB0aGVuIHZhbGlkYXRlcyB0aGUgcmVzcG9uc2UgYWdhaW5zdFxuICoge0BsaW5rIEdlbmllU3BhY2VTY2hlbWF9ICh1bmtub3duIGZpZWxkcyBsaWtlIGBldGFnYCAvXG4gKiBgcGFyZW50X3BhdGhgIGFyZSBzdHJpcHBlZCkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRHZW5pZVNwYWNlKFxuICBzcGFjZUlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiBHZXRHZW5pZVNwYWNlT3B0aW9ucyxcbik6IFByb21pc2U8R2VuaWVTcGFjZT4ge1xuICBjb25zdCBjbGllbnQgPSBvcHRpb25zPy53b3Jrc3BhY2VDbGllbnQgPz8gbmV3IFdvcmtzcGFjZUNsaWVudCh7fSk7XG4gIGNvbnN0IHNlcmlhbGl6ZWQgPSBvcHRpb25zPy5zZXJpYWxpemVkICE9PSBmYWxzZTtcbiAgY29uc3QgY3R4ID0gb3B0aW9ucz8uY29udGV4dCA/IGRhdGFicmlja3MudG9Db250ZXh0KG9wdGlvbnMuY29udGV4dCkgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IHJhdyA9IGF3YWl0IGNsaWVudC5hcGlDbGllbnQucmVxdWVzdChcbiAgICB7XG4gICAgICBwYXRoOiBgL2FwaS8yLjAvZ2VuaWUvc3BhY2VzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KHNwYWNlSWQpfWAsXG4gICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICBxdWVyeTogc2VyaWFsaXplZCA/IHsgaW5jbHVkZV9zZXJpYWxpemVkX3NwYWNlOiB0cnVlIH0gOiB7fSxcbiAgICAgIGhlYWRlcnM6IG5ldyBIZWFkZXJzKCksXG4gICAgICByYXc6IGZhbHNlLFxuICAgIH0sXG4gICAgY3R4LFxuICApO1xuICByZXR1cm4gZ2VuaWVNb2RlbC5HZW5pZVNwYWNlU2NoZW1hLnBhcnNlKHJhdyk7XG59XG5cbi8qKlxuICogT25lIGVudHJ5IGluIGEgc2VyaWFsaXplZCBzcGFjZSdzIGBjb25maWcuc2FtcGxlX3F1ZXN0aW9uc2AuIFRoZVxuICogYXV0aG9yLWZhY2luZyBmaWVsZCBpcyBgcXVlc3Rpb25gLCB3aGljaCB0aGUgd2lyZSBmb3JtYXQgbW9kZWxzIGFzIGEgc3RyaW5nXG4gKiBhcnJheSAoYSBzaW5nbGUgbXVsdGktbGluZSBxdWVzdGlvbiBpcyBzcGxpdCBhY3Jvc3MgZW50cmllcyk7IHdlIHRyZWF0IHRoZVxuICogZmlyc3Qgbm9uLWVtcHR5IGVudHJ5IGFzIHRoZSBkaXNwbGF5YWJsZSBxdWVzdGlvbiB0ZXh0LlxuICovXG5pbnRlcmZhY2UgU2VyaWFsaXplZFNhbXBsZVF1ZXN0aW9uIHtcbiAgcXVlc3Rpb24/OiB1bmtub3duO1xufVxuXG4vKipcbiAqIEV4dHJhY3QgdGhlIGN1cmF0ZWQgc3RhcnRlciBxdWVzdGlvbnMgYW4gYXV0aG9yIGNvbmZpZ3VyZWQgb24gYSBHZW5pZSBzcGFjZS5cbiAqIFJlYWRzIGBzZXJpYWxpemVkX3NwYWNlIC0+IGNvbmZpZy5zYW1wbGVfcXVlc3Rpb25zWypdLnF1ZXN0aW9uYC4gUmV0dXJucyBgW11gXG4gKiB3aGVuIHRoZSBzcGFjZSBjYXJyaWVzIG5vIHNlcmlhbGl6ZWQgYmxvYiwgdGhlIGJsb2IgaXMgdW5wYXJzZWFibGUsIG9yIG5vXG4gKiBzYW1wbGUgcXVlc3Rpb25zIGFyZSBjb25maWd1cmVkIC0gc28gYSBtaXNzaW5nIG9yIG1pc2NvbmZpZ3VyZWQgc3BhY2VcbiAqIGRlZ3JhZGVzIHRvIFwibm8gc3VnZ2VzdGlvbnNcIiByYXRoZXIgdGhhbiB0aHJvd2luZy4gT3JkZXIgaXMgcHJlc2VydmVkICh0aGVcbiAqIGF1dGhvcidzIG9yZGVyaW5nKSBhbmQgZHVwbGljYXRlcyBhcmUgZHJvcHBlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmllU2FtcGxlUXVlc3Rpb25zKHNwYWNlOiBHZW5pZVNwYWNlKTogc3RyaW5nW10ge1xuICBjb25zdCBzZXJpYWxpemVkID0gc3BhY2Uuc2VyaWFsaXplZF9zcGFjZTtcbiAgaWYgKCFzZXJpYWxpemVkKSByZXR1cm4gW107XG4gIGNvbnN0IHBhcnNlZCA9IGpzb24ucGFyc2Uoc2VyaWFsaXplZCk7XG4gIGlmIChwYXJzZWQgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvZ2dlci53YXJuKFwic2VyaWFsaXplZC1zcGFjZTpwYXJzZS1lcnJvclwiLCB7IHNwYWNlSWQ6IHNwYWNlLnNwYWNlX2lkIH0pO1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBzYW1wbGVRdWVzdGlvbnMgPSAocGFyc2VkIGFzIHsgY29uZmlnPzogeyBzYW1wbGVfcXVlc3Rpb25zPzogdW5rbm93biB9IH0gfCBudWxsKT8uY29uZmlnXG4gICAgPy5zYW1wbGVfcXVlc3Rpb25zO1xuICBpZiAoIUFycmF5LmlzQXJyYXkoc2FtcGxlUXVlc3Rpb25zKSkgcmV0dXJuIFtdO1xuXG4gIHJldHVybiBbXG4gICAgLi4ub2JqZWN0XG4gICAgICAuc2VxdWVuY2Uoc2FtcGxlUXVlc3Rpb25zIGFzIFNlcmlhbGl6ZWRTYW1wbGVRdWVzdGlvbltdKVxuICAgICAgLm1hcCgoZW50cnkpID0+IHN0cmluZy5maXJzdE5vbkVtcHR5KGVudHJ5Py5xdWVzdGlvbikpXG4gICAgICAubm9uTnVsbCgpXG4gICAgICAuZGlzdGluY3QoKSxcbiAgXTtcbn1cbiJdfQ==
|
|
109
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUVILE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUsVUFBVSxFQUFtQixNQUFNLHlCQUF5QixDQUFDO0FBRXRFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7QUEyQnpDOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGFBQWEsQ0FDakMsT0FBZSxFQUNmLE9BQThCO0lBRTlCLE1BQU0sTUFBTSxHQUFHLE9BQU8sRUFBRSxlQUFlLElBQUksSUFBSSxlQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkUsTUFBTSxVQUFVLEdBQUcsT0FBTyxFQUFFLFVBQVUsS0FBSyxLQUFLLENBQUM7SUFDakQsTUFBTSxHQUFHLEdBQUcsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUNqRixNQUFNLE9BQU8sR0FBRyxDQUFDLGlCQUEwQixFQUFvQixFQUFFLENBQy9ELE1BQU0sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUN0QjtRQUNFLElBQUksRUFBRSx5QkFBeUIsa0JBQWtCLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDNUQsTUFBTSxFQUFFLEtBQUs7UUFDYixLQUFLLEVBQUUsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLEVBQUUsd0JBQXdCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUU7UUFDbEUsT0FBTyxFQUFFLElBQUksT0FBTyxFQUFFO1FBQ3RCLEdBQUcsRUFBRSxLQUFLO0tBQ1gsRUFDRCxHQUFHLENBQ0osQ0FBQztJQUVKLElBQUksR0FBWSxDQUFDO0lBQ2pCLElBQUksQ0FBQztRQUNILEdBQUcsR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxHQUFHLENBQUM7WUFBRSxNQUFNLEdBQUcsQ0FBQztRQUMvRCxNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixFQUFFO1lBQ3pDLE9BQU87WUFDUCxLQUFLLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUM7U0FDL0IsQ0FBQyxDQUFDO1FBQ0gsR0FBRyxHQUFHLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFDRCxPQUFPLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDaEQsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUywwQkFBMEIsQ0FBQyxHQUFZO0lBQzlDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsT0FBTyxDQUNMLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDO1FBQzFCLE9BQU8sQ0FBQyxVQUFVLENBQUMsbUJBQW1CLENBQUM7UUFDdkMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FDL0IsQ0FBQztBQUNKLENBQUM7QUFZRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEtBQWlCO0lBQ3BELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztJQUMxQyxJQUFJLENBQUMsVUFBVTtRQUFFLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdEMsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDekIsTUFBTSxDQUFDLElBQUksQ0FBQyw4QkFBOEIsRUFBRSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN6RSxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLGVBQWUsR0FBSSxNQUE2RCxFQUFFLE1BQU07UUFDNUYsRUFBRSxnQkFBZ0IsQ0FBQztJQUNyQixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUUvQyxPQUFPO1FBQ0wsR0FBRyxNQUFNO2FBQ04sUUFBUSxDQUFDLGVBQTZDLENBQUM7YUFDdkQsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQzthQUNyRCxPQUFPLEVBQUU7YUFDVCxRQUFRLEVBQUU7S0FDZCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuaWUgc3BhY2UgbWV0YWRhdGEgaGVscGVycy5cbiAqXG4gKiBGZXRjaGVzIGEgR2VuaWUgc3BhY2UncyBkZWZpbml0aW9uIChpbmNsdWRpbmcgdGhlIG9wdC1pbiBgc2VyaWFsaXplZF9zcGFjZWBcbiAqIGJsb2IpIGFuZCBleHRyYWN0cyB0aGUgY3VyYXRlZCBzdGFydGVyIHF1ZXN0aW9ucyBhbiBhdXRob3IgY29uZmlndXJlZCBvbiB0aGVcbiAqIHNwYWNlLiBUaGUgdHlwZWQgU0RLIGBjbGllbnQuZ2VuaWUuZ2V0U3BhY2VgIG9ubHkgcmV0dXJucyB0aGVcbiAqIGRpcmVjdG9yeS1saXN0aW5nIHN1cmZhY2UgKGB0aXRsZWAgLyBgZGVzY3JpcHRpb25gIC8gYHdhcmVob3VzZV9pZGApOyB0aGVcbiAqIHNhbXBsZSBxdWVzdGlvbnMgbGl2ZSBpbnNpZGUgYHNlcmlhbGl6ZWRfc3BhY2VgLCB3aGljaCB0aGUgUkVTVCBBUEkgcmV0dXJuc1xuICogb25seSB3aGVuIGBpbmNsdWRlX3NlcmlhbGl6ZWRfc3BhY2U9dHJ1ZWAuIFdlIGhpdCB0aGF0IGVuZHBvaW50IHRocm91Z2ggdGhlXG4gKiB3b3Jrc3BhY2UgY2xpZW50J3MgcmF3IGBhcGlDbGllbnRgIHNpbmNlIHRoZSB0eXBlZCByZXF1ZXN0IHNoYXBlIGhhcyBubyBmbGFnXG4gKiBmb3IgaXQuXG4gKlxuICogVGhlIHNlcmlhbGl6ZWQgYmxvYiBpcyBhbHNvIG1vcmUgcHJpdmlsZWdlZCB0aGFuIHRoZSBsaXN0aW5nIHN1cmZhY2U6IHRoZVxuICogd29ya3NwYWNlIEFQSSByZXF1aXJlcyBgQ2FuIEVkaXRgIG9uIHRoZSBzcGFjZSB0byByZXR1cm4gaXQsIHdoaWxlIGBDYW4gUnVuYFxuICogaXMgZW5vdWdoIGZvciB0aXRsZSAvIGRlc2NyaXB0aW9uLiBBIGNhbGxlciB0aGF0IG9ubHkgaG9sZHMgYENhbiBSdW5gIC0gYW5cbiAqIGFwcCBzZXJ2aWNlIHByaW5jaXBhbCBncmFudGVkIGp1c3QgZW5vdWdoIHRvIGFzayBxdWVzdGlvbnMgaXMgdGhlIGNvbW1vbiBjYXNlXG4gKiAtIHdvdWxkIG90aGVyd2lzZSBsb3NlIHRoZSB3aG9sZSBzcGFjZSBsb29rdXAgdG8gYSBgUEVSTUlTU0lPTl9ERU5JRURgIGl0XG4gKiBjYW5ub3QgYWN0IG9uLCBzbyB0aGUgZmV0Y2ggZGVncmFkZXMgdG8gdGhlIHVuc2VyaWFsaXplZCByZXF1ZXN0IGluc3RlYWQgb2ZcbiAqIGZhaWxpbmcgKHNlZSB7QGxpbmsgZ2V0R2VuaWVTcGFjZX0pLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBXb3Jrc3BhY2VDbGllbnQgfSBmcm9tIFwiQGRhdGFicmlja3Mvc2RrLWV4cGVyaW1lbnRhbFwiO1xuaW1wb3J0IHsgZGF0YWJyaWNrcyB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdFwiO1xuaW1wb3J0IHsgZXJyb3IsIGpzb24sIGxvZywgb2JqZWN0LCBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgZ2VuaWVNb2RlbCwgdHlwZSBHZW5pZVNwYWNlIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWdlbmllXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJnZW5pZS9zcGFjZVwiKTtcblxuLyoqIE9wdGlvbnMgZm9yIHtAbGluayBnZXRHZW5pZVNwYWNlfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2V0R2VuaWVTcGFjZU9wdGlvbnMge1xuICAvKipcbiAgICogRXhwbGljaXQgYFdvcmtzcGFjZUNsaWVudGAuIERlZmF1bHRzIHRvIGEgZnJlc2ggYG5ldyBXb3Jrc3BhY2VDbGllbnQoe30pYFxuICAgKiAoZW52LXZhciBhdXRoKS4gU2VydmVyIGNhbGxlcnMgc2hvdWxkIHBhc3MgdGhlaXIgT0JPLXNjb3BlZCBjbGllbnQgc28gdGhlXG4gICAqIGxvb2t1cCBydW5zIGFzIHRoZSB1c2VyLlxuICAgKi9cbiAgd29ya3NwYWNlQ2xpZW50PzogV29ya3NwYWNlQ2xpZW50O1xuICAvKipcbiAgICogUmVxdWVzdCB0aGUgYHNlcmlhbGl6ZWRfc3BhY2VgIGJsb2IgKGNhdGFsb2dzLCB0YWJsZXMsIHNhbXBsZSBxdWVzdGlvbnMsXG4gICAqIHByb21wdHMpLiBEZWZhdWx0cyB0byBgdHJ1ZWAgLSB0aGUgb25seSByZWFzb24gdG8gc2tpcCBpdCBpcyB3aGVuIHRoZVxuICAgKiBjYWxsZXIganVzdCBuZWVkcyB0aXRsZSAvIGRlc2NyaXB0aW9uIGFuZCB3YW50cyB0aGUgc21hbGxlciBwYXlsb2FkLlxuICAgKlxuICAgKiBSZXF1ZXN0aW5nIGl0IGlzIGJlc3QtZWZmb3J0OiB0aGUgYmxvYiBuZWVkcyBgQ2FuIEVkaXRgIG9uIHRoZSBzcGFjZSwgc28gYVxuICAgKiBjYWxsZXIgd2l0aG91dCBpdCBnZXRzIHRoZSB1bnNlcmlhbGl6ZWQgc3BhY2UgYmFjayByYXRoZXIgdGhhbiBhbiBlcnJvcixcbiAgICogYW5kIHtAbGluayBnZW5pZVNhbXBsZVF1ZXN0aW9uc30gdGhlbiByZXBvcnRzIG5vIHN1Z2dlc3Rpb25zLlxuICAgKi9cbiAgc2VyaWFsaXplZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBFeHRlcm5hbCBjYW5jZWxsYXRpb24uIEFjY2VwdHMgYSBXSEFUV0cgYEFib3J0U2lnbmFsYCBvciBhIGZ1bGx5LWJ1aWx0IFNES1xuICAgKiBgQ29udGV4dGAgKHNlZSBgZGF0YWJyaWNrcy5Db250ZXh0TGlrZWApLlxuICAgKi9cbiAgY29udGV4dD86IGRhdGFicmlja3MuQ29udGV4dExpa2U7XG59XG5cbi8qKlxuICogRmV0Y2ggYSBHZW5pZSBzcGFjZSBieSBpZCwgb3B0aW9uYWxseSBpbmNsdWRpbmcgaXRzIHNlcmlhbGl6ZWQgZGVmaW5pdGlvbi5cbiAqIEhpdHMgYEdFVCAvYXBpLzIuMC9nZW5pZS9zcGFjZXMvPGlkPmAgd2l0aCBgaW5jbHVkZV9zZXJpYWxpemVkX3NwYWNlPXRydWVgXG4gKiB0aHJvdWdoIHRoZSByYXcgYGFwaUNsaWVudGAsIHRoZW4gdmFsaWRhdGVzIHRoZSByZXNwb25zZSBhZ2FpbnN0XG4gKiB7QGxpbmsgR2VuaWVTcGFjZVNjaGVtYX0gKHVua25vd24gZmllbGRzIGxpa2UgYGV0YWdgIC9cbiAqIGBwYXJlbnRfcGF0aGAgYXJlIHN0cmlwcGVkKS5cbiAqXG4gKiBXaGVuIHRoZSBzZXJpYWxpemVkIHJlcXVlc3QgaXMgcmVqZWN0ZWQgZm9yIGxhY2sgb2YgcGVybWlzc2lvbiAoYDQwM2AsIG9yIGFcbiAqIGBQRVJNSVNTSU9OX0RFTklFRGAgLyBgQ2FuIEVkaXRgIG1lc3NhZ2UgLSB0aGUgd29ya3NwYWNlIEFQSSBnYXRlcyB0aGUgYmxvYlxuICogYmVoaW5kIGBDYW4gRWRpdGApLCBpdCByZXRyaWVzIG9uY2Ugd2l0aG91dCB0aGUgZmxhZyBzbyB0aGUgY2FsbGVyIHN0aWxsIGdldHNcbiAqIHRoZSBzcGFjZS4gQW55IG90aGVyIGZhaWx1cmUsIGFuZCBhIHJldHJ5IHRoYXQgZmFpbHMgdG9vLCBpcyByZXRocm93bjogYVxuICogY2FuY2VsbGVkIHJlcXVlc3Qgb3IgYSBtaXNzaW5nIHNwYWNlIG11c3Qgbm90IGxvb2sgbGlrZSBhbiB1bnNlcmlhbGl6ZWRcbiAqIHNwYWNlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0R2VuaWVTcGFjZShcbiAgc3BhY2VJZDogc3RyaW5nLFxuICBvcHRpb25zPzogR2V0R2VuaWVTcGFjZU9wdGlvbnMsXG4pOiBQcm9taXNlPEdlbmllU3BhY2U+IHtcbiAgY29uc3QgY2xpZW50ID0gb3B0aW9ucz8ud29ya3NwYWNlQ2xpZW50ID8/IG5ldyBXb3Jrc3BhY2VDbGllbnQoe30pO1xuICBjb25zdCBzZXJpYWxpemVkID0gb3B0aW9ucz8uc2VyaWFsaXplZCAhPT0gZmFsc2U7XG4gIGNvbnN0IGN0eCA9IG9wdGlvbnM/LmNvbnRleHQgPyBkYXRhYnJpY2tzLnRvQ29udGV4dChvcHRpb25zLmNvbnRleHQpIDogdW5kZWZpbmVkO1xuICBjb25zdCByZXF1ZXN0ID0gKGluY2x1ZGVTZXJpYWxpemVkOiBib29sZWFuKTogUHJvbWlzZTx1bmtub3duPiA9PlxuICAgIGNsaWVudC5hcGlDbGllbnQucmVxdWVzdChcbiAgICAgIHtcbiAgICAgICAgcGF0aDogYC9hcGkvMi4wL2dlbmllL3NwYWNlcy8ke2VuY29kZVVSSUNvbXBvbmVudChzcGFjZUlkKX1gLFxuICAgICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICAgIHF1ZXJ5OiBpbmNsdWRlU2VyaWFsaXplZCA/IHsgaW5jbHVkZV9zZXJpYWxpemVkX3NwYWNlOiB0cnVlIH0gOiB7fSxcbiAgICAgICAgaGVhZGVyczogbmV3IEhlYWRlcnMoKSxcbiAgICAgICAgcmF3OiBmYWxzZSxcbiAgICAgIH0sXG4gICAgICBjdHgsXG4gICAgKTtcblxuICBsZXQgcmF3OiB1bmtub3duO1xuICB0cnkge1xuICAgIHJhdyA9IGF3YWl0IHJlcXVlc3Qoc2VyaWFsaXplZCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmICghc2VyaWFsaXplZCB8fCAhaXNTZXJpYWxpemVkU3BhY2VGb3JiaWRkZW4oZXJyKSkgdGhyb3cgZXJyO1xuICAgIGxvZ2dlci5kZWJ1ZyhcInNlcmlhbGl6ZWQtc3BhY2U6Zm9yYmlkZGVuXCIsIHtcbiAgICAgIHNwYWNlSWQsXG4gICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgcmF3ID0gYXdhaXQgcmVxdWVzdChmYWxzZSk7XG4gIH1cbiAgcmV0dXJuIGdlbmllTW9kZWwuR2VuaWVTcGFjZVNjaGVtYS5wYXJzZShyYXcpO1xufVxuXG4vKipcbiAqIFRydWUgd2hlbiBhIGZhaWxlZCBzcGFjZSByZXF1ZXN0IHdhcyByZWplY3RlZCBmb3IgbGFjayBvZiBwZXJtaXNzaW9uLCB0aGUgb25lXG4gKiBmYWlsdXJlIHRoZSB1bnNlcmlhbGl6ZWQgcmV0cnkgY2FuIHJlY292ZXIgZnJvbS4gTWF0Y2hlcyBvbiBgNDAzYCBhbmQgb24gdGhlXG4gKiBgUEVSTUlTU0lPTl9ERU5JRURgIC8gYENhbiBFZGl0YCB3b3JkaW5nIHRoZSB3b3Jrc3BhY2UgQVBJIHJldHVybnMsIHNpbmNlIHRoZVxuICogU0RLIHN1cmZhY2VzIHRoZSBlcnJvciBjb2RlIHdpdGhvdXQgYWx3YXlzIGNhcnJ5aW5nIGEgc3RhdHVzLlxuICovXG5mdW5jdGlvbiBpc1NlcmlhbGl6ZWRTcGFjZUZvcmJpZGRlbihlcnI6IHVua25vd24pOiBib29sZWFuIHtcbiAgY29uc3QgY29udGV4dCA9IGVycm9yLmVycm9yQ29udGV4dChlcnIpO1xuICByZXR1cm4gKFxuICAgIGNvbnRleHQuaGFzU3RhdHVzQ29kZSg0MDMpIHx8XG4gICAgY29udGV4dC5oYXNNZXNzYWdlKFwicGVybWlzc2lvbiBkZW5pZWRcIikgfHxcbiAgICBjb250ZXh0Lmhhc01lc3NhZ2UoXCJjYW4gZWRpdFwiKVxuICApO1xufVxuXG4vKipcbiAqIE9uZSBlbnRyeSBpbiBhIHNlcmlhbGl6ZWQgc3BhY2UncyBgY29uZmlnLnNhbXBsZV9xdWVzdGlvbnNgLiBUaGVcbiAqIGF1dGhvci1mYWNpbmcgZmllbGQgaXMgYHF1ZXN0aW9uYCwgd2hpY2ggdGhlIHdpcmUgZm9ybWF0IG1vZGVscyBhcyBhIHN0cmluZ1xuICogYXJyYXkgKGEgc2luZ2xlIG11bHRpLWxpbmUgcXVlc3Rpb24gaXMgc3BsaXQgYWNyb3NzIGVudHJpZXMpOyB3ZSB0cmVhdCB0aGVcbiAqIGZpcnN0IG5vbi1lbXB0eSBlbnRyeSBhcyB0aGUgZGlzcGxheWFibGUgcXVlc3Rpb24gdGV4dC5cbiAqL1xuaW50ZXJmYWNlIFNlcmlhbGl6ZWRTYW1wbGVRdWVzdGlvbiB7XG4gIHF1ZXN0aW9uPzogdW5rbm93bjtcbn1cblxuLyoqXG4gKiBFeHRyYWN0IHRoZSBjdXJhdGVkIHN0YXJ0ZXIgcXVlc3Rpb25zIGFuIGF1dGhvciBjb25maWd1cmVkIG9uIGEgR2VuaWUgc3BhY2UuXG4gKiBSZWFkcyBgc2VyaWFsaXplZF9zcGFjZSAtPiBjb25maWcuc2FtcGxlX3F1ZXN0aW9uc1sqXS5xdWVzdGlvbmAuIFJldHVybnMgYFtdYFxuICogd2hlbiB0aGUgc3BhY2UgY2FycmllcyBubyBzZXJpYWxpemVkIGJsb2IsIHRoZSBibG9iIGlzIHVucGFyc2VhYmxlLCBvciBub1xuICogc2FtcGxlIHF1ZXN0aW9ucyBhcmUgY29uZmlndXJlZCAtIHNvIGEgbWlzc2luZyBvciBtaXNjb25maWd1cmVkIHNwYWNlXG4gKiBkZWdyYWRlcyB0byBcIm5vIHN1Z2dlc3Rpb25zXCIgcmF0aGVyIHRoYW4gdGhyb3dpbmcuIE9yZGVyIGlzIHByZXNlcnZlZCAodGhlXG4gKiBhdXRob3IncyBvcmRlcmluZykgYW5kIGR1cGxpY2F0ZXMgYXJlIGRyb3BwZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5pZVNhbXBsZVF1ZXN0aW9ucyhzcGFjZTogR2VuaWVTcGFjZSk6IHN0cmluZ1tdIHtcbiAgY29uc3Qgc2VyaWFsaXplZCA9IHNwYWNlLnNlcmlhbGl6ZWRfc3BhY2U7XG4gIGlmICghc2VyaWFsaXplZCkgcmV0dXJuIFtdO1xuICBjb25zdCBwYXJzZWQgPSBqc29uLnBhcnNlKHNlcmlhbGl6ZWQpO1xuICBpZiAocGFyc2VkID09PSB1bmRlZmluZWQpIHtcbiAgICBsb2dnZXIud2FybihcInNlcmlhbGl6ZWQtc3BhY2U6cGFyc2UtZXJyb3JcIiwgeyBzcGFjZUlkOiBzcGFjZS5zcGFjZV9pZCB9KTtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgY29uc3Qgc2FtcGxlUXVlc3Rpb25zID0gKHBhcnNlZCBhcyB7IGNvbmZpZz86IHsgc2FtcGxlX3F1ZXN0aW9ucz86IHVua25vd24gfSB9IHwgbnVsbCk/LmNvbmZpZ1xuICAgID8uc2FtcGxlX3F1ZXN0aW9ucztcbiAgaWYgKCFBcnJheS5pc0FycmF5KHNhbXBsZVF1ZXN0aW9ucykpIHJldHVybiBbXTtcblxuICByZXR1cm4gW1xuICAgIC4uLm9iamVjdFxuICAgICAgLnNlcXVlbmNlKHNhbXBsZVF1ZXN0aW9ucyBhcyBTZXJpYWxpemVkU2FtcGxlUXVlc3Rpb25bXSlcbiAgICAgIC5tYXAoKGVudHJ5KSA9PiBzdHJpbmcuZmlyc3ROb25FbXB0eShlbnRyeT8ucXVlc3Rpb24pKVxuICAgICAgLm5vbk51bGwoKVxuICAgICAgLmRpc3RpbmN0KCksXG4gIF07XG59XG4iXX0=
|
package/package.json
CHANGED
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
31
|
-
"@dbx-tools/appkit": "0.6.
|
|
32
|
-
"@dbx-tools/shared-core": "0.6.
|
|
33
|
-
"@dbx-tools/shared-genie": "0.6.
|
|
31
|
+
"@dbx-tools/appkit": "0.6.63",
|
|
32
|
+
"@dbx-tools/shared-core": "0.6.63",
|
|
33
|
+
"@dbx-tools/shared-genie": "0.6.63"
|
|
34
34
|
},
|
|
35
35
|
"main": "./lib/index.js",
|
|
36
36
|
"license": "UNLICENSED",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"./package.json": "./package.json"
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
|
-
"version": "0.6.
|
|
49
|
+
"version": "0.6.63",
|
|
50
50
|
"types": "./lib/index.d.ts",
|
|
51
51
|
"type": "module",
|
|
52
52
|
"exports": {
|
package/src/space.ts
CHANGED
|
@@ -10,12 +10,20 @@
|
|
|
10
10
|
* workspace client's raw `apiClient` since the typed request shape has no flag
|
|
11
11
|
* for it.
|
|
12
12
|
*
|
|
13
|
+
* The serialized blob is also more privileged than the listing surface: the
|
|
14
|
+
* workspace API requires `Can Edit` on the space to return it, while `Can Run`
|
|
15
|
+
* is enough for title / description. A caller that only holds `Can Run` - an
|
|
16
|
+
* app service principal granted just enough to ask questions is the common case
|
|
17
|
+
* - would otherwise lose the whole space lookup to a `PERMISSION_DENIED` it
|
|
18
|
+
* cannot act on, so the fetch degrades to the unserialized request instead of
|
|
19
|
+
* failing (see {@link getGenieSpace}).
|
|
20
|
+
*
|
|
13
21
|
* @module
|
|
14
22
|
*/
|
|
15
23
|
|
|
16
24
|
import { WorkspaceClient } from "@databricks/sdk-experimental";
|
|
17
25
|
import { databricks } from "@dbx-tools/appkit";
|
|
18
|
-
import { json, log, object, string } from "@dbx-tools/shared-core";
|
|
26
|
+
import { error, json, log, object, string } from "@dbx-tools/shared-core";
|
|
19
27
|
import { genieModel, type GenieSpace } from "@dbx-tools/shared-genie";
|
|
20
28
|
|
|
21
29
|
const logger = log.logger("genie/space");
|
|
@@ -32,6 +40,10 @@ export interface GetGenieSpaceOptions {
|
|
|
32
40
|
* Request the `serialized_space` blob (catalogs, tables, sample questions,
|
|
33
41
|
* prompts). Defaults to `true` - the only reason to skip it is when the
|
|
34
42
|
* caller just needs title / description and wants the smaller payload.
|
|
43
|
+
*
|
|
44
|
+
* Requesting it is best-effort: the blob needs `Can Edit` on the space, so a
|
|
45
|
+
* caller without it gets the unserialized space back rather than an error,
|
|
46
|
+
* and {@link genieSampleQuestions} then reports no suggestions.
|
|
35
47
|
*/
|
|
36
48
|
serialized?: boolean;
|
|
37
49
|
/**
|
|
@@ -47,6 +59,13 @@ export interface GetGenieSpaceOptions {
|
|
|
47
59
|
* through the raw `apiClient`, then validates the response against
|
|
48
60
|
* {@link GenieSpaceSchema} (unknown fields like `etag` /
|
|
49
61
|
* `parent_path` are stripped).
|
|
62
|
+
*
|
|
63
|
+
* When the serialized request is rejected for lack of permission (`403`, or a
|
|
64
|
+
* `PERMISSION_DENIED` / `Can Edit` message - the workspace API gates the blob
|
|
65
|
+
* behind `Can Edit`), it retries once without the flag so the caller still gets
|
|
66
|
+
* the space. Any other failure, and a retry that fails too, is rethrown: a
|
|
67
|
+
* cancelled request or a missing space must not look like an unserialized
|
|
68
|
+
* space.
|
|
50
69
|
*/
|
|
51
70
|
export async function getGenieSpace(
|
|
52
71
|
spaceId: string,
|
|
@@ -55,19 +74,47 @@ export async function getGenieSpace(
|
|
|
55
74
|
const client = options?.workspaceClient ?? new WorkspaceClient({});
|
|
56
75
|
const serialized = options?.serialized !== false;
|
|
57
76
|
const ctx = options?.context ? databricks.toContext(options.context) : undefined;
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
const request = (includeSerialized: boolean): Promise<unknown> =>
|
|
78
|
+
client.apiClient.request(
|
|
79
|
+
{
|
|
80
|
+
path: `/api/2.0/genie/spaces/${encodeURIComponent(spaceId)}`,
|
|
81
|
+
method: "GET",
|
|
82
|
+
query: includeSerialized ? { include_serialized_space: true } : {},
|
|
83
|
+
headers: new Headers(),
|
|
84
|
+
raw: false,
|
|
85
|
+
},
|
|
86
|
+
ctx,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
let raw: unknown;
|
|
90
|
+
try {
|
|
91
|
+
raw = await request(serialized);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
if (!serialized || !isSerializedSpaceForbidden(err)) throw err;
|
|
94
|
+
logger.debug("serialized-space:forbidden", {
|
|
95
|
+
spaceId,
|
|
96
|
+
error: error.errorMessage(err),
|
|
97
|
+
});
|
|
98
|
+
raw = await request(false);
|
|
99
|
+
}
|
|
68
100
|
return genieModel.GenieSpaceSchema.parse(raw);
|
|
69
101
|
}
|
|
70
102
|
|
|
103
|
+
/**
|
|
104
|
+
* True when a failed space request was rejected for lack of permission, the one
|
|
105
|
+
* failure the unserialized retry can recover from. Matches on `403` and on the
|
|
106
|
+
* `PERMISSION_DENIED` / `Can Edit` wording the workspace API returns, since the
|
|
107
|
+
* SDK surfaces the error code without always carrying a status.
|
|
108
|
+
*/
|
|
109
|
+
function isSerializedSpaceForbidden(err: unknown): boolean {
|
|
110
|
+
const context = error.errorContext(err);
|
|
111
|
+
return (
|
|
112
|
+
context.hasStatusCode(403) ||
|
|
113
|
+
context.hasMessage("permission denied") ||
|
|
114
|
+
context.hasMessage("can edit")
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
71
118
|
/**
|
|
72
119
|
* One entry in a serialized space's `config.sample_questions`. The
|
|
73
120
|
* author-facing field is `question`, which the wire format models as a string
|