@dbx-tools/shared-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.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @dbx-tools/shared-search
2
+
3
+ Browser-safe AI Search (Databricks Vector Search) schemas and inferred types.
4
+
5
+ Import this package when a UI, Mastra tool schema, server route, or test needs
6
+ to validate the same search payloads that
7
+ [`@dbx-tools/search`](../../node/search) reads and writes.
8
+
9
+ Key features:
10
+
11
+ - Shared `SearchRequest` / `SearchResult` contract with `{ id, score, fields }`
12
+ hits, so an autocomplete box, a docs lookup, and a Mastra tool speak one shape.
13
+ - `SearchMode` (`hybrid` / `vector` / `keyword`) matching the serving query
14
+ types, with hybrid as the sensible default.
15
+ - `UniversalSearchRequest` for federated search across several indexes at once.
16
+ - `SearchDocument` / `UpsertResult` for adding and updating direct-access index
17
+ contents.
18
+ - `SearchIndexInfo` / `SearchClientConfig` for the boot-time index catalogue a
19
+ search box reads with no server round-trip.
20
+ - Model/tool-friendly schemas that avoid JSON Schema constraints known to cause
21
+ problems with some serving endpoints.
22
+
23
+ ## Validate A Search Request
24
+
25
+ ```ts
26
+ import { search, type SearchRequest } from "@dbx-tools/shared-search";
27
+
28
+ const request: SearchRequest = search.searchRequestSchema.parse({
29
+ query: "reset my password",
30
+ index: "main.support.docs",
31
+ limit: 5,
32
+ mode: "hybrid",
33
+ filter: { locale: "en", published: true },
34
+ });
35
+ ```
36
+
37
+ ## Validate Search Results
38
+
39
+ ```ts
40
+ const result = search.searchResultSchema.parse(await response.json());
41
+ for (const hit of result.hits) {
42
+ console.log(hit.score, hit.id, hit.fields.title);
43
+ }
44
+ ```
45
+
46
+ `searchHitSchema` returns the requested columns under `fields`, keyed by column
47
+ name, plus the primary-key `id` and a relevance `score`. A federated hit also
48
+ carries the `index` it came from.
49
+
50
+ ## Read The Index Catalogue
51
+
52
+ ```ts
53
+ const config = search.searchClientConfigSchema.parse(
54
+ await fetch("/api/search/indexes").then((r) => r.json()),
55
+ );
56
+ ```
57
+
58
+ `searchClientConfigSchema` is what a search box reads at boot to know which
59
+ indexes it may query, which is the default, and the page size to request.
60
+
61
+ ## Module
62
+
63
+ - `search` - `searchModeSchema`, `searchRequestSchema`, `searchHitSchema`,
64
+ `searchResultSchema`, `universalSearchRequestSchema`, `searchDocumentSchema`,
65
+ `upsertResultSchema`, `searchIndexInfoSchema`, `searchClientConfigSchema`, and
66
+ the flat inferred types (`SearchMode`, `SearchRequest`, `SearchHit`,
67
+ `SearchResult`, `UniversalSearchRequest`, `SearchDocument`, `UpsertResult`,
68
+ `SearchIndexInfo`, `SearchClientConfig`).
69
+
70
+ Runtime search, index management, the Mastra tools, and the AppKit plugin live
71
+ in [`@dbx-tools/search`](../../node/search). The React search box lives in
72
+ [`@dbx-tools/ui-search`](../../ui/search).
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ // GENERATED by projen watch - DO NOT EDIT.
2
+ // Regenerated from the exporting modules in ./src.
3
+ // Hand edits are overwritten on the next watch; this file is read-only.
4
+
5
+ export * as search from "./src/search.ts";
6
+ export { searchModeSchema, searchRequestSchema, searchHitSchema, searchResultSchema, universalSearchRequestSchema, searchDocumentSchema, upsertResultSchema, searchIndexInfoSchema, searchClientConfigSchema, createIndexRequestSchema, syncIndexRequestSchema, indexInfoSchema } from "./src/search.ts";
7
+ export type { SearchMode, SearchRequest, SearchHit, SearchResult, UniversalSearchRequest, SearchDocument, UpsertResult, SearchIndexInfo, SearchClientConfig, CreateIndexRequest, SyncIndexRequest, IndexInfo } from "./src/search.ts";
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * as search from "./src/search.ts";
2
+ export { searchModeSchema, searchRequestSchema, searchHitSchema, searchResultSchema, universalSearchRequestSchema, searchDocumentSchema, upsertResultSchema, searchIndexInfoSchema, searchClientConfigSchema, createIndexRequestSchema, syncIndexRequestSchema, indexInfoSchema } from "./src/search.ts";
3
+ export type { SearchMode, SearchRequest, SearchHit, SearchResult, UniversalSearchRequest, SearchDocument, UpsertResult, SearchIndexInfo, SearchClientConfig, CreateIndexRequest, SyncIndexRequest, IndexInfo } from "./src/search.ts";
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // GENERATED by projen watch - DO NOT EDIT.
2
+ // Regenerated from the exporting modules in ./src.
3
+ // Hand edits are overwritten on the next watch; this file is read-only.
4
+ export * as search from "./src/search.js";
5
+ export { searchModeSchema, searchRequestSchema, searchHitSchema, searchResultSchema, universalSearchRequestSchema, searchDocumentSchema, upsertResultSchema, searchIndexInfoSchema, searchClientConfigSchema, createIndexRequestSchema, syncIndexRequestSchema, indexInfoSchema } from "./src/search.js";
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssTUFBTSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsa0JBQWtCLEVBQUUsNEJBQTRCLEVBQUUsb0JBQW9CLEVBQUUsa0JBQWtCLEVBQUUscUJBQXFCLEVBQUUsd0JBQXdCLEVBQUUsd0JBQXdCLEVBQUUsc0JBQXNCLEVBQUUsZUFBZSxFQUFFLE1BQU0saUJBQWlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHRU5FUkFURUQgYnkgcHJvamVuIHdhdGNoIC0gRE8gTk9UIEVESVQuXG4vLyBSZWdlbmVyYXRlZCBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlcyBpbiAuL3NyYy5cbi8vIEhhbmQgZWRpdHMgYXJlIG92ZXJ3cml0dGVuIG9uIHRoZSBuZXh0IHdhdGNoOyB0aGlzIGZpbGUgaXMgcmVhZC1vbmx5LlxuXG5leHBvcnQgKiBhcyBzZWFyY2ggZnJvbSBcIi4vc3JjL3NlYXJjaC50c1wiO1xuZXhwb3J0IHsgc2VhcmNoTW9kZVNjaGVtYSwgc2VhcmNoUmVxdWVzdFNjaGVtYSwgc2VhcmNoSGl0U2NoZW1hLCBzZWFyY2hSZXN1bHRTY2hlbWEsIHVuaXZlcnNhbFNlYXJjaFJlcXVlc3RTY2hlbWEsIHNlYXJjaERvY3VtZW50U2NoZW1hLCB1cHNlcnRSZXN1bHRTY2hlbWEsIHNlYXJjaEluZGV4SW5mb1NjaGVtYSwgc2VhcmNoQ2xpZW50Q29uZmlnU2NoZW1hLCBjcmVhdGVJbmRleFJlcXVlc3RTY2hlbWEsIHN5bmNJbmRleFJlcXVlc3RTY2hlbWEsIGluZGV4SW5mb1NjaGVtYSB9IGZyb20gXCIuL3NyYy9zZWFyY2gudHNcIjtcbmV4cG9ydCB0eXBlIHsgU2VhcmNoTW9kZSwgU2VhcmNoUmVxdWVzdCwgU2VhcmNoSGl0LCBTZWFyY2hSZXN1bHQsIFVuaXZlcnNhbFNlYXJjaFJlcXVlc3QsIFNlYXJjaERvY3VtZW50LCBVcHNlcnRSZXN1bHQsIFNlYXJjaEluZGV4SW5mbywgU2VhcmNoQ2xpZW50Q29uZmlnLCBDcmVhdGVJbmRleFJlcXVlc3QsIFN5bmNJbmRleFJlcXVlc3QsIEluZGV4SW5mbyB9IGZyb20gXCIuL3NyYy9zZWFyY2gudHNcIjtcbiJdfQ==
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Wire-format contract for the AI Search add-on: the query a caller (a UI
3
+ * search box, a Mastra tool, a universal-search route) sends and the hits it
4
+ * gets back, plus the document shape used to add / update index contents.
5
+ *
6
+ * Pure (zod + inferred types, no Node-only imports) so the server-side client
7
+ * in `@dbx-tools/search`, the Mastra tool, the `POST /api/search` route,
8
+ * and the React search box all validate / type against ONE definition.
9
+ *
10
+ * "AI Search" is Databricks' current name for Vector Search: an index built
11
+ * from a Delta table (or written directly) that answers a natural-language
12
+ * query with the most relevant rows, combining vector similarity with BM25
13
+ * keyword matching (hybrid). This contract is index-agnostic - it names the
14
+ * index by its Unity Catalog path and returns hits as `{ id, score, fields }`
15
+ * so the same shape serves an autocomplete box, a docs lookup, and a
16
+ * federated search across many indexes.
17
+ *
18
+ * Array fields intentionally avoid `.min()` / `.nonempty()`: those emit
19
+ * `minItems` in the JSON schema, which some Model Serving endpoints reject
20
+ * when the schema is forwarded as a tool definition.
21
+ *
22
+ * @module
23
+ */
24
+ import { z } from "zod";
25
+ /**
26
+ * How a query is matched. `hybrid` (the default) fuses vector similarity with
27
+ * BM25 keyword ranking - the right choice for most search boxes and for source
28
+ * data with exact identifiers (SKUs, error codes). `vector` is pure semantic
29
+ * similarity; `keyword` is pure BM25 full-text (Beta on Databricks). The
30
+ * value maps onto the serving API's `query_type` (`ANN` / `HYBRID`).
31
+ */
32
+ export declare const searchModeSchema: z.ZodEnum<{
33
+ hybrid: "hybrid";
34
+ vector: "vector";
35
+ keyword: "keyword";
36
+ }>;
37
+ /** How a query is matched (see {@link searchModeSchema}). */
38
+ export type SearchMode = z.infer<typeof searchModeSchema>;
39
+ /** Schema for a search request against a single index. */
40
+ export declare const searchRequestSchema: z.ZodObject<{
41
+ query: z.ZodString;
42
+ index: z.ZodOptional<z.ZodString>;
43
+ limit: z.ZodOptional<z.ZodNumber>;
44
+ mode: z.ZodOptional<z.ZodEnum<{
45
+ hybrid: "hybrid";
46
+ vector: "vector";
47
+ keyword: "keyword";
48
+ }>>;
49
+ columns: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
+ filter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
51
+ scoreThreshold: z.ZodOptional<z.ZodNumber>;
52
+ }, z.core.$strip>;
53
+ /** A validated search request ({@link searchRequestSchema}). */
54
+ export type SearchRequest = z.infer<typeof searchRequestSchema>;
55
+ /** Schema for a single search hit. */
56
+ export declare const searchHitSchema: z.ZodObject<{
57
+ id: z.ZodString;
58
+ score: z.ZodNumber;
59
+ fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
60
+ index: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strip>;
62
+ /** A single search hit ({@link searchHitSchema}). */
63
+ export type SearchHit = z.infer<typeof searchHitSchema>;
64
+ /** Schema for the result of a search. */
65
+ export declare const searchResultSchema: z.ZodObject<{
66
+ query: z.ZodString;
67
+ hits: z.ZodArray<z.ZodObject<{
68
+ id: z.ZodString;
69
+ score: z.ZodNumber;
70
+ fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
71
+ index: z.ZodOptional<z.ZodString>;
72
+ }, z.core.$strip>>;
73
+ index: z.ZodOptional<z.ZodString>;
74
+ count: z.ZodNumber;
75
+ }, z.core.$strip>;
76
+ /** The outcome of a search ({@link searchResultSchema}). */
77
+ export type SearchResult = z.infer<typeof searchResultSchema>;
78
+ /** Schema for a universal (federated) search across several indexes at once. */
79
+ export declare const universalSearchRequestSchema: z.ZodObject<{
80
+ query: z.ZodString;
81
+ indexes: z.ZodOptional<z.ZodArray<z.ZodString>>;
82
+ limit: z.ZodOptional<z.ZodNumber>;
83
+ mode: z.ZodOptional<z.ZodEnum<{
84
+ hybrid: "hybrid";
85
+ vector: "vector";
86
+ keyword: "keyword";
87
+ }>>;
88
+ }, z.core.$strip>;
89
+ /** A validated universal-search request ({@link universalSearchRequestSchema}). */
90
+ export type UniversalSearchRequest = z.infer<typeof universalSearchRequestSchema>;
91
+ /** Schema for a document written to a direct-access index. */
92
+ export declare const searchDocumentSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
93
+ /** A document written to an index ({@link searchDocumentSchema}). */
94
+ export type SearchDocument = z.infer<typeof searchDocumentSchema>;
95
+ /** Schema for the result of adding / updating documents. */
96
+ export declare const upsertResultSchema: z.ZodObject<{
97
+ index: z.ZodString;
98
+ count: z.ZodNumber;
99
+ }, z.core.$strip>;
100
+ /** The outcome of an add-documents call ({@link upsertResultSchema}). */
101
+ export type UpsertResult = z.infer<typeof upsertResultSchema>;
102
+ /**
103
+ * Schema for the boot-time index catalogue a UI reads to populate a search box
104
+ * (the payload of the plugin's client config / `GET /api/search/indexes`). An
105
+ * entry names an index, an optional short alias, and the columns worth
106
+ * showing, so a search box needs no server round-trip to render.
107
+ */
108
+ export declare const searchIndexInfoSchema: z.ZodObject<{
109
+ name: z.ZodString;
110
+ alias: z.ZodOptional<z.ZodString>;
111
+ primaryKey: z.ZodOptional<z.ZodString>;
112
+ columns: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ isDefault: z.ZodOptional<z.ZodBoolean>;
114
+ }, z.core.$strip>;
115
+ /** One entry in the index catalogue ({@link searchIndexInfoSchema}). */
116
+ export type SearchIndexInfo = z.infer<typeof searchIndexInfoSchema>;
117
+ /** Schema for the plugin's client config surfaced to a UI. */
118
+ export declare const searchClientConfigSchema: z.ZodObject<{
119
+ indexes: z.ZodArray<z.ZodObject<{
120
+ name: z.ZodString;
121
+ alias: z.ZodOptional<z.ZodString>;
122
+ primaryKey: z.ZodOptional<z.ZodString>;
123
+ columns: z.ZodOptional<z.ZodArray<z.ZodString>>;
124
+ isDefault: z.ZodOptional<z.ZodBoolean>;
125
+ }, z.core.$strip>>;
126
+ defaultIndex: z.ZodOptional<z.ZodString>;
127
+ pageSize: z.ZodNumber;
128
+ basePath: z.ZodString;
129
+ }, z.core.$strip>;
130
+ /** The plugin's client config ({@link searchClientConfigSchema}). */
131
+ export type SearchClientConfig = z.infer<typeof searchClientConfigSchema>;
132
+ /**
133
+ * Schema for creating an index (the `create_index` tool input / the
134
+ * `POST /api/search/index` body). Two shapes, both inferring aggressively:
135
+ * pass `sourceTable` for a Delta Sync index (Databricks computes embeddings and
136
+ * keeps it synced) or `embeddingDimension` for a direct-access index you write
137
+ * vectors to yourself.
138
+ */
139
+ export declare const createIndexRequestSchema: z.ZodObject<{
140
+ name: z.ZodString;
141
+ sourceTable: z.ZodOptional<z.ZodString>;
142
+ primaryKey: z.ZodOptional<z.ZodString>;
143
+ embeddingSourceColumn: z.ZodOptional<z.ZodString>;
144
+ embeddingModel: z.ZodOptional<z.ZodString>;
145
+ endpoint: z.ZodOptional<z.ZodString>;
146
+ embeddingDimension: z.ZodOptional<z.ZodNumber>;
147
+ pipelineType: z.ZodOptional<z.ZodEnum<{
148
+ TRIGGERED: "TRIGGERED";
149
+ CONTINUOUS: "CONTINUOUS";
150
+ }>>;
151
+ columnsToSync: z.ZodOptional<z.ZodArray<z.ZodString>>;
152
+ }, z.core.$strip>;
153
+ /** A validated create-index request ({@link createIndexRequestSchema}). */
154
+ export type CreateIndexRequest = z.infer<typeof createIndexRequestSchema>;
155
+ /** Schema for the `sync_index` tool input / the `POST /api/search/index/sync` body. */
156
+ export declare const syncIndexRequestSchema: z.ZodObject<{
157
+ index: z.ZodOptional<z.ZodString>;
158
+ }, z.core.$strip>;
159
+ /** A validated sync-index request ({@link syncIndexRequestSchema}). */
160
+ export type SyncIndexRequest = z.infer<typeof syncIndexRequestSchema>;
161
+ /** Schema for a resolved index definition (the create/get result). */
162
+ export declare const indexInfoSchema: z.ZodObject<{
163
+ name: z.ZodString;
164
+ endpoint: z.ZodOptional<z.ZodString>;
165
+ primaryKey: z.ZodOptional<z.ZodString>;
166
+ columns: z.ZodArray<z.ZodString>;
167
+ ready: z.ZodBoolean;
168
+ rowCount: z.ZodOptional<z.ZodNumber>;
169
+ }, z.core.$strip>;
170
+ /** A resolved index definition ({@link indexInfoSchema}). */
171
+ export type IndexInfo = z.infer<typeof indexInfoSchema>;
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Wire-format contract for the AI Search add-on: the query a caller (a UI
3
+ * search box, a Mastra tool, a universal-search route) sends and the hits it
4
+ * gets back, plus the document shape used to add / update index contents.
5
+ *
6
+ * Pure (zod + inferred types, no Node-only imports) so the server-side client
7
+ * in `@dbx-tools/search`, the Mastra tool, the `POST /api/search` route,
8
+ * and the React search box all validate / type against ONE definition.
9
+ *
10
+ * "AI Search" is Databricks' current name for Vector Search: an index built
11
+ * from a Delta table (or written directly) that answers a natural-language
12
+ * query with the most relevant rows, combining vector similarity with BM25
13
+ * keyword matching (hybrid). This contract is index-agnostic - it names the
14
+ * index by its Unity Catalog path and returns hits as `{ id, score, fields }`
15
+ * so the same shape serves an autocomplete box, a docs lookup, and a
16
+ * federated search across many indexes.
17
+ *
18
+ * Array fields intentionally avoid `.min()` / `.nonempty()`: those emit
19
+ * `minItems` in the JSON schema, which some Model Serving endpoints reject
20
+ * when the schema is forwarded as a tool definition.
21
+ *
22
+ * @module
23
+ */
24
+ import { z } from "zod";
25
+ /**
26
+ * How a query is matched. `hybrid` (the default) fuses vector similarity with
27
+ * BM25 keyword ranking - the right choice for most search boxes and for source
28
+ * data with exact identifiers (SKUs, error codes). `vector` is pure semantic
29
+ * similarity; `keyword` is pure BM25 full-text (Beta on Databricks). The
30
+ * value maps onto the serving API's `query_type` (`ANN` / `HYBRID`).
31
+ */
32
+ export const searchModeSchema = z
33
+ .enum(["hybrid", "vector", "keyword"])
34
+ .describe("Match strategy: 'hybrid' fuses semantic similarity with keyword ranking (default, best for most searches), 'vector' is pure semantic, 'keyword' is pure full-text.");
35
+ /** Schema for a search request against a single index. */
36
+ export const searchRequestSchema = z.object({
37
+ query: z
38
+ .string()
39
+ .describe("What to search for, as natural language or keywords. Prefix fragments work for autocomplete."),
40
+ index: z
41
+ .string()
42
+ .optional()
43
+ .describe("Unity Catalog name of the index to search (catalog.schema.index). Defaults to the plugin's configured index. Accepts a short alias when one is configured."),
44
+ limit: z
45
+ .number()
46
+ .int()
47
+ .positive()
48
+ .optional()
49
+ .describe("Maximum number of hits to return. Defaults to the plugin's configured page size."),
50
+ mode: searchModeSchema.optional(),
51
+ columns: z
52
+ .array(z.string())
53
+ .optional()
54
+ .describe("Which document columns to return per hit. Defaults to the plugin's configured columns (or all indexed columns)."),
55
+ filter: z
56
+ .record(z.string(), z.unknown())
57
+ .optional()
58
+ .describe('Attribute filters as { column: value } (a value, or an operator map like { ">=": 10 }). Combined with AND. Maps onto the index `filters_json`.'),
59
+ scoreThreshold: z
60
+ .number()
61
+ .optional()
62
+ .describe("Drop hits whose relevance score is below this value."),
63
+ });
64
+ /** Schema for a single search hit. */
65
+ export const searchHitSchema = z.object({
66
+ id: z.string().describe("The document's primary-key value."),
67
+ score: z.number().describe("Relevance score; higher is more relevant."),
68
+ fields: z
69
+ .record(z.string(), z.unknown())
70
+ .describe("The returned columns for this document, keyed by column name."),
71
+ index: z
72
+ .string()
73
+ .optional()
74
+ .describe("Which index the hit came from (set on universal/federated results)."),
75
+ });
76
+ /** Schema for the result of a search. */
77
+ export const searchResultSchema = z.object({
78
+ query: z.string().describe("Echo of the query that was searched."),
79
+ hits: z.array(searchHitSchema).describe("Matching documents, most relevant first."),
80
+ index: z.string().optional().describe("The index searched (omitted for a universal search)."),
81
+ count: z.number().int().describe("Number of hits returned."),
82
+ });
83
+ /** Schema for a universal (federated) search across several indexes at once. */
84
+ export const universalSearchRequestSchema = z.object({
85
+ query: z.string().describe("What to search for across every configured index."),
86
+ indexes: z
87
+ .array(z.string())
88
+ .optional()
89
+ .describe("Which indexes to search. Defaults to every index the plugin knows about."),
90
+ limit: z
91
+ .number()
92
+ .int()
93
+ .positive()
94
+ .optional()
95
+ .describe("Maximum hits PER index before results are merged and re-ranked."),
96
+ mode: searchModeSchema.optional(),
97
+ });
98
+ /** Schema for a document written to a direct-access index. */
99
+ export const searchDocumentSchema = z
100
+ .record(z.string(), z.unknown())
101
+ .describe("A document as { column: value }. Must include the index primary-key column.");
102
+ /** Schema for the result of adding / updating documents. */
103
+ export const upsertResultSchema = z.object({
104
+ index: z.string().describe("The index the documents were written to."),
105
+ count: z.number().int().describe("Number of documents accepted."),
106
+ });
107
+ /**
108
+ * Schema for the boot-time index catalogue a UI reads to populate a search box
109
+ * (the payload of the plugin's client config / `GET /api/search/indexes`). An
110
+ * entry names an index, an optional short alias, and the columns worth
111
+ * showing, so a search box needs no server round-trip to render.
112
+ */
113
+ export const searchIndexInfoSchema = z.object({
114
+ name: z.string().describe("Unity Catalog name of the index (catalog.schema.index)."),
115
+ alias: z.string().optional().describe("Short alias the plugin accepts in place of `name`."),
116
+ primaryKey: z.string().optional().describe("The index's primary-key column, when known."),
117
+ columns: z
118
+ .array(z.string())
119
+ .optional()
120
+ .describe("Columns returned by default, in display order."),
121
+ isDefault: z.boolean().optional().describe("True for the plugin's default index."),
122
+ });
123
+ /** Schema for the plugin's client config surfaced to a UI. */
124
+ export const searchClientConfigSchema = z.object({
125
+ indexes: z.array(searchIndexInfoSchema).describe("Indexes the search UI may query."),
126
+ defaultIndex: z.string().optional().describe("The index a search box selects by default."),
127
+ pageSize: z.number().int().describe("Default number of hits a search returns."),
128
+ basePath: z
129
+ .string()
130
+ .describe("Base path the search routes are mounted under (e.g. /api/search)."),
131
+ });
132
+ /**
133
+ * Schema for creating an index (the `create_index` tool input / the
134
+ * `POST /api/search/index` body). Two shapes, both inferring aggressively:
135
+ * pass `sourceTable` for a Delta Sync index (Databricks computes embeddings and
136
+ * keeps it synced) or `embeddingDimension` for a direct-access index you write
137
+ * vectors to yourself.
138
+ */
139
+ export const createIndexRequestSchema = z.object({
140
+ name: z.string().describe("Unity Catalog name for the new index (catalog.schema.index)."),
141
+ sourceTable: z
142
+ .string()
143
+ .optional()
144
+ .describe("Delta table (catalog.schema.table) to build a synced index from. Provide this OR embeddingDimension."),
145
+ primaryKey: z.string().optional().describe("Primary-key column. Defaults to 'id'."),
146
+ embeddingSourceColumn: z
147
+ .string()
148
+ .optional()
149
+ .describe("Text column embeddings are computed from (Delta Sync). Defaults to the first of text/content/body."),
150
+ embeddingModel: z
151
+ .string()
152
+ .optional()
153
+ .describe("Embedding model endpoint (name or loose name). Defaults to the app's embedding model, or the best embedding endpoint in the workspace."),
154
+ endpoint: z
155
+ .string()
156
+ .optional()
157
+ .describe("Vector Search endpoint to host the index on. Defaults to the app's configured endpoint."),
158
+ embeddingDimension: z
159
+ .number()
160
+ .int()
161
+ .positive()
162
+ .optional()
163
+ .describe("For a direct-access index (no source table): the embedding vector dimension."),
164
+ pipelineType: z
165
+ .enum(["TRIGGERED", "CONTINUOUS"])
166
+ .optional()
167
+ .describe("Delta Sync mode: 'TRIGGERED' (default) syncs on demand; 'CONTINUOUS' keeps the index fresh."),
168
+ columnsToSync: z
169
+ .array(z.string())
170
+ .optional()
171
+ .describe("Extra columns to sync alongside the embedding source column (Delta Sync)."),
172
+ });
173
+ /** Schema for the `sync_index` tool input / the `POST /api/search/index/sync` body. */
174
+ export const syncIndexRequestSchema = z.object({
175
+ index: z
176
+ .string()
177
+ .describe("The index to sync (name or configured alias). Defaults to the app's default index when omitted.")
178
+ .optional(),
179
+ });
180
+ /** Schema for a resolved index definition (the create/get result). */
181
+ export const indexInfoSchema = z.object({
182
+ name: z.string().describe("Unity Catalog name of the index."),
183
+ endpoint: z.string().optional().describe("The Vector Search endpoint hosting the index."),
184
+ primaryKey: z.string().optional().describe("The index's primary-key column."),
185
+ columns: z.array(z.string()).describe("Columns available on the index."),
186
+ ready: z.boolean().describe("True when the index has finished provisioning and can be queried."),
187
+ rowCount: z.number().int().optional().describe("Number of indexed rows, when known."),
188
+ });
189
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEI7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQztLQUM5QixJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0tBQ3JDLFFBQVEsQ0FDUCxvS0FBb0ssQ0FDckssQ0FBQztBQUtKLDBEQUEwRDtBQUMxRCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzFDLEtBQUssRUFBRSxDQUFDO1NBQ0wsTUFBTSxFQUFFO1NBQ1IsUUFBUSxDQUNQLDhGQUE4RixDQUMvRjtJQUNILEtBQUssRUFBRSxDQUFDO1NBQ0wsTUFBTSxFQUFFO1NBQ1IsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUNQLDRKQUE0SixDQUM3SjtJQUNILEtBQUssRUFBRSxDQUFDO1NBQ0wsTUFBTSxFQUFFO1NBQ1IsR0FBRyxFQUFFO1NBQ0wsUUFBUSxFQUFFO1NBQ1YsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUFDLGtGQUFrRixDQUFDO0lBQy9GLElBQUksRUFBRSxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUU7SUFDakMsT0FBTyxFQUFFLENBQUM7U0FDUCxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO1NBQ2pCLFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FDUCxpSEFBaUgsQ0FDbEg7SUFDSCxNQUFNLEVBQUUsQ0FBQztTQUNOLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1NBQy9CLFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FDUCxnSkFBZ0osQ0FDako7SUFDSCxjQUFjLEVBQUUsQ0FBQztTQUNkLE1BQU0sRUFBRTtTQUNSLFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FBQyxzREFBc0QsQ0FBQztDQUNwRSxDQUFDLENBQUM7QUFLSCxzQ0FBc0M7QUFDdEMsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDdEMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsbUNBQW1DLENBQUM7SUFDNUQsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsMkNBQTJDLENBQUM7SUFDdkUsTUFBTSxFQUFFLENBQUM7U0FDTixNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztTQUMvQixRQUFRLENBQUMsK0RBQStELENBQUM7SUFDNUUsS0FBSyxFQUFFLENBQUM7U0FDTCxNQUFNLEVBQUU7U0FDUixRQUFRLEVBQUU7U0FDVixRQUFRLENBQUMscUVBQXFFLENBQUM7Q0FDbkYsQ0FBQyxDQUFDO0FBS0gseUNBQXlDO0FBQ3pDLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDekMsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsc0NBQXNDLENBQUM7SUFDbEUsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxDQUFDLDBDQUEwQyxDQUFDO0lBQ25GLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLHNEQUFzRCxDQUFDO0lBQzdGLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLDBCQUEwQixDQUFDO0NBQzdELENBQUMsQ0FBQztBQUtILGdGQUFnRjtBQUNoRixNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ25ELEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLG1EQUFtRCxDQUFDO0lBQy9FLE9BQU8sRUFBRSxDQUFDO1NBQ1AsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztTQUNqQixRQUFRLEVBQUU7U0FDVixRQUFRLENBQUMsMEVBQTBFLENBQUM7SUFDdkYsS0FBSyxFQUFFLENBQUM7U0FDTCxNQUFNLEVBQUU7U0FDUixHQUFHLEVBQUU7U0FDTCxRQUFRLEVBQUU7U0FDVixRQUFRLEVBQUU7U0FDVixRQUFRLENBQUMsaUVBQWlFLENBQUM7SUFDOUUsSUFBSSxFQUFFLGdCQUFnQixDQUFDLFFBQVEsRUFBRTtDQUNsQyxDQUFDLENBQUM7QUFLSCw4REFBOEQ7QUFDOUQsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQztLQUNsQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztLQUMvQixRQUFRLENBQUMsNkVBQTZFLENBQUMsQ0FBQztBQUszRiw0REFBNEQ7QUFDNUQsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN6QyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQywwQ0FBMEMsQ0FBQztJQUN0RSxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQywrQkFBK0IsQ0FBQztDQUNsRSxDQUFDLENBQUM7QUFLSDs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDNUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMseURBQXlELENBQUM7SUFDcEYsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsb0RBQW9ELENBQUM7SUFDM0YsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsNkNBQTZDLENBQUM7SUFDekYsT0FBTyxFQUFFLENBQUM7U0FDUCxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO1NBQ2pCLFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FBQyxnREFBZ0QsQ0FBQztJQUM3RCxTQUFTLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztDQUNuRixDQUFDLENBQUM7QUFLSCw4REFBOEQ7QUFDOUQsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUMvQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxrQ0FBa0MsQ0FBQztJQUNwRixZQUFZLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyw0Q0FBNEMsQ0FBQztJQUMxRixRQUFRLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQywwQ0FBMEMsQ0FBQztJQUMvRSxRQUFRLEVBQUUsQ0FBQztTQUNSLE1BQU0sRUFBRTtTQUNSLFFBQVEsQ0FBQyxtRUFBbUUsQ0FBQztDQUNqRixDQUFDLENBQUM7QUFLSDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQy9DLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLDhEQUE4RCxDQUFDO0lBQ3pGLFdBQVcsRUFBRSxDQUFDO1NBQ1gsTUFBTSxFQUFFO1NBQ1IsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUNQLHNHQUFzRyxDQUN2RztJQUNILFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLHVDQUF1QyxDQUFDO0lBQ25GLHFCQUFxQixFQUFFLENBQUM7U0FDckIsTUFBTSxFQUFFO1NBQ1IsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUNQLG9HQUFvRyxDQUNyRztJQUNILGNBQWMsRUFBRSxDQUFDO1NBQ2QsTUFBTSxFQUFFO1NBQ1IsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUNQLHdJQUF3SSxDQUN6STtJQUNILFFBQVEsRUFBRSxDQUFDO1NBQ1IsTUFBTSxFQUFFO1NBQ1IsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUNQLHlGQUF5RixDQUMxRjtJQUNILGtCQUFrQixFQUFFLENBQUM7U0FDbEIsTUFBTSxFQUFFO1NBQ1IsR0FBRyxFQUFFO1NBQ0wsUUFBUSxFQUFFO1NBQ1YsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUFDLDhFQUE4RSxDQUFDO0lBQzNGLFlBQVksRUFBRSxDQUFDO1NBQ1osSUFBSSxDQUFDLENBQUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxDQUFDO1NBQ2pDLFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FDUCw2RkFBNkYsQ0FDOUY7SUFDSCxhQUFhLEVBQUUsQ0FBQztTQUNiLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7U0FDakIsUUFBUSxFQUFFO1NBQ1YsUUFBUSxDQUFDLDJFQUEyRSxDQUFDO0NBQ3pGLENBQUMsQ0FBQztBQUtILHVGQUF1RjtBQUN2RixNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzdDLEtBQUssRUFBRSxDQUFDO1NBQ0wsTUFBTSxFQUFFO1NBQ1IsUUFBUSxDQUNQLGlHQUFpRyxDQUNsRztTQUNBLFFBQVEsRUFBRTtDQUNkLENBQUMsQ0FBQztBQUtILHNFQUFzRTtBQUN0RSxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN0QyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxrQ0FBa0MsQ0FBQztJQUM3RCxRQUFRLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQywrQ0FBK0MsQ0FBQztJQUN6RixVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxpQ0FBaUMsQ0FBQztJQUM3RSxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsaUNBQWlDLENBQUM7SUFDeEUsS0FBSyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsbUVBQW1FLENBQUM7SUFDaEcsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMscUNBQXFDLENBQUM7Q0FDdEYsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXaXJlLWZvcm1hdCBjb250cmFjdCBmb3IgdGhlIEFJIFNlYXJjaCBhZGQtb246IHRoZSBxdWVyeSBhIGNhbGxlciAoYSBVSVxuICogc2VhcmNoIGJveCwgYSBNYXN0cmEgdG9vbCwgYSB1bml2ZXJzYWwtc2VhcmNoIHJvdXRlKSBzZW5kcyBhbmQgdGhlIGhpdHMgaXRcbiAqIGdldHMgYmFjaywgcGx1cyB0aGUgZG9jdW1lbnQgc2hhcGUgdXNlZCB0byBhZGQgLyB1cGRhdGUgaW5kZXggY29udGVudHMuXG4gKlxuICogUHVyZSAoem9kICsgaW5mZXJyZWQgdHlwZXMsIG5vIE5vZGUtb25seSBpbXBvcnRzKSBzbyB0aGUgc2VydmVyLXNpZGUgY2xpZW50XG4gKiBpbiBgQGRieC10b29scy9zZWFyY2hgLCB0aGUgTWFzdHJhIHRvb2wsIHRoZSBgUE9TVCAvYXBpL3NlYXJjaGAgcm91dGUsXG4gKiBhbmQgdGhlIFJlYWN0IHNlYXJjaCBib3ggYWxsIHZhbGlkYXRlIC8gdHlwZSBhZ2FpbnN0IE9ORSBkZWZpbml0aW9uLlxuICpcbiAqIFwiQUkgU2VhcmNoXCIgaXMgRGF0YWJyaWNrcycgY3VycmVudCBuYW1lIGZvciBWZWN0b3IgU2VhcmNoOiBhbiBpbmRleCBidWlsdFxuICogZnJvbSBhIERlbHRhIHRhYmxlIChvciB3cml0dGVuIGRpcmVjdGx5KSB0aGF0IGFuc3dlcnMgYSBuYXR1cmFsLWxhbmd1YWdlXG4gKiBxdWVyeSB3aXRoIHRoZSBtb3N0IHJlbGV2YW50IHJvd3MsIGNvbWJpbmluZyB2ZWN0b3Igc2ltaWxhcml0eSB3aXRoIEJNMjVcbiAqIGtleXdvcmQgbWF0Y2hpbmcgKGh5YnJpZCkuIFRoaXMgY29udHJhY3QgaXMgaW5kZXgtYWdub3N0aWMgLSBpdCBuYW1lcyB0aGVcbiAqIGluZGV4IGJ5IGl0cyBVbml0eSBDYXRhbG9nIHBhdGggYW5kIHJldHVybnMgaGl0cyBhcyBgeyBpZCwgc2NvcmUsIGZpZWxkcyB9YFxuICogc28gdGhlIHNhbWUgc2hhcGUgc2VydmVzIGFuIGF1dG9jb21wbGV0ZSBib3gsIGEgZG9jcyBsb29rdXAsIGFuZCBhXG4gKiBmZWRlcmF0ZWQgc2VhcmNoIGFjcm9zcyBtYW55IGluZGV4ZXMuXG4gKlxuICogQXJyYXkgZmllbGRzIGludGVudGlvbmFsbHkgYXZvaWQgYC5taW4oKWAgLyBgLm5vbmVtcHR5KClgOiB0aG9zZSBlbWl0XG4gKiBgbWluSXRlbXNgIGluIHRoZSBKU09OIHNjaGVtYSwgd2hpY2ggc29tZSBNb2RlbCBTZXJ2aW5nIGVuZHBvaW50cyByZWplY3RcbiAqIHdoZW4gdGhlIHNjaGVtYSBpcyBmb3J3YXJkZWQgYXMgYSB0b29sIGRlZmluaXRpb24uXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbi8qKlxuICogSG93IGEgcXVlcnkgaXMgbWF0Y2hlZC4gYGh5YnJpZGAgKHRoZSBkZWZhdWx0KSBmdXNlcyB2ZWN0b3Igc2ltaWxhcml0eSB3aXRoXG4gKiBCTTI1IGtleXdvcmQgcmFua2luZyAtIHRoZSByaWdodCBjaG9pY2UgZm9yIG1vc3Qgc2VhcmNoIGJveGVzIGFuZCBmb3Igc291cmNlXG4gKiBkYXRhIHdpdGggZXhhY3QgaWRlbnRpZmllcnMgKFNLVXMsIGVycm9yIGNvZGVzKS4gYHZlY3RvcmAgaXMgcHVyZSBzZW1hbnRpY1xuICogc2ltaWxhcml0eTsgYGtleXdvcmRgIGlzIHB1cmUgQk0yNSBmdWxsLXRleHQgKEJldGEgb24gRGF0YWJyaWNrcykuIFRoZVxuICogdmFsdWUgbWFwcyBvbnRvIHRoZSBzZXJ2aW5nIEFQSSdzIGBxdWVyeV90eXBlYCAoYEFOTmAgLyBgSFlCUklEYCkuXG4gKi9cbmV4cG9ydCBjb25zdCBzZWFyY2hNb2RlU2NoZW1hID0gelxuICAuZW51bShbXCJoeWJyaWRcIiwgXCJ2ZWN0b3JcIiwgXCJrZXl3b3JkXCJdKVxuICAuZGVzY3JpYmUoXG4gICAgXCJNYXRjaCBzdHJhdGVneTogJ2h5YnJpZCcgZnVzZXMgc2VtYW50aWMgc2ltaWxhcml0eSB3aXRoIGtleXdvcmQgcmFua2luZyAoZGVmYXVsdCwgYmVzdCBmb3IgbW9zdCBzZWFyY2hlcyksICd2ZWN0b3InIGlzIHB1cmUgc2VtYW50aWMsICdrZXl3b3JkJyBpcyBwdXJlIGZ1bGwtdGV4dC5cIixcbiAgKTtcblxuLyoqIEhvdyBhIHF1ZXJ5IGlzIG1hdGNoZWQgKHNlZSB7QGxpbmsgc2VhcmNoTW9kZVNjaGVtYX0pLiAqL1xuZXhwb3J0IHR5cGUgU2VhcmNoTW9kZSA9IHouaW5mZXI8dHlwZW9mIHNlYXJjaE1vZGVTY2hlbWE+O1xuXG4vKiogU2NoZW1hIGZvciBhIHNlYXJjaCByZXF1ZXN0IGFnYWluc3QgYSBzaW5nbGUgaW5kZXguICovXG5leHBvcnQgY29uc3Qgc2VhcmNoUmVxdWVzdFNjaGVtYSA9IHoub2JqZWN0KHtcbiAgcXVlcnk6IHpcbiAgICAuc3RyaW5nKClcbiAgICAuZGVzY3JpYmUoXG4gICAgICBcIldoYXQgdG8gc2VhcmNoIGZvciwgYXMgbmF0dXJhbCBsYW5ndWFnZSBvciBrZXl3b3Jkcy4gUHJlZml4IGZyYWdtZW50cyB3b3JrIGZvciBhdXRvY29tcGxldGUuXCIsXG4gICAgKSxcbiAgaW5kZXg6IHpcbiAgICAuc3RyaW5nKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIFwiVW5pdHkgQ2F0YWxvZyBuYW1lIG9mIHRoZSBpbmRleCB0byBzZWFyY2ggKGNhdGFsb2cuc2NoZW1hLmluZGV4KS4gRGVmYXVsdHMgdG8gdGhlIHBsdWdpbidzIGNvbmZpZ3VyZWQgaW5kZXguIEFjY2VwdHMgYSBzaG9ydCBhbGlhcyB3aGVuIG9uZSBpcyBjb25maWd1cmVkLlwiLFxuICAgICksXG4gIGxpbWl0OiB6XG4gICAgLm51bWJlcigpXG4gICAgLmludCgpXG4gICAgLnBvc2l0aXZlKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcIk1heGltdW0gbnVtYmVyIG9mIGhpdHMgdG8gcmV0dXJuLiBEZWZhdWx0cyB0byB0aGUgcGx1Z2luJ3MgY29uZmlndXJlZCBwYWdlIHNpemUuXCIpLFxuICBtb2RlOiBzZWFyY2hNb2RlU2NoZW1hLm9wdGlvbmFsKCksXG4gIGNvbHVtbnM6IHpcbiAgICAuYXJyYXkoei5zdHJpbmcoKSlcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIFwiV2hpY2ggZG9jdW1lbnQgY29sdW1ucyB0byByZXR1cm4gcGVyIGhpdC4gRGVmYXVsdHMgdG8gdGhlIHBsdWdpbidzIGNvbmZpZ3VyZWQgY29sdW1ucyAob3IgYWxsIGluZGV4ZWQgY29sdW1ucykuXCIsXG4gICAgKSxcbiAgZmlsdGVyOiB6XG4gICAgLnJlY29yZCh6LnN0cmluZygpLCB6LnVua25vd24oKSlcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgICdBdHRyaWJ1dGUgZmlsdGVycyBhcyB7IGNvbHVtbjogdmFsdWUgfSAoYSB2YWx1ZSwgb3IgYW4gb3BlcmF0b3IgbWFwIGxpa2UgeyBcIj49XCI6IDEwIH0pLiBDb21iaW5lZCB3aXRoIEFORC4gTWFwcyBvbnRvIHRoZSBpbmRleCBgZmlsdGVyc19qc29uYC4nLFxuICAgICksXG4gIHNjb3JlVGhyZXNob2xkOiB6XG4gICAgLm51bWJlcigpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXCJEcm9wIGhpdHMgd2hvc2UgcmVsZXZhbmNlIHNjb3JlIGlzIGJlbG93IHRoaXMgdmFsdWUuXCIpLFxufSk7XG5cbi8qKiBBIHZhbGlkYXRlZCBzZWFyY2ggcmVxdWVzdCAoe0BsaW5rIHNlYXJjaFJlcXVlc3RTY2hlbWF9KS4gKi9cbmV4cG9ydCB0eXBlIFNlYXJjaFJlcXVlc3QgPSB6LmluZmVyPHR5cGVvZiBzZWFyY2hSZXF1ZXN0U2NoZW1hPjtcblxuLyoqIFNjaGVtYSBmb3IgYSBzaW5nbGUgc2VhcmNoIGhpdC4gKi9cbmV4cG9ydCBjb25zdCBzZWFyY2hIaXRTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGlkOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVGhlIGRvY3VtZW50J3MgcHJpbWFyeS1rZXkgdmFsdWUuXCIpLFxuICBzY29yZTogei5udW1iZXIoKS5kZXNjcmliZShcIlJlbGV2YW5jZSBzY29yZTsgaGlnaGVyIGlzIG1vcmUgcmVsZXZhbnQuXCIpLFxuICBmaWVsZHM6IHpcbiAgICAucmVjb3JkKHouc3RyaW5nKCksIHoudW5rbm93bigpKVxuICAgIC5kZXNjcmliZShcIlRoZSByZXR1cm5lZCBjb2x1bW5zIGZvciB0aGlzIGRvY3VtZW50LCBrZXllZCBieSBjb2x1bW4gbmFtZS5cIiksXG4gIGluZGV4OiB6XG4gICAgLnN0cmluZygpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXCJXaGljaCBpbmRleCB0aGUgaGl0IGNhbWUgZnJvbSAoc2V0IG9uIHVuaXZlcnNhbC9mZWRlcmF0ZWQgcmVzdWx0cykuXCIpLFxufSk7XG5cbi8qKiBBIHNpbmdsZSBzZWFyY2ggaGl0ICh7QGxpbmsgc2VhcmNoSGl0U2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBTZWFyY2hIaXQgPSB6LmluZmVyPHR5cGVvZiBzZWFyY2hIaXRTY2hlbWE+O1xuXG4vKiogU2NoZW1hIGZvciB0aGUgcmVzdWx0IG9mIGEgc2VhcmNoLiAqL1xuZXhwb3J0IGNvbnN0IHNlYXJjaFJlc3VsdFNjaGVtYSA9IHoub2JqZWN0KHtcbiAgcXVlcnk6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJFY2hvIG9mIHRoZSBxdWVyeSB0aGF0IHdhcyBzZWFyY2hlZC5cIiksXG4gIGhpdHM6IHouYXJyYXkoc2VhcmNoSGl0U2NoZW1hKS5kZXNjcmliZShcIk1hdGNoaW5nIGRvY3VtZW50cywgbW9zdCByZWxldmFudCBmaXJzdC5cIiksXG4gIGluZGV4OiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJUaGUgaW5kZXggc2VhcmNoZWQgKG9taXR0ZWQgZm9yIGEgdW5pdmVyc2FsIHNlYXJjaCkuXCIpLFxuICBjb3VudDogei5udW1iZXIoKS5pbnQoKS5kZXNjcmliZShcIk51bWJlciBvZiBoaXRzIHJldHVybmVkLlwiKSxcbn0pO1xuXG4vKiogVGhlIG91dGNvbWUgb2YgYSBzZWFyY2ggKHtAbGluayBzZWFyY2hSZXN1bHRTY2hlbWF9KS4gKi9cbmV4cG9ydCB0eXBlIFNlYXJjaFJlc3VsdCA9IHouaW5mZXI8dHlwZW9mIHNlYXJjaFJlc3VsdFNjaGVtYT47XG5cbi8qKiBTY2hlbWEgZm9yIGEgdW5pdmVyc2FsIChmZWRlcmF0ZWQpIHNlYXJjaCBhY3Jvc3Mgc2V2ZXJhbCBpbmRleGVzIGF0IG9uY2UuICovXG5leHBvcnQgY29uc3QgdW5pdmVyc2FsU2VhcmNoUmVxdWVzdFNjaGVtYSA9IHoub2JqZWN0KHtcbiAgcXVlcnk6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJXaGF0IHRvIHNlYXJjaCBmb3IgYWNyb3NzIGV2ZXJ5IGNvbmZpZ3VyZWQgaW5kZXguXCIpLFxuICBpbmRleGVzOiB6XG4gICAgLmFycmF5KHouc3RyaW5nKCkpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXCJXaGljaCBpbmRleGVzIHRvIHNlYXJjaC4gRGVmYXVsdHMgdG8gZXZlcnkgaW5kZXggdGhlIHBsdWdpbiBrbm93cyBhYm91dC5cIiksXG4gIGxpbWl0OiB6XG4gICAgLm51bWJlcigpXG4gICAgLmludCgpXG4gICAgLnBvc2l0aXZlKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcIk1heGltdW0gaGl0cyBQRVIgaW5kZXggYmVmb3JlIHJlc3VsdHMgYXJlIG1lcmdlZCBhbmQgcmUtcmFua2VkLlwiKSxcbiAgbW9kZTogc2VhcmNoTW9kZVNjaGVtYS5vcHRpb25hbCgpLFxufSk7XG5cbi8qKiBBIHZhbGlkYXRlZCB1bml2ZXJzYWwtc2VhcmNoIHJlcXVlc3QgKHtAbGluayB1bml2ZXJzYWxTZWFyY2hSZXF1ZXN0U2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBVbml2ZXJzYWxTZWFyY2hSZXF1ZXN0ID0gei5pbmZlcjx0eXBlb2YgdW5pdmVyc2FsU2VhcmNoUmVxdWVzdFNjaGVtYT47XG5cbi8qKiBTY2hlbWEgZm9yIGEgZG9jdW1lbnQgd3JpdHRlbiB0byBhIGRpcmVjdC1hY2Nlc3MgaW5kZXguICovXG5leHBvcnQgY29uc3Qgc2VhcmNoRG9jdW1lbnRTY2hlbWEgPSB6XG4gIC5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpXG4gIC5kZXNjcmliZShcIkEgZG9jdW1lbnQgYXMgeyBjb2x1bW46IHZhbHVlIH0uIE11c3QgaW5jbHVkZSB0aGUgaW5kZXggcHJpbWFyeS1rZXkgY29sdW1uLlwiKTtcblxuLyoqIEEgZG9jdW1lbnQgd3JpdHRlbiB0byBhbiBpbmRleCAoe0BsaW5rIHNlYXJjaERvY3VtZW50U2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBTZWFyY2hEb2N1bWVudCA9IHouaW5mZXI8dHlwZW9mIHNlYXJjaERvY3VtZW50U2NoZW1hPjtcblxuLyoqIFNjaGVtYSBmb3IgdGhlIHJlc3VsdCBvZiBhZGRpbmcgLyB1cGRhdGluZyBkb2N1bWVudHMuICovXG5leHBvcnQgY29uc3QgdXBzZXJ0UmVzdWx0U2NoZW1hID0gei5vYmplY3Qoe1xuICBpbmRleDogei5zdHJpbmcoKS5kZXNjcmliZShcIlRoZSBpbmRleCB0aGUgZG9jdW1lbnRzIHdlcmUgd3JpdHRlbiB0by5cIiksXG4gIGNvdW50OiB6Lm51bWJlcigpLmludCgpLmRlc2NyaWJlKFwiTnVtYmVyIG9mIGRvY3VtZW50cyBhY2NlcHRlZC5cIiksXG59KTtcblxuLyoqIFRoZSBvdXRjb21lIG9mIGFuIGFkZC1kb2N1bWVudHMgY2FsbCAoe0BsaW5rIHVwc2VydFJlc3VsdFNjaGVtYX0pLiAqL1xuZXhwb3J0IHR5cGUgVXBzZXJ0UmVzdWx0ID0gei5pbmZlcjx0eXBlb2YgdXBzZXJ0UmVzdWx0U2NoZW1hPjtcblxuLyoqXG4gKiBTY2hlbWEgZm9yIHRoZSBib290LXRpbWUgaW5kZXggY2F0YWxvZ3VlIGEgVUkgcmVhZHMgdG8gcG9wdWxhdGUgYSBzZWFyY2ggYm94XG4gKiAodGhlIHBheWxvYWQgb2YgdGhlIHBsdWdpbidzIGNsaWVudCBjb25maWcgLyBgR0VUIC9hcGkvc2VhcmNoL2luZGV4ZXNgKS4gQW5cbiAqIGVudHJ5IG5hbWVzIGFuIGluZGV4LCBhbiBvcHRpb25hbCBzaG9ydCBhbGlhcywgYW5kIHRoZSBjb2x1bW5zIHdvcnRoXG4gKiBzaG93aW5nLCBzbyBhIHNlYXJjaCBib3ggbmVlZHMgbm8gc2VydmVyIHJvdW5kLXRyaXAgdG8gcmVuZGVyLlxuICovXG5leHBvcnQgY29uc3Qgc2VhcmNoSW5kZXhJbmZvU2NoZW1hID0gei5vYmplY3Qoe1xuICBuYW1lOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVW5pdHkgQ2F0YWxvZyBuYW1lIG9mIHRoZSBpbmRleCAoY2F0YWxvZy5zY2hlbWEuaW5kZXgpLlwiKSxcbiAgYWxpYXM6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIlNob3J0IGFsaWFzIHRoZSBwbHVnaW4gYWNjZXB0cyBpbiBwbGFjZSBvZiBgbmFtZWAuXCIpLFxuICBwcmltYXJ5S2V5OiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJUaGUgaW5kZXgncyBwcmltYXJ5LWtleSBjb2x1bW4sIHdoZW4ga25vd24uXCIpLFxuICBjb2x1bW5zOiB6XG4gICAgLmFycmF5KHouc3RyaW5nKCkpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXCJDb2x1bW5zIHJldHVybmVkIGJ5IGRlZmF1bHQsIGluIGRpc3BsYXkgb3JkZXIuXCIpLFxuICBpc0RlZmF1bHQ6IHouYm9vbGVhbigpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJUcnVlIGZvciB0aGUgcGx1Z2luJ3MgZGVmYXVsdCBpbmRleC5cIiksXG59KTtcblxuLyoqIE9uZSBlbnRyeSBpbiB0aGUgaW5kZXggY2F0YWxvZ3VlICh7QGxpbmsgc2VhcmNoSW5kZXhJbmZvU2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBTZWFyY2hJbmRleEluZm8gPSB6LmluZmVyPHR5cGVvZiBzZWFyY2hJbmRleEluZm9TY2hlbWE+O1xuXG4vKiogU2NoZW1hIGZvciB0aGUgcGx1Z2luJ3MgY2xpZW50IGNvbmZpZyBzdXJmYWNlZCB0byBhIFVJLiAqL1xuZXhwb3J0IGNvbnN0IHNlYXJjaENsaWVudENvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgaW5kZXhlczogei5hcnJheShzZWFyY2hJbmRleEluZm9TY2hlbWEpLmRlc2NyaWJlKFwiSW5kZXhlcyB0aGUgc2VhcmNoIFVJIG1heSBxdWVyeS5cIiksXG4gIGRlZmF1bHRJbmRleDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiVGhlIGluZGV4IGEgc2VhcmNoIGJveCBzZWxlY3RzIGJ5IGRlZmF1bHQuXCIpLFxuICBwYWdlU2l6ZTogei5udW1iZXIoKS5pbnQoKS5kZXNjcmliZShcIkRlZmF1bHQgbnVtYmVyIG9mIGhpdHMgYSBzZWFyY2ggcmV0dXJucy5cIiksXG4gIGJhc2VQYXRoOiB6XG4gICAgLnN0cmluZygpXG4gICAgLmRlc2NyaWJlKFwiQmFzZSBwYXRoIHRoZSBzZWFyY2ggcm91dGVzIGFyZSBtb3VudGVkIHVuZGVyIChlLmcuIC9hcGkvc2VhcmNoKS5cIiksXG59KTtcblxuLyoqIFRoZSBwbHVnaW4ncyBjbGllbnQgY29uZmlnICh7QGxpbmsgc2VhcmNoQ2xpZW50Q29uZmlnU2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBTZWFyY2hDbGllbnRDb25maWcgPSB6LmluZmVyPHR5cGVvZiBzZWFyY2hDbGllbnRDb25maWdTY2hlbWE+O1xuXG4vKipcbiAqIFNjaGVtYSBmb3IgY3JlYXRpbmcgYW4gaW5kZXggKHRoZSBgY3JlYXRlX2luZGV4YCB0b29sIGlucHV0IC8gdGhlXG4gKiBgUE9TVCAvYXBpL3NlYXJjaC9pbmRleGAgYm9keSkuIFR3byBzaGFwZXMsIGJvdGggaW5mZXJyaW5nIGFnZ3Jlc3NpdmVseTpcbiAqIHBhc3MgYHNvdXJjZVRhYmxlYCBmb3IgYSBEZWx0YSBTeW5jIGluZGV4IChEYXRhYnJpY2tzIGNvbXB1dGVzIGVtYmVkZGluZ3MgYW5kXG4gKiBrZWVwcyBpdCBzeW5jZWQpIG9yIGBlbWJlZGRpbmdEaW1lbnNpb25gIGZvciBhIGRpcmVjdC1hY2Nlc3MgaW5kZXggeW91IHdyaXRlXG4gKiB2ZWN0b3JzIHRvIHlvdXJzZWxmLlxuICovXG5leHBvcnQgY29uc3QgY3JlYXRlSW5kZXhSZXF1ZXN0U2NoZW1hID0gei5vYmplY3Qoe1xuICBuYW1lOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVW5pdHkgQ2F0YWxvZyBuYW1lIGZvciB0aGUgbmV3IGluZGV4IChjYXRhbG9nLnNjaGVtYS5pbmRleCkuXCIpLFxuICBzb3VyY2VUYWJsZTogelxuICAgIC5zdHJpbmcoKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgXCJEZWx0YSB0YWJsZSAoY2F0YWxvZy5zY2hlbWEudGFibGUpIHRvIGJ1aWxkIGEgc3luY2VkIGluZGV4IGZyb20uIFByb3ZpZGUgdGhpcyBPUiBlbWJlZGRpbmdEaW1lbnNpb24uXCIsXG4gICAgKSxcbiAgcHJpbWFyeUtleTogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiUHJpbWFyeS1rZXkgY29sdW1uLiBEZWZhdWx0cyB0byAnaWQnLlwiKSxcbiAgZW1iZWRkaW5nU291cmNlQ29sdW1uOiB6XG4gICAgLnN0cmluZygpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXG4gICAgICBcIlRleHQgY29sdW1uIGVtYmVkZGluZ3MgYXJlIGNvbXB1dGVkIGZyb20gKERlbHRhIFN5bmMpLiBEZWZhdWx0cyB0byB0aGUgZmlyc3Qgb2YgdGV4dC9jb250ZW50L2JvZHkuXCIsXG4gICAgKSxcbiAgZW1iZWRkaW5nTW9kZWw6IHpcbiAgICAuc3RyaW5nKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIFwiRW1iZWRkaW5nIG1vZGVsIGVuZHBvaW50IChuYW1lIG9yIGxvb3NlIG5hbWUpLiBEZWZhdWx0cyB0byB0aGUgYXBwJ3MgZW1iZWRkaW5nIG1vZGVsLCBvciB0aGUgYmVzdCBlbWJlZGRpbmcgZW5kcG9pbnQgaW4gdGhlIHdvcmtzcGFjZS5cIixcbiAgICApLFxuICBlbmRwb2ludDogelxuICAgIC5zdHJpbmcoKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgXCJWZWN0b3IgU2VhcmNoIGVuZHBvaW50IHRvIGhvc3QgdGhlIGluZGV4IG9uLiBEZWZhdWx0cyB0byB0aGUgYXBwJ3MgY29uZmlndXJlZCBlbmRwb2ludC5cIixcbiAgICApLFxuICBlbWJlZGRpbmdEaW1lbnNpb246IHpcbiAgICAubnVtYmVyKClcbiAgICAuaW50KClcbiAgICAucG9zaXRpdmUoKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFwiRm9yIGEgZGlyZWN0LWFjY2VzcyBpbmRleCAobm8gc291cmNlIHRhYmxlKTogdGhlIGVtYmVkZGluZyB2ZWN0b3IgZGltZW5zaW9uLlwiKSxcbiAgcGlwZWxpbmVUeXBlOiB6XG4gICAgLmVudW0oW1wiVFJJR0dFUkVEXCIsIFwiQ09OVElOVU9VU1wiXSlcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIFwiRGVsdGEgU3luYyBtb2RlOiAnVFJJR0dFUkVEJyAoZGVmYXVsdCkgc3luY3Mgb24gZGVtYW5kOyAnQ09OVElOVU9VUycga2VlcHMgdGhlIGluZGV4IGZyZXNoLlwiLFxuICAgICksXG4gIGNvbHVtbnNUb1N5bmM6IHpcbiAgICAuYXJyYXkoei5zdHJpbmcoKSlcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcIkV4dHJhIGNvbHVtbnMgdG8gc3luYyBhbG9uZ3NpZGUgdGhlIGVtYmVkZGluZyBzb3VyY2UgY29sdW1uIChEZWx0YSBTeW5jKS5cIiksXG59KTtcblxuLyoqIEEgdmFsaWRhdGVkIGNyZWF0ZS1pbmRleCByZXF1ZXN0ICh7QGxpbmsgY3JlYXRlSW5kZXhSZXF1ZXN0U2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBDcmVhdGVJbmRleFJlcXVlc3QgPSB6LmluZmVyPHR5cGVvZiBjcmVhdGVJbmRleFJlcXVlc3RTY2hlbWE+O1xuXG4vKiogU2NoZW1hIGZvciB0aGUgYHN5bmNfaW5kZXhgIHRvb2wgaW5wdXQgLyB0aGUgYFBPU1QgL2FwaS9zZWFyY2gvaW5kZXgvc3luY2AgYm9keS4gKi9cbmV4cG9ydCBjb25zdCBzeW5jSW5kZXhSZXF1ZXN0U2NoZW1hID0gei5vYmplY3Qoe1xuICBpbmRleDogelxuICAgIC5zdHJpbmcoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIFwiVGhlIGluZGV4IHRvIHN5bmMgKG5hbWUgb3IgY29uZmlndXJlZCBhbGlhcykuIERlZmF1bHRzIHRvIHRoZSBhcHAncyBkZWZhdWx0IGluZGV4IHdoZW4gb21pdHRlZC5cIixcbiAgICApXG4gICAgLm9wdGlvbmFsKCksXG59KTtcblxuLyoqIEEgdmFsaWRhdGVkIHN5bmMtaW5kZXggcmVxdWVzdCAoe0BsaW5rIHN5bmNJbmRleFJlcXVlc3RTY2hlbWF9KS4gKi9cbmV4cG9ydCB0eXBlIFN5bmNJbmRleFJlcXVlc3QgPSB6LmluZmVyPHR5cGVvZiBzeW5jSW5kZXhSZXF1ZXN0U2NoZW1hPjtcblxuLyoqIFNjaGVtYSBmb3IgYSByZXNvbHZlZCBpbmRleCBkZWZpbml0aW9uICh0aGUgY3JlYXRlL2dldCByZXN1bHQpLiAqL1xuZXhwb3J0IGNvbnN0IGluZGV4SW5mb1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgbmFtZTogei5zdHJpbmcoKS5kZXNjcmliZShcIlVuaXR5IENhdGFsb2cgbmFtZSBvZiB0aGUgaW5kZXguXCIpLFxuICBlbmRwb2ludDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiVGhlIFZlY3RvciBTZWFyY2ggZW5kcG9pbnQgaG9zdGluZyB0aGUgaW5kZXguXCIpLFxuICBwcmltYXJ5S2V5OiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJUaGUgaW5kZXgncyBwcmltYXJ5LWtleSBjb2x1bW4uXCIpLFxuICBjb2x1bW5zOiB6LmFycmF5KHouc3RyaW5nKCkpLmRlc2NyaWJlKFwiQ29sdW1ucyBhdmFpbGFibGUgb24gdGhlIGluZGV4LlwiKSxcbiAgcmVhZHk6IHouYm9vbGVhbigpLmRlc2NyaWJlKFwiVHJ1ZSB3aGVuIHRoZSBpbmRleCBoYXMgZmluaXNoZWQgcHJvdmlzaW9uaW5nIGFuZCBjYW4gYmUgcXVlcmllZC5cIiksXG4gIHJvd0NvdW50OiB6Lm51bWJlcigpLmludCgpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJOdW1iZXIgb2YgaW5kZXhlZCByb3dzLCB3aGVuIGtub3duLlwiKSxcbn0pO1xuXG4vKiogQSByZXNvbHZlZCBpbmRleCBkZWZpbml0aW9uICh7QGxpbmsgaW5kZXhJbmZvU2NoZW1hfSkuICovXG5leHBvcnQgdHlwZSBJbmRleEluZm8gPSB6LmluZmVyPHR5cGVvZiBpbmRleEluZm9TY2hlbWE+O1xuIl19
@@ -0,0 +1 @@
1
+ {"root":["../src/search.ts","../index.ts"],"version":"5.9.3"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@dbx-tools/shared-search",
3
+ "repository": {
4
+ "type": "git",
5
+ "url": "git+https://github.com/reggie-db/dbx-tools.git",
6
+ "directory": "packages/shared/search"
7
+ },
8
+ "devDependencies": {
9
+ "@types/node": "^24.6.0",
10
+ "tsx": "^4.23.0",
11
+ "typescript": "^5.9.3"
12
+ },
13
+ "dependencies": {
14
+ "zod": "4.3.6",
15
+ "@dbx-tools/shared-core": "0.6.9"
16
+ },
17
+ "main": "./lib/index.js",
18
+ "license": "UNLICENSED",
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "version": "0.6.9",
23
+ "types": "./lib/index.d.ts",
24
+ "type": "module",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./lib/index.d.ts",
28
+ "default": "./lib/index.js"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "files": [
33
+ "index.ts",
34
+ "src",
35
+ "lib"
36
+ ],
37
+ "dbxToolsConfig": {
38
+ "tags": [
39
+ "shared"
40
+ ]
41
+ },
42
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\".",
43
+ "scripts": {
44
+ "build": "projen build",
45
+ "compile": "projen compile",
46
+ "default": "projen default",
47
+ "package": "projen package",
48
+ "post-compile": "projen post-compile",
49
+ "pre-compile": "projen pre-compile",
50
+ "test": "projen test",
51
+ "watch": "projen watch",
52
+ "projen": "projen"
53
+ }
54
+ }
package/src/search.ts ADDED
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Wire-format contract for the AI Search add-on: the query a caller (a UI
3
+ * search box, a Mastra tool, a universal-search route) sends and the hits it
4
+ * gets back, plus the document shape used to add / update index contents.
5
+ *
6
+ * Pure (zod + inferred types, no Node-only imports) so the server-side client
7
+ * in `@dbx-tools/search`, the Mastra tool, the `POST /api/search` route,
8
+ * and the React search box all validate / type against ONE definition.
9
+ *
10
+ * "AI Search" is Databricks' current name for Vector Search: an index built
11
+ * from a Delta table (or written directly) that answers a natural-language
12
+ * query with the most relevant rows, combining vector similarity with BM25
13
+ * keyword matching (hybrid). This contract is index-agnostic - it names the
14
+ * index by its Unity Catalog path and returns hits as `{ id, score, fields }`
15
+ * so the same shape serves an autocomplete box, a docs lookup, and a
16
+ * federated search across many indexes.
17
+ *
18
+ * Array fields intentionally avoid `.min()` / `.nonempty()`: those emit
19
+ * `minItems` in the JSON schema, which some Model Serving endpoints reject
20
+ * when the schema is forwarded as a tool definition.
21
+ *
22
+ * @module
23
+ */
24
+
25
+ import { z } from "zod";
26
+
27
+ /**
28
+ * How a query is matched. `hybrid` (the default) fuses vector similarity with
29
+ * BM25 keyword ranking - the right choice for most search boxes and for source
30
+ * data with exact identifiers (SKUs, error codes). `vector` is pure semantic
31
+ * similarity; `keyword` is pure BM25 full-text (Beta on Databricks). The
32
+ * value maps onto the serving API's `query_type` (`ANN` / `HYBRID`).
33
+ */
34
+ export const searchModeSchema = z
35
+ .enum(["hybrid", "vector", "keyword"])
36
+ .describe(
37
+ "Match strategy: 'hybrid' fuses semantic similarity with keyword ranking (default, best for most searches), 'vector' is pure semantic, 'keyword' is pure full-text.",
38
+ );
39
+
40
+ /** How a query is matched (see {@link searchModeSchema}). */
41
+ export type SearchMode = z.infer<typeof searchModeSchema>;
42
+
43
+ /** Schema for a search request against a single index. */
44
+ export const searchRequestSchema = z.object({
45
+ query: z
46
+ .string()
47
+ .describe(
48
+ "What to search for, as natural language or keywords. Prefix fragments work for autocomplete.",
49
+ ),
50
+ index: z
51
+ .string()
52
+ .optional()
53
+ .describe(
54
+ "Unity Catalog name of the index to search (catalog.schema.index). Defaults to the plugin's configured index. Accepts a short alias when one is configured.",
55
+ ),
56
+ limit: z
57
+ .number()
58
+ .int()
59
+ .positive()
60
+ .optional()
61
+ .describe("Maximum number of hits to return. Defaults to the plugin's configured page size."),
62
+ mode: searchModeSchema.optional(),
63
+ columns: z
64
+ .array(z.string())
65
+ .optional()
66
+ .describe(
67
+ "Which document columns to return per hit. Defaults to the plugin's configured columns (or all indexed columns).",
68
+ ),
69
+ filter: z
70
+ .record(z.string(), z.unknown())
71
+ .optional()
72
+ .describe(
73
+ 'Attribute filters as { column: value } (a value, or an operator map like { ">=": 10 }). Combined with AND. Maps onto the index `filters_json`.',
74
+ ),
75
+ scoreThreshold: z
76
+ .number()
77
+ .optional()
78
+ .describe("Drop hits whose relevance score is below this value."),
79
+ });
80
+
81
+ /** A validated search request ({@link searchRequestSchema}). */
82
+ export type SearchRequest = z.infer<typeof searchRequestSchema>;
83
+
84
+ /** Schema for a single search hit. */
85
+ export const searchHitSchema = z.object({
86
+ id: z.string().describe("The document's primary-key value."),
87
+ score: z.number().describe("Relevance score; higher is more relevant."),
88
+ fields: z
89
+ .record(z.string(), z.unknown())
90
+ .describe("The returned columns for this document, keyed by column name."),
91
+ index: z
92
+ .string()
93
+ .optional()
94
+ .describe("Which index the hit came from (set on universal/federated results)."),
95
+ });
96
+
97
+ /** A single search hit ({@link searchHitSchema}). */
98
+ export type SearchHit = z.infer<typeof searchHitSchema>;
99
+
100
+ /** Schema for the result of a search. */
101
+ export const searchResultSchema = z.object({
102
+ query: z.string().describe("Echo of the query that was searched."),
103
+ hits: z.array(searchHitSchema).describe("Matching documents, most relevant first."),
104
+ index: z.string().optional().describe("The index searched (omitted for a universal search)."),
105
+ count: z.number().int().describe("Number of hits returned."),
106
+ });
107
+
108
+ /** The outcome of a search ({@link searchResultSchema}). */
109
+ export type SearchResult = z.infer<typeof searchResultSchema>;
110
+
111
+ /** Schema for a universal (federated) search across several indexes at once. */
112
+ export const universalSearchRequestSchema = z.object({
113
+ query: z.string().describe("What to search for across every configured index."),
114
+ indexes: z
115
+ .array(z.string())
116
+ .optional()
117
+ .describe("Which indexes to search. Defaults to every index the plugin knows about."),
118
+ limit: z
119
+ .number()
120
+ .int()
121
+ .positive()
122
+ .optional()
123
+ .describe("Maximum hits PER index before results are merged and re-ranked."),
124
+ mode: searchModeSchema.optional(),
125
+ });
126
+
127
+ /** A validated universal-search request ({@link universalSearchRequestSchema}). */
128
+ export type UniversalSearchRequest = z.infer<typeof universalSearchRequestSchema>;
129
+
130
+ /** Schema for a document written to a direct-access index. */
131
+ export const searchDocumentSchema = z
132
+ .record(z.string(), z.unknown())
133
+ .describe("A document as { column: value }. Must include the index primary-key column.");
134
+
135
+ /** A document written to an index ({@link searchDocumentSchema}). */
136
+ export type SearchDocument = z.infer<typeof searchDocumentSchema>;
137
+
138
+ /** Schema for the result of adding / updating documents. */
139
+ export const upsertResultSchema = z.object({
140
+ index: z.string().describe("The index the documents were written to."),
141
+ count: z.number().int().describe("Number of documents accepted."),
142
+ });
143
+
144
+ /** The outcome of an add-documents call ({@link upsertResultSchema}). */
145
+ export type UpsertResult = z.infer<typeof upsertResultSchema>;
146
+
147
+ /**
148
+ * Schema for the boot-time index catalogue a UI reads to populate a search box
149
+ * (the payload of the plugin's client config / `GET /api/search/indexes`). An
150
+ * entry names an index, an optional short alias, and the columns worth
151
+ * showing, so a search box needs no server round-trip to render.
152
+ */
153
+ export const searchIndexInfoSchema = z.object({
154
+ name: z.string().describe("Unity Catalog name of the index (catalog.schema.index)."),
155
+ alias: z.string().optional().describe("Short alias the plugin accepts in place of `name`."),
156
+ primaryKey: z.string().optional().describe("The index's primary-key column, when known."),
157
+ columns: z
158
+ .array(z.string())
159
+ .optional()
160
+ .describe("Columns returned by default, in display order."),
161
+ isDefault: z.boolean().optional().describe("True for the plugin's default index."),
162
+ });
163
+
164
+ /** One entry in the index catalogue ({@link searchIndexInfoSchema}). */
165
+ export type SearchIndexInfo = z.infer<typeof searchIndexInfoSchema>;
166
+
167
+ /** Schema for the plugin's client config surfaced to a UI. */
168
+ export const searchClientConfigSchema = z.object({
169
+ indexes: z.array(searchIndexInfoSchema).describe("Indexes the search UI may query."),
170
+ defaultIndex: z.string().optional().describe("The index a search box selects by default."),
171
+ pageSize: z.number().int().describe("Default number of hits a search returns."),
172
+ basePath: z
173
+ .string()
174
+ .describe("Base path the search routes are mounted under (e.g. /api/search)."),
175
+ });
176
+
177
+ /** The plugin's client config ({@link searchClientConfigSchema}). */
178
+ export type SearchClientConfig = z.infer<typeof searchClientConfigSchema>;
179
+
180
+ /**
181
+ * Schema for creating an index (the `create_index` tool input / the
182
+ * `POST /api/search/index` body). Two shapes, both inferring aggressively:
183
+ * pass `sourceTable` for a Delta Sync index (Databricks computes embeddings and
184
+ * keeps it synced) or `embeddingDimension` for a direct-access index you write
185
+ * vectors to yourself.
186
+ */
187
+ export const createIndexRequestSchema = z.object({
188
+ name: z.string().describe("Unity Catalog name for the new index (catalog.schema.index)."),
189
+ sourceTable: z
190
+ .string()
191
+ .optional()
192
+ .describe(
193
+ "Delta table (catalog.schema.table) to build a synced index from. Provide this OR embeddingDimension.",
194
+ ),
195
+ primaryKey: z.string().optional().describe("Primary-key column. Defaults to 'id'."),
196
+ embeddingSourceColumn: z
197
+ .string()
198
+ .optional()
199
+ .describe(
200
+ "Text column embeddings are computed from (Delta Sync). Defaults to the first of text/content/body.",
201
+ ),
202
+ embeddingModel: z
203
+ .string()
204
+ .optional()
205
+ .describe(
206
+ "Embedding model endpoint (name or loose name). Defaults to the app's embedding model, or the best embedding endpoint in the workspace.",
207
+ ),
208
+ endpoint: z
209
+ .string()
210
+ .optional()
211
+ .describe(
212
+ "Vector Search endpoint to host the index on. Defaults to the app's configured endpoint.",
213
+ ),
214
+ embeddingDimension: z
215
+ .number()
216
+ .int()
217
+ .positive()
218
+ .optional()
219
+ .describe("For a direct-access index (no source table): the embedding vector dimension."),
220
+ pipelineType: z
221
+ .enum(["TRIGGERED", "CONTINUOUS"])
222
+ .optional()
223
+ .describe(
224
+ "Delta Sync mode: 'TRIGGERED' (default) syncs on demand; 'CONTINUOUS' keeps the index fresh.",
225
+ ),
226
+ columnsToSync: z
227
+ .array(z.string())
228
+ .optional()
229
+ .describe("Extra columns to sync alongside the embedding source column (Delta Sync)."),
230
+ });
231
+
232
+ /** A validated create-index request ({@link createIndexRequestSchema}). */
233
+ export type CreateIndexRequest = z.infer<typeof createIndexRequestSchema>;
234
+
235
+ /** Schema for the `sync_index` tool input / the `POST /api/search/index/sync` body. */
236
+ export const syncIndexRequestSchema = z.object({
237
+ index: z
238
+ .string()
239
+ .describe(
240
+ "The index to sync (name or configured alias). Defaults to the app's default index when omitted.",
241
+ )
242
+ .optional(),
243
+ });
244
+
245
+ /** A validated sync-index request ({@link syncIndexRequestSchema}). */
246
+ export type SyncIndexRequest = z.infer<typeof syncIndexRequestSchema>;
247
+
248
+ /** Schema for a resolved index definition (the create/get result). */
249
+ export const indexInfoSchema = z.object({
250
+ name: z.string().describe("Unity Catalog name of the index."),
251
+ endpoint: z.string().optional().describe("The Vector Search endpoint hosting the index."),
252
+ primaryKey: z.string().optional().describe("The index's primary-key column."),
253
+ columns: z.array(z.string()).describe("Columns available on the index."),
254
+ ready: z.boolean().describe("True when the index has finished provisioning and can be queried."),
255
+ rowCount: z.number().int().optional().describe("Number of indexed rows, when known."),
256
+ });
257
+
258
+ /** A resolved index definition ({@link indexInfoSchema}). */
259
+ export type IndexInfo = z.infer<typeof indexInfoSchema>;