blume 0.6.7 → 0.8.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 (211) hide show
  1. package/CHANGELOG.md +618 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/cli/index.js +2609 -1041
  5. package/dist/cli/index.js.map +110 -103
  6. package/dist/types/ai/component-markdown.d.ts +34 -0
  7. package/dist/types/components/content/youtube.d.ts +18 -0
  8. package/dist/types/core/base-path.d.ts +47 -0
  9. package/dist/types/core/config-input.d.ts +110 -12
  10. package/dist/types/core/config.d.ts +6 -4
  11. package/dist/types/core/data.d.ts +4 -0
  12. package/dist/types/core/i18n-ui.d.ts +477 -135
  13. package/dist/types/core/schema.d.ts +309 -195
  14. package/dist/types/core/sources/types.d.ts +2 -0
  15. package/dist/types/core/types.d.ts +6 -1
  16. package/dist/types/index.d.ts +1 -0
  17. package/dist/types/openapi/references.d.ts +60 -0
  18. package/docs/01-quickstart.mdx +5 -2
  19. package/docs/02-deployment.mdx +24 -9
  20. package/docs/03-faq.mdx +46 -16
  21. package/docs/advanced/custom-pages.mdx +1 -1
  22. package/docs/advanced/skills.mdx +1 -1
  23. package/docs/configuration/ai.mdx +49 -10
  24. package/docs/configuration/customization.mdx +11 -0
  25. package/docs/configuration/index.mdx +33 -3
  26. package/docs/configuration/seo.mdx +2 -2
  27. package/docs/content/components.mdx +30 -3
  28. package/docs/content/i18n.mdx +1 -1
  29. package/docs/content/islands.mdx +8 -0
  30. package/docs/content/navigation.mdx +3 -3
  31. package/docs/content/sources.mdx +1 -1
  32. package/docs/content/syntax.mdx +17 -2
  33. package/docs/index.mdx +2 -2
  34. package/docs/reference/cli.mdx +8 -6
  35. package/package.json +15 -4
  36. package/skills/blume/SKILL.md +5 -3
  37. package/skills/blume-update-docs/SKILL.md +3 -2
  38. package/src/ai/agent-readability.ts +11 -5
  39. package/src/ai/ask-context.ts +7 -2
  40. package/src/ai/ask-data.ts +3 -0
  41. package/src/ai/ask.ts +12 -7
  42. package/src/ai/component-markdown.ts +461 -0
  43. package/src/ai/llms.ts +143 -23
  44. package/src/ai/markdown.ts +35 -6
  45. package/src/ai/mcp/data.ts +33 -8
  46. package/src/ai/mcp/discovery.ts +10 -3
  47. package/src/ai/mcp/server.ts +24 -7
  48. package/src/ai/visibility.ts +74 -0
  49. package/src/astro/component-slots.ts +16 -4
  50. package/src/astro/examples.ts +12 -7
  51. package/src/astro/generate.ts +393 -189
  52. package/src/astro/index.ts +5 -1
  53. package/src/astro/integration.ts +9 -5
  54. package/src/astro/islands.ts +11 -5
  55. package/src/astro/markdown-negotiation.ts +2 -2
  56. package/src/astro/pages.ts +89 -22
  57. package/src/astro/templates.ts +259 -25
  58. package/src/blume-modules.d.ts +8 -0
  59. package/src/cli/commands/build.ts +131 -38
  60. package/src/cli/commands/check.ts +1 -1
  61. package/src/cli/commands/dev.ts +71 -17
  62. package/src/cli/commands/doctor.ts +2 -2
  63. package/src/cli/commands/eject.ts +47 -19
  64. package/src/cli/commands/init.ts +120 -180
  65. package/src/cli/commands/preview.ts +4 -1
  66. package/src/cli/commands/validate.ts +44 -2
  67. package/src/cli/dev-lock.ts +34 -19
  68. package/src/cli/eject-scripts.ts +72 -0
  69. package/src/cli/env.ts +15 -5
  70. package/src/cli/init/questions.ts +158 -0
  71. package/src/cli/init/scaffold.ts +380 -0
  72. package/src/cli/required-secrets.ts +2 -1
  73. package/src/components/content/AccordionItem.astro +23 -4
  74. package/src/components/content/Badge.astro +3 -1
  75. package/src/components/content/Card.astro +4 -2
  76. package/src/components/content/CodeBlock.astro +3 -0
  77. package/src/components/content/Component.astro +30 -16
  78. package/src/components/content/Diff.astro +3 -1
  79. package/src/components/content/Step.astro +10 -1
  80. package/src/components/content/Tabs.astro +15 -3
  81. package/src/components/content/Tile.astro +2 -1
  82. package/src/components/content/Tooltip.astro +3 -1
  83. package/src/components/content/Update.astro +9 -2
  84. package/src/components/content/auto-type-table.ts +25 -9
  85. package/src/components/content/base-href.ts +33 -0
  86. package/src/components/content/changelog-element.ts +9 -2
  87. package/src/components/content/diff.ts +12 -6
  88. package/src/components/content/mermaid-element.ts +10 -2
  89. package/src/components/index.ts +23 -1
  90. package/src/components/islands/AskAI.astro +5 -2
  91. package/src/components/islands/ask-ai.tsx +68 -12
  92. package/src/components/islands/base-path.ts +28 -0
  93. package/src/components/islands/hooks.ts +44 -9
  94. package/src/components/layout/Banner.astro +12 -3
  95. package/src/components/layout/Breadcrumbs.astro +2 -1
  96. package/src/components/layout/Favicon.astro +3 -2
  97. package/src/components/layout/Header.astro +15 -5
  98. package/src/components/layout/LanguageSwitcher.astro +2 -1
  99. package/src/components/layout/Logo.astro +13 -4
  100. package/src/components/layout/NavSelector.astro +2 -1
  101. package/src/components/layout/NavTree.astro +22 -7
  102. package/src/components/layout/PageActions.astro +25 -10
  103. package/src/components/layout/PageFeedback.astro +4 -1
  104. package/src/components/layout/PageLayout.astro +51 -9
  105. package/src/components/layout/Pagination.astro +3 -2
  106. package/src/components/layout/ReferenceLayout.astro +8 -1
  107. package/src/components/layout/RootLayout.astro +74 -13
  108. package/src/components/layout/Search.astro +107 -27
  109. package/src/components/layout/nav-utils.ts +18 -10
  110. package/src/components/layout/search/algolia.ts +11 -2
  111. package/src/components/layout/search/endpoint.ts +11 -5
  112. package/src/components/layout/search/orama-cloud.ts +8 -2
  113. package/src/components/layout/search/pagefind.ts +3 -0
  114. package/src/components/layout/search/types.ts +5 -1
  115. package/src/components/layout/search/typesense.ts +4 -1
  116. package/src/components/layout/toc-element.ts +8 -2
  117. package/src/components/openapi/ApiTagOperations.astro +2 -1
  118. package/src/components/openapi/Operation.astro +47 -40
  119. package/src/components/openapi/RequestPanel.astro +8 -2
  120. package/src/components/openapi/helpers.ts +71 -3
  121. package/src/components/openapi/panel.ts +1 -1
  122. package/src/components/openapi/snippets.ts +25 -11
  123. package/src/core/base-path.ts +94 -0
  124. package/src/core/builtin-tags.ts +2 -0
  125. package/src/core/component-overrides.ts +103 -74
  126. package/src/core/config-input.ts +118 -17
  127. package/src/core/config.ts +8 -5
  128. package/src/core/content.ts +2 -0
  129. package/src/core/data.ts +4 -0
  130. package/src/core/diagnostics.ts +54 -34
  131. package/src/core/gitignore.ts +4 -1
  132. package/src/core/graph.ts +166 -88
  133. package/src/core/i18n-ui.ts +63 -3
  134. package/src/core/last-modified.ts +15 -6
  135. package/src/core/links.ts +69 -25
  136. package/src/core/manifest.ts +62 -45
  137. package/src/core/nav-diagnostics.ts +1 -1
  138. package/src/core/navigation.ts +144 -58
  139. package/src/core/package-json.ts +17 -2
  140. package/src/core/project-graph.ts +25 -15
  141. package/src/core/schema.ts +605 -620
  142. package/src/core/sources/assets.ts +6 -1
  143. package/src/core/sources/filesystem.ts +4 -0
  144. package/src/core/sources/github-releases.ts +2 -1
  145. package/src/core/sources/mdx-remote.ts +76 -63
  146. package/src/core/sources/normalize.ts +236 -91
  147. package/src/core/sources/notion.ts +27 -18
  148. package/src/core/sources/types.ts +2 -0
  149. package/src/core/tsconfig-aliases.ts +59 -30
  150. package/src/core/types.ts +6 -1
  151. package/src/core/ui-packs/ar.ts +1 -0
  152. package/src/core/ui-packs/bg.ts +1 -0
  153. package/src/core/ui-packs/bn.ts +1 -0
  154. package/src/core/ui-packs/ca.ts +1 -0
  155. package/src/core/ui-packs/cs.ts +1 -0
  156. package/src/core/ui-packs/da.ts +1 -0
  157. package/src/core/ui-packs/de.ts +1 -0
  158. package/src/core/ui-packs/el.ts +1 -0
  159. package/src/core/ui-packs/es.ts +1 -0
  160. package/src/core/ui-packs/fa.ts +1 -0
  161. package/src/core/ui-packs/fi.ts +1 -0
  162. package/src/core/ui-packs/fr.ts +2 -1
  163. package/src/core/ui-packs/he.ts +1 -0
  164. package/src/core/ui-packs/hi.ts +1 -0
  165. package/src/core/ui-packs/hr.ts +1 -0
  166. package/src/core/ui-packs/hu.ts +1 -0
  167. package/src/core/ui-packs/id.ts +1 -0
  168. package/src/core/ui-packs/it.ts +1 -0
  169. package/src/core/ui-packs/ja.ts +1 -0
  170. package/src/core/ui-packs/ko.ts +1 -0
  171. package/src/core/ui-packs/nl.ts +1 -0
  172. package/src/core/ui-packs/no.ts +1 -0
  173. package/src/core/ui-packs/pl.ts +1 -0
  174. package/src/core/ui-packs/pt-br.ts +1 -0
  175. package/src/core/ui-packs/pt.ts +1 -0
  176. package/src/core/ui-packs/ro.ts +1 -0
  177. package/src/core/ui-packs/ru.ts +1 -0
  178. package/src/core/ui-packs/sk.ts +1 -0
  179. package/src/core/ui-packs/sr.ts +1 -0
  180. package/src/core/ui-packs/sv.ts +1 -0
  181. package/src/core/ui-packs/th.ts +1 -0
  182. package/src/core/ui-packs/tr.ts +1 -0
  183. package/src/core/ui-packs/uk.ts +1 -0
  184. package/src/core/ui-packs/vi.ts +1 -0
  185. package/src/core/ui-packs/zh-tw.ts +1 -0
  186. package/src/core/ui-packs/zh.ts +1 -0
  187. package/src/deploy/adapter-output.ts +18 -8
  188. package/src/deploy/redirects.ts +25 -2
  189. package/src/deploy/robots.ts +6 -1
  190. package/src/deploy/rss.ts +10 -3
  191. package/src/deploy/sitemap.ts +59 -13
  192. package/src/index.ts +5 -0
  193. package/src/markdown/base-links.ts +60 -0
  194. package/src/markdown/code-title.ts +11 -14
  195. package/src/markdown/index.ts +46 -9
  196. package/src/markdown/inline-code.ts +14 -4
  197. package/src/markdown/package-commands.ts +10 -4
  198. package/src/markdown/themes.ts +24 -0
  199. package/src/openapi/model.ts +15 -5
  200. package/src/openapi/parse.ts +21 -0
  201. package/src/openapi/references.ts +75 -21
  202. package/src/openapi/render-mdx.ts +11 -6
  203. package/src/openapi/scalar.ts +32 -16
  204. package/src/openapi/source.ts +59 -10
  205. package/src/registry/eject.ts +247 -19
  206. package/src/registry/registry.ts +0 -3
  207. package/src/search/build.ts +3 -0
  208. package/src/search/documents.ts +36 -4
  209. package/src/search/sync/typesense.ts +6 -4
  210. package/src/seo/jsonld.ts +28 -17
  211. package/src/theme/entry.ts +85 -20
@@ -100,10 +100,9 @@ export interface NotionSourceOptions {
100
100
  token?: string;
101
101
  properties?: NotionPropertyMap;
102
102
  /**
103
- * When set, the `Status` property is treated as a publish signal: any value
104
- * other than this maps to `draft: true`. Omit to import every page regardless
105
- * of status (the safe default for databases that use Status for an editorial
106
- * workflow rather than publishing).
103
+ * The `Status` property is treated as a publish signal: any value other than
104
+ * this maps to `draft: true`. Defaults to `Published`; pages without a
105
+ * Status/select property are always imported as published.
107
106
  */
108
107
  publishedValue?: string;
109
108
  /** Opt-in dev polling interval (seconds); omit to freeze for the session. */
@@ -153,7 +152,7 @@ const withNotionRetry = async <T>(call: () => Promise<T>): Promise<T> => {
153
152
  let lastError: unknown;
154
153
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt += 1) {
155
154
  try {
156
- // oxlint-disable-next-line no-await-in-loop -- sequential retry attempts
155
+ // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- sequential retry attempts, not independent
157
156
  return await call();
158
157
  } catch (error) {
159
158
  lastError = error;
@@ -372,9 +371,10 @@ export const notionSource = (
372
371
  );
373
372
  // Join with a blank line, except between consecutive list items, which stay
374
373
  // tight so they render as a single list rather than separate loose ones.
375
- const pairs = blocks
376
- .map((block, i) => ({ block, text: parts[i] ?? "" }))
377
- .filter((pair) => pair.text);
374
+ const pairs = blocks.flatMap((block, i) => {
375
+ const text = parts[i] ?? "";
376
+ return text ? [{ block, text }] : [];
377
+ });
378
378
  return pairs
379
379
  .map((pair, i) => {
380
380
  if (i === 0) {
@@ -394,12 +394,13 @@ export const notionSource = (
394
394
  };
395
395
 
396
396
  const isDraft = (page: NotionPage): boolean => {
397
- if (!options.publishedValue) {
398
- return false;
399
- }
400
397
  const prop = page.properties[props.status ?? "Status"];
401
398
  const status = prop?.status?.name ?? prop?.select?.name;
402
- return Boolean(status && status !== options.publishedValue);
399
+ // A page without a Status/select property stays published; one with a
400
+ // status is a draft unless it matches the published value.
401
+ return Boolean(
402
+ status && status !== (options.publishedValue ?? "Published")
403
+ );
403
404
  };
404
405
 
405
406
  const orderOf = (page: NotionPage): number | undefined => {
@@ -460,6 +461,19 @@ export const notionSource = (
460
461
  };
461
462
  };
462
463
 
464
+ // Hoisted out of `load` so the retry closure doesn't nest past the linter's
465
+ // 4-level limit (source factory → queryDatabase → withNotionRetry callback).
466
+ const queryDatabase = (
467
+ client: NotionClientLike,
468
+ cursor?: string
469
+ ): Promise<NotionList<NotionPage>> =>
470
+ withNotionRetry(() =>
471
+ client.databases.query({
472
+ database_id: options.database,
473
+ start_cursor: cursor,
474
+ })
475
+ );
476
+
463
477
  const load = async (
464
478
  refresh = ctx?.refresh ?? true
465
479
  ): Promise<SourceLoadResult> => {
@@ -470,12 +484,7 @@ export const notionSource = (
470
484
  async () => {
471
485
  const client = await resolveClient();
472
486
  const pages = await collectAll((cursor) =>
473
- withNotionRetry(() =>
474
- client.databases.query({
475
- database_id: options.database,
476
- start_cursor: cursor,
477
- })
478
- )
487
+ queryDatabase(client, cursor)
479
488
  );
480
489
  const built = await Promise.all(
481
490
  pages.map((page) => toEntry(client, page))
@@ -106,6 +106,8 @@ export interface ContentSource {
106
106
  /** Context passed to `normalizeEntry`, describing the owning source. */
107
107
  export interface NormalizeContext {
108
108
  source: { name: string; prefix?: string; staged: boolean };
109
+ /** Site-wide route mount point (`""` or `/seg`), prepended to every route. */
110
+ basePath?: string;
109
111
  defaultType: string;
110
112
  i18n?: ResolvedI18nConfig;
111
113
  }
@@ -21,38 +21,65 @@ import { dirname, isAbsolute, join, resolve } from "pathe";
21
21
  * aliases (the prior behavior).
22
22
  */
23
23
 
24
+ interface ScanStep {
25
+ append: string;
26
+ inString: boolean;
27
+ next: number;
28
+ }
29
+
30
+ /** Scan one character (or comment/escape run) starting at `index`. */
31
+ const scanJsonChar = (
32
+ text: string,
33
+ index: number,
34
+ inString: boolean
35
+ ): ScanStep => {
36
+ const char = text[index];
37
+ if (inString) {
38
+ if (char === "\\") {
39
+ return {
40
+ append: char + (text[index + 1] ?? ""),
41
+ inString: true,
42
+ next: index + 2,
43
+ };
44
+ }
45
+ return { append: char ?? "", inString: char !== '"', next: index + 1 };
46
+ }
47
+ if (char === '"') {
48
+ return { append: char, inString: true, next: index + 1 };
49
+ }
50
+ if (char === "/" && text[index + 1] === "/") {
51
+ const newline = text.indexOf("\n", index + 2);
52
+ return {
53
+ append: "",
54
+ inString: false,
55
+ next: newline === -1 ? text.length : newline,
56
+ };
57
+ }
58
+ if (char === "/" && text[index + 1] === "*") {
59
+ const end = text.indexOf("*/", index + 2);
60
+ return {
61
+ append: "",
62
+ inString: false,
63
+ next: end === -1 ? text.length : end + 2,
64
+ };
65
+ }
66
+ return { append: char ?? "", inString: false, next: index + 1 };
67
+ };
68
+
24
69
  /** Strip `//` line and `/* *\/` block comments that sit outside strings. */
25
70
  const stripJsonComments = (text: string): string => {
26
71
  let out = "";
27
72
  let inString = false;
28
- for (let index = 0; index < text.length; index += 1) {
29
- const char = text[index];
30
- if (inString) {
31
- out += char;
32
- if (char === "\\") {
33
- out += text[index + 1] ?? "";
34
- index += 1;
35
- } else if (char === '"') {
36
- inString = false;
37
- }
38
- continue;
39
- }
40
- if (char === '"') {
41
- inString = true;
42
- out += char;
43
- continue;
44
- }
45
- if (char === "/" && text[index + 1] === "/") {
46
- const newline = text.indexOf("\n", index + 2);
47
- index = newline === -1 ? text.length : newline - 1;
48
- continue;
49
- }
50
- if (char === "/" && text[index + 1] === "*") {
51
- const end = text.indexOf("*/", index + 2);
52
- index = end === -1 ? text.length : end + 1;
53
- continue;
54
- }
55
- out += char;
73
+ let index = 0;
74
+ while (index < text.length) {
75
+ const {
76
+ append,
77
+ inString: nextInString,
78
+ next,
79
+ } = scanJsonChar(text, index, inString);
80
+ out += append;
81
+ inString = nextInString;
82
+ index = next;
56
83
  }
57
84
  return out;
58
85
  };
@@ -97,10 +124,12 @@ const resolveExtends = (spec: string, fromDir: string): string | null => {
97
124
  }
98
125
  // A bare specifier points at a package's shared config (e.g. `@tsconfig/*`).
99
126
  try {
100
- const require_ = createRequire(pathToFileURL(join(fromDir, "_.js")).href);
127
+ const requireFromDir = createRequire(
128
+ pathToFileURL(join(fromDir, "_.js")).href
129
+ );
101
130
  for (const sub of [`${spec}/tsconfig.json`, spec]) {
102
131
  try {
103
- return require_.resolve(sub);
132
+ return requireFromDir.resolve(sub);
104
133
  } catch {
105
134
  // try the next candidate
106
135
  }
package/src/core/types.ts CHANGED
@@ -173,10 +173,15 @@ export interface NavSelectorItem {
173
173
  tag?: string;
174
174
  }
175
175
 
176
+ /** Context-partition selector kinds (a versioned/localized/multi-product site). */
177
+ type NavSelectorContextKind = "product" | "version";
178
+ /** What a top-level partition selector switches between. */
179
+ type NavSelectorKind = "dropdown" | "language" | NavSelectorContextKind;
180
+
176
181
  /** Top-level partition selectors (products, versions, languages). */
177
182
  export interface NavSelector {
178
183
  label: string;
179
- kind: "dropdown" | "language" | "product" | "version";
184
+ kind: NavSelectorKind;
180
185
  items: NavSelectorItem[];
181
186
  }
182
187
 
@@ -23,6 +23,7 @@ export const ar: UIStringsOverride = {
23
23
  send: "إرسال",
24
24
  title: "اسأل الذكاء الاصطناعي",
25
25
  },
26
+ banner: { dismiss: "إغلاق الإعلان" },
26
27
  feedback: {
27
28
  no: "لا",
28
29
  question: "هل كانت هذه الصفحة مفيدة؟",
@@ -23,6 +23,7 @@ export const bg: UIStringsOverride = {
23
23
  send: "Изпрати",
24
24
  title: "Попитай ИИ",
25
25
  },
26
+ banner: { dismiss: "Затваряне на съобщението" },
26
27
  feedback: {
27
28
  no: "Не",
28
29
  question: "Беше ли полезна тази страница?",
@@ -23,6 +23,7 @@ export const bn: UIStringsOverride = {
23
23
  send: "পাঠান",
24
24
  title: "AI-কে জিজ্ঞাসা করুন",
25
25
  },
26
+ banner: { dismiss: "ঘোষণা বন্ধ করুন" },
26
27
  feedback: {
27
28
  no: "না",
28
29
  question: "এই পৃষ্ঠাটি কি সহায়ক ছিল?",
@@ -23,6 +23,7 @@ export const ca: UIStringsOverride = {
23
23
  send: "Envia",
24
24
  title: "Pregunta a la IA",
25
25
  },
26
+ banner: { dismiss: "Tanca l'anunci" },
26
27
  feedback: {
27
28
  no: "No",
28
29
  question: "Aquesta pàgina t'ha estat útil?",
@@ -23,6 +23,7 @@ export const cs: UIStringsOverride = {
23
23
  send: "Odeslat",
24
24
  title: "Zeptat se AI",
25
25
  },
26
+ banner: { dismiss: "Zavřít oznámení" },
26
27
  feedback: {
27
28
  no: "Ne",
28
29
  question: "Byla tato stránka užitečná?",
@@ -23,6 +23,7 @@ export const da: UIStringsOverride = {
23
23
  send: "Send",
24
24
  title: "Spørg AI",
25
25
  },
26
+ banner: { dismiss: "Luk meddelelsen" },
26
27
  feedback: {
27
28
  no: "Nej",
28
29
  question: "Var denne side nyttig?",
@@ -23,6 +23,7 @@ export const de: UIStringsOverride = {
23
23
  send: "Senden",
24
24
  title: "KI fragen",
25
25
  },
26
+ banner: { dismiss: "Ankündigung schließen" },
26
27
  feedback: {
27
28
  no: "Nein",
28
29
  question: "War diese Seite hilfreich?",
@@ -23,6 +23,7 @@ export const el: UIStringsOverride = {
23
23
  send: "Αποστολή",
24
24
  title: "Ρωτήστε την AI",
25
25
  },
26
+ banner: { dismiss: "Κλείσιμο ανακοίνωσης" },
26
27
  feedback: {
27
28
  no: "Όχι",
28
29
  question: "Σας φάνηκε χρήσιμη αυτή η σελίδα;",
@@ -23,6 +23,7 @@ export const es: UIStringsOverride = {
23
23
  send: "Enviar",
24
24
  title: "Preguntar a la IA",
25
25
  },
26
+ banner: { dismiss: "Cerrar el anuncio" },
26
27
  feedback: {
27
28
  no: "No",
28
29
  question: "¿Te ha resultado útil esta página?",
@@ -23,6 +23,7 @@ export const fa: UIStringsOverride = {
23
23
  send: "ارسال",
24
24
  title: "از هوش مصنوعی بپرسید",
25
25
  },
26
+ banner: { dismiss: "بستن اطلاعیه" },
26
27
  feedback: {
27
28
  no: "خیر",
28
29
  question: "آیا این صفحه مفید بود؟",
@@ -23,6 +23,7 @@ export const fi: UIStringsOverride = {
23
23
  send: "Lähetä",
24
24
  title: "Kysy tekoälyltä",
25
25
  },
26
+ banner: { dismiss: "Sulje ilmoitus" },
26
27
  feedback: {
27
28
  no: "Ei",
28
29
  question: "Oliko tästä sivusta apua?",
@@ -5,7 +5,7 @@ export const fr: UIStringsOverride = {
5
5
  actions: {
6
6
  addToCursor: "Ajouter à Cursor",
7
7
  addToVscode: "Ajouter à VS Code",
8
- askAI: "Demander à l'IA",
8
+ askAI: "Demander à l'IA à propos de cette page",
9
9
  connectMcp: "Se connecter à MCP",
10
10
  copied: "Copié !",
11
11
  copyClaudeCode: "Copier la commande Claude Code",
@@ -23,6 +23,7 @@ export const fr: UIStringsOverride = {
23
23
  send: "Envoyer",
24
24
  title: "Demander à l'IA",
25
25
  },
26
+ banner: { dismiss: "Fermer l'annonce" },
26
27
  feedback: {
27
28
  no: "Non",
28
29
  question: "Cette page vous a-t-elle été utile ?",
@@ -23,6 +23,7 @@ export const he: UIStringsOverride = {
23
23
  send: "שלח",
24
24
  title: "שאל את ה-AI",
25
25
  },
26
+ banner: { dismiss: "סגירת ההודעה" },
26
27
  feedback: {
27
28
  no: "לא",
28
29
  question: "האם העמוד הזה היה מועיל?",
@@ -23,6 +23,7 @@ export const hi: UIStringsOverride = {
23
23
  send: "भेजें",
24
24
  title: "AI से पूछें",
25
25
  },
26
+ banner: { dismiss: "घोषणा बंद करें" },
26
27
  feedback: {
27
28
  no: "नहीं",
28
29
  question: "क्या यह पेज सहायक था?",
@@ -23,6 +23,7 @@ export const hr: UIStringsOverride = {
23
23
  send: "Pošalji",
24
24
  title: "Pitaj AI",
25
25
  },
26
+ banner: { dismiss: "Zatvori obavijest" },
26
27
  feedback: {
27
28
  no: "Ne",
28
29
  question: "Je li vam ova stranica bila korisna?",
@@ -23,6 +23,7 @@ export const hu: UIStringsOverride = {
23
23
  send: "Küldés",
24
24
  title: "Kérdezd az AI-t",
25
25
  },
26
+ banner: { dismiss: "Közlemény bezárása" },
26
27
  feedback: {
27
28
  no: "Nem",
28
29
  question: "Hasznos volt ez az oldal?",
@@ -23,6 +23,7 @@ export const id: UIStringsOverride = {
23
23
  send: "Kirim",
24
24
  title: "Tanya AI",
25
25
  },
26
+ banner: { dismiss: "Tutup pengumuman" },
26
27
  feedback: {
27
28
  no: "Tidak",
28
29
  question: "Apakah halaman ini membantu?",
@@ -23,6 +23,7 @@ export const it: UIStringsOverride = {
23
23
  send: "Invia",
24
24
  title: "Chiedi all'IA",
25
25
  },
26
+ banner: { dismiss: "Chiudi l'annuncio" },
26
27
  feedback: {
27
28
  no: "No",
28
29
  question: "Questa pagina ti è stata utile?",
@@ -23,6 +23,7 @@ export const ja: UIStringsOverride = {
23
23
  send: "送信",
24
24
  title: "AI に質問",
25
25
  },
26
+ banner: { dismiss: "お知らせを閉じる" },
26
27
  feedback: {
27
28
  no: "いいえ",
28
29
  question: "このページは役に立ちましたか?",
@@ -23,6 +23,7 @@ export const ko: UIStringsOverride = {
23
23
  send: "보내기",
24
24
  title: "AI에게 질문",
25
25
  },
26
+ banner: { dismiss: "공지 닫기" },
26
27
  feedback: {
27
28
  no: "아니요",
28
29
  question: "이 페이지가 도움이 되었나요?",
@@ -23,6 +23,7 @@ export const nl: UIStringsOverride = {
23
23
  send: "Verzenden",
24
24
  title: "AI vragen",
25
25
  },
26
+ banner: { dismiss: "Aankondiging sluiten" },
26
27
  feedback: {
27
28
  no: "Nee",
28
29
  question: "Was deze pagina nuttig?",
@@ -23,6 +23,7 @@ export const no: UIStringsOverride = {
23
23
  send: "Send",
24
24
  title: "Spør AI",
25
25
  },
26
+ banner: { dismiss: "Lukk kunngjøringen" },
26
27
  feedback: {
27
28
  no: "Nei",
28
29
  question: "Var denne siden nyttig?",
@@ -23,6 +23,7 @@ export const pl: UIStringsOverride = {
23
23
  send: "Wyślij",
24
24
  title: "Zapytaj AI",
25
25
  },
26
+ banner: { dismiss: "Zamknij ogłoszenie" },
26
27
  feedback: {
27
28
  no: "Nie",
28
29
  question: "Czy ta strona była pomocna?",
@@ -23,6 +23,7 @@ export const ptBR: UIStringsOverride = {
23
23
  send: "Enviar",
24
24
  title: "Perguntar à IA",
25
25
  },
26
+ banner: { dismiss: "Fechar o anúncio" },
26
27
  feedback: {
27
28
  no: "Não",
28
29
  question: "Esta página foi útil?",
@@ -23,6 +23,7 @@ export const pt: UIStringsOverride = {
23
23
  send: "Enviar",
24
24
  title: "Perguntar à IA",
25
25
  },
26
+ banner: { dismiss: "Fechar o anúncio" },
26
27
  feedback: {
27
28
  no: "Não",
28
29
  question: "Esta página foi útil?",
@@ -23,6 +23,7 @@ export const ro: UIStringsOverride = {
23
23
  send: "Trimite",
24
24
  title: "Întreabă AI",
25
25
  },
26
+ banner: { dismiss: "Închide anunțul" },
26
27
  feedback: {
27
28
  no: "Nu",
28
29
  question: "Ți-a fost utilă această pagină?",
@@ -23,6 +23,7 @@ export const ru: UIStringsOverride = {
23
23
  send: "Отправить",
24
24
  title: "Спросить ИИ",
25
25
  },
26
+ banner: { dismiss: "Закрыть объявление" },
26
27
  feedback: {
27
28
  no: "Нет",
28
29
  question: "Эта страница была полезной?",
@@ -23,6 +23,7 @@ export const sk: UIStringsOverride = {
23
23
  send: "Odoslať",
24
24
  title: "Opýtať sa AI",
25
25
  },
26
+ banner: { dismiss: "Zavrieť oznámenie" },
26
27
  feedback: {
27
28
  no: "Nie",
28
29
  question: "Bola táto stránka užitočná?",
@@ -23,6 +23,7 @@ export const sr: UIStringsOverride = {
23
23
  send: "Пошаљи",
24
24
  title: "Питајте AI",
25
25
  },
26
+ banner: { dismiss: "Затвори обавештење" },
26
27
  feedback: {
27
28
  no: "Не",
28
29
  question: "Да ли вам је ова страница помогла?",
@@ -23,6 +23,7 @@ export const sv: UIStringsOverride = {
23
23
  send: "Skicka",
24
24
  title: "Fråga AI",
25
25
  },
26
+ banner: { dismiss: "Stäng meddelandet" },
26
27
  feedback: {
27
28
  no: "Nej",
28
29
  question: "Var den här sidan till hjälp?",
@@ -23,6 +23,7 @@ export const th: UIStringsOverride = {
23
23
  send: "ส่ง",
24
24
  title: "ถาม AI",
25
25
  },
26
+ banner: { dismiss: "ปิดประกาศ" },
26
27
  feedback: {
27
28
  no: "ไม่",
28
29
  question: "หน้านี้มีประโยชน์หรือไม่?",
@@ -23,6 +23,7 @@ export const tr: UIStringsOverride = {
23
23
  send: "Gönder",
24
24
  title: "Yapay zekâya sor",
25
25
  },
26
+ banner: { dismiss: "Duyuruyu kapat" },
26
27
  feedback: {
27
28
  no: "Hayır",
28
29
  question: "Bu sayfa yardımcı oldu mu?",
@@ -23,6 +23,7 @@ export const uk: UIStringsOverride = {
23
23
  send: "Надіслати",
24
24
  title: "Запитати ШІ",
25
25
  },
26
+ banner: { dismiss: "Закрити оголошення" },
26
27
  feedback: {
27
28
  no: "Ні",
28
29
  question: "Чи була ця сторінка корисною?",
@@ -23,6 +23,7 @@ export const vi: UIStringsOverride = {
23
23
  send: "Gửi",
24
24
  title: "Hỏi AI",
25
25
  },
26
+ banner: { dismiss: "Đóng thông báo" },
26
27
  feedback: {
27
28
  no: "Không",
28
29
  question: "Trang này có hữu ích không?",
@@ -23,6 +23,7 @@ export const zhTW: UIStringsOverride = {
23
23
  send: "傳送",
24
24
  title: "向 AI 提問",
25
25
  },
26
+ banner: { dismiss: "關閉公告" },
26
27
  feedback: {
27
28
  no: "沒有幫助",
28
29
  question: "這個頁面有幫助嗎?",
@@ -23,6 +23,7 @@ export const zh: UIStringsOverride = {
23
23
  send: "发送",
24
24
  title: "向 AI 提问",
25
25
  },
26
+ banner: { dismiss: "关闭公告" },
26
27
  feedback: {
27
28
  no: "没有帮助",
28
29
  question: "这个页面有帮助吗?",
@@ -17,12 +17,15 @@ type Adapter = NonNullable<ResolvedConfig["deployment"]["adapter"]>;
17
17
  *
18
18
  * `vercel` writes a Build Output API v3 tree at `.vercel/output`; only that
19
19
  * subtree is moved, so a `vercel pull`-ed `.vercel/project.json` sitting at the
20
- * project root survives the relocation. `netlify` owns its whole `.netlify`
21
- * dir. `node` and `cloudflare` emit into `dist/` (already at the project root),
22
- * so they are absent here and need no relocation.
20
+ * project root survives the relocation. `netlify` writes a Frameworks API tree
21
+ * at `.netlify/v1` (its `.netlify/build` sibling is only the intermediate SSR
22
+ * bundle, already traced into `v1/functions`); only `v1` is moved, so the
23
+ * `.netlify/state.json` written by `netlify link` survives too. `node` and
24
+ * `cloudflare` emit into `dist/` (already at the project root), so they are
25
+ * absent here and need no relocation.
23
26
  */
24
27
  export const ADAPTER_OUTPUT_PATHS: Partial<Record<Adapter, string>> = {
25
- netlify: ".netlify",
28
+ netlify: ".netlify/v1",
26
29
  vercel: ".vercel/output",
27
30
  };
28
31
 
@@ -30,7 +33,10 @@ export const ADAPTER_OUTPUT_PATHS: Partial<Record<Adapter, string>> = {
30
33
  * Directory whose contents the deploy platform serves as static files. Build
31
34
  * artifacts (robots.txt, sitemap.xml, llms.txt, …) must be written here to be
32
35
  * served. For a Vercel server build that is the adapter's
33
- * `.vercel/output/static`; every other build serves `dist/`.
36
+ * `.vercel/output/static`; for a Node server build it is Astro's
37
+ * `build.client` dir (`dist/client/`), the only directory the standalone
38
+ * server's static handler reads from. Netlify publishes `dist/` itself and
39
+ * Cloudflare serves the `outDir` root, so every other build serves `dist/`.
34
40
  */
35
41
  export const deployStaticDir = (
36
42
  config: ResolvedConfig,
@@ -40,7 +46,11 @@ export const deployStaticDir = (
40
46
  if (output === "server" && adapter === "vercel") {
41
47
  return join(context.root, ".vercel", "output", "static");
42
48
  }
43
- return context.distDir ?? join(context.root, "dist");
49
+ const dist = context.distDir ?? join(context.root, "dist");
50
+ if (output === "server" && adapter === "node") {
51
+ return join(dist, "client");
52
+ }
53
+ return dist;
44
54
  };
45
55
 
46
56
  /** Outcome of {@link surfaceAdapterOutput}, for logging and `.gitignore`. */
@@ -76,7 +86,7 @@ export const surfaceAdapterOutput = async (
76
86
  await cp(from, to, { recursive: true });
77
87
  await rm(from, { force: true, recursive: true });
78
88
  // The `.gitignore` entry is the surfaced top-level dir (`.vercel`/`.netlify`),
79
- // never the moved sub-path — Vercel's own `.vercel/project.json` lives there
80
- // too and must also be ignored.
89
+ // never the moved sub-path — the platform's own state (`.vercel/project.json`,
90
+ // `.netlify/state.json`) lives there too and must also be ignored.
81
91
  return { from, ignore: `${rel.split("/")[0]}/`, moved: true, to };
82
92
  };