@aglyn/plugins-ai 1.0.0-beta.291 → 1.0.0-beta.293

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 (149) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-site-import-job.component.js +5 -4
  3. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  4. package/src/lib/components/ai-site-import-start.component.js +3 -3
  5. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  6. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  7. package/src/lib/components/ai-site-start-card.component.js +129 -29
  8. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  9. package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
  10. package/src/lib/components/ai-site-start-steps.component.js +42 -25
  11. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  12. package/src/lib/components/ai-site-style-previews.d.ts +17 -0
  13. package/src/lib/components/ai-site-style-previews.js +26 -95
  14. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  15. package/src/lib/declarations.server.js +22 -0
  16. package/src/lib/declarations.server.js.map +1 -1
  17. package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
  18. package/src/lib/jobs/ai-job-import-step.js +179 -49
  19. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  20. package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
  21. package/src/lib/jobs/ai-job-layout-language.js +156 -113
  22. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  23. package/src/lib/jobs/ai-job-layout-step.js +56 -17
  24. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  25. package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
  26. package/src/lib/jobs/ai-job-page-language.js +120 -66
  27. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  28. package/src/lib/jobs/ai-job-page-step.js +27 -7
  29. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  30. package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
  31. package/src/lib/jobs/ai-job-site-datasets.js +36 -16
  32. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  33. package/src/lib/jobs/ai-jobs.js +6 -2
  34. package/src/lib/jobs/ai-jobs.js.map +1 -1
  35. package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
  36. package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
  37. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  38. package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
  39. package/src/lib/jobs/ai-site-import-compile.js +1143 -0
  40. package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
  41. package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
  42. package/src/lib/jobs/ai-site-import-document.js +23 -489
  43. package/src/lib/jobs/ai-site-import-document.js.map +1 -1
  44. package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
  45. package/src/lib/jobs/ai-site-import-look.js +163 -52
  46. package/src/lib/jobs/ai-site-import-look.js.map +1 -1
  47. package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
  48. package/src/lib/jobs/ai-site-import-publish.js +19 -5
  49. package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
  50. package/src/lib/jobs/ai-site-late-photos.js +4 -2
  51. package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
  52. package/src/lib/jobs/ai-site-publish.d.ts +10 -1
  53. package/src/lib/jobs/ai-site-publish.js +8 -3
  54. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  55. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
  56. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
  57. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
  58. package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
  59. package/src/lib/layout-language/ai-layout-compiler.js +677 -33
  60. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  61. package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
  62. package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
  63. package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
  64. package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
  65. package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
  66. package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
  67. package/src/lib/layout-language/ai-layout-frame.js +121 -29
  68. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  69. package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
  70. package/src/lib/layout-language/ai-layout-language.js +85 -120
  71. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  72. package/src/lib/model/ai-credit-estimate.d.ts +11 -7
  73. package/src/lib/model/ai-credit-estimate.js +11 -7
  74. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  75. package/src/lib/model/ai-site-import.d.ts +307 -13
  76. package/src/lib/model/ai-site-import.js +227 -19
  77. package/src/lib/model/ai-site-import.js.map +1 -1
  78. package/src/lib/model/ai-site-look.d.ts +65 -1
  79. package/src/lib/model/ai-site-look.js +141 -23
  80. package/src/lib/model/ai-site-look.js.map +1 -1
  81. package/src/lib/model/ai-site-photos.d.ts +2 -0
  82. package/src/lib/model/ai-site-photos.js.map +1 -1
  83. package/src/lib/model/ai-site-start-steps.d.ts +4 -3
  84. package/src/lib/model/ai-site-start-steps.js +11 -3
  85. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  86. package/src/lib/model/ai-site-start.d.ts +23 -2
  87. package/src/lib/model/ai-site-start.js +25 -3
  88. package/src/lib/model/ai-site-start.js.map +1 -1
  89. package/src/lib/providers/routing.d.ts +11 -0
  90. package/src/lib/providers/routing.js +23 -0
  91. package/src/lib/providers/routing.js.map +1 -1
  92. package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
  93. package/src/lib/runtime/ai-doctrine-validators.js +7 -2
  94. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  95. package/src/lib/runtime/ai-icon-library.d.ts +4 -0
  96. package/src/lib/runtime/ai-icon-library.js +4 -0
  97. package/src/lib/runtime/ai-icon-library.js.map +1 -1
  98. package/src/lib/runtime/ai-node-tree.js +5 -1
  99. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  100. package/src/lib/runtime/ai-palette.d.ts +2 -0
  101. package/src/lib/runtime/ai-palette.generated.js +19 -3
  102. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  103. package/src/lib/runtime/ai-palette.js +2 -1
  104. package/src/lib/runtime/ai-palette.js.map +1 -1
  105. package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
  106. package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
  107. package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
  108. package/src/lib/site-import/site-import-crawl.d.ts +18 -1
  109. package/src/lib/site-import/site-import-crawl.js +70 -10
  110. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  111. package/src/lib/site-import/site-import-css.d.ts +110 -0
  112. package/src/lib/site-import/site-import-css.js +826 -0
  113. package/src/lib/site-import/site-import-css.js.map +1 -0
  114. package/src/lib/site-import/site-import-html.d.ts +116 -1
  115. package/src/lib/site-import/site-import-html.js +538 -46
  116. package/src/lib/site-import/site-import-html.js.map +1 -1
  117. package/src/lib/site-import/site-import-layout.d.ts +79 -0
  118. package/src/lib/site-import/site-import-layout.js +1608 -0
  119. package/src/lib/site-import/site-import-layout.js.map +1 -0
  120. package/src/lib/site-import/site-import-nav.d.ts +40 -0
  121. package/src/lib/site-import/site-import-nav.js +437 -0
  122. package/src/lib/site-import/site-import-nav.js.map +1 -0
  123. package/src/lib/site-import/site-import-page.d.ts +8 -1
  124. package/src/lib/site-import/site-import-page.js +24 -2
  125. package/src/lib/site-import/site-import-page.js.map +1 -1
  126. package/src/lib/assets/site-styles/beauty.webp +0 -0
  127. package/src/lib/assets/site-styles/blog.webp +0 -0
  128. package/src/lib/assets/site-styles/business.webp +0 -0
  129. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  130. package/src/lib/assets/site-styles/education.webp +0 -0
  131. package/src/lib/assets/site-styles/events.webp +0 -0
  132. package/src/lib/assets/site-styles/fitness.webp +0 -0
  133. package/src/lib/assets/site-styles/landing.webp +0 -0
  134. package/src/lib/assets/site-styles/music.webp +0 -0
  135. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  136. package/src/lib/assets/site-styles/personal.webp +0 -0
  137. package/src/lib/assets/site-styles/photography.webp +0 -0
  138. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  139. package/src/lib/assets/site-styles/professional.webp +0 -0
  140. package/src/lib/assets/site-styles/realestate.webp +0 -0
  141. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  142. package/src/lib/assets/site-styles/store.webp +0 -0
  143. package/src/lib/assets/site-styles/studio.webp +0 -0
  144. package/src/lib/assets/site-styles/trades.webp +0 -0
  145. package/src/lib/assets/site-styles/wellness.webp +0 -0
  146. package/src/lib/assets/site-styles/yoga.webp +0 -0
  147. package/src/lib/site-import/site-import-review.d.ts +0 -40
  148. package/src/lib/site-import/site-import-review.js +0 -149
  149. package/src/lib/site-import/site-import-review.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-site-import-document.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * A PAGE BROUGHT IN WORD FOR WORD (AGL-4084).\n *\n * An imported page is never rewritten. Its words are the source's, as the\n * crawler read them (`AiSiteImportPageRead.blocks`), and this module is the\n * only thing that puts them on the new page:\n *\n * - **Lines.** The page's main region, numbered: every heading, paragraph,\n * list item, quote, link and picture in source order. A link inside a\n * sentence is in its sentence already and is no line of its own.\n * - **Sections.** One for the page's opening (its title and what comes\n * before the first second-level heading), then one for each second-level\n * heading, as the source divides itself. The page's plan has exactly\n * these sections, by these names.\n * - **Copied** (a collection's page, a long page): laid out by code, every\n * line in order, the bands alternating plain and soft, with no model at\n * all.\n * - **Arranged** (a main page): the model's answer says each section's band\n * and columns and which numbered lines go in which kind of block\n * (`AI_LAYOUT_ARRANGE_TOOL`, which has no field for a word of copy). Code\n * substitutes the lines exactly as written. A block naming a line already\n * placed is dropped, a line of another section is not taken, and every\n * line the answer never placed is added at the end of its own section, so\n * each line is on the page exactly once.\n *\n * Both write the palette's own elements with the theme's tokens, the way the\n * layout language compiler does (`ai-layout-compiler.ts`), so the page\n * renders in the site's theme and every word stays editable in the\n * Besigner's fields. Nothing is fitted, cut at a clean boundary or reworded:\n * a paragraph longer than a text element holds is split between sentences,\n * and a page longer than one page may weigh ends at a line, marked `cut`, so\n * the review says how many of its words came through.\n *=========================================*/\n\nimport { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport { bandSx } from '../layout-language/ai-layout-compiler'\nimport {\n AI_LAYOUT_ARRANGE_ITEM_KINDS,\n type AiLayoutArrangeBand,\n type AiLayoutArrangedBlock,\n type AiLayoutArrangedSection,\n type AiLayoutArrangement,\n} from '../layout-language/ai-layout-language'\nimport type { AiLayoutPage } from '../layout-language/ai-layout-links'\nimport { AiLayoutTreeBuilder, aiLayoutSpans, type AiLayoutRawTree } from '../layout-language/ai-layout-tree'\nimport {\n AI_SITE_IMPORT_LABEL_MAX_CHARS,\n AI_SITE_IMPORT_MAX_SECTIONS,\n type AiSiteImportBuild,\n type AiSiteImportPhoto,\n} from '../model/ai-site-import'\nimport type { SiteImportBlock } from '../site-import/site-import-html'\nimport { siteImportLabel } from '../site-import/site-import-page'\nimport { AI_TEXT_LIMITS } from '../runtime/ai-palette'\n\n/** The unit input carrying a page brought in word for word: its lines, its photos and where its links go. */\nexport const AI_LAYOUT_IMPORTED_SECTIONS_INPUT = 'importedSections'\n\n/** A page brought in, as the import step hands it to the page step. Untrusted data from the owner's site. */\nexport interface AiSiteImportDocument {\n build: AiSiteImportBuild\n /** The page's name on the new site: its h1 where the source shows no heading. */\n title: string\n /** Where the page is on the owner's website. */\n url: string\n /** The page's main region, in order. */\n blocks: SiteImportBlock[]\n /** Its photos as the library holds them, each by the source address it was read from. */\n photos: AiSiteImportPhoto[]\n /** The site's own pages a link may go to: the source path each was read from, and the page it is now. */\n links: Array<{ path: string; id: string }>\n /** The origins the old site answers on: a link to one of them is to a page of its own. */\n origins: string[]\n}\n\n/** The most characters a text element holds (the palette's ceiling for body copy). */\nexport const AI_SITE_IMPORT_TEXT_MAX_CHARS = AI_TEXT_LIMITS.body\n\n/** The most characters a heading style holds; a longer heading is drawn in a subtitle style, still a heading. */\nexport const AI_SITE_IMPORT_HEADLINE_MAX_CHARS = AI_TEXT_LIMITS.headline\n\n/** The most characters a button's label holds; a longer link keeps its words as a line of text. */\nexport const AI_SITE_IMPORT_LABEL_CHARS = 40\n\n/**\n * What one page may weigh, inside the budget of a page of its owner's own\n * words (`AI_OWN_WORDS_PAGE_BUDGET`): a page that would run past it ends at\n * the line before, marked `cut`.\n */\nexport const AI_SITE_IMPORT_DOC_MAX_NODES = 1_400\nexport const AI_SITE_IMPORT_DOC_MAX_CHARS = 200_000\n\nconst SECTION_PADDING = { xs: 8, md: 12 } as const\n\n/** One numbered line of a page. */\nexport interface AiSiteImportLine {\n /** 1-based, in source order. */\n n: number\n block: SiteImportBlock\n /** The section it belongs to, by plan index. */\n section: number\n}\n\nexport interface AiSiteImportDocSection {\n name: string\n /** Its lines' numbers, in order. */\n lines: number[]\n}\n\nexport interface AiSiteImportDocLines {\n lines: AiSiteImportLine[]\n sections: AiSiteImportDocSection[]\n}\n\nconst clean = (text: string) => String(text ?? '').replace(/\\s+/g, ' ').trim()\n\n/** Whether a block is a line of its own: a link inside a sentence is in its sentence already. */\nfunction isLine(block: SiteImportBlock): boolean {\n if (block.kind === 'image') return !!block.url\n if (block.kind === 'link') return !block.inline && !!clean(block.text)\n return !!clean(block.text)\n}\n\n/**\n * The page's lines and sections (AGL-4084): the opening, then one section\n * at each second-level heading, at most `AI_SITE_IMPORT_MAX_SECTIONS` (the\n * last holds whatever follows). A page that opens on a second-level heading\n * opens with it. Section names are the headings' words, neutralized and cut\n * to a label, since they travel outside a fence.\n */\nexport function aiSiteImportDocLines(blocks: readonly SiteImportBlock[], title: string): AiSiteImportDocLines {\n const lines: AiSiteImportLine[] = []\n const sections: AiSiteImportDocSection[] = []\n let current: AiSiteImportDocSection | null = null\n for (const block of blocks) {\n if (!isLine(block)) continue\n const starts = block.kind === 'heading' && block.level === 2 && sections.length < AI_SITE_IMPORT_MAX_SECTIONS\n if (!current || (starts && current.lines.length > 0)) {\n current = { name: '', lines: [] }\n sections.push(current)\n }\n const n = lines.length + 1\n lines.push({ n, block, section: sections.length - 1 })\n current.lines.push(n)\n }\n const named = new Set<string>()\n sections.forEach((section, index) => {\n const heading = section.lines.map((n) => lines[n - 1].block).find((block) => block.kind === 'heading')\n let name = siteImportLabel(heading && heading.kind === 'heading' ? heading.text : index === 0 ? title : '') || (index === 0 ? siteImportLabel(title) : '')\n if (!name) name = `Section ${index + 1}`\n // Two sections of one name are told apart, so a link to either finds it.\n let unique = name\n for (let attempt = 2; named.has(unique.toLowerCase()); attempt += 1) {\n unique = `${name.slice(0, AI_SITE_IMPORT_LABEL_MAX_CHARS - 4)} (${attempt})`\n }\n named.add(unique.toLowerCase())\n section.name = unique\n })\n if (!sections.length) sections.push({ name: siteImportLabel(title) || 'Introduction', lines: [] })\n return { lines, sections }\n}\n\n/** The words a line shows: an image's are its description. */\nexport function aiSiteImportLineText(line: Pick<AiSiteImportLine, 'block'>): string {\n return line.block.kind === 'image' ? clean(line.block.alt) : clean(line.block.text)\n}\n\nconst wordsIn = (text: string) => (text.match(/[\\p{L}\\p{N}]+/gu) ?? []).length\n\n/** The input a page job carries, read defensively; `null` on every other job. */\nexport function aiSiteImportDocumentOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiSiteImportDocument | null {\n const raw = inputs?.[AI_LAYOUT_IMPORTED_SECTIONS_INPUT]\n if (!raw || typeof raw !== 'object') return null\n const value = raw as Record<string, unknown>\n const build = value['build'] === 'copied' || value['build'] === 'arranged' ? value['build'] : null\n if (!build || !Array.isArray(value['blocks'])) return null\n const blocks = (value['blocks'] as unknown[]).flatMap((entry): SiteImportBlock[] => {\n if (!entry || typeof entry !== 'object') return []\n const block = entry as Record<string, unknown>\n const text = typeof block['text'] === 'string' ? block['text'] : ''\n const region = 'main' as const\n switch (block['kind']) {\n case 'heading': {\n const level = Number(block['level'])\n return [{ kind: 'heading', level: (Number.isInteger(level) && level >= 1 && level <= 6 ? level : 2) as 1 | 2 | 3 | 4 | 5 | 6, text, region }]\n }\n case 'paragraph':\n case 'list-item':\n case 'quote':\n return [{ kind: block['kind'], text, region }]\n case 'image':\n return typeof block['url'] === 'string' ? [{ kind: 'image', url: block['url'], alt: typeof block['alt'] === 'string' ? block['alt'] : '', region }] : []\n case 'link':\n return typeof block['href'] === 'string'\n ? [{ kind: 'link', text, href: block['href'], region, ...(block['inline'] === true ? { inline: true as const } : {}) }]\n : []\n default:\n return []\n }\n })\n const strings = (list: unknown) => (Array.isArray(list) ? list.filter((entry): entry is string => typeof entry === 'string') : [])\n return {\n build,\n title: typeof value['title'] === 'string' ? value['title'] : '',\n url: typeof value['url'] === 'string' ? value['url'].slice(0, 2048) : '',\n blocks,\n photos: (Array.isArray(value['photos']) ? value['photos'] : []).flatMap((entry): AiSiteImportPhoto[] => {\n const photo = entry as Record<string, unknown> | null\n return photo && typeof photo['mediaId'] === 'string' && typeof photo['src'] === 'string'\n ? [\n {\n mediaId: photo['mediaId'],\n src: photo['src'],\n ...(typeof photo['alt'] === 'string' ? { alt: photo['alt'] } : {}),\n ...(typeof photo['from'] === 'string' ? { from: photo['from'] } : {}),\n },\n ]\n : []\n }),\n links: (Array.isArray(value['links']) ? value['links'] : []).flatMap((entry) => {\n const link = entry as Record<string, unknown> | null\n return link && typeof link['path'] === 'string' && typeof link['id'] === 'string' ? [{ path: link['path'], id: link['id'] }] : []\n }),\n origins: strings(value['origins']),\n }\n}\n\n/*------------------------------------------\n * Drawing the lines\n *-----------------------------------------*/\n\n/** A paragraph cut between sentences into parts a text element holds, every word kept in order. */\nexport function aiSiteImportTextParts(text: string, max = AI_SITE_IMPORT_TEXT_MAX_CHARS): string[] {\n const words = clean(text)\n if (words.length <= max) return words ? [words] : []\n const sentences = words.match(/[^.!?…]+(?:[.!?…]+[\"'”’)\\]]*\\s*|$)/g) ?? [words]\n const parts: string[] = []\n let part = ''\n const push = () => {\n if (part.trim()) parts.push(part.trim())\n part = ''\n }\n for (const sentence of sentences) {\n if ((part + sentence).trim().length <= max) {\n part += sentence\n continue\n }\n push()\n // One sentence longer than an element holds is cut between words.\n let rest = sentence.trim()\n while (rest.length > max) {\n const at = rest.lastIndexOf(' ', max)\n const cut = at > 0 ? at : max\n parts.push(rest.slice(0, cut).trim())\n rest = rest.slice(cut).trim()\n }\n part = rest ? `${rest} ` : ''\n }\n push()\n return parts\n}\n\ntype Style = 'heading' | 'eyebrow' | 'lede' | 'text' | 'note'\n\ninterface DocScope {\n tree: AiLayoutTreeBuilder\n doc: AiSiteImportDocument\n /** The pages a link may go to by id. */\n pageIds: ReadonlySet<string>\n /** Source path → page id, for the ones a link may go to. */\n pathTo: ReadonlyMap<string, string>\n photos: ReadonlyMap<string, AiSiteImportPhoto>\n /** Whether the page's h1 is written. */\n titled: boolean\n /** The level of the last heading drawn, which the next may go at most one under. */\n lastLevel: number\n /** Pictures drawn so far: the first loads at once, the rest when reached. */\n pictures: number\n /** Lines on the page, in the order drawn. */\n placed: number[]\n words: number\n chars: number\n cut: boolean\n}\n\n/** Whether the page has room for one more line of this many characters. */\nfunction room(scope: DocScope, chars: number): boolean {\n if (scope.cut) return false\n if (Object.keys(scope.tree.nodes).length >= AI_SITE_IMPORT_DOC_MAX_NODES || scope.chars + chars > AI_SITE_IMPORT_DOC_MAX_CHARS) {\n scope.cut = true\n return false\n }\n return true\n}\n\nfunction took(scope: DocScope, line: AiSiteImportLine): void {\n scope.placed.push(line.n)\n const text = aiSiteImportLineText(line)\n scope.chars += text.length\n if (line.block.kind !== 'image') scope.words += wordsIn(text)\n}\n\n/** A heading at its place in the outline: the page's one h1 first, then the section's h2, then h3 under it. */\nfunction headingNode(scope: DocScope, text: string, level: number, centered: boolean): string {\n // The outline never skips a level: an h3 straight under the h1 is drawn an h2.\n const tag = !scope.titled ? 1 : Math.max(2, Math.min(3, level, scope.lastLevel + 1))\n scope.titled = true\n scope.lastLevel = tag\n const variant = text.length > AI_SITE_IMPORT_HEADLINE_MAX_CHARS ? 'subtitle1' : tag === 1 ? 'h1' : tag === 2 ? 'h2' : 'h4'\n return scope.tree.add(\n 'muiTypography',\n { children: text, variant, component: `h${tag}`, ...(centered ? { align: 'center' } : {}) },\n null,\n null,\n 'heading',\n )\n}\n\nconst VARIANTS: Record<Exclude<Style, 'heading'>, string> = { eyebrow: 'overline', lede: 'lede', text: 'body1', note: 'body2' }\n\n/** Words in a style, split where a text element would cut them. */\nfunction textNodes(scope: DocScope, text: string, style: Exclude<Style, 'heading'>, centered: boolean): string[] {\n return aiSiteImportTextParts(text).map((part) =>\n scope.tree.add(\n 'muiTypography',\n { children: part, variant: VARIANTS[style], component: 'p', ...(centered ? { align: 'center' } : {}) },\n style === 'note' ? { color: 'text.secondary' } : null,\n null,\n style,\n ),\n )\n}\n\n/** Where a link goes on the new site, or `null` where it goes nowhere a page of it may send a visitor. */\nfunction linkProps(scope: DocScope, href: string): Record<string, unknown> | null {\n if (/^mailto:[^\\s@]+@[^\\s@]+$/i.test(href) || /^tel:\\+?[\\d\\s().-]{3,}$/i.test(href)) return { href }\n let url: URL\n try {\n url = new URL(href)\n } catch {\n return null\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') return null\n if (scope.doc.origins.includes(url.origin)) {\n // The old site's own page: the page it became, where that page may be linked.\n const path = url.pathname.replace(/\\/+$/, '') || '/'\n const id = scope.pathTo.get(path)\n return id && scope.pageIds.has(id) ? { screenId: id } : null\n }\n return url.protocol === 'https:' ? { href: url.toString(), target: '_blank' } : null\n}\n\n/** A link line: a button that goes where the source's did, or its words as a line where it cannot. */\nfunction linkNodes(scope: DocScope, line: AiSiteImportLine, style: 'primary' | 'secondary' | 'quiet', centered: boolean): string[] {\n const block = line.block\n if (block.kind !== 'link') return []\n const label = clean(block.text)\n const goes = label.length <= AI_SITE_IMPORT_LABEL_CHARS ? linkProps(scope, block.href) : null\n if (!goes) return textNodes(scope, label, 'text', centered)\n const look =\n style === 'primary'\n ? { variant: 'contained', color: 'primary' }\n : style === 'secondary'\n ? { variant: 'outlined', color: 'primary' }\n : { variant: 'text', color: 'primary' }\n return [\n scope.tree.add(\n 'muiButton',\n { children: label, ...look, size: 'medium', ...goes },\n { alignSelf: centered ? 'center' : 'flex-start' },\n null,\n 'button',\n ),\n ]\n}\n\n/** A picture line: the photo the library holds for it, or nothing where it could not be brought in. */\nfunction imageNodes(scope: DocScope, line: AiSiteImportLine): string[] {\n const block = line.block\n if (block.kind !== 'image') return []\n const photo = scope.photos.get(block.url)\n if (!photo) return []\n const alt = clean(block.alt || photo.alt || '').slice(0, 200)\n scope.pictures += 1\n return [\n scope.tree.add(\n 'image',\n {\n src: photo.src,\n ...(alt ? { alt } : { decorative: true }),\n objectFit: 'cover',\n ...(scope.pictures > 1 ? { loading: 'lazy' } : {}),\n },\n null,\n null,\n 'image',\n ),\n ]\n}\n\n/** One line in a style a block asked for; a picture is a picture and a link a link, wherever they are placed. */\nfunction lineNodes(scope: DocScope, line: AiSiteImportLine, style: Style, centered: boolean, button: 'primary' | 'secondary' | 'quiet' = 'quiet'): string[] {\n if (!room(scope, aiSiteImportLineText(line).length)) return []\n const block = line.block\n let ids: string[]\n if (block.kind === 'image') ids = imageNodes(scope, line)\n else if (block.kind === 'link') ids = linkNodes(scope, line, button, centered)\n else if (style === 'heading' || (block.kind === 'heading' && style === 'text')) ids = [headingNode(scope, clean(block.text), block.kind === 'heading' ? block.level : 2, centered)]\n else if (block.kind === 'quote' && style === 'text') {\n ids = [scope.tree.add('muiBox', { component: 'blockquote' }, null, textNodes(scope, block.text, 'text', centered), 'quote')]\n } else ids = textNodes(scope, block.text, style, centered)\n // A picture the library could not bring in is not on the page.\n if (ids.length) took(scope, line)\n return ids\n}\n\n/** A run of lines as a list, one item each. */\nfunction listNode(scope: DocScope, lines: readonly AiSiteImportLine[]): string[] {\n const rows: string[] = []\n const rest: string[] = []\n for (const line of lines) {\n if (line.block.kind === 'image' || line.block.kind === 'link') {\n rest.push(...lineNodes(scope, line, 'text', false))\n continue\n }\n const text = aiSiteImportLineText(line)\n if (!room(scope, text.length)) break\n for (const part of aiSiteImportTextParts(text)) {\n rows.push(\n scope.tree.add('muiListItem', { disableGutters: true }, null, [scope.tree.add('muiListItemText', { primary: part }, null, null, 'line')], 'row'),\n )\n }\n took(scope, line)\n }\n return [...(rows.length ? [scope.tree.add('muiList', { disablePadding: true }, null, rows, 'list')] : []), ...rest]\n}\n\n/** A group's items, each a title line over its text lines, laid out side by side. */\nfunction groupNode(scope: DocScope, kind: AiLayoutArrangedBlock['kind'], items: readonly AiSiteImportLine[][]): string[] {\n const pairs: string[] = []\n const rest: string[] = []\n for (const item of items) {\n const words = item.filter((line) => line.block.kind !== 'image' && line.block.kind !== 'link')\n for (const line of item) if (line.block.kind === 'image' || line.block.kind === 'link') rest.push(...lineNodes(scope, line, 'text', false))\n if (!words.length) continue\n const [title, ...body] = words\n const text = body.map(aiSiteImportLineText).join(' ')\n if (!room(scope, aiSiteImportLineText(title).length + text.length)) break\n const primary = aiSiteImportLineText(title)\n if (primary.length > AI_SITE_IMPORT_TEXT_MAX_CHARS || text.length > AI_SITE_IMPORT_TEXT_MAX_CHARS) {\n // An item too long for its element is its lines, one under another.\n for (const line of words) rest.push(...lineNodes(scope, line, 'text', false))\n continue\n }\n pairs.push(scope.tree.add('muiListItemText', { primary, ...(text ? { secondary: text } : {}) }, null, null, 'pair'))\n for (const line of words) took(scope, line)\n }\n if (!pairs.length) return rest\n const perRow = kind === 'faq' || kind === 'steps' || pairs.length === 1 ? 1 : Math.min(3, pairs.length)\n if (perRow === 1) return [scope.tree.add('muiStack', { spacing: '3' }, null, pairs, kind), ...rest]\n const size = perRow === 2 ? 'xs:12 sm:6' : 'xs:12 md:4'\n const cells = pairs.map((id) => scope.tree.add('muiGrid', { size }, null, [id], 'cell'))\n return [scope.tree.add('muiGrid', { container: true, spacing: '3' }, null, cells, kind), ...rest]\n}\n\n/** A section root: its band, its container and its content, under the id its plan stores it by. */\nfunction sectionNode(scope: DocScope, index: number, name: string, band: AiLayoutArrangeBand, parts: readonly string[], id: string, wide: boolean): string {\n const tree = scope.tree\n const content = parts.length === 1 ? parts[0] : tree.add('muiStack', { spacing: '3', useFlexGap: true }, null, parts, 'content')\n const container = tree.add('muiContainer', { maxWidth: wide ? 'lg' : 'md' }, { py: { ...SECTION_PADDING } }, [content], 'container')\n return tree.add(\n 'section',\n { element: 'section', ariaLabel: name || `Section ${index + 1}`, ...(band === 'dark' ? { colorScheme: 'dark' } : {}) },\n bandSx(band),\n [container],\n 'section',\n id,\n )\n}\n\n/** The lines of a section, in source order, as the source draws them: lists as lists, the rest one under another. */\nfunction copiedParts(scope: DocScope, lines: readonly AiSiteImportLine[]): string[] {\n const parts: string[] = []\n for (let at = 0; at < lines.length; at += 1) {\n const line = lines[at]\n if (line.block.kind === 'list-item') {\n const run: AiSiteImportLine[] = []\n while (at < lines.length && lines[at].block.kind === 'list-item') run.push(lines[at++])\n at -= 1\n parts.push(...listNode(scope, run))\n continue\n }\n parts.push(...lineNodes(scope, line, 'text', false))\n }\n return parts\n}\n\n/** One arranged block's lines, still unplaced and of its own section; `null` where it named a line already placed. */\nfunction ownLines(lineOf: (n: number) => AiSiteImportLine | undefined, numbers: readonly number[], section: number, used: Set<number>): AiSiteImportLine[] | null {\n const lines: AiSiteImportLine[] = []\n for (const n of numbers) {\n const line = lineOf(n)\n if (!line || line.section !== section) continue\n if (used.has(n)) return null\n lines.push(line)\n }\n return lines\n}\n\n/** An arranged block drawn: its lines in the kind it asked for. */\nfunction arrangedBlock(scope: DocScope, block: AiLayoutArrangedBlock, lines: readonly AiSiteImportLine[], items: readonly AiSiteImportLine[][], centered: boolean): string[] {\n switch (block.kind) {\n case 'list':\n return listNode(scope, lines)\n case 'cards':\n case 'steps':\n case 'stats':\n case 'faq':\n return groupNode(scope, block.kind, items.length ? items : lines.map((line) => [line]))\n case 'button': {\n const style = block.style === 'primary' || block.style === 'secondary' ? block.style : 'quiet'\n return lines.flatMap((line) => lineNodes(scope, line, 'text', centered, style))\n }\n case 'image':\n return lines.flatMap((line) => lineNodes(scope, line, 'text', centered))\n case 'heading':\n case 'eyebrow':\n case 'lede':\n case 'note': {\n const style: Style = block.kind\n return lines.flatMap((line, position) =>\n // A heading block's first line is the heading; any more are its words.\n lineNodes(scope, line, style === 'heading' && position > 0 ? 'text' : style, centered),\n )\n }\n default:\n return lines.flatMap((line) => lineNodes(scope, line, line.block.kind === 'heading' ? 'heading' : 'text', centered))\n }\n}\n\n/** One section as the arrangement lays it out, every line of it that the arrangement left out added at its end. */\nfunction arrangedParts(\n scope: DocScope,\n arranged: AiLayoutArrangedSection,\n index: number,\n lines: readonly AiSiteImportLine[],\n lineOf: (n: number) => AiSiteImportLine | undefined,\n used: Set<number>,\n): { parts: string[]; wide: boolean } {\n const centered = arranged.align === 'center'\n const cols = arranged.cols && arranged.cols.length >= 2 ? arranged.cols : null\n const head: string[] = []\n const tail: string[] = []\n const columns: string[][] = cols ? cols.map(() => []) : []\n let placedInRow = false\n for (const block of arranged.blocks) {\n const groups = AI_LAYOUT_ARRANGE_ITEM_KINDS.has(block.kind)\n const named = groups && block.items?.length ? block.items.flat() : block.from\n const taken = ownLines(lineOf, named, index, used)\n // A block that names a line twice is dropped; its other lines are added at the end.\n if (!taken?.length) continue\n for (const line of taken) used.add(line.n)\n const items = groups && block.items?.length ? block.items.map((item) => taken.filter((line) => item.includes(line.n))).filter((item) => item.length) : []\n const ids = arrangedBlock(scope, block, taken, items, centered && block.col === undefined)\n if (cols && block.col !== undefined) {\n columns[Math.min(block.col, cols.length - 1)].push(...ids)\n placedInRow = true\n } else (placedInRow ? tail : head).push(...ids)\n }\n // Every line the arrangement did not place, in source order, at the section's end.\n const left = lines.filter((line) => !used.has(line.n))\n for (const line of left) used.add(line.n)\n tail.push(...copiedParts(scope, left))\n const filled = columns.map((ids, position) => ({ ids, weight: cols?.[position] ?? 1 })).filter((entry) => entry.ids.length)\n const parts = [...head]\n if (filled.length >= 2) {\n const spans = aiLayoutSpans(filled.map((entry) => entry.weight))\n const cells = filled.map((entry, position) =>\n scope.tree.add(\n 'muiGrid',\n { size: `xs:12 md:${spans[position]}` },\n null,\n [entry.ids.length === 1 ? entry.ids[0] : scope.tree.add('muiStack', { spacing: '3' }, null, entry.ids, 'column')],\n 'cell',\n ),\n )\n parts.push(scope.tree.add('muiGrid', { container: true, spacing: '6' }, null, cells, 'row'))\n } else if (filled.length === 1) parts.push(...filled[0].ids)\n parts.push(...tail)\n return { parts, wide: filled.length >= 2 }\n}\n\nexport interface AiSiteImportCompileInput {\n doc: AiSiteImportDocument\n /** The ids the page stores its sections under, in plan order: one for each of the document's sections. */\n sectionIds: readonly string[]\n /** The site's pages a link may go to (the page step's targets). */\n pages: readonly Pick<AiLayoutPage, 'id'>[]\n /** The model's arrangement, for an arranged page; absent, the page is laid out as the source has it. */\n arrangement?: AiLayoutArrangement | null\n}\n\nexport interface AiSiteImportCompiled {\n tree: AiLayoutRawTree\n /** The line numbers on the page, in the order drawn. */\n placed: number[]\n /** Every line the page has. */\n lines: number\n /** The words on the page, and the words its lines hold. */\n words: number\n sourceWords: number\n /** Set when the page ran past what one page may weigh, and ends at the line before. */\n cut: boolean\n}\n\n/**\n * The page brought in, compiled into its tree (AGL-4084): copied as the\n * source has it, or as the arrangement lays it out, with every line on it\n * exactly once in either case and never a word that is not the source's.\n */\nexport function aiCompileImportedDocument(input: AiSiteImportCompileInput): AiSiteImportCompiled {\n const { doc } = input\n const { lines, sections } = aiSiteImportDocLines(doc.blocks, doc.title)\n const tree = new AiLayoutTreeBuilder('li')\n const pageIds = new Set(input.pages.map((page) => page.id))\n const scope: DocScope = {\n tree,\n doc,\n pageIds,\n pathTo: new Map(doc.links.map((link) => [link.path.replace(/\\/+$/, '') || '/', link.id])),\n photos: new Map(doc.photos.flatMap((photo) => (photo.from ? [[photo.from, photo] as const] : []))),\n titled: false,\n lastLevel: 1,\n pictures: 0,\n placed: [],\n words: 0,\n chars: 0,\n cut: false,\n }\n const lineOf = (n: number) => lines[n - 1]\n const used = new Set<number>()\n const arranged = doc.build === 'arranged' ? input.arrangement : null\n // An arranged opening with no heading block takes its first heading line as one, so the page keeps its h1.\n const opening = arranged?.sections[0]\n if (opening && !opening.blocks.some((block) => block.kind === 'heading')) {\n const first = opening.blocks.find((block) => block.from.some((n) => lineOf(n)?.block.kind === 'heading'))\n if (first && !AI_LAYOUT_ARRANGE_ITEM_KINDS.has(first.kind) && first.kind !== 'list') first.kind = 'heading'\n }\n const roots = sections.map((section, index) => {\n const own = section.lines.map(lineOf)\n // The page's h1: its title, where its opening shows no heading of its own.\n const titleParts: string[] = []\n if (index === 0 && !own.some((line) => line.block.kind === 'heading') && !(arranged?.sections[0]?.blocks.some((block) => block.kind === 'heading'))) {\n titleParts.push(headingNode(scope, clean(doc.title) || section.name, 1, false))\n }\n const plan = arranged?.sections[index] ?? null\n const drawn = plan ? arrangedParts(scope, plan, index, own, lineOf, used) : { parts: copiedParts(scope, own.filter((line) => !used.has(line.n))), wide: false }\n for (const line of own) used.add(line.n)\n const band: AiLayoutArrangeBand = plan?.band ?? (index % 2 === 1 ? 'soft' : 'plain')\n const parts = [...titleParts, ...drawn.parts]\n if (!parts.length) {\n // A section whose lines could not come through (its pictures, the page's weight) keeps its place by its name.\n parts.push(headingNode(scope, section.name, 2, false))\n }\n return sectionNode(scope, index, section.name, band, parts, input.sectionIds[index] ?? `section-${index + 1}`, drawn.wide)\n })\n const rootId = tree.add('div', null, null, roots, 'page', CANVAS_ROOT_ELEMENT_ID)\n for (const root of roots) tree.prune(root)\n const sourceWords = lines.reduce((total, line) => total + (line.block.kind === 'image' ? 0 : wordsIn(aiSiteImportLineText(line))), 0)\n return { tree: { rootId, nodes: tree.nodes }, placed: scope.placed, lines: lines.length, words: scope.words, sourceWords, cut: scope.cut }\n}\n\n/*------------------------------------------\n * What the arrangement is shown\n *-----------------------------------------*/\n\n/** The most characters of a page's numbered lines an arrangement prompt shows. */\nexport const AI_SITE_IMPORT_ARRANGE_MAX_CHARS = 60_000\n\nconst LINE_KIND: Record<SiteImportBlock['kind'], string> = {\n heading: 'heading',\n paragraph: 'text',\n 'list-item': 'list item',\n quote: 'quote',\n link: 'link',\n image: 'picture',\n}\n\n/** The page's lines as the arrangement reads them: each section, its numbered lines and their kinds. */\nexport function aiSiteImportArrangeText(doc: Pick<AiSiteImportDocument, 'blocks' | 'title'>): string {\n const { lines, sections } = aiSiteImportDocLines(doc.blocks, doc.title)\n return sections\n .map((section, index) =>\n [\n `Section ${index + 1}: ${section.name}`,\n ...section.lines.map((n) => {\n const line = lines[n - 1]\n const kind = line.block.kind === 'heading' ? `heading ${line.block.level}` : LINE_KIND[line.block.kind]\n return `[${n}] (${kind}) ${aiSiteImportLineText(line) || '(no description)'}`\n }),\n ].join('\\n'),\n )\n .join('\\n\\n')\n}\n"],"names":["CANVAS_ROOT_ELEMENT_ID","bandSx","AI_LAYOUT_ARRANGE_ITEM_KINDS","AiLayoutTreeBuilder","aiLayoutSpans","AI_SITE_IMPORT_LABEL_MAX_CHARS","AI_SITE_IMPORT_MAX_SECTIONS","siteImportLabel","AI_TEXT_LIMITS","AI_LAYOUT_IMPORTED_SECTIONS_INPUT","AI_SITE_IMPORT_TEXT_MAX_CHARS","body","AI_SITE_IMPORT_HEADLINE_MAX_CHARS","headline","AI_SITE_IMPORT_LABEL_CHARS","AI_SITE_IMPORT_DOC_MAX_NODES","AI_SITE_IMPORT_DOC_MAX_CHARS","SECTION_PADDING","xs","md","clean","text","String","replace","trim","isLine","block","kind","url","inline","aiSiteImportDocLines","blocks","title","lines","sections","current","starts","level","length","name","push","n","section","named","Set","forEach","index","heading","map","find","unique","attempt","has","toLowerCase","slice","add","aiSiteImportLineText","line","alt","wordsIn","match","aiSiteImportDocumentOf","inputs","raw","value","build","Array","isArray","flatMap","entry","region","Number","isInteger","href","strings","list","filter","photos","photo","mediaId","src","from","links","link","path","id","origins","aiSiteImportTextParts","max","words","sentences","parts","part","sentence","rest","at","lastIndexOf","cut","room","scope","chars","Object","keys","tree","nodes","took","placed","headingNode","centered","tag","titled","Math","min","lastLevel","variant","children","component","align","VARIANTS","eyebrow","lede","note","textNodes","style","color","linkProps","test","URL","protocol","doc","includes","origin","pathname","pathTo","get","pageIds","screenId","toString","target","linkNodes","label","goes","look","size","alignSelf","imageNodes","pictures","decorative","objectFit","loading","lineNodes","button","ids","listNode","rows","disableGutters","primary","disablePadding","groupNode","items","pairs","item","join","secondary","perRow","spacing","cells","container","sectionNode","band","wide","content","useFlexGap","maxWidth","py","element","ariaLabel","colorScheme","copiedParts","run","ownLines","lineOf","numbers","used","arrangedBlock","position","arrangedParts","arranged","cols","head","tail","columns","placedInRow","groups","flat","taken","col","undefined","left","filled","weight","spans","aiCompileImportedDocument","input","pages","page","Map","arrangement","opening","some","first","roots","own","titleParts","plan","drawn","sectionIds","rootId","root","prune","sourceWords","reduce","total","AI_SITE_IMPORT_ARRANGE_MAX_CHARS","LINE_KIND","paragraph","quote","image","aiSiteImportArrangeText"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-site-import-document.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * A PAGE BROUGHT IN WORD FOR WORD (AGL-4084, AGL-4107).\n *\n * An imported page is never rewritten. Its words are the source's, as the\n * crawler read them (`AiSiteImportPageRead.blocks`), and how the source lays\n * them out is the reader's (`AiSiteImportPageRead.layout`, AGL-4106). This\n * module is the page as its job carries it: its blocks, its layout, its\n * photos and where its links go, read defensively off the job's inputs.\n *\n * - **Lines.** The page's main region, numbered: every heading, paragraph,\n * list item, quote, link and picture in source order. A link inside a\n * sentence is in its sentence already and is no line of its own.\n * - **Sections.** Where a read kept no layout (one made before the reader,\n * or one past its budget), one for the page's opening and one at each\n * second-level heading, as the source divides itself.\n *\n * The page is drawn by the site compiler (`ai-site-import-compile.ts`), with\n * every line on it exactly once and never a word that is not the source's.\n *=========================================*/\n\n\nimport {\n AI_SITE_IMPORT_LABEL_MAX_CHARS,\n AI_SITE_IMPORT_MAX_SECTIONS,\n type AiSiteImportBuild,\n type AiSiteImportPhoto,\n type SiteImportLayout,\n} from '../model/ai-site-import'\nimport type { SiteImportBlock } from '../site-import/site-import-html'\nimport { siteImportLabel } from '../site-import/site-import-page'\nimport { AI_TEXT_LIMITS } from '../runtime/ai-palette'\n\n/** The unit input carrying a page brought in word for word: its lines, its photos and where its links go. */\nexport const AI_LAYOUT_IMPORTED_SECTIONS_INPUT = 'importedSections'\n\n/** A page brought in, as the import step hands it to the page step. Untrusted data from the owner's site. */\nexport interface AiSiteImportDocument {\n build: AiSiteImportBuild\n /** The page's name on the new site: its h1 where the source shows no heading. */\n title: string\n /** Where the page is on the owner's website. */\n url: string\n /** The page's main region, in order. */\n blocks: SiteImportBlock[]\n /** Its photos as the library holds them, each by the source address it was read from. */\n photos: AiSiteImportPhoto[]\n /** The site's own pages a link may go to: the source path each was read from, and the page it is now. */\n links: Array<{ path: string; id: string }>\n /** The origins the old site answers on: a link to one of them is to a page of its own. */\n origins: string[]\n /**\n * How the source lays the page out (AGL-4106), over `blocks` by index;\n * absent on a read made before the reader, or one past its budget.\n */\n layout?: SiteImportLayout | null\n}\n\n/** The most characters a text element holds (the palette's ceiling for body copy). */\nexport const AI_SITE_IMPORT_TEXT_MAX_CHARS = AI_TEXT_LIMITS.body\n\n/** The most characters a heading style holds; a longer heading is drawn in a subtitle style, still a heading. */\nexport const AI_SITE_IMPORT_HEADLINE_MAX_CHARS = AI_TEXT_LIMITS.headline\n\n/** The most characters a button's label holds; a longer link keeps its words as a line of text. */\nexport const AI_SITE_IMPORT_LABEL_CHARS = 40\n\n/**\n * What one page may weigh, inside the budget of a page of its owner's own\n * words (`AI_OWN_WORDS_PAGE_BUDGET`): a page that would run past it ends at\n * the section before, marked `cut`.\n */\nexport const AI_SITE_IMPORT_DOC_MAX_NODES = 1_400\nexport const AI_SITE_IMPORT_DOC_MAX_CHARS = 200_000\n\n/** One numbered line of a page. */\nexport interface AiSiteImportLine {\n /** 1-based, in source order. */\n n: number\n block: SiteImportBlock\n /** The section it belongs to, by plan index. */\n section: number\n}\n\nexport interface AiSiteImportDocSection {\n name: string\n /** Its lines' numbers, in order. */\n lines: number[]\n}\n\nexport interface AiSiteImportDocLines {\n lines: AiSiteImportLine[]\n sections: AiSiteImportDocSection[]\n}\n\nconst clean = (text: string) => String(text ?? '').replace(/\\s+/g, ' ').trim()\n\n/** Whether a block is a line of its own: a link inside a sentence is in its sentence already. */\nfunction isLine(block: SiteImportBlock): boolean {\n if (block.kind === 'image') return !!block.url\n if (block.kind === 'link') return !block.inline && !!clean(block.text)\n return !!clean(block.text)\n}\n\n/**\n * The page's lines and sections (AGL-4084): the opening, then one section\n * at each second-level heading, at most `AI_SITE_IMPORT_MAX_SECTIONS` (the\n * last holds whatever follows). A page that opens on a second-level heading\n * opens with it. Section names are the headings' words, neutralized and cut\n * to a label, since they travel outside a fence.\n */\nexport function aiSiteImportDocLines(blocks: readonly SiteImportBlock[], title: string): AiSiteImportDocLines {\n const lines: AiSiteImportLine[] = []\n const sections: AiSiteImportDocSection[] = []\n let current: AiSiteImportDocSection | null = null\n for (const block of blocks) {\n if (!isLine(block)) continue\n const starts = block.kind === 'heading' && block.level === 2 && sections.length < AI_SITE_IMPORT_MAX_SECTIONS\n if (!current || (starts && current.lines.length > 0)) {\n current = { name: '', lines: [] }\n sections.push(current)\n }\n const n = lines.length + 1\n lines.push({ n, block, section: sections.length - 1 })\n current.lines.push(n)\n }\n const named = new Set<string>()\n sections.forEach((section, index) => {\n const heading = section.lines.map((n) => lines[n - 1].block).find((block) => block.kind === 'heading')\n let name = siteImportLabel(heading && heading.kind === 'heading' ? heading.text : index === 0 ? title : '') || (index === 0 ? siteImportLabel(title) : '')\n if (!name) name = `Section ${index + 1}`\n // Two sections of one name are told apart, so a link to either finds it.\n let unique = name\n for (let attempt = 2; named.has(unique.toLowerCase()); attempt += 1) {\n unique = `${name.slice(0, AI_SITE_IMPORT_LABEL_MAX_CHARS - 4)} (${attempt})`\n }\n named.add(unique.toLowerCase())\n section.name = unique\n })\n if (!sections.length) sections.push({ name: siteImportLabel(title) || 'Introduction', lines: [] })\n return { lines, sections }\n}\n\n/** The words a line shows: an image's are its description. */\nexport function aiSiteImportLineText(line: Pick<AiSiteImportLine, 'block'>): string {\n return line.block.kind === 'image' ? clean(line.block.alt) : clean(line.block.text)\n}\n\n/** How many words a line says: its runs of letters and digits, as the review counts them. */\nexport const aiSiteImportWordsIn = (text: string): number => (text.match(/[\\p{L}\\p{N}]+/gu) ?? []).length\n\n/** The input a page job carries, read defensively; `null` on every other job. */\nexport function aiSiteImportDocumentOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiSiteImportDocument | null {\n const raw = inputs?.[AI_LAYOUT_IMPORTED_SECTIONS_INPUT]\n if (!raw || typeof raw !== 'object') return null\n const value = raw as Record<string, unknown>\n const build = value['build'] === 'copied' || value['build'] === 'arranged' ? value['build'] : null\n if (!build || !Array.isArray(value['blocks'])) return null\n const blocks = (value['blocks'] as unknown[]).flatMap((entry): SiteImportBlock[] => {\n if (!entry || typeof entry !== 'object') return []\n const block = entry as Record<string, unknown>\n const text = typeof block['text'] === 'string' ? block['text'] : ''\n const region = 'main' as const\n switch (block['kind']) {\n case 'heading': {\n const level = Number(block['level'])\n return [{ kind: 'heading', level: (Number.isInteger(level) && level >= 1 && level <= 6 ? level : 2) as 1 | 2 | 3 | 4 | 5 | 6, text, region }]\n }\n case 'paragraph':\n case 'list-item':\n case 'quote':\n return [{ kind: block['kind'], text, region }]\n case 'image':\n return typeof block['url'] === 'string' ? [{ kind: 'image', url: block['url'], alt: typeof block['alt'] === 'string' ? block['alt'] : '', region }] : []\n case 'link':\n return typeof block['href'] === 'string'\n ? [{ kind: 'link', text, href: block['href'], region, ...(block['inline'] === true ? { inline: true as const } : {}) }]\n : []\n default:\n return []\n }\n })\n const strings = (list: unknown) => (Array.isArray(list) ? list.filter((entry): entry is string => typeof entry === 'string') : [])\n return {\n build,\n title: typeof value['title'] === 'string' ? value['title'] : '',\n url: typeof value['url'] === 'string' ? value['url'].slice(0, 2048) : '',\n blocks,\n photos: (Array.isArray(value['photos']) ? value['photos'] : []).flatMap((entry): AiSiteImportPhoto[] => {\n const photo = entry as Record<string, unknown> | null\n return photo && typeof photo['mediaId'] === 'string' && typeof photo['src'] === 'string'\n ? [\n {\n mediaId: photo['mediaId'],\n src: photo['src'],\n ...(typeof photo['alt'] === 'string' ? { alt: photo['alt'] } : {}),\n ...(typeof photo['from'] === 'string' ? { from: photo['from'] } : {}),\n },\n ]\n : []\n }),\n links: (Array.isArray(value['links']) ? value['links'] : []).flatMap((entry) => {\n const link = entry as Record<string, unknown> | null\n return link && typeof link['path'] === 'string' && typeof link['id'] === 'string' ? [{ path: link['path'], id: link['id'] }] : []\n }),\n origins: strings(value['origins']),\n ...(isLayout(value['layout']) ? { layout: value['layout'] } : {}),\n }\n}\n\n/** Whether a value is a layout as the reader writes one: its sections, icons and look. */\nfunction isLayout(value: unknown): value is SiteImportLayout {\n if (!value || typeof value !== 'object') return false\n const layout = value as Record<string, unknown>\n return (\n layout['v'] === 1 &&\n Array.isArray(layout['sections']) &&\n (layout['sections'] as unknown[]).every((section) => !!section && typeof section === 'object' && Array.isArray((section as Record<string, unknown>)['nodes'])) &&\n Array.isArray(layout['icons'])\n )\n}\n\n/*------------------------------------------\n * Words in parts a text element holds\n *-----------------------------------------*/\n\n/** A paragraph cut between sentences into parts a text element holds, every word kept in order. */\nexport function aiSiteImportTextParts(text: string, max = AI_SITE_IMPORT_TEXT_MAX_CHARS): string[] {\n const words = clean(text)\n if (words.length <= max) return words ? [words] : []\n const sentences = words.match(/[^.!?…]+(?:[.!?…]+[\"'”’)\\]]*\\s*|$)/g) ?? [words]\n const parts: string[] = []\n let part = ''\n const push = () => {\n if (part.trim()) parts.push(part.trim())\n part = ''\n }\n for (const sentence of sentences) {\n if ((part + sentence).trim().length <= max) {\n part += sentence\n continue\n }\n push()\n // One sentence longer than an element holds is cut between words.\n let rest = sentence.trim()\n while (rest.length > max) {\n const at = rest.lastIndexOf(' ', max)\n const cut = at > 0 ? at : max\n parts.push(rest.slice(0, cut).trim())\n rest = rest.slice(cut).trim()\n }\n part = rest ? `${rest} ` : ''\n }\n push()\n return parts\n}\n"],"names":["AI_SITE_IMPORT_LABEL_MAX_CHARS","AI_SITE_IMPORT_MAX_SECTIONS","siteImportLabel","AI_TEXT_LIMITS","AI_LAYOUT_IMPORTED_SECTIONS_INPUT","AI_SITE_IMPORT_TEXT_MAX_CHARS","body","AI_SITE_IMPORT_HEADLINE_MAX_CHARS","headline","AI_SITE_IMPORT_LABEL_CHARS","AI_SITE_IMPORT_DOC_MAX_NODES","AI_SITE_IMPORT_DOC_MAX_CHARS","clean","text","String","replace","trim","isLine","block","kind","url","inline","aiSiteImportDocLines","blocks","title","lines","sections","current","starts","level","length","name","push","n","section","named","Set","forEach","index","heading","map","find","unique","attempt","has","toLowerCase","slice","add","aiSiteImportLineText","line","alt","aiSiteImportWordsIn","match","aiSiteImportDocumentOf","inputs","raw","value","build","Array","isArray","flatMap","entry","region","Number","isInteger","href","strings","list","filter","photos","photo","mediaId","src","from","links","link","path","id","origins","isLayout","layout","every","aiSiteImportTextParts","max","words","sentences","parts","part","sentence","rest","at","lastIndexOf","cut"],"mappings":"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"}
@@ -15,9 +15,11 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { PluginMediaIngest } from '@aglyn/aglyn/plugin-manager/plugin-media-ingest';
18
- import type { AiSiteImportHome, AiSiteImportLook, AiSiteImportPhoto } from '../model/ai-site-import';
18
+ import { type ThemeFontFacts } from '@aglyn/aglyn/plugin-manager/plugin-theme-font-catalog';
19
+ import type { AiSiteImportHome, AiSiteImportLook, AiSiteImportPhoto, SiteImportLookFacts } from '../model/ai-site-import';
19
20
  import { type AiSiteStyle } from '../model/ai-site-look';
20
21
  import { type SiteImportCrawlSeams } from '../site-import/site-import-crawl';
22
+ import { siteImportEdgeHeadersFor, type SiteImportHeadersFor } from '../site-import/site-import-edge';
21
23
  import { aiSaveSiteTheme, aiWorkspaceSiteStyles } from './ai-job-site-look';
22
24
  import { type AiSiteInspirationSite } from './ai-site-inspiration-signals';
23
25
  import { type AiReferencePage, type PublicFetchOptions, type PublicFetchResult } from './ai-theme-brand-inputs';
@@ -27,13 +29,14 @@ export declare const AI_SITE_IMPORT_LOGO_HEIGHT = 192;
27
29
  export declare const AI_SITE_IMPORT_LOGO_MAX_BYTES: number;
28
30
  type Fetch = (url: string, options: PublicFetchOptions) => Promise<PublicFetchResult>;
29
31
  /**
30
- * The home page and its first stylesheets, read as AglynBot (AGL-4084), the
31
- * edge headers going with the page and with a stylesheet only on the page's
32
- * own host. `null` when the page cannot be read.
32
+ * The home page and its first stylesheets, read as AglynBot (AGL-4084).
33
+ * `headersFor` is asked for every request and every redirect hop, as the
34
+ * crawl asks it (`aiSiteImportLookHeaders`: the edge header only to the
35
+ * site's own origins). `null` when the page cannot be read.
33
36
  */
34
37
  export declare function readSiteImportLookPage(url: string, input: {
35
38
  fetch?: Fetch;
36
- headers?: Readonly<Record<string, string>> | null;
39
+ headersFor?: SiteImportHeadersFor | null;
37
40
  signal?: AbortSignal;
38
41
  }): Promise<AiReferencePage | null>;
39
42
  /**
@@ -45,17 +48,44 @@ export declare function readSiteImportLookPage(url: string, input: {
45
48
  * drawn in, which the theme reader would otherwise take as its brand.
46
49
  */
47
50
  export declare function aiSiteImportBrandColors(page: Pick<AiReferencePage, 'html' | 'stylesheets'>): string[];
51
+ /**
52
+ * The brand and accent a source's look facts give (AGL-4108): the fill of
53
+ * its filled buttons as the brand, the color of its links as the accent
54
+ * where it is a color of its own, and the reverse where its buttons are not
55
+ * colorful. The theme draws the brand at the nearest shade of it that reads
56
+ * (`aiSiteColors`): aglyn.com's light blue buttons, under white words at
57
+ * 2.4:1, come out at the deeper blue of its own links.
58
+ */
59
+ export declare function aiSiteImportBrandOf(facts: Pick<SiteImportLookFacts, 'buttonFill' | 'link'> | null | undefined): {
60
+ brand: string;
61
+ accent: string | null;
62
+ } | null;
48
63
  /**
49
64
  * The look a source's signals pin (AGL-4084), drawn the way a guided start's
50
65
  * is: the kind of site its own description says, the import's seed, its
51
- * strongest color as the brand. `null` where the source showed no color to
66
+ * strongest color as the brand. What the reader found of its look
67
+ * (`facts`, AGL-4108) pins it closer: its buttons' fill as the brand and its
68
+ * links' color as the accent, its page's ground, and its own fonts where the
69
+ * catalog has them (`fonts`). `null` where the source showed no color to
52
70
  * carry a brand, so the site keeps the theme it has.
53
71
  */
54
72
  export declare function aiSiteImportStyle(site: AiSiteInspirationSite | null, input: {
55
73
  seed: number;
56
74
  description: string;
57
75
  avoid?: readonly AiSiteStyle[];
76
+ facts?: SiteImportLookFacts | null;
77
+ fonts?: AiSiteStyle['sourceFonts'];
58
78
  }): AiSiteStyle | null;
79
+ /** A family's facts, as the theme font catalog answers them. */
80
+ export type AiSiteImportFontFacts = (family: string) => Promise<ThemeFontFacts | undefined>;
81
+ /**
82
+ * The source's own fonts (AGL-4108), each where the theme font catalog has
83
+ * the family (Google Fonts', as the fonts plugin registers it), or the
84
+ * source loads it from Google Fonts itself: its body's and its headings'.
85
+ * `null` where its body's family is neither, and the pairing of the source's
86
+ * type mood sets the site instead.
87
+ */
88
+ export declare function aiSiteImportSourceFonts(facts: Pick<SiteImportLookFacts, 'fonts'> | null | undefined, lookup?: AiSiteImportFontFacts): Promise<AiSiteStyle['sourceFonts']>;
59
89
  /**
60
90
  * The site's listing in the home page's own words (AGL-4084), as field
61
91
  * paths: its title and description each only where the site still has the
@@ -67,7 +97,12 @@ export declare function aiSiteImportListingUpdates(seo: unknown, displayName: un
67
97
  export type AiSiteImportRasterize = (svg: Uint8Array, height: number) => Promise<Uint8Array | null>;
68
98
  export interface AiSiteImportLookDeps {
69
99
  fetch?: Fetch;
100
+ /** The edge headers for the source, asked with its domain; absent, the edge is asked as the crawl asks it (AGL-4108). */
70
101
  headersFor?: SiteImportCrawlSeams['headersFor'];
102
+ /** The edge's own answer, per address (`siteImportEdgeHeadersFor`), where no `headersFor` is given. */
103
+ edgeHeadersFor?: typeof siteImportEdgeHeadersFor;
104
+ /** A family's facts in the theme font catalog (`themeFontFacts`). */
105
+ fontFacts?: AiSiteImportFontFacts;
71
106
  save?: typeof aiSaveSiteTheme;
72
107
  others?: typeof aiWorkspaceSiteStyles;
73
108
  ingest?: PluginMediaIngest | null;
@@ -100,7 +135,7 @@ export declare function aiSiteImportLogo(input: {
100
135
  domain: string;
101
136
  logo: NonNullable<AiSiteImportHome['brand']['logo']>;
102
137
  alt: string;
103
- headers?: Readonly<Record<string, string>> | null;
138
+ headersFor?: SiteImportHeadersFor | null;
104
139
  signal?: AbortSignal;
105
140
  }, deps: {
106
141
  fetch?: Fetch;
@@ -109,4 +144,16 @@ export declare function aiSiteImportLogo(input: {
109
144
  }): Promise<AiSiteImportPhoto | null>;
110
145
  /** The look pass (AGL-4084): the theme, the logo and the listing, from the owner's own home page. No model. */
111
146
  export declare function aiRunSiteImportLook(input: AiSiteImportLookInput, deps?: AiSiteImportLookDeps): Promise<AiSiteImportLook>;
147
+ /**
148
+ * The headers the look's reads of the source go with, per address (AGL-4108),
149
+ * exactly as the crawl's (`siteRequestHeaders`): the caller's where it hands
150
+ * them in, else the edge's own, so a site this platform serves is read past
151
+ * its challenge however the step was registered; and nothing for any address
152
+ * off the site's two origins, a redirect hop's included. Never throws.
153
+ *
154
+ * The 10/29 look read went without the header twice over: no caller handed
155
+ * one in, and the read passed headers the fetch does not take, which is why
156
+ * this is a function the fetch asks for every hop (`headersFor`).
157
+ */
158
+ export declare function aiSiteImportLookHeaders(domain: string, deps: Pick<AiSiteImportLookDeps, 'headersFor' | 'edgeHeadersFor'>): Promise<SiteImportHeadersFor>;
112
159
  export {};