@dbx-tools/search 0.6.222 → 0.6.224

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.
@@ -1,34 +1,42 @@
1
1
  /**
2
- * The shared AI Search runtime: the resolved config plus a single
3
- * {@link SearchClient} instance the plugin, the Mastra tools, and the routes
4
- * all read. Mirrors the web-search / email runtime pattern - the plugin primes
5
- * it from its config at setup, and everything else reads the same instance so
6
- * a tool invoked outside the agent still sees the deployment's config.
2
+ * AI Search runtime construction helpers.
3
+ *
4
+ * Each plugin and standalone tool set owns its runtime and client. Provider
5
+ * attachment updates only that runtime, so two apps in one process can use
6
+ * different backends without sharing state.
7
7
  *
8
8
  * @module
9
9
  */
10
10
  import { createSearchClient } from "./client.js";
11
11
  import { resolveSearchConfig, } from "./config.js";
12
- let runtime;
12
+ /** Build an isolated runtime for one plugin instance or standalone tool set. */
13
+ export function createSearchRuntime(options = {}) {
14
+ const config = resolveSearchConfig(options.config);
15
+ return {
16
+ config,
17
+ client: createSearchClient(config, undefined, options.readBackend),
18
+ ...(options.readBackend ? { readBackend: options.readBackend } : {}),
19
+ };
20
+ }
21
+ /** Attach a provider to one runtime while preserving its object identity. */
22
+ export function setSearchReadBackend(runtime, readBackend) {
23
+ runtime.readBackend = readBackend;
24
+ runtime.client = createSearchClient(runtime.config, undefined, readBackend);
25
+ }
13
26
  /**
14
- * Return the shared runtime, building it on first use from the supplied config
15
- * layered over environment defaults. Overrides are only read when the runtime
16
- * is first created, so prime it from the plugin's config at setup; subsequent
17
- * calls pass nothing and get the same instance.
27
+ * Build an isolated standalone runtime.
28
+ *
29
+ * @deprecated Use {@link createSearchRuntime}. This compatibility helper
30
+ * returns a new runtime on every call and never reads or updates plugin state.
18
31
  */
19
32
  export function getSearchRuntime(options) {
20
- if (!runtime) {
21
- const config = resolveSearchConfig(options?.config);
22
- runtime = {
23
- config,
24
- client: createSearchClient(config, undefined, options?.readBackend),
25
- ...(options?.readBackend ? { readBackend: options.readBackend } : {}),
26
- };
27
- }
28
- return runtime;
33
+ return createSearchRuntime(options);
29
34
  }
30
- /** Drop the memoized runtime so the next {@link getSearchRuntime} rebuilds it. */
35
+ /**
36
+ * @deprecated Plugin runtimes are instance-owned and need no global reset.
37
+ * This compatibility helper is intentionally a no-op.
38
+ */
31
39
  export function resetSearchRuntime() {
32
- runtime = undefined;
40
+ return;
33
41
  }
34
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUgsT0FBTyxFQUFFLGtCQUFrQixFQUF3QyxNQUFNLGFBQWEsQ0FBQztBQUN2RixPQUFPLEVBQ0wsbUJBQW1CLEdBR3BCLE1BQU0sYUFBYSxDQUFDO0FBZXJCLElBQUksT0FBa0MsQ0FBQztBQUV2Qzs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUE4QjtJQUM3RCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixNQUFNLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDcEQsT0FBTyxHQUFHO1lBQ1IsTUFBTTtZQUNOLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUM7WUFDbkUsR0FBRyxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ3RFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixNQUFNLFVBQVUsa0JBQWtCO0lBQ2hDLE9BQU8sR0FBRyxTQUFTLENBQUM7QUFDdEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIHNoYXJlZCBBSSBTZWFyY2ggcnVudGltZTogdGhlIHJlc29sdmVkIGNvbmZpZyBwbHVzIGEgc2luZ2xlXG4gKiB7QGxpbmsgU2VhcmNoQ2xpZW50fSBpbnN0YW5jZSB0aGUgcGx1Z2luLCB0aGUgTWFzdHJhIHRvb2xzLCBhbmQgdGhlIHJvdXRlc1xuICogYWxsIHJlYWQuIE1pcnJvcnMgdGhlIHdlYi1zZWFyY2ggLyBlbWFpbCBydW50aW1lIHBhdHRlcm4gLSB0aGUgcGx1Z2luIHByaW1lc1xuICogaXQgZnJvbSBpdHMgY29uZmlnIGF0IHNldHVwLCBhbmQgZXZlcnl0aGluZyBlbHNlIHJlYWRzIHRoZSBzYW1lIGluc3RhbmNlIHNvXG4gKiBhIHRvb2wgaW52b2tlZCBvdXRzaWRlIHRoZSBhZ2VudCBzdGlsbCBzZWVzIHRoZSBkZXBsb3ltZW50J3MgY29uZmlnLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVTZWFyY2hDbGllbnQsIFNlYXJjaENsaWVudCwgdHlwZSBTZWFyY2hSZWFkQmFja2VuZCB9IGZyb20gXCIuL2NsaWVudC50c1wiO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZVNlYXJjaENvbmZpZyxcbiAgdHlwZSBTZWFyY2hQbHVnaW5Db25maWcsXG4gIHR5cGUgUmVzb2x2ZWRTZWFyY2hDb25maWcsXG59IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuXG4vKiogQ29uZmlndXJhdGlvbiBhbmQgcHJvdmlkZXIgdXNlZCB0byBidWlsZCB0aGUgc2hhcmVkIGV4dGVuc2lvbiBydW50aW1lLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hSdW50aW1lT3B0aW9ucyB7XG4gIGNvbmZpZz86IFNlYXJjaFBsdWdpbkNvbmZpZztcbiAgcmVhZEJhY2tlbmQ/OiBTZWFyY2hSZWFkQmFja2VuZDtcbn1cblxuLyoqIFRoZSBzaGFyZWQgcmVzb2x2ZWQgY29uZmlnIHBsdXMgdGhlIGNsaWVudCByZWFkcyBydW4gdGhyb3VnaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VhcmNoUnVudGltZSB7XG4gIGNvbmZpZzogUmVzb2x2ZWRTZWFyY2hDb25maWc7XG4gIGNsaWVudDogU2VhcmNoQ2xpZW50O1xuICByZWFkQmFja2VuZD86IFNlYXJjaFJlYWRCYWNrZW5kO1xufVxuXG5sZXQgcnVudGltZTogU2VhcmNoUnVudGltZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIHNoYXJlZCBydW50aW1lLCBidWlsZGluZyBpdCBvbiBmaXJzdCB1c2UgZnJvbSB0aGUgc3VwcGxpZWQgY29uZmlnXG4gKiBsYXllcmVkIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMuIE92ZXJyaWRlcyBhcmUgb25seSByZWFkIHdoZW4gdGhlIHJ1bnRpbWVcbiAqIGlzIGZpcnN0IGNyZWF0ZWQsIHNvIHByaW1lIGl0IGZyb20gdGhlIHBsdWdpbidzIGNvbmZpZyBhdCBzZXR1cDsgc3Vic2VxdWVudFxuICogY2FsbHMgcGFzcyBub3RoaW5nIGFuZCBnZXQgdGhlIHNhbWUgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZWFyY2hSdW50aW1lKG9wdGlvbnM/OiBTZWFyY2hSdW50aW1lT3B0aW9ucyk6IFNlYXJjaFJ1bnRpbWUge1xuICBpZiAoIXJ1bnRpbWUpIHtcbiAgICBjb25zdCBjb25maWcgPSByZXNvbHZlU2VhcmNoQ29uZmlnKG9wdGlvbnM/LmNvbmZpZyk7XG4gICAgcnVudGltZSA9IHtcbiAgICAgIGNvbmZpZyxcbiAgICAgIGNsaWVudDogY3JlYXRlU2VhcmNoQ2xpZW50KGNvbmZpZywgdW5kZWZpbmVkLCBvcHRpb25zPy5yZWFkQmFja2VuZCksXG4gICAgICAuLi4ob3B0aW9ucz8ucmVhZEJhY2tlbmQgPyB7IHJlYWRCYWNrZW5kOiBvcHRpb25zLnJlYWRCYWNrZW5kIH0gOiB7fSksXG4gICAgfTtcbiAgfVxuICByZXR1cm4gcnVudGltZTtcbn1cblxuLyoqIERyb3AgdGhlIG1lbW9pemVkIHJ1bnRpbWUgc28gdGhlIG5leHQge0BsaW5rIGdldFNlYXJjaFJ1bnRpbWV9IHJlYnVpbGRzIGl0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0U2VhcmNoUnVudGltZSgpOiB2b2lkIHtcbiAgcnVudGltZSA9IHVuZGVmaW5lZDtcbn1cbiJdfQ==
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUgsT0FBTyxFQUFFLGtCQUFrQixFQUF3QyxNQUFNLGFBQWEsQ0FBQztBQUN2RixPQUFPLEVBQ0wsbUJBQW1CLEdBR3BCLE1BQU0sYUFBYSxDQUFDO0FBZXJCLGdGQUFnRjtBQUNoRixNQUFNLFVBQVUsbUJBQW1CLENBQUMsVUFBZ0MsRUFBRTtJQUNwRSxNQUFNLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbkQsT0FBTztRQUNMLE1BQU07UUFDTixNQUFNLEVBQUUsa0JBQWtCLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDO1FBQ2xFLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUNyRSxDQUFDO0FBQ0osQ0FBQztBQUVELDZFQUE2RTtBQUM3RSxNQUFNLFVBQVUsb0JBQW9CLENBQUMsT0FBc0IsRUFBRSxXQUE4QjtJQUN6RixPQUFPLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztJQUNsQyxPQUFPLENBQUMsTUFBTSxHQUFHLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUE4QjtJQUM3RCxPQUFPLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3RDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsa0JBQWtCO0lBQ2hDLE9BQU87QUFDVCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBSSBTZWFyY2ggcnVudGltZSBjb25zdHJ1Y3Rpb24gaGVscGVycy5cbiAqXG4gKiBFYWNoIHBsdWdpbiBhbmQgc3RhbmRhbG9uZSB0b29sIHNldCBvd25zIGl0cyBydW50aW1lIGFuZCBjbGllbnQuIFByb3ZpZGVyXG4gKiBhdHRhY2htZW50IHVwZGF0ZXMgb25seSB0aGF0IHJ1bnRpbWUsIHNvIHR3byBhcHBzIGluIG9uZSBwcm9jZXNzIGNhbiB1c2VcbiAqIGRpZmZlcmVudCBiYWNrZW5kcyB3aXRob3V0IHNoYXJpbmcgc3RhdGUuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVNlYXJjaENsaWVudCwgU2VhcmNoQ2xpZW50LCB0eXBlIFNlYXJjaFJlYWRCYWNrZW5kIH0gZnJvbSBcIi4vY2xpZW50LnRzXCI7XG5pbXBvcnQge1xuICByZXNvbHZlU2VhcmNoQ29uZmlnLFxuICB0eXBlIFNlYXJjaFBsdWdpbkNvbmZpZyxcbiAgdHlwZSBSZXNvbHZlZFNlYXJjaENvbmZpZyxcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5cbi8qKiBDb25maWd1cmF0aW9uIGFuZCBwcm92aWRlciB1c2VkIHRvIGJ1aWxkIGFuIGV4dGVuc2lvbiBydW50aW1lLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hSdW50aW1lT3B0aW9ucyB7XG4gIGNvbmZpZz86IFNlYXJjaFBsdWdpbkNvbmZpZztcbiAgcmVhZEJhY2tlbmQ/OiBTZWFyY2hSZWFkQmFja2VuZDtcbn1cblxuLyoqIFRoZSByZXNvbHZlZCBjb25maWcgcGx1cyB0aGUgY2xpZW50IHJlYWRzIHJ1biB0aHJvdWdoLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hSdW50aW1lIHtcbiAgY29uZmlnOiBSZXNvbHZlZFNlYXJjaENvbmZpZztcbiAgY2xpZW50OiBTZWFyY2hDbGllbnQ7XG4gIHJlYWRCYWNrZW5kPzogU2VhcmNoUmVhZEJhY2tlbmQ7XG59XG5cbi8qKiBCdWlsZCBhbiBpc29sYXRlZCBydW50aW1lIGZvciBvbmUgcGx1Z2luIGluc3RhbmNlIG9yIHN0YW5kYWxvbmUgdG9vbCBzZXQuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2VhcmNoUnVudGltZShvcHRpb25zOiBTZWFyY2hSdW50aW1lT3B0aW9ucyA9IHt9KTogU2VhcmNoUnVudGltZSB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlc29sdmVTZWFyY2hDb25maWcob3B0aW9ucy5jb25maWcpO1xuICByZXR1cm4ge1xuICAgIGNvbmZpZyxcbiAgICBjbGllbnQ6IGNyZWF0ZVNlYXJjaENsaWVudChjb25maWcsIHVuZGVmaW5lZCwgb3B0aW9ucy5yZWFkQmFja2VuZCksXG4gICAgLi4uKG9wdGlvbnMucmVhZEJhY2tlbmQgPyB7IHJlYWRCYWNrZW5kOiBvcHRpb25zLnJlYWRCYWNrZW5kIH0gOiB7fSksXG4gIH07XG59XG5cbi8qKiBBdHRhY2ggYSBwcm92aWRlciB0byBvbmUgcnVudGltZSB3aGlsZSBwcmVzZXJ2aW5nIGl0cyBvYmplY3QgaWRlbnRpdHkuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0U2VhcmNoUmVhZEJhY2tlbmQocnVudGltZTogU2VhcmNoUnVudGltZSwgcmVhZEJhY2tlbmQ6IFNlYXJjaFJlYWRCYWNrZW5kKTogdm9pZCB7XG4gIHJ1bnRpbWUucmVhZEJhY2tlbmQgPSByZWFkQmFja2VuZDtcbiAgcnVudGltZS5jbGllbnQgPSBjcmVhdGVTZWFyY2hDbGllbnQocnVudGltZS5jb25maWcsIHVuZGVmaW5lZCwgcmVhZEJhY2tlbmQpO1xufVxuXG4vKipcbiAqIEJ1aWxkIGFuIGlzb2xhdGVkIHN0YW5kYWxvbmUgcnVudGltZS5cbiAqXG4gKiBAZGVwcmVjYXRlZCBVc2Uge0BsaW5rIGNyZWF0ZVNlYXJjaFJ1bnRpbWV9LiBUaGlzIGNvbXBhdGliaWxpdHkgaGVscGVyXG4gKiByZXR1cm5zIGEgbmV3IHJ1bnRpbWUgb24gZXZlcnkgY2FsbCBhbmQgbmV2ZXIgcmVhZHMgb3IgdXBkYXRlcyBwbHVnaW4gc3RhdGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZWFyY2hSdW50aW1lKG9wdGlvbnM/OiBTZWFyY2hSdW50aW1lT3B0aW9ucyk6IFNlYXJjaFJ1bnRpbWUge1xuICByZXR1cm4gY3JlYXRlU2VhcmNoUnVudGltZShvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZCBQbHVnaW4gcnVudGltZXMgYXJlIGluc3RhbmNlLW93bmVkIGFuZCBuZWVkIG5vIGdsb2JhbCByZXNldC5cbiAqIFRoaXMgY29tcGF0aWJpbGl0eSBoZWxwZXIgaXMgaW50ZW50aW9uYWxseSBhIG5vLW9wLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRTZWFyY2hSdW50aW1lKCk6IHZvaWQge1xuICByZXR1cm47XG59XG4iXX0=
package/lib/src/tool.d.ts CHANGED
@@ -2,21 +2,31 @@
2
2
  * The `search`, `universal_search`, and (opt-in) `add_documents`,
3
3
  * `create_index`, and `sync_index` Mastra tools.
4
4
  *
5
- * All three read the shared runtime primed by the plugin, so a tool spread
6
- * into an agent uses the deployment's default index, columns, page size, and
7
- * mode without any per-tool wiring. They run under the caller's OBO scope (the
8
- * client resolves the execution context's workspace client), so search runs as
9
- * the requesting user and Unity Catalog ACLs apply.
5
+ * App-integrated agents should consume the plugin's native toolkit so calls
6
+ * retain that plugin's config and provider backend. These standalone factories
7
+ * capture an explicit runtime or build an isolated one from config plus a
8
+ * provider. They run under the caller's OBO scope (the client resolves the
9
+ * execution context's workspace client), so search runs as the requesting user
10
+ * and Unity Catalog ACLs apply.
10
11
  *
11
12
  * The same tools are exposed to AppKit's own agents through the plugin's
12
- * `ToolProvider` (see `plugin.ts`); this module is the Mastra half.
13
+ * `ToolProvider` (see `plugin.ts`).
13
14
  *
14
15
  * @module
15
16
  */
16
- /** Common option accepted by every tool factory: override the tool id. */
17
+ import type { SearchReadBackend } from "./client.ts";
18
+ import type { SearchPluginConfig } from "./config.ts";
19
+ import { type SearchRuntime } from "./runtime.ts";
20
+ /** Options accepted by every standalone tool factory. */
17
21
  export interface SearchToolOptions {
18
22
  /** Override the tool id (defaults per tool). */
19
23
  id?: string;
24
+ /** Isolated runtime used by this standalone tool. Mutually exclusive with config/backend. */
25
+ runtime?: SearchRuntime;
26
+ /** Config used to create an isolated runtime. */
27
+ config?: SearchPluginConfig;
28
+ /** Provider used when creating a runtime from config. */
29
+ readBackend?: SearchReadBackend;
20
30
  }
21
31
  /**
22
32
  * Build the `search` tool. Spread it into any agent that should be able to look
package/lib/src/tool.js CHANGED
@@ -2,25 +2,37 @@
2
2
  * The `search`, `universal_search`, and (opt-in) `add_documents`,
3
3
  * `create_index`, and `sync_index` Mastra tools.
4
4
  *
5
- * All three read the shared runtime primed by the plugin, so a tool spread
6
- * into an agent uses the deployment's default index, columns, page size, and
7
- * mode without any per-tool wiring. They run under the caller's OBO scope (the
8
- * client resolves the execution context's workspace client), so search runs as
9
- * the requesting user and Unity Catalog ACLs apply.
5
+ * App-integrated agents should consume the plugin's native toolkit so calls
6
+ * retain that plugin's config and provider backend. These standalone factories
7
+ * capture an explicit runtime or build an isolated one from config plus a
8
+ * provider. They run under the caller's OBO scope (the client resolves the
9
+ * execution context's workspace client), so search runs as the requesting user
10
+ * and Unity Catalog ACLs apply.
10
11
  *
11
12
  * The same tools are exposed to AppKit's own agents through the plugin's
12
- * `ToolProvider` (see `plugin.ts`); this module is the Mastra half.
13
+ * `ToolProvider` (see `plugin.ts`).
13
14
  *
14
15
  * @module
15
16
  */
16
17
  import { search as sharedSearch } from "@dbx-tools/shared-search";
17
18
  import { createTool } from "@mastra/core/tools";
18
19
  import { z } from "zod";
20
+ import { toSearchOptions, toUniversalSearchOptions } from "./_search-options.js";
19
21
  import { toCreateIndexOptions } from "./index-tools.js";
20
22
  import { toDocumentArray } from "./query.js";
21
- import { getSearchRuntime } from "./runtime.js";
22
- import { toSearchOptions, toUniversalSearchOptions } from "./_search-options.js";
23
+ import { createSearchRuntime } from "./runtime.js";
23
24
  import { ADD_DOCUMENTS_TOOL_DESCRIPTION, CREATE_INDEX_TOOL_DESCRIPTION, SEARCH_TOOL_DESCRIPTION, SYNC_INDEX_TOOL_DESCRIPTION, UNIVERSAL_SEARCH_TOOL_DESCRIPTION, createIndexToolSchema, indexInfoSchema, searchResultSchema, searchToolSchema, syncIndexToolSchema, universalSearchToolSchema, } from "./schema.js";
25
+ /** Resolve the isolated runtime captured by one standalone tool factory. */
26
+ function toolRuntime(options) {
27
+ if (options.runtime && (options.config || options.readBackend)) {
28
+ throw new TypeError("search tool options accept runtime or config/readBackend, not both");
29
+ }
30
+ return (options.runtime ??
31
+ createSearchRuntime({
32
+ config: options.config,
33
+ readBackend: options.readBackend,
34
+ }));
35
+ }
24
36
  /**
25
37
  * Build the `search` tool. Spread it into any agent that should be able to look
26
38
  * things up in an index.
@@ -37,6 +49,7 @@ import { ADD_DOCUMENTS_TOOL_DESCRIPTION, CREATE_INDEX_TOOL_DESCRIPTION, SEARCH_T
37
49
  * ```
38
50
  */
39
51
  export function searchTool(options = {}) {
52
+ const runtime = toolRuntime(options);
40
53
  return createTool({
41
54
  id: options.id ?? "search",
42
55
  description: SEARCH_TOOL_DESCRIPTION,
@@ -44,13 +57,13 @@ export function searchTool(options = {}) {
44
57
  outputSchema: searchResultSchema,
45
58
  execute: async (input, context) => {
46
59
  const request = searchToolSchema.parse(input);
47
- const { client } = getSearchRuntime();
48
- return client.search(request.query, toSearchOptions(request, context?.abortSignal));
60
+ return runtime.client.search(request.query, toSearchOptions(request, context?.abortSignal));
49
61
  },
50
62
  });
51
63
  }
52
64
  /** Build the `universal_search` tool (federated search across every index). */
53
65
  export function universalSearchTool(options = {}) {
66
+ const runtime = toolRuntime(options);
54
67
  return createTool({
55
68
  id: options.id ?? "universal_search",
56
69
  description: UNIVERSAL_SEARCH_TOOL_DESCRIPTION,
@@ -58,8 +71,7 @@ export function universalSearchTool(options = {}) {
58
71
  outputSchema: searchResultSchema,
59
72
  execute: async (input, context) => {
60
73
  const request = universalSearchToolSchema.parse(input);
61
- const { client } = getSearchRuntime();
62
- return client.universalSearch(request.query, toUniversalSearchOptions(request, context?.abortSignal));
74
+ return runtime.client.universalSearch(request.query, toUniversalSearchOptions(request, context?.abortSignal));
63
75
  },
64
76
  });
65
77
  }
@@ -68,6 +80,7 @@ export function universalSearchTool(options = {}) {
68
80
  * Only install it when the plugin's write surface is enabled.
69
81
  */
70
82
  export function addDocumentsTool(options = {}) {
83
+ const runtime = toolRuntime(options);
71
84
  const inputSchema = sharedSearch.searchDocumentSchema
72
85
  .array()
73
86
  .describe("Documents to add or update. Each must include the index primary key.");
@@ -79,7 +92,7 @@ export function addDocumentsTool(options = {}) {
79
92
  .extend({ documents: inputSchema }),
80
93
  outputSchema: sharedSearch.upsertResultSchema,
81
94
  execute: async (input, context) => {
82
- const { client, config } = getSearchRuntime();
95
+ const { client, config } = runtime;
83
96
  const record = input;
84
97
  const documents = toDocumentArray(record.documents);
85
98
  const index = record.index ?? config.defaultIndex ?? "";
@@ -94,6 +107,7 @@ export function addDocumentsTool(options = {}) {
94
107
  * key, and columns from the request + plugin config.
95
108
  */
96
109
  export function createIndexTool(options = {}) {
110
+ const runtime = toolRuntime(options);
97
111
  return createTool({
98
112
  id: options.id ?? "create_index",
99
113
  description: CREATE_INDEX_TOOL_DESCRIPTION,
@@ -101,8 +115,7 @@ export function createIndexTool(options = {}) {
101
115
  outputSchema: indexInfoSchema,
102
116
  execute: async (input, context) => {
103
117
  const request = createIndexToolSchema.parse(input);
104
- const { client } = getSearchRuntime();
105
- return client.createIndex(request.name, toCreateIndexOptions(request, context?.abortSignal));
118
+ return runtime.client.createIndex(request.name, toCreateIndexOptions(request, context?.abortSignal));
106
119
  },
107
120
  });
108
121
  }
@@ -116,6 +129,7 @@ const syncIndexResultSchema = z.object({
116
129
  * source table). Only install it when the plugin's write surface is enabled.
117
130
  */
118
131
  export function syncIndexTool(options = {}) {
132
+ const runtime = toolRuntime(options);
119
133
  return createTool({
120
134
  id: options.id ?? "sync_index",
121
135
  description: SYNC_INDEX_TOOL_DESCRIPTION,
@@ -123,11 +137,11 @@ export function syncIndexTool(options = {}) {
123
137
  outputSchema: syncIndexResultSchema,
124
138
  execute: async (input, context) => {
125
139
  const request = syncIndexToolSchema.parse(input);
126
- const { client, config } = getSearchRuntime();
140
+ const { client, config } = runtime;
127
141
  const index = request.index ?? config.defaultIndex ?? "";
128
142
  await client.syncIndex(index, context?.abortSignal);
129
143
  return { index, synced: true };
130
144
  },
131
145
  });
132
146
  }
133
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsT0FBTyxFQUFFLE1BQU0sSUFBSSxZQUFZLEVBQXFCLE1BQU0sMEJBQTBCLENBQUM7QUFDckYsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDeEIsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUM3QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUsRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pGLE9BQU8sRUFDTCw4QkFBOEIsRUFDOUIsNkJBQTZCLEVBQzdCLHVCQUF1QixFQUN2QiwyQkFBMkIsRUFDM0IsaUNBQWlDLEVBQ2pDLHFCQUFxQixFQUNyQixlQUFlLEVBQ2Ysa0JBQWtCLEVBQ2xCLGdCQUFnQixFQUNoQixtQkFBbUIsRUFDbkIseUJBQXlCLEdBQzFCLE1BQU0sYUFBYSxDQUFDO0FBUXJCOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBQyxVQUE2QixFQUFFO0lBQ3hELE9BQU8sVUFBVSxDQUFDO1FBQ2hCLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRSxJQUFJLFFBQVE7UUFDMUIsV0FBVyxFQUFFLHVCQUF1QjtRQUNwQyxXQUFXLEVBQUUsZ0JBQWdCO1FBQzdCLFlBQVksRUFBRSxrQkFBa0I7UUFDaEMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDaEMsTUFBTSxPQUFPLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxDQUFD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IjpbIi8qKlxuICogVGhlIGBzZWFyY2hgLCBgdW5pdmVyc2FsX3NlYXJjaGAsIGFuZCAob3B0LWluKSBgYWRkX2RvY3VtZW50c2AsXG4gKiBgY3JlYXRlX2luZGV4YCwgYW5kIGBzeW5jX2luZGV4YCBNYXN0cmEgdG9vbHMuXG4gKlxuICogQWxsIHRocmVlIHJlYWQgdGhlIHNoYXJlZCBydW50aW1lIHByaW1lZCBieSB0aGUgcGx1Z2luLCBzbyBhIHRvb2wgc3ByZWFkXG4gKiBpbnRvIGFuIGFnZW50IHVzZXMgdGhlIGRlcGxveW1lbnQncyBkZWZhdWx0IGluZGV4LCBjb2x1bW5zLCBwYWdlIHNpemUsIGFuZFxuICogbW9kZSB3aXRob3V0IGFueSBwZXItdG9vbCB3aXJpbmcuIFRoZXkgcnVuIHVuZGVyIHRoZSBjYWxsZXIncyBPQk8gc2NvcGUgKHRoZVxuICogY2xpZW50IHJlc29sdmVzIHRoZSBleGVjdXRpb24gY29udGV4dCdzIHdvcmtzcGFjZSBjbGllbnQpLCBzbyBzZWFyY2ggcnVucyBhc1xuICogdGhlIHJlcXVlc3RpbmcgdXNlciBhbmQgVW5pdHkgQ2F0YWxvZyBBQ0xzIGFwcGx5LlxuICpcbiAqIFRoZSBzYW1lIHRvb2xzIGFyZSBleHBvc2VkIHRvIEFwcEtpdCdzIG93biBhZ2VudHMgdGhyb3VnaCB0aGUgcGx1Z2luJ3NcbiAqIGBUb29sUHJvdmlkZXJgIChzZWUgYHBsdWdpbi50c2ApOyB0aGlzIG1vZHVsZSBpcyB0aGUgTWFzdHJhIGhhbGYuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHNlYXJjaCBhcyBzaGFyZWRTZWFyY2gsIHR5cGUgVXBzZXJ0UmVzdWx0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLXNlYXJjaFwiO1xuaW1wb3J0IHsgY3JlYXRlVG9vbCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvdG9vbHNcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgeyB0b0NyZWF0ZUluZGV4T3B0aW9ucyB9IGZyb20gXCIuL2luZGV4LXRvb2xzLnRzXCI7XG5pbXBvcnQgeyB0b0RvY3VtZW50QXJyYXkgfSBmcm9tIFwiLi9xdWVyeS50c1wiO1xuaW1wb3J0IHsgZ2V0U2VhcmNoUnVudGltZSB9IGZyb20gXCIuL3J1bnRpbWUudHNcIjtcbmltcG9ydCB7IHRvU2VhcmNoT3B0aW9ucywgdG9Vbml2ZXJzYWxTZWFyY2hPcHRpb25zIH0gZnJvbSBcIi4vX3NlYXJjaC1vcHRpb25zLnRzXCI7XG5pbXBvcnQge1xuICBBRERfRE9DVU1FTlRTX1RPT0xfREVTQ1JJUFRJT04sXG4gIENSRUFURV9JTkRFWF9UT09MX0RFU0NSSVBUSU9OLFxuICBTRUFSQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgU1lOQ19JTkRFWF9UT09MX0RFU0NSSVBUSU9OLFxuICBVTklWRVJTQUxfU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sXG4gIGNyZWF0ZUluZGV4VG9vbFNjaGVtYSxcbiAgaW5kZXhJbmZvU2NoZW1hLFxuICBzZWFyY2hSZXN1bHRTY2hlbWEsXG4gIHNlYXJjaFRvb2xTY2hlbWEsXG4gIHN5bmNJbmRleFRvb2xTY2hlbWEsXG4gIHVuaXZlcnNhbFNlYXJjaFRvb2xTY2hlbWEsXG59IGZyb20gXCIuL3NjaGVtYS50c1wiO1xuXG4vKiogQ29tbW9uIG9wdGlvbiBhY2NlcHRlZCBieSBldmVyeSB0b29sIGZhY3Rvcnk6IG92ZXJyaWRlIHRoZSB0b29sIGlkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hUb29sT3B0aW9ucyB7XG4gIC8qKiBPdmVycmlkZSB0aGUgdG9vbCBpZCAoZGVmYXVsdHMgcGVyIHRvb2wpLiAqL1xuICBpZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgYHNlYXJjaGAgdG9vbC4gU3ByZWFkIGl0IGludG8gYW55IGFnZW50IHRoYXQgc2hvdWxkIGJlIGFibGUgdG8gbG9va1xuICogdGhpbmdzIHVwIGluIGFuIGluZGV4LlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgc2VhcmNoVG9vbCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NlYXJjaFwiO1xuICogaW1wb3J0IHsgY3JlYXRlQWdlbnQgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXQtbWFzdHJhXCI7XG4gKlxuICogY29uc3Qgc3VwcG9ydCA9IGNyZWF0ZUFnZW50KHtcbiAqICAgaW5zdHJ1Y3Rpb25zOiBcIkFuc3dlciBmcm9tIHRoZSBkb2NzLiBVc2UgYHNlYXJjaGAgdG8gZmluZCB0aGVtLlwiLFxuICogICB0b29sczogKCkgPT4gKHsgc2VhcmNoOiBzZWFyY2hUb29sKCkgfSksXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VhcmNoVG9vbChvcHRpb25zOiBTZWFyY2hUb29sT3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogb3B0aW9ucy5pZCA/PyBcInNlYXJjaFwiLFxuICAgIGRlc2NyaXB0aW9uOiBTRUFSQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogc2VhcmNoVG9vbFNjaGVtYSxcbiAgICBvdXRwdXRTY2hlbWE6IHNlYXJjaFJlc3VsdFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIGNvbnRleHQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSBzZWFyY2hUb29sU2NoZW1hLnBhcnNlKGlucHV0KTtcbiAgICAgIGNvbnN0IHsgY2xpZW50IH0gPSBnZXRTZWFyY2hSdW50aW1lKCk7XG4gICAgICByZXR1cm4gY2xpZW50LnNlYXJjaChyZXF1ZXN0LnF1ZXJ5LCB0b1NlYXJjaE9wdGlvbnMocmVxdWVzdCwgY29udGV4dD8uYWJvcnRTaWduYWwpKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqIEJ1aWxkIHRoZSBgdW5pdmVyc2FsX3NlYXJjaGAgdG9vbCAoZmVkZXJhdGVkIHNlYXJjaCBhY3Jvc3MgZXZlcnkgaW5kZXgpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaXZlcnNhbFNlYXJjaFRvb2wob3B0aW9uczogU2VhcmNoVG9vbE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdGlvbnMuaWQgPz8gXCJ1bml2ZXJzYWxfc2VhcmNoXCIsXG4gICAgZGVzY3JpcHRpb246IFVOSVZFUlNBTF9TRUFSQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogdW5pdmVyc2FsU2VhcmNoVG9vbFNjaGVtYSxcbiAgICBvdXRwdXRTY2hlbWE6IHNlYXJjaFJlc3VsdFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIGNvbnRleHQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSB1bml2ZXJzYWxTZWFyY2hUb29sU2NoZW1hLnBhcnNlKGlucHV0KTtcbiAgICAgIGNvbnN0IHsgY2xpZW50IH0gPSBnZXRTZWFyY2hSdW50aW1lKCk7XG4gICAgICByZXR1cm4gY2xpZW50LnVuaXZlcnNhbFNlYXJjaChcbiAgICAgICAgcmVxdWVzdC5xdWVyeSxcbiAgICAgICAgdG9Vbml2ZXJzYWxTZWFyY2hPcHRpb25zKHJlcXVlc3QsIGNvbnRleHQ/LmFib3J0U2lnbmFsKSxcbiAgICAgICk7XG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIG9wdC1pbiBgYWRkX2RvY3VtZW50c2AgdG9vbCAod3JpdGUgaW50byBhIGRpcmVjdC1hY2Nlc3MgaW5kZXgpLlxuICogT25seSBpbnN0YWxsIGl0IHdoZW4gdGhlIHBsdWdpbidzIHdyaXRlIHN1cmZhY2UgaXMgZW5hYmxlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFkZERvY3VtZW50c1Rvb2wob3B0aW9uczogU2VhcmNoVG9vbE9wdGlvbnMgPSB7fSkge1xuICBjb25zdCBpbnB1dFNjaGVtYSA9IHNoYXJlZFNlYXJjaC5zZWFyY2hEb2N1bWVudFNjaGVtYVxuICAgIC5hcnJheSgpXG4gICAgLmRlc2NyaWJlKFwiRG9jdW1lbnRzIHRvIGFkZCBvciB1cGRhdGUuIEVhY2ggbXVzdCBpbmNsdWRlIHRoZSBpbmRleCBwcmltYXJ5IGtleS5cIik7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogb3B0aW9ucy5pZCA/PyBcImFkZF9kb2N1bWVudHNcIixcbiAgICBkZXNjcmlwdGlvbjogQUREX0RPQ1VNRU5UU19UT09MX0RFU0NSSVBUSU9OLFxuICAgIGlucHV0U2NoZW1hOiBzaGFyZWRTZWFyY2guc2VhcmNoUmVxdWVzdFNjaGVtYVxuICAgICAgLnBpY2soeyBpbmRleDogdHJ1ZSB9KVxuICAgICAgLmV4dGVuZCh7IGRvY3VtZW50czogaW5wdXRTY2hlbWEgfSksXG4gICAgb3V0cHV0U2NoZW1hOiBzaGFyZWRTZWFyY2gudXBzZXJ0UmVzdWx0U2NoZW1hLFxuICAgIGV4ZWN1dGU6IGFzeW5jIChpbnB1dCwgY29udGV4dCk6IFByb21pc2U8VXBzZXJ0UmVzdWx0PiA9PiB7XG4gICAgICBjb25zdCB7IGNsaWVudCwgY29uZmlnIH0gPSBnZXRTZWFyY2hSdW50aW1lKCk7XG4gICAgICBjb25zdCByZWNvcmQgPSBpbnB1dCBhcyB7IGluZGV4Pzogc3RyaW5nOyBkb2N1bWVudHM6IHVua25vd24gfTtcbiAgICAgIGNvbnN0IGRvY3VtZW50cyA9IHRvRG9jdW1lbnRBcnJheShyZWNvcmQuZG9jdW1lbnRzKTtcbiAgICAgIGNvbnN0IGluZGV4ID0gcmVjb3JkLmluZGV4ID8/IGNvbmZpZy5kZWZhdWx0SW5kZXggPz8gXCJcIjtcbiAgICAgIHJldHVybiBjbGllbnQuYWRkRG9jdW1lbnRzKGluZGV4LCBkb2N1bWVudHMsIGNvbnRleHQ/LmFib3J0U2lnbmFsKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgb3B0LWluIGBjcmVhdGVfaW5kZXhgIHRvb2wgKHByb3Zpc2lvbiBhIFZlY3RvciBTZWFyY2ggaW5kZXgpLlxuICogT25seSBpbnN0YWxsIGl0IHdoZW4gdGhlIHBsdWdpbidzIHdyaXRlIHN1cmZhY2UgaXMgZW5hYmxlZC4gRGVsZWdhdGVzIHRvXG4gKiB7QGxpbmsgU2VhcmNoQ2xpZW50LmNyZWF0ZUluZGV4fSwgaW5mZXJyaW5nIHRoZSBlbmRwb2ludCwgZW1iZWRkaW5nIG1vZGVsLFxuICoga2V5LCBhbmQgY29sdW1ucyBmcm9tIHRoZSByZXF1ZXN0ICsgcGx1Z2luIGNvbmZpZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUluZGV4VG9vbChvcHRpb25zOiBTZWFyY2hUb29sT3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogb3B0aW9ucy5pZCA/PyBcImNyZWF0ZV9pbmRleFwiLFxuICAgIGRlc2NyaXB0aW9uOiBDUkVBVEVfSU5ERVhfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogY3JlYXRlSW5kZXhUb29sU2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogaW5kZXhJbmZvU2NoZW1hLFxuICAgIGV4ZWN1dGU6IGFzeW5jIChpbnB1dCwgY29udGV4dCkgPT4ge1xuICAgICAgY29uc3QgcmVxdWVzdCA9IGNyZWF0ZUluZGV4VG9vbFNjaGVtYS5wYXJzZShpbnB1dCk7XG4gICAgICBjb25zdCB7IGNsaWVudCB9ID0gZ2V0U2VhcmNoUnVudGltZSgpO1xuICAgICAgcmV0dXJuIGNsaWVudC5jcmVhdGVJbmRleChyZXF1ZXN0Lm5hbWUsIHRvQ3JlYXRlSW5kZXhPcHRpb25zKHJlcXVlc3QsIGNvbnRleHQ/LmFib3J0U2lnbmFsKSk7XG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKiBPdXRwdXQgc2NoZW1hIGZvciB0aGUgYHN5bmNfaW5kZXhgIHRvb2wuICovXG5jb25zdCBzeW5jSW5kZXhSZXN1bHRTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGluZGV4OiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVGhlIGluZGV4IHRoYXQgd2FzIHN5bmNlZC5cIiksXG4gIHN5bmNlZDogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJUcnVlIG9uY2UgdGhlIHN5bmMgd2FzIHRyaWdnZXJlZC5cIiksXG59KTtcblxuLyoqXG4gKiBCdWlsZCB0aGUgb3B0LWluIGBzeW5jX2luZGV4YCB0b29sIChyZWZyZXNoIGEgRGVsdGEgU3luYyBpbmRleCBmcm9tIGl0c1xuICogc291cmNlIHRhYmxlKS4gT25seSBpbnN0YWxsIGl0IHdoZW4gdGhlIHBsdWdpbidzIHdyaXRlIHN1cmZhY2UgaXMgZW5hYmxlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN5bmNJbmRleFRvb2wob3B0aW9uczogU2VhcmNoVG9vbE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdGlvbnMuaWQgPz8gXCJzeW5jX2luZGV4XCIsXG4gICAgZGVzY3JpcHRpb246IFNZTkNfSU5ERVhfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogc3luY0luZGV4VG9vbFNjaGVtYSxcbiAgICBvdXRwdXRTY2hlbWE6IHN5bmNJbmRleFJlc3VsdFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIGNvbnRleHQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSBzeW5jSW5kZXhUb29sU2NoZW1hLnBhcnNlKGlucHV0KTtcbiAgICAgIGNvbnN0IHsgY2xpZW50LCBjb25maWcgfSA9IGdldFNlYXJjaFJ1bnRpbWUoKTtcbiAgICAgIGNvbnN0IGluZGV4ID0gcmVxdWVzdC5pbmRleCA/PyBjb25maWcuZGVmYXVsdEluZGV4ID8/IFwiXCI7XG4gICAgICBhd2FpdCBjbGllbnQuc3luY0luZGV4KGluZGV4LCBjb250ZXh0Py5hYm9ydFNpZ25hbCk7XG4gICAgICByZXR1cm4geyBpbmRleCwgc3luY2VkOiB0cnVlIH07XG4gICAgfSxcbiAgfSk7XG59XG4iXX0=
147
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBRSxNQUFNLElBQUksWUFBWSxFQUFxQixNQUFNLDBCQUEwQixDQUFDO0FBQ3JGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxlQUFlLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUdqRixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN4RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxtQkFBbUIsRUFBc0IsTUFBTSxjQUFjLENBQUM7QUFDdkUsT0FBTyxFQUNMLDhCQUE4QixFQUM5Qiw2QkFBNkIsRUFDN0IsdUJBQXVCLEVBQ3ZCLDJCQUEyQixFQUMzQixpQ0FBaUMsRUFDakMscUJBQXFCLEVBQ3JCLGVBQWUsRUFDZixrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLG1CQUFtQixFQUNuQix5QkFBeUIsR0FDMUIsTUFBTSxhQUFhLENBQUM7QUFjckIsNEVBQTRFO0FBQzVFLFNBQVMsV0FBVyxDQUFDLE9BQTBCO0lBQzdDLElBQUksT0FBTyxDQUFDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7UUFDL0QsTUFBTSxJQUFJLFNBQVMsQ0FBQyxvRUFBb0UsQ0FBQyxDQUFDO0lBQzVGLENBQUM7SUFDRCxPQUFPLENBQ0wsT0FBTyxDQUFDLE9BQU87UUFDZixtQkFBbUIsQ0FBQztZQUNsQixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07WUFDdEIsV0FBVyxFQUFFLE9BQU8sQ0FB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O1FBQ2hDLFlBQVksRUFBRSxxQkFBcUI7UUFDbkMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDaEMsTUFBTSxPQUFPLEdBQUcsbUJBQW1CLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2pELE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDO1lBQ25DLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLElBQUksTUFBTSxDQUFDLFlBQVksSUFBSSxFQUFFLENBQUM7WUFDekQsTUFBTSxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7WUFDcEQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDakMsQ0FBQztLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoZSBgc2VhcmNoYCwgYHVuaXZlcnNhbF9zZWFyY2hgLCBhbmQgKG9wdC1pbikgYGFkZF9kb2N1bWVudHNgLFxuICogYGNyZWF0ZV9pbmRleGAsIGFuZCBgc3luY19pbmRleGAgTWFzdHJhIHRvb2xzLlxuICpcbiAqIEFwcC1pbnRlZ3JhdGVkIGFnZW50cyBzaG91bGQgY29uc3VtZSB0aGUgcGx1Z2luJ3MgbmF0aXZlIHRvb2xraXQgc28gY2FsbHNcbiAqIHJldGFpbiB0aGF0IHBsdWdpbidzIGNvbmZpZyBhbmQgcHJvdmlkZXIgYmFja2VuZC4gVGhlc2Ugc3RhbmRhbG9uZSBmYWN0b3JpZXNcbiAqIGNhcHR1cmUgYW4gZXhwbGljaXQgcnVudGltZSBvciBidWlsZCBhbiBpc29sYXRlZCBvbmUgZnJvbSBjb25maWcgcGx1cyBhXG4gKiBwcm92aWRlci4gVGhleSBydW4gdW5kZXIgdGhlIGNhbGxlcidzIE9CTyBzY29wZSAodGhlIGNsaWVudCByZXNvbHZlcyB0aGVcbiAqIGV4ZWN1dGlvbiBjb250ZXh0J3Mgd29ya3NwYWNlIGNsaWVudCksIHNvIHNlYXJjaCBydW5zIGFzIHRoZSByZXF1ZXN0aW5nIHVzZXJcbiAqIGFuZCBVbml0eSBDYXRhbG9nIEFDTHMgYXBwbHkuXG4gKlxuICogVGhlIHNhbWUgdG9vbHMgYXJlIGV4cG9zZWQgdG8gQXBwS2l0J3Mgb3duIGFnZW50cyB0aHJvdWdoIHRoZSBwbHVnaW4nc1xuICogYFRvb2xQcm92aWRlcmAgKHNlZSBgcGx1Z2luLnRzYCkuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHNlYXJjaCBhcyBzaGFyZWRTZWFyY2gsIHR5cGUgVXBzZXJ0UmVzdWx0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLXNlYXJjaFwiO1xuaW1wb3J0IHsgY3JlYXRlVG9vbCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvdG9vbHNcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgeyB0b1NlYXJjaE9wdGlvbnMsIHRvVW5pdmVyc2FsU2VhcmNoT3B0aW9ucyB9IGZyb20gXCIuL19zZWFyY2gtb3B0aW9ucy50c1wiO1xuaW1wb3J0IHR5cGUgeyBTZWFyY2hSZWFkQmFja2VuZCB9IGZyb20gXCIuL2NsaWVudC50c1wiO1xuaW1wb3J0IHR5cGUgeyBTZWFyY2hQbHVnaW5Db25maWcgfSBmcm9tIFwiLi9jb25maWcudHNcIjtcbmltcG9ydCB7IHRvQ3JlYXRlSW5kZXhPcHRpb25zIH0gZnJvbSBcIi4vaW5kZXgtdG9vbHMudHNcIjtcbmltcG9ydCB7IHRvRG9jdW1lbnRBcnJheSB9IGZyb20gXCIuL3F1ZXJ5LnRzXCI7XG5pbXBvcnQgeyBjcmVhdGVTZWFyY2hSdW50aW1lLCB0eXBlIFNlYXJjaFJ1bnRpbWUgfSBmcm9tIFwiLi9ydW50aW1lLnRzXCI7XG5pbXBvcnQge1xuICBBRERfRE9DVU1FTlRTX1RPT0xfREVTQ1JJUFRJT04sXG4gIENSRUFURV9JTkRFWF9UT09MX0RFU0NSSVBUSU9OLFxuICBTRUFSQ0hfVE9PTF9ERVNDUklQVElPTixcbiAgU1lOQ19JTkRFWF9UT09MX0RFU0NSSVBUSU9OLFxuICBVTklWRVJTQUxfU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sXG4gIGNyZWF0ZUluZGV4VG9vbFNjaGVtYSxcbiAgaW5kZXhJbmZvU2NoZW1hLFxuICBzZWFyY2hSZXN1bHRTY2hlbWEsXG4gIHNlYXJjaFRvb2xTY2hlbWEsXG4gIHN5bmNJbmRleFRvb2xTY2hlbWEsXG4gIHVuaXZlcnNhbFNlYXJjaFRvb2xTY2hlbWEsXG59IGZyb20gXCIuL3NjaGVtYS50c1wiO1xuXG4vKiogT3B0aW9ucyBhY2NlcHRlZCBieSBldmVyeSBzdGFuZGFsb25lIHRvb2wgZmFjdG9yeS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VhcmNoVG9vbE9wdGlvbnMge1xuICAvKiogT3ZlcnJpZGUgdGhlIHRvb2wgaWQgKGRlZmF1bHRzIHBlciB0b29sKS4gKi9cbiAgaWQ/OiBzdHJpbmc7XG4gIC8qKiBJc29sYXRlZCBydW50aW1lIHVzZWQgYnkgdGhpcyBzdGFuZGFsb25lIHRvb2wuIE11dHVhbGx5IGV4Y2x1c2l2ZSB3aXRoIGNvbmZpZy9iYWNrZW5kLiAqL1xuICBydW50aW1lPzogU2VhcmNoUnVudGltZTtcbiAgLyoqIENvbmZpZyB1c2VkIHRvIGNyZWF0ZSBhbiBpc29sYXRlZCBydW50aW1lLiAqL1xuICBjb25maWc/OiBTZWFyY2hQbHVnaW5Db25maWc7XG4gIC8qKiBQcm92aWRlciB1c2VkIHdoZW4gY3JlYXRpbmcgYSBydW50aW1lIGZyb20gY29uZmlnLiAqL1xuICByZWFkQmFja2VuZD86IFNlYXJjaFJlYWRCYWNrZW5kO1xufVxuXG4vKiogUmVzb2x2ZSB0aGUgaXNvbGF0ZWQgcnVudGltZSBjYXB0dXJlZCBieSBvbmUgc3RhbmRhbG9uZSB0b29sIGZhY3RvcnkuICovXG5mdW5jdGlvbiB0b29sUnVudGltZShvcHRpb25zOiBTZWFyY2hUb29sT3B0aW9ucyk6IFNlYXJjaFJ1bnRpbWUge1xuICBpZiAob3B0aW9ucy5ydW50aW1lICYmIChvcHRpb25zLmNvbmZpZyB8fCBvcHRpb25zLnJlYWRCYWNrZW5kKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJzZWFyY2ggdG9vbCBvcHRpb25zIGFjY2VwdCBydW50aW1lIG9yIGNvbmZpZy9yZWFkQmFja2VuZCwgbm90IGJvdGhcIik7XG4gIH1cbiAgcmV0dXJuIChcbiAgICBvcHRpb25zLnJ1bnRpbWUgPz9cbiAgICBjcmVhdGVTZWFyY2hSdW50aW1lKHtcbiAgICAgIGNvbmZpZzogb3B0aW9ucy5jb25maWcsXG4gICAgICByZWFkQmFja2VuZDogb3B0aW9ucy5yZWFkQmFja2VuZCxcbiAgICB9KVxuICApO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBgc2VhcmNoYCB0b29sLiBTcHJlYWQgaXQgaW50byBhbnkgYWdlbnQgdGhhdCBzaG91bGQgYmUgYWJsZSB0byBsb29rXG4gKiB0aGluZ3MgdXAgaW4gYW4gaW5kZXguXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBzZWFyY2hUb29sIH0gZnJvbSBcIkBkYngtdG9vbHMvc2VhcmNoXCI7XG4gKiBpbXBvcnQgeyBjcmVhdGVBZ2VudCB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC1tYXN0cmFcIjtcbiAqXG4gKiBjb25zdCBzdXBwb3J0ID0gY3JlYXRlQWdlbnQoe1xuICogICBpbnN0cnVjdGlvbnM6IFwiQW5zd2VyIGZyb20gdGhlIGRvY3MuIFVzZSBgc2VhcmNoYCB0byBmaW5kIHRoZW0uXCIsXG4gKiAgIHRvb2xzOiAoKSA9PiAoeyBzZWFyY2g6IHNlYXJjaFRvb2woKSB9KSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZWFyY2hUb29sKG9wdGlvbnM6IFNlYXJjaFRvb2xPcHRpb25zID0ge30pIHtcbiAgY29uc3QgcnVudGltZSA9IHRvb2xSdW50aW1lKG9wdGlvbnMpO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdGlvbnMuaWQgPz8gXCJzZWFyY2hcIixcbiAgICBkZXNjcmlwdGlvbjogU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sXG4gICAgaW5wdXRTY2hlbWE6IHNlYXJjaFRvb2xTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBzZWFyY2hSZXN1bHRTY2hlbWEsXG4gICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0LCBjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gc2VhcmNoVG9vbFNjaGVtYS5wYXJzZShpbnB1dCk7XG4gICAgICByZXR1cm4gcnVudGltZS5jbGllbnQuc2VhcmNoKHJlcXVlc3QucXVlcnksIHRvU2VhcmNoT3B0aW9ucyhyZXF1ZXN0LCBjb250ZXh0Py5hYm9ydFNpZ25hbCkpO1xuICAgIH0sXG4gIH0pO1xufVxuXG4vKiogQnVpbGQgdGhlIGB1bml2ZXJzYWxfc2VhcmNoYCB0b29sIChmZWRlcmF0ZWQgc2VhcmNoIGFjcm9zcyBldmVyeSBpbmRleCkuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pdmVyc2FsU2VhcmNoVG9vbChvcHRpb25zOiBTZWFyY2hUb29sT3B0aW9ucyA9IHt9KSB7XG4gIGNvbnN0IHJ1bnRpbWUgPSB0b29sUnVudGltZShvcHRpb25zKTtcbiAgcmV0dXJuIGNyZWF0ZVRvb2woe1xuICAgIGlkOiBvcHRpb25zLmlkID8/IFwidW5pdmVyc2FsX3NlYXJjaFwiLFxuICAgIGRlc2NyaXB0aW9uOiBVTklWRVJTQUxfU0VBUkNIX1RPT0xfREVTQ1JJUFRJT04sXG4gICAgaW5wdXRTY2hlbWE6IHVuaXZlcnNhbFNlYXJjaFRvb2xTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBzZWFyY2hSZXN1bHRTY2hlbWEsXG4gICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0LCBjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gdW5pdmVyc2FsU2VhcmNoVG9vbFNjaGVtYS5wYXJzZShpbnB1dCk7XG4gICAgICByZXR1cm4gcnVudGltZS5jbGllbnQudW5pdmVyc2FsU2VhcmNoKFxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LFxuICAgICAgICB0b1VuaXZlcnNhbFNlYXJjaE9wdGlvbnMocmVxdWVzdCwgY29udGV4dD8uYWJvcnRTaWduYWwpLFxuICAgICAgKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgb3B0LWluIGBhZGRfZG9jdW1lbnRzYCB0b29sICh3cml0ZSBpbnRvIGEgZGlyZWN0LWFjY2VzcyBpbmRleCkuXG4gKiBPbmx5IGluc3RhbGwgaXQgd2hlbiB0aGUgcGx1Z2luJ3Mgd3JpdGUgc3VyZmFjZSBpcyBlbmFibGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkRG9jdW1lbnRzVG9vbChvcHRpb25zOiBTZWFyY2hUb29sT3B0aW9ucyA9IHt9KSB7XG4gIGNvbnN0IHJ1bnRpbWUgPSB0b29sUnVudGltZShvcHRpb25zKTtcbiAgY29uc3QgaW5wdXRTY2hlbWEgPSBzaGFyZWRTZWFyY2guc2VhcmNoRG9jdW1lbnRTY2hlbWFcbiAgICAuYXJyYXkoKVxuICAgIC5kZXNjcmliZShcIkRvY3VtZW50cyB0byBhZGQgb3IgdXBkYXRlLiBFYWNoIG11c3QgaW5jbHVkZSB0aGUgaW5kZXggcHJpbWFyeSBrZXkuXCIpO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdGlvbnMuaWQgPz8gXCJhZGRfZG9jdW1lbnRzXCIsXG4gICAgZGVzY3JpcHRpb246IEFERF9ET0NVTUVOVFNfVE9PTF9ERVNDUklQVElPTixcbiAgICBpbnB1dFNjaGVtYTogc2hhcmVkU2VhcmNoLnNlYXJjaFJlcXVlc3RTY2hlbWFcbiAgICAgIC5waWNrKHsgaW5kZXg6IHRydWUgfSlcbiAgICAgIC5leHRlbmQoeyBkb2N1bWVudHM6IGlucHV0U2NoZW1hIH0pLFxuICAgIG91dHB1dFNjaGVtYTogc2hhcmVkU2VhcmNoLnVwc2VydFJlc3VsdFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIGNvbnRleHQpOiBQcm9taXNlPFVwc2VydFJlc3VsdD4gPT4ge1xuICAgICAgY29uc3QgeyBjbGllbnQsIGNvbmZpZyB9ID0gcnVudGltZTtcbiAgICAgIGNvbnN0IHJlY29yZCA9IGlucHV0IGFzIHsgaW5kZXg/OiBzdHJpbmc7IGRvY3VtZW50czogdW5rbm93biB9O1xuICAgICAgY29uc3QgZG9jdW1lbnRzID0gdG9Eb2N1bWVudEFycmF5KHJlY29yZC5kb2N1bWVudHMpO1xuICAgICAgY29uc3QgaW5kZXggPSByZWNvcmQuaW5kZXggPz8gY29uZmlnLmRlZmF1bHRJbmRleCA/PyBcIlwiO1xuICAgICAgcmV0dXJuIGNsaWVudC5hZGREb2N1bWVudHMoaW5kZXgsIGRvY3VtZW50cywgY29udGV4dD8uYWJvcnRTaWduYWwpO1xuICAgIH0sXG4gIH0pO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBvcHQtaW4gYGNyZWF0ZV9pbmRleGAgdG9vbCAocHJvdmlzaW9uIGEgVmVjdG9yIFNlYXJjaCBpbmRleCkuXG4gKiBPbmx5IGluc3RhbGwgaXQgd2hlbiB0aGUgcGx1Z2luJ3Mgd3JpdGUgc3VyZmFjZSBpcyBlbmFibGVkLiBEZWxlZ2F0ZXMgdG9cbiAqIHtAbGluayBTZWFyY2hDbGllbnQuY3JlYXRlSW5kZXh9LCBpbmZlcnJpbmcgdGhlIGVuZHBvaW50LCBlbWJlZGRpbmcgbW9kZWwsXG4gKiBrZXksIGFuZCBjb2x1bW5zIGZyb20gdGhlIHJlcXVlc3QgKyBwbHVnaW4gY29uZmlnLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlSW5kZXhUb29sKG9wdGlvbnM6IFNlYXJjaFRvb2xPcHRpb25zID0ge30pIHtcbiAgY29uc3QgcnVudGltZSA9IHRvb2xSdW50aW1lKG9wdGlvbnMpO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IG9wdGlvbnMuaWQgPz8gXCJjcmVhdGVfaW5kZXhcIixcbiAgICBkZXNjcmlwdGlvbjogQ1JFQVRFX0lOREVYX1RPT0xfREVTQ1JJUFRJT04sXG4gICAgaW5wdXRTY2hlbWE6IGNyZWF0ZUluZGV4VG9vbFNjaGVtYSxcbiAgICBvdXRwdXRTY2hlbWE6IGluZGV4SW5mb1NjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIGNvbnRleHQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSBjcmVhdGVJbmRleFRvb2xTY2hlbWEucGFyc2UoaW5wdXQpO1xuICAgICAgcmV0dXJuIHJ1bnRpbWUuY2xpZW50LmNyZWF0ZUluZGV4KFxuICAgICAgICByZXF1ZXN0Lm5hbWUsXG4gICAgICAgIHRvQ3JlYXRlSW5kZXhPcHRpb25zKHJlcXVlc3QsIGNvbnRleHQ/LmFib3J0U2lnbmFsKSxcbiAgICAgICk7XG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKiBPdXRwdXQgc2NoZW1hIGZvciB0aGUgYHN5bmNfaW5kZXhgIHRvb2wuICovXG5jb25zdCBzeW5jSW5kZXhSZXN1bHRTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGluZGV4OiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVGhlIGluZGV4IHRoYXQgd2FzIHN5bmNlZC5cIiksXG4gIHN5bmNlZDogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJUcnVlIG9uY2UgdGhlIHN5bmMgd2FzIHRyaWdnZXJlZC5cIiksXG59KTtcblxuLyoqXG4gKiBCdWlsZCB0aGUgb3B0LWluIGBzeW5jX2luZGV4YCB0b29sIChyZWZyZXNoIGEgRGVsdGEgU3luYyBpbmRleCBmcm9tIGl0c1xuICogc291cmNlIHRhYmxlKS4gT25seSBpbnN0YWxsIGl0IHdoZW4gdGhlIHBsdWdpbidzIHdyaXRlIHN1cmZhY2UgaXMgZW5hYmxlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN5bmNJbmRleFRvb2wob3B0aW9uczogU2VhcmNoVG9vbE9wdGlvbnMgPSB7fSkge1xuICBjb25zdCBydW50aW1lID0gdG9vbFJ1bnRpbWUob3B0aW9ucyk7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogb3B0aW9ucy5pZCA/PyBcInN5bmNfaW5kZXhcIixcbiAgICBkZXNjcmlwdGlvbjogU1lOQ19JTkRFWF9UT09MX0RFU0NSSVBUSU9OLFxuICAgIGlucHV0U2NoZW1hOiBzeW5jSW5kZXhUb29sU2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogc3luY0luZGV4UmVzdWx0U2NoZW1hLFxuICAgIGV4ZWN1dGU6IGFzeW5jIChpbnB1dCwgY29udGV4dCkgPT4ge1xuICAgICAgY29uc3QgcmVxdWVzdCA9IHN5bmNJbmRleFRvb2xTY2hlbWEucGFyc2UoaW5wdXQpO1xuICAgICAgY29uc3QgeyBjbGllbnQsIGNvbmZpZyB9ID0gcnVudGltZTtcbiAgICAgIGNvbnN0IGluZGV4ID0gcmVxdWVzdC5pbmRleCA/PyBjb25maWcuZGVmYXVsdEluZGV4ID8/IFwiXCI7XG4gICAgICBhd2FpdCBjbGllbnQuc3luY0luZGV4KGluZGV4LCBjb250ZXh0Py5hYm9ydFNpZ25hbCk7XG4gICAgICByZXR1cm4geyBpbmRleCwgc3luY2VkOiB0cnVlIH07XG4gICAgfSxcbiAgfSk7XG59XG4iXX0=
package/package.json CHANGED
@@ -29,12 +29,12 @@
29
29
  "dependencies": {
30
30
  "@databricks/appkit": "^0.60.0",
31
31
  "@databricks/sdk-experimental": "^0.17.0",
32
- "@dbx-tools/appkit": "0.6.222",
33
- "@dbx-tools/core": "0.6.222",
34
- "@dbx-tools/model": "0.6.222",
35
- "@dbx-tools/shared-core": "0.6.222",
36
- "@dbx-tools/shared-model": "0.6.222",
37
- "@dbx-tools/shared-search": "0.6.222",
32
+ "@dbx-tools/appkit": "0.6.224",
33
+ "@dbx-tools/core": "0.6.224",
34
+ "@dbx-tools/model": "0.6.224",
35
+ "@dbx-tools/shared-core": "0.6.224",
36
+ "@dbx-tools/shared-model": "0.6.224",
37
+ "@dbx-tools/shared-search": "0.6.224",
38
38
  "@mastra/core": "1.71.0",
39
39
  "pg": "^8.22.0",
40
40
  "zod": "4.3.6"
@@ -53,7 +53,7 @@
53
53
  "./package.json": "./package.json"
54
54
  }
55
55
  },
56
- "version": "0.6.222",
56
+ "version": "0.6.224",
57
57
  "types": "./lib/index.d.ts",
58
58
  "type": "module",
59
59
  "exports": {
package/src/plugin.ts CHANGED
@@ -34,12 +34,12 @@ import {
34
34
  import { plugin as appkitPlugin } from "@dbx-tools/appkit";
35
35
  import { error as sharedError, log, string } from "@dbx-tools/shared-core";
36
36
  import { search as sharedSearch, type SearchClientConfig } from "@dbx-tools/shared-search";
37
+ import { toSearchOptions, toUniversalSearchOptions } from "./_search-options.ts";
37
38
  import { SEARCH_CONFIG_SCHEMA, resolveSearchConfig, type SearchPluginConfig } from "./config.ts";
38
39
  import { toCreateIndexOptions } from "./index-tools.ts";
39
40
  import { nativeAiSearchBackend } from "./native.ts";
40
41
  import { toDocumentArray } from "./query.ts";
41
- import { getSearchRuntime, resetSearchRuntime } from "./runtime.ts";
42
- import { toSearchOptions, toUniversalSearchOptions } from "./_search-options.ts";
42
+ import { createSearchRuntime, setSearchReadBackend, type SearchRuntime } from "./runtime.ts";
43
43
  import {
44
44
  ADD_DOCUMENTS_TOOL_DESCRIPTION,
45
45
  CREATE_INDEX_TOOL_DESCRIPTION,
@@ -110,6 +110,9 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
110
110
  config: { schema: SEARCH_CONFIG_SCHEMA },
111
111
  } satisfies PluginManifest<"search">;
112
112
 
113
+ /** Runtime owned exclusively by this plugin instance. */
114
+ private readonly runtime: SearchRuntime = createSearchRuntime({ config: this.config });
115
+
113
116
  /** The base path AppKit mounts this plugin's routes under. */
114
117
  private get basePath(): string {
115
118
  return `/api/${SearchPlugin.manifest.name}`;
@@ -123,7 +126,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
123
126
  * granted explicitly.
124
127
  */
125
128
  private get tools(): ToolRegistry {
126
- const { config, readBackend } = getSearchRuntime({ config: this.config });
129
+ const { config, readBackend } = this.runtime;
127
130
  const registry: ToolRegistry = {
128
131
  search: defineTool({
129
132
  description: SEARCH_TOOL_DESCRIPTION,
@@ -170,16 +173,11 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
170
173
  return registry;
171
174
  }
172
175
 
173
- /** Prime the shared runtime from config and log the effective policy at boot. */
176
+ /** Attach the registered provider and log the effective policy at boot. */
174
177
  override async setup(): Promise<void> {
175
178
  const readBackend = this.resolveProviderBackend();
176
- // The runtime may already have been built (config-only) when `tools()` ran
177
- // during registration; rebuild it so it carries the chosen backend.
178
- resetSearchRuntime();
179
- const { config } = getSearchRuntime({
180
- config: this.config,
181
- readBackend,
182
- });
179
+ setSearchReadBackend(this.runtime, readBackend);
180
+ const { config } = this.runtime;
183
181
  logger.info("ready", {
184
182
  backend: readBackend.supportsLifecycle ? "appkit-ai-search" : "lakebase-ai-search",
185
183
  defaultIndex: config.defaultIndex ?? "(none - pass per request)",
@@ -211,9 +209,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
211
209
  * out-of-request fallback. Failures are logged, never thrown - a search app
212
210
  * should still start even if provisioning is slow or a permission is missing.
213
211
  */
214
- private async runEnsureOnSetup(
215
- config: ReturnType<typeof getSearchRuntime>["config"],
216
- ): Promise<void> {
212
+ private async runEnsureOnSetup(config: SearchRuntime["config"]): Promise<void> {
217
213
  const spec = config.ensureOnSetup;
218
214
  if (!spec) return;
219
215
  const index = string.trimToNull(spec.index) ?? config.defaultIndex;
@@ -232,7 +228,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
232
228
  : undefined);
233
229
  try {
234
230
  logger.info("ensure-start", { index });
235
- const { client } = getSearchRuntime();
231
+ const { client } = this.runtime;
236
232
  const info = await client.provision(index, {
237
233
  ...(spec.endpoint ? { endpoint: spec.endpoint } : {}),
238
234
  ...(spec.primaryKey ? { primaryKey: spec.primaryKey } : {}),
@@ -274,14 +270,13 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
274
270
  return schema;
275
271
  }
276
272
 
277
- /** Drop the shared runtime so a restarted app re-resolves config. */
278
- async shutdown(): Promise<void> {
279
- resetSearchRuntime();
273
+ /** Release this plugin's instance-owned runtime. */
274
+ shutdown(): void {
275
+ return;
280
276
  }
281
277
 
282
278
  override abortActiveOperations(): void {
283
279
  super.abortActiveOperations();
284
- void this.shutdown();
285
280
  }
286
281
 
287
282
  /**
@@ -313,7 +308,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
313
308
  method: "post",
314
309
  path: DOCUMENTS_ROUTE,
315
310
  handler: async (req, res) => {
316
- const { config } = getSearchRuntime();
311
+ const { config } = this.runtime;
317
312
  if (!config.allowWrite) {
318
313
  res.status(403).json({ error: "the document write surface is disabled" });
319
314
  return;
@@ -328,7 +323,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
328
323
  method: "post",
329
324
  path: INDEX_ROUTE,
330
325
  handler: async (req, res) => {
331
- const { config, readBackend } = getSearchRuntime();
326
+ const { config, readBackend } = this.runtime;
332
327
  if (!config.allowWrite || !readBackend?.supportsLifecycle) {
333
328
  res.status(403).json({ error: "the index write surface is disabled" });
334
329
  return;
@@ -343,7 +338,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
343
338
  method: "post",
344
339
  path: INDEX_SYNC_ROUTE,
345
340
  handler: async (req, res) => {
346
- const { config, readBackend } = getSearchRuntime();
341
+ const { config, readBackend } = this.runtime;
347
342
  if (!config.allowWrite || !readBackend?.supportsLifecycle) {
348
343
  res.status(403).json({ error: "the index write surface is disabled" });
349
344
  return;
@@ -378,7 +373,7 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
378
373
 
379
374
  /** Surface the index catalogue + defaults so a search box needs no round-trip. */
380
375
  override clientConfig(): Record<string, unknown> {
381
- const { config } = getSearchRuntime({ config: this.config });
376
+ const { config } = this.runtime;
382
377
  const payload: SearchClientConfig = {
383
378
  indexes: config.indexes.map((index) => ({
384
379
  name: index.name,
@@ -426,19 +421,19 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
426
421
 
427
422
  private async runSearch(args: unknown, signal?: AbortSignal) {
428
423
  const request = sharedSearch.searchRequestSchema.parse(args);
429
- const { client } = getSearchRuntime();
424
+ const { client } = this.runtime;
430
425
  return client.search(request.query, toSearchOptions(request, signal));
431
426
  }
432
427
 
433
428
  private async runUniversalSearch(args: unknown, signal?: AbortSignal) {
434
429
  const request = sharedSearch.universalSearchRequestSchema.parse(args);
435
- const { client } = getSearchRuntime();
430
+ const { client } = this.runtime;
436
431
  return client.universalSearch(request.query, toUniversalSearchOptions(request, signal));
437
432
  }
438
433
 
439
434
  private async runAddDocuments(args: unknown, signal?: AbortSignal) {
440
435
  const record = (args ?? {}) as { index?: string; documents: unknown };
441
- const { client, config } = getSearchRuntime();
436
+ const { client, config } = this.runtime;
442
437
  const documents = toDocumentArray(record.documents);
443
438
  const index = record.index ?? config.defaultIndex ?? "";
444
439
  return client.addDocuments(index, documents, signal);
@@ -446,13 +441,13 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
446
441
 
447
442
  private async runCreateIndex(args: unknown, signal?: AbortSignal) {
448
443
  const request = sharedSearch.createIndexRequestSchema.parse(args);
449
- const { client } = getSearchRuntime();
444
+ const { client } = this.runtime;
450
445
  return client.createIndex(request.name, toCreateIndexOptions(request, signal));
451
446
  }
452
447
 
453
448
  private async runSyncIndex(args: unknown, signal?: AbortSignal) {
454
449
  const request = sharedSearch.syncIndexRequestSchema.parse(args);
455
- const { client, config } = getSearchRuntime();
450
+ const { client, config } = this.runtime;
456
451
  const index = request.index ?? config.defaultIndex ?? "";
457
452
  await client.syncIndex(index, signal);
458
453
  return { index, synced: true };
@@ -465,12 +460,14 @@ export class SearchPlugin extends Plugin<SearchPluginConfig> implements ToolProv
465
460
  * @example
466
461
  * ```ts
467
462
  * import { createApp, server } from "@databricks/appkit";
468
- * import { plugin as searchPlugin, tool as searchToolApi } from "@dbx-tools/search";
463
+ * import { plugin as searchPlugin } from "@dbx-tools/search";
469
464
  * import { agents, plugin as mastraPlugin } from "@dbx-tools/appkit-mastra";
470
465
  *
471
466
  * const support = agents.createAgent({
472
467
  * instructions: "Answer from the docs; use `search` to find them.",
473
- * tools: () => ({ search: searchToolApi.searchTool() }),
468
+ * async tools(plugins) {
469
+ * return { ...(await plugins.search.toolkit()) };
470
+ * },
474
471
  * });
475
472
  *
476
473
  * await createApp({
package/src/runtime.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
- * The shared AI Search runtime: the resolved config plus a single
3
- * {@link SearchClient} instance the plugin, the Mastra tools, and the routes
4
- * all read. Mirrors the web-search / email runtime pattern - the plugin primes
5
- * it from its config at setup, and everything else reads the same instance so
6
- * a tool invoked outside the agent still sees the deployment's config.
2
+ * AI Search runtime construction helpers.
3
+ *
4
+ * Each plugin and standalone tool set owns its runtime and client. Provider
5
+ * attachment updates only that runtime, so two apps in one process can use
6
+ * different backends without sharing state.
7
7
  *
8
8
  * @module
9
9
  */
@@ -15,40 +15,49 @@ import {
15
15
  type ResolvedSearchConfig,
16
16
  } from "./config.ts";
17
17
 
18
- /** Configuration and provider used to build the shared extension runtime. */
18
+ /** Configuration and provider used to build an extension runtime. */
19
19
  export interface SearchRuntimeOptions {
20
20
  config?: SearchPluginConfig;
21
21
  readBackend?: SearchReadBackend;
22
22
  }
23
23
 
24
- /** The shared resolved config plus the client reads run through. */
24
+ /** The resolved config plus the client reads run through. */
25
25
  export interface SearchRuntime {
26
26
  config: ResolvedSearchConfig;
27
27
  client: SearchClient;
28
28
  readBackend?: SearchReadBackend;
29
29
  }
30
30
 
31
- let runtime: SearchRuntime | undefined;
31
+ /** Build an isolated runtime for one plugin instance or standalone tool set. */
32
+ export function createSearchRuntime(options: SearchRuntimeOptions = {}): SearchRuntime {
33
+ const config = resolveSearchConfig(options.config);
34
+ return {
35
+ config,
36
+ client: createSearchClient(config, undefined, options.readBackend),
37
+ ...(options.readBackend ? { readBackend: options.readBackend } : {}),
38
+ };
39
+ }
40
+
41
+ /** Attach a provider to one runtime while preserving its object identity. */
42
+ export function setSearchReadBackend(runtime: SearchRuntime, readBackend: SearchReadBackend): void {
43
+ runtime.readBackend = readBackend;
44
+ runtime.client = createSearchClient(runtime.config, undefined, readBackend);
45
+ }
32
46
 
33
47
  /**
34
- * Return the shared runtime, building it on first use from the supplied config
35
- * layered over environment defaults. Overrides are only read when the runtime
36
- * is first created, so prime it from the plugin's config at setup; subsequent
37
- * calls pass nothing and get the same instance.
48
+ * Build an isolated standalone runtime.
49
+ *
50
+ * @deprecated Use {@link createSearchRuntime}. This compatibility helper
51
+ * returns a new runtime on every call and never reads or updates plugin state.
38
52
  */
39
53
  export function getSearchRuntime(options?: SearchRuntimeOptions): SearchRuntime {
40
- if (!runtime) {
41
- const config = resolveSearchConfig(options?.config);
42
- runtime = {
43
- config,
44
- client: createSearchClient(config, undefined, options?.readBackend),
45
- ...(options?.readBackend ? { readBackend: options.readBackend } : {}),
46
- };
47
- }
48
- return runtime;
54
+ return createSearchRuntime(options);
49
55
  }
50
56
 
51
- /** Drop the memoized runtime so the next {@link getSearchRuntime} rebuilds it. */
57
+ /**
58
+ * @deprecated Plugin runtimes are instance-owned and need no global reset.
59
+ * This compatibility helper is intentionally a no-op.
60
+ */
52
61
  export function resetSearchRuntime(): void {
53
- runtime = undefined;
62
+ return;
54
63
  }