@dbx-tools/search 0.6.9

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.
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Configuration for the AI Search plugin: the typed
3
+ * {@link SearchPluginConfig} (the plugin's slice of AppKit config), the JSON
4
+ * Schema the manifest publishes for it, and {@link resolveSearchConfig}
5
+ * which layers that config over environment defaults into the concrete
6
+ * {@link ResolvedSearchConfig} the runtime, client, tools, and routes read.
7
+ *
8
+ * The design goal is "one index, zero config": name a default index (or set
9
+ * `DATABRICKS_VECTOR_SEARCH_INDEX`) and everything else - the columns to
10
+ * return, the page size, the match mode, the mounted route path, the embedding
11
+ * model used when creating an index - has a sensible default that can be
12
+ * overridden when a deployment needs to go deeper.
13
+ *
14
+ * Which index / endpoint is used follows the standard precedence: explicit
15
+ * plugin config, then environment, then a default.
16
+ *
17
+ * Env fallbacks: `DATABRICKS_VECTOR_SEARCH_INDEX` (the default index),
18
+ * `SEARCH_INDEX`, `SEARCH_ENDPOINT`, `SEARCH_COLUMNS`,
19
+ * `SEARCH_PAGE_SIZE`, `SEARCH_MODE`, `SEARCH_EMBEDDING_MODEL`,
20
+ * `SEARCH_TIMEOUT_MS`, `SEARCH_WRITE`.
21
+ *
22
+ * @module
23
+ */
24
+ import { type BasePluginConfig } from "@databricks/appkit";
25
+ import type { SearchDocument, SearchMode } from "@dbx-tools/shared-search";
26
+ import type { JSONSchema7 } from "json-schema";
27
+ /** The default index, honoring AppKit's standard Vector Search binding name. */
28
+ export declare const INDEX_ENV = "SEARCH_INDEX";
29
+ /** AppKit's standard environment name for a Vector Search index binding. */
30
+ export declare const DATABRICKS_INDEX_ENV = "DATABRICKS_VECTOR_SEARCH_INDEX";
31
+ /** Dedicated override for the Vector Search serving endpoint that hosts indexes. */
32
+ export declare const ENDPOINT_ENV = "SEARCH_ENDPOINT";
33
+ /** Default match mode when a request does not name one. Hybrid suits most search boxes. */
34
+ export declare const DEFAULT_MODE: SearchMode;
35
+ /** Default number of hits a search returns (a good autocomplete / results-list size). */
36
+ export declare const DEFAULT_PAGE_SIZE = 10;
37
+ /** Default per-call timeout for a search / index operation. */
38
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
39
+ /** Base path the plugin mounts its routes under, unless overridden. */
40
+ export declare const DEFAULT_BASE_PATH = "/api/search";
41
+ /**
42
+ * A configured index the plugin knows about ahead of time. Only `name` (or
43
+ * `alias`) is required; the rest is resolved from the live index definition
44
+ * when omitted, so a deployment can register `{ name }` and let the plugin fill
45
+ * in the primary key and columns.
46
+ */
47
+ export interface SearchIndexConfig {
48
+ /** Unity Catalog name of the index (catalog.schema.index). */
49
+ name: string;
50
+ /** Short alias a caller may use in place of `name` (defaults to the last name segment). */
51
+ alias?: string;
52
+ /** Primary-key column. Resolved from the index definition when omitted. */
53
+ primaryKey?: string;
54
+ /** Columns to return per hit, in display order. Defaults to every indexed column. */
55
+ columns?: string[];
56
+ }
57
+ /**
58
+ * The AI Search plugin's slice of AppKit config. Every field is optional - the
59
+ * plugin works with nothing but an index name in the environment.
60
+ */
61
+ export interface SearchPluginConfig extends BasePluginConfig {
62
+ /** The default index searched when a request omits one (name or alias). */
63
+ index?: string;
64
+ /** Indexes the plugin should know about (for aliases, universal search, and the UI catalogue). */
65
+ indexes?: Array<string | SearchIndexConfig>;
66
+ /** The Vector Search serving endpoint indexes live on (only needed to create an index). */
67
+ endpoint?: string;
68
+ /** Default columns to return per hit. Falls back to each index's own columns. */
69
+ columns?: string[];
70
+ /** Default number of hits a search returns. */
71
+ pageSize?: number;
72
+ /** Default match mode. */
73
+ mode?: SearchMode;
74
+ /** Embedding model endpoint used when the plugin CREATES a Delta Sync index. Fuzzy-resolved. */
75
+ embeddingModel?: string;
76
+ /** Per-call timeout in milliseconds. */
77
+ timeoutMs?: number;
78
+ /** Enable the write surface (`add_documents` tool + `POST /documents`). Off by default. */
79
+ allowWrite?: boolean;
80
+ /**
81
+ * Provision a REAL index at boot: ensure the endpoint + index exist and seed
82
+ * documents when the index is empty. Runs in the background during `setup()`
83
+ * (a slow first-time endpoint/index build never blocks the server) using the
84
+ * boot-time SDK auth (env / config profile). Idempotent - safe every boot.
85
+ *
86
+ * The default is a MANAGED direct-access index (Databricks embeds the text
87
+ * column), so `documents` are plain rows and search-by-text works with no
88
+ * Delta table, no warehouse, and no vectors to compute. Point it at a
89
+ * `sourceTable` to provision a Delta Sync index instead.
90
+ */
91
+ ensureOnSetup?: EnsureOnSetupConfig;
92
+ }
93
+ /** Boot-time provisioning + seeding for a single index (see `ensureOnSetup`). */
94
+ export interface EnsureOnSetupConfig {
95
+ /** UC name of the index to ensure (catalog.schema.index). Defaults to the plugin's `index`. */
96
+ index?: string;
97
+ /** Vector Search endpoint to host it on. Defaults to the plugin's `endpoint`. */
98
+ endpoint?: string;
99
+ /** Primary-key column. Defaults to `id`. */
100
+ primaryKey?: string;
101
+ /** Text column Databricks embeds (managed direct-access). Defaults to `text`. */
102
+ textColumn?: string;
103
+ /** Embedding model endpoint. Fuzzy-matched; defaults to the best embedding endpoint. */
104
+ embeddingModel?: string;
105
+ /** For a Delta Sync index instead of managed direct-access: the source Delta table. */
106
+ sourceTable?: string;
107
+ /** Column -> type map for the managed direct-access `schema_json`. Inferred from `documents` when omitted. */
108
+ schema?: Record<string, string>;
109
+ /** Documents to seed when the index is empty. Plain `{ id, text, ... }` rows for a managed index. */
110
+ documents?: SearchDocument[];
111
+ /** Max time to wait for endpoint + index readiness. Defaults to 20 minutes. */
112
+ timeoutMs?: number;
113
+ }
114
+ /** A fully resolved index entry (the plugin-known form). */
115
+ export interface ResolvedIndexConfig {
116
+ name: string;
117
+ alias: string;
118
+ primaryKey?: string;
119
+ columns?: string[];
120
+ }
121
+ /** The concrete config the runtime, client, tools, and routes read. */
122
+ export interface ResolvedSearchConfig {
123
+ defaultIndex?: string;
124
+ indexes: ResolvedIndexConfig[];
125
+ endpoint?: string;
126
+ columns?: string[];
127
+ pageSize: number;
128
+ mode: SearchMode;
129
+ embeddingModel?: string;
130
+ basePath: string;
131
+ timeoutMs: number;
132
+ allowWrite: boolean;
133
+ ensureOnSetup?: EnsureOnSetupConfig;
134
+ }
135
+ /** JSON Schema the plugin manifest publishes for {@link SearchPluginConfig}. */
136
+ export declare const SEARCH_CONFIG_SCHEMA: JSONSchema7;
137
+ /** Derive the default alias for an index name (its last dotted segment). */
138
+ export declare function defaultAlias(name: string): string;
139
+ /**
140
+ * Resolve plugin config over environment defaults into the concrete
141
+ * {@link ResolvedSearchConfig}. The default index is unioned into the known
142
+ * indexes so it always appears in the catalogue, aliases are de-duplicated,
143
+ * and a bad mode throws a {@link ConfigurationError} naming the field.
144
+ */
145
+ export declare function resolveSearchConfig(config?: SearchPluginConfig): ResolvedSearchConfig;
146
+ /**
147
+ * Resolve a caller-supplied index reference (a full UC name or a configured
148
+ * alias) into a concrete index name. Falls back to the default index when the
149
+ * reference is empty. Returns `null` when nothing can be resolved so callers
150
+ * raise a stable, user-facing error rather than calling a phantom index.
151
+ */
152
+ export declare function resolveIndexName(config: ResolvedSearchConfig, reference: string | undefined): string | null;
153
+ /** The known config for an index name, when the plugin was told about it. */
154
+ export declare function indexConfigFor(config: ResolvedSearchConfig, name: string): ResolvedIndexConfig | undefined;
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Configuration for the AI Search plugin: the typed
3
+ * {@link SearchPluginConfig} (the plugin's slice of AppKit config), the JSON
4
+ * Schema the manifest publishes for it, and {@link resolveSearchConfig}
5
+ * which layers that config over environment defaults into the concrete
6
+ * {@link ResolvedSearchConfig} the runtime, client, tools, and routes read.
7
+ *
8
+ * The design goal is "one index, zero config": name a default index (or set
9
+ * `DATABRICKS_VECTOR_SEARCH_INDEX`) and everything else - the columns to
10
+ * return, the page size, the match mode, the mounted route path, the embedding
11
+ * model used when creating an index - has a sensible default that can be
12
+ * overridden when a deployment needs to go deeper.
13
+ *
14
+ * Which index / endpoint is used follows the standard precedence: explicit
15
+ * plugin config, then environment, then a default.
16
+ *
17
+ * Env fallbacks: `DATABRICKS_VECTOR_SEARCH_INDEX` (the default index),
18
+ * `SEARCH_INDEX`, `SEARCH_ENDPOINT`, `SEARCH_COLUMNS`,
19
+ * `SEARCH_PAGE_SIZE`, `SEARCH_MODE`, `SEARCH_EMBEDDING_MODEL`,
20
+ * `SEARCH_TIMEOUT_MS`, `SEARCH_WRITE`.
21
+ *
22
+ * @module
23
+ */
24
+ import { ConfigurationError } from "@databricks/appkit";
25
+ import { object, string } from "@dbx-tools/shared-core";
26
+ /** The default index, honoring AppKit's standard Vector Search binding name. */
27
+ export const INDEX_ENV = "SEARCH_INDEX";
28
+ /** AppKit's standard environment name for a Vector Search index binding. */
29
+ export const DATABRICKS_INDEX_ENV = "DATABRICKS_VECTOR_SEARCH_INDEX";
30
+ /** Dedicated override for the Vector Search serving endpoint that hosts indexes. */
31
+ export const ENDPOINT_ENV = "SEARCH_ENDPOINT";
32
+ /** Default match mode when a request does not name one. Hybrid suits most search boxes. */
33
+ export const DEFAULT_MODE = "hybrid";
34
+ /** Default number of hits a search returns (a good autocomplete / results-list size). */
35
+ export const DEFAULT_PAGE_SIZE = 10;
36
+ /** Default per-call timeout for a search / index operation. */
37
+ export const DEFAULT_TIMEOUT_MS = 30_000;
38
+ /** Base path the plugin mounts its routes under, unless overridden. */
39
+ export const DEFAULT_BASE_PATH = "/api/search";
40
+ /** JSON Schema the plugin manifest publishes for {@link SearchPluginConfig}. */
41
+ export const SEARCH_CONFIG_SCHEMA = {
42
+ type: "object",
43
+ additionalProperties: true,
44
+ properties: {
45
+ index: {
46
+ type: "string",
47
+ description: "Default index to search (catalog.schema.index or a configured alias).",
48
+ },
49
+ indexes: {
50
+ type: "array",
51
+ description: "Indexes the plugin knows about, for aliases, universal search, and the UI.",
52
+ items: {
53
+ oneOf: [
54
+ { type: "string" },
55
+ {
56
+ type: "object",
57
+ required: ["name"],
58
+ properties: {
59
+ name: { type: "string" },
60
+ alias: { type: "string" },
61
+ primaryKey: { type: "string" },
62
+ columns: { type: "array", items: { type: "string" } },
63
+ },
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ endpoint: {
69
+ type: "string",
70
+ description: "Vector Search serving endpoint indexes live on (needed only to create one).",
71
+ },
72
+ columns: {
73
+ type: "array",
74
+ items: { type: "string" },
75
+ description: "Default columns to return.",
76
+ },
77
+ pageSize: { type: "number", description: "Default number of hits per search." },
78
+ mode: { enum: ["hybrid", "vector", "keyword"], description: "Default match mode." },
79
+ embeddingModel: {
80
+ type: "string",
81
+ description: "Embedding endpoint used when creating a Delta Sync index (fuzzy-matched).",
82
+ },
83
+ timeoutMs: { type: "number", description: "Per-call timeout in milliseconds." },
84
+ allowWrite: {
85
+ type: "boolean",
86
+ description: "Enable the document write surface (add_documents tool + route).",
87
+ },
88
+ ensureOnSetup: {
89
+ type: "object",
90
+ description: "Provision a real index at boot: ensure the endpoint + index exist and seed " +
91
+ "documents when empty. Runs in the background during setup using boot-time auth.",
92
+ additionalProperties: true,
93
+ properties: {
94
+ index: { type: "string" },
95
+ endpoint: { type: "string" },
96
+ primaryKey: { type: "string" },
97
+ textColumn: { type: "string" },
98
+ embeddingModel: { type: "string" },
99
+ sourceTable: { type: "string" },
100
+ schema: { type: "object", additionalProperties: { type: "string" } },
101
+ documents: { type: "array", items: { type: "object", additionalProperties: true } },
102
+ timeoutMs: { type: "number" },
103
+ },
104
+ },
105
+ },
106
+ };
107
+ /** Derive the default alias for an index name (its last dotted segment). */
108
+ export function defaultAlias(name) {
109
+ const segments = name.split(".").filter(Boolean);
110
+ return segments.length > 0 ? segments[segments.length - 1] : name;
111
+ }
112
+ /** Normalize a config index entry (string or object) into a {@link ResolvedIndexConfig}. */
113
+ function toResolvedIndex(entry) {
114
+ const raw = typeof entry === "string" ? { name: entry } : entry;
115
+ const name = string.trimToNull(raw.name);
116
+ if (name === null)
117
+ return null;
118
+ return {
119
+ name,
120
+ alias: string.trimToNull(raw.alias) ?? defaultAlias(name),
121
+ ...(raw.primaryKey ? { primaryKey: raw.primaryKey } : {}),
122
+ ...(raw.columns && raw.columns.length > 0 ? { columns: [...raw.columns] } : {}),
123
+ };
124
+ }
125
+ /** Coerce a positive integer from config or an env var, falling back to a default. */
126
+ function resolvePositiveInt(configured, envVar, fallback) {
127
+ const raw = configured ?? Number(process.env[envVar]);
128
+ const value = Number(raw);
129
+ if (Number.isFinite(value) && value > 0)
130
+ return Math.floor(value);
131
+ return fallback;
132
+ }
133
+ /** Parse and validate a {@link SearchMode} from config or an env var. */
134
+ function resolveMode(configured) {
135
+ const raw = configured ?? string.trimToNull(process.env.SEARCH_MODE) ?? undefined;
136
+ if (raw === undefined)
137
+ return DEFAULT_MODE;
138
+ if (raw !== "hybrid" && raw !== "vector" && raw !== "keyword") {
139
+ throw new ConfigurationError('mode must be "hybrid", "vector" or "keyword" (env: SEARCH_MODE)', { context: { field: "mode", envVar: "SEARCH_MODE" } });
140
+ }
141
+ return raw;
142
+ }
143
+ /**
144
+ * Resolve plugin config over environment defaults into the concrete
145
+ * {@link ResolvedSearchConfig}. The default index is unioned into the known
146
+ * indexes so it always appears in the catalogue, aliases are de-duplicated,
147
+ * and a bad mode throws a {@link ConfigurationError} naming the field.
148
+ */
149
+ export function resolveSearchConfig(config = {}) {
150
+ const defaultIndexRaw = string.trimToNull(config.index) ??
151
+ string.trimToNull(process.env[INDEX_ENV]) ??
152
+ string.trimToNull(process.env[DATABRICKS_INDEX_ENV]) ??
153
+ undefined;
154
+ const configured = (config.indexes ?? [])
155
+ .map(toResolvedIndex)
156
+ .filter((entry) => entry !== null);
157
+ // Ensure the default index is represented in the known set.
158
+ if (defaultIndexRaw && !configured.some((i) => i.name === defaultIndexRaw)) {
159
+ const fromEnv = string.parseList(process.env.SEARCH_COLUMNS);
160
+ configured.unshift({
161
+ name: defaultIndexRaw,
162
+ alias: defaultAlias(defaultIndexRaw),
163
+ ...(fromEnv.length > 0 ? { columns: fromEnv } : {}),
164
+ });
165
+ }
166
+ const seenAliases = new Set();
167
+ const indexes = configured.map((entry) => {
168
+ let alias = entry.alias;
169
+ while (seenAliases.has(alias))
170
+ alias = `${alias}_`;
171
+ seenAliases.add(alias);
172
+ return { ...entry, alias };
173
+ });
174
+ const defaultIndex = defaultIndexRaw ?? indexes[0]?.name;
175
+ const columns = config.columns ?? string.parseList(process.env.SEARCH_COLUMNS);
176
+ return {
177
+ ...(defaultIndex ? { defaultIndex } : {}),
178
+ indexes,
179
+ ...((string.trimToNull(config.endpoint) ?? string.trimToNull(process.env[ENDPOINT_ENV]))
180
+ ? {
181
+ endpoint: string.trimToNull(config.endpoint) ??
182
+ string.trimToNull(process.env[ENDPOINT_ENV]) ??
183
+ undefined,
184
+ }
185
+ : {}),
186
+ ...(columns.length > 0 ? { columns } : {}),
187
+ pageSize: resolvePositiveInt(config.pageSize, "SEARCH_PAGE_SIZE", DEFAULT_PAGE_SIZE),
188
+ mode: resolveMode(config.mode),
189
+ ...((string.trimToNull(config.embeddingModel) ??
190
+ string.trimToNull(process.env.SEARCH_EMBEDDING_MODEL))
191
+ ? {
192
+ embeddingModel: string.trimToNull(config.embeddingModel) ??
193
+ string.trimToNull(process.env.SEARCH_EMBEDDING_MODEL) ??
194
+ undefined,
195
+ }
196
+ : {}),
197
+ basePath: DEFAULT_BASE_PATH,
198
+ timeoutMs: resolvePositiveInt(config.timeoutMs, "SEARCH_TIMEOUT_MS", DEFAULT_TIMEOUT_MS),
199
+ allowWrite: config.allowWrite ?? object.toBoolean(process.env.SEARCH_WRITE) ?? false,
200
+ ...(config.ensureOnSetup ? { ensureOnSetup: config.ensureOnSetup } : {}),
201
+ };
202
+ }
203
+ /**
204
+ * Resolve a caller-supplied index reference (a full UC name or a configured
205
+ * alias) into a concrete index name. Falls back to the default index when the
206
+ * reference is empty. Returns `null` when nothing can be resolved so callers
207
+ * raise a stable, user-facing error rather than calling a phantom index.
208
+ */
209
+ export function resolveIndexName(config, reference) {
210
+ const ref = string.trimToNull(reference);
211
+ if (ref === null)
212
+ return config.defaultIndex ?? null;
213
+ const byAlias = config.indexes.find((i) => i.alias === ref || i.name === ref);
214
+ if (byAlias)
215
+ return byAlias.name;
216
+ // Accept an unregistered but fully-qualified UC name (three dotted parts).
217
+ if (ref.split(".").filter(Boolean).length === 3)
218
+ return ref;
219
+ return config.defaultIndex ?? null;
220
+ }
221
+ /** The known config for an index name, when the plugin was told about it. */
222
+ export function indexConfigFor(config, name) {
223
+ return config.indexes.find((i) => i.name === name || i.alias === name);
224
+ }
225
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFBRSxrQkFBa0IsRUFBeUIsTUFBTSxvQkFBb0IsQ0FBQztBQUUvRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR3hELGdGQUFnRjtBQUNoRixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDO0FBRXhDLDRFQUE0RTtBQUM1RSxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxnQ0FBZ0MsQ0FBQztBQUVyRSxvRkFBb0Y7QUFDcEYsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLGlCQUFpQixDQUFDO0FBRTlDLDJGQUEyRjtBQUMzRixNQUFNLENBQUMsTUFBTSxZQUFZLEdBQWUsUUFBUSxDQUFDO0FBRWpELHlGQUF5RjtBQUN6RixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLENBQUM7QUFFcEMsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQztBQUV6Qyx1RUFBdUU7QUFDdkUsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsYUFBYSxDQUFDO0FBcUcvQyxnRkFBZ0Y7QUFDaEYsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQWdCO0lBQy9DLElBQUksRUFBRSxRQUFRO0lBQ2Qsb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixVQUFVLEVBQUU7UUFDVixLQUFLLEVBQUU7WUFDTCxJQUFJLEVBQUUsUUFBUTtZQUNkLFdBQVcsRUFBRSx1RUFBdUU7U0FDckY7UUFDRCxPQUFPLEVBQUU7WUFDUCxJQUFJLEVBQUUsT0FBTztZQUNiLFdBQVcsRUFBRSw0RUFBNEU7WUFDekYsS0FBSyxFQUFFO2dCQUNMLEtBQUssRUFBRTtvQkFDTCxFQUFFLElBQUks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SSxLQUFLLElBQUksSUFBSSxDQUFDLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDO0FBQ3pFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSBBSSBTZWFyY2ggcGx1Z2luOiB0aGUgdHlwZWRcbiAqIHtAbGluayBTZWFyY2hQbHVnaW5Db25maWd9ICh0aGUgcGx1Z2luJ3Mgc2xpY2Ugb2YgQXBwS2l0IGNvbmZpZyksIHRoZSBKU09OXG4gKiBTY2hlbWEgdGhlIG1hbmlmZXN0IHB1Ymxpc2hlcyBmb3IgaXQsIGFuZCB7QGxpbmsgcmVzb2x2ZVNlYXJjaENvbmZpZ31cbiAqIHdoaWNoIGxheWVycyB0aGF0IGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzIGludG8gdGhlIGNvbmNyZXRlXG4gKiB7QGxpbmsgUmVzb2x2ZWRTZWFyY2hDb25maWd9IHRoZSBydW50aW1lLCBjbGllbnQsIHRvb2xzLCBhbmQgcm91dGVzIHJlYWQuXG4gKlxuICogVGhlIGRlc2lnbiBnb2FsIGlzIFwib25lIGluZGV4LCB6ZXJvIGNvbmZpZ1wiOiBuYW1lIGEgZGVmYXVsdCBpbmRleCAob3Igc2V0XG4gKiBgREFUQUJSSUNLU19WRUNUT1JfU0VBUkNIX0lOREVYYCkgYW5kIGV2ZXJ5dGhpbmcgZWxzZSAtIHRoZSBjb2x1bW5zIHRvXG4gKiByZXR1cm4sIHRoZSBwYWdlIHNpemUsIHRoZSBtYXRjaCBtb2RlLCB0aGUgbW91bnRlZCByb3V0ZSBwYXRoLCB0aGUgZW1iZWRkaW5nXG4gKiBtb2RlbCB1c2VkIHdoZW4gY3JlYXRpbmcgYW4gaW5kZXggLSBoYXMgYSBzZW5zaWJsZSBkZWZhdWx0IHRoYXQgY2FuIGJlXG4gKiBvdmVycmlkZGVuIHdoZW4gYSBkZXBsb3ltZW50IG5lZWRzIHRvIGdvIGRlZXBlci5cbiAqXG4gKiBXaGljaCBpbmRleCAvIGVuZHBvaW50IGlzIHVzZWQgZm9sbG93cyB0aGUgc3RhbmRhcmQgcHJlY2VkZW5jZTogZXhwbGljaXRcbiAqIHBsdWdpbiBjb25maWcsIHRoZW4gZW52aXJvbm1lbnQsIHRoZW4gYSBkZWZhdWx0LlxuICpcbiAqIEVudiBmYWxsYmFja3M6IGBEQVRBQlJJQ0tTX1ZFQ1RPUl9TRUFSQ0hfSU5ERVhgICh0aGUgZGVmYXVsdCBpbmRleCksXG4gKiBgU0VBUkNIX0lOREVYYCwgYFNFQVJDSF9FTkRQT0lOVGAsIGBTRUFSQ0hfQ09MVU1OU2AsXG4gKiBgU0VBUkNIX1BBR0VfU0laRWAsIGBTRUFSQ0hfTU9ERWAsIGBTRUFSQ0hfRU1CRURESU5HX01PREVMYCxcbiAqIGBTRUFSQ0hfVElNRU9VVF9NU2AsIGBTRUFSQ0hfV1JJVEVgLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBDb25maWd1cmF0aW9uRXJyb3IsIHR5cGUgQmFzZVBsdWdpbkNvbmZpZyB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB0eXBlIHsgU2VhcmNoRG9jdW1lbnQsIFNlYXJjaE1vZGUgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtc2VhcmNoXCI7XG5pbXBvcnQgeyBvYmplY3QsIHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IEpTT05TY2hlbWE3IH0gZnJvbSBcImpzb24tc2NoZW1hXCI7XG5cbi8qKiBUaGUgZGVmYXVsdCBpbmRleCwgaG9ub3JpbmcgQXBwS2l0J3Mgc3RhbmRhcmQgVmVjdG9yIFNlYXJjaCBiaW5kaW5nIG5hbWUuICovXG5leHBvcnQgY29uc3QgSU5ERVhfRU5WID0gXCJTRUFSQ0hfSU5ERVhcIjtcblxuLyoqIEFwcEtpdCdzIHN0YW5kYXJkIGVudmlyb25tZW50IG5hbWUgZm9yIGEgVmVjdG9yIFNlYXJjaCBpbmRleCBiaW5kaW5nLiAqL1xuZXhwb3J0IGNvbnN0IERBVEFCUklDS1NfSU5ERVhfRU5WID0gXCJEQVRBQlJJQ0tTX1ZFQ1RPUl9TRUFSQ0hfSU5ERVhcIjtcblxuLyoqIERlZGljYXRlZCBvdmVycmlkZSBmb3IgdGhlIFZlY3RvciBTZWFyY2ggc2VydmluZyBlbmRwb2ludCB0aGF0IGhvc3RzIGluZGV4ZXMuICovXG5leHBvcnQgY29uc3QgRU5EUE9JTlRfRU5WID0gXCJTRUFSQ0hfRU5EUE9JTlRcIjtcblxuLyoqIERlZmF1bHQgbWF0Y2ggbW9kZSB3aGVuIGEgcmVxdWVzdCBkb2VzIG5vdCBuYW1lIG9uZS4gSHlicmlkIHN1aXRzIG1vc3Qgc2VhcmNoIGJveGVzLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfTU9ERTogU2VhcmNoTW9kZSA9IFwiaHlicmlkXCI7XG5cbi8qKiBEZWZhdWx0IG51bWJlciBvZiBoaXRzIGEgc2VhcmNoIHJldHVybnMgKGEgZ29vZCBhdXRvY29tcGxldGUgLyByZXN1bHRzLWxpc3Qgc2l6ZSkuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9QQUdFX1NJWkUgPSAxMDtcblxuLyoqIERlZmF1bHQgcGVyLWNhbGwgdGltZW91dCBmb3IgYSBzZWFyY2ggLyBpbmRleCBvcGVyYXRpb24uICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gMzBfMDAwO1xuXG4vKiogQmFzZSBwYXRoIHRoZSBwbHVnaW4gbW91bnRzIGl0cyByb3V0ZXMgdW5kZXIsIHVubGVzcyBvdmVycmlkZGVuLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfQkFTRV9QQVRIID0gXCIvYXBpL3NlYXJjaFwiO1xuXG4vKipcbiAqIEEgY29uZmlndXJlZCBpbmRleCB0aGUgcGx1Z2luIGtub3dzIGFib3V0IGFoZWFkIG9mIHRpbWUuIE9ubHkgYG5hbWVgIChvclxuICogYGFsaWFzYCkgaXMgcmVxdWlyZWQ7IHRoZSByZXN0IGlzIHJlc29sdmVkIGZyb20gdGhlIGxpdmUgaW5kZXggZGVmaW5pdGlvblxuICogd2hlbiBvbWl0dGVkLCBzbyBhIGRlcGxveW1lbnQgY2FuIHJlZ2lzdGVyIGB7IG5hbWUgfWAgYW5kIGxldCB0aGUgcGx1Z2luIGZpbGxcbiAqIGluIHRoZSBwcmltYXJ5IGtleSBhbmQgY29sdW1ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hJbmRleENvbmZpZyB7XG4gIC8qKiBVbml0eSBDYXRhbG9nIG5hbWUgb2YgdGhlIGluZGV4IChjYXRhbG9nLnNjaGVtYS5pbmRleCkuICovXG4gIG5hbWU6IHN0cmluZztcbiAgLyoqIFNob3J0IGFsaWFzIGEgY2FsbGVyIG1heSB1c2UgaW4gcGxhY2Ugb2YgYG5hbWVgIChkZWZhdWx0cyB0byB0aGUgbGFzdCBuYW1lIHNlZ21lbnQpLiAqL1xuICBhbGlhcz86IHN0cmluZztcbiAgLyoqIFByaW1hcnkta2V5IGNvbHVtbi4gUmVzb2x2ZWQgZnJvbSB0aGUgaW5kZXggZGVmaW5pdGlvbiB3aGVuIG9taXR0ZWQuICovXG4gIHByaW1hcnlLZXk/OiBzdHJpbmc7XG4gIC8qKiBDb2x1bW5zIHRvIHJldHVybiBwZXIgaGl0LCBpbiBkaXNwbGF5IG9yZGVyLiBEZWZhdWx0cyB0byBldmVyeSBpbmRleGVkIGNvbHVtbi4gKi9cbiAgY29sdW1ucz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFRoZSBBSSBTZWFyY2ggcGx1Z2luJ3Mgc2xpY2Ugb2YgQXBwS2l0IGNvbmZpZy4gRXZlcnkgZmllbGQgaXMgb3B0aW9uYWwgLSB0aGVcbiAqIHBsdWdpbiB3b3JrcyB3aXRoIG5vdGhpbmcgYnV0IGFuIGluZGV4IG5hbWUgaW4gdGhlIGVudmlyb25tZW50LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlYXJjaFBsdWdpbkNvbmZpZyBleHRlbmRzIEJhc2VQbHVnaW5Db25maWcge1xuICAvKiogVGhlIGRlZmF1bHQgaW5kZXggc2VhcmNoZWQgd2hlbiBhIHJlcXVlc3Qgb21pdHMgb25lIChuYW1lIG9yIGFsaWFzKS4gKi9cbiAgaW5kZXg/OiBzdHJpbmc7XG4gIC8qKiBJbmRleGVzIHRoZSBwbHVnaW4gc2hvdWxkIGtub3cgYWJvdXQgKGZvciBhbGlhc2VzLCB1bml2ZXJzYWwgc2VhcmNoLCBhbmQgdGhlIFVJIGNhdGFsb2d1ZSkuICovXG4gIGluZGV4ZXM/OiBBcnJheTxzdHJpbmcgfCBTZWFyY2hJbmRleENvbmZpZz47XG4gIC8qKiBUaGUgVmVjdG9yIFNlYXJjaCBzZXJ2aW5nIGVuZHBvaW50IGluZGV4ZXMgbGl2ZSBvbiAob25seSBuZWVkZWQgdG8gY3JlYXRlIGFuIGluZGV4KS4gKi9cbiAgZW5kcG9pbnQ/OiBzdHJpbmc7XG4gIC8qKiBEZWZhdWx0IGNvbHVtbnMgdG8gcmV0dXJuIHBlciBoaXQuIEZhbGxzIGJhY2sgdG8gZWFjaCBpbmRleCdzIG93biBjb2x1bW5zLiAqL1xuICBjb2x1bW5zPzogc3RyaW5nW107XG4gIC8qKiBEZWZhdWx0IG51bWJlciBvZiBoaXRzIGEgc2VhcmNoIHJldHVybnMuICovXG4gIHBhZ2VTaXplPzogbnVtYmVyO1xuICAvKiogRGVmYXVsdCBtYXRjaCBtb2RlLiAqL1xuICBtb2RlPzogU2VhcmNoTW9kZTtcbiAgLyoqIEVtYmVkZGluZyBtb2RlbCBlbmRwb2ludCB1c2VkIHdoZW4gdGhlIHBsdWdpbiBDUkVBVEVTIGEgRGVsdGEgU3luYyBpbmRleC4gRnV6enktcmVzb2x2ZWQuICovXG4gIGVtYmVkZGluZ01vZGVsPzogc3RyaW5nO1xuICAvKiogUGVyLWNhbGwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMuICovXG4gIHRpbWVvdXRNcz86IG51bWJlcjtcbiAgLyoqIEVuYWJsZSB0aGUgd3JpdGUgc3VyZmFjZSAoYGFkZF9kb2N1bWVudHNgIHRvb2wgKyBgUE9TVCAvZG9jdW1lbnRzYCkuIE9mZiBieSBkZWZhdWx0LiAqL1xuICBhbGxvd1dyaXRlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFByb3Zpc2lvbiBhIFJFQUwgaW5kZXggYXQgYm9vdDogZW5zdXJlIHRoZSBlbmRwb2ludCArIGluZGV4IGV4aXN0IGFuZCBzZWVkXG4gICAqIGRvY3VtZW50cyB3aGVuIHRoZSBpbmRleCBpcyBlbXB0eS4gUnVucyBpbiB0aGUgYmFja2dyb3VuZCBkdXJpbmcgYHNldHVwKClgXG4gICAqIChhIHNsb3cgZmlyc3QtdGltZSBlbmRwb2ludC9pbmRleCBidWlsZCBuZXZlciBibG9ja3MgdGhlIHNlcnZlcikgdXNpbmcgdGhlXG4gICAqIGJvb3QtdGltZSBTREsgYXV0aCAoZW52IC8gY29uZmlnIHByb2ZpbGUpLiBJZGVtcG90ZW50IC0gc2FmZSBldmVyeSBib290LlxuICAgKlxuICAgKiBUaGUgZGVmYXVsdCBpcyBhIE1BTkFHRUQgZGlyZWN0LWFjY2VzcyBpbmRleCAoRGF0YWJyaWNrcyBlbWJlZHMgdGhlIHRleHRcbiAgICogY29sdW1uKSwgc28gYGRvY3VtZW50c2AgYXJlIHBsYWluIHJvd3MgYW5kIHNlYXJjaC1ieS10ZXh0IHdvcmtzIHdpdGggbm9cbiAgICogRGVsdGEgdGFibGUsIG5vIHdhcmVob3VzZSwgYW5kIG5vIHZlY3RvcnMgdG8gY29tcHV0ZS4gUG9pbnQgaXQgYXQgYVxuICAgKiBgc291cmNlVGFibGVgIHRvIHByb3Zpc2lvbiBhIERlbHRhIFN5bmMgaW5kZXggaW5zdGVhZC5cbiAgICovXG4gIGVuc3VyZU9uU2V0dXA/OiBFbnN1cmVPblNldHVwQ29uZmlnO1xufVxuXG4vKiogQm9vdC10aW1lIHByb3Zpc2lvbmluZyArIHNlZWRpbmcgZm9yIGEgc2luZ2xlIGluZGV4IChzZWUgYGVuc3VyZU9uU2V0dXBgKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW5zdXJlT25TZXR1cENvbmZpZyB7XG4gIC8qKiBVQyBuYW1lIG9mIHRoZSBpbmRleCB0byBlbnN1cmUgKGNhdGFsb2cuc2NoZW1hLmluZGV4KS4gRGVmYXVsdHMgdG8gdGhlIHBsdWdpbidzIGBpbmRleGAuICovXG4gIGluZGV4Pzogc3RyaW5nO1xuICAvKiogVmVjdG9yIFNlYXJjaCBlbmRwb2ludCB0byBob3N0IGl0IG9uLiBEZWZhdWx0cyB0byB0aGUgcGx1Z2luJ3MgYGVuZHBvaW50YC4gKi9cbiAgZW5kcG9pbnQ/OiBzdHJpbmc7XG4gIC8qKiBQcmltYXJ5LWtleSBjb2x1bW4uIERlZmF1bHRzIHRvIGBpZGAuICovXG4gIHByaW1hcnlLZXk/OiBzdHJpbmc7XG4gIC8qKiBUZXh0IGNvbHVtbiBEYXRhYnJpY2tzIGVtYmVkcyAobWFuYWdlZCBkaXJlY3QtYWNjZXNzKS4gRGVmYXVsdHMgdG8gYHRleHRgLiAqL1xuICB0ZXh0Q29sdW1uPzogc3RyaW5nO1xuICAvKiogRW1iZWRkaW5nIG1vZGVsIGVuZHBvaW50LiBGdXp6eS1tYXRjaGVkOyBkZWZhdWx0cyB0byB0aGUgYmVzdCBlbWJlZGRpbmcgZW5kcG9pbnQuICovXG4gIGVtYmVkZGluZ01vZGVsPzogc3RyaW5nO1xuICAvKiogRm9yIGEgRGVsdGEgU3luYyBpbmRleCBpbnN0ZWFkIG9mIG1hbmFnZWQgZGlyZWN0LWFjY2VzczogdGhlIHNvdXJjZSBEZWx0YSB0YWJsZS4gKi9cbiAgc291cmNlVGFibGU/OiBzdHJpbmc7XG4gIC8qKiBDb2x1bW4gLT4gdHlwZSBtYXAgZm9yIHRoZSBtYW5hZ2VkIGRpcmVjdC1hY2Nlc3MgYHNjaGVtYV9qc29uYC4gSW5mZXJyZWQgZnJvbSBgZG9jdW1lbnRzYCB3aGVuIG9taXR0ZWQuICovXG4gIHNjaGVtYT86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKiBEb2N1bWVudHMgdG8gc2VlZCB3aGVuIHRoZSBpbmRleCBpcyBlbXB0eS4gUGxhaW4gYHsgaWQsIHRleHQsIC4uLiB9YCByb3dzIGZvciBhIG1hbmFnZWQgaW5kZXguICovXG4gIGRvY3VtZW50cz86IFNlYXJjaERvY3VtZW50W107XG4gIC8qKiBNYXggdGltZSB0byB3YWl0IGZvciBlbmRwb2ludCArIGluZGV4IHJlYWRpbmVzcy4gRGVmYXVsdHMgdG8gMjAgbWludXRlcy4gKi9cbiAgdGltZW91dE1zPzogbnVtYmVyO1xufVxuXG4vKiogQSBmdWxseSByZXNvbHZlZCBpbmRleCBlbnRyeSAodGhlIHBsdWdpbi1rbm93biBmb3JtKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRJbmRleENvbmZpZyB7XG4gIG5hbWU6IHN0cmluZztcbiAgYWxpYXM6IHN0cmluZztcbiAgcHJpbWFyeUtleT86IHN0cmluZztcbiAgY29sdW1ucz86IHN0cmluZ1tdO1xufVxuXG4vKiogVGhlIGNvbmNyZXRlIGNvbmZpZyB0aGUgcnVudGltZSwgY2xpZW50LCB0b29scywgYW5kIHJvdXRlcyByZWFkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZFNlYXJjaENvbmZpZyB7XG4gIGRlZmF1bHRJbmRleD86IHN0cmluZztcbiAgaW5kZXhlczogUmVzb2x2ZWRJbmRleENvbmZpZ1tdO1xuICBlbmRwb2ludD86IHN0cmluZztcbiAgY29sdW1ucz86IHN0cmluZ1tdO1xuICBwYWdlU2l6ZTogbnVtYmVyO1xuICBtb2RlOiBTZWFyY2hNb2RlO1xuICBlbWJlZGRpbmdNb2RlbD86IHN0cmluZztcbiAgYmFzZVBhdGg6IHN0cmluZztcbiAgdGltZW91dE1zOiBudW1iZXI7XG4gIGFsbG93V3JpdGU6IGJvb2xlYW47XG4gIGVuc3VyZU9uU2V0dXA/OiBFbnN1cmVPblNldHVwQ29uZmlnO1xufVxuXG4vKiogSlNPTiBTY2hlbWEgdGhlIHBsdWdpbiBtYW5pZmVzdCBwdWJsaXNoZXMgZm9yIHtAbGluayBTZWFyY2hQbHVnaW5Db25maWd9LiAqL1xuZXhwb3J0IGNvbnN0IFNFQVJDSF9DT05GSUdfU0NIRU1BOiBKU09OU2NoZW1hNyA9IHtcbiAgdHlwZTogXCJvYmplY3RcIixcbiAgYWRkaXRpb25hbFByb3BlcnRpZXM6IHRydWUsXG4gIHByb3BlcnRpZXM6IHtcbiAgICBpbmRleDoge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkRlZmF1bHQgaW5kZXggdG8gc2VhcmNoIChjYXRhbG9nLnNjaGVtYS5pbmRleCBvciBhIGNvbmZpZ3VyZWQgYWxpYXMpLlwiLFxuICAgIH0sXG4gICAgaW5kZXhlczoge1xuICAgICAgdHlwZTogXCJhcnJheVwiLFxuICAgICAgZGVzY3JpcHRpb246IFwiSW5kZXhlcyB0aGUgcGx1Z2luIGtub3dzIGFib3V0LCBmb3IgYWxpYXNlcywgdW5pdmVyc2FsIHNlYXJjaCwgYW5kIHRoZSBVSS5cIixcbiAgICAgIGl0ZW1zOiB7XG4gICAgICAgIG9uZU9mOiBbXG4gICAgICAgICAgeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgICAgICAgIHJlcXVpcmVkOiBbXCJuYW1lXCJdLFxuICAgICAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgICAgICBuYW1lOiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgICAgICAgYWxpYXM6IHsgdHlwZTogXCJzdHJpbmdcIiB9LFxuICAgICAgICAgICAgICBwcmltYXJ5S2V5OiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgICAgICAgY29sdW1uczogeyB0eXBlOiBcImFycmF5XCIsIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICB9LFxuICAgIGVuZHBvaW50OiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246IFwiVmVjdG9yIFNlYXJjaCBzZXJ2aW5nIGVuZHBvaW50IGluZGV4ZXMgbGl2ZSBvbiAobmVlZGVkIG9ubHkgdG8gY3JlYXRlIG9uZSkuXCIsXG4gICAgfSxcbiAgICBjb2x1bW5zOiB7XG4gICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICBpdGVtczogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICBkZXNjcmlwdGlvbjogXCJEZWZhdWx0IGNvbHVtbnMgdG8gcmV0dXJuLlwiLFxuICAgIH0sXG4gICAgcGFnZVNpemU6IHsgdHlwZTogXCJudW1iZXJcIiwgZGVzY3JpcHRpb246IFwiRGVmYXVsdCBudW1iZXIgb2YgaGl0cyBwZXIgc2VhcmNoLlwiIH0sXG4gICAgbW9kZTogeyBlbnVtOiBbXCJoeWJyaWRcIiwgXCJ2ZWN0b3JcIiwgXCJrZXl3b3JkXCJdLCBkZXNjcmlwdGlvbjogXCJEZWZhdWx0IG1hdGNoIG1vZGUuXCIgfSxcbiAgICBlbWJlZGRpbmdNb2RlbDoge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkVtYmVkZGluZyBlbmRwb2ludCB1c2VkIHdoZW4gY3JlYXRpbmcgYSBEZWx0YSBTeW5jIGluZGV4IChmdXp6eS1tYXRjaGVkKS5cIixcbiAgICB9LFxuICAgIHRpbWVvdXRNczogeyB0eXBlOiBcIm51bWJlclwiLCBkZXNjcmlwdGlvbjogXCJQZXItY2FsbCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcy5cIiB9LFxuICAgIGFsbG93V3JpdGU6IHtcbiAgICAgIHR5cGU6IFwiYm9vbGVhblwiLFxuICAgICAgZGVzY3JpcHRpb246IFwiRW5hYmxlIHRoZSBkb2N1bWVudCB3cml0ZSBzdXJmYWNlIChhZGRfZG9jdW1lbnRzIHRvb2wgKyByb3V0ZSkuXCIsXG4gICAgfSxcbiAgICBlbnN1cmVPblNldHVwOiB7XG4gICAgICB0eXBlOiBcIm9iamVjdFwiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiUHJvdmlzaW9uIGEgcmVhbCBpbmRleCBhdCBib290OiBlbnN1cmUgdGhlIGVuZHBvaW50ICsgaW5kZXggZXhpc3QgYW5kIHNlZWQgXCIgK1xuICAgICAgICBcImRvY3VtZW50cyB3aGVuIGVtcHR5LiBSdW5zIGluIHRoZSBiYWNrZ3JvdW5kIGR1cmluZyBzZXR1cCB1c2luZyBib290LXRpbWUgYXV0aC5cIixcbiAgICAgIGFkZGl0aW9uYWxQcm9wZXJ0aWVzOiB0cnVlLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBpbmRleDogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICAgIGVuZHBvaW50OiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgcHJpbWFyeUtleTogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICAgIHRleHRDb2x1bW46IHsgdHlwZTogXCJzdHJpbmdcIiB9LFxuICAgICAgICBlbWJlZGRpbmdNb2RlbDogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICAgIHNvdXJjZVRhYmxlOiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgc2NoZW1hOiB7IHR5cGU6IFwib2JqZWN0XCIsIGFkZGl0aW9uYWxQcm9wZXJ0aWVzOiB7IHR5cGU6IFwic3RyaW5nXCIgfSB9LFxuICAgICAgICBkb2N1bWVudHM6IHsgdHlwZTogXCJhcnJheVwiLCBpdGVtczogeyB0eXBlOiBcIm9iamVjdFwiLCBhZGRpdGlvbmFsUHJvcGVydGllczogdHJ1ZSB9IH0sXG4gICAgICAgIHRpbWVvdXRNczogeyB0eXBlOiBcIm51bWJlclwiIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0sXG59O1xuXG4vKiogRGVyaXZlIHRoZSBkZWZhdWx0IGFsaWFzIGZvciBhbiBpbmRleCBuYW1lIChpdHMgbGFzdCBkb3R0ZWQgc2VnbWVudCkuICovXG5leHBvcnQgZnVuY3Rpb24gZGVmYXVsdEFsaWFzKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHNlZ21lbnRzID0gbmFtZS5zcGxpdChcIi5cIikuZmlsdGVyKEJvb2xlYW4pO1xuICByZXR1cm4gc2VnbWVudHMubGVuZ3RoID4gMCA/IHNlZ21lbnRzW3NlZ21lbnRzLmxlbmd0aCAtIDFdIDogbmFtZTtcbn1cblxuLyoqIE5vcm1hbGl6ZSBhIGNvbmZpZyBpbmRleCBlbnRyeSAoc3RyaW5nIG9yIG9iamVjdCkgaW50byBhIHtAbGluayBSZXNvbHZlZEluZGV4Q29uZmlnfS4gKi9cbmZ1bmN0aW9uIHRvUmVzb2x2ZWRJbmRleChlbnRyeTogc3RyaW5nIHwgU2VhcmNoSW5kZXhDb25maWcpOiBSZXNvbHZlZEluZGV4Q29uZmlnIHwgbnVsbCB7XG4gIGNvbnN0IHJhdyA9IHR5cGVvZiBlbnRyeSA9PT0gXCJzdHJpbmdcIiA/IHsgbmFtZTogZW50cnkgfSA6IGVudHJ5O1xuICBjb25zdCBuYW1lID0gc3RyaW5nLnRyaW1Ub051bGwocmF3Lm5hbWUpO1xuICBpZiAobmFtZSA9PT0gbnVsbCkgcmV0dXJuIG51bGw7XG4gIHJldHVybiB7XG4gICAgbmFtZSxcbiAgICBhbGlhczogc3RyaW5nLnRyaW1Ub051bGwocmF3LmFsaWFzKSA/PyBkZWZhdWx0QWxpYXMobmFtZSksXG4gICAgLi4uKHJhdy5wcmltYXJ5S2V5ID8geyBwcmltYXJ5S2V5OiByYXcucHJpbWFyeUtleSB9IDoge30pLFxuICAgIC4uLihyYXcuY29sdW1ucyAmJiByYXcuY29sdW1ucy5sZW5ndGggPiAwID8geyBjb2x1bW5zOiBbLi4ucmF3LmNvbHVtbnNdIH0gOiB7fSksXG4gIH07XG59XG5cbi8qKiBDb2VyY2UgYSBwb3NpdGl2ZSBpbnRlZ2VyIGZyb20gY29uZmlnIG9yIGFuIGVudiB2YXIsIGZhbGxpbmcgYmFjayB0byBhIGRlZmF1bHQuICovXG5mdW5jdGlvbiByZXNvbHZlUG9zaXRpdmVJbnQoXG4gIGNvbmZpZ3VyZWQ6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZW52VmFyOiBzdHJpbmcsXG4gIGZhbGxiYWNrOiBudW1iZXIsXG4pOiBudW1iZXIge1xuICBjb25zdCByYXcgPSBjb25maWd1cmVkID8/IE51bWJlcihwcm9jZXNzLmVudltlbnZWYXJdKTtcbiAgY29uc3QgdmFsdWUgPSBOdW1iZXIocmF3KTtcbiAgaWYgKE51bWJlci5pc0Zpbml0ZSh2YWx1ZSkgJiYgdmFsdWUgPiAwKSByZXR1cm4gTWF0aC5mbG9vcih2YWx1ZSk7XG4gIHJldHVybiBmYWxsYmFjaztcbn1cblxuLyoqIFBhcnNlIGFuZCB2YWxpZGF0ZSBhIHtAbGluayBTZWFyY2hNb2RlfSBmcm9tIGNvbmZpZyBvciBhbiBlbnYgdmFyLiAqL1xuZnVuY3Rpb24gcmVzb2x2ZU1vZGUoY29uZmlndXJlZDogU2VhcmNoTW9kZSB8IHVuZGVmaW5lZCk6IFNlYXJjaE1vZGUge1xuICBjb25zdCByYXcgPSBjb25maWd1cmVkID8/IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LlNFQVJDSF9NT0RFKSA/PyB1bmRlZmluZWQ7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCkgcmV0dXJuIERFRkFVTFRfTU9ERTtcbiAgaWYgKHJhdyAhPT0gXCJoeWJyaWRcIiAmJiByYXcgIT09IFwidmVjdG9yXCIgJiYgcmF3ICE9PSBcImtleXdvcmRcIikge1xuICAgIHRocm93IG5ldyBDb25maWd1cmF0aW9uRXJyb3IoXG4gICAgICAnbW9kZSBtdXN0IGJlIFwiaHlicmlkXCIsIFwidmVjdG9yXCIgb3IgXCJrZXl3b3JkXCIgKGVudjogU0VBUkNIX01PREUpJyxcbiAgICAgIHsgY29udGV4dDogeyBmaWVsZDogXCJtb2RlXCIsIGVudlZhcjogXCJTRUFSQ0hfTU9ERVwiIH0gfSxcbiAgICApO1xuICB9XG4gIHJldHVybiByYXc7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBwbHVnaW4gY29uZmlnIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMgaW50byB0aGUgY29uY3JldGVcbiAqIHtAbGluayBSZXNvbHZlZFNlYXJjaENvbmZpZ30uIFRoZSBkZWZhdWx0IGluZGV4IGlzIHVuaW9uZWQgaW50byB0aGUga25vd25cbiAqIGluZGV4ZXMgc28gaXQgYWx3YXlzIGFwcGVhcnMgaW4gdGhlIGNhdGFsb2d1ZSwgYWxpYXNlcyBhcmUgZGUtZHVwbGljYXRlZCxcbiAqIGFuZCBhIGJhZCBtb2RlIHRocm93cyBhIHtAbGluayBDb25maWd1cmF0aW9uRXJyb3J9IG5hbWluZyB0aGUgZmllbGQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlU2VhcmNoQ29uZmlnKGNvbmZpZzogU2VhcmNoUGx1Z2luQ29uZmlnID0ge30pOiBSZXNvbHZlZFNlYXJjaENvbmZpZyB7XG4gIGNvbnN0IGRlZmF1bHRJbmRleFJhdyA9XG4gICAgc3RyaW5nLnRyaW1Ub051bGwoY29uZmlnLmluZGV4KSA/P1xuICAgIHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52W0lOREVYX0VOVl0pID8/XG4gICAgc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnZbREFUQUJSSUNLU19JTkRFWF9FTlZdKSA/P1xuICAgIHVuZGVmaW5lZDtcblxuICBjb25zdCBjb25maWd1cmVkID0gKGNvbmZpZy5pbmRleGVzID8/IFtdKVxuICAgIC5tYXAodG9SZXNvbHZlZEluZGV4KVxuICAgIC5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgUmVzb2x2ZWRJbmRleENvbmZpZyA9PiBlbnRyeSAhPT0gbnVsbCk7XG5cbiAgLy8gRW5zdXJlIHRoZSBkZWZhdWx0IGluZGV4IGlzIHJlcHJlc2VudGVkIGluIHRoZSBrbm93biBzZXQuXG4gIGlmIChkZWZhdWx0SW5kZXhSYXcgJiYgIWNvbmZpZ3VyZWQuc29tZSgoaSkgPT4gaS5uYW1lID09PSBkZWZhdWx0SW5kZXhSYXcpKSB7XG4gICAgY29uc3QgZnJvbUVudiA9IHN0cmluZy5wYXJzZUxpc3QocHJvY2Vzcy5lbnYuU0VBUkNIX0NPTFVNTlMpO1xuICAgIGNvbmZpZ3VyZWQudW5zaGlmdCh7XG4gICAgICBuYW1lOiBkZWZhdWx0SW5kZXhSYXcsXG4gICAgICBhbGlhczogZGVmYXVsdEFsaWFzKGRlZmF1bHRJbmRleFJhdyksXG4gICAgICAuLi4oZnJvbUVudi5sZW5ndGggPiAwID8geyBjb2x1bW5zOiBmcm9tRW52IH0gOiB7fSksXG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBzZWVuQWxpYXNlcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBpbmRleGVzID0gY29uZmlndXJlZC5tYXAoKGVudHJ5KSA9PiB7XG4gICAgbGV0IGFsaWFzID0gZW50cnkuYWxpYXM7XG4gICAgd2hpbGUgKHNlZW5BbGlhc2VzLmhhcyhhbGlhcykpIGFsaWFzID0gYCR7YWxpYXN9X2A7XG4gICAgc2VlbkFsaWFzZXMuYWRkKGFsaWFzKTtcbiAgICByZXR1cm4geyAuLi5lbnRyeSwgYWxpYXMgfTtcbiAgfSk7XG5cbiAgY29uc3QgZGVmYXVsdEluZGV4ID0gZGVmYXVsdEluZGV4UmF3ID8/IGluZGV4ZXNbMF0/Lm5hbWU7XG4gIGNvbnN0IGNvbHVtbnMgPSBjb25maWcuY29sdW1ucyA/PyBzdHJpbmcucGFyc2VMaXN0KHByb2Nlc3MuZW52LlNFQVJDSF9DT0xVTU5TKTtcblxuICByZXR1cm4ge1xuICAgIC4uLihkZWZhdWx0SW5kZXggPyB7IGRlZmF1bHRJbmRleCB9IDoge30pLFxuICAgIGluZGV4ZXMsXG4gICAgLi4uKChzdHJpbmcudHJpbVRvTnVsbChjb25maWcuZW5kcG9pbnQpID8/IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52W0VORFBPSU5UX0VOVl0pKVxuICAgICAgPyB7XG4gICAgICAgICAgZW5kcG9pbnQ6XG4gICAgICAgICAgICBzdHJpbmcudHJpbVRvTnVsbChjb25maWcuZW5kcG9pbnQpID8/XG4gICAgICAgICAgICBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudltFTkRQT0lOVF9FTlZdKSA/P1xuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgICA6IHt9KSxcbiAgICAuLi4oY29sdW1ucy5sZW5ndGggPiAwID8geyBjb2x1bW5zIH0gOiB7fSksXG4gICAgcGFnZVNpemU6IHJlc29sdmVQb3NpdGl2ZUludChjb25maWcucGFnZVNpemUsIFwiU0VBUkNIX1BBR0VfU0laRVwiLCBERUZBVUxUX1BBR0VfU0laRSksXG4gICAgbW9kZTogcmVzb2x2ZU1vZGUoY29uZmlnLm1vZGUpLFxuICAgIC4uLigoc3RyaW5nLnRyaW1Ub051bGwoY29uZmlnLmVtYmVkZGluZ01vZGVsKSA/P1xuICAgIHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LlNFQVJDSF9FTUJFRERJTkdfTU9ERUwpKVxuICAgICAgPyB7XG4gICAgICAgICAgZW1iZWRkaW5nTW9kZWw6XG4gICAgICAgICAgICBzdHJpbmcudHJpbVRvTnVsbChjb25maWcuZW1iZWRkaW5nTW9kZWwpID8/XG4gICAgICAgICAgICBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5TRUFSQ0hfRU1CRURESU5HX01PREVMKSA/P1xuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgICA6IHt9KSxcbiAgICBiYXNlUGF0aDogREVGQVVMVF9CQVNFX1BBVEgsXG4gICAgdGltZW91dE1zOiByZXNvbHZlUG9zaXRpdmVJbnQoY29uZmlnLnRpbWVvdXRNcywgXCJTRUFSQ0hfVElNRU9VVF9NU1wiLCBERUZBVUxUX1RJTUVPVVRfTVMpLFxuICAgIGFsbG93V3JpdGU6IGNvbmZpZy5hbGxvd1dyaXRlID8/IG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuU0VBUkNIX1dSSVRFKSA/PyBmYWxzZSxcbiAgICAuLi4oY29uZmlnLmVuc3VyZU9uU2V0dXAgPyB7IGVuc3VyZU9uU2V0dXA6IGNvbmZpZy5lbnN1cmVPblNldHVwIH0gOiB7fSksXG4gIH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIGNhbGxlci1zdXBwbGllZCBpbmRleCByZWZlcmVuY2UgKGEgZnVsbCBVQyBuYW1lIG9yIGEgY29uZmlndXJlZFxuICogYWxpYXMpIGludG8gYSBjb25jcmV0ZSBpbmRleCBuYW1lLiBGYWxscyBiYWNrIHRvIHRoZSBkZWZhdWx0IGluZGV4IHdoZW4gdGhlXG4gKiByZWZlcmVuY2UgaXMgZW1wdHkuIFJldHVybnMgYG51bGxgIHdoZW4gbm90aGluZyBjYW4gYmUgcmVzb2x2ZWQgc28gY2FsbGVyc1xuICogcmFpc2UgYSBzdGFibGUsIHVzZXItZmFjaW5nIGVycm9yIHJhdGhlciB0aGFuIGNhbGxpbmcgYSBwaGFudG9tIGluZGV4LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUluZGV4TmFtZShcbiAgY29uZmlnOiBSZXNvbHZlZFNlYXJjaENvbmZpZyxcbiAgcmVmZXJlbmNlOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiBzdHJpbmcgfCBudWxsIHtcbiAgY29uc3QgcmVmID0gc3RyaW5nLnRyaW1Ub051bGwocmVmZXJlbmNlKTtcbiAgaWYgKHJlZiA9PT0gbnVsbCkgcmV0dXJuIGNvbmZpZy5kZWZhdWx0SW5kZXggPz8gbnVsbDtcbiAgY29uc3QgYnlBbGlhcyA9IGNvbmZpZy5pbmRleGVzLmZpbmQoKGkpID0+IGkuYWxpYXMgPT09IHJlZiB8fCBpLm5hbWUgPT09IHJlZik7XG4gIGlmIChieUFsaWFzKSByZXR1cm4gYnlBbGlhcy5uYW1lO1xuICAvLyBBY2NlcHQgYW4gdW5yZWdpc3RlcmVkIGJ1dCBmdWxseS1xdWFsaWZpZWQgVUMgbmFtZSAodGhyZWUgZG90dGVkIHBhcnRzKS5cbiAgaWYgKHJlZi5zcGxpdChcIi5cIikuZmlsdGVyKEJvb2xlYW4pLmxlbmd0aCA9PT0gMykgcmV0dXJuIHJlZjtcbiAgcmV0dXJuIGNvbmZpZy5kZWZhdWx0SW5kZXggPz8gbnVsbDtcbn1cblxuLyoqIFRoZSBrbm93biBjb25maWcgZm9yIGFuIGluZGV4IG5hbWUsIHdoZW4gdGhlIHBsdWdpbiB3YXMgdG9sZCBhYm91dCBpdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbmRleENvbmZpZ0ZvcihcbiAgY29uZmlnOiBSZXNvbHZlZFNlYXJjaENvbmZpZyxcbiAgbmFtZTogc3RyaW5nLFxuKTogUmVzb2x2ZWRJbmRleENvbmZpZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBjb25maWcuaW5kZXhlcy5maW5kKChpKSA9PiBpLm5hbWUgPT09IG5hbWUgfHwgaS5hbGlhcyA9PT0gbmFtZSk7XG59XG4iXX0=
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Shared translation from the browser-safe {@link CreateIndexRequest} wire
3
+ * shape onto the client's {@link CreateIndexOptions}. Lives in its own module
4
+ * because both the Mastra `create_index` tool (`tool.ts`) and the AppKit tool
5
+ * provider (`plugin.ts`) build the same options object, and the mapping (which
6
+ * optional fields to spread, folding in the abort signal) is easy to let drift
7
+ * between the two.
8
+ *
9
+ * @module
10
+ */
11
+ import type { CreateIndexRequest } from "@dbx-tools/shared-search";
12
+ import type { CreateIndexOptions } from "./client.ts";
13
+ /**
14
+ * Map a validated {@link CreateIndexRequest} onto {@link CreateIndexOptions},
15
+ * spreading only the fields that were supplied so the client's own defaults
16
+ * (endpoint, embedding model, primary key, text column) still apply, and
17
+ * folding in the caller's abort signal.
18
+ */
19
+ export declare function toCreateIndexOptions(request: CreateIndexRequest, signal?: AbortSignal): CreateIndexOptions;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shared translation from the browser-safe {@link CreateIndexRequest} wire
3
+ * shape onto the client's {@link CreateIndexOptions}. Lives in its own module
4
+ * because both the Mastra `create_index` tool (`tool.ts`) and the AppKit tool
5
+ * provider (`plugin.ts`) build the same options object, and the mapping (which
6
+ * optional fields to spread, folding in the abort signal) is easy to let drift
7
+ * between the two.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Map a validated {@link CreateIndexRequest} onto {@link CreateIndexOptions},
13
+ * spreading only the fields that were supplied so the client's own defaults
14
+ * (endpoint, embedding model, primary key, text column) still apply, and
15
+ * folding in the caller's abort signal.
16
+ */
17
+ export function toCreateIndexOptions(request, signal) {
18
+ return {
19
+ ...(request.sourceTable ? { sourceTable: request.sourceTable } : {}),
20
+ ...(request.primaryKey ? { primaryKey: request.primaryKey } : {}),
21
+ ...(request.embeddingSourceColumn
22
+ ? { embeddingSourceColumn: request.embeddingSourceColumn }
23
+ : {}),
24
+ ...(request.embeddingModel ? { embeddingModel: request.embeddingModel } : {}),
25
+ ...(request.endpoint ? { endpoint: request.endpoint } : {}),
26
+ ...(request.embeddingDimension !== undefined
27
+ ? { embeddingDimension: request.embeddingDimension }
28
+ : {}),
29
+ ...(request.pipelineType ? { pipelineType: request.pipelineType } : {}),
30
+ ...(request.columnsToSync ? { columnsToSync: request.columnsToSync } : {}),
31
+ ...(signal ? { signal } : {}),
32
+ };
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgtdG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgtdG9vbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7OztHQVNHO0FBS0g7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLE9BQTJCLEVBQzNCLE1BQW9CO0lBRXBCLE9BQU87UUFDTCxHQUFHLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDcEUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ2pFLEdBQUcsQ0FBQyxPQUFPLENBQUMscUJBQXFCO1lBQy9CLENBQUMsQ0FBQyxFQUFFLHFCQUFxQixFQUFFLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRTtZQUMxRCxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ1AsR0FBRyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzdFLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMzRCxHQUFHLENBQUMsT0FBTyxDQUFDLGtCQUFrQixLQUFLLFNBQVM7WUFDMUMsQ0FBQyxDQUFDLEVBQUUsa0JBQWtCLEVBQUUsT0FBTyxDQUFDLGtCQUFrQixFQUFFO1lBQ3BELENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDUCxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdkUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUM5QixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2hhcmVkIHRyYW5zbGF0aW9uIGZyb20gdGhlIGJyb3dzZXItc2FmZSB7QGxpbmsgQ3JlYXRlSW5kZXhSZXF1ZXN0fSB3aXJlXG4gKiBzaGFwZSBvbnRvIHRoZSBjbGllbnQncyB7QGxpbmsgQ3JlYXRlSW5kZXhPcHRpb25zfS4gTGl2ZXMgaW4gaXRzIG93biBtb2R1bGVcbiAqIGJlY2F1c2UgYm90aCB0aGUgTWFzdHJhIGBjcmVhdGVfaW5kZXhgIHRvb2wgKGB0b29sLnRzYCkgYW5kIHRoZSBBcHBLaXQgdG9vbFxuICogcHJvdmlkZXIgKGBwbHVnaW4udHNgKSBidWlsZCB0aGUgc2FtZSBvcHRpb25zIG9iamVjdCwgYW5kIHRoZSBtYXBwaW5nICh3aGljaFxuICogb3B0aW9uYWwgZmllbGRzIHRvIHNwcmVhZCwgZm9sZGluZyBpbiB0aGUgYWJvcnQgc2lnbmFsKSBpcyBlYXN5IHRvIGxldCBkcmlmdFxuICogYmV0d2VlbiB0aGUgdHdvLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IENyZWF0ZUluZGV4UmVxdWVzdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1zZWFyY2hcIjtcbmltcG9ydCB0eXBlIHsgQ3JlYXRlSW5kZXhPcHRpb25zIH0gZnJvbSBcIi4vY2xpZW50LnRzXCI7XG5cbi8qKlxuICogTWFwIGEgdmFsaWRhdGVkIHtAbGluayBDcmVhdGVJbmRleFJlcXVlc3R9IG9udG8ge0BsaW5rIENyZWF0ZUluZGV4T3B0aW9uc30sXG4gKiBzcHJlYWRpbmcgb25seSB0aGUgZmllbGRzIHRoYXQgd2VyZSBzdXBwbGllZCBzbyB0aGUgY2xpZW50J3Mgb3duIGRlZmF1bHRzXG4gKiAoZW5kcG9pbnQsIGVtYmVkZGluZyBtb2RlbCwgcHJpbWFyeSBrZXksIHRleHQgY29sdW1uKSBzdGlsbCBhcHBseSwgYW5kXG4gKiBmb2xkaW5nIGluIHRoZSBjYWxsZXIncyBhYm9ydCBzaWduYWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0NyZWF0ZUluZGV4T3B0aW9ucyhcbiAgcmVxdWVzdDogQ3JlYXRlSW5kZXhSZXF1ZXN0LFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IENyZWF0ZUluZGV4T3B0aW9ucyB7XG4gIHJldHVybiB7XG4gICAgLi4uKHJlcXVlc3Quc291cmNlVGFibGUgPyB7IHNvdXJjZVRhYmxlOiByZXF1ZXN0LnNvdXJjZVRhYmxlIH0gOiB7fSksXG4gICAgLi4uKHJlcXVlc3QucHJpbWFyeUtleSA/IHsgcHJpbWFyeUtleTogcmVxdWVzdC5wcmltYXJ5S2V5IH0gOiB7fSksXG4gICAgLi4uKHJlcXVlc3QuZW1iZWRkaW5nU291cmNlQ29sdW1uXG4gICAgICA/IHsgZW1iZWRkaW5nU291cmNlQ29sdW1uOiByZXF1ZXN0LmVtYmVkZGluZ1NvdXJjZUNvbHVtbiB9XG4gICAgICA6IHt9KSxcbiAgICAuLi4ocmVxdWVzdC5lbWJlZGRpbmdNb2RlbCA/IHsgZW1iZWRkaW5nTW9kZWw6IHJlcXVlc3QuZW1iZWRkaW5nTW9kZWwgfSA6IHt9KSxcbiAgICAuLi4ocmVxdWVzdC5lbmRwb2ludCA/IHsgZW5kcG9pbnQ6IHJlcXVlc3QuZW5kcG9pbnQgfSA6IHt9KSxcbiAgICAuLi4ocmVxdWVzdC5lbWJlZGRpbmdEaW1lbnNpb24gIT09IHVuZGVmaW5lZFxuICAgICAgPyB7IGVtYmVkZGluZ0RpbWVuc2lvbjogcmVxdWVzdC5lbWJlZGRpbmdEaW1lbnNpb24gfVxuICAgICAgOiB7fSksXG4gICAgLi4uKHJlcXVlc3QucGlwZWxpbmVUeXBlID8geyBwaXBlbGluZVR5cGU6IHJlcXVlc3QucGlwZWxpbmVUeXBlIH0gOiB7fSksXG4gICAgLi4uKHJlcXVlc3QuY29sdW1uc1RvU3luYyA/IHsgY29sdW1uc1RvU3luYzogcmVxdWVzdC5jb2x1bW5zVG9TeW5jIH0gOiB7fSksXG4gICAgLi4uKHNpZ25hbCA/IHsgc2lnbmFsIH0gOiB7fSksXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,86 @@
1
+ /**
2
+ * A Lakebase (Postgres) full-text search backend - the FALLBACK used when no
3
+ * Databricks Vector Search endpoint/index is configured but a Lakebase pool is
4
+ * available. It provisions a single table per index, indexes a generated
5
+ * `tsvector`, and answers queries with `websearch_to_tsquery` + `ts_rank`.
6
+ *
7
+ * The whole point is parity: this backend returns the EXACT same
8
+ * `@dbx-tools/shared-search` shapes (`SearchResult` / `SearchHit` /
9
+ * `UpsertResult`) as the Vector Search backend, so the client, the Mastra
10
+ * tools, the routes, and the React search box cannot tell which one answered.
11
+ * A hit's `id` is the primary key, its `score` is the text-rank, and `fields`
12
+ * is the stored document minus the internal columns.
13
+ *
14
+ * The Postgres pool is built the same way `@dbx-tools/appkit-mastra` builds its
15
+ * memory pool: the AppKit `lakebase` plugin resolves a service-principal
16
+ * `PoolConfig` (connection target + OAuth token-refresh `password` callback),
17
+ * and this backend constructs a `pg.Pool` from it. It never re-implements auth.
18
+ *
19
+ * @module
20
+ */
21
+ import { Pool, type PoolConfig } from "pg";
22
+ import type { SearchDocument, SearchResult, UpsertResult } from "@dbx-tools/shared-search";
23
+ /** Options for a single-index Lakebase search (mirrors the client's `SearchOptions`). */
24
+ export interface LakebaseSearchOptions {
25
+ limit?: number;
26
+ scoreThreshold?: number;
27
+ signal?: AbortSignal;
28
+ }
29
+ /** Options for provisioning a Lakebase-backed index. */
30
+ export interface LakebaseProvisionOptions {
31
+ /** Text column embedded into the search vector. Defaults to `text`. */
32
+ textColumn?: string;
33
+ /** Documents to seed when the table is empty. */
34
+ seed?: SearchDocument[];
35
+ signal?: AbortSignal;
36
+ }
37
+ /**
38
+ * A Postgres full-text backend. One instance is shared across indexes; each
39
+ * index maps to a table whose name is derived from the index reference.
40
+ */
41
+ export declare class LakebaseSearchBackend {
42
+ private readonly pgConfigFactory;
43
+ private readonly schema;
44
+ /** How a pool is built from the resolved config. Overridable for tests. */
45
+ private readonly poolFactory;
46
+ private pool;
47
+ private poolPromise;
48
+ private readonly provisioned;
49
+ constructor(pgConfigFactory: () => Promise<PoolConfig> | PoolConfig, schema?: string,
50
+ /** How a pool is built from the resolved config. Overridable for tests. */
51
+ poolFactory?: (config: PoolConfig) => Pool);
52
+ /** Lazily build (and cache) the pg pool from the resolved Lakebase config. */
53
+ private getPool;
54
+ /** Close the pool so a restarted app rebuilds it. */
55
+ close(): Promise<void>;
56
+ /**
57
+ * Search a Lakebase-backed index. Returns hits sorted most-relevant-first,
58
+ * shaped identically to the Vector Search backend.
59
+ */
60
+ search(index: string, query: string, options?: LakebaseSearchOptions): Promise<SearchResult>;
61
+ /**
62
+ * Ensure the table + full-text index exist and seed documents when empty.
63
+ * Idempotent, so it is safe to call on every boot.
64
+ */
65
+ provision(index: string, options?: LakebaseProvisionOptions): Promise<number>;
66
+ /** Add or update documents by primary key. */
67
+ addDocuments(index: string, documents: SearchDocument[], textColumn?: string, signal?: AbortSignal): Promise<UpsertResult>;
68
+ /** Delete documents by primary key. */
69
+ deleteDocuments(index: string, ids: Array<string | number>, signal?: AbortSignal): Promise<UpsertResult>;
70
+ /** Create the table + GIN index once per table (memoized across calls). */
71
+ private ensureTable;
72
+ /** Upsert rows: the whole document as jsonb + a flattened text blob to index. */
73
+ private upsert;
74
+ /** The text a row is indexed by: the text column first, then any other string field. */
75
+ private searchText;
76
+ /** A hit's `fields`: the stored document minus the reserved/internal keys. */
77
+ private toFields;
78
+ /** The fully-qualified table name for an index reference. */
79
+ private tableFor;
80
+ /** A safe bare table name derived from an index reference. */
81
+ private bareName;
82
+ /** Quote a Postgres identifier. */
83
+ private ident;
84
+ /** Run one query under external cancellation. */
85
+ private query;
86
+ }