blume 1.6.5 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/bin/blume.mjs +3 -2
  3. package/dist/cli/chunk-0qhq7b8q.js +111 -0
  4. package/dist/cli/chunk-0qhq7b8q.js.map +11 -0
  5. package/dist/cli/chunk-18tjv4f7.js +96 -0
  6. package/dist/cli/chunk-18tjv4f7.js.map +10 -0
  7. package/dist/cli/chunk-27gtm2ym.js +69 -0
  8. package/dist/cli/chunk-27gtm2ym.js.map +11 -0
  9. package/dist/cli/chunk-2aj8ddew.js +72 -0
  10. package/dist/cli/chunk-2aj8ddew.js.map +10 -0
  11. package/dist/cli/chunk-3r94j3tc.js +221 -0
  12. package/dist/cli/chunk-3r94j3tc.js.map +10 -0
  13. package/dist/cli/chunk-4trphnvy.js +102 -0
  14. package/dist/cli/chunk-4trphnvy.js.map +11 -0
  15. package/dist/cli/chunk-4xyggvgf.js +21 -0
  16. package/dist/cli/chunk-4xyggvgf.js.map +10 -0
  17. package/dist/cli/chunk-5d4q7121.js +4064 -0
  18. package/dist/cli/chunk-5d4q7121.js.map +40 -0
  19. package/dist/cli/chunk-5hs6gb7n.js +32 -0
  20. package/dist/cli/chunk-5hs6gb7n.js.map +10 -0
  21. package/dist/cli/chunk-6kzzpsx8.js +26 -0
  22. package/dist/cli/chunk-6kzzpsx8.js.map +10 -0
  23. package/dist/cli/chunk-8gnpdsn1.js +952 -0
  24. package/dist/cli/chunk-8gnpdsn1.js.map +12 -0
  25. package/dist/cli/chunk-9qs6acpw.js +176 -0
  26. package/dist/cli/chunk-9qs6acpw.js.map +10 -0
  27. package/dist/cli/chunk-agy5rzxy.js +2453 -0
  28. package/dist/cli/chunk-agy5rzxy.js.map +15 -0
  29. package/dist/cli/chunk-bcy492zc.js +16 -0
  30. package/dist/cli/chunk-bcy492zc.js.map +10 -0
  31. package/dist/cli/chunk-btfr9yvw.js +41 -0
  32. package/dist/cli/chunk-btfr9yvw.js.map +10 -0
  33. package/dist/cli/chunk-cbjnx4s8.js +73 -0
  34. package/dist/cli/chunk-cbjnx4s8.js.map +10 -0
  35. package/dist/cli/chunk-cfw6x4rm.js +1967 -0
  36. package/dist/cli/chunk-cfw6x4rm.js.map +34 -0
  37. package/dist/cli/chunk-ckh3a410.js +277 -0
  38. package/dist/cli/chunk-ckh3a410.js.map +11 -0
  39. package/dist/cli/chunk-drke6t0h.js +259 -0
  40. package/dist/cli/chunk-drke6t0h.js.map +11 -0
  41. package/dist/cli/chunk-ev67ycx0.js +15 -0
  42. package/dist/cli/chunk-ev67ycx0.js.map +10 -0
  43. package/dist/cli/chunk-ey89bjj1.js +209 -0
  44. package/dist/cli/chunk-ey89bjj1.js.map +11 -0
  45. package/dist/cli/chunk-j6pxe0dt.js +69 -0
  46. package/dist/cli/chunk-j6pxe0dt.js.map +11 -0
  47. package/dist/cli/chunk-jk1zwka1.js +387 -0
  48. package/dist/cli/chunk-jk1zwka1.js.map +12 -0
  49. package/dist/cli/chunk-jtb45atp.js +467 -0
  50. package/dist/cli/chunk-jtb45atp.js.map +14 -0
  51. package/dist/cli/chunk-jxkxjsc1.js +76 -0
  52. package/dist/cli/chunk-jxkxjsc1.js.map +10 -0
  53. package/dist/cli/chunk-kwx90v78.js +81 -0
  54. package/dist/cli/chunk-kwx90v78.js.map +10 -0
  55. package/dist/cli/chunk-n0nyat6g.js +30 -0
  56. package/dist/cli/chunk-n0nyat6g.js.map +10 -0
  57. package/dist/cli/chunk-pxj10x8y.js +35 -0
  58. package/dist/cli/chunk-pxj10x8y.js.map +10 -0
  59. package/dist/cli/chunk-qq9nm3qd.js +1141 -0
  60. package/dist/cli/chunk-qq9nm3qd.js.map +19 -0
  61. package/dist/cli/chunk-s102bysw.js +5170 -0
  62. package/dist/cli/chunk-s102bysw.js.map +47 -0
  63. package/dist/cli/chunk-s5dsk8bj.js +769 -0
  64. package/dist/cli/chunk-s5dsk8bj.js.map +13 -0
  65. package/dist/cli/chunk-s5e5jt53.js +227 -0
  66. package/dist/cli/chunk-s5e5jt53.js.map +11 -0
  67. package/dist/cli/chunk-sbdqrjbb.js +81 -0
  68. package/dist/cli/chunk-sbdqrjbb.js.map +10 -0
  69. package/dist/cli/chunk-tnskyrej.js +117 -0
  70. package/dist/cli/chunk-tnskyrej.js.map +10 -0
  71. package/dist/cli/chunk-v2ymm99c.js +1016 -0
  72. package/dist/cli/chunk-v2ymm99c.js.map +13 -0
  73. package/dist/cli/chunk-v5mm027v.js +185 -0
  74. package/dist/cli/chunk-v5mm027v.js.map +11 -0
  75. package/dist/cli/chunk-vt8fgygt.js +23 -0
  76. package/dist/cli/chunk-vt8fgygt.js.map +10 -0
  77. package/dist/cli/chunk-vxv4x1n8.js +17 -0
  78. package/dist/cli/chunk-vxv4x1n8.js.map +10 -0
  79. package/dist/cli/chunk-wd27zjcz.js +60 -0
  80. package/dist/cli/chunk-wd27zjcz.js.map +10 -0
  81. package/dist/cli/chunk-x66c5yjn.js +23 -0
  82. package/dist/cli/chunk-x66c5yjn.js.map +10 -0
  83. package/dist/cli/chunk-xv91q4nm.js +5314 -0
  84. package/dist/cli/chunk-xv91q4nm.js.map +58 -0
  85. package/dist/cli/chunk-y3g15rvv.js +679 -0
  86. package/dist/cli/chunk-y3g15rvv.js.map +15 -0
  87. package/dist/cli/chunk-ye9zdkgv.js +136 -0
  88. package/dist/cli/chunk-ye9zdkgv.js.map +10 -0
  89. package/dist/cli/chunk-ynacq3ev.js +1062 -0
  90. package/dist/cli/chunk-ynacq3ev.js.map +25 -0
  91. package/dist/cli/chunk-zr3ygrq3.js +54 -0
  92. package/dist/cli/chunk-zr3ygrq3.js.map +10 -0
  93. package/dist/cli/index.js +55 -27597
  94. package/dist/cli/index.js.map +5 -243
  95. package/dist/types/ai/ask-context.d.ts +26 -0
  96. package/dist/types/components/layout/nav-utils.d.ts +33 -1
  97. package/dist/types/core/code-fences.d.ts +11 -0
  98. package/dist/types/core/package-root.d.ts +1 -1
  99. package/dist/types/core/schema.d.ts +70 -0
  100. package/dist/types/theme/fonts.d.ts +22 -22
  101. package/docs/02-deployment.mdx +22 -1
  102. package/docs/configuration/ask-ai.mdx +1 -1
  103. package/docs/configuration/customization.mdx +2 -9
  104. package/docs/content/navigation.mdx +2 -0
  105. package/docs/content/syntax.mdx +1 -1
  106. package/docs/discoverability/open-graph.mdx +4 -0
  107. package/docs/reference/cli.mdx +1 -1
  108. package/package.json +4 -2
  109. package/src/ai/api/handlers.ts +4 -7
  110. package/src/ai/api/paths.ts +8 -0
  111. package/src/ai/api/spec.ts +2 -1
  112. package/src/ai/ask-context.ts +378 -22
  113. package/src/astro/generate.ts +161 -28
  114. package/src/astro/include-hmr.ts +10 -13
  115. package/src/astro/include-refresh.ts +0 -0
  116. package/src/astro/index.ts +6 -1
  117. package/src/astro/integration.ts +280 -53
  118. package/src/astro/module-types.ts +83 -0
  119. package/src/astro/templates.ts +256 -108
  120. package/src/audit/image-size.ts +10 -8
  121. package/src/cli/command-meta.ts +77 -0
  122. package/src/cli/commands/add.ts +2 -4
  123. package/src/cli/commands/audit.ts +2 -4
  124. package/src/cli/commands/build.ts +70 -346
  125. package/src/cli/commands/check.ts +2 -4
  126. package/src/cli/commands/dev.ts +31 -42
  127. package/src/cli/commands/doctor.ts +2 -4
  128. package/src/cli/commands/eject.ts +3 -41
  129. package/src/cli/commands/eval.ts +2 -5
  130. package/src/cli/commands/init.ts +2 -4
  131. package/src/cli/commands/mcp-stdio.ts +2 -5
  132. package/src/cli/commands/preview.ts +3 -5
  133. package/src/cli/commands/sync.ts +2 -4
  134. package/src/cli/commands/translate.ts +2 -5
  135. package/src/cli/commands/validate.ts +2 -4
  136. package/src/cli/commands/version.ts +2 -4
  137. package/src/cli/eject-scripts.ts +0 -45
  138. package/src/cli/host-args.ts +16 -0
  139. package/src/cli/index.ts +84 -35
  140. package/src/cli/lazy-command.ts +47 -0
  141. package/src/components/Icon.astro +24 -0
  142. package/src/components/content/GithubInfo.astro +4 -1
  143. package/src/components/icon-sprite-middleware.ts +41 -0
  144. package/src/components/icon-sprite.ts +93 -0
  145. package/src/components/layout/IconSprite.astro +11 -0
  146. package/src/components/layout/NavTree.astro +156 -188
  147. package/src/components/layout/NavTreeCache.astro +45 -0
  148. package/src/components/layout/NavTreeScript.astro +256 -0
  149. package/src/components/layout/PageActions.astro +11 -5
  150. package/src/components/layout/PageLayout.astro +21 -3
  151. package/src/components/layout/ReferenceLayout.astro +21 -4
  152. package/src/components/layout/RootLayout.astro +44 -6
  153. package/src/components/layout/nav-cache.ts +49 -0
  154. package/src/components/layout/nav-utils.ts +69 -1
  155. package/src/components/layout/page-locale.ts +29 -0
  156. package/src/core/api-name.ts +18 -0
  157. package/src/core/code-fences.ts +48 -0
  158. package/src/core/content-assets.ts +3 -7
  159. package/src/core/includes.ts +3 -7
  160. package/src/core/package-root.ts +1 -1
  161. package/src/core/schema.ts +19 -0
  162. package/src/core/sources/normalize.ts +2 -37
  163. package/src/core/sources/obsidian.ts +3 -2
  164. package/src/core/svg-dimensions.ts +97 -0
  165. package/src/core/version-cut.ts +2 -2
  166. package/src/deploy/artifacts.ts +370 -0
  167. package/src/deploy/cloudflare-negotiation.ts +97 -32
  168. package/src/deploy/function-bundle.ts +66 -20
  169. package/src/deploy/sitemap.ts +6 -0
  170. package/src/deploy/vercel-negotiation.ts +8 -30
  171. package/src/markdown/language-icon.ts +64 -20
  172. package/src/markdown/mermaid.ts +11 -0
  173. package/src/og/cache.ts +236 -0
  174. package/src/og/card.ts +18 -16
  175. package/src/og/index.ts +8 -1
  176. package/src/openapi/render-mdx.ts +9 -5
  177. package/src/registry/eject.ts +23 -10
  178. package/src/theme/entry.ts +41 -7
  179. package/src/theme/fonts.ts +30 -23
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/diagnostics.ts
4
+ import { colors } from "consola/utils";
5
+ import { relative } from "pathe";
6
+
7
+ class BlumeError extends Error {
8
+ diagnostic;
9
+ constructor(diagnostic) {
10
+ super(diagnostic.message);
11
+ this.name = "BlumeError";
12
+ this.diagnostic = diagnostic;
13
+ }
14
+ }
15
+ var DOCS_BASE = "https://useblume.dev";
16
+ var DOCS_DEPLOYMENT = "/docs/deployment";
17
+ var DOCS_REFERENCE_CLI = "/docs/reference/cli";
18
+ var DOCS_CONTENT_SOURCES = "/docs/content/sources";
19
+ var DOCS_CONTENT_NAVIGATION = "/docs/content/navigation";
20
+ var DOCS_CONTENT_INCLUDES = "/docs/content/includes";
21
+ var DOCS_PATHS = new Map(Object.entries({
22
+ BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,
23
+ BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,
24
+ BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,
25
+ BLUME_BROKEN_ANCHOR: DOCS_REFERENCE_CLI,
26
+ BLUME_BROKEN_ASSET: DOCS_REFERENCE_CLI,
27
+ BLUME_BROKEN_LINK: DOCS_REFERENCE_CLI,
28
+ BLUME_CONFIG_INVALID: "/docs/configuration",
29
+ BLUME_CONFIG_LOAD_FAILED: "/docs/configuration",
30
+ BLUME_CONTENT_ROOT_MISSING: DOCS_CONTENT_SOURCES,
31
+ BLUME_DEAD_LINK: DOCS_REFERENCE_CLI,
32
+ BLUME_DUPLICATE_ROUTE: DOCS_CONTENT_NAVIGATION,
33
+ BLUME_DUPLICATE_SIDEBAR_ORDER: DOCS_CONTENT_NAVIGATION,
34
+ BLUME_FRONTMATTER_INVALID: "/docs/reference/frontmatter",
35
+ BLUME_INCLUDE_CYCLE: DOCS_CONTENT_INCLUDES,
36
+ BLUME_INCLUDE_NOT_FOUND: DOCS_CONTENT_INCLUDES,
37
+ BLUME_INCLUDE_OUTSIDE_ROOT: DOCS_CONTENT_INCLUDES,
38
+ BLUME_MDX_CURLY_ANCHOR: "/docs/content/syntax",
39
+ BLUME_META_INVALID: "/docs/content/meta",
40
+ BLUME_META_LOAD_FAILED: "/docs/content/meta",
41
+ BLUME_MISSING_SECRET: DOCS_DEPLOYMENT,
42
+ BLUME_NAV_DUPLICATE_LABEL: DOCS_CONTENT_NAVIGATION,
43
+ BLUME_NAV_HIDDEN_IN_SIDEBAR: DOCS_CONTENT_NAVIGATION,
44
+ BLUME_NAV_INDEX_TITLE_MISMATCH: DOCS_CONTENT_NAVIGATION,
45
+ BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,
46
+ BLUME_NODE_VERSION: "/docs/quickstart",
47
+ BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,
48
+ BLUME_SIDEBAR_DISPLAY_IGNORED: DOCS_CONTENT_NAVIGATION,
49
+ BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,
50
+ BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,
51
+ BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,
52
+ BLUME_SOURCE_SDK_MISSING: DOCS_CONTENT_SOURCES,
53
+ BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,
54
+ BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
55
+ BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,
56
+ BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES,
57
+ BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES
58
+ }));
59
+ var resolveDocsUrl = (code) => {
60
+ const path = DOCS_PATHS.get(code);
61
+ return path ? `${DOCS_BASE}${path}` : undefined;
62
+ };
63
+ var enrichDiagnostic = (diagnostic) => diagnostic.docsUrl ? diagnostic : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };
64
+ var REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/gu;
65
+ var escapeRegExp = (value) => value.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
66
+ var isKeySegment = (segment) => typeof segment === "string";
67
+ var stepSegment = (source, segment, cursor) => {
68
+ if (!isKeySegment(segment)) {
69
+ return { index: -1, next: cursor, stop: false };
70
+ }
71
+ const matcher = new RegExp(`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`, "gu");
72
+ matcher.lastIndex = cursor;
73
+ const match = matcher.exec(source);
74
+ if (!match) {
75
+ return { index: -1, next: cursor, stop: true };
76
+ }
77
+ return { index: match.index, next: matcher.lastIndex, stop: false };
78
+ };
79
+ var locatePath = (source, path) => {
80
+ let cursor = 0;
81
+ let found = -1;
82
+ for (const segment of path) {
83
+ const step = stepSegment(source, segment, cursor);
84
+ if (step.stop) {
85
+ break;
86
+ }
87
+ cursor = step.next;
88
+ if (step.index >= 0) {
89
+ found = step.index;
90
+ }
91
+ }
92
+ if (found < 0) {
93
+ return;
94
+ }
95
+ const before = source.slice(0, found);
96
+ const lastNewline = before.lastIndexOf(`
97
+ `);
98
+ return { column: found - lastNewline, line: before.split(`
99
+ `).length };
100
+ };
101
+ var FRONTMATTER = /^---\r?\n(?<body>[\s\S]*?)\r?\n---/u;
102
+ var locateFrontmatterKey = (source, path) => {
103
+ const block = FRONTMATTER.exec(source);
104
+ if (!block) {
105
+ return;
106
+ }
107
+ const position = locatePath(block.groups?.body ?? "", path);
108
+ return position && { column: position.column, line: position.line + 1 };
109
+ };
110
+ var diagnosticsFromIssues = (issues, options) => issues.map((issue) => {
111
+ const schemaPath = issue.path.join(".");
112
+ const position = options.source ? locatePath(options.source, issue.path) : undefined;
113
+ return {
114
+ code: options.code,
115
+ column: position?.column,
116
+ file: options.file,
117
+ line: position?.line,
118
+ message: schemaPath ? `${schemaPath}: ${issue.message}` : issue.message,
119
+ schemaPath: schemaPath || undefined,
120
+ severity: "error"
121
+ };
122
+ });
123
+ var diagnosticsFromZod = (error, options) => diagnosticsFromIssues(error.issues.map((issue) => ({
124
+ message: issue.message,
125
+ path: issue.path.filter((segment) => typeof segment !== "symbol")
126
+ })), options);
127
+ var severityColor = (severity) => {
128
+ if (severity === "error") {
129
+ return colors.red;
130
+ }
131
+ if (severity === "warning") {
132
+ return colors.yellow;
133
+ }
134
+ return colors.blue;
135
+ };
136
+ var formatDiagnostic = (diagnostic, root) => {
137
+ const color = severityColor(diagnostic.severity);
138
+ const lines = [
139
+ `${color(colors.bold(diagnostic.code))} ${diagnostic.message}`
140
+ ];
141
+ if (diagnostic.url) {
142
+ lines.push(` ${colors.dim(`at ${diagnostic.url}`)}`);
143
+ }
144
+ if (diagnostic.file) {
145
+ const location = root ? relative(root, diagnostic.file) : diagnostic.file;
146
+ const column = diagnostic.column === undefined ? "" : `:${diagnostic.column}`;
147
+ const position = diagnostic.line === undefined ? "" : `:${diagnostic.line}${column}`;
148
+ const label = diagnostic.url ? "in" : "at";
149
+ lines.push(` ${colors.dim(`${label} ${location}${position}`)}`);
150
+ }
151
+ if (diagnostic.suggestion) {
152
+ lines.push(` ${colors.cyan(`fix: ${diagnostic.suggestion}`)}`);
153
+ }
154
+ if (diagnostic.docsUrl) {
155
+ lines.push(` ${colors.dim(`docs: ${diagnostic.docsUrl}`)}`);
156
+ }
157
+ return lines.join(`
158
+ `);
159
+ };
160
+ var hasErrors = (diagnostics) => diagnostics.some((d) => d.severity === "error");
161
+ var countBySeverity = (diagnostics) => {
162
+ const counts = { error: 0, info: 0, warning: 0 };
163
+ for (const diagnostic of diagnostics) {
164
+ counts[diagnostic.severity] += 1;
165
+ }
166
+ return counts;
167
+ };
168
+
169
+ // src/cli/log.ts
170
+ import { consola } from "consola";
171
+ import { relative as relative2 } from "pathe";
172
+ var logger = consola.withTag("blume");
173
+ var flushStdout = () => new Promise((resolve) => {
174
+ process.stdout.write("", () => resolve());
175
+ });
176
+ var reportDiagnosticsJson = (diagnostics, root) => {
177
+ const enriched = diagnostics.map((diagnostic) => {
178
+ const withDocs = enrichDiagnostic(diagnostic);
179
+ return withDocs.file && root ? { ...withDocs, file: relative2(root, withDocs.file) } : withDocs;
180
+ });
181
+ process.stdout.write(`${JSON.stringify({ diagnostics: enriched, summary: countBySeverity(diagnostics) }, null, 2)}
182
+ `);
183
+ return hasErrors(diagnostics);
184
+ };
185
+ var reportDiagnostics = (diagnostics, root) => {
186
+ if (diagnostics.length === 0) {
187
+ return false;
188
+ }
189
+ for (const diagnostic of diagnostics) {
190
+ process.stderr.write(`${formatDiagnostic(enrichDiagnostic(diagnostic), root)}
191
+ `);
192
+ }
193
+ const counts = countBySeverity(diagnostics);
194
+ const summary = [
195
+ counts.error ? `${counts.error} error(s)` : null,
196
+ counts.warning ? `${counts.warning} warning(s)` : null
197
+ ].filter(Boolean).join(", ");
198
+ if (summary) {
199
+ process.stderr.write(`
200
+ ${summary}
201
+ `);
202
+ }
203
+ return hasErrors(diagnostics);
204
+ };
205
+
206
+ export { BlumeError, enrichDiagnostic, locateFrontmatterKey, diagnosticsFromIssues, diagnosticsFromZod, hasErrors, countBySeverity, logger, flushStdout, reportDiagnosticsJson, reportDiagnostics };
207
+
208
+ //# debugId=ACFDBD3E8C054D7D64756E2164756E21
209
+ //# sourceMappingURL=chunk-ey89bjj1.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/diagnostics.ts", "../src/cli/log.ts"],
4
+ "sourcesContent": [
5
+ "import { colors } from \"consola/utils\";\nimport { relative } from \"pathe\";\nimport type { ZodError } from \"zod\";\n\nimport type { Diagnostic } from \"./types.ts\";\n\n/** A recoverable error carrying a structured diagnostic. */\nexport class BlumeError extends Error {\n readonly diagnostic: Diagnostic;\n\n constructor(diagnostic: Diagnostic) {\n super(diagnostic.message);\n this.name = \"BlumeError\";\n this.diagnostic = diagnostic;\n }\n}\n\nexport const createDiagnostic = (diagnostic: Diagnostic): Diagnostic =>\n diagnostic;\n\n/** Docs site base; diagnostic help links resolve against it. */\nconst DOCS_BASE = \"https://useblume.dev\";\n\nconst DOCS_DEPLOYMENT = \"/docs/deployment\";\nconst DOCS_REFERENCE_CLI = \"/docs/reference/cli\";\nconst DOCS_CONTENT_SOURCES = \"/docs/content/sources\";\nconst DOCS_CONTENT_NAVIGATION = \"/docs/content/navigation\";\nconst DOCS_CONTENT_INCLUDES = \"/docs/content/includes\";\n\n/** Diagnostic code → the docs page that explains it. */\nconst DOCS_PATHS = new Map(\n Object.entries({\n BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,\n BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,\n BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,\n BLUME_BROKEN_ANCHOR: DOCS_REFERENCE_CLI,\n BLUME_BROKEN_ASSET: DOCS_REFERENCE_CLI,\n BLUME_BROKEN_LINK: DOCS_REFERENCE_CLI,\n BLUME_CONFIG_INVALID: \"/docs/configuration\",\n BLUME_CONFIG_LOAD_FAILED: \"/docs/configuration\",\n BLUME_CONTENT_ROOT_MISSING: DOCS_CONTENT_SOURCES,\n BLUME_DEAD_LINK: DOCS_REFERENCE_CLI,\n BLUME_DUPLICATE_ROUTE: DOCS_CONTENT_NAVIGATION,\n BLUME_DUPLICATE_SIDEBAR_ORDER: DOCS_CONTENT_NAVIGATION,\n BLUME_FRONTMATTER_INVALID: \"/docs/reference/frontmatter\",\n BLUME_INCLUDE_CYCLE: DOCS_CONTENT_INCLUDES,\n BLUME_INCLUDE_NOT_FOUND: DOCS_CONTENT_INCLUDES,\n BLUME_INCLUDE_OUTSIDE_ROOT: DOCS_CONTENT_INCLUDES,\n BLUME_MDX_CURLY_ANCHOR: \"/docs/content/syntax\",\n\n BLUME_META_INVALID: \"/docs/content/meta\",\n BLUME_META_LOAD_FAILED: \"/docs/content/meta\",\n BLUME_MISSING_SECRET: DOCS_DEPLOYMENT,\n BLUME_NAV_DUPLICATE_LABEL: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_HIDDEN_IN_SIDEBAR: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_INDEX_TITLE_MISMATCH: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,\n BLUME_NODE_VERSION: \"/docs/quickstart\",\n BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,\n BLUME_SIDEBAR_DISPLAY_IGNORED: DOCS_CONTENT_NAVIGATION,\n BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_SDK_MISSING: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,\n BLUME_UNKNOWN_COMPONENT: \"/docs/configuration/customization\",\n BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,\n BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES,\n BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES,\n })\n);\n\n/** The docs URL that explains a diagnostic code, if one is mapped. */\nexport const resolveDocsUrl = (code: string): string | undefined => {\n const path = DOCS_PATHS.get(code);\n return path ? `${DOCS_BASE}${path}` : undefined;\n};\n\n/** Fill in `docsUrl` from the code map where a diagnostic doesn't set its own. */\nexport const enrichDiagnostic = (diagnostic: Diagnostic): Diagnostic =>\n diagnostic.docsUrl\n ? diagnostic\n : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };\n\nconst REGEXP_SPECIAL = /[$()*+.?[\\\\\\]^{|}]/gu;\nconst escapeRegExp = (value: string): string =>\n value.replaceAll(REGEXP_SPECIAL, String.raw`\\$&`);\n\n/** A key segment scans the source text; an array index has no key to find. */\nconst isKeySegment = (segment: string | number): segment is string =>\n typeof segment === \"string\";\n\n/**\n * Best-effort source position for a Zod issue path (e.g. `[\"seo\", \"title\"]`) in\n * the raw config / frontmatter text. Narrows key-by-key — finding each string\n * segment as a `key:`/`key =` at or after the previous match — so a nested key\n * lands under its parent. Array indices are skipped. Returns 1-based line/column,\n * or undefined when nothing matches.\n */\nconst stepSegment = (\n source: string,\n segment: string | number,\n cursor: number\n) => {\n // A non-string path segment (array index) is skipped without moving on.\n if (!isKeySegment(segment)) {\n return { index: -1, next: cursor, stop: false };\n }\n // The negative lookbehind keeps a segment like `title` from matching the\n // tail of an unrelated key such as `subtitle:`.\n const matcher = new RegExp(\n `(?<![\\\\w$])${escapeRegExp(segment)}\\\\s*[:=]`,\n \"gu\"\n );\n matcher.lastIndex = cursor;\n const match = matcher.exec(source);\n if (!match) {\n return { index: -1, next: cursor, stop: true };\n }\n return { index: match.index, next: matcher.lastIndex, stop: false };\n};\n\nconst locatePath = (\n source: string,\n path: readonly (string | number)[]\n): { column: number; line: number } | undefined => {\n let cursor = 0;\n let found = -1;\n for (const segment of path) {\n const step = stepSegment(source, segment, cursor);\n if (step.stop) {\n break;\n }\n cursor = step.next;\n if (step.index >= 0) {\n found = step.index;\n }\n }\n if (found < 0) {\n return;\n }\n const before = source.slice(0, found);\n const lastNewline = before.lastIndexOf(\"\\n\");\n return { column: found - lastNewline, line: before.split(\"\\n\").length };\n};\n\n/** The YAML front matter block of a `.md`/`.mdx` source, if it has one. */\nconst FRONTMATTER = /^---\\r?\\n(?<body>[\\s\\S]*?)\\r?\\n---/u;\n\n/**\n * Locate a front matter key in a content file, e.g. `[\"seo\", \"description\"]` in\n * `docs/api.mdx`. Scoped to the front matter block so a `title:` written in the\n * page body can't be mistaken for the front matter key of the same name; returns\n * undefined when the file has no front matter or the key isn't set (a missing\n * key has no line to point at — callers anchor to the file instead).\n */\nexport const locateFrontmatterKey = (\n source: string,\n path: readonly (string | number)[]\n): { column: number; line: number } | undefined => {\n const block = FRONTMATTER.exec(source);\n if (!block) {\n return;\n }\n // `locatePath` reports lines 1-based within the text it was given, and the\n // front matter body starts one line below the opening `---`.\n const position = locatePath(block.groups?.body ?? \"\", path);\n return position && { column: position.column, line: position.line + 1 };\n};\n\n/**\n * Convert generic validation issues (message + path, the shape shared by Zod\n * and Standard Schema issues) into Blume diagnostics, anchored to a file.\n */\nexport const diagnosticsFromIssues = (\n issues: readonly {\n message: string;\n path: readonly (string | number)[];\n }[],\n options: { code: string; file?: string; source?: string }\n): Diagnostic[] =>\n issues.map((issue) => {\n const schemaPath = issue.path.join(\".\");\n const position = options.source\n ? locatePath(options.source, issue.path)\n : undefined;\n return {\n code: options.code,\n column: position?.column,\n file: options.file,\n line: position?.line,\n message: schemaPath ? `${schemaPath}: ${issue.message}` : issue.message,\n schemaPath: schemaPath || undefined,\n severity: \"error\",\n } satisfies Diagnostic;\n });\n\n/** Convert a ZodError into Blume diagnostics, anchored to a file. */\nexport const diagnosticsFromZod = (\n error: ZodError,\n options: { code: string; file?: string; source?: string }\n): Diagnostic[] =>\n diagnosticsFromIssues(\n error.issues.map((issue) => ({\n message: issue.message,\n // Zod 4 paths are PropertyKey[]; a symbol segment has no place in a\n // dotted schema path or a source-position scan.\n path: issue.path.filter(\n (segment): segment is string | number => typeof segment !== \"symbol\"\n ),\n })),\n options\n );\n\nconst severityColor = (severity: Diagnostic[\"severity\"]) => {\n if (severity === \"error\") {\n return colors.red;\n }\n if (severity === \"warning\") {\n return colors.yellow;\n }\n return colors.blue;\n};\n\n/** Format a single diagnostic for terminal output. */\nexport const formatDiagnostic = (\n diagnostic: Diagnostic,\n root?: string\n): string => {\n const color = severityColor(diagnostic.severity);\n const lines: string[] = [\n `${color(colors.bold(diagnostic.code))} ${diagnostic.message}`,\n ];\n\n // An audit finding is about a built URL, and names the source file that fixes\n // it as a second line (\"at /docs/api\" / \"in docs/api.mdx:3:2\"). Everything\n // else is about a file alone, and keeps the original single `at file` line.\n if (diagnostic.url) {\n lines.push(` ${colors.dim(`at ${diagnostic.url}`)}`);\n }\n if (diagnostic.file) {\n const location = root ? relative(root, diagnostic.file) : diagnostic.file;\n const column =\n diagnostic.column === undefined ? \"\" : `:${diagnostic.column}`;\n const position =\n diagnostic.line === undefined ? \"\" : `:${diagnostic.line}${column}`;\n const label = diagnostic.url ? \"in\" : \"at\";\n lines.push(` ${colors.dim(`${label} ${location}${position}`)}`);\n }\n\n if (diagnostic.suggestion) {\n lines.push(` ${colors.cyan(`fix: ${diagnostic.suggestion}`)}`);\n }\n\n if (diagnostic.docsUrl) {\n lines.push(` ${colors.dim(`docs: ${diagnostic.docsUrl}`)}`);\n }\n\n return lines.join(\"\\n\");\n};\n\nexport const hasErrors = (diagnostics: Diagnostic[]): boolean =>\n diagnostics.some((d) => d.severity === \"error\");\n\nexport const countBySeverity = (diagnostics: Diagnostic[]) => {\n const counts = { error: 0, info: 0, warning: 0 } satisfies Record<\n Diagnostic[\"severity\"],\n number\n >;\n for (const diagnostic of diagnostics) {\n counts[diagnostic.severity] += 1;\n }\n return counts;\n};\n",
6
+ "import { consola } from \"consola\";\nimport { relative } from \"pathe\";\n\nimport {\n countBySeverity,\n enrichDiagnostic,\n formatDiagnostic,\n hasErrors,\n} from \"../core/diagnostics.ts\";\nimport type { Diagnostic } from \"../core/types.ts\";\n\nexport const logger = consola.withTag(\"blume\");\n\n/**\n * Resolve once stdout has drained. `process.exit` doesn't flush a piped stdout,\n * so await this before exiting non-zero after writing machine-readable output\n * (e.g. `--json`), otherwise the payload can be truncated in CI.\n */\nexport const flushStdout = (): Promise<void> =>\n // oxlint-disable-next-line promise/avoid-new -- adapt stdout's write callback\n new Promise((resolve) => {\n process.stdout.write(\"\", () => resolve());\n });\n\n/**\n * Print diagnostics as a JSON document on stdout for CI and editors: each is\n * enriched with its `docsUrl` and its `file` made root-relative. Returns whether\n * any were errors, matching {@link reportDiagnostics}.\n */\nexport const reportDiagnosticsJson = (\n diagnostics: Diagnostic[],\n root?: string\n): boolean => {\n const enriched = diagnostics.map((diagnostic) => {\n const withDocs = enrichDiagnostic(diagnostic);\n return withDocs.file && root\n ? { ...withDocs, file: relative(root, withDocs.file) }\n : withDocs;\n });\n process.stdout.write(\n `${JSON.stringify(\n { diagnostics: enriched, summary: countBySeverity(diagnostics) },\n null,\n 2\n )}\\n`\n );\n return hasErrors(diagnostics);\n};\n\n/** Print a batch of diagnostics and return whether any were errors. */\nexport const reportDiagnostics = (\n diagnostics: Diagnostic[],\n root?: string\n): boolean => {\n if (diagnostics.length === 0) {\n return false;\n }\n\n for (const diagnostic of diagnostics) {\n process.stderr.write(\n `${formatDiagnostic(enrichDiagnostic(diagnostic), root)}\\n`\n );\n }\n\n const counts = countBySeverity(diagnostics);\n const summary = [\n counts.error ? `${counts.error} error(s)` : null,\n counts.warning ? `${counts.warning} warning(s)` : null,\n ]\n .filter(Boolean)\n .join(\", \");\n if (summary) {\n process.stderr.write(`\\n${summary}\\n`);\n }\n\n return hasErrors(diagnostics);\n};\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "ACFDBD3E8C054D7D64756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ absoluteUrl
4
+ } from "./chunk-vxv4x1n8.js";
5
+ import {
6
+ resolveReferences
7
+ } from "./chunk-xv91q4nm.js";
8
+ import {
9
+ normalizeBasePath,
10
+ withBasePath
11
+ } from "./chunk-27gtm2ym.js";
12
+
13
+ // src/ai/api/paths.ts
14
+ var OPENAPI_PATH = "/openapi.json";
15
+ var API_BASE = "/api/docs";
16
+ var API_PAGES_PATH = `${API_BASE}/pages.json`;
17
+ var API_PAGE_PATH = `${API_BASE}/pages/{route}.json`;
18
+ var API_NAVIGATION_PATH = `${API_BASE}/navigation.json`;
19
+ var API_SEARCH_PATH = `${API_BASE}/search`;
20
+ var pageParam = (route) => route === "/" ? "index" : route.slice(1);
21
+ var pageJsonPath = (route) => `${API_BASE}/pages/${pageParam(route)}.json`;
22
+
23
+ // src/ai/api-catalog.ts
24
+ var API_CATALOG_PATH = "/.well-known/api-catalog";
25
+ var API_CATALOG_TYPE = "application/linkset+json";
26
+ var HTTP_URL = /^https?:\/\//u;
27
+ var linksetEntries = (config) => {
28
+ const site = config.deployment.site ?? null;
29
+ const deployBase = normalizeBasePath(config.deployment.base);
30
+ const abs = (path) => {
31
+ const based = withBasePath(deployBase, path);
32
+ return site ? absoluteUrl(site, based) : based;
33
+ };
34
+ const entries = [];
35
+ for (const reference of resolveReferences(config)) {
36
+ const docRoute = reference.renderer === "blume" ? withBasePath(reference.basePath, reference.route) : reference.route;
37
+ const entry = {
38
+ anchor: abs(docRoute),
39
+ "service-doc": [{ href: abs(docRoute), type: "text/html" }]
40
+ };
41
+ if (HTTP_URL.test(reference.spec)) {
42
+ entry["service-desc"] = [{ href: reference.spec }];
43
+ }
44
+ entries.push(entry);
45
+ }
46
+ if (config.ai.api) {
47
+ entries.push({
48
+ anchor: abs(API_BASE),
49
+ "service-desc": [{ href: abs(OPENAPI_PATH), type: "application/json" }],
50
+ "service-doc": [{ href: abs("/"), type: "text/html" }]
51
+ });
52
+ }
53
+ if (config.ai.mcp.enabled) {
54
+ entries.push({
55
+ anchor: abs(config.ai.mcp.route),
56
+ "service-desc": [
57
+ { href: abs("/.well-known/mcp.json"), type: "application/json" }
58
+ ],
59
+ "service-doc": [{ href: abs("/"), type: "text/html" }]
60
+ });
61
+ }
62
+ return entries;
63
+ };
64
+ var hasApiCatalog = (config) => linksetEntries(config).length > 0;
65
+
66
+ export { OPENAPI_PATH, API_PAGES_PATH, API_PAGE_PATH, API_NAVIGATION_PATH, API_SEARCH_PATH, pageJsonPath, API_CATALOG_PATH, API_CATALOG_TYPE, hasApiCatalog };
67
+
68
+ //# debugId=41C2FD41D67952F664756E2164756E21
69
+ //# sourceMappingURL=chunk-j6pxe0dt.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ai/api/paths.ts", "../src/ai/api-catalog.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Where the JSON docs API and its OpenAPI description are served. Base-less\n * (like every route Blume emits); callers layer `deployment.base` on top.\n * Under `/api/` alongside the Ask AI endpoint (`/api/ask`) so the namespace a\n * Blume site reserves for live endpoints stays one prefix, and under its own\n * `docs` segment so a search provider's proxy at `/api/search` never collides.\n */\n\nexport const OPENAPI_PATH = \"/openapi.json\";\nexport const API_BASE = \"/api/docs\";\nexport const API_PAGES_PATH = `${API_BASE}/pages.json`;\nexport const API_PAGE_PATH = `${API_BASE}/pages/{route}.json`;\nexport const API_NAVIGATION_PATH = `${API_BASE}/navigation.json`;\nexport const API_SEARCH_PATH = `${API_BASE}/search`;\n\n/** The `pages/{route}.json` path segment for a route (`index` for home). */\nexport const pageParam = (route: string): string =>\n route === \"/\" ? \"index\" : route.slice(1);\n\n/** The base-less served path of a route's per-page JSON document. */\nexport const pageJsonPath = (route: string): string =>\n `${API_BASE}/pages/${pageParam(route)}.json`;\n",
6
+ "import { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport { resolveReferences } from \"../openapi/references.ts\";\nimport { API_BASE, OPENAPI_PATH } from \"./api/paths.ts\";\n\n/**\n * RFC 9727 API catalog: a linkset (RFC 9264) at `/.well-known/api-catalog`\n * enumerating the APIs a publisher offers, so agents can discover them from\n * the domain alone. Blume already knows the site's APIs — the configured\n * OpenAPI/AsyncAPI references and the hosted MCP server — so the catalog is\n * generated, never hand-written: one entry per API, anchored at its docs\n * route (the RFC's own examples anchor on developer-portal pages), with\n * `service-doc` pointing at the rendered reference and `service-desc` at the\n * spec when it lives at a fetchable URL. The site's own JSON docs API is an\n * entry too, described by its generated `/openapi.json`.\n */\n\nexport const API_CATALOG_PATH = \"/.well-known/api-catalog\";\nexport const API_CATALOG_TYPE = \"application/linkset+json\";\n\n/** An RFC 9264 linkset entry, restricted to the relations Blume emits. */\ninterface LinksetEntry {\n anchor: string;\n \"service-desc\"?: { href: string; type?: string }[];\n \"service-doc\"?: { href: string; type: string }[];\n}\n\nconst HTTP_URL = /^https?:\\/\\//u;\n\n/** The catalog's linkset entries; empty when the site publishes no APIs. */\nconst linksetEntries = (config: ResolvedConfig): LinksetEntry[] => {\n const site = config.deployment.site ?? null;\n const deployBase = normalizeBasePath(config.deployment.base);\n const abs = (path: string): string => {\n const based = withBasePath(deployBase, path);\n return site ? absoluteUrl(site, based) : based;\n };\n\n const entries: LinksetEntry[] = [];\n for (const reference of resolveReferences(config)) {\n // Blume-rendered pages mount under `basePath`; Scalar pages stay at the\n // raw route (see `referenceRoutes`).\n const docRoute =\n reference.renderer === \"blume\"\n ? withBasePath(reference.basePath, reference.route)\n : reference.route;\n const entry: LinksetEntry = {\n anchor: abs(docRoute),\n \"service-doc\": [{ href: abs(docRoute), type: \"text/html\" }],\n };\n // A local spec file is parsed into pages, not served, so only a remote\n // spec has a fetchable `service-desc` URL.\n if (HTTP_URL.test(reference.spec)) {\n entry[\"service-desc\"] = [{ href: reference.spec }];\n }\n entries.push(entry);\n }\n\n if (config.ai.api) {\n entries.push({\n anchor: abs(API_BASE),\n \"service-desc\": [{ href: abs(OPENAPI_PATH), type: \"application/json\" }],\n \"service-doc\": [{ href: abs(\"/\"), type: \"text/html\" }],\n });\n }\n\n if (config.ai.mcp.enabled) {\n entries.push({\n anchor: abs(config.ai.mcp.route),\n \"service-desc\": [\n { href: abs(\"/.well-known/mcp.json\"), type: \"application/json\" },\n ],\n \"service-doc\": [{ href: abs(\"/\"), type: \"text/html\" }],\n });\n }\n return entries;\n};\n\n/** Whether the site has anything to catalog — gates every emission surface. */\nexport const hasApiCatalog = (config: ResolvedConfig): boolean =>\n linksetEntries(config).length > 0;\n\n/** The `application/linkset+json` document, or null when there are no APIs. */\nexport const buildApiCatalog = (config: ResolvedConfig): string | null => {\n const linkset = linksetEntries(config);\n if (linkset.length === 0) {\n return null;\n }\n return `${JSON.stringify({ linkset }, null, 2)}\\n`;\n};\n"
7
+ ],
8
+ "mappings": ";;;;;;;;;;;;;AAQO,IAAM,eAAe;AACrB,IAAM,WAAW;AACjB,IAAM,iBAAiB,GAAG;AAC1B,IAAM,gBAAgB,GAAG;AACzB,IAAM,sBAAsB,GAAG;AAC/B,IAAM,kBAAkB,GAAG;AAG3B,IAAM,YAAY,CAAC,UACxB,UAAU,MAAM,UAAU,MAAM,MAAM,CAAC;AAGlC,IAAM,eAAe,CAAC,UAC3B,GAAG,kBAAkB,UAAU,KAAK;;;ACH/B,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAShC,IAAM,WAAW;AAGjB,IAAM,iBAAiB,CAAC,WAA2C;AAAA,EACjE,MAAM,OAAO,OAAO,WAAW,QAAQ;AAAA,EACvC,MAAM,aAAa,kBAAkB,OAAO,WAAW,IAAI;AAAA,EAC3D,MAAM,MAAM,CAAC,SAAyB;AAAA,IACpC,MAAM,QAAQ,aAAa,YAAY,IAAI;AAAA,IAC3C,OAAO,OAAO,YAAY,MAAM,KAAK,IAAI;AAAA;AAAA,EAG3C,MAAM,UAA0B,CAAC;AAAA,EACjC,WAAW,aAAa,kBAAkB,MAAM,GAAG;AAAA,IAGjD,MAAM,WACJ,UAAU,aAAa,UACnB,aAAa,UAAU,UAAU,UAAU,KAAK,IAChD,UAAU;AAAA,IAChB,MAAM,QAAsB;AAAA,MAC1B,QAAQ,IAAI,QAAQ;AAAA,MACpB,eAAe,CAAC,EAAE,MAAM,IAAI,QAAQ,GAAG,MAAM,YAAY,CAAC;AAAA,IAC5D;AAAA,IAGA,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,MACjC,MAAM,kBAAkB,CAAC,EAAE,MAAM,UAAU,KAAK,CAAC;AAAA,IACnD;AAAA,IACA,QAAQ,KAAK,KAAK;AAAA,EACpB;AAAA,EAEA,IAAI,OAAO,GAAG,KAAK;AAAA,IACjB,QAAQ,KAAK;AAAA,MACX,QAAQ,IAAI,QAAQ;AAAA,MACpB,gBAAgB,CAAC,EAAE,MAAM,IAAI,YAAY,GAAG,MAAM,mBAAmB,CAAC;AAAA,MACtE,eAAe,CAAC,EAAE,MAAM,IAAI,GAAG,GAAG,MAAM,YAAY,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,OAAO,GAAG,IAAI,SAAS;AAAA,IACzB,QAAQ,KAAK;AAAA,MACX,QAAQ,IAAI,OAAO,GAAG,IAAI,KAAK;AAAA,MAC/B,gBAAgB;AAAA,QACd,EAAE,MAAM,IAAI,uBAAuB,GAAG,MAAM,mBAAmB;AAAA,MACjE;AAAA,MACA,eAAe,CAAC,EAAE,MAAM,IAAI,GAAG,GAAG,MAAM,YAAY,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,gBAAgB,CAAC,WAC5B,eAAe,MAAM,EAAE,SAAS;",
9
+ "debugId": "41C2FD41D67952F664756E2164756E21",
10
+ "names": []
11
+ }