@dbx-tools/appkit-generator 0.0.0-stage → 0.9.136

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 (60) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +181 -2
  3. package/index.ts +44 -0
  4. package/lib/index.d.ts +40 -0
  5. package/lib/index.js +30 -0
  6. package/lib/src/assets.d.ts +33 -0
  7. package/lib/src/assets.js +224 -0
  8. package/lib/src/config.d.ts +75 -0
  9. package/lib/src/config.js +31 -0
  10. package/lib/src/dashboard.d.ts +30 -0
  11. package/lib/src/dashboard.js +257 -0
  12. package/lib/src/data.d.ts +17 -0
  13. package/lib/src/data.js +114 -0
  14. package/lib/src/defaults.d.ts +39 -0
  15. package/lib/src/defaults.js +36 -0
  16. package/lib/src/generate.d.ts +51 -0
  17. package/lib/src/generate.js +163 -0
  18. package/lib/src/genie.d.ts +51 -0
  19. package/lib/src/genie.js +84 -0
  20. package/lib/src/kpi.d.ts +22 -0
  21. package/lib/src/kpi.js +74 -0
  22. package/lib/src/manifest.json +72 -0
  23. package/lib/src/namespace.d.ts +36 -0
  24. package/lib/src/namespace.js +119 -0
  25. package/lib/src/operations.d.ts +42 -0
  26. package/lib/src/operations.js +96 -0
  27. package/lib/src/palette.d.ts +10 -0
  28. package/lib/src/palette.js +69 -0
  29. package/lib/src/plan.d.ts +21 -0
  30. package/lib/src/plan.js +33 -0
  31. package/lib/src/plugin.d.ts +619 -0
  32. package/lib/src/plugin.js +205 -0
  33. package/lib/src/research.d.ts +78 -0
  34. package/lib/src/research.js +235 -0
  35. package/lib/src/schema.d.ts +52 -0
  36. package/lib/src/schema.js +82 -0
  37. package/lib/src/structured.d.ts +27 -0
  38. package/lib/src/structured.js +30 -0
  39. package/lib/src/workflow.d.ts +314 -0
  40. package/lib/src/workflow.js +171 -0
  41. package/lib/tsconfig.tsbuildinfo +1 -0
  42. package/package.json +218 -4
  43. package/src/assets.ts +248 -0
  44. package/src/config.ts +98 -0
  45. package/src/dashboard.ts +295 -0
  46. package/src/data.ts +167 -0
  47. package/src/defaults.ts +61 -0
  48. package/src/generate.ts +250 -0
  49. package/src/genie.ts +111 -0
  50. package/src/kpi.ts +106 -0
  51. package/src/manifest.json +72 -0
  52. package/src/namespace.ts +192 -0
  53. package/src/operations.ts +171 -0
  54. package/src/palette.ts +81 -0
  55. package/src/plan.ts +59 -0
  56. package/src/plugin.ts +244 -0
  57. package/src/research.ts +382 -0
  58. package/src/schema.ts +114 -0
  59. package/src/structured.ts +54 -0
  60. package/src/workflow.ts +221 -0
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Deterministic AI/BI dashboard assembly and OBO publication.
3
+ *
4
+ * @module
5
+ */
6
+ import { ExecutionError } from "@databricks/appkit";
7
+ import { databricks } from "@dbx-tools/appkit";
8
+ import { hash } from "@dbx-tools/shared-core";
9
+ import { GeneratedDashboardSchema, } from "@dbx-tools/shared-generator/workflow";
10
+ import { z } from "zod";
11
+ import { resolveGeneratorIdentity } from "./namespace.js";
12
+ const SerializedDashboardSchema = z
13
+ .object({
14
+ datasets: z.array(z.record(z.string(), z.unknown())).min(1),
15
+ pages: z.array(z.record(z.string(), z.unknown())).min(1),
16
+ uiSettings: z.record(z.string(), z.unknown()),
17
+ })
18
+ .strict();
19
+ /** Compile one metric into a reusable Lakeview dataset measure. */
20
+ function measure(metric) {
21
+ const expression = metric.aggregation === "count"
22
+ ? "COUNT(`*`)"
23
+ : `${metric.aggregation === "sum" ? "SUM" : "AVG"}(\`${metric.column}\`)`;
24
+ return {
25
+ displayName: metric.label,
26
+ description: metric.definition,
27
+ expression,
28
+ };
29
+ }
30
+ /** Counter widget bound to one dataset measure. */
31
+ function counterWidget(metric, index) {
32
+ const fieldName = `measure(${metric.label})`;
33
+ return {
34
+ widget: {
35
+ name: `kpi_${metric.name}`,
36
+ queries: [
37
+ {
38
+ name: "main_query",
39
+ query: {
40
+ datasetName: "generated_facts",
41
+ fields: [{ name: fieldName, expression: `MEASURE(\`${metric.label}\`)` }],
42
+ disaggregated: false,
43
+ },
44
+ },
45
+ ],
46
+ spec: {
47
+ version: 2,
48
+ widgetType: "counter",
49
+ encodings: {
50
+ value: {
51
+ fieldName,
52
+ displayName: metric.label,
53
+ ...(metric.unit === "percent"
54
+ ? {
55
+ format: {
56
+ type: "number-percent",
57
+ decimalPlaces: { type: "max", places: 2 },
58
+ },
59
+ }
60
+ : {}),
61
+ },
62
+ },
63
+ frame: { showTitle: true, title: metric.label },
64
+ },
65
+ },
66
+ position: {
67
+ x: (index % 3) * 4,
68
+ y: 2 + Math.floor(index / 3) * 3,
69
+ width: 4,
70
+ height: 3,
71
+ },
72
+ };
73
+ }
74
+ /** Build one complete dashboard with automatic companion Genie enabled. */
75
+ export function buildGeneratorDashboard(input) {
76
+ const fullTable = `${input.location.catalog}.${input.location.schema}.${input.plan.table}`;
77
+ const dateColumn = input.plan.columns.find(({ generator }) => generator === "date")?.name;
78
+ const categoryColumn = input.plan.columns.find(({ generator }) => generator === "category")?.name;
79
+ const metric = input.plan.metrics[0];
80
+ const metricField = `measure(${metric.label})`;
81
+ const kpiRows = Math.ceil(input.plan.metrics.length / 3);
82
+ const chartY = 2 + kpiRows * 3;
83
+ const layout = [
84
+ {
85
+ widget: {
86
+ name: "header",
87
+ multilineTextboxSpec: {
88
+ lines: [`# ${input.company}: ${input.purpose}\n`, `\n`, input.plan.story],
89
+ },
90
+ },
91
+ position: { x: 0, y: 0, width: 12, height: 2 },
92
+ },
93
+ ...input.plan.metrics.map(counterWidget),
94
+ ];
95
+ if (dateColumn) {
96
+ layout.push({
97
+ widget: {
98
+ name: "metric_trend",
99
+ queries: [
100
+ {
101
+ name: "main_query",
102
+ query: {
103
+ datasetName: "generated_facts",
104
+ fields: [
105
+ {
106
+ name: `daily(${dateColumn})`,
107
+ expression: `DATE_TRUNC("DAY", \`${dateColumn}\`)`,
108
+ },
109
+ { name: metricField, expression: `MEASURE(\`${metric.label}\`)` },
110
+ ],
111
+ disaggregated: false,
112
+ },
113
+ },
114
+ ],
115
+ spec: {
116
+ version: 3,
117
+ widgetType: "line",
118
+ encodings: {
119
+ x: {
120
+ fieldName: `daily(${dateColumn})`,
121
+ scale: { type: "temporal" },
122
+ displayName: "Date",
123
+ },
124
+ y: {
125
+ fieldName: metricField,
126
+ scale: { type: "quantitative" },
127
+ displayName: metric.label,
128
+ },
129
+ },
130
+ frame: { showTitle: true, title: `${metric.label} trend` },
131
+ },
132
+ },
133
+ position: { x: 0, y: chartY, width: 7, height: 6 },
134
+ });
135
+ }
136
+ if (categoryColumn) {
137
+ layout.push({
138
+ widget: {
139
+ name: "metric_by_category",
140
+ queries: [
141
+ {
142
+ name: "main_query",
143
+ query: {
144
+ datasetName: "generated_facts",
145
+ fields: [
146
+ { name: categoryColumn, expression: `\`${categoryColumn}\`` },
147
+ { name: metricField, expression: `MEASURE(\`${metric.label}\`)` },
148
+ ],
149
+ disaggregated: false,
150
+ },
151
+ },
152
+ ],
153
+ spec: {
154
+ version: 3,
155
+ widgetType: "bar",
156
+ encodings: {
157
+ x: {
158
+ fieldName: categoryColumn,
159
+ scale: { type: "categorical" },
160
+ displayName: categoryColumn,
161
+ },
162
+ y: {
163
+ fieldName: metricField,
164
+ scale: { type: "quantitative" },
165
+ displayName: metric.label,
166
+ },
167
+ },
168
+ frame: { showTitle: true, title: `${metric.label} by ${categoryColumn}` },
169
+ },
170
+ },
171
+ position: { x: 7, y: chartY, width: 5, height: 6 },
172
+ });
173
+ }
174
+ return SerializedDashboardSchema.parse({
175
+ datasets: [
176
+ {
177
+ name: "generated_facts",
178
+ displayName: input.plan.table,
179
+ asset_name: fullTable,
180
+ columns: input.plan.metrics.map(measure),
181
+ },
182
+ ],
183
+ pages: [
184
+ {
185
+ name: "overview",
186
+ displayName: "Overview",
187
+ pageType: "PAGE_TYPE_CANVAS",
188
+ layoutVersion: "GRID_V1",
189
+ layout,
190
+ },
191
+ ],
192
+ uiSettings: {
193
+ theme: {
194
+ canvasBackgroundColor: {
195
+ light: input.brand.colors.background,
196
+ dark: input.brand.colors.foreground,
197
+ },
198
+ widgetBackgroundColor: {
199
+ light: input.brand.colors.surface,
200
+ dark: input.brand.colors.primary,
201
+ },
202
+ fontColor: {
203
+ light: input.brand.colors.foreground,
204
+ dark: input.brand.colors.background,
205
+ },
206
+ selectionColor: {
207
+ light: input.brand.colors.primary,
208
+ dark: input.brand.colors.accent,
209
+ },
210
+ visualizationColors: [
211
+ input.brand.colors.primary,
212
+ input.brand.colors.accent,
213
+ input.brand.colors.primaryHover,
214
+ input.brand.colors.muted,
215
+ ],
216
+ widgetHeaderAlignment: "LEFT",
217
+ },
218
+ genieSpace: {
219
+ isEnabled: true,
220
+ enablementMode: "AUTO",
221
+ },
222
+ },
223
+ });
224
+ }
225
+ /** Create and publish a dashboard as the active OBO user. */
226
+ export async function createGeneratorDashboard(input, signal) {
227
+ const identity = await resolveGeneratorIdentity();
228
+ if (identity.principal !== input.location.principal) {
229
+ throw new ExecutionError("Dashboard principal does not match the active OBO user");
230
+ }
231
+ const legacy = identity.userClient.toLegacyWorkspaceClient();
232
+ const parentPath = `/Workspace/Users/${identity.principal}/.dbx-tools/generator/${input.location.schema}`;
233
+ const context = signal ? databricks.toContext(signal) : undefined;
234
+ await legacy.workspace.mkdirs({ path: parentPath }, context);
235
+ const created = await legacy.lakeview.create({
236
+ dashboard: {
237
+ display_name: `${input.company} ${input.purpose} ${hash.id(6)}`,
238
+ parent_path: parentPath,
239
+ warehouse_id: input.warehouseId,
240
+ serialized_dashboard: JSON.stringify(buildGeneratorDashboard(input)),
241
+ },
242
+ }, context);
243
+ if (!created.dashboard_id) {
244
+ throw new ExecutionError("Lakeview create returned no dashboard id");
245
+ }
246
+ await legacy.lakeview.publish({
247
+ dashboard_id: created.dashboard_id,
248
+ warehouse_id: input.warehouseId,
249
+ embed_credentials: false,
250
+ }, context);
251
+ return GeneratedDashboardSchema.parse({
252
+ dashboardId: created.dashboard_id,
253
+ ...(created.path ? { path: created.path } : {}),
254
+ companionGenie: "AUTO",
255
+ });
256
+ }
257
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Rhc2hib2FyZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUMsT0FBTyxFQUNMLHdCQUF3QixHQUt6QixNQUFNLHNDQUFzQyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDeEIsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFMUQsTUFBTSx5QkFBeUIsR0FBRyxDQUFDO0tBQ2hDLE1BQU0sQ0FBQztJQUNOLFFBQVEsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMzRCxLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEQsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztDQUM5QyxDQUFDO0tBQ0QsTUFBTSxFQUFFLENBQUM7QUFrQlosbUVBQW1FO0FBQ25FLFNBQVMsT0FBTyxDQUFDLE1BQXVCO0lBQ3RDLE1BQU0sVUFBVSxHQUNkLE1BQU0sQ0FBQyxXQUFXLEtBQUssT0FBTztRQUM1QixDQUFDLENBQUMsWUFBWTtRQUNkLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxXQUFXLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssTUFBTSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7SUFDOUUsT0FBTztRQUNMLFdBQVcsRUFBRSxNQUFNLENBQUMsS0FBSztRQUN6QixXQUFXLEVBQUUsTUFBTSxDQUFDLFVBQVU7UUFDOUIsVUFBVTtLQUNYLENBQUM7QUFDSixDQUFDO0FBRUQsbURBQW1EO0FBQ25ELFNBQVMsYUFBYSxDQUFDLE1BQXVCLEVBQUUsS0FBYTtJQUMzRCxNQUFNLFNBQVMsR0FBRyxXQUFXLE1BQU0sQ0FBQyxLQUFLLEdBQUcsQ0FBQztJQUM3QyxPQUFPO1FBQ0wsTUFBTSxFQUFFO1lBQ04sSUFBSSxFQUFFLE9BQU8sTUFBTSxDQUFDLElBQUksRUFBRTtZQUMxQixPQUFPLEVBQUU7Z0JBQ1A7b0JBQ0UsSUFBSSxFQUFFLFlBQVk7b0JBQ2xCLEtBQUssRUFBRTt3QkFDTCxXQUFXLEVBQUUsaUJBQWlCO3dCQUM5QixNQUFNLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLGFBQWEsTUFBTSxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUM7d0JBQ3pFLGFBQWEsRUFBRSxLQUFLO3FCQUNyQjtpQkFDRjthQUNGO1lBQ0QsSUFBSSxFQUFFO2dCQUNKLE9BQU8sRUFBRSxDQUFDO2dCQUNWLFVBQVUsRUFBRSxTQUFTO2dCQUNyQixTQUFTLEVBQUU7b0JBQ1QsS0FBSyxFQUFFO3dCQUNMLFNBQVM7d0JBQ1QsV0FBVyxFQUFFLE1BQU0sQ0FBQyxLQUFLO3dCQUN6QixHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxTQUFTOzRCQUMzQixDQUFDLENBQUM7Z0NBQ0UsTUFBTSxFQUFFO29DQUNOLElBQUksRUFBRSxnQkFBZ0I7b0NBQ3RCLGFBQWEsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRTtpQ0FDMUM7NkJBQ0Y7NEJBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQztxQkFDUjtpQkFDRjtnQkFDRCxLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFO2FBQ2hEO1NBQ0Y7UUFDRCxRQUFRLEVBQUU7WUFDUixDQUFDLEVBQUUsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQztZQUNsQixDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDaEMsS0FBSyxFQUFFLENBQUM7WUFDUixNQUFNLEVBQUUsQ0FBQztTQUNWO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsTUFBTSxVQUFVLHVCQUF1QixDQUFDLEtBQW9DO0lBQzFFLE1BQU0sU0FBUyxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMzRixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxTQUFTLEtBQUssTUFBTSxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQzFGLE1BQU0sY0FBYyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxDQUFDLFNBQVMsS0FBSyxVQUFVLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDbEcsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFFLENBQUM7SUFDdEMsTUFBTSxXQUFXLEdBQUcsV0FBVyxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUM7SUFDL0MsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDekQsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLE9BQU8sR0FBRyxDQUFDLENBQUM7SUFDL0IsTUFBTSxNQUFNLEdBQThCO1FBQ3hDO1lBQ0UsTUFBTSxFQUFFO2dCQUNOLElBQUksRUFBRSxRQUFRO2dCQUNkLG9CQUFvQixFQUFFO29CQUNwQixLQUFLLEVBQUUsQ0FBQyxLQUFLLEtBQUssQ0FBQyxPQUFPLEtBQUssS0FBSyxDQUFDLE9BQU8sSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztpQkFDMUU7YUFDRjtZQUNELFFBQVEsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUU7U0FDL0M7UUFDRCxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUM7S0FDekMsQ0FBQztJQUNGLElBQUksVUFBVSxFQUFFLENBQUM7UUFDZixNQUFNLENBQUMsSUFBSSxDQUFDO1lBQ1YsTUFBTSxFQUFFO2dCQUNOLElBQUksRUFBRSxjQUFjO2dCQUNwQixPQUFPLEVBQUU7b0JBQ1A7d0JBQ0UsSUFBSSxFQUFFLFlBQVk7d0JBQ2xCLEtBQUssRUFBRTs0QkFDTCxXQUFXLEVBQUUsaUJBQWlCOzRCQUM5QixNQUFNLEVBQUU7Z0NBQ047b0NBQ0UsSUFBSSxFQUFFLFNBQVMsVUFBVSxHQUFHO29DQUM1QixVQUFVLEVBQUUsdUJBQXVCLFVBQVUsS0FBSztpQ0FDbkQ7Z0NBQ0QsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxhQUFhLE1BQU0sQ0FBQyxLQUFLLEtBQUssRUFBRTs2QkFDbEU7NEJBQ0QsYUFBYSxFQUFFLEtBQUs7eUJBQ3JCO3FCQUNGO2lCQUNGO2dCQUNELElBQUksRUFBRTtvQkFDSixPQUFPLEVBQUUsQ0FBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtvQkFDbEIsU0FBUyxFQUFFO3dCQUNULENBQUMsRUFBRTs0QkFDRCxTQUFTLEVBQUUsU0FBUyxVQUFVLEdBQUc7NEJBQ2pDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7NEJBQzNCLFdBQVcsRUFBRSxNQUFNO3lCQUNwQjt3QkFDRCxDQUFDLEVBQUU7NEJBQ0QsU0FBUyxFQUFFLFdBQVc7NEJBQ3RCLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUU7NEJBQy9CLFdBQVcsRUFBRSxNQUFNLENBQUMsS0FBSzt5QkFDMUI7cUJBQ0Y7b0JBQ0QsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxNQUFNLENBQUMsS0FBSyxRQUFRLEVBQUU7aUJBQzNEO2FBQ0Y7WUFDRCxRQUFRLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFO1NBQ25ELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxJQUFJLGNBQWMsRUFBRSxDQUFDO1FBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDVixNQUFNLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLG9CQUFvQjtnQkFDMUIsT0FBTyxFQUFFO29CQUNQO3dCQUNFLElBQUksRUFBRSxZQUFZO3dCQUNsQixLQUFLLEVBQUU7NEJBQ0wsV0FBVyxFQUFFLGlCQUFpQjs0QkFDOUIsTUFBTSxFQUFFO2dDQUNOLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsS0FBSyxjQUFjLElBQUksRUFBRTtnQ0FDN0QsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxhQUFhLE1BQU0sQ0FBQyxLQUFLLEtBQUssRUFBRTs2QkFDbEU7NEJBQ0QsYUFBYSxFQUFFLEtBQUs7eUJBQ3JCO3FCQUNGO2lCQUNGO2dCQUNELElBQUksRUFBRTtvQkFDSixPQUFPLEVBQUUsQ0FBQztvQkFDVixVQUFVLEVBQUUsS0FBSztvQkFDakIsU0FBUyxFQUFFO3dCQUNULENBQUMsRUFBRTs0QkFDRCxTQUFTLEVBQUUsY0FBYzs0QkFDekIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRTs0QkFDOUIsV0FBVyxFQUFFLGNBQWM7eUJBQzVCO3dCQUNELENBQUMsRUFBRTs0QkFDRCxTQUFTLEVBQUUsV0FBVzs0QkFDdEIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRTs0QkFDL0IsV0FBVyxFQUFFLE1BQU0sQ0FBQyxLQUFLO3lCQUMxQjtxQkFDRjtvQkFDRCxLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sQ0FBQyxLQUFLLE9BQU8sY0FBYyxFQUFFLEVBQUU7aUJBQzFFO2FBQ0Y7WUFDRCxRQUFRLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFO1NBQ25ELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLHlCQUF5QixDQUFDLEtBQUssQ0FBQztRQUNyQyxRQUFRLEVBQUU7WUFDUjtnQkFDRSxJQUFJLEVBQUUsaUJBQWlCO2dCQUN2QixXQUFXLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLO2dCQUM3QixVQUFVLEVBQUUsU0FBUztnQkFDckIsT0FBTyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUM7YUFDekM7U0FDRjtRQUNELEtBQUssRUFBRTtZQUNMO2dCQUNFLElBQUksRUFBRSxVQUFVO2dCQUNoQixXQUFXLEVBQUUsVUFBVTtnQkFDdkIsUUFBUSxFQUFFLGtCQUFrQjtnQkFDNUIsYUFBYSxFQUFFLFNBQVM7Z0JBQ3hCLE1BQU07YUFDUDtTQUNGO1FBQ0QsVUFBVSxFQUFFO1lBQ1YsS0FBSyxFQUFFO2dCQUNMLHFCQUFxQixFQUFFO29CQUNyQixLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVTtvQkFDcEMsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVU7aUJBQ3BDO2dCQUNELHFCQUFxQixFQUFFO29CQUNyQixLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTztvQkFDakMsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU87aUJBQ2pDO2dCQUNELFNBQVMsRUFBRTtvQkFDVCxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVTtvQkFDcEMsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVU7aUJBQ3BDO2dCQUNELGNBQWMsRUFBRTtvQkFDZCxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTztvQkFDakMsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU07aUJBQ2hDO2dCQUNELG1CQUFtQixFQUFFO29CQUNuQixLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPO29CQUMxQixLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNO29CQUN6QixLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxZQUFZO29CQUMvQixLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLO2lCQUN6QjtnQkFDRCxxQkFBcUIsRUFBRSxNQUFNO2FBQzlCO1lBQ0QsVUFBVSxFQUFFO2dCQUNWLFNBQVMsRUFBRSxJQUFJO2dCQUNmLGNBQWMsRUFBRSxNQUFNO2FBQ3ZCO1NBQ0Y7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsNkRBQTZEO0FBQzdELE1BQU0sQ0FBQyxLQUFLLFVBQVUsd0JBQXdCLENBQzVDLEtBQW9DLEVBQ3BDLE1BQW9CO0lBRXBCLE1BQU0sUUFBUSxHQUFHLE1BQU0sd0JBQXdCLEVBQUUsQ0FBQztJQUNsRCxJQUFJLFFBQVEsQ0FBQyxTQUFTLEtBQUssS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNwRCxNQUFNLElBQUksY0FBYyxDQUFDLHdEQUF3RCxDQUFDLENBQUM7SUFDckYsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztJQUM3RCxNQUFNLFVBQVUsR0FBRyxvQkFBb0IsUUFBUSxDQUFDLFNBQVMseUJBQXlCLEtBQUssQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDMUcsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDbEUsTUFBTSxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM3RCxNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUMxQztRQUNFLFNBQVMsRUFBRTtZQUNULFlBQVksRUFBRSxHQUFHLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQy9ELFdBQVcsRUFBRSxVQUFVO1lBQ3ZCLFlBQVksRUFBRSxLQUFLLENBQUMsV0FBVztZQUMvQixvQkFBb0IsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLHVCQUF1QixDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ3JFO0tBQ0YsRUFDRCxPQUFPLENBQ1IsQ0FBQztJQUNGLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDMUIsTUFBTSxJQUFJLGNBQWMsQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFDRCxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUMzQjtRQUNFLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtRQUNsQyxZQUFZLEVBQUUsS0FBSyxDQUFDLFdBQVc7UUFDL0IsaUJBQWlCLEVBQUUsS0FBSztLQUN6QixFQUNELE9BQU8sQ0FDUixDQUFDO0lBQ0YsT0FBTyx3QkFBd0IsQ0FBQyxLQUFLLENBQUM7UUFDcEMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxZQUFZO1FBQ2pDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMvQyxjQUFjLEVBQUUsTUFBTTtLQUN2QixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZXRlcm1pbmlzdGljIEFJL0JJIGRhc2hib2FyZCBhc3NlbWJseSBhbmQgT0JPIHB1YmxpY2F0aW9uLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBFeGVjdXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGRhdGFicmlja3MgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbmltcG9ydCB7IGhhc2ggfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBCcmFuZENvbnRleHQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZS9icmFuZC11dGlsc1wiO1xuaW1wb3J0IHtcbiAgR2VuZXJhdGVkRGFzaGJvYXJkU2NoZW1hLFxuICB0eXBlIEdlbmVyYXRlZERhc2hib2FyZCxcbiAgdHlwZSBHZW5lcmF0ZWRNZXRyaWMsXG4gIHR5cGUgR2VuZXJhdGVkU2NoZW1hLFxuICB0eXBlIEdlbmVyYXRvclBsYW4sXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1nZW5lcmF0b3Ivd29ya2Zsb3dcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgeyByZXNvbHZlR2VuZXJhdG9ySWRlbnRpdHkgfSBmcm9tIFwiLi9uYW1lc3BhY2UudHNcIjtcblxuY29uc3QgU2VyaWFsaXplZERhc2hib2FyZFNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgZGF0YXNldHM6IHouYXJyYXkoei5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpKS5taW4oMSksXG4gICAgcGFnZXM6IHouYXJyYXkoei5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpKS5taW4oMSksXG4gICAgdWlTZXR0aW5nczogei5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpLFxuICB9KVxuICAuc3RyaWN0KCk7XG5cbi8qKiBJbnB1dHMgZm9yIGRhc2hib2FyZCBhc3NlbWJseSBhbmQgcHVibGljYXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZUdlbmVyYXRvckRhc2hib2FyZElucHV0IHtcbiAgLyoqIEdlbmVyYXRlZCBzY2hlbWEgY29udGFpbmluZyB0aGUgZmFjdCB0YWJsZS4gKi9cbiAgbG9jYXRpb246IEdlbmVyYXRlZFNjaGVtYTtcbiAgLyoqIFZhbGlkYXRlZCBkYXRhIGFuZCBtZXRyaWMgcGxhbi4gKi9cbiAgcGxhbjogR2VuZXJhdG9yUGxhbjtcbiAgLyoqIEJyYW5kIGFwcGxpZWQgdG8gdGhlIGRhc2hib2FyZCB0aGVtZS4gKi9cbiAgYnJhbmQ6IEJyYW5kQ29udGV4dDtcbiAgLyoqIFNRTCB3YXJlaG91c2UgdXNlZCBieSB0aGUgZGFzaGJvYXJkLiAqL1xuICB3YXJlaG91c2VJZDogc3RyaW5nO1xuICAvKiogQ29tcGFueSBkaXNwbGF5IG5hbWUuICovXG4gIGNvbXBhbnk6IHN0cmluZztcbiAgLyoqIERlbW8gcHVycG9zZS4gKi9cbiAgcHVycG9zZTogc3RyaW5nO1xufVxuXG4vKiogQ29tcGlsZSBvbmUgbWV0cmljIGludG8gYSByZXVzYWJsZSBMYWtldmlldyBkYXRhc2V0IG1lYXN1cmUuICovXG5mdW5jdGlvbiBtZWFzdXJlKG1ldHJpYzogR2VuZXJhdGVkTWV0cmljKSB7XG4gIGNvbnN0IGV4cHJlc3Npb24gPVxuICAgIG1ldHJpYy5hZ2dyZWdhdGlvbiA9PT0gXCJjb3VudFwiXG4gICAgICA/IFwiQ09VTlQoYCpgKVwiXG4gICAgICA6IGAke21ldHJpYy5hZ2dyZWdhdGlvbiA9PT0gXCJzdW1cIiA/IFwiU1VNXCIgOiBcIkFWR1wifShcXGAke21ldHJpYy5jb2x1bW59XFxgKWA7XG4gIHJldHVybiB7XG4gICAgZGlzcGxheU5hbWU6IG1ldHJpYy5sYWJlbCxcbiAgICBkZXNjcmlwdGlvbjogbWV0cmljLmRlZmluaXRpb24sXG4gICAgZXhwcmVzc2lvbixcbiAgfTtcbn1cblxuLyoqIENvdW50ZXIgd2lkZ2V0IGJvdW5kIHRvIG9uZSBkYXRhc2V0IG1lYXN1cmUuICovXG5mdW5jdGlvbiBjb3VudGVyV2lkZ2V0KG1ldHJpYzogR2VuZXJhdGVkTWV0cmljLCBpbmRleDogbnVtYmVyKSB7XG4gIGNvbnN0IGZpZWxkTmFtZSA9IGBtZWFzdXJlKCR7bWV0cmljLmxhYmVsfSlgO1xuICByZXR1cm4ge1xuICAgIHdpZGdldDoge1xuICAgICAgbmFtZTogYGtwaV8ke21ldHJpYy5uYW1lfWAsXG4gICAgICBxdWVyaWVzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcIm1haW5fcXVlcnlcIixcbiAgICAgICAgICBxdWVyeToge1xuICAgICAgICAgICAgZGF0YXNldE5hbWU6IFwiZ2VuZXJhdGVkX2ZhY3RzXCIsXG4gICAgICAgICAgICBmaWVsZHM6IFt7IG5hbWU6IGZpZWxkTmFtZSwgZXhwcmVzc2lvbjogYE1FQVNVUkUoXFxgJHttZXRyaWMubGFiZWx9XFxgKWAgfV0sXG4gICAgICAgICAgICBkaXNhZ2dyZWdhdGVkOiBmYWxzZSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIHNwZWM6IHtcbiAgICAgICAgdmVyc2lvbjogMixcbiAgICAgICAgd2lkZ2V0VHlwZTogXCJjb3VudGVyXCIsXG4gICAgICAgIGVuY29kaW5nczoge1xuICAgICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAgICBmaWVsZE5hbWUsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZTogbWV0cmljLmxhYmVsLFxuICAgICAgICAgICAgLi4uKG1ldHJpYy51bml0ID09PSBcInBlcmNlbnRcIlxuICAgICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICAgIGZvcm1hdDoge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiBcIm51bWJlci1wZXJjZW50XCIsXG4gICAgICAgICAgICAgICAgICAgIGRlY2ltYWxQbGFjZXM6IHsgdHlwZTogXCJtYXhcIiwgcGxhY2VzOiAyIH0sXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgZnJhbWU6IHsgc2hvd1RpdGxlOiB0cnVlLCB0aXRsZTogbWV0cmljLmxhYmVsIH0sXG4gICAgICB9LFxuICAgIH0sXG4gICAgcG9zaXRpb246IHtcbiAgICAgIHg6IChpbmRleCAlIDMpICogNCxcbiAgICAgIHk6IDIgKyBNYXRoLmZsb29yKGluZGV4IC8gMykgKiAzLFxuICAgICAgd2lkdGg6IDQsXG4gICAgICBoZWlnaHQ6IDMsXG4gICAgfSxcbiAgfTtcbn1cblxuLyoqIEJ1aWxkIG9uZSBjb21wbGV0ZSBkYXNoYm9hcmQgd2l0aCBhdXRvbWF0aWMgY29tcGFuaW9uIEdlbmllIGVuYWJsZWQuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRHZW5lcmF0b3JEYXNoYm9hcmQoaW5wdXQ6IENyZWF0ZUdlbmVyYXRvckRhc2hib2FyZElucHV0KSB7XG4gIGNvbnN0IGZ1bGxUYWJsZSA9IGAke2lucHV0LmxvY2F0aW9uLmNhdGFsb2d9LiR7aW5wdXQubG9jYXRpb24uc2NoZW1hfS4ke2lucHV0LnBsYW4udGFibGV9YDtcbiAgY29uc3QgZGF0ZUNvbHVtbiA9IGlucHV0LnBsYW4uY29sdW1ucy5maW5kKCh7IGdlbmVyYXRvciB9KSA9PiBnZW5lcmF0b3IgPT09IFwiZGF0ZVwiKT8ubmFtZTtcbiAgY29uc3QgY2F0ZWdvcnlDb2x1bW4gPSBpbnB1dC5wbGFuLmNvbHVtbnMuZmluZCgoeyBnZW5lcmF0b3IgfSkgPT4gZ2VuZXJhdG9yID09PSBcImNhdGVnb3J5XCIpPy5uYW1lO1xuICBjb25zdCBtZXRyaWMgPSBpbnB1dC5wbGFuLm1ldHJpY3NbMF0hO1xuICBjb25zdCBtZXRyaWNGaWVsZCA9IGBtZWFzdXJlKCR7bWV0cmljLmxhYmVsfSlgO1xuICBjb25zdCBrcGlSb3dzID0gTWF0aC5jZWlsKGlucHV0LnBsYW4ubWV0cmljcy5sZW5ndGggLyAzKTtcbiAgY29uc3QgY2hhcnRZID0gMiArIGtwaVJvd3MgKiAzO1xuICBjb25zdCBsYXlvdXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+W10gPSBbXG4gICAge1xuICAgICAgd2lkZ2V0OiB7XG4gICAgICAgIG5hbWU6IFwiaGVhZGVyXCIsXG4gICAgICAgIG11bHRpbGluZVRleHRib3hTcGVjOiB7XG4gICAgICAgICAgbGluZXM6IFtgIyAke2lucHV0LmNvbXBhbnl9OiAke2lucHV0LnB1cnBvc2V9XFxuYCwgYFxcbmAsIGlucHV0LnBsYW4uc3RvcnldLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHBvc2l0aW9uOiB7IHg6IDAsIHk6IDAsIHdpZHRoOiAxMiwgaGVpZ2h0OiAyIH0sXG4gICAgfSxcbiAgICAuLi5pbnB1dC5wbGFuLm1ldHJpY3MubWFwKGNvdW50ZXJXaWRnZXQpLFxuICBdO1xuICBpZiAoZGF0ZUNvbHVtbikge1xuICAgIGxheW91dC5wdXNoKHtcbiAgICAgIHdpZGdldDoge1xuICAgICAgICBuYW1lOiBcIm1ldHJpY190cmVuZFwiLFxuICAgICAgICBxdWVyaWVzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgbmFtZTogXCJtYWluX3F1ZXJ5XCIsXG4gICAgICAgICAgICBxdWVyeToge1xuICAgICAgICAgICAgICBkYXRhc2V0TmFtZTogXCJnZW5lcmF0ZWRfZmFjdHNcIixcbiAgICAgICAgICAgICAgZmllbGRzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgbmFtZTogYGRhaWx5KCR7ZGF0ZUNvbHVtbn0pYCxcbiAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb246IGBEQVRFX1RSVU5DKFwiREFZXCIsIFxcYCR7ZGF0ZUNvbHVtbn1cXGApYCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHsgbmFtZTogbWV0cmljRmllbGQsIGV4cHJlc3Npb246IGBNRUFTVVJFKFxcYCR7bWV0cmljLmxhYmVsfVxcYClgIH0sXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIGRpc2FnZ3JlZ2F0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICBzcGVjOiB7XG4gICAgICAgICAgdmVyc2lvbjogMyxcbiAgICAgICAgICB3aWRnZXRUeXBlOiBcImxpbmVcIixcbiAgICAgICAgICBlbmNvZGluZ3M6IHtcbiAgICAgICAgICAgIHg6IHtcbiAgICAgICAgICAgICAgZmllbGROYW1lOiBgZGFpbHkoJHtkYXRlQ29sdW1ufSlgLFxuICAgICAgICAgICAgICBzY2FsZTogeyB0eXBlOiBcInRlbXBvcmFsXCIgfSxcbiAgICAgICAgICAgICAgZGlzcGxheU5hbWU6IFwiRGF0ZVwiLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHk6IHtcbiAgICAgICAgICAgICAgZmllbGROYW1lOiBtZXRyaWNGaWVsZCxcbiAgICAgICAgICAgICAgc2NhbGU6IHsgdHlwZTogXCJxdWFudGl0YXRpdmVcIiB9LFxuICAgICAgICAgICAgICBkaXNwbGF5TmFtZTogbWV0cmljLmxhYmVsLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGZyYW1lOiB7IHNob3dUaXRsZTogdHJ1ZSwgdGl0bGU6IGAke21ldHJpYy5sYWJlbH0gdHJlbmRgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgcG9zaXRpb246IHsgeDogMCwgeTogY2hhcnRZLCB3aWR0aDogNywgaGVpZ2h0OiA2IH0sXG4gICAgfSk7XG4gIH1cbiAgaWYgKGNhdGVnb3J5Q29sdW1uKSB7XG4gICAgbGF5b3V0LnB1c2goe1xuICAgICAgd2lkZ2V0OiB7XG4gICAgICAgIG5hbWU6IFwibWV0cmljX2J5X2NhdGVnb3J5XCIsXG4gICAgICAgIHF1ZXJpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBuYW1lOiBcIm1haW5fcXVlcnlcIixcbiAgICAgICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgICAgIGRhdGFzZXROYW1lOiBcImdlbmVyYXRlZF9mYWN0c1wiLFxuICAgICAgICAgICAgICBmaWVsZHM6IFtcbiAgICAgICAgICAgICAgICB7IG5hbWU6IGNhdGVnb3J5Q29sdW1uLCBleHByZXNzaW9uOiBgXFxgJHtjYXRlZ29yeUNvbHVtbn1cXGBgIH0sXG4gICAgICAgICAgICAgICAgeyBuYW1lOiBtZXRyaWNGaWVsZCwgZXhwcmVzc2lvbjogYE1FQVNVUkUoXFxgJHttZXRyaWMubGFiZWx9XFxgKWAgfSxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgZGlzYWdncmVnYXRlZDogZmFsc2UsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIHNwZWM6IHtcbiAgICAgICAgICB2ZXJzaW9uOiAzLFxuICAgICAgICAgIHdpZGdldFR5cGU6IFwiYmFyXCIsXG4gICAgICAgICAgZW5jb2RpbmdzOiB7XG4gICAgICAgICAgICB4OiB7XG4gICAgICAgICAgICAgIGZpZWxkTmFtZTogY2F0ZWdvcnlDb2x1bW4sXG4gICAgICAgICAgICAgIHNjYWxlOiB7IHR5cGU6IFwiY2F0ZWdvcmljYWxcIiB9LFxuICAgICAgICAgICAgICBkaXNwbGF5TmFtZTogY2F0ZWdvcnlDb2x1bW4sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeToge1xuICAgICAgICAgICAgICBmaWVsZE5hbWU6IG1ldHJpY0ZpZWxkLFxuICAgICAgICAgICAgICBzY2FsZTogeyB0eXBlOiBcInF1YW50aXRhdGl2ZVwiIH0sXG4gICAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBtZXRyaWMubGFiZWwsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgZnJhbWU6IHsgc2hvd1RpdGxlOiB0cnVlLCB0aXRsZTogYCR7bWV0cmljLmxhYmVsfSBieSAke2NhdGVnb3J5Q29sdW1ufWAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBwb3NpdGlvbjogeyB4OiA3LCB5OiBjaGFydFksIHdpZHRoOiA1LCBoZWlnaHQ6IDYgfSxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gU2VyaWFsaXplZERhc2hib2FyZFNjaGVtYS5wYXJzZSh7XG4gICAgZGF0YXNldHM6IFtcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJnZW5lcmF0ZWRfZmFjdHNcIixcbiAgICAgICAgZGlzcGxheU5hbWU6IGlucHV0LnBsYW4udGFibGUsXG4gICAgICAgIGFzc2V0X25hbWU6IGZ1bGxUYWJsZSxcbiAgICAgICAgY29sdW1uczogaW5wdXQucGxhbi5tZXRyaWNzLm1hcChtZWFzdXJlKSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICBwYWdlczogW1xuICAgICAge1xuICAgICAgICBuYW1lOiBcIm92ZXJ2aWV3XCIsXG4gICAgICAgIGRpc3BsYXlOYW1lOiBcIk92ZXJ2aWV3XCIsXG4gICAgICAgIHBhZ2VUeXBlOiBcIlBBR0VfVFlQRV9DQU5WQVNcIixcbiAgICAgICAgbGF5b3V0VmVyc2lvbjogXCJHUklEX1YxXCIsXG4gICAgICAgIGxheW91dCxcbiAgICAgIH0sXG4gICAgXSxcbiAgICB1aVNldHRpbmdzOiB7XG4gICAgICB0aGVtZToge1xuICAgICAgICBjYW52YXNCYWNrZ3JvdW5kQ29sb3I6IHtcbiAgICAgICAgICBsaWdodDogaW5wdXQuYnJhbmQuY29sb3JzLmJhY2tncm91bmQsXG4gICAgICAgICAgZGFyazogaW5wdXQuYnJhbmQuY29sb3JzLmZvcmVncm91bmQsXG4gICAgICAgIH0sXG4gICAgICAgIHdpZGdldEJhY2tncm91bmRDb2xvcjoge1xuICAgICAgICAgIGxpZ2h0OiBpbnB1dC5icmFuZC5jb2xvcnMuc3VyZmFjZSxcbiAgICAgICAgICBkYXJrOiBpbnB1dC5icmFuZC5jb2xvcnMucHJpbWFyeSxcbiAgICAgICAgfSxcbiAgICAgICAgZm9udENvbG9yOiB7XG4gICAgICAgICAgbGlnaHQ6IGlucHV0LmJyYW5kLmNvbG9ycy5mb3JlZ3JvdW5kLFxuICAgICAgICAgIGRhcms6IGlucHV0LmJyYW5kLmNvbG9ycy5iYWNrZ3JvdW5kLFxuICAgICAgICB9LFxuICAgICAgICBzZWxlY3Rpb25Db2xvcjoge1xuICAgICAgICAgIGxpZ2h0OiBpbnB1dC5icmFuZC5jb2xvcnMucHJpbWFyeSxcbiAgICAgICAgICBkYXJrOiBpbnB1dC5icmFuZC5jb2xvcnMuYWNjZW50LFxuICAgICAgICB9LFxuICAgICAgICB2aXN1YWxpemF0aW9uQ29sb3JzOiBbXG4gICAgICAgICAgaW5wdXQuYnJhbmQuY29sb3JzLnByaW1hcnksXG4gICAgICAgICAgaW5wdXQuYnJhbmQuY29sb3JzLmFjY2VudCxcbiAgICAgICAgICBpbnB1dC5icmFuZC5jb2xvcnMucHJpbWFyeUhvdmVyLFxuICAgICAgICAgIGlucHV0LmJyYW5kLmNvbG9ycy5tdXRlZCxcbiAgICAgICAgXSxcbiAgICAgICAgd2lkZ2V0SGVhZGVyQWxpZ25tZW50OiBcIkxFRlRcIixcbiAgICAgIH0sXG4gICAgICBnZW5pZVNwYWNlOiB7XG4gICAgICAgIGlzRW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgZW5hYmxlbWVudE1vZGU6IFwiQVVUT1wiLFxuICAgICAgfSxcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqIENyZWF0ZSBhbmQgcHVibGlzaCBhIGRhc2hib2FyZCBhcyB0aGUgYWN0aXZlIE9CTyB1c2VyLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUdlbmVyYXRvckRhc2hib2FyZChcbiAgaW5wdXQ6IENyZWF0ZUdlbmVyYXRvckRhc2hib2FyZElucHV0LFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8R2VuZXJhdGVkRGFzaGJvYXJkPiB7XG4gIGNvbnN0IGlkZW50aXR5ID0gYXdhaXQgcmVzb2x2ZUdlbmVyYXRvcklkZW50aXR5KCk7XG4gIGlmIChpZGVudGl0eS5wcmluY2lwYWwgIT09IGlucHV0LmxvY2F0aW9uLnByaW5jaXBhbCkge1xuICAgIHRocm93IG5ldyBFeGVjdXRpb25FcnJvcihcIkRhc2hib2FyZCBwcmluY2lwYWwgZG9lcyBub3QgbWF0Y2ggdGhlIGFjdGl2ZSBPQk8gdXNlclwiKTtcbiAgfVxuICBjb25zdCBsZWdhY3kgPSBpZGVudGl0eS51c2VyQ2xpZW50LnRvTGVnYWN5V29ya3NwYWNlQ2xpZW50KCk7XG4gIGNvbnN0IHBhcmVudFBhdGggPSBgL1dvcmtzcGFjZS9Vc2Vycy8ke2lkZW50aXR5LnByaW5jaXBhbH0vLmRieC10b29scy9nZW5lcmF0b3IvJHtpbnB1dC5sb2NhdGlvbi5zY2hlbWF9YDtcbiAgY29uc3QgY29udGV4dCA9IHNpZ25hbCA/IGRhdGFicmlja3MudG9Db250ZXh0KHNpZ25hbCkgOiB1bmRlZmluZWQ7XG4gIGF3YWl0IGxlZ2FjeS53b3Jrc3BhY2UubWtkaXJzKHsgcGF0aDogcGFyZW50UGF0aCB9LCBjb250ZXh0KTtcbiAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IGxlZ2FjeS5sYWtldmlldy5jcmVhdGUoXG4gICAge1xuICAgICAgZGFzaGJvYXJkOiB7XG4gICAgICAgIGRpc3BsYXlfbmFtZTogYCR7aW5wdXQuY29tcGFueX0gJHtpbnB1dC5wdXJwb3NlfSAke2hhc2guaWQoNil9YCxcbiAgICAgICAgcGFyZW50X3BhdGg6IHBhcmVudFBhdGgsXG4gICAgICAgIHdhcmVob3VzZV9pZDogaW5wdXQud2FyZWhvdXNlSWQsXG4gICAgICAgIHNlcmlhbGl6ZWRfZGFzaGJvYXJkOiBKU09OLnN0cmluZ2lmeShidWlsZEdlbmVyYXRvckRhc2hib2FyZChpbnB1dCkpLFxuICAgICAgfSxcbiAgICB9LFxuICAgIGNvbnRleHQsXG4gICk7XG4gIGlmICghY3JlYXRlZC5kYXNoYm9hcmRfaWQpIHtcbiAgICB0aHJvdyBuZXcgRXhlY3V0aW9uRXJyb3IoXCJMYWtldmlldyBjcmVhdGUgcmV0dXJuZWQgbm8gZGFzaGJvYXJkIGlkXCIpO1xuICB9XG4gIGF3YWl0IGxlZ2FjeS5sYWtldmlldy5wdWJsaXNoKFxuICAgIHtcbiAgICAgIGRhc2hib2FyZF9pZDogY3JlYXRlZC5kYXNoYm9hcmRfaWQsXG4gICAgICB3YXJlaG91c2VfaWQ6IGlucHV0LndhcmVob3VzZUlkLFxuICAgICAgZW1iZWRfY3JlZGVudGlhbHM6IGZhbHNlLFxuICAgIH0sXG4gICAgY29udGV4dCxcbiAgKTtcbiAgcmV0dXJuIEdlbmVyYXRlZERhc2hib2FyZFNjaGVtYS5wYXJzZSh7XG4gICAgZGFzaGJvYXJkSWQ6IGNyZWF0ZWQuZGFzaGJvYXJkX2lkLFxuICAgIC4uLihjcmVhdGVkLnBhdGggPyB7IHBhdGg6IGNyZWF0ZWQucGF0aCB9IDoge30pLFxuICAgIGNvbXBhbmlvbkdlbmllOiBcIkFVVE9cIixcbiAgfSk7XG59XG4iXX0=
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Deterministic Databricks SQL compilation, execution, and validation.
3
+ *
4
+ * @module
5
+ */
6
+ import { type WorkspaceClient } from "@databricks/appkit";
7
+ import type { GeneratedMetric, GeneratedSchema, GeneratorPlan, MaterializedGeneratorData } from "@dbx-tools/shared-generator/workflow";
8
+ type StatementResponse = Awaited<ReturnType<WorkspaceClient["statementExecution"]["getStatement"]>>;
9
+ /** Compile the generated table statement without accepting model-authored SQL. */
10
+ export declare function compileGeneratorTableSql(location: GeneratedSchema, plan: GeneratorPlan): string;
11
+ /** Compile one KPI validation query from its typed aggregate. */
12
+ export declare function compileMetricValidationSql(table: string, metric: GeneratedMetric): string;
13
+ /** Execute one statement and wait for its terminal response. */
14
+ export declare function executeGeneratorStatement(client: WorkspaceClient, warehouseId: string, statement: string, location: Pick<GeneratedSchema, "catalog" | "schema">, signal?: AbortSignal): Promise<StatementResponse>;
15
+ /** Materialize generated data as the OBO user and validate every planned KPI. */
16
+ export declare function materializeGeneratorData(location: GeneratedSchema, plan: GeneratorPlan, warehouseId: string, signal?: AbortSignal): Promise<MaterializedGeneratorData>;
17
+ export {};
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Deterministic Databricks SQL compilation, execution, and validation.
3
+ *
4
+ * @module
5
+ */
6
+ import { ExecutionError } from "@databricks/appkit";
7
+ import { databricks } from "@dbx-tools/appkit";
8
+ import { asyncUtils } from "@dbx-tools/shared-core";
9
+ import { MaterializedGeneratorDataSchema } from "@dbx-tools/shared-generator/workflow";
10
+ import { resolveGeneratorIdentity } from "./namespace.js";
11
+ const TERMINAL_STATEMENT_STATES = new Set(["SUCCEEDED", "FAILED", "CANCELED", "CLOSED"]);
12
+ /** Quote one already-validated SQL identifier. */
13
+ function quoteIdentifier(value) {
14
+ return `\`${value.replaceAll("`", "``")}\``;
15
+ }
16
+ /** Quote one SQL string literal. */
17
+ function quoteLiteral(value) {
18
+ return `'${value.replaceAll("'", "''")}'`;
19
+ }
20
+ /** Compile one safe column generator into a SQL expression. */
21
+ function columnExpression(column) {
22
+ const salt = quoteLiteral(column.name);
23
+ switch (column.generator) {
24
+ case "id":
25
+ return `concat('ID-', lpad(cast(id as string), 8, '0'))`;
26
+ case "date":
27
+ return `date_sub(current_date(), pmod(xxhash64(id, ${salt}), ${column.days}))`;
28
+ case "category": {
29
+ const values = column.values.map(quoteLiteral);
30
+ const fallback = `element_at(array(${values.join(", ")}), pmod(xxhash64(id, ${salt}), ${values.length}) + 1)`;
31
+ return `case when pmod(xxhash64(id, ${salt}), 100) < 55 then ${values[0]} when pmod(xxhash64(id, ${salt}), 100) < 80 then ${values[1]} else ${fallback} end`;
32
+ }
33
+ case "number": {
34
+ const spread = column.maximum - column.minimum;
35
+ return `round((${column.minimum} + (pmod(xxhash64(id, ${salt}), 1000000) / 999999.0) * ${spread}) * case when pmod(xxhash64(id, ${salt}, 'anomaly'), 100) < 8 then 1.65 else 1 end, ${column.decimals})`;
36
+ }
37
+ case "boolean":
38
+ return `pmod(xxhash64(id, ${salt}), 10000) < ${Math.round(column.trueProbability * 10_000)}`;
39
+ default: {
40
+ const exhaustive = column;
41
+ throw new TypeError(`Unsupported generated column: ${String(exhaustive)}`);
42
+ }
43
+ }
44
+ }
45
+ /** Compile the generated table statement without accepting model-authored SQL. */
46
+ export function compileGeneratorTableSql(location, plan) {
47
+ const columns = plan.columns.map((column) => `${columnExpression(column)} AS ${quoteIdentifier(column.name)}`);
48
+ return [
49
+ `CREATE OR REPLACE TABLE ${quoteIdentifier(location.catalog)}.${quoteIdentifier(location.schema)}.${quoteIdentifier(plan.table)}`,
50
+ `COMMENT ${quoteLiteral(plan.story)}`,
51
+ "AS SELECT",
52
+ ` ${columns.join(",\n ")}`,
53
+ `FROM range(${plan.rowCount})`,
54
+ ].join("\n");
55
+ }
56
+ /** Compile one KPI validation query from its typed aggregate. */
57
+ export function compileMetricValidationSql(table, metric) {
58
+ const aggregate = metric.aggregation === "count"
59
+ ? "count(*)"
60
+ : `${metric.aggregation === "sum" ? "sum" : "avg"}(${quoteIdentifier(metric.column)})`;
61
+ return `SELECT ${aggregate} AS ${quoteIdentifier(metric.name)} FROM ${table}`;
62
+ }
63
+ /** Execute one statement and wait for its terminal response. */
64
+ export async function executeGeneratorStatement(client, warehouseId, statement, location, signal) {
65
+ const context = signal ? databricks.toContext(signal) : undefined;
66
+ let response = await client.statementExecution.executeStatement({
67
+ warehouse_id: warehouseId,
68
+ statement,
69
+ catalog: location.catalog,
70
+ schema: location.schema,
71
+ wait_timeout: "50s",
72
+ on_wait_timeout: "CONTINUE",
73
+ }, context);
74
+ if (!TERMINAL_STATEMENT_STATES.has(response.status?.state ?? "")) {
75
+ const statementId = response.statement_id;
76
+ if (!statementId)
77
+ throw new ExecutionError("Statement execution returned no statement id");
78
+ for await (const polled of asyncUtils.poll(({ signal: pollSignal }) => client.statementExecution.getStatement({ statement_id: statementId }, databricks.toContext(pollSignal)), {
79
+ intervalMs: 1_000,
80
+ timeoutMs: 180_000,
81
+ ...(signal ? { signal } : {}),
82
+ predicate: (value) => !TERMINAL_STATEMENT_STATES.has(value.status?.state ?? ""),
83
+ })) {
84
+ response = polled;
85
+ }
86
+ }
87
+ if (response.status?.state !== "SUCCEEDED") {
88
+ throw new ExecutionError(response.status?.error?.message ??
89
+ `Statement ended in ${response.status?.state ?? "UNKNOWN"}`);
90
+ }
91
+ return response;
92
+ }
93
+ /** Materialize generated data as the OBO user and validate every planned KPI. */
94
+ export async function materializeGeneratorData(location, plan, warehouseId, signal) {
95
+ const identity = await resolveGeneratorIdentity();
96
+ if (identity.principal !== location.principal) {
97
+ throw new ExecutionError("Generator schema principal does not match the active OBO user");
98
+ }
99
+ await executeGeneratorStatement(identity.userClient, warehouseId, compileGeneratorTableSql(location, plan), location, signal);
100
+ const fullTable = `${location.catalog}.${location.schema}.${plan.table}`;
101
+ const validationStatements = {};
102
+ for (const metric of plan.metrics) {
103
+ const response = await executeGeneratorStatement(identity.userClient, warehouseId, compileMetricValidationSql(fullTable, metric), location, signal);
104
+ if (!response.statement_id) {
105
+ throw new ExecutionError(`Validation for ${metric.name} returned no statement id`);
106
+ }
107
+ validationStatements[metric.name] = response.statement_id;
108
+ }
109
+ return MaterializedGeneratorDataSchema.parse({
110
+ tables: [fullTable],
111
+ validationStatements,
112
+ });
113
+ }
114
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSCxPQUFPLEVBQUUsY0FBYyxFQUF3QixNQUFNLG9CQUFvQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEQsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFRdkYsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFMUQsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFHekYsa0RBQWtEO0FBQ2xELFNBQVMsZUFBZSxDQUFDLEtBQWE7SUFDcEMsT0FBTyxLQUFLLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUM7QUFDOUMsQ0FBQztBQUVELG9DQUFvQztBQUNwQyxTQUFTLFlBQVksQ0FBQyxLQUFhO0lBQ2pDLE9BQU8sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDO0FBQzVDLENBQUM7QUFFRCwrREFBK0Q7QUFDL0QsU0FBUyxnQkFBZ0IsQ0FBQyxNQUF1QjtJQUMvQyxNQUFNLElBQUksR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZDLFFBQVEsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3pCLEtBQUssSUFBSTtZQUNQLE9BQU8saURBQWlELENBQUM7UUFDM0QsS0FBSyxNQUFNO1lBQ1QsT0FBTyw4Q0FBOEMsSUFBSSxNQUFNLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQztRQUNq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QUMsRUFDN0MsUUFBUSxFQUNSLE1BQU0sQ0FDUCxDQUFDO1FBQ0YsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksY0FBYyxDQUFDLGtCQUFrQixNQUFNLENBQUMsSUFBSSwyQkFBMkIsQ0FBQyxDQUFDO1FBQ3JGLENBQUM7UUFDRCxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQztJQUM1RCxDQUFDO0lBQ0QsT0FBTywrQkFBK0IsQ0FBQyxLQUFLLENBQUM7UUFDM0MsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDO1FBQ25CLG9CQUFvQjtLQUNyQixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZXRlcm1pbmlzdGljIERhdGFicmlja3MgU1FMIGNvbXBpbGF0aW9uLCBleGVjdXRpb24sIGFuZCB2YWxpZGF0aW9uLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBFeGVjdXRpb25FcnJvciwgdHlwZSBXb3Jrc3BhY2VDbGllbnQgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBkYXRhYnJpY2tzIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG5pbXBvcnQgeyBhc3luY1V0aWxzIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IE1hdGVyaWFsaXplZEdlbmVyYXRvckRhdGFTY2hlbWEgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZ2VuZXJhdG9yL3dvcmtmbG93XCI7XG5pbXBvcnQgdHlwZSB7XG4gIEdlbmVyYXRlZENvbHVtbixcbiAgR2VuZXJhdGVkTWV0cmljLFxuICBHZW5lcmF0ZWRTY2hlbWEsXG4gIEdlbmVyYXRvclBsYW4sXG4gIE1hdGVyaWFsaXplZEdlbmVyYXRvckRhdGEsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1nZW5lcmF0b3Ivd29ya2Zsb3dcIjtcbmltcG9ydCB7IHJlc29sdmVHZW5lcmF0b3JJZGVudGl0eSB9IGZyb20gXCIuL25hbWVzcGFjZS50c1wiO1xuXG5jb25zdCBURVJNSU5BTF9TVEFURU1FTlRfU1RBVEVTID0gbmV3IFNldChbXCJTVUNDRUVERURcIiwgXCJGQUlMRURcIiwgXCJDQU5DRUxFRFwiLCBcIkNMT1NFRFwiXSk7XG50eXBlIFN0YXRlbWVudFJlc3BvbnNlID0gQXdhaXRlZDxSZXR1cm5UeXBlPFdvcmtzcGFjZUNsaWVudFtcInN0YXRlbWVudEV4ZWN1dGlvblwiXVtcImdldFN0YXRlbWVudFwiXT4+O1xuXG4vKiogUXVvdGUgb25lIGFscmVhZHktdmFsaWRhdGVkIFNRTCBpZGVudGlmaWVyLiAqL1xuZnVuY3Rpb24gcXVvdGVJZGVudGlmaWVyKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYFxcYCR7dmFsdWUucmVwbGFjZUFsbChcImBcIiwgXCJgYFwiKX1cXGBgO1xufVxuXG4vKiogUXVvdGUgb25lIFNRTCBzdHJpbmcgbGl0ZXJhbC4gKi9cbmZ1bmN0aW9uIHF1b3RlTGl0ZXJhbCh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAnJHt2YWx1ZS5yZXBsYWNlQWxsKFwiJ1wiLCBcIicnXCIpfSdgO1xufVxuXG4vKiogQ29tcGlsZSBvbmUgc2FmZSBjb2x1bW4gZ2VuZXJhdG9yIGludG8gYSBTUUwgZXhwcmVzc2lvbi4gKi9cbmZ1bmN0aW9uIGNvbHVtbkV4cHJlc3Npb24oY29sdW1uOiBHZW5lcmF0ZWRDb2x1bW4pOiBzdHJpbmcge1xuICBjb25zdCBzYWx0ID0gcXVvdGVMaXRlcmFsKGNvbHVtbi5uYW1lKTtcbiAgc3dpdGNoIChjb2x1bW4uZ2VuZXJhdG9yKSB7XG4gICAgY2FzZSBcImlkXCI6XG4gICAgICByZXR1cm4gYGNvbmNhdCgnSUQtJywgbHBhZChjYXN0KGlkIGFzIHN0cmluZyksIDgsICcwJykpYDtcbiAgICBjYXNlIFwiZGF0ZVwiOlxuICAgICAgcmV0dXJuIGBkYXRlX3N1YihjdXJyZW50X2RhdGUoKSwgcG1vZCh4eGhhc2g2NChpZCwgJHtzYWx0fSksICR7Y29sdW1uLmRheXN9KSlgO1xuICAgIGNhc2UgXCJjYXRlZ29yeVwiOiB7XG4gICAgICBjb25zdCB2YWx1ZXMgPSBjb2x1bW4udmFsdWVzLm1hcChxdW90ZUxpdGVyYWwpO1xuICAgICAgY29uc3QgZmFsbGJhY2sgPSBgZWxlbWVudF9hdChhcnJheSgke3ZhbHVlcy5qb2luKFwiLCBcIil9KSwgcG1vZCh4eGhhc2g2NChpZCwgJHtzYWx0fSksICR7dmFsdWVzLmxlbmd0aH0pICsgMSlgO1xuICAgICAgcmV0dXJuIGBjYXNlIHdoZW4gcG1vZCh4eGhhc2g2NChpZCwgJHtzYWx0fSksIDEwMCkgPCA1NSB0aGVuICR7dmFsdWVzWzBdfSB3aGVuIHBtb2QoeHhoYXNoNjQoaWQsICR7c2FsdH0pLCAxMDApIDwgODAgdGhlbiAke3ZhbHVlc1sxXX0gZWxzZSAke2ZhbGxiYWNrfSBlbmRgO1xuICAgIH1cbiAgICBjYXNlIFwibnVtYmVyXCI6IHtcbiAgICAgIGNvbnN0IHNwcmVhZCA9IGNvbHVtbi5tYXhpbXVtIC0gY29sdW1uLm1pbmltdW07XG4gICAgICByZXR1cm4gYHJvdW5kKCgke2NvbHVtbi5taW5pbXVtfSArIChwbW9kKHh4aGFzaDY0KGlkLCAke3NhbHR9KSwgMTAwMDAwMCkgLyA5OTk5OTkuMCkgKiAke3NwcmVhZH0pICogY2FzZSB3aGVuIHBtb2QoeHhoYXNoNjQoaWQsICR7c2FsdH0sICdhbm9tYWx5JyksIDEwMCkgPCA4IHRoZW4gMS42NSBlbHNlIDEgZW5kLCAke2NvbHVtbi5kZWNpbWFsc30pYDtcbiAgICB9XG4gICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICAgIHJldHVybiBgcG1vZCh4eGhhc2g2NChpZCwgJHtzYWx0fSksIDEwMDAwKSA8ICR7TWF0aC5yb3VuZChjb2x1bW4udHJ1ZVByb2JhYmlsaXR5ICogMTBfMDAwKX1gO1xuICAgIGRlZmF1bHQ6IHtcbiAgICAgIGNvbnN0IGV4aGF1c3RpdmU6IG5ldmVyID0gY29sdW1uO1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgVW5zdXBwb3J0ZWQgZ2VuZXJhdGVkIGNvbHVtbjogJHtTdHJpbmcoZXhoYXVzdGl2ZSl9YCk7XG4gICAgfVxuICB9XG59XG5cbi8qKiBDb21waWxlIHRoZSBnZW5lcmF0ZWQgdGFibGUgc3RhdGVtZW50IHdpdGhvdXQgYWNjZXB0aW5nIG1vZGVsLWF1dGhvcmVkIFNRTC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21waWxlR2VuZXJhdG9yVGFibGVTcWwobG9jYXRpb246IEdlbmVyYXRlZFNjaGVtYSwgcGxhbjogR2VuZXJhdG9yUGxhbik6IHN0cmluZyB7XG4gIGNvbnN0IGNvbHVtbnMgPSBwbGFuLmNvbHVtbnMubWFwKFxuICAgIChjb2x1bW4pID0+IGAke2NvbHVtbkV4cHJlc3Npb24oY29sdW1uKX0gQVMgJHtxdW90ZUlkZW50aWZpZXIoY29sdW1uLm5hbWUpfWAsXG4gICk7XG4gIHJldHVybiBbXG4gICAgYENSRUFURSBPUiBSRVBMQUNFIFRBQkxFICR7cXVvdGVJZGVudGlmaWVyKGxvY2F0aW9uLmNhdGFsb2cpfS4ke3F1b3RlSWRlbnRpZmllcihsb2NhdGlvbi5zY2hlbWEpfS4ke3F1b3RlSWRlbnRpZmllcihwbGFuLnRhYmxlKX1gLFxuICAgIGBDT01NRU5UICR7cXVvdGVMaXRlcmFsKHBsYW4uc3RvcnkpfWAsXG4gICAgXCJBUyBTRUxFQ1RcIixcbiAgICBgICAke2NvbHVtbnMuam9pbihcIixcXG4gIFwiKX1gLFxuICAgIGBGUk9NIHJhbmdlKCR7cGxhbi5yb3dDb3VudH0pYCxcbiAgXS5qb2luKFwiXFxuXCIpO1xufVxuXG4vKiogQ29tcGlsZSBvbmUgS1BJIHZhbGlkYXRpb24gcXVlcnkgZnJvbSBpdHMgdHlwZWQgYWdncmVnYXRlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBpbGVNZXRyaWNWYWxpZGF0aW9uU3FsKHRhYmxlOiBzdHJpbmcsIG1ldHJpYzogR2VuZXJhdGVkTWV0cmljKTogc3RyaW5nIHtcbiAgY29uc3QgYWdncmVnYXRlID1cbiAgICBtZXRyaWMuYWdncmVnYXRpb24gPT09IFwiY291bnRcIlxuICAgICAgPyBcImNvdW50KCopXCJcbiAgICAgIDogYCR7bWV0cmljLmFnZ3JlZ2F0aW9uID09PSBcInN1bVwiID8gXCJzdW1cIiA6IFwiYXZnXCJ9KCR7cXVvdGVJZGVudGlmaWVyKG1ldHJpYy5jb2x1bW4hKX0pYDtcbiAgcmV0dXJuIGBTRUxFQ1QgJHthZ2dyZWdhdGV9IEFTICR7cXVvdGVJZGVudGlmaWVyKG1ldHJpYy5uYW1lKX0gRlJPTSAke3RhYmxlfWA7XG59XG5cbi8qKiBFeGVjdXRlIG9uZSBzdGF0ZW1lbnQgYW5kIHdhaXQgZm9yIGl0cyB0ZXJtaW5hbCByZXNwb25zZS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBleGVjdXRlR2VuZXJhdG9yU3RhdGVtZW50KFxuICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCxcbiAgd2FyZWhvdXNlSWQ6IHN0cmluZyxcbiAgc3RhdGVtZW50OiBzdHJpbmcsXG4gIGxvY2F0aW9uOiBQaWNrPEdlbmVyYXRlZFNjaGVtYSwgXCJjYXRhbG9nXCIgfCBcInNjaGVtYVwiPixcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPFN0YXRlbWVudFJlc3BvbnNlPiB7XG4gIGNvbnN0IGNvbnRleHQgPSBzaWduYWwgPyBkYXRhYnJpY2tzLnRvQ29udGV4dChzaWduYWwpIDogdW5kZWZpbmVkO1xuICBsZXQgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQuc3RhdGVtZW50RXhlY3V0aW9uLmV4ZWN1dGVTdGF0ZW1lbnQoXG4gICAge1xuICAgICAgd2FyZWhvdXNlX2lkOiB3YXJlaG91c2VJZCxcbiAgICAgIHN0YXRlbWVudCxcbiAgICAgIGNhdGFsb2c6IGxvY2F0aW9uLmNhdGFsb2csXG4gICAgICBzY2hlbWE6IGxvY2F0aW9uLnNjaGVtYSxcbiAgICAgIHdhaXRfdGltZW91dDogXCI1MHNcIixcbiAgICAgIG9uX3dhaXRfdGltZW91dDogXCJDT05USU5VRVwiLFxuICAgIH0sXG4gICAgY29udGV4dCxcbiAgKTtcbiAgaWYgKCFURVJNSU5BTF9TVEFURU1FTlRfU1RBVEVTLmhhcyhyZXNwb25zZS5zdGF0dXM/LnN0YXRlID8/IFwiXCIpKSB7XG4gICAgY29uc3Qgc3RhdGVtZW50SWQgPSByZXNwb25zZS5zdGF0ZW1lbnRfaWQ7XG4gICAgaWYgKCFzdGF0ZW1lbnRJZCkgdGhyb3cgbmV3IEV4ZWN1dGlvbkVycm9yKFwiU3RhdGVtZW50IGV4ZWN1dGlvbiByZXR1cm5lZCBubyBzdGF0ZW1lbnQgaWRcIik7XG4gICAgZm9yIGF3YWl0IChjb25zdCBwb2xsZWQgb2YgYXN5bmNVdGlscy5wb2xsPFN0YXRlbWVudFJlc3BvbnNlPihcbiAgICAgICh7IHNpZ25hbDogcG9sbFNpZ25hbCB9KSA9PlxuICAgICAgICBjbGllbnQuc3RhdGVtZW50RXhlY3V0aW9uLmdldFN0YXRlbWVudChcbiAgICAgICAgICB7IHN0YXRlbWVudF9pZDogc3RhdGVtZW50SWQgfSxcbiAgICAgICAgICBkYXRhYnJpY2tzLnRvQ29udGV4dChwb2xsU2lnbmFsKSxcbiAgICAgICAgKSxcbiAgICAgIHtcbiAgICAgICAgaW50ZXJ2YWxNczogMV8wMDAsXG4gICAgICAgIHRpbWVvdXRNczogMTgwXzAwMCxcbiAgICAgICAgLi4uKHNpZ25hbCA/IHsgc2lnbmFsIH0gOiB7fSksXG4gICAgICAgIHByZWRpY2F0ZTogKHZhbHVlKSA9PiAhVEVSTUlOQUxfU1RBVEVNRU5UX1NUQVRFUy5oYXModmFsdWUuc3RhdHVzPy5zdGF0ZSA/PyBcIlwiKSxcbiAgICAgIH0sXG4gICAgKSkge1xuICAgICAgcmVzcG9uc2UgPSBwb2xsZWQ7XG4gICAgfVxuICB9XG4gIGlmIChyZXNwb25zZS5zdGF0dXM/LnN0YXRlICE9PSBcIlNVQ0NFRURFRFwiKSB7XG4gICAgdGhyb3cgbmV3IEV4ZWN1dGlvbkVycm9yKFxuICAgICAgcmVzcG9uc2Uuc3RhdHVzPy5lcnJvcj8ubWVzc2FnZSA/P1xuICAgICAgICBgU3RhdGVtZW50IGVuZGVkIGluICR7cmVzcG9uc2Uuc3RhdHVzPy5zdGF0ZSA/PyBcIlVOS05PV05cIn1gLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHJlc3BvbnNlO1xufVxuXG4vKiogTWF0ZXJpYWxpemUgZ2VuZXJhdGVkIGRhdGEgYXMgdGhlIE9CTyB1c2VyIGFuZCB2YWxpZGF0ZSBldmVyeSBwbGFubmVkIEtQSS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBtYXRlcmlhbGl6ZUdlbmVyYXRvckRhdGEoXG4gIGxvY2F0aW9uOiBHZW5lcmF0ZWRTY2hlbWEsXG4gIHBsYW46IEdlbmVyYXRvclBsYW4sXG4gIHdhcmVob3VzZUlkOiBzdHJpbmcsXG4gIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuKTogUHJvbWlzZTxNYXRlcmlhbGl6ZWRHZW5lcmF0b3JEYXRhPiB7XG4gIGNvbnN0IGlkZW50aXR5ID0gYXdhaXQgcmVzb2x2ZUdlbmVyYXRvcklkZW50aXR5KCk7XG4gIGlmIChpZGVudGl0eS5wcmluY2lwYWwgIT09IGxvY2F0aW9uLnByaW5jaXBhbCkge1xuICAgIHRocm93IG5ldyBFeGVjdXRpb25FcnJvcihcIkdlbmVyYXRvciBzY2hlbWEgcHJpbmNpcGFsIGRvZXMgbm90IG1hdGNoIHRoZSBhY3RpdmUgT0JPIHVzZXJcIik7XG4gIH1cbiAgYXdhaXQgZXhlY3V0ZUdlbmVyYXRvclN0YXRlbWVudChcbiAgICBpZGVudGl0eS51c2VyQ2xpZW50LFxuICAgIHdhcmVob3VzZUlkLFxuICAgIGNvbXBpbGVHZW5lcmF0b3JUYWJsZVNxbChsb2NhdGlvbiwgcGxhbiksXG4gICAgbG9jYXRpb24sXG4gICAgc2lnbmFsLFxuICApO1xuICBjb25zdCBmdWxsVGFibGUgPSBgJHtsb2NhdGlvbi5jYXRhbG9nfS4ke2xvY2F0aW9uLnNjaGVtYX0uJHtwbGFuLnRhYmxlfWA7XG4gIGNvbnN0IHZhbGlkYXRpb25TdGF0ZW1lbnRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gIGZvciAoY29uc3QgbWV0cmljIG9mIHBsYW4ubWV0cmljcykge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZXhlY3V0ZUdlbmVyYXRvclN0YXRlbWVudChcbiAgICAgIGlkZW50aXR5LnVzZXJDbGllbnQsXG4gICAgICB3YXJlaG91c2VJZCxcbiAgICAgIGNvbXBpbGVNZXRyaWNWYWxpZGF0aW9uU3FsKGZ1bGxUYWJsZSwgbWV0cmljKSxcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgc2lnbmFsLFxuICAgICk7XG4gICAgaWYgKCFyZXNwb25zZS5zdGF0ZW1lbnRfaWQpIHtcbiAgICAgIHRocm93IG5ldyBFeGVjdXRpb25FcnJvcihgVmFsaWRhdGlvbiBmb3IgJHttZXRyaWMubmFtZX0gcmV0dXJuZWQgbm8gc3RhdGVtZW50IGlkYCk7XG4gICAgfVxuICAgIHZhbGlkYXRpb25TdGF0ZW1lbnRzW21ldHJpYy5uYW1lXSA9IHJlc3BvbnNlLnN0YXRlbWVudF9pZDtcbiAgfVxuICByZXR1cm4gTWF0ZXJpYWxpemVkR2VuZXJhdG9yRGF0YVNjaGVtYS5wYXJzZSh7XG4gICAgdGFibGVzOiBbZnVsbFRhYmxlXSxcbiAgICB2YWxpZGF0aW9uU3RhdGVtZW50cyxcbiAgfSk7XG59XG4iXX0=
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AppKit interceptor settings for researched brand generation.
3
+ *
4
+ * @module
5
+ */
6
+ import { type BrandGenerationRequest } from "./schema.ts";
7
+ /** AppKit execute configuration used by this package. */
8
+ export type BrandExecuteConfig = {
9
+ cache?: {
10
+ enabled?: boolean;
11
+ ttl?: number;
12
+ cacheKey?: (string | number | object)[];
13
+ };
14
+ retry?: {
15
+ enabled?: boolean;
16
+ attempts?: number;
17
+ initialDelay?: number;
18
+ maxDelay?: number;
19
+ };
20
+ timeout?: number;
21
+ };
22
+ /** Execution settings accepted by `Plugin.execute()`. */
23
+ export type BrandExecutionSettings = {
24
+ default: BrandExecuteConfig;
25
+ user?: BrandExecuteConfig;
26
+ };
27
+ /** Cache lifetime for a generated branding package. */
28
+ export declare const BRAND_CACHE_TTL_SECONDS = 21600;
29
+ /** Cache-key version for the generated package shape and asset policy. */
30
+ export declare const BRAND_CACHE_VERSION = 5;
31
+ /** Attempts for the idempotent structured synthesis call. */
32
+ export declare const BRAND_GENERATION_ATTEMPTS = 2;
33
+ /** Build request-specific interceptor settings for brand generation. */
34
+ export declare function brandGenerationSettings(request: BrandGenerationRequest, options: {
35
+ timeoutMs: number;
36
+ model?: string;
37
+ maxSources: number;
38
+ sourceMaxLength: number;
39
+ }): BrandExecutionSettings;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * AppKit interceptor settings for researched brand generation.
3
+ *
4
+ * @module
5
+ */
6
+ import { brandRequestSubject } from "./schema.js";
7
+ /** Cache lifetime for a generated branding package. */
8
+ export const BRAND_CACHE_TTL_SECONDS = 21_600;
9
+ /** Cache-key version for the generated package shape and asset policy. */
10
+ export const BRAND_CACHE_VERSION = 5;
11
+ /** Attempts for the idempotent structured synthesis call. */
12
+ export const BRAND_GENERATION_ATTEMPTS = 2;
13
+ /** Build request-specific interceptor settings for brand generation. */
14
+ export function brandGenerationSettings(request, options) {
15
+ return {
16
+ default: {
17
+ cache: {
18
+ enabled: true,
19
+ ttl: BRAND_CACHE_TTL_SECONDS,
20
+ cacheKey: [
21
+ "brand",
22
+ "generate",
23
+ BRAND_CACHE_VERSION,
24
+ brandRequestSubject(request).toLowerCase(),
25
+ request.website ?? "",
26
+ options.model ?? "",
27
+ options.maxSources,
28
+ options.sourceMaxLength,
29
+ ],
30
+ },
31
+ retry: { enabled: true, attempts: BRAND_GENERATION_ATTEMPTS },
32
+ timeout: options.timeoutMs,
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVmYXVsdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBRSxtQkFBbUIsRUFBK0IsTUFBTSxhQUFhLENBQUM7QUFlL0UsdURBQXVEO0FBQ3ZELE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLE1BQU0sQ0FBQztBQUU5QywwRUFBMEU7QUFDMUUsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBRXJDLDZEQUE2RDtBQUM3RCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLENBQUM7QUFFM0Msd0VBQXdFO0FBQ3hFLE1BQU0sVUFBVSx1QkFBdUIsQ0FDckMsT0FBK0IsRUFDL0IsT0FLQztJQUVELE9BQU87UUFDTCxPQUFPLEVBQUU7WUFDUCxLQUFLLEVBQUU7Z0JBQ0wsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsR0FBRyxFQUFFLHVCQUF1QjtnQkFDNUIsUUFBUSxFQUFFO29CQUNSLE9BQU87b0JBQ1AsVUFBVTtvQkFDVixtQkFBbUI7b0JBQ25CLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDLFdBQVcsRUFBRTtvQkFDMUMsT0FBTyxDQUFDLE9BQU8sSUFBSSxFQUFFO29CQUNyQixPQUFPLENBQUMsS0FBSyxJQUFJLEVBQUU7b0JBQ25CLE9BQU8sQ0FBQyxVQUFVO29CQUNsQixPQUFPLENBQUMsZUFBZTtpQkFDeEI7YUFDRjtZQUNELEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLHlCQUF5QixFQUFFO1lBQzdELE9BQU8sRUFBRSxPQUFPLENBQUMsU0FBUztTQUMzQjtLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBcHBLaXQgaW50ZXJjZXB0b3Igc2V0dGluZ3MgZm9yIHJlc2VhcmNoZWQgYnJhbmQgZ2VuZXJhdGlvbi5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgYnJhbmRSZXF1ZXN0U3ViamVjdCwgdHlwZSBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0IH0gZnJvbSBcIi4vc2NoZW1hLnRzXCI7XG5cbi8qKiBBcHBLaXQgZXhlY3V0ZSBjb25maWd1cmF0aW9uIHVzZWQgYnkgdGhpcyBwYWNrYWdlLiAqL1xuZXhwb3J0IHR5cGUgQnJhbmRFeGVjdXRlQ29uZmlnID0ge1xuICBjYWNoZT86IHsgZW5hYmxlZD86IGJvb2xlYW47IHR0bD86IG51bWJlcjsgY2FjaGVLZXk/OiAoc3RyaW5nIHwgbnVtYmVyIHwgb2JqZWN0KVtdIH07XG4gIHJldHJ5PzogeyBlbmFibGVkPzogYm9vbGVhbjsgYXR0ZW1wdHM/OiBudW1iZXI7IGluaXRpYWxEZWxheT86IG51bWJlcjsgbWF4RGVsYXk/OiBudW1iZXIgfTtcbiAgdGltZW91dD86IG51bWJlcjtcbn07XG5cbi8qKiBFeGVjdXRpb24gc2V0dGluZ3MgYWNjZXB0ZWQgYnkgYFBsdWdpbi5leGVjdXRlKClgLiAqL1xuZXhwb3J0IHR5cGUgQnJhbmRFeGVjdXRpb25TZXR0aW5ncyA9IHtcbiAgZGVmYXVsdDogQnJhbmRFeGVjdXRlQ29uZmlnO1xuICB1c2VyPzogQnJhbmRFeGVjdXRlQ29uZmlnO1xufTtcblxuLyoqIENhY2hlIGxpZmV0aW1lIGZvciBhIGdlbmVyYXRlZCBicmFuZGluZyBwYWNrYWdlLiAqL1xuZXhwb3J0IGNvbnN0IEJSQU5EX0NBQ0hFX1RUTF9TRUNPTkRTID0gMjFfNjAwO1xuXG4vKiogQ2FjaGUta2V5IHZlcnNpb24gZm9yIHRoZSBnZW5lcmF0ZWQgcGFja2FnZSBzaGFwZSBhbmQgYXNzZXQgcG9saWN5LiAqL1xuZXhwb3J0IGNvbnN0IEJSQU5EX0NBQ0hFX1ZFUlNJT04gPSA1O1xuXG4vKiogQXR0ZW1wdHMgZm9yIHRoZSBpZGVtcG90ZW50IHN0cnVjdHVyZWQgc3ludGhlc2lzIGNhbGwuICovXG5leHBvcnQgY29uc3QgQlJBTkRfR0VORVJBVElPTl9BVFRFTVBUUyA9IDI7XG5cbi8qKiBCdWlsZCByZXF1ZXN0LXNwZWNpZmljIGludGVyY2VwdG9yIHNldHRpbmdzIGZvciBicmFuZCBnZW5lcmF0aW9uLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJyYW5kR2VuZXJhdGlvblNldHRpbmdzKFxuICByZXF1ZXN0OiBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0LFxuICBvcHRpb25zOiB7XG4gICAgdGltZW91dE1zOiBudW1iZXI7XG4gICAgbW9kZWw/OiBzdHJpbmc7XG4gICAgbWF4U291cmNlczogbnVtYmVyO1xuICAgIHNvdXJjZU1heExlbmd0aDogbnVtYmVyO1xuICB9LFxuKTogQnJhbmRFeGVjdXRpb25TZXR0aW5ncyB7XG4gIHJldHVybiB7XG4gICAgZGVmYXVsdDoge1xuICAgICAgY2FjaGU6IHtcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgdHRsOiBCUkFORF9DQUNIRV9UVExfU0VDT05EUyxcbiAgICAgICAgY2FjaGVLZXk6IFtcbiAgICAgICAgICBcImJyYW5kXCIsXG4gICAgICAgICAgXCJnZW5lcmF0ZVwiLFxuICAgICAgICAgIEJSQU5EX0NBQ0hFX1ZFUlNJT04sXG4gICAgICAgICAgYnJhbmRSZXF1ZXN0U3ViamVjdChyZXF1ZXN0KS50b0xvd2VyQ2FzZSgpLFxuICAgICAgICAgIHJlcXVlc3Qud2Vic2l0ZSA/PyBcIlwiLFxuICAgICAgICAgIG9wdGlvbnMubW9kZWwgPz8gXCJcIixcbiAgICAgICAgICBvcHRpb25zLm1heFNvdXJjZXMsXG4gICAgICAgICAgb3B0aW9ucy5zb3VyY2VNYXhMZW5ndGgsXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICAgcmV0cnk6IHsgZW5hYmxlZDogdHJ1ZSwgYXR0ZW1wdHM6IEJSQU5EX0dFTkVSQVRJT05fQVRURU1QVFMgfSxcbiAgICAgIHRpbWVvdXQ6IG9wdGlvbnMudGltZW91dE1zLFxuICAgIH0sXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Evidence-backed generation of the portable shared brand context.
3
+ *
4
+ * @module
5
+ */
6
+ import type { WorkspaceClient } from "@databricks/appkit";
7
+ import { type BrandProgressReporter, type BrandResearch, type BrandResearchClient } from "./research.ts";
8
+ import { type BrandGenerationRequest, type BrandPackage, type GeneratedBrandProfile } from "./schema.ts";
9
+ /** Inputs passed to a structured brand-profile synthesizer. */
10
+ export interface BrandSynthesisInput {
11
+ /** Validated brand request. */
12
+ request: BrandGenerationRequest;
13
+ /** Search summary and fetched page evidence. */
14
+ research: BrandResearch;
15
+ /** Optional synthesis-model preference. */
16
+ model?: string;
17
+ /** Explicit workspace client for standalone callers. */
18
+ workspaceClient?: WorkspaceClient;
19
+ }
20
+ /** Replaceable structured synthesis boundary used by tests and custom runtimes. */
21
+ export type BrandSynthesizer = (input: BrandSynthesisInput, signal?: AbortSignal) => Promise<GeneratedBrandProfile>;
22
+ /** Options for one complete brand-generation workflow. */
23
+ export interface GenerateBrandPackageOptions {
24
+ /** Search and fetch operations from the registered web-search plugin. */
25
+ client: BrandResearchClient;
26
+ /** Optional synthesis-model preference. */
27
+ model?: string;
28
+ /** Maximum cited pages fetched per brand. */
29
+ maxSources?: number;
30
+ /** Maximum readable characters retained from each fetched page. */
31
+ sourceMaxLength?: number;
32
+ /** Custom structured synthesizer. Defaults to the AppKit model resolver. */
33
+ synthesize?: BrandSynthesizer;
34
+ /** Receives observable workflow progress. */
35
+ onProgress?: BrandProgressReporter;
36
+ /** Receives fetched research for exporters that persist visual references. */
37
+ onResearch?: (research: BrandResearch) => void | Promise<void>;
38
+ /** Explicit workspace client for standalone model resolution. */
39
+ workspaceClient?: WorkspaceClient;
40
+ }
41
+ /** Instructions applied outside the untrusted page-content prompt. */
42
+ export declare const BRAND_SYNTHESIS_INSTRUCTIONS: string;
43
+ /** Format bounded research evidence as the model's data-only prompt. */
44
+ export declare function brandSynthesisPrompt(input: BrandSynthesisInput): string;
45
+ /** Synthesize the evidence into the required brand-profile contract. */
46
+ export declare function synthesizeBrandProfile(input: BrandSynthesisInput, signal?: AbortSignal): Promise<GeneratedBrandProfile>;
47
+ /**
48
+ * Search and fetch official sources, synthesize a structured profile, and
49
+ * attach deterministic page-discovered artwork as a portable BrandContext.
50
+ */
51
+ export declare function generateBrandPackage(input: BrandGenerationRequest, options: GenerateBrandPackageOptions, signal?: AbortSignal): Promise<BrandPackage>;