@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,171 @@
1
+ /**
2
+ * Mastra workflow composing reusable generator operations.
3
+ *
4
+ * @module
5
+ */
6
+ import { BrandPackageSchema } from "@dbx-tools/shared-generator/brand";
7
+ import { KpiResearchResultSchema } from "@dbx-tools/shared-generator/kpi";
8
+ import { GeneratedAssetsSchema, GeneratedSchemaSchema, GeneratorPlanSchema, GeneratorRequestSchema, MaterializedGeneratorDataSchema, } from "@dbx-tools/shared-generator/workflow";
9
+ import { createStep, createWorkflow } from "@mastra/core/workflows";
10
+ import { z } from "zod";
11
+ const ResearchOutputSchema = z
12
+ .object({
13
+ request: GeneratorRequestSchema,
14
+ brand: BrandPackageSchema,
15
+ kpiResearch: KpiResearchResultSchema,
16
+ })
17
+ .strict();
18
+ const PlanOutputSchema = ResearchOutputSchema.extend({
19
+ plan: GeneratorPlanSchema,
20
+ }).strict();
21
+ const ProvisionOutputSchema = PlanOutputSchema.extend({
22
+ location: GeneratedSchemaSchema,
23
+ }).strict();
24
+ const MaterializeOutputSchema = ProvisionOutputSchema.extend({
25
+ materialized: MaterializedGeneratorDataSchema,
26
+ }).strict();
27
+ /** Build one typed workflow over an isolated generator operation owner. */
28
+ export function createGeneratorWorkflow(operations, options = {}) {
29
+ const research = createStep({
30
+ id: "research-brand-and-kpis",
31
+ inputSchema: GeneratorRequestSchema,
32
+ outputSchema: ResearchOutputSchema,
33
+ execute: async ({ inputData, abortSignal, writer }) => {
34
+ await writer?.write({ type: "generator-progress", stage: "research", status: "started" });
35
+ const brandRequest = {
36
+ name: inputData.company,
37
+ ...(inputData.website ? { website: inputData.website } : {}),
38
+ };
39
+ const [brand, kpiResearch] = await Promise.all([
40
+ operations.generateBrand(brandRequest, abortSignal),
41
+ operations.researchKpis({
42
+ company: inputData.company,
43
+ purpose: inputData.purpose,
44
+ queries: inputData.queries,
45
+ }, abortSignal),
46
+ ]);
47
+ return { request: inputData, brand, kpiResearch };
48
+ },
49
+ });
50
+ const plan = createStep({
51
+ id: "plan-demo-data",
52
+ inputSchema: ResearchOutputSchema,
53
+ outputSchema: PlanOutputSchema,
54
+ execute: async ({ inputData, abortSignal, writer }) => {
55
+ await writer?.write({ type: "generator-progress", stage: "plan", status: "started" });
56
+ const generatedPlan = await operations.planData(inputData, abortSignal);
57
+ return { ...inputData, plan: generatedPlan };
58
+ },
59
+ });
60
+ const approval = createStep({
61
+ id: "approve-mutation-plan",
62
+ inputSchema: PlanOutputSchema,
63
+ outputSchema: PlanOutputSchema,
64
+ resumeSchema: z.object({
65
+ approved: z.boolean().describe("Whether the generated mutation plan is approved."),
66
+ }),
67
+ suspendSchema: z.object({
68
+ reason: z.string().describe("Why approval is required."),
69
+ plan: GeneratorPlanSchema,
70
+ }),
71
+ execute: async ({ inputData, resumeData, suspend }) => {
72
+ if (options.approval === false)
73
+ return inputData;
74
+ if (resumeData === undefined) {
75
+ return suspend({
76
+ reason: "Approve schema, data, and presentation creation.",
77
+ plan: inputData.plan,
78
+ });
79
+ }
80
+ if (!resumeData.approved) {
81
+ throw new Error("Generator mutation plan was rejected");
82
+ }
83
+ return inputData;
84
+ },
85
+ });
86
+ const provision = createStep({
87
+ id: "provision-schema",
88
+ inputSchema: PlanOutputSchema,
89
+ outputSchema: ProvisionOutputSchema,
90
+ execute: async ({ inputData, abortSignal, writer }) => {
91
+ await writer?.write({ type: "generator-progress", stage: "schema", status: "started" });
92
+ const location = await operations.provisionSchema({
93
+ request: {
94
+ company: inputData.request.company,
95
+ purpose: inputData.request.purpose,
96
+ },
97
+ }, abortSignal);
98
+ return { ...inputData, location };
99
+ },
100
+ });
101
+ const materialize = createStep({
102
+ id: "materialize-and-validate-data",
103
+ inputSchema: ProvisionOutputSchema,
104
+ outputSchema: MaterializeOutputSchema,
105
+ execute: async ({ inputData, abortSignal, writer }) => {
106
+ await writer?.write({ type: "generator-progress", stage: "data", status: "started" });
107
+ const materialized = await operations.materializeData({
108
+ location: inputData.location,
109
+ plan: inputData.plan,
110
+ }, abortSignal);
111
+ return { ...inputData, materialized };
112
+ },
113
+ });
114
+ const presentation = createStep({
115
+ id: "create-presentation",
116
+ inputSchema: MaterializeOutputSchema,
117
+ outputSchema: GeneratedAssetsSchema,
118
+ execute: async ({ inputData, abortSignal, writer }) => {
119
+ await writer?.write({
120
+ type: "generator-progress",
121
+ stage: "presentation",
122
+ status: "started",
123
+ });
124
+ const presentationInput = {
125
+ request: {
126
+ company: inputData.request.company,
127
+ purpose: inputData.request.purpose,
128
+ },
129
+ location: inputData.location,
130
+ plan: inputData.plan,
131
+ brand: inputData.brand,
132
+ };
133
+ if (inputData.request.presentation === "dashboard") {
134
+ const dashboard = await operations.createDashboard(presentationInput, abortSignal);
135
+ return GeneratedAssetsSchema.parse({
136
+ request: inputData.request,
137
+ schema: inputData.location,
138
+ tables: inputData.materialized.tables,
139
+ brand: inputData.brand,
140
+ kpiResearch: inputData.kpiResearch,
141
+ plan: inputData.plan,
142
+ dashboard,
143
+ });
144
+ }
145
+ const genie = await operations.createGenie(presentationInput, abortSignal);
146
+ return GeneratedAssetsSchema.parse({
147
+ request: inputData.request,
148
+ schema: inputData.location,
149
+ tables: inputData.materialized.tables,
150
+ brand: inputData.brand,
151
+ kpiResearch: inputData.kpiResearch,
152
+ plan: inputData.plan,
153
+ genie,
154
+ });
155
+ },
156
+ });
157
+ return createWorkflow({
158
+ id: "generator-demo-assets",
159
+ inputSchema: GeneratorRequestSchema,
160
+ outputSchema: GeneratedAssetsSchema,
161
+ options: { autoRestartActiveRuns: false },
162
+ })
163
+ .then(research)
164
+ .then(plan)
165
+ .then(approval)
166
+ .then(provision)
167
+ .then(materialize)
168
+ .then(presentation)
169
+ .commit();
170
+ }
171
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2Zsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2Zsb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBRSxrQkFBa0IsRUFBK0IsTUFBTSxtQ0FBbUMsQ0FBQztBQUNwRyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMxRSxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLHFCQUFxQixFQUNyQixtQkFBbUIsRUFDbkIsc0JBQXNCLEVBQ3RCLCtCQUErQixHQUNoQyxNQUFNLHNDQUFzQyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEUsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQXFCeEIsTUFBTSxvQkFBb0IsR0FBRyxDQUFDO0tBQzNCLE1BQU0sQ0FBQztJQUNOLE9BQU8sRUFBRSxzQkFBc0I7SUFDL0IsS0FBSyxFQUFFLGtCQUFrQjtJQUN6QixXQUFXLEVBQUUsdUJBQXVCO0NBQ3JDLENBQUM7S0FDRCxNQUFNLEVBQUUsQ0FBQztBQUVaLE1BQU0sZ0JBQWdCLEdBQUcsb0JBQW9CLENBQUMsTUFBTSxDQUFDO0lBQ25ELElBQUksRUFBRSxtQkFBbUI7Q0FDMUIsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO0FBRVosTUFBTSxxQkFBcUIsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUM7SUFDcEQsUUFBUSxFQUFFLHFCQUFxQjtDQUNoQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7QUFFWixNQUFNLHVCQUF1QixHQUFHLHFCQUFxQixDQUFDLE1BQU0sQ0FBQztJQUMzRCxZQUFZLEVBQUUsK0JBQStCO0NBQzlDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUVaLDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsdUJBQXVCLENBQ3JDLFVBQXVDLEVBQ3ZDLFVBQW9D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USxDQUFDO1NBQ2QsSUFBSSxDQUFDLFNBQVMsQ0FBQztTQUNmLElBQUksQ0FBQyxXQUFXLENBQUM7U0FDakIsSUFBSSxDQUFDLFlBQVksQ0FBQztTQUNsQixNQUFNLEVBQUUsQ0FBQztBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1hc3RyYSB3b3JrZmxvdyBjb21wb3NpbmcgcmV1c2FibGUgZ2VuZXJhdG9yIG9wZXJhdGlvbnMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IEJyYW5kUGFja2FnZVNjaGVtYSwgdHlwZSBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWdlbmVyYXRvci9icmFuZFwiO1xuaW1wb3J0IHsgS3BpUmVzZWFyY2hSZXN1bHRTY2hlbWEgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZ2VuZXJhdG9yL2twaVwiO1xuaW1wb3J0IHtcbiAgR2VuZXJhdGVkQXNzZXRzU2NoZW1hLFxuICBHZW5lcmF0ZWRTY2hlbWFTY2hlbWEsXG4gIEdlbmVyYXRvclBsYW5TY2hlbWEsXG4gIEdlbmVyYXRvclJlcXVlc3RTY2hlbWEsXG4gIE1hdGVyaWFsaXplZEdlbmVyYXRvckRhdGFTY2hlbWEsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1nZW5lcmF0b3Ivd29ya2Zsb3dcIjtcbmltcG9ydCB7IGNyZWF0ZVN0ZXAsIGNyZWF0ZVdvcmtmbG93IH0gZnJvbSBcIkBtYXN0cmEvY29yZS93b3JrZmxvd3NcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgdHlwZSB7IEdlbmVyYXRvck9wZXJhdGlvbnMgfSBmcm9tIFwiLi9vcGVyYXRpb25zLnRzXCI7XG5cbi8qKiBPcGVyYXRpb24gc3VyZmFjZSBjb25zdW1lZCBieSB0aGUgd29ya2Zsb3cgYW5kIGltcGxlbWVudGVkIGJ5IEdlbmVyYXRvck9wZXJhdGlvbnMuICovXG5leHBvcnQgdHlwZSBHZW5lcmF0b3JXb3JrZmxvd09wZXJhdGlvbnMgPSBQaWNrPFxuICBHZW5lcmF0b3JPcGVyYXRpb25zLFxuICB8IFwiZ2VuZXJhdGVCcmFuZFwiXG4gIHwgXCJyZXNlYXJjaEtwaXNcIlxuICB8IFwicGxhbkRhdGFcIlxuICB8IFwicHJvdmlzaW9uU2NoZW1hXCJcbiAgfCBcIm1hdGVyaWFsaXplRGF0YVwiXG4gIHwgXCJjcmVhdGVEYXNoYm9hcmRcIlxuICB8IFwiY3JlYXRlR2VuaWVcIlxuPjtcblxuLyoqIENvbnN0cnVjdGlvbiBvcHRpb25zIGZvciB3b3JrZmxvdyBob3N0cyBhbmQgaXNvbGF0ZWQgdGVzdHMuICovXG5leHBvcnQgaW50ZXJmYWNlIEdlbmVyYXRvcldvcmtmbG93T3B0aW9ucyB7XG4gIC8qKiBTdXNwZW5kIGJlZm9yZSBtdXRhdGlvbnMuIERlZmF1bHRzIHRvIHRydWUuICovXG4gIGFwcHJvdmFsPzogYm9vbGVhbjtcbn1cblxuY29uc3QgUmVzZWFyY2hPdXRwdXRTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHJlcXVlc3Q6IEdlbmVyYXRvclJlcXVlc3RTY2hlbWEsXG4gICAgYnJhbmQ6IEJyYW5kUGFja2FnZVNjaGVtYSxcbiAgICBrcGlSZXNlYXJjaDogS3BpUmVzZWFyY2hSZXN1bHRTY2hlbWEsXG4gIH0pXG4gIC5zdHJpY3QoKTtcblxuY29uc3QgUGxhbk91dHB1dFNjaGVtYSA9IFJlc2VhcmNoT3V0cHV0U2NoZW1hLmV4dGVuZCh7XG4gIHBsYW46IEdlbmVyYXRvclBsYW5TY2hlbWEsXG59KS5zdHJpY3QoKTtcblxuY29uc3QgUHJvdmlzaW9uT3V0cHV0U2NoZW1hID0gUGxhbk91dHB1dFNjaGVtYS5leHRlbmQoe1xuICBsb2NhdGlvbjogR2VuZXJhdGVkU2NoZW1hU2NoZW1hLFxufSkuc3RyaWN0KCk7XG5cbmNvbnN0IE1hdGVyaWFsaXplT3V0cHV0U2NoZW1hID0gUHJvdmlzaW9uT3V0cHV0U2NoZW1hLmV4dGVuZCh7XG4gIG1hdGVyaWFsaXplZDogTWF0ZXJpYWxpemVkR2VuZXJhdG9yRGF0YVNjaGVtYSxcbn0pLnN0cmljdCgpO1xuXG4vKiogQnVpbGQgb25lIHR5cGVkIHdvcmtmbG93IG92ZXIgYW4gaXNvbGF0ZWQgZ2VuZXJhdG9yIG9wZXJhdGlvbiBvd25lci4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVHZW5lcmF0b3JXb3JrZmxvdyhcbiAgb3BlcmF0aW9uczogR2VuZXJhdG9yV29ya2Zsb3dPcGVyYXRpb25zLFxuICBvcHRpb25zOiBHZW5lcmF0b3JXb3JrZmxvd09wdGlvbnMgPSB7fSxcbikge1xuICBjb25zdCByZXNlYXJjaCA9IGNyZWF0ZVN0ZXAoe1xuICAgIGlkOiBcInJlc2VhcmNoLWJyYW5kLWFuZC1rcGlzXCIsXG4gICAgaW5wdXRTY2hlbWE6IEdlbmVyYXRvclJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBSZXNlYXJjaE91dHB1dFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoeyBpbnB1dERhdGEsIGFib3J0U2lnbmFsLCB3cml0ZXIgfSkgPT4ge1xuICAgICAgYXdhaXQgd3JpdGVyPy53cml0ZSh7IHR5cGU6IFwiZ2VuZXJhdG9yLXByb2dyZXNzXCIsIHN0YWdlOiBcInJlc2VhcmNoXCIsIHN0YXR1czogXCJzdGFydGVkXCIgfSk7XG4gICAgICBjb25zdCBicmFuZFJlcXVlc3Q6IEJyYW5kR2VuZXJhdGlvblJlcXVlc3QgPSB7XG4gICAgICAgIG5hbWU6IGlucHV0RGF0YS5jb21wYW55LFxuICAgICAgICAuLi4oaW5wdXREYXRhLndlYnNpdGUgPyB7IHdlYnNpdGU6IGlucHV0RGF0YS53ZWJzaXRlIH0gOiB7fSksXG4gICAgICB9O1xuICAgICAgY29uc3QgW2JyYW5kLCBrcGlSZXNlYXJjaF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIG9wZXJhdGlvbnMuZ2VuZXJhdGVCcmFuZChicmFuZFJlcXVlc3QsIGFib3J0U2lnbmFsKSxcbiAgICAgICAgb3BlcmF0aW9ucy5yZXNlYXJjaEtwaXMoXG4gICAgICAgICAge1xuICAgICAgICAgICAgY29tcGFueTogaW5wdXREYXRhLmNvbXBhbnksXG4gICAgICAgICAgICBwdXJwb3NlOiBpbnB1dERhdGEucHVycG9zZSxcbiAgICAgICAgICAgIHF1ZXJpZXM6IGlucHV0RGF0YS5xdWVyaWVzLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgYWJvcnRTaWduYWwsXG4gICAgICAgICksXG4gICAgICBdKTtcbiAgICAgIHJldHVybiB7IHJlcXVlc3Q6IGlucHV0RGF0YSwgYnJhbmQsIGtwaVJlc2VhcmNoIH07XG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3QgcGxhbiA9IGNyZWF0ZVN0ZXAoe1xuICAgIGlkOiBcInBsYW4tZGVtby1kYXRhXCIsXG4gICAgaW5wdXRTY2hlbWE6IFJlc2VhcmNoT3V0cHV0U2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogUGxhbk91dHB1dFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoeyBpbnB1dERhdGEsIGFib3J0U2lnbmFsLCB3cml0ZXIgfSkgPT4ge1xuICAgICAgYXdhaXQgd3JpdGVyPy53cml0ZSh7IHR5cGU6IFwiZ2VuZXJhdG9yLXByb2dyZXNzXCIsIHN0YWdlOiBcInBsYW5cIiwgc3RhdHVzOiBcInN0YXJ0ZWRcIiB9KTtcbiAgICAgIGNvbnN0IGdlbmVyYXRlZFBsYW4gPSBhd2FpdCBvcGVyYXRpb25zLnBsYW5EYXRhKGlucHV0RGF0YSwgYWJvcnRTaWduYWwpO1xuICAgICAgcmV0dXJuIHsgLi4uaW5wdXREYXRhLCBwbGFuOiBnZW5lcmF0ZWRQbGFuIH07XG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3QgYXBwcm92YWwgPSBjcmVhdGVTdGVwKHtcbiAgICBpZDogXCJhcHByb3ZlLW11dGF0aW9uLXBsYW5cIixcbiAgICBpbnB1dFNjaGVtYTogUGxhbk91dHB1dFNjaGVtYSxcbiAgICBvdXRwdXRTY2hlbWE6IFBsYW5PdXRwdXRTY2hlbWEsXG4gICAgcmVzdW1lU2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBhcHByb3ZlZDogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSBnZW5lcmF0ZWQgbXV0YXRpb24gcGxhbiBpcyBhcHByb3ZlZC5cIiksXG4gICAgfSksXG4gICAgc3VzcGVuZFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgcmVhc29uOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiV2h5IGFwcHJvdmFsIGlzIHJlcXVpcmVkLlwiKSxcbiAgICAgIHBsYW46IEdlbmVyYXRvclBsYW5TY2hlbWEsXG4gICAgfSksXG4gICAgZXhlY3V0ZTogYXN5bmMgKHsgaW5wdXREYXRhLCByZXN1bWVEYXRhLCBzdXNwZW5kIH0pID0+IHtcbiAgICAgIGlmIChvcHRpb25zLmFwcHJvdmFsID09PSBmYWxzZSkgcmV0dXJuIGlucHV0RGF0YTtcbiAgICAgIGlmIChyZXN1bWVEYXRhID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIHN1c3BlbmQoe1xuICAgICAgICAgIHJlYXNvbjogXCJBcHByb3ZlIHNjaGVtYSwgZGF0YSwgYW5kIHByZXNlbnRhdGlvbiBjcmVhdGlvbi5cIixcbiAgICAgICAgICBwbGFuOiBpbnB1dERhdGEucGxhbixcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBpZiAoIXJlc3VtZURhdGEuYXBwcm92ZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiR2VuZXJhdG9yIG11dGF0aW9uIHBsYW4gd2FzIHJlamVjdGVkXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGlucHV0RGF0YTtcbiAgICB9LFxuICB9KTtcblxuICBjb25zdCBwcm92aXNpb24gPSBjcmVhdGVTdGVwKHtcbiAgICBpZDogXCJwcm92aXNpb24tc2NoZW1hXCIsXG4gICAgaW5wdXRTY2hlbWE6IFBsYW5PdXRwdXRTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBQcm92aXNpb25PdXRwdXRTY2hlbWEsXG4gICAgZXhlY3V0ZTogYXN5bmMgKHsgaW5wdXREYXRhLCBhYm9ydFNpZ25hbCwgd3JpdGVyIH0pID0+IHtcbiAgICAgIGF3YWl0IHdyaXRlcj8ud3JpdGUoeyB0eXBlOiBcImdlbmVyYXRvci1wcm9ncmVzc1wiLCBzdGFnZTogXCJzY2hlbWFcIiwgc3RhdHVzOiBcInN0YXJ0ZWRcIiB9KTtcbiAgICAgIGNvbnN0IGxvY2F0aW9uID0gYXdhaXQgb3BlcmF0aW9ucy5wcm92aXNpb25TY2hlbWEoXG4gICAgICAgIHtcbiAgICAgICAgICByZXF1ZXN0OiB7XG4gICAgICAgICAgICBjb21wYW55OiBpbnB1dERhdGEucmVxdWVzdC5jb21wYW55LFxuICAgICAgICAgICAgcHVycG9zZTogaW5wdXREYXRhLnJlcXVlc3QucHVycG9zZSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhYm9ydFNpZ25hbCxcbiAgICAgICk7XG4gICAgICByZXR1cm4geyAuLi5pbnB1dERhdGEsIGxvY2F0aW9uIH07XG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3QgbWF0ZXJpYWxpemUgPSBjcmVhdGVTdGVwKHtcbiAgICBpZDogXCJtYXRlcmlhbGl6ZS1hbmQtdmFsaWRhdGUtZGF0YVwiLFxuICAgIGlucHV0U2NoZW1hOiBQcm92aXNpb25PdXRwdXRTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBNYXRlcmlhbGl6ZU91dHB1dFNjaGVtYSxcbiAgICBleGVjdXRlOiBhc3luYyAoeyBpbnB1dERhdGEsIGFib3J0U2lnbmFsLCB3cml0ZXIgfSkgPT4ge1xuICAgICAgYXdhaXQgd3JpdGVyPy53cml0ZSh7IHR5cGU6IFwiZ2VuZXJhdG9yLXByb2dyZXNzXCIsIHN0YWdlOiBcImRhdGFcIiwgc3RhdHVzOiBcInN0YXJ0ZWRcIiB9KTtcbiAgICAgIGNvbnN0IG1hdGVyaWFsaXplZCA9IGF3YWl0IG9wZXJhdGlvbnMubWF0ZXJpYWxpemVEYXRhKFxuICAgICAgICB7XG4gICAgICAgICAgbG9jYXRpb246IGlucHV0RGF0YS5sb2NhdGlvbixcbiAgICAgICAgICBwbGFuOiBpbnB1dERhdGEucGxhbixcbiAgICAgICAgfSxcbiAgICAgICAgYWJvcnRTaWduYWwsXG4gICAgICApO1xuICAgICAgcmV0dXJuIHsgLi4uaW5wdXREYXRhLCBtYXRlcmlhbGl6ZWQgfTtcbiAgICB9LFxuICB9KTtcblxuICBjb25zdCBwcmVzZW50YXRpb24gPSBjcmVhdGVTdGVwKHtcbiAgICBpZDogXCJjcmVhdGUtcHJlc2VudGF0aW9uXCIsXG4gICAgaW5wdXRTY2hlbWE6IE1hdGVyaWFsaXplT3V0cHV0U2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogR2VuZXJhdGVkQXNzZXRzU2NoZW1hLFxuICAgIGV4ZWN1dGU6IGFzeW5jICh7IGlucHV0RGF0YSwgYWJvcnRTaWduYWwsIHdyaXRlciB9KSA9PiB7XG4gICAgICBhd2FpdCB3cml0ZXI/LndyaXRlKHtcbiAgICAgICAgdHlwZTogXCJnZW5lcmF0b3ItcHJvZ3Jlc3NcIixcbiAgICAgICAgc3RhZ2U6IFwicHJlc2VudGF0aW9uXCIsXG4gICAgICAgIHN0YXR1czogXCJzdGFydGVkXCIsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByZXNlbnRhdGlvbklucHV0ID0ge1xuICAgICAgICByZXF1ZXN0OiB7XG4gICAgICAgICAgY29tcGFueTogaW5wdXREYXRhLnJlcXVlc3QuY29tcGFueSxcbiAgICAgICAgICBwdXJwb3NlOiBpbnB1dERhdGEucmVxdWVzdC5wdXJwb3NlLFxuICAgICAgICB9LFxuICAgICAgICBsb2NhdGlvbjogaW5wdXREYXRhLmxvY2F0aW9uLFxuICAgICAgICBwbGFuOiBpbnB1dERhdGEucGxhbixcbiAgICAgICAgYnJhbmQ6IGlucHV0RGF0YS5icmFuZCxcbiAgICAgIH07XG4gICAgICBpZiAoaW5wdXREYXRhLnJlcXVlc3QucHJlc2VudGF0aW9uID09PSBcImRhc2hib2FyZFwiKSB7XG4gICAgICAgIGNvbnN0IGRhc2hib2FyZCA9IGF3YWl0IG9wZXJhdGlvbnMuY3JlYXRlRGFzaGJvYXJkKHByZXNlbnRhdGlvbklucHV0LCBhYm9ydFNpZ25hbCk7XG4gICAgICAgIHJldHVybiBHZW5lcmF0ZWRBc3NldHNTY2hlbWEucGFyc2Uoe1xuICAgICAgICAgIHJlcXVlc3Q6IGlucHV0RGF0YS5yZXF1ZXN0LFxuICAgICAgICAgIHNjaGVtYTogaW5wdXREYXRhLmxvY2F0aW9uLFxuICAgICAgICAgIHRhYmxlczogaW5wdXREYXRhLm1hdGVyaWFsaXplZC50YWJsZXMsXG4gICAgICAgICAgYnJhbmQ6IGlucHV0RGF0YS5icmFuZCxcbiAgICAgICAgICBrcGlSZXNlYXJjaDogaW5wdXREYXRhLmtwaVJlc2VhcmNoLFxuICAgICAgICAgIHBsYW46IGlucHV0RGF0YS5wbGFuLFxuICAgICAgICAgIGRhc2hib2FyZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBjb25zdCBnZW5pZSA9IGF3YWl0IG9wZXJhdGlvbnMuY3JlYXRlR2VuaWUocHJlc2VudGF0aW9uSW5wdXQsIGFib3J0U2lnbmFsKTtcbiAgICAgIHJldHVybiBHZW5lcmF0ZWRBc3NldHNTY2hlbWEucGFyc2Uoe1xuICAgICAgICByZXF1ZXN0OiBpbnB1dERhdGEucmVxdWVzdCxcbiAgICAgICAgc2NoZW1hOiBpbnB1dERhdGEubG9jYXRpb24sXG4gICAgICAgIHRhYmxlczogaW5wdXREYXRhLm1hdGVyaWFsaXplZC50YWJsZXMsXG4gICAgICAgIGJyYW5kOiBpbnB1dERhdGEuYnJhbmQsXG4gICAgICAgIGtwaVJlc2VhcmNoOiBpbnB1dERhdGEua3BpUmVzZWFyY2gsXG4gICAgICAgIHBsYW46IGlucHV0RGF0YS5wbGFuLFxuICAgICAgICBnZW5pZSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pO1xuXG4gIHJldHVybiBjcmVhdGVXb3JrZmxvdyh7XG4gICAgaWQ6IFwiZ2VuZXJhdG9yLWRlbW8tYXNzZXRzXCIsXG4gICAgaW5wdXRTY2hlbWE6IEdlbmVyYXRvclJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiBHZW5lcmF0ZWRBc3NldHNTY2hlbWEsXG4gICAgb3B0aW9uczogeyBhdXRvUmVzdGFydEFjdGl2ZVJ1bnM6IGZhbHNlIH0sXG4gIH0pXG4gICAgLnRoZW4ocmVzZWFyY2gpXG4gICAgLnRoZW4ocGxhbilcbiAgICAudGhlbihhcHByb3ZhbClcbiAgICAudGhlbihwcm92aXNpb24pXG4gICAgLnRoZW4obWF0ZXJpYWxpemUpXG4gICAgLnRoZW4ocHJlc2VudGF0aW9uKVxuICAgIC5jb21taXQoKTtcbn1cblxuLyoqIEdlbmVyYXRvciB3b3JrZmxvdyB0eXBlLiAqL1xuZXhwb3J0IHR5cGUgR2VuZXJhdG9yV29ya2Zsb3cgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVHZW5lcmF0b3JXb3JrZmxvdz47XG4iXX0=
@@ -0,0 +1 @@
1
+ {"root":["../src/assets.ts","../src/config.ts","../src/dashboard.ts","../src/data.ts","../src/defaults.ts","../src/generate.ts","../src/genie.ts","../src/kpi.ts","../src/namespace.ts","../src/operations.ts","../src/palette.ts","../src/plan.ts","../src/plugin.ts","../src/research.ts","../src/schema.ts","../src/structured.ts","../src/workflow.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,6 +1,220 @@
1
1
  {
2
2
  "name": "@dbx-tools/appkit-generator",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "description": "AppKit tools and Mastra workflows for researched Databricks demo assets",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/reggie-db/dbx-tools.git",
7
+ "directory": "packages/js/node/appkit-generator"
8
+ },
9
+ "scripts": {
10
+ "build": "projen build",
11
+ "compile": "projen compile",
12
+ "default": "projen default",
13
+ "package": "projen package",
14
+ "post-compile": "projen post-compile",
15
+ "pre-compile": "projen pre-compile",
16
+ "prepack": "projen prepack",
17
+ "test": "projen test",
18
+ "watch": "projen watch",
19
+ "projen": "projen"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^24.6.0",
23
+ "typescript": "^5.9.3"
24
+ },
25
+ "dependencies": {
26
+ "@databricks/appkit": "0.81.0",
27
+ "@databricks/sdk-experimental": "^0.17.0",
28
+ "@dbx-tools/appkit": "^0.9.136",
29
+ "@dbx-tools/appkit-mastra": "^0.9.136",
30
+ "@dbx-tools/appkit-web-search": "^0.9.136",
31
+ "@dbx-tools/core": "^0.9.136",
32
+ "@dbx-tools/genie": "^0.9.136",
33
+ "@dbx-tools/shared-core": "^0.9.136",
34
+ "@dbx-tools/shared-generator": "^0.9.136",
35
+ "@dbx-tools/shared-genie": "^0.9.136",
36
+ "@mastra/core": "1.71.0",
37
+ "ai": "^7.0.0",
38
+ "cheerio": "^1.2.0",
39
+ "zod": "4.3.6"
40
+ },
41
+ "main": "./lib/index.js",
42
+ "license": "Apache-2.0",
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "main": "./lib/index.js",
46
+ "types": "./lib/index.d.ts",
47
+ "exports": {
48
+ ".": {
49
+ "types": "./lib/index.d.ts",
50
+ "default": "./lib/index.js"
51
+ },
52
+ "./assets": {
53
+ "types": "./lib/src/assets.d.ts",
54
+ "default": "./lib/src/assets.js"
55
+ },
56
+ "./config": {
57
+ "types": "./lib/src/config.d.ts",
58
+ "default": "./lib/src/config.js"
59
+ },
60
+ "./dashboard": {
61
+ "types": "./lib/src/dashboard.d.ts",
62
+ "default": "./lib/src/dashboard.js"
63
+ },
64
+ "./data": {
65
+ "types": "./lib/src/data.d.ts",
66
+ "default": "./lib/src/data.js"
67
+ },
68
+ "./defaults": {
69
+ "types": "./lib/src/defaults.d.ts",
70
+ "default": "./lib/src/defaults.js"
71
+ },
72
+ "./generate": {
73
+ "types": "./lib/src/generate.d.ts",
74
+ "default": "./lib/src/generate.js"
75
+ },
76
+ "./genie": {
77
+ "types": "./lib/src/genie.d.ts",
78
+ "default": "./lib/src/genie.js"
79
+ },
80
+ "./kpi": {
81
+ "types": "./lib/src/kpi.d.ts",
82
+ "default": "./lib/src/kpi.js"
83
+ },
84
+ "./namespace": {
85
+ "types": "./lib/src/namespace.d.ts",
86
+ "default": "./lib/src/namespace.js"
87
+ },
88
+ "./operations": {
89
+ "types": "./lib/src/operations.d.ts",
90
+ "default": "./lib/src/operations.js"
91
+ },
92
+ "./palette": {
93
+ "types": "./lib/src/palette.d.ts",
94
+ "default": "./lib/src/palette.js"
95
+ },
96
+ "./plan": {
97
+ "types": "./lib/src/plan.d.ts",
98
+ "default": "./lib/src/plan.js"
99
+ },
100
+ "./plugin": {
101
+ "types": "./lib/src/plugin.d.ts",
102
+ "default": "./lib/src/plugin.js"
103
+ },
104
+ "./research": {
105
+ "types": "./lib/src/research.d.ts",
106
+ "default": "./lib/src/research.js"
107
+ },
108
+ "./schema": {
109
+ "types": "./lib/src/schema.d.ts",
110
+ "default": "./lib/src/schema.js"
111
+ },
112
+ "./structured": {
113
+ "types": "./lib/src/structured.d.ts",
114
+ "default": "./lib/src/structured.js"
115
+ },
116
+ "./workflow": {
117
+ "types": "./lib/src/workflow.d.ts",
118
+ "default": "./lib/src/workflow.js"
119
+ },
120
+ "./*": {
121
+ "types": "./lib/src/*/index.d.ts",
122
+ "default": "./lib/src/*/index.js"
123
+ },
124
+ "./package.json": "./package.json"
125
+ }
126
+ },
127
+ "version": "0.9.136",
128
+ "types": "./lib/index.d.ts",
129
+ "dbxToolsConfig": {
130
+ "tags": [
131
+ "node"
132
+ ]
133
+ },
134
+ "type": "module",
135
+ "exports": {
136
+ ".": {
137
+ "types": "./lib/index.d.ts",
138
+ "default": "./lib/index.js"
139
+ },
140
+ "./assets": {
141
+ "types": "./lib/src/assets.d.ts",
142
+ "default": "./lib/src/assets.js"
143
+ },
144
+ "./config": {
145
+ "types": "./lib/src/config.d.ts",
146
+ "default": "./lib/src/config.js"
147
+ },
148
+ "./dashboard": {
149
+ "types": "./lib/src/dashboard.d.ts",
150
+ "default": "./lib/src/dashboard.js"
151
+ },
152
+ "./data": {
153
+ "types": "./lib/src/data.d.ts",
154
+ "default": "./lib/src/data.js"
155
+ },
156
+ "./defaults": {
157
+ "types": "./lib/src/defaults.d.ts",
158
+ "default": "./lib/src/defaults.js"
159
+ },
160
+ "./generate": {
161
+ "types": "./lib/src/generate.d.ts",
162
+ "default": "./lib/src/generate.js"
163
+ },
164
+ "./genie": {
165
+ "types": "./lib/src/genie.d.ts",
166
+ "default": "./lib/src/genie.js"
167
+ },
168
+ "./kpi": {
169
+ "types": "./lib/src/kpi.d.ts",
170
+ "default": "./lib/src/kpi.js"
171
+ },
172
+ "./namespace": {
173
+ "types": "./lib/src/namespace.d.ts",
174
+ "default": "./lib/src/namespace.js"
175
+ },
176
+ "./operations": {
177
+ "types": "./lib/src/operations.d.ts",
178
+ "default": "./lib/src/operations.js"
179
+ },
180
+ "./palette": {
181
+ "types": "./lib/src/palette.d.ts",
182
+ "default": "./lib/src/palette.js"
183
+ },
184
+ "./plan": {
185
+ "types": "./lib/src/plan.d.ts",
186
+ "default": "./lib/src/plan.js"
187
+ },
188
+ "./plugin": {
189
+ "types": "./lib/src/plugin.d.ts",
190
+ "default": "./lib/src/plugin.js"
191
+ },
192
+ "./research": {
193
+ "types": "./lib/src/research.d.ts",
194
+ "default": "./lib/src/research.js"
195
+ },
196
+ "./schema": {
197
+ "types": "./lib/src/schema.d.ts",
198
+ "default": "./lib/src/schema.js"
199
+ },
200
+ "./structured": {
201
+ "types": "./lib/src/structured.d.ts",
202
+ "default": "./lib/src/structured.js"
203
+ },
204
+ "./workflow": {
205
+ "types": "./lib/src/workflow.d.ts",
206
+ "default": "./lib/src/workflow.js"
207
+ },
208
+ "./*": {
209
+ "types": "./lib/src/*/index.d.ts",
210
+ "default": "./lib/src/*/index.js"
211
+ },
212
+ "./package.json": "./package.json"
213
+ },
214
+ "files": [
215
+ "index.ts",
216
+ "src",
217
+ "lib"
218
+ ],
219
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"bunx projen\"."
220
+ }
package/src/assets.ts ADDED
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Deterministic brand-asset discovery from an official page.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import { object } from "@dbx-tools/shared-core";
8
+ import type { BrandAssetSet } from "@dbx-tools/shared-core/brand-utils";
9
+ import { load } from "cheerio";
10
+
11
+ /** Asset references extracted from one official HTML page. */
12
+ export interface DiscoveredBrandAssets {
13
+ /** Theme-aware icon reference. */
14
+ icon: BrandAssetSet;
15
+ /** Theme-aware logo reference. */
16
+ logo: BrandAssetSet;
17
+ /** Browser favicon reference. */
18
+ favicon: string;
19
+ }
20
+
21
+ /** Visual references extracted from an official mobile-store page. */
22
+ export interface DiscoveredMobileAppVisuals {
23
+ /** Store listing application name. */
24
+ appName: string;
25
+ /** App icon and screenshot URLs in page order. */
26
+ imageUrls: string[];
27
+ }
28
+
29
+ /** Normalize a page-relative asset reference to a public HTTPS URL. */
30
+ function assetUrl(value: string | undefined, baseUrl: string): string | undefined {
31
+ if (!value?.trim()) return undefined;
32
+ try {
33
+ const resolved = new URL(value.trim(), baseUrl);
34
+ return resolved.protocol === "https:" ? resolved.toString() : undefined;
35
+ } catch {
36
+ return undefined;
37
+ }
38
+ }
39
+
40
+ /** Add a normalized URL to a candidate list once. */
41
+ function appendCandidate(candidates: string[], value: string | undefined, baseUrl: string): void {
42
+ const resolved = assetUrl(value, baseUrl);
43
+ if (resolved && !candidates.includes(resolved)) candidates.push(resolved);
44
+ }
45
+
46
+ /** Collapse CDN size and format variants of the same mobile artwork. */
47
+ function mobileImageIdentity(value: string): string {
48
+ const url = new URL(value);
49
+ if (/googleusercontent\.com$/i.test(url.hostname)) {
50
+ return `${url.origin}${url.pathname.replace(/=[^/]+$/, "")}`;
51
+ }
52
+ if (/mzstatic\.com$/i.test(url.hostname)) {
53
+ return `${url.origin}${url.pathname.replace(/\/[^/]+$/, "")}`;
54
+ }
55
+ return url.toString();
56
+ }
57
+
58
+ /**
59
+ * Find logo-like URLs nested in JSON-LD organization metadata.
60
+ *
61
+ * JSON-LD permits `logo` and `image` to be a URL, an object with a `url` or
62
+ * `contentUrl`, or an array. The bounded recursive walk accepts those forms
63
+ * without treating unrelated strings elsewhere in the document as assets.
64
+ */
65
+ function jsonLdAssetUrls(value: unknown, depth = 0, assetContext = false): string[] {
66
+ if (depth > 8 || value === null || value === undefined) return [];
67
+ if (typeof value === "string") return assetContext ? [value] : [];
68
+ if (Array.isArray(value)) {
69
+ return value.flatMap((entry) => jsonLdAssetUrls(entry, depth + 1, assetContext));
70
+ }
71
+ if (!object.isRecord(value)) return [];
72
+
73
+ const direct = assetContext
74
+ ? [value.url, value.contentUrl].flatMap((entry) => (typeof entry === "string" ? [entry] : []))
75
+ : [];
76
+ return [
77
+ ...direct,
78
+ ...jsonLdAssetUrls(value.logo, depth + 1, true),
79
+ ...jsonLdAssetUrls(value.image, depth + 1, true),
80
+ ...jsonLdAssetUrls(value["@graph"], depth + 1, false),
81
+ ];
82
+ }
83
+
84
+ /** Collect mobile screenshots and image objects from JSON-LD. */
85
+ function jsonLdMobileImageUrls(value: unknown, depth = 0, imageContext = false): string[] {
86
+ if (depth > 10 || value === null || value === undefined) return [];
87
+ if (typeof value === "string") return imageContext ? [value] : [];
88
+ if (Array.isArray(value)) {
89
+ return value.flatMap((entry) => jsonLdMobileImageUrls(entry, depth + 1, imageContext));
90
+ }
91
+ if (!object.isRecord(value)) return [];
92
+ const direct = imageContext
93
+ ? [value.url, value.contentUrl].flatMap((entry) => (typeof entry === "string" ? [entry] : []))
94
+ : [];
95
+ return [
96
+ ...direct,
97
+ ...jsonLdMobileImageUrls(value.screenshot, depth + 1, true),
98
+ ...jsonLdMobileImageUrls(value.image, depth + 1, true),
99
+ ...jsonLdMobileImageUrls(value.thumbnailUrl, depth + 1, true),
100
+ ...jsonLdMobileImageUrls(value["@graph"], depth + 1, false),
101
+ ];
102
+ }
103
+
104
+ /**
105
+ * Discover icon, logo, and favicon URLs from an official page.
106
+ *
107
+ * The function only returns URLs present in page metadata or markup. When the
108
+ * page omits an icon, it uses the conventional `/favicon.ico` URL on the same
109
+ * origin. The logo falls back to that icon so a generated context never points
110
+ * at the dbx-tools default artwork.
111
+ */
112
+ export function discoverBrandAssets(html: string, pageUrl: string): DiscoveredBrandAssets {
113
+ const $ = load(html);
114
+ const icons: string[] = [];
115
+ const logos: string[] = [];
116
+
117
+ $("link[rel]").each((_index, element) => {
118
+ const rel = ($(element).attr("rel") ?? "").toLowerCase();
119
+ if (rel.split(/\s+/).some((part) => part === "icon" || part === "apple-touch-icon")) {
120
+ appendCandidate(icons, $(element).attr("href"), pageUrl);
121
+ }
122
+ });
123
+
124
+ for (const selector of [
125
+ 'meta[property="og:image"]',
126
+ 'meta[property="og:logo"]',
127
+ 'meta[name="twitter:image"]',
128
+ ]) {
129
+ $(selector).each((_index, element) => {
130
+ appendCandidate(logos, $(element).attr("content"), pageUrl);
131
+ });
132
+ }
133
+
134
+ $("img").each((_index, element) => {
135
+ const descriptor = [
136
+ $(element).attr("alt"),
137
+ $(element).attr("class"),
138
+ $(element).attr("id"),
139
+ $(element).attr("data-testid"),
140
+ ]
141
+ .filter(Boolean)
142
+ .join(" ");
143
+ if (/\b(?:brand|logo|wordmark)\b/i.test(descriptor)) {
144
+ appendCandidate(logos, $(element).attr("src"), pageUrl);
145
+ }
146
+ });
147
+
148
+ $('script[type="application/ld+json"]').each((_index, element) => {
149
+ try {
150
+ const value: unknown = JSON.parse($(element).text());
151
+ for (const candidate of jsonLdAssetUrls(value)) {
152
+ appendCandidate(logos, candidate, pageUrl);
153
+ }
154
+ } catch {
155
+ return;
156
+ }
157
+ });
158
+
159
+ const fallbackIcon = new URL("/favicon.ico", pageUrl).toString();
160
+ const icon = icons[0] ?? logos[0] ?? fallbackIcon;
161
+ const logo = logos[0] ?? icons[0] ?? fallbackIcon;
162
+ return {
163
+ icon: { light: icon },
164
+ logo: { light: logo },
165
+ favicon: icon,
166
+ };
167
+ }
168
+
169
+ /** Extract an app name plus representative screenshots/icons from a store page. */
170
+ export function discoverMobileAppVisuals(
171
+ html: string,
172
+ pageUrl: string,
173
+ ): DiscoveredMobileAppVisuals {
174
+ const $ = load(html);
175
+ const metadataImages: string[] = [];
176
+ const structuredImages: string[] = [];
177
+ const screenshotImages: string[] = [];
178
+ const iconImages: string[] = [];
179
+ const otherStoreImages: string[] = [];
180
+ for (const selector of ['meta[property="og:image"]', 'meta[name="twitter:image"]']) {
181
+ $(selector).each((_index, element) => {
182
+ appendCandidate(metadataImages, $(element).attr("content"), pageUrl);
183
+ });
184
+ }
185
+ $('script[type="application/ld+json"]').each((_index, element) => {
186
+ try {
187
+ const value: unknown = JSON.parse($(element).text());
188
+ for (const candidate of jsonLdMobileImageUrls(value)) {
189
+ appendCandidate(structuredImages, candidate, pageUrl);
190
+ }
191
+ } catch {
192
+ return;
193
+ }
194
+ });
195
+ $("img").each((_index, element) => {
196
+ const descriptor = [
197
+ $(element).attr("alt"),
198
+ $(element).attr("class"),
199
+ $(element).attr("aria-label"),
200
+ ]
201
+ .filter(Boolean)
202
+ .join(" ");
203
+ const source = $(element).attr("src") ?? $(element).attr("data-src");
204
+ const isStoreImageHost = /(?:mzstatic|ggpht|googleusercontent)\./i.test(source ?? "");
205
+ const target = /\b(?:phone|screen|screenshot|tablet)\b/i.test(descriptor)
206
+ ? screenshotImages
207
+ : /\b(?:app|icon)\b/i.test(descriptor)
208
+ ? iconImages
209
+ : isStoreImageHost
210
+ ? otherStoreImages
211
+ : undefined;
212
+ if (target) {
213
+ appendCandidate(target, source, pageUrl);
214
+ const srcset = ($(element).attr("srcset") ?? $(element).attr("data-srcset"))
215
+ ?.split(",")
216
+ .at(-1)
217
+ ?.trim()
218
+ .split(/\s+/)[0];
219
+ appendCandidate(target, srcset, pageUrl);
220
+ }
221
+ });
222
+ $("picture source[srcset]").each((_index, element) => {
223
+ const srcset = $(element).attr("srcset")?.split(",").at(-1)?.trim().split(/\s+/)[0];
224
+ appendCandidate(screenshotImages, srcset, pageUrl);
225
+ });
226
+ const images: string[] = [];
227
+ const seenImages = new Set<string>();
228
+ for (const candidate of [
229
+ ...metadataImages.slice(0, 1),
230
+ ...screenshotImages,
231
+ ...iconImages,
232
+ ...structuredImages,
233
+ ...otherStoreImages,
234
+ ]) {
235
+ const resolved = assetUrl(candidate, pageUrl);
236
+ if (!resolved) continue;
237
+ const identity = mobileImageIdentity(resolved);
238
+ if (seenImages.has(identity)) continue;
239
+ seenImages.add(identity);
240
+ images.push(resolved);
241
+ }
242
+ const rawName =
243
+ $('meta[property="og:title"]').attr("content") ?? $("h1").first().text() ?? $("title").text();
244
+ const appName =
245
+ rawName.replace(/\s+(?:on the App Store|- Apps on Google Play).*$/i, "").trim() ||
246
+ new URL(pageUrl).hostname;
247
+ return { appName, imageUrls: images.slice(0, 6) };
248
+ }