@dbx-tools/appkit-mastra 0.3.44 → 0.4.0

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.
Files changed (56) hide show
  1. package/lib/index.d.ts +71 -0
  2. package/lib/index.js +56 -0
  3. package/lib/src/agents.d.ts +347 -0
  4. package/lib/src/agents.js +554 -0
  5. package/lib/src/chart.d.ts +192 -0
  6. package/lib/src/chart.js +638 -0
  7. package/lib/src/config.d.ts +479 -0
  8. package/lib/src/config.js +190 -0
  9. package/lib/src/defaults.d.ts +68 -0
  10. package/lib/src/defaults.js +107 -0
  11. package/lib/src/filesystems.d.ts +208 -0
  12. package/lib/src/filesystems.js +958 -0
  13. package/lib/src/genie.d.ts +166 -0
  14. package/lib/src/genie.js +969 -0
  15. package/lib/src/history.d.ts +97 -0
  16. package/lib/src/history.js +264 -0
  17. package/lib/src/mcp.d.ts +66 -0
  18. package/lib/src/mcp.js +65 -0
  19. package/lib/src/memory.d.ts +111 -0
  20. package/lib/src/memory.js +275 -0
  21. package/lib/src/mlflow.d.ts +63 -0
  22. package/lib/src/mlflow.js +117 -0
  23. package/lib/src/model.d.ts +62 -0
  24. package/lib/src/model.js +168 -0
  25. package/lib/src/observability.d.ts +81 -0
  26. package/lib/src/observability.js +98 -0
  27. package/lib/src/pagination.d.ts +23 -0
  28. package/lib/src/pagination.js +31 -0
  29. package/lib/src/plugin.d.ts +352 -0
  30. package/lib/src/plugin.js +1015 -0
  31. package/lib/src/processors.d.ts +62 -0
  32. package/lib/src/processors.js +162 -0
  33. package/lib/src/rest.d.ts +36 -0
  34. package/lib/src/rest.js +46 -0
  35. package/lib/src/server.d.ts +155 -0
  36. package/lib/src/server.js +336 -0
  37. package/lib/src/serving-sanitize.d.ts +104 -0
  38. package/lib/src/serving-sanitize.js +228 -0
  39. package/lib/src/serving.d.ts +61 -0
  40. package/lib/src/serving.js +78 -0
  41. package/lib/src/statement.d.ts +51 -0
  42. package/lib/src/statement.js +83 -0
  43. package/lib/src/storage-schema.d.ts +14 -0
  44. package/lib/src/storage-schema.js +34 -0
  45. package/lib/src/summarize.d.ts +70 -0
  46. package/lib/src/summarize.js +142 -0
  47. package/lib/src/threads.d.ts +109 -0
  48. package/lib/src/threads.js +301 -0
  49. package/lib/src/validation.d.ts +19 -0
  50. package/lib/src/validation.js +17 -0
  51. package/lib/src/workspaces.d.ts +68 -0
  52. package/lib/src/workspaces.js +246 -0
  53. package/lib/src/writer.d.ts +25 -0
  54. package/lib/src/writer.js +40 -0
  55. package/lib/tsconfig.tsbuildinfo +1 -0
  56. package/package.json +17 -13
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Express-layer plumbing for the Mastra plugin: a `MastraServer` that
3
+ * stamps the per-request `RequestContext`, and a route-patch middleware
4
+ * that lets the plugin's custom API routes (e.g. `historyRoute`) work
5
+ * behind an Express mount point.
6
+ *
7
+ * @module
8
+ */
9
+ import { getExecutionContext } from "@databricks/appkit";
10
+ import { hash, http, log, object, string, token } from "@dbx-tools/shared-core";
11
+ import { feedback, thread } from "@dbx-tools/shared-mastra";
12
+ import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext, } from "@mastra/core/request-context";
13
+ import { MastraServer as MastraServerExpress } from "@mastra/express";
14
+ import { trace } from "@opentelemetry/api";
15
+ import { executionContextUserId, MASTRA_REQUEST_ID_KEY, MASTRA_SCOPES_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_KEY, MASTRA_USER_NAME_KEY, } from "./config.js";
16
+ import { resolveFeedbackEnabled } from "./mlflow.js";
17
+ import { extractModelOverride, MASTRA_MODEL_OVERRIDE_KEY, resolveServingConfig } from "./serving.js";
18
+ /**
19
+ * OpenTelemetry's sentinel for "no valid trace" - 32 zero hex chars.
20
+ * `trace.getActiveSpan()` returns a non-recording span with this id
21
+ * when no SDK is registered, which must never be surfaced as a trace to
22
+ * attach feedback to.
23
+ */
24
+ const INVALID_TRACE_ID = "0".repeat(32);
25
+ /**
26
+ * Stamp the AppKit user (plus the resource id and trace metadata) onto
27
+ * `requestContext`.
28
+ *
29
+ * Split out of {@link MastraServer} because the HTTP middleware is not the only
30
+ * caller that needs it: an out-of-band turn (a Teams activity arriving on
31
+ * another plugin's route, a scheduled job) drives `agent.generate` directly, and
32
+ * without this stamp every user-scoped tool - `ask_genie` above all - fails with
33
+ * "invoke the tool from an agent turn served by the mastra plugin". Those
34
+ * callers build a context with {@link createRequestContext} instead of a
35
+ * request.
36
+ *
37
+ * Idempotent: returns immediately when the user and resource id are already
38
+ * present, so the middleware can call it over a context another layer stamped.
39
+ */
40
+ export async function stampRequestContextUser(requestContext) {
41
+ if ([MASTRA_USER_KEY, MASTRA_RESOURCE_ID_KEY].every((key) => requestContext.get(key)))
42
+ return;
43
+ const executionContext = getExecutionContext();
44
+ const user = {
45
+ id: executionContextUserId(executionContext),
46
+ executionContext,
47
+ };
48
+ requestContext.set(MASTRA_USER_KEY, user);
49
+ requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);
50
+ // AppKit's `UserContext` surfaces display name / email only on
51
+ // OBO requests. Service-context calls (background tasks, server
52
+ // start-up) leave these undefined and we skip the stamp so
53
+ // downstream trace metadata stays absent rather than empty.
54
+ let userName;
55
+ let email;
56
+ if ("isUserContext" in executionContext) {
57
+ userName = executionContext.userName;
58
+ email = executionContext.userEmail;
59
+ }
60
+ else if (process.env.NODE_ENV === "development") {
61
+ const currentUser = await executionContext.client.currentUser.me();
62
+ userName = currentUser?.userName;
63
+ email = currentUser?.emails?.filter((email) => email.primary).find((email) => email.value)
64
+ ?.value;
65
+ }
66
+ if (userName) {
67
+ requestContext.set(MASTRA_USER_NAME_KEY, userName);
68
+ }
69
+ if (email) {
70
+ requestContext.set(MASTRA_USER_EMAIL_KEY, email);
71
+ }
72
+ }
73
+ /**
74
+ * Build the `RequestContext` a NON-HTTP agent turn needs.
75
+ *
76
+ * Everything Mastra's tools read off the context is stamped the same way the
77
+ * request middleware stamps it - the AppKit user (so `ask_genie` and the model
78
+ * resolver can mint user-scoped tokens), the memory thread / resource pair, and
79
+ * a request id so the turn's spans join up in traces. The result is passed as
80
+ * `requestContext` to `agent.generate` / `agent.stream`.
81
+ *
82
+ * This is what makes a card turn answer with the SAME data a chat turn does: the
83
+ * difference between the two endpoints is presentation, not capability.
84
+ */
85
+ export async function createRequestContext(options = {}) {
86
+ const requestContext = new RequestContext();
87
+ await stampRequestContextUser(requestContext);
88
+ if (options.threadId)
89
+ requestContext.set(MASTRA_THREAD_ID_KEY, options.threadId);
90
+ // Stamped AFTER the user so an explicit resource id (a channel member, say)
91
+ // wins over the ambient identity `stampRequestContextUser` defaulted to.
92
+ if (options.resourceId)
93
+ requestContext.set(MASTRA_RESOURCE_ID_KEY, options.resourceId);
94
+ requestContext.set(MASTRA_REQUEST_ID_KEY, options.requestId ?? hash.id());
95
+ return requestContext;
96
+ }
97
+ /**
98
+ * `@mastra/express` subclass that stamps `RequestContext` with the
99
+ * AppKit user, resource id, and a thread id backed by an HTTP-only
100
+ * session cookie (`appkit_<plugin-name>_session_id`).
101
+ */
102
+ export class MastraServer extends MastraServerExpress {
103
+ config;
104
+ log;
105
+ /**
106
+ * Whether to stamp the MLflow trace-id header on responses. Shares the
107
+ * plugin's feedback gate via {@link resolveFeedbackEnabled}.
108
+ */
109
+ feedbackEnabled;
110
+ constructor(config, ...args) {
111
+ super(...args);
112
+ this.config = config;
113
+ this.log = log.logger(config);
114
+ this.feedbackEnabled = resolveFeedbackEnabled(config.feedback);
115
+ }
116
+ registerAuthMiddleware() {
117
+ super.registerAuthMiddleware();
118
+ this.app.use(async (req, res, next) => {
119
+ const requestContext = res.locals.requestContext;
120
+ await this.configureRequestContextUser(requestContext);
121
+ this.configureRequestContextThreadId(req, res, requestContext);
122
+ this.configureRequestContextModelOverride(req, requestContext);
123
+ this.configureRequestContextRequestId(req, res, requestContext);
124
+ this.configureRequestContextScopes(req, requestContext);
125
+ this.configureMlflowTraceId(res);
126
+ this.log.debug("auth:middleware", {
127
+ method: req.method,
128
+ path: req.path,
129
+ requestId: requestContext.get(MASTRA_REQUEST_ID_KEY),
130
+ threadId: requestContext.get(MASTRA_THREAD_ID_KEY),
131
+ resourceId: requestContext.get(MASTRA_RESOURCE_ID_KEY),
132
+ userName: requestContext.get(MASTRA_USER_NAME_KEY),
133
+ userEmail: requestContext.get(MASTRA_USER_EMAIL_KEY),
134
+ modelOverride: requestContext.get(
135
+ // imported below; logged so a misrouted request shows
136
+ // up alongside its model selection in `LOG_LEVEL=debug`.
137
+ "mastra__model_override"),
138
+ });
139
+ next();
140
+ });
141
+ }
142
+ async configureRequestContextUser(requestContext) {
143
+ await stampRequestContextUser(requestContext);
144
+ }
145
+ /**
146
+ * Stamp a per-request id and echo it on the response so an upstream
147
+ * proxy / curl client / browser-side log line can pair its view of
148
+ * the request with the matching trace span. Reuses `X-Request-Id`
149
+ * when the upstream already supplies one so multi-hop traces stay
150
+ * joined; otherwise mints a UUIDv4.
151
+ *
152
+ * The id is surfaced as `mastra__requestId` span metadata via
153
+ * {@link TRACE_REQUEST_CONTEXT_KEYS} and as the `X-Request-Id`
154
+ * response header so dev tools can copy it from either side.
155
+ */
156
+ configureRequestContextRequestId(req, res, requestContext) {
157
+ if (requestContext.get(MASTRA_REQUEST_ID_KEY))
158
+ return;
159
+ const headerValue = req.headers["x-request-id"];
160
+ const upstream = Array.isArray(headerValue) ? headerValue[0] : headerValue;
161
+ const requestId = upstream?.trim() || hash.id();
162
+ requestContext.set(MASTRA_REQUEST_ID_KEY, requestId);
163
+ res.setHeader("X-Request-Id", requestId);
164
+ }
165
+ /**
166
+ * Stamp OAuth scopes from the forwarded access token on
167
+ * {@link MASTRA_SCOPES_KEY} for workspace mount gating.
168
+ */
169
+ configureRequestContextScopes(req, requestContext) {
170
+ const scopes = [
171
+ ...object
172
+ .sequence(token.getAccessTokenScopes(req), token.getAccessTokenScopes(req, "authorization"))
173
+ .distinct(),
174
+ ];
175
+ requestContext.set(MASTRA_SCOPES_KEY, scopes);
176
+ }
177
+ /**
178
+ * Stamp the turn's MLflow trace id on the response so the chat client
179
+ * can attach thumbs / comment feedback to it later. MLflow derives
180
+ * its trace id from the OpenTelemetry trace id (`tr-<hex>`), and every
181
+ * Mastra span for this request inherits the ambient OTel context (see
182
+ * `observability.ts`), so the active span's trace id here is the id
183
+ * MLflow will record for the turn.
184
+ *
185
+ * No-op unless feedback is enabled, and when no live OTel span is
186
+ * active (e.g. the OTLP SDK isn't registered): in that case the header
187
+ * is simply absent and the client hides feedback for that message,
188
+ * degrading gracefully rather than emitting a bogus trace id.
189
+ */
190
+ configureMlflowTraceId(res) {
191
+ if (!this.feedbackEnabled || res.headersSent)
192
+ return;
193
+ const traceId = trace.getActiveSpan()?.spanContext().traceId;
194
+ if (!traceId || traceId === INVALID_TRACE_ID)
195
+ return;
196
+ res.setHeader(feedback.MLFLOW_TRACE_ID_HEADER, `tr-${traceId}`);
197
+ }
198
+ /**
199
+ * Resolve the thread id this request targets and pin it on
200
+ * `RequestContext` (consumed by the agent stream for persistence and
201
+ * by the history / threads routes). Resolution order:
202
+ *
203
+ * 1. A client-supplied thread id (the thread-selection header /
204
+ * `?threadId=` query). This is how the chat UI references a
205
+ * specific conversation among the many a user owns - it picks a
206
+ * thread id from the `/threads` listing (or mints one for a new
207
+ * conversation) and stamps it here. The id is scoped to the
208
+ * caller's resource by the recall / list routes, so a client
209
+ * can only ever read or write its own threads.
210
+ * 2. The per-session cookie (`appkit_<plugin-name>_session_id`),
211
+ * minted on first contact. This is the default single-thread
212
+ * fallback for clients that don't manage threads explicitly, so
213
+ * existing embeds keep one stable conversation per session with
214
+ * no client changes.
215
+ */
216
+ configureRequestContextThreadId(req, res, requestContext) {
217
+ if (requestContext.get(MASTRA_THREAD_ID_KEY))
218
+ return;
219
+ const requested = this.readRequestedThreadId(req);
220
+ if (requested) {
221
+ requestContext.set(MASTRA_THREAD_ID_KEY, requested);
222
+ return;
223
+ }
224
+ const cookies = http.parseCookies(req.headers.cookie);
225
+ const cookieName = string.toIdentifierWithOptions({ delimiter: "_", distinct: true }, "appkit", this.config.name, "sessionId");
226
+ let sessionId = cookies[cookieName];
227
+ if (!sessionId) {
228
+ sessionId = hash.id();
229
+ res.cookie(cookieName, sessionId, {
230
+ httpOnly: true,
231
+ sameSite: "lax",
232
+ secure: req.secure,
233
+ path: "/",
234
+ });
235
+ }
236
+ requestContext.set(MASTRA_THREAD_ID_KEY, sessionId);
237
+ }
238
+ /**
239
+ * Read the client-selected thread id from the request, preferring
240
+ * the thread-selection header over the `?threadId=` query. Returns
241
+ * `null` when neither carries a non-empty value so the caller falls
242
+ * back to the session cookie.
243
+ */
244
+ readRequestedThreadId(req) {
245
+ const headerValue = req.headers[thread.THREAD_ID_HEADER];
246
+ const queryValue = req.query[thread.THREAD_ID_QUERY];
247
+ return (string.trimToNull(Array.isArray(headerValue) ? headerValue[0] : headerValue) ??
248
+ string.trimToNull(Array.isArray(queryValue) ? queryValue[0] : queryValue));
249
+ }
250
+ configureRequestContextModelOverride(req, requestContext) {
251
+ // Per-request model override: only honored when the plugin
252
+ // opts in (default). Sources, in priority order, are
253
+ // `X-Mastra-Model` header, `?model=` query, and `model` /
254
+ // `modelId` body field; see `serving.ts`.
255
+ const serving = resolveServingConfig(this.config);
256
+ if (serving.allowOverride) {
257
+ const override = extractModelOverride({
258
+ headers: req.headers,
259
+ query: req.query,
260
+ body: req.body,
261
+ });
262
+ if (override)
263
+ requestContext.set(MASTRA_MODEL_OVERRIDE_KEY, override);
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Mount-relative agent inference paths (`/agents/:id/<verb>...`). Matched
269
+ * by prefix on the verb so future variants (`streamVNext`, `stream/vnext`,
270
+ * `generateVNext`) stay covered without a code change.
271
+ *
272
+ * Covers the plain inference verbs (`stream` / `generate` / `network`) plus
273
+ * the human-in-the-loop resume verbs a paused `requireApproval` tool needs
274
+ * to continue: `approve-tool-call` / `decline-tool-call` (streaming, and via
275
+ * prefix their `-generate` non-streaming variants), the `-network-` variants,
276
+ * and `resume-stream` (covers `resume-stream-until-idle`). Without these an
277
+ * approval-gated tool (e.g. `send_email`) can be requested but never approved
278
+ * from the browser - the resume `POST` 403s under scoped mode. These are the
279
+ * only *writes* the browser client is allowed to make against stock Mastra.
280
+ */
281
+ const AGENT_INFERENCE = /^\/agents\/[^/]+\/(stream|generate|network|resume-stream|approve-tool-call|decline-tool-call|approve-network-tool-call|decline-network-tool-call)/i;
282
+ /** Mount-relative read-only agent metadata (`/agents`, `/agents/:id`). */
283
+ const AGENT_METADATA = /^\/agents(\/[^/]+)?$/;
284
+ /**
285
+ * Whether a request to the stock `@mastra/express` sub-app should be
286
+ * dispatched, given the configured {@link MastraApiGateOptions.access}.
287
+ *
288
+ * `path` is mount-relative (what the plugin's catch-all sees, e.g.
289
+ * `/agents/x/stream`, `/route/history/x`, `/mcp/...`). In `"scoped"`
290
+ * mode the allowlist is deliberately tight - the chat client only ever
291
+ * needs agent inference, read-only agent metadata, this plugin's own
292
+ * OBO/resource-scoped `/route/*` routes, and (when enabled) MCP - so the
293
+ * whole admin / mutating / bulk-export surface Mastra also exposes is
294
+ * denied by default rather than enumerated.
295
+ */
296
+ export function isMastraRequestAllowed(method, path, opts) {
297
+ if (opts.access === "full")
298
+ return true;
299
+ const p = path.startsWith("/") ? path : `/${path}`;
300
+ // This plugin's own custom routes are individually OBO- and
301
+ // resource-scoped (see history.ts / threads.ts), so every method is safe.
302
+ if (p === "/route" || p.startsWith("/route/"))
303
+ return true;
304
+ if (opts.mcpEnabled && (p === "/mcp" || p.startsWith("/mcp/")))
305
+ return true;
306
+ const m = method.toUpperCase();
307
+ if (m === "POST" && AGENT_INFERENCE.test(p))
308
+ return true;
309
+ if (m === "GET" && AGENT_METADATA.test(p))
310
+ return true;
311
+ return false;
312
+ }
313
+ /**
314
+ * Patches around `@mastra/express`'s custom-route dispatcher so the
315
+ * plugin's custom API routes (e.g. `historyRoute`) work when
316
+ * `MastraServer` is hosted on an Express subapp mounted under a parent
317
+ * path (e.g. `/api/mastra`).
318
+ *
319
+ * The adapter's `registerCustomApiRoutes` matches against `req.path`
320
+ * (mount-relative, correct) but dispatches to its internal Hono
321
+ * mini-app using `req.originalUrl`, which still contains the parent
322
+ * mount prefix. The Hono app registers the literal route paths
323
+ * (for example `/route/history`), so the absolute URL never matches
324
+ * until we overwrite `originalUrl` for `/route` and `/route/*` to the
325
+ * mount-relative path.
326
+ */
327
+ export function attachRoutePatchMiddleware(app) {
328
+ app.use((req, _res, next) => {
329
+ const isCustomRoute = req.path === "/route" || req.path.startsWith("/route/");
330
+ if (!isCustomRoute)
331
+ return next();
332
+ req.originalUrl = req.path;
333
+ next();
334
+ });
335
+ }
336
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RCxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxJQUFJLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzNDLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLG9CQUFvQixHQUdyQixNQUFNLFVBQVUsQ0FBQztBQUNsQixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFbEQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLHlCQUF5QixFQUFFLG9CQUFvQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ2xHOzs7OztHQUtHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRXhDOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSx1QkFBdUIsQ0FBQyxjQUE4QjtJQUMxRSxJQUFJLENBQUMsZUFBZSxFQUFFLHNCQUFzQixDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFF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Qy9CLElBQUksQ0FBQyxLQUFLLE1BQU0sSUFBSSxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3pELElBQUksQ0FBQyxLQUFLLEtBQUssSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLFVBQVUsMEJBQTBCLENBQUMsR0FBb0I7SUFDN0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUU7UUFDMUIsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDOUUsSUFBSSxDQUFDLGFBQWE7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ2xDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhwcmVzcy1sYXllciBwbHVtYmluZyBmb3IgdGhlIE1hc3RyYSBwbHVnaW46IGEgYE1hc3RyYVNlcnZlcmAgdGhhdFxuICogc3RhbXBzIHRoZSBwZXItcmVxdWVzdCBgUmVxdWVzdENvbnRleHRgLCBhbmQgYSByb3V0ZS1wYXRjaCBtaWRkbGV3YXJlXG4gKiB0aGF0IGxldHMgdGhlIHBsdWdpbidzIGN1c3RvbSBBUEkgcm91dGVzIChlLmcuIGBoaXN0b3J5Um91dGVgKSB3b3JrXG4gKiBiZWhpbmQgYW4gRXhwcmVzcyBtb3VudCBwb2ludC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgZ2V0RXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGhhc2gsIGh0dHAsIGxvZywgb2JqZWN0LCBzdHJpbmcsIHRva2VuIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGZlZWRiYWNrLCB0aHJlYWQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbWFzdHJhXCI7XG5pbXBvcnQge1xuICBNQVNUUkFfUkVTT1VSQ0VfSURfS0VZLFxuICBNQVNUUkFfVEhSRUFEX0lEX0tFWSxcbiAgUmVxdWVzdENvbnRleHQsXG59IGZyb20gXCJAbWFzdHJhL2NvcmUvcmVxdWVzdC1jb250ZXh0XCI7XG5pbXBvcnQgeyBNYXN0cmFTZXJ2ZXIgYXMgTWFzdHJhU2VydmVyRXhwcmVzcyB9IGZyb20gXCJAbWFzdHJhL2V4cHJlc3NcIjtcbmltcG9ydCB7IHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHR5cGUgZXhwcmVzcyBmcm9tIFwiZXhwcmVzc1wiO1xuXG5pbXBvcnQge1xuICBleGVjdXRpb25Db250ZXh0VXNlcklkLFxuICBNQVNUUkFfUkVRVUVTVF9JRF9LRVksXG4gIE1BU1RSQV9TQ09QRVNfS0VZLFxuICBNQVNUUkFfVVNFUl9FTUFJTF9LRVksXG4gIE1BU1RSQV9VU0VSX0tFWSxcbiAgTUFTVFJBX1VTRVJfTkFNRV9LRVksXG4gIHR5cGUgTWFzdHJhUGx1Z2luQ29uZmlnLFxuICB0eXBlIFVzZXIsXG59IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgcmVzb2x2ZUZlZWRiYWNrRW5hYmxlZCB9IGZyb20gXCIuL21sZmxvd1wiO1xuXG5pbXBvcnQgeyBleHRyYWN0TW9kZWxPdmVycmlkZSwgTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSwgcmVzb2x2ZVNlcnZpbmdDb25maWcgfSBmcm9tIFwiLi9zZXJ2aW5nXCI7XG4vKipcbiAqIE9wZW5UZWxlbWV0cnkncyBzZW50aW5lbCBmb3IgXCJubyB2YWxpZCB0cmFjZVwiIC0gMzIgemVybyBoZXggY2hhcnMuXG4gKiBgdHJhY2UuZ2V0QWN0aXZlU3BhbigpYCByZXR1cm5zIGEgbm9uLXJlY29yZGluZyBzcGFuIHdpdGggdGhpcyBpZFxuICogd2hlbiBubyBTREsgaXMgcmVnaXN0ZXJlZCwgd2hpY2ggbXVzdCBuZXZlciBiZSBzdXJmYWNlZCBhcyBhIHRyYWNlIHRvXG4gKiBhdHRhY2ggZmVlZGJhY2sgdG8uXG4gKi9cbmNvbnN0IElOVkFMSURfVFJBQ0VfSUQgPSBcIjBcIi5yZXBlYXQoMzIpO1xuXG4vKipcbiAqIFN0YW1wIHRoZSBBcHBLaXQgdXNlciAocGx1cyB0aGUgcmVzb3VyY2UgaWQgYW5kIHRyYWNlIG1ldGFkYXRhKSBvbnRvXG4gKiBgcmVxdWVzdENvbnRleHRgLlxuICpcbiAqIFNwbGl0IG91dCBvZiB7QGxpbmsgTWFzdHJhU2VydmVyfSBiZWNhdXNlIHRoZSBIVFRQIG1pZGRsZXdhcmUgaXMgbm90IHRoZSBvbmx5XG4gKiBjYWxsZXIgdGhhdCBuZWVkcyBpdDogYW4gb3V0LW9mLWJhbmQgdHVybiAoYSBUZWFtcyBhY3Rpdml0eSBhcnJpdmluZyBvblxuICogYW5vdGhlciBwbHVnaW4ncyByb3V0ZSwgYSBzY2hlZHVsZWQgam9iKSBkcml2ZXMgYGFnZW50LmdlbmVyYXRlYCBkaXJlY3RseSwgYW5kXG4gKiB3aXRob3V0IHRoaXMgc3RhbXAgZXZlcnkgdXNlci1zY29wZWQgdG9vbCAtIGBhc2tfZ2VuaWVgIGFib3ZlIGFsbCAtIGZhaWxzIHdpdGhcbiAqIFwiaW52b2tlIHRoZSB0b29sIGZyb20gYW4gYWdlbnQgdHVybiBzZXJ2ZWQgYnkgdGhlIG1hc3RyYSBwbHVnaW5cIi4gVGhvc2VcbiAqIGNhbGxlcnMgYnVpbGQgYSBjb250ZXh0IHdpdGgge0BsaW5rIGNyZWF0ZVJlcXVlc3RDb250ZXh0fSBpbnN0ZWFkIG9mIGFcbiAqIHJlcXVlc3QuXG4gKlxuICogSWRlbXBvdGVudDogcmV0dXJucyBpbW1lZGlhdGVseSB3aGVuIHRoZSB1c2VyIGFuZCByZXNvdXJjZSBpZCBhcmUgYWxyZWFkeVxuICogcHJlc2VudCwgc28gdGhlIG1pZGRsZXdhcmUgY2FuIGNhbGwgaXQgb3ZlciBhIGNvbnRleHQgYW5vdGhlciBsYXllciBzdGFtcGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXIocmVxdWVzdENvbnRleHQ6IFJlcXVlc3RDb250ZXh0KTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChbTUFTVFJBX1VTRVJfS0VZLCBNQVNUUkFfUkVTT1VSQ0VfSURfS0VZXS5ldmVyeSgoa2V5KSA9PiByZXF1ZXN0Q29udGV4dC5nZXQoa2V5KSkpIHJldHVybjtcbiAgY29uc3QgZXhlY3V0aW9uQ29udGV4dCA9IGdldEV4ZWN1dGlvbkNvbnRleHQoKTtcbiAgY29uc3QgdXNlcjogVXNlciA9IHtcbiAgICBpZDogZXhlY3V0aW9uQ29udGV4dFVzZXJJZChleGVjdXRpb25Db250ZXh0KSxcbiAgICBleGVjdXRpb25Db250ZXh0LFxuICB9O1xuICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1VTRVJfS0VZLCB1c2VyKTtcbiAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVksIHVzZXIuaWQpO1xuICAvLyBBcHBLaXQncyBgVXNlckNvbnRleHRgIHN1cmZhY2VzIGRpc3BsYXkgbmFtZSAvIGVtYWlsIG9ubHkgb25cbiAgLy8gT0JPIHJlcXVlc3RzLiBTZXJ2aWNlLWNvbnRleHQgY2FsbHMgKGJhY2tncm91bmQgdGFza3MsIHNlcnZlclxuICAvLyBzdGFydC11cCkgbGVhdmUgdGhlc2UgdW5kZWZpbmVkIGFuZCB3ZSBza2lwIHRoZSBzdGFtcCBzb1xuICAvLyBkb3duc3RyZWFtIHRyYWNlIG1ldGFkYXRhIHN0YXlzIGFic2VudCByYXRoZXIgdGhhbiBlbXB0eS5cbiAgbGV0IHVzZXJOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBlbWFpbDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBpZiAoXCJpc1VzZXJDb250ZXh0XCIgaW4gZXhlY3V0aW9uQ29udGV4dCkge1xuICAgIHVzZXJOYW1lID0gZXhlY3V0aW9uQ29udGV4dC51c2VyTmFtZTtcbiAgICBlbWFpbCA9IGV4ZWN1dGlvbkNvbnRleHQudXNlckVtYWlsO1xuICB9IGVsc2UgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcImRldmVsb3BtZW50XCIpIHtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IGF3YWl0IGV4ZWN1dGlvbkNvbnRleHQuY2xpZW50LmN1cnJlbnRVc2VyLm1lKCk7XG4gICAgdXNlck5hbWUgPSBjdXJyZW50VXNlcj8udXNlck5hbWU7XG4gICAgZW1haWwgPSBjdXJyZW50VXNlcj8uZW1haWxzPy5maWx0ZXIoKGVtYWlsKSA9PiBlbWFpbC5wcmltYXJ5KS5maW5kKChlbWFpbCkgPT4gZW1haWwudmFsdWUpXG4gICAgICA/LnZhbHVlIGFzIHN0cmluZztcbiAgfVxuICBpZiAodXNlck5hbWUpIHtcbiAgICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1VTRVJfTkFNRV9LRVksIHVzZXJOYW1lKTtcbiAgfVxuICBpZiAoZW1haWwpIHtcbiAgICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1VTRVJfRU1BSUxfS0VZLCBlbWFpbCk7XG4gIH1cbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgYFJlcXVlc3RDb250ZXh0YCBhIE5PTi1IVFRQIGFnZW50IHR1cm4gbmVlZHMuXG4gKlxuICogRXZlcnl0aGluZyBNYXN0cmEncyB0b29scyByZWFkIG9mZiB0aGUgY29udGV4dCBpcyBzdGFtcGVkIHRoZSBzYW1lIHdheSB0aGVcbiAqIHJlcXVlc3QgbWlkZGxld2FyZSBzdGFtcHMgaXQgLSB0aGUgQXBwS2l0IHVzZXIgKHNvIGBhc2tfZ2VuaWVgIGFuZCB0aGUgbW9kZWxcbiAqIHJlc29sdmVyIGNhbiBtaW50IHVzZXItc2NvcGVkIHRva2VucyksIHRoZSBtZW1vcnkgdGhyZWFkIC8gcmVzb3VyY2UgcGFpciwgYW5kXG4gKiBhIHJlcXVlc3QgaWQgc28gdGhlIHR1cm4ncyBzcGFucyBqb2luIHVwIGluIHRyYWNlcy4gVGhlIHJlc3VsdCBpcyBwYXNzZWQgYXNcbiAqIGByZXF1ZXN0Q29udGV4dGAgdG8gYGFnZW50LmdlbmVyYXRlYCAvIGBhZ2VudC5zdHJlYW1gLlxuICpcbiAqIFRoaXMgaXMgd2hhdCBtYWtlcyBhIGNhcmQgdHVybiBhbnN3ZXIgd2l0aCB0aGUgU0FNRSBkYXRhIGEgY2hhdCB0dXJuIGRvZXM6IHRoZVxuICogZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZW5kcG9pbnRzIGlzIHByZXNlbnRhdGlvbiwgbm90IGNhcGFiaWxpdHkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVSZXF1ZXN0Q29udGV4dChcbiAgb3B0aW9uczogeyB0aHJlYWRJZD86IHN0cmluZzsgcmVzb3VyY2VJZD86IHN0cmluZzsgcmVxdWVzdElkPzogc3RyaW5nIH0gPSB7fSxcbik6IFByb21pc2U8UmVxdWVzdENvbnRleHQ+IHtcbiAgY29uc3QgcmVxdWVzdENvbnRleHQgPSBuZXcgUmVxdWVzdENvbnRleHQoKTtcbiAgYXdhaXQgc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXIocmVxdWVzdENvbnRleHQpO1xuICBpZiAob3B0aW9ucy50aHJlYWRJZCkgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9USFJFQURfSURfS0VZLCBvcHRpb25zLnRocmVhZElkKTtcbiAgLy8gU3RhbXBlZCBBRlRFUiB0aGUgdXNlciBzbyBhbiBleHBsaWNpdCByZXNvdXJjZSBpZCAoYSBjaGFubmVsIG1lbWJlciwgc2F5KVxuICAvLyB3aW5zIG92ZXIgdGhlIGFtYmllbnQgaWRlbnRpdHkgYHN0YW1wUmVxdWVzdENvbnRleHRVc2VyYCBkZWZhdWx0ZWQgdG8uXG4gIGlmIChvcHRpb25zLnJlc291cmNlSWQpIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfUkVTT1VSQ0VfSURfS0VZLCBvcHRpb25zLnJlc291cmNlSWQpO1xuICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1JFUVVFU1RfSURfS0VZLCBvcHRpb25zLnJlcXVlc3RJZCA/PyBoYXNoLmlkKCkpO1xuICByZXR1cm4gcmVxdWVzdENvbnRleHQ7XG59XG5cbi8qKlxuICogYEBtYXN0cmEvZXhwcmVzc2Agc3ViY2xhc3MgdGhhdCBzdGFtcHMgYFJlcXVlc3RDb250ZXh0YCB3aXRoIHRoZVxuICogQXBwS2l0IHVzZXIsIHJlc291cmNlIGlkLCBhbmQgYSB0aHJlYWQgaWQgYmFja2VkIGJ5IGFuIEhUVFAtb25seVxuICogc2Vzc2lvbiBjb29raWUgKGBhcHBraXRfPHBsdWdpbi1uYW1lPl9zZXNzaW9uX2lkYCkuXG4gKi9cbmV4cG9ydCBjbGFzcyBNYXN0cmFTZXJ2ZXIgZXh0ZW5kcyBNYXN0cmFTZXJ2ZXJFeHByZXNzIHtcbiAgcHJpdmF0ZSBsb2c6IGxvZy5Mb2dnZXI7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHN0YW1wIHRoZSBNTGZsb3cgdHJhY2UtaWQgaGVhZGVyIG9uIHJlc3BvbnNlcy4gU2hhcmVzIHRoZVxuICAgKiBwbHVnaW4ncyBmZWVkYmFjayBnYXRlIHZpYSB7QGxpbmsgcmVzb2x2ZUZlZWRiYWNrRW5hYmxlZH0uXG4gICAqL1xuICBwcml2YXRlIGZlZWRiYWNrRW5hYmxlZDogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGNvbmZpZzogTWFzdHJhUGx1Z2luQ29uZmlnLFxuICAgIC4uLmFyZ3M6IENvbnN0cnVjdG9yUGFyYW1ldGVyczx0eXBlb2YgTWFzdHJhU2VydmVyRXhwcmVzcz5cbiAgKSB7XG4gICAgc3VwZXIoLi4uYXJncyk7XG4gICAgdGhpcy5sb2cgPSBsb2cubG9nZ2VyKGNvbmZpZyk7XG4gICAgdGhpcy5mZWVkYmFja0VuYWJsZWQgPSByZXNvbHZlRmVlZGJhY2tFbmFibGVkKGNvbmZpZy5mZWVkYmFjayk7XG4gIH1cblxuICBvdmVycmlkZSByZWdpc3RlckF1dGhNaWRkbGV3YXJlKCk6IHZvaWQge1xuICAgIHN1cGVyLnJlZ2lzdGVyQXV0aE1pZGRsZXdhcmUoKTtcbiAgICB0aGlzLmFwcC51c2UoYXN5bmMgKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICBjb25zdCByZXF1ZXN0Q29udGV4dCA9IHJlcy5sb2NhbHMucmVxdWVzdENvbnRleHQhIGFzIFJlcXVlc3RDb250ZXh0O1xuICAgICAgYXdhaXQgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFVzZXIocmVxdWVzdENvbnRleHQpO1xuICAgICAgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFRocmVhZElkKHJlcSwgcmVzLCByZXF1ZXN0Q29udGV4dCk7XG4gICAgICB0aGlzLmNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0TW9kZWxPdmVycmlkZShyZXEsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRSZXF1ZXN0SWQocmVxLCByZXMsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRTY29wZXMocmVxLCByZXF1ZXN0Q29udGV4dCk7XG5cbiAgICAgIHRoaXMuY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXMpO1xuICAgICAgdGhpcy5sb2cuZGVidWcoXCJhdXRoOm1pZGRsZXdhcmVcIiwge1xuICAgICAgICBtZXRob2Q6IHJlcS5tZXRob2QsXG4gICAgICAgIHBhdGg6IHJlcS5wYXRoLFxuICAgICAgICByZXF1ZXN0SWQ6IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfUkVRVUVTVF9JRF9LRVkpLFxuICAgICAgICB0aHJlYWRJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9USFJFQURfSURfS0VZKSxcbiAgICAgICAgcmVzb3VyY2VJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVkpLFxuICAgICAgICB1c2VyTmFtZTogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9VU0VSX05BTUVfS0VZKSxcbiAgICAgICAgdXNlckVtYWlsOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1VTRVJfRU1BSUxfS0VZKSxcbiAgICAgICAgbW9kZWxPdmVycmlkZTogcmVxdWVzdENvbnRleHQuZ2V0KFxuICAgICAgICAgIC8vIGltcG9ydGVkIGJlbG93OyBsb2dnZWQgc28gYSBtaXNyb3V0ZWQgcmVxdWVzdCBzaG93c1xuICAgICAgICAgIC8vIHVwIGFsb25nc2lkZSBpdHMgbW9kZWwgc2VsZWN0aW9uIGluIGBMT0dfTEVWRUw9ZGVidWdgLlxuICAgICAgICAgIFwibWFzdHJhX19tb2RlbF9vdmVycmlkZVwiLFxuICAgICAgICApLFxuICAgICAgfSk7XG4gICAgICBuZXh0KCk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBjb25maWd1cmVSZXF1ZXN0Q29udGV4dFVzZXIocmVxdWVzdENvbnRleHQ6IFJlcXVlc3RDb250ZXh0KSB7XG4gICAgYXdhaXQgc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXIocmVxdWVzdENvbnRleHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YW1wIGEgcGVyLXJlcXVlc3QgaWQgYW5kIGVjaG8gaXQgb24gdGhlIHJlc3BvbnNlIHNvIGFuIHVwc3RyZWFtXG4gICAqIHByb3h5IC8gY3VybCBjbGllbnQgLyBicm93c2VyLXNpZGUgbG9nIGxpbmUgY2FuIHBhaXIgaXRzIHZpZXcgb2ZcbiAgICogdGhlIHJlcXVlc3Qgd2l0aCB0aGUgbWF0Y2hpbmcgdHJhY2Ugc3Bhbi4gUmV1c2VzIGBYLVJlcXVlc3QtSWRgXG4gICAqIHdoZW4gdGhlIHVwc3RyZWFtIGFscmVhZHkgc3VwcGxpZXMgb25lIHNvIG11bHRpLWhvcCB0cmFjZXMgc3RheVxuICAgKiBqb2luZWQ7IG90aGVyd2lzZSBtaW50cyBhIFVVSUR2NC5cbiAgICpcbiAgICogVGhlIGlkIGlzIHN1cmZhY2VkIGFzIGBtYXN0cmFfX3JlcXVlc3RJZGAgc3BhbiBtZXRhZGF0YSB2aWFcbiAgICoge0BsaW5rIFRSQUNFX1JFUVVFU1RfQ09OVEVYVF9LRVlTfSBhbmQgYXMgdGhlIGBYLVJlcXVlc3QtSWRgXG4gICAqIHJlc3BvbnNlIGhlYWRlciBzbyBkZXYgdG9vbHMgY2FuIGNvcHkgaXQgZnJvbSBlaXRoZXIgc2lkZS5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0UmVxdWVzdElkKFxuICAgIHJlcTogZXhwcmVzcy5SZXF1ZXN0LFxuICAgIHJlczogZXhwcmVzcy5SZXNwb25zZSxcbiAgICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQsXG4gICkge1xuICAgIGlmIChyZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1JFUVVFU1RfSURfS0VZKSkgcmV0dXJuO1xuICAgIGNvbnN0IGhlYWRlclZhbHVlID0gcmVxLmhlYWRlcnNbXCJ4LXJlcXVlc3QtaWRcIl07XG4gICAgY29uc3QgdXBzdHJlYW0gPSBBcnJheS5pc0FycmF5KGhlYWRlclZhbHVlKSA/IGhlYWRlclZhbHVlWzBdIDogaGVhZGVyVmFsdWU7XG4gICAgY29uc3QgcmVxdWVzdElkID0gdXBzdHJlYW0/LnRyaW0oKSB8fCBoYXNoLmlkKCk7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSwgcmVxdWVzdElkKTtcbiAgICByZXMuc2V0SGVhZGVyKFwiWC1SZXF1ZXN0LUlkXCIsIHJlcXVlc3RJZCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhbXAgT0F1dGggc2NvcGVzIGZyb20gdGhlIGZvcndhcmRlZCBhY2Nlc3MgdG9rZW4gb25cbiAgICoge0BsaW5rIE1BU1RSQV9TQ09QRVNfS0VZfSBmb3Igd29ya3NwYWNlIG1vdW50IGdhdGluZy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0U2NvcGVzKHJlcTogZXhwcmVzcy5SZXF1ZXN0LCByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQpIHtcbiAgICBjb25zdCBzY29wZXMgPSBbXG4gICAgICAuLi5vYmplY3RcbiAgICAgICAgLnNlcXVlbmNlKHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSksIHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSwgXCJhdXRob3JpemF0aW9uXCIpKVxuICAgICAgICAuZGlzdGluY3QoKSxcbiAgICBdO1xuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfU0NPUEVTX0tFWSwgc2NvcGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFtcCB0aGUgdHVybidzIE1MZmxvdyB0cmFjZSBpZCBvbiB0aGUgcmVzcG9uc2Ugc28gdGhlIGNoYXQgY2xpZW50XG4gICAqIGNhbiBhdHRhY2ggdGh1bWJzIC8gY29tbWVudCBmZWVkYmFjayB0byBpdCBsYXRlci4gTUxmbG93IGRlcml2ZXNcbiAgICogaXRzIHRyYWNlIGlkIGZyb20gdGhlIE9wZW5UZWxlbWV0cnkgdHJhY2UgaWQgKGB0ci08aGV4PmApLCBhbmQgZXZlcnlcbiAgICogTWFzdHJhIHNwYW4gZm9yIHRoaXMgcmVxdWVzdCBpbmhlcml0cyB0aGUgYW1iaWVudCBPVGVsIGNvbnRleHQgKHNlZVxuICAgKiBgb2JzZXJ2YWJpbGl0eS50c2ApLCBzbyB0aGUgYWN0aXZlIHNwYW4ncyB0cmFjZSBpZCBoZXJlIGlzIHRoZSBpZFxuICAgKiBNTGZsb3cgd2lsbCByZWNvcmQgZm9yIHRoZSB0dXJuLlxuICAgKlxuICAgKiBOby1vcCB1bmxlc3MgZmVlZGJhY2sgaXMgZW5hYmxlZCwgYW5kIHdoZW4gbm8gbGl2ZSBPVGVsIHNwYW4gaXNcbiAgICogYWN0aXZlIChlLmcuIHRoZSBPVExQIFNESyBpc24ndCByZWdpc3RlcmVkKTogaW4gdGhhdCBjYXNlIHRoZSBoZWFkZXJcbiAgICogaXMgc2ltcGx5IGFic2VudCBhbmQgdGhlIGNsaWVudCBoaWRlcyBmZWVkYmFjayBmb3IgdGhhdCBtZXNzYWdlLFxuICAgKiBkZWdyYWRpbmcgZ3JhY2VmdWxseSByYXRoZXIgdGhhbiBlbWl0dGluZyBhIGJvZ3VzIHRyYWNlIGlkLlxuICAgKi9cbiAgY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXM6IGV4cHJlc3MuUmVzcG9uc2UpIHtcbiAgICBpZiAoIXRoaXMuZmVlZGJhY2tFbmFibGVkIHx8IHJlcy5oZWFkZXJzU2VudCkgcmV0dXJuO1xuICAgIGNvbnN0IHRyYWNlSWQgPSB0cmFjZS5nZXRBY3RpdmVTcGFuKCk/LnNwYW5Db250ZXh0KCkudHJhY2VJZDtcbiAgICBpZiAoIXRyYWNlSWQgfHwgdHJhY2VJZCA9PT0gSU5WQUxJRF9UUkFDRV9JRCkgcmV0dXJuO1xuICAgIHJlcy5zZXRIZWFkZXIoZmVlZGJhY2suTUxGTE9XX1RSQUNFX0lEX0hFQURFUiwgYHRyLSR7dHJhY2VJZH1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSB0aHJlYWQgaWQgdGhpcyByZXF1ZXN0IHRhcmdldHMgYW5kIHBpbiBpdCBvblxuICAgKiBgUmVxdWVzdENvbnRleHRgIChjb25zdW1lZCBieSB0aGUgYWdlbnQgc3RyZWFtIGZvciBwZXJzaXN0ZW5jZSBhbmRcbiAgICogYnkgdGhlIGhpc3RvcnkgLyB0aHJlYWRzIHJvdXRlcykuIFJlc29sdXRpb24gb3JkZXI6XG4gICAqXG4gICAqICAgMS4gQSBjbGllbnQtc3VwcGxpZWQgdGhyZWFkIGlkICh0aGUgdGhyZWFkLXNlbGVjdGlvbiBoZWFkZXIgL1xuICAgKiAgICAgIGA/dGhyZWFkSWQ9YCBxdWVyeSkuIFRoaXMgaXMgaG93IHRoZSBjaGF0IFVJIHJlZmVyZW5jZXMgYVxuICAgKiAgICAgIHNwZWNpZmljIGNvbnZlcnNhdGlvbiBhbW9uZyB0aGUgbWFueSBhIHVzZXIgb3ducyAtIGl0IHBpY2tzIGFcbiAgICogICAgICB0aHJlYWQgaWQgZnJvbSB0aGUgYC90aHJlYWRzYCBsaXN0aW5nIChvciBtaW50cyBvbmUgZm9yIGEgbmV3XG4gICAqICAgICAgY29udmVyc2F0aW9uKSBhbmQgc3RhbXBzIGl0IGhlcmUuIFRoZSBpZCBpcyBzY29wZWQgdG8gdGhlXG4gICAqICAgICAgY2FsbGVyJ3MgcmVzb3VyY2UgYnkgdGhlIHJlY2FsbCAvIGxpc3Qgcm91dGVzLCBzbyBhIGNsaWVudFxuICAgKiAgICAgIGNhbiBvbmx5IGV2ZXIgcmVhZCBvciB3cml0ZSBpdHMgb3duIHRocmVhZHMuXG4gICAqICAgMi4gVGhlIHBlci1zZXNzaW9uIGNvb2tpZSAoYGFwcGtpdF88cGx1Z2luLW5hbWU+X3Nlc3Npb25faWRgKSxcbiAgICogICAgICBtaW50ZWQgb24gZmlyc3QgY29udGFjdC4gVGhpcyBpcyB0aGUgZGVmYXVsdCBzaW5nbGUtdGhyZWFkXG4gICAqICAgICAgZmFsbGJhY2sgZm9yIGNsaWVudHMgdGhhdCBkb24ndCBtYW5hZ2UgdGhyZWFkcyBleHBsaWNpdGx5LCBzb1xuICAgKiAgICAgIGV4aXN0aW5nIGVtYmVkcyBrZWVwIG9uZSBzdGFibGUgY29udmVyc2F0aW9uIHBlciBzZXNzaW9uIHdpdGhcbiAgICogICAgICBubyBjbGllbnQgY2hhbmdlcy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VGhyZWFkSWQoXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICAgIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgKSB7XG4gICAgaWYgKHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVEhSRUFEX0lEX0tFWSkpIHJldHVybjtcbiAgICBjb25zdCByZXF1ZXN0ZWQgPSB0aGlzLnJlYWRSZXF1ZXN0ZWRUaHJlYWRJZChyZXEpO1xuICAgIGlmIChyZXF1ZXN0ZWQpIHtcbiAgICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgcmVxdWVzdGVkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY29va2llcyA9IGh0dHAucGFyc2VDb29raWVzKHJlcS5oZWFkZXJzLmNvb2tpZSk7XG4gICAgY29uc3QgY29va2llTmFtZSA9IHN0cmluZy50b0lkZW50aWZpZXJXaXRoT3B0aW9ucyhcbiAgICAgIHsgZGVsaW1pdGVyOiBcIl9cIiwgZGlzdGluY3Q6IHRydWUgfSxcbiAgICAgIFwiYXBwa2l0XCIsXG4gICAgICB0aGlzLmNvbmZpZy5uYW1lISxcbiAgICAgIFwic2Vzc2lvbklkXCIsXG4gICAgKTtcbiAgICBsZXQgc2Vzc2lvbklkID0gY29va2llc1tjb29raWVOYW1lXTtcbiAgICBpZiAoIXNlc3Npb25JZCkge1xuICAgICAgc2Vzc2lvbklkID0gaGFzaC5pZCgpO1xuICAgICAgcmVzLmNvb2tpZShjb29raWVOYW1lLCBzZXNzaW9uSWQsIHtcbiAgICAgICAgaHR0cE9ubHk6IHRydWUsXG4gICAgICAgIHNhbWVTaXRlOiBcImxheFwiLFxuICAgICAgICBzZWN1cmU6IHJlcS5zZWN1cmUsXG4gICAgICAgIHBhdGg6IFwiL1wiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgc2Vzc2lvbklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIHRoZSBjbGllbnQtc2VsZWN0ZWQgdGhyZWFkIGlkIGZyb20gdGhlIHJlcXVlc3QsIHByZWZlcnJpbmdcbiAgICogdGhlIHRocmVhZC1zZWxlY3Rpb24gaGVhZGVyIG92ZXIgdGhlIGA/dGhyZWFkSWQ9YCBxdWVyeS4gUmV0dXJuc1xuICAgKiBgbnVsbGAgd2hlbiBuZWl0aGVyIGNhcnJpZXMgYSBub24tZW1wdHkgdmFsdWUgc28gdGhlIGNhbGxlciBmYWxsc1xuICAgKiBiYWNrIHRvIHRoZSBzZXNzaW9uIGNvb2tpZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZFJlcXVlc3RlZFRocmVhZElkKHJlcTogZXhwcmVzcy5SZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgaGVhZGVyVmFsdWUgPSByZXEuaGVhZGVyc1t0aHJlYWQuVEhSRUFEX0lEX0hFQURFUl07XG4gICAgY29uc3QgcXVlcnlWYWx1ZSA9IHJlcS5xdWVyeVt0aHJlYWQuVEhSRUFEX0lEX1FVRVJZXTtcbiAgICByZXR1cm4gKFxuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShoZWFkZXJWYWx1ZSkgPyBoZWFkZXJWYWx1ZVswXSA6IGhlYWRlclZhbHVlKSA/P1xuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShxdWVyeVZhbHVlKSA/IHF1ZXJ5VmFsdWVbMF0gOiBxdWVyeVZhbHVlKVxuICAgICk7XG4gIH1cblxuICBjb25maWd1cmVSZXF1ZXN0Q29udGV4dE1vZGVsT3ZlcnJpZGUocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIC8vIFBlci1yZXF1ZXN0IG1vZGVsIG92ZXJyaWRlOiBvbmx5IGhvbm9yZWQgd2hlbiB0aGUgcGx1Z2luXG4gICAgLy8gb3B0cyBpbiAoZGVmYXVsdCkuIFNvdXJjZXMsIGluIHByaW9yaXR5IG9yZGVyLCBhcmVcbiAgICAvLyBgWC1NYXN0cmEtTW9kZWxgIGhlYWRlciwgYD9tb2RlbD1gIHF1ZXJ5LCBhbmQgYG1vZGVsYCAvXG4gICAgLy8gYG1vZGVsSWRgIGJvZHkgZmllbGQ7IHNlZSBgc2VydmluZy50c2AuXG4gICAgY29uc3Qgc2VydmluZyA9IHJlc29sdmVTZXJ2aW5nQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgICBpZiAoc2VydmluZy5hbGxvd092ZXJyaWRlKSB7XG4gICAgICBjb25zdCBvdmVycmlkZSA9IGV4dHJhY3RNb2RlbE92ZXJyaWRlKHtcbiAgICAgICAgaGVhZGVyczogcmVxLmhlYWRlcnMgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+LFxuICAgICAgICBxdWVyeTogcmVxLnF1ZXJ5IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgICAgICBib2R5OiByZXEuYm9keSxcbiAgICAgIH0pO1xuICAgICAgaWYgKG92ZXJyaWRlKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSwgb3ZlcnJpZGUpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogSW5wdXRzIGZvciB7QGxpbmsgaXNNYXN0cmFSZXF1ZXN0QWxsb3dlZH0uICovXG5leHBvcnQgaW50ZXJmYWNlIE1hc3RyYUFwaUdhdGVPcHRpb25zIHtcbiAgLyoqIGBjb25maWcuYXBpQWNjZXNzYDsgYFwiZnVsbFwiYCBzaG9ydC1jaXJjdWl0cyB0byBhbGxvdyBldmVyeXRoaW5nLiAqL1xuICBhY2Nlc3M6IFwic2NvcGVkXCIgfCBcImZ1bGxcIjtcbiAgLyoqIFdoZXRoZXIgdGhlIE1DUCB0cmFuc3BvcnQgaXMgbW91bnRlZCAoc28gYC9tY3AvKmAgaXMgbGVnaXRpbWF0ZSkuICovXG4gIG1jcEVuYWJsZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogTW91bnQtcmVsYXRpdmUgYWdlbnQgaW5mZXJlbmNlIHBhdGhzIChgL2FnZW50cy86aWQvPHZlcmI+Li4uYCkuIE1hdGNoZWRcbiAqIGJ5IHByZWZpeCBvbiB0aGUgdmVyYiBzbyBmdXR1cmUgdmFyaWFudHMgKGBzdHJlYW1WTmV4dGAsIGBzdHJlYW0vdm5leHRgLFxuICogYGdlbmVyYXRlVk5leHRgKSBzdGF5IGNvdmVyZWQgd2l0aG91dCBhIGNvZGUgY2hhbmdlLlxuICpcbiAqIENvdmVycyB0aGUgcGxhaW4gaW5mZXJlbmNlIHZlcmJzIChgc3RyZWFtYCAvIGBnZW5lcmF0ZWAgLyBgbmV0d29ya2ApIHBsdXNcbiAqIHRoZSBodW1hbi1pbi10aGUtbG9vcCByZXN1bWUgdmVyYnMgYSBwYXVzZWQgYHJlcXVpcmVBcHByb3ZhbGAgdG9vbCBuZWVkc1xuICogdG8gY29udGludWU6IGBhcHByb3ZlLXRvb2wtY2FsbGAgLyBgZGVjbGluZS10b29sLWNhbGxgIChzdHJlYW1pbmcsIGFuZCB2aWFcbiAqIHByZWZpeCB0aGVpciBgLWdlbmVyYXRlYCBub24tc3RyZWFtaW5nIHZhcmlhbnRzKSwgdGhlIGAtbmV0d29yay1gIHZhcmlhbnRzLFxuICogYW5kIGByZXN1bWUtc3RyZWFtYCAoY292ZXJzIGByZXN1bWUtc3RyZWFtLXVudGlsLWlkbGVgKS4gV2l0aG91dCB0aGVzZSBhblxuICogYXBwcm92YWwtZ2F0ZWQgdG9vbCAoZS5nLiBgc2VuZF9lbWFpbGApIGNhbiBiZSByZXF1ZXN0ZWQgYnV0IG5ldmVyIGFwcHJvdmVkXG4gKiBmcm9tIHRoZSBicm93c2VyIC0gdGhlIHJlc3VtZSBgUE9TVGAgNDAzcyB1bmRlciBzY29wZWQgbW9kZS4gVGhlc2UgYXJlIHRoZVxuICogb25seSAqd3JpdGVzKiB0aGUgYnJvd3NlciBjbGllbnQgaXMgYWxsb3dlZCB0byBtYWtlIGFnYWluc3Qgc3RvY2sgTWFzdHJhLlxuICovXG5jb25zdCBBR0VOVF9JTkZFUkVOQ0UgPVxuICAvXlxcL2FnZW50c1xcL1teL10rXFwvKHN0cmVhbXxnZW5lcmF0ZXxuZXR3b3JrfHJlc3VtZS1zdHJlYW18YXBwcm92ZS10b29sLWNhbGx8ZGVjbGluZS10b29sLWNhbGx8YXBwcm92ZS1uZXR3b3JrLXRvb2wtY2FsbHxkZWNsaW5lLW5ldHdvcmstdG9vbC1jYWxsKS9pO1xuXG4vKiogTW91bnQtcmVsYXRpdmUgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhIChgL2FnZW50c2AsIGAvYWdlbnRzLzppZGApLiAqL1xuY29uc3QgQUdFTlRfTUVUQURBVEEgPSAvXlxcL2FnZW50cyhcXC9bXi9dKyk/JC87XG5cbi8qKlxuICogV2hldGhlciBhIHJlcXVlc3QgdG8gdGhlIHN0b2NrIGBAbWFzdHJhL2V4cHJlc3NgIHN1Yi1hcHAgc2hvdWxkIGJlXG4gKiBkaXNwYXRjaGVkLCBnaXZlbiB0aGUgY29uZmlndXJlZCB7QGxpbmsgTWFzdHJhQXBpR2F0ZU9wdGlvbnMuYWNjZXNzfS5cbiAqXG4gKiBgcGF0aGAgaXMgbW91bnQtcmVsYXRpdmUgKHdoYXQgdGhlIHBsdWdpbidzIGNhdGNoLWFsbCBzZWVzLCBlLmcuXG4gKiBgL2FnZW50cy94L3N0cmVhbWAsIGAvcm91dGUvaGlzdG9yeS94YCwgYC9tY3AvLi4uYCkuIEluIGBcInNjb3BlZFwiYFxuICogbW9kZSB0aGUgYWxsb3dsaXN0IGlzIGRlbGliZXJhdGVseSB0aWdodCAtIHRoZSBjaGF0IGNsaWVudCBvbmx5IGV2ZXJcbiAqIG5lZWRzIGFnZW50IGluZmVyZW5jZSwgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhLCB0aGlzIHBsdWdpbidzIG93blxuICogT0JPL3Jlc291cmNlLXNjb3BlZCBgL3JvdXRlLypgIHJvdXRlcywgYW5kICh3aGVuIGVuYWJsZWQpIE1DUCAtIHNvIHRoZVxuICogd2hvbGUgYWRtaW4gLyBtdXRhdGluZyAvIGJ1bGstZXhwb3J0IHN1cmZhY2UgTWFzdHJhIGFsc28gZXhwb3NlcyBpc1xuICogZGVuaWVkIGJ5IGRlZmF1bHQgcmF0aGVyIHRoYW4gZW51bWVyYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTWFzdHJhUmVxdWVzdEFsbG93ZWQoXG4gIG1ldGhvZDogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIG9wdHM6IE1hc3RyYUFwaUdhdGVPcHRpb25zLFxuKTogYm9vbGVhbiB7XG4gIGlmIChvcHRzLmFjY2VzcyA9PT0gXCJmdWxsXCIpIHJldHVybiB0cnVlO1xuICBjb25zdCBwID0gcGF0aC5zdGFydHNXaXRoKFwiL1wiKSA/IHBhdGggOiBgLyR7cGF0aH1gO1xuICAvLyBUaGlzIHBsdWdpbidzIG93biBjdXN0b20gcm91dGVzIGFyZSBpbmRpdmlkdWFsbHkgT0JPLSBhbmRcbiAgLy8gcmVzb3VyY2Utc2NvcGVkIChzZWUgaGlzdG9yeS50cyAvIHRocmVhZHMudHMpLCBzbyBldmVyeSBtZXRob2QgaXMgc2FmZS5cbiAgaWYgKHAgPT09IFwiL3JvdXRlXCIgfHwgcC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKSkgcmV0dXJuIHRydWU7XG4gIGlmIChvcHRzLm1jcEVuYWJsZWQgJiYgKHAgPT09IFwiL21jcFwiIHx8IHAuc3RhcnRzV2l0aChcIi9tY3AvXCIpKSkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IG0gPSBtZXRob2QudG9VcHBlckNhc2UoKTtcbiAgaWYgKG0gPT09IFwiUE9TVFwiICYmIEFHRU5UX0lORkVSRU5DRS50ZXN0KHApKSByZXR1cm4gdHJ1ZTtcbiAgaWYgKG0gPT09IFwiR0VUXCIgJiYgQUdFTlRfTUVUQURBVEEudGVzdChwKSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBQYXRjaGVzIGFyb3VuZCBgQG1hc3RyYS9leHByZXNzYCdzIGN1c3RvbS1yb3V0ZSBkaXNwYXRjaGVyIHNvIHRoZVxuICogcGx1Z2luJ3MgY3VzdG9tIEFQSSByb3V0ZXMgKGUuZy4gYGhpc3RvcnlSb3V0ZWApIHdvcmsgd2hlblxuICogYE1hc3RyYVNlcnZlcmAgaXMgaG9zdGVkIG9uIGFuIEV4cHJlc3Mgc3ViYXBwIG1vdW50ZWQgdW5kZXIgYSBwYXJlbnRcbiAqIHBhdGggKGUuZy4gYC9hcGkvbWFzdHJhYCkuXG4gKlxuICogVGhlIGFkYXB0ZXIncyBgcmVnaXN0ZXJDdXN0b21BcGlSb3V0ZXNgIG1hdGNoZXMgYWdhaW5zdCBgcmVxLnBhdGhgXG4gKiAobW91bnQtcmVsYXRpdmUsIGNvcnJlY3QpIGJ1dCBkaXNwYXRjaGVzIHRvIGl0cyBpbnRlcm5hbCBIb25vXG4gKiBtaW5pLWFwcCB1c2luZyBgcmVxLm9yaWdpbmFsVXJsYCwgd2hpY2ggc3RpbGwgY29udGFpbnMgdGhlIHBhcmVudFxuICogbW91bnQgcHJlZml4LiBUaGUgSG9ubyBhcHAgcmVnaXN0ZXJzIHRoZSBsaXRlcmFsIHJvdXRlIHBhdGhzXG4gKiAoZm9yIGV4YW1wbGUgYC9yb3V0ZS9oaXN0b3J5YCksIHNvIHRoZSBhYnNvbHV0ZSBVUkwgbmV2ZXIgbWF0Y2hlc1xuICogdW50aWwgd2Ugb3ZlcndyaXRlIGBvcmlnaW5hbFVybGAgZm9yIGAvcm91dGVgIGFuZCBgL3JvdXRlLypgIHRvIHRoZVxuICogbW91bnQtcmVsYXRpdmUgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFJvdXRlUGF0Y2hNaWRkbGV3YXJlKGFwcDogZXhwcmVzcy5FeHByZXNzKTogdm9pZCB7XG4gIGFwcC51c2UoKHJlcSwgX3JlcywgbmV4dCkgPT4ge1xuICAgIGNvbnN0IGlzQ3VzdG9tUm91dGUgPSByZXEucGF0aCA9PT0gXCIvcm91dGVcIiB8fCByZXEucGF0aC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKTtcbiAgICBpZiAoIWlzQ3VzdG9tUm91dGUpIHJldHVybiBuZXh0KCk7XG4gICAgcmVxLm9yaWdpbmFsVXJsID0gcmVxLnBhdGg7XG4gICAgbmV4dCgpO1xuICB9KTtcbn1cbiJdfQ==
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Repairs traffic between Mastra / the AI SDK and Databricks Model Serving's
3
+ * OpenAI-compatible `/chat/completions` route, in both directions.
4
+ *
5
+ * Outbound ({@link rewriteServingBody}), because the transcript Mastra
6
+ * persists is not always a transcript the provider will accept back:
7
+ * Databricks-hosted Claude rejects replayed extended-thinking blocks and reads
8
+ * a trailing assistant message as a prefill request.
9
+ *
10
+ * Inbound ({@link rewriteServingResponseBody}), because Databricks-hosted
11
+ * Gemini answers with its native content-parts array where the OpenAI contract
12
+ * (and therefore the AI SDK's response schema) requires a plain string.
13
+ *
14
+ * Every repair here is a provider quirk rather than a schema violation, so all
15
+ * of them are applied on the wire (see the `globalThis.fetch` wrapper in
16
+ * `model.ts`) rather than by changing what the agent stores or what the UI
17
+ * shows.
18
+ *
19
+ * @module
20
+ */
21
+ import { type ChatMessage, type ChatRole } from "@dbx-tools/shared-model";
22
+ /**
23
+ * A chat message as it arrives on the serving wire, plus the extended-thinking
24
+ * fields Databricks-hosted Claude adds. The OpenAI-standard part of the shape
25
+ * is {@link ChatMessage} from `@dbx-tools/shared-model`; only the provider
26
+ * extensions this module strips are declared here.
27
+ */
28
+ export interface ServingChatMessage extends ChatMessage {
29
+ /** Narrowed to the roles this repair pass reasons about, plus Claude's `reasoning` turn. */
30
+ role: ChatRole | "reasoning";
31
+ reasoning?: unknown;
32
+ reasoning_content?: unknown;
33
+ }
34
+ /**
35
+ * Parse, sanitize, and re-serialize a `/serving-endpoints/...` POST
36
+ * body. Returns the original string verbatim when the body is not
37
+ * JSON or no rewrite was needed.
38
+ */
39
+ export declare function rewriteServingBody(body: string): string;
40
+ /**
41
+ * Drop extended-thinking / reasoning blocks from a replayed transcript.
42
+ *
43
+ * Hybrid Claude endpoints (e.g. Sonnet 4.5+) may emit `reasoning` content
44
+ * parts on the first turn. Mastra persists and replays them on the next
45
+ * agent step, but Databricks-hosted Claude rejects those blocks on
46
+ * multi-turn tool continuations. The UI already captured reasoning for
47
+ * display; stripping here keeps provider replay compatible without
48
+ * changing what users see in the chat bubble.
49
+ */
50
+ export declare function stripReasoningFromServingMessages(messages: ServingChatMessage[]): boolean;
51
+ /**
52
+ * Repair a Mastra/AI SDK message replay that Databricks-hosted Claude
53
+ * rejects with `"This model does not support assistant message
54
+ * prefill. The conversation must end with a user message."`.
55
+ *
56
+ * The bug pattern: when an assistant turn streams text *and* a
57
+ * `tool_call`, the AI SDK persists them as two separate assistant
58
+ * entries (text-only and tool-call-only). On the next agent step the
59
+ * tool-call entry is replayed *before* the tool result and the
60
+ * text entry is replayed *after* it, so the conversation ends with a
61
+ * trailing assistant text message. Anthropic interprets that as a
62
+ * prefill request and rejects it on Databricks (the upstream Bedrock
63
+ * route disallows prefill).
64
+ *
65
+ * Fix: when the last message is an assistant text with no `tool_calls`
66
+ * and the chain immediately before it is `assistant(tool_calls=...)`
67
+ * followed only by `tool(...)` results, fold the trailing text back
68
+ * into the `content` of that opening assistant and drop the duplicate.
69
+ */
70
+ export declare function repairAssistantPrefill(messages: ServingChatMessage[]): boolean;
71
+ /**
72
+ * Parse, sanitize, and re-serialize a `/serving-endpoints/...` non-streaming
73
+ * JSON RESPONSE body. Returns the original string verbatim when the body is
74
+ * not JSON or no rewrite was needed, mirroring
75
+ * {@link rewriteServingBody} on the request side.
76
+ */
77
+ export declare function rewriteServingResponseBody(body: string): string;
78
+ /**
79
+ * Collapse a structured `choices[].message.content` array to the plain string
80
+ * the OpenAI Chat Completions contract specifies.
81
+ *
82
+ * Databricks-hosted Gemini answers a non-streaming `/chat/completions` call
83
+ * with the Gemini-native parts shape:
84
+ *
85
+ * ```json
86
+ * "content": [{ "type": "text", "text": "...", "thoughtSignature": "..." }]
87
+ * ```
88
+ *
89
+ * `@ai-sdk/openai-compatible` validates the response against the OpenAI
90
+ * schema, where `content` is a nullable string, so it throws
91
+ * `Type validation failed: ... expected string, received array` and the whole
92
+ * call fails (`AI_APICallError: Invalid JSON response` on an HTTP 200). Mastra
93
+ * uses `doGenerate` for its side calls, so the visible symptom is
94
+ * `Error generating title` - every thread keeps its placeholder name.
95
+ *
96
+ * Flattening on the wire keeps the repair in one place: the streaming path is
97
+ * unaffected (deltas already carry string content), and neither the agent's
98
+ * stored transcript nor the UI has to know the provider emitted parts. Any
99
+ * non-text part (a `thoughtSignature`-only entry, an inline image) contributes
100
+ * nothing, matching {@link openaiChat.chatContentToText}, and an all-parts-empty
101
+ * message flattens to `""` rather than being dropped, so `finish_reason` and
102
+ * `usage` still round-trip.
103
+ */
104
+ export declare function flattenChoiceMessageContent(payload: Record<string, unknown>): boolean;