@contentrain/wp-import 0.11.12 → 0.11.14

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["iso"],"sources":["../src/php-unserialize.ts","../src/core.ts","../src/wxr.ts","../src/acf.ts","../src/rest-redirects.ts","../src/rest-menus.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/delta.ts"],"sourcesContent":["// Small PHP serialize() decoder, ported from the measured import chain.\n// Supported: s (byte-length strings), i, d, b, N, a (array → list or object), O (object → { __class, … }).\n// PHP string lengths are BYTES, so the walk happens over a Buffer, not a JS string.\n\nexport interface UnserializeResult {\n ok: boolean\n serialized: boolean\n value: unknown\n error?: string\n}\n\nexport function looksSerialized(s: unknown): s is string {\n return typeof s === 'string' && /^(a|O):\\d+:[{\"]|^(s|i|d|b):[^;]+;?$|^N;$/.test(s)\n}\n\nexport function phpUnserialize(str: string): unknown {\n const buf = Buffer.from(str, 'utf8')\n let p = 0\n const fail = (m: string): never => {\n throw new Error(`unserialize: ${m} at byte ${p}`)\n }\n const readUntil = (ch: string): string => {\n const i = buf.indexOf(ch, p)\n if (i < 0) fail(`expected ${ch}`)\n const s = buf.toString('utf8', p, i)\n p = i + 1\n return s\n }\n const expect = (ch: string): void => {\n if (buf[p] !== ch.charCodeAt(0)) fail(`expected '${ch}' got '${String.fromCharCode(buf[p] ?? 0)}'`)\n p++\n }\n const value = (): unknown => {\n const t = String.fromCharCode(buf[p] ?? 0)\n p++\n switch (t) {\n case 'N':\n expect(';')\n return null\n case 'b': {\n expect(':')\n return readUntil(';') === '1'\n }\n case 'i': {\n expect(':')\n return Number(readUntil(';'))\n }\n case 'd': {\n expect(':')\n const v = readUntil(';')\n return v === 'INF' ? Infinity : v === '-INF' ? -Infinity : v === 'NAN' ? Number.NaN : Number(v)\n }\n case 's': {\n expect(':')\n const n = Number(readUntil(':'))\n expect('\"')\n const s = buf.toString('utf8', p, p + n)\n p += n\n expect('\"')\n expect(';')\n return s\n }\n case 'a': {\n expect(':')\n const n = Number(readUntil(':'))\n expect('{')\n const entries: Array<[unknown, unknown]> = []\n for (let i = 0; i < n; i++) {\n const k = value()\n const v = value()\n entries.push([k, v])\n }\n expect('}')\n // consecutive 0..n-1 integer keys → JSON list; anything else → object\n const isList = entries.every(([k], i) => k === i)\n return isList ? entries.map(([, v]) => v) : Object.fromEntries(entries.map(([k, v]) => [String(k), v]))\n }\n case 'O': {\n expect(':')\n readUntil(':')\n expect('\"')\n const cls = readUntil('\"')\n expect(':')\n const n = Number(readUntil(':'))\n expect('{')\n const o: Record<string, unknown> = { __class: cls }\n for (let i = 0; i < n; i++) {\n const k = value()\n const v = value()\n o[String(k).split('\\u0000').at(-1) ?? String(k)] = v\n }\n expect('}')\n return o\n }\n default:\n return fail(`unknown type '${t}'`)\n }\n }\n const v = value()\n if (p !== buf.length) fail(`trailing ${buf.length - p} bytes`)\n return v\n}\n\n/** Attempt a decode; on failure the value stays exactly as it was. */\nexport function tryUnserialize(s: string): UnserializeResult {\n if (!looksSerialized(s)) return { ok: false, serialized: false, value: s }\n try {\n return { ok: true, serialized: true, value: phpUnserialize(s) }\n } catch (e) {\n return { ok: false, serialized: true, value: s, error: e instanceof Error ? e.message : String(e) }\n }\n}\n","// Shared conversion helpers, ported from the measured induction core.\n// The identity formulas here are load-bearing: hexId('posts:' + slug) must\n// produce the same entry id whether the site arrived via WXR or REST, or a\n// later delta import would duplicate every entry.\n\nimport { createHash } from 'node:crypto'\nimport type { FieldDef } from '@contentrain/types'\n\nexport const norm = (s: unknown): string => String(s ?? '').replace(/\\s+/g, ' ').trim()\n\n// The same table as the starter's summarize() (templates/astro-starter/src/lib/seo.ts);\n// kept here because a package cannot depend on a template.\nconst ENTITIES: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ', hellip: '…', mdash: '—', ndash: '–', rsquo: '’', lsquo: '‘', rdquo: '”', ldquo: '“' }\n\n/**\n * Decode character references once: `&amp;lt;` is `&lt;`, not `<`. A plain-text field\n * is escaped where it is printed (Astro's text escaping), so a reference left in it\n * would print as `&amp;hellip;`. An unknown name or a code point out of range stays.\n */\nexport const decodeEntities = (s: string): string =>\n s.replace(/&(?:#(\\d+)|#x([0-9a-f]+)|([a-z]+));/gi, (m, dec?: string, hex?: string, name?: string) => {\n if (name !== undefined) return ENTITIES[name] ?? ENTITIES[name.toLowerCase()] ?? m\n const code = dec !== undefined ? Number(dec) : Number.parseInt(hex!, 16)\n try {\n return String.fromCodePoint(code)\n } catch {\n return m\n }\n })\n\n/** Plain text from markup: tags out first (so `&lt;b&gt;` survives as text), then references decoded. */\nexport const strip = (s: unknown): string => norm(decodeEntities(String(s ?? '').replace(/<[^>]*>/g, ' ')))\n\n/** Entry id: deterministic hex from a stable key (model:slug style). */\nexport const hexId = (s: string): string => createHash('sha1').update(s).digest('hex').slice(0, 24)\n\nconst sortDeep = (v: unknown): unknown =>\n Array.isArray(v)\n ? v.map(sortDeep)\n : v && typeof v === 'object'\n ? Object.fromEntries(\n Object.keys(v as Record<string, unknown>)\n .toSorted()\n .map((k) => [k, sortDeep((v as Record<string, unknown>)[k])]),\n )\n : v\n\n/** Canonical serialization: sorted keys, 2-space indent, trailing newline. */\nexport const canon = (o: unknown): string => `${JSON.stringify(sortDeep(o), null, 2)}\\n`\n\n/** Field-type inference from a value (open meta / ACF fields). */\nexport const byValue = (v: unknown): string | null => {\n if (typeof v === 'boolean') return 'boolean'\n if (typeof v === 'number') return Number.isInteger(v) ? 'integer' : 'decimal'\n if (Array.isArray(v)) return 'array'\n if (v && typeof v === 'object') return 'object'\n const s = String(v ?? '').trim()\n if (!s) return null\n if (/^https?:\\/\\/\\S+\\.(mp3|m4a|wav|pdf|zip|docx?)(\\?|$)/i.test(s)) return 'file'\n if (/^https?:\\/\\/\\S+\\.(jpe?g|png|gif|webp|avif|svg)(\\?|$)/i.test(s)) return 'image'\n if (/^https?:\\/\\//.test(s)) return 'url'\n if (/^[^@\\s]+@[^@\\s]+\\.[a-z]{2,}$/i.test(s)) return 'email'\n if (/^\\d{4}-\\d{2}-\\d{2}([T ]\\d{2}:\\d{2})/.test(s)) return 'datetime'\n if (/<[a-z][\\s\\S]*>/i.test(s)) return 'richtext'\n return s.length > 200 ? 'text' : 'string'\n}\n\n/** What `RawPost.password` holds for a protected post: the fact, never the password. */\nexport const PROTECTED = '[protected]'\n\n/**\n * WP post types that never become content models: core plumbing (`wp_*`\n * covers `wp_global_styles`, `wp_navigation`, `wp_block`, `wp_template*`),\n * Jetpack, and theme/page-builder internals that store design, not content —\n * GeneratePress elements, GenerateBlocks styles, Elementor templates and\n * Contact Form 7 / WPForms definitions. ACF field/group records stay in:\n * their cross-model parent links are part of the lossless import contract.\n * Whether a stored record gets a public route is the route producer's decision.\n */\nexport const SKIP_TYPES =\n /^(attachment|nav_menu_item|wp_|jp_|pattern|revision|oembed_cache|customize_changeset|user_request|custom_css|gblocks_|gblocks-|gp_elements|gp-elements|elementor_library|e-landing-page|wpcf7_contact_form|wpforms)/\n\n/** Open meta keys that are plugin plumbing, not editorial fields. */\nexport const PLUGIN_META = /^(jetpack|wpdc|discourse|footnotes|inline_featured|spay_|advanced_seo|rank_math|yoast)/i\n\n/** WP core/plumbing meta keys (never editorial). */\nexport const CORE_META =\n /^(_edit_last|_edit_lock|_thumbnail_id|_wp_page_template|_wp_old_slug|_wp_attached_file|_wp_attachment_metadata|_wp_attachment_image_alt|_wp_attachment_backup_sizes|_wp_desired_post_slug|_wp_trash_meta_.*|_menu_item_.*|_oembed_.*|_publicize_.*|_wpas_.*|_pingme|_encloseme|enclosure|_last_editor_used_jetpack|_rest_api_.*|_wp_attachment_context|_wp_attachment_is_custom_header|_wp_attachment_is_custom_background|_customize_.*|_elementor_.*|_wpcom_.*|_wp_suggested_privacy_policy_content|geo_.*|_jetpack_.*|_links_to.*|_format_.*)$/\n\n/** Taxonomy → model id. */\nexport const taxModelId = (t: string): string =>\n t === 'post_tag' ? 'tags' : t === 'category' ? 'categories' : t.replace(/_/g, '-')\n\nexport const slugify = (s: unknown): string =>\n String(s ?? '')\n .normalize('NFKD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n/**\n * A WordPress `post_name` as the address it is: percent-encoded UTF-8 decoded, NFC, lowercase, anything outside letters,\n * digits and marks (the contract's slug alphabet) a hyphen. Nothing is transliterated: `日本語`, `ışık` and `straße`\n * stay what the source site served, because the slug is the page's address. ASCII comes out exactly as `slugify`\n * gives it. Empty when nothing of a word is left, or when the slug would not fit a file name (200 bytes).\n */\nexport const addressSlug = (raw: string): string => {\n const slug = decodeSlug(raw)\n .normalize('NFC')\n .toLowerCase()\n .normalize('NFC')\n .replace(/[^\\p{Ll}\\p{Lo}\\p{Lm}\\p{N}\\p{M}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n return new TextEncoder().encode(slug).length > 200 ? '' : slug\n}\n\nexport const decodeSlug = (s: string): string => {\n try {\n return decodeURIComponent(s)\n } catch {\n return s\n }\n}\n\n/** The measured core field skeleton for content models (same order/labels). */\nexport function coreFields(opts: {\n excerpt: boolean\n body: boolean\n date: boolean\n author: boolean\n taxes: string[]\n cover: boolean\n}): { fields: Record<string, FieldDef>; order: number } {\n const fields: Record<string, FieldDef> = {\n title: { type: 'string', required: true, label: 'Title', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n }\n let o = 30\n if (opts.excerpt) fields.excerpt = { type: 'text', label: 'Excerpt', order: (o += 10) }\n if (opts.body) fields.body = { type: 'richtext', label: 'Body', order: (o += 10) }\n if (opts.date) fields.published_at = { type: 'datetime', label: 'Published at', order: (o += 10) }\n if (opts.author) fields.author = { type: 'relation', model: 'authors', label: 'Author', order: (o += 10) }\n for (const t of opts.taxes) fields[taxModelId(t)] = { type: 'relations', model: taxModelId(t), label: t, order: (o += 10) }\n if (opts.cover) fields.cover = { type: 'relation', model: 'media', label: 'Cover', order: (o += 10) }\n return { fields, order: o }\n}\n","// WXR (WordPress eXtended RSS) → RawIR.\n//\n// Streaming (sax) parse: a 100 MB export holds only its records in memory,\n// never the XML. Ported from the measured import chain — the state machine,\n// the meta decoding, and the resolution passes are the parts three sessions\n// of corpus work already debugged; they are transliterated, not redesigned.\n\nimport sax from 'sax'\nimport type { Readable } from 'node:stream'\nimport type {\n RawIR,\n RawPost,\n RawLanguagePair,\n RawAttachment,\n RawAuthor,\n RawComment,\n RawMenu,\n RawMenuItem,\n RawMenuTarget,\n RawTerm,\n RawTermRef,\n RawAcfValue,\n} from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { tryUnserialize } from './php-unserialize.js'\nimport { strip, PROTECTED } from './core.js'\n\nexport interface WxrStats {\n serialized: { detected: number; decoded: number; failed: number; keys: string[] }\n acf_fields: number\n unresolved_terms: number\n counts: Record<string, number>\n}\n\nexport interface WxrParseResult {\n raw: RawIR\n stats: WxrStats\n}\n\ninterface XItem {\n [k: string]: unknown\n terms: Array<{ taxonomy: string; slug: string; name?: string }>\n postmeta: Array<{ key?: string; value?: string }>\n comments: Array<Record<string, string | Array<{ key?: string; value?: string }>>>\n}\n\nconst ts = (s: string | undefined): string | null =>\n !s || s.startsWith('0000-00-00') ? null : s.replace(' ', 'T')\nconst iso = (local: string | undefined, gmt: string | undefined): string | null =>\n gmt && !gmt.startsWith('0000') ? `${ts(gmt)}Z` : ts(local)\nconst num = (s: unknown): number => (s === '' || s == null ? 0 : Number(s))\nconst termKey = (tax: string, slug: string): string => `${tax}:${slug}`\n\nexport async function parseWxr(input: string | Readable, opts?: { tool?: string }): Promise<WxrParseResult> {\n const site: Record<string, unknown> = {}\n const authors: Array<Record<string, string>> = []\n const terms: Array<Record<string, string>> = []\n const items: XItem[] = []\n const stats: WxrStats = {\n serialized: { detected: 0, decoded: 0, failed: 0, keys: [] },\n acf_fields: 0,\n unresolved_terms: 0,\n counts: {},\n }\n const serializedKeySet = new Set<string>()\n\n // ── sax state machine (ported verbatim) ──\n const parser = sax.createStream(true, { trim: false })\n const path: string[] = []\n let text = ''\n let item: XItem | null = null\n let meta: { key?: string; value?: string } | null = null\n let comment: Record<string, string | Array<{ key?: string; value?: string }>> | null = null\n let cmeta: { key?: string; value?: string } | null = null\n let author: Record<string, string> | null = null\n let term: (Record<string, string> & { _tag?: string }) | null = null\n const channelText: Record<string, string> = {}\n\n const leaf = (name: string, into: Record<string, unknown>, map: Record<string, string>): void => {\n const target = map[name]\n if (target) into[target] = text\n }\n parser.on('opentag', (node) => {\n path.push(node.name)\n text = ''\n const n = node.name\n if (n === 'item') item = { terms: [], postmeta: [], comments: [] }\n else if (n === 'wp:postmeta') meta = {}\n else if (n === 'wp:comment') comment = { meta: [] }\n else if (n === 'wp:commentmeta') cmeta = {}\n else if (n === 'wp:author') author = {}\n else if (n === 'wp:category' || n === 'wp:tag' || n === 'wp:term') term = { _tag: n }\n else if (n === 'category' && item) {\n const attrs = node.attributes as Record<string, string>\n item.terms.push({ taxonomy: attrs.domain ?? '', slug: attrs.nicename ?? '' })\n }\n })\n parser.on('text', (t) => {\n text += t\n })\n parser.on('cdata', (t) => {\n text += t\n })\n parser.on('comment', (c) => {\n const m = /generator=\"([^\"]*)\"\\s+created=\"([^\"]*)\"/.exec(c)\n if (m) {\n site.generator = m[1]\n site.export_date = m[2]\n }\n })\n parser.on('closetag', (n) => {\n const parent = path[path.length - 2]\n if (cmeta) {\n if (n === 'wp:meta_key') cmeta.key = text\n else if (n === 'wp:meta_value') cmeta.value = text\n else if (n === 'wp:commentmeta') {\n ;(comment!.meta as Array<{ key?: string; value?: string }>).push(cmeta)\n cmeta = null\n }\n } else if (comment) {\n const map: Record<string, string> = {\n 'wp:comment_id': 'id',\n 'wp:comment_author': 'author',\n 'wp:comment_author_email': 'email',\n 'wp:comment_author_url': 'url',\n 'wp:comment_date': 'date',\n 'wp:comment_date_gmt': 'date_gmt',\n 'wp:comment_content': 'content',\n 'wp:comment_approved': 'approved',\n 'wp:comment_type': 'type',\n 'wp:comment_parent': 'parent',\n 'wp:comment_user_id': 'user_id',\n }\n leaf(n, comment, map)\n if (n === 'wp:comment') {\n item!.comments.push(comment)\n comment = null\n }\n } else if (meta) {\n if (n === 'wp:meta_key') meta.key = text\n else if (n === 'wp:meta_value') meta.value = text\n else if (n === 'wp:postmeta') {\n item!.postmeta.push(meta)\n meta = null\n }\n } else if (item) {\n if (n === 'category') {\n const t = item.terms.at(-1)\n if (t) t.name = text\n } else {\n const map: Record<string, string> = {\n title: 'title',\n link: 'link',\n 'dc:creator': 'author',\n guid: 'guid',\n description: 'description',\n 'content:encoded': 'content',\n 'excerpt:encoded': 'excerpt',\n 'wp:post_id': 'id',\n 'wp:post_date': 'date',\n 'wp:post_date_gmt': 'date_gmt',\n 'wp:post_modified': 'modified',\n 'wp:post_modified_gmt': 'modified_gmt',\n 'wp:comment_status': 'comment_status',\n 'wp:ping_status': 'ping_status',\n 'wp:post_name': 'slug',\n 'wp:status': 'status',\n 'wp:post_parent': 'parent',\n 'wp:menu_order': 'menu_order',\n 'wp:post_type': 'type',\n 'wp:post_password': 'password',\n 'wp:is_sticky': 'sticky',\n 'wp:attachment_url': 'attachment_url',\n }\n leaf(n, item, map)\n if (n === 'item') {\n items.push(item)\n item = null\n }\n }\n } else if (author) {\n leaf(n, author, {\n 'wp:author_id': 'id',\n 'wp:author_login': 'login',\n 'wp:author_email': 'email',\n 'wp:author_display_name': 'display_name',\n 'wp:author_first_name': 'first_name',\n 'wp:author_last_name': 'last_name',\n })\n if (n === 'wp:author') {\n authors.push(author)\n author = null\n }\n } else if (term) {\n leaf(n, term, {\n 'wp:term_id': 'id',\n 'wp:category_nicename': 'slug',\n 'wp:category_parent': 'parent',\n 'wp:cat_name': 'name',\n 'wp:category_description': 'description',\n 'wp:tag_slug': 'slug',\n 'wp:tag_name': 'name',\n 'wp:tag_description': 'description',\n 'wp:term_taxonomy': 'taxonomy',\n 'wp:term_slug': 'slug',\n 'wp:term_parent': 'parent',\n 'wp:term_name': 'name',\n 'wp:term_description': 'description',\n })\n if (n === term._tag) {\n term.taxonomy = term._tag === 'wp:category' ? 'category' : term._tag === 'wp:tag' ? 'post_tag' : (term.taxonomy ?? '')\n delete term._tag\n terms.push(term)\n term = null\n }\n } else if (parent === 'channel') {\n leaf(n, channelText, {\n title: 'title',\n link: 'link',\n description: 'description',\n language: 'language',\n 'wp:wxr_version': 'wxr_version',\n 'wp:base_site_url': 'base_site_url',\n 'wp:base_blog_url': 'base_blog_url',\n })\n }\n path.pop()\n text = ''\n })\n\n await new Promise<void>((resolve, reject) => {\n parser.on('end', () => resolve())\n parser.on('error', reject)\n if (typeof input === 'string') {\n parser.end(input)\n } else {\n input.pipe(parser)\n }\n })\n Object.assign(site, channelText)\n\n // ── post-processing: meta decode, ACF pairing, entity split, resolution flags ──\n const decodeMeta = (list: Array<{ key?: string; value?: string }>): { meta: Record<string, unknown>; serializedKeys: string[] } => {\n const out: Record<string, unknown> = {}\n const serializedKeys: string[] = []\n for (const { key, value } of list) {\n if (!key) continue\n const r = tryUnserialize(value ?? '')\n if (r.serialized) {\n stats.serialized.detected++\n serializedKeySet.add(key)\n if (r.ok) {\n stats.serialized.decoded++\n serializedKeys.push(key)\n } else stats.serialized.failed++\n }\n const v = r.ok ? r.value : (value ?? '')\n out[key] = key in out ? ([] as unknown[]).concat(out[key] as unknown[], [v]) : v\n }\n return { meta: out, serializedKeys }\n }\n const extractAcf = (metaObj: Record<string, unknown>): Record<string, RawAcfValue> => {\n const acf: Record<string, RawAcfValue> = {}\n for (const [k, v] of Object.entries(metaObj)) {\n if (k.startsWith('_') && typeof v === 'string' && /^field_[0-9a-f]+$/.test(v) && k.slice(1) in metaObj) {\n acf[k.slice(1)] = { value: metaObj[k.slice(1)], field_key: v }\n }\n }\n return acf\n }\n\n const termSet = new Set(terms.map((t) => termKey(t.taxonomy ?? '', t.slug ?? '')))\n\n interface Rec extends RawPost {\n attachment_url: string | null\n _comments: RawComment[]\n }\n const records: Rec[] = items.map((it) => {\n const { meta: m, serializedKeys } = decodeMeta(it.postmeta)\n const acf = extractAcf(m)\n stats.acf_fields += Object.keys(acf).length\n const id = num(it.id)\n const termRefs: RawTermRef[] = it.terms.map((t) => ({\n taxonomy: t.taxonomy,\n slug: t.slug,\n name: t.name ?? '',\n resolved: termSet.has(termKey(t.taxonomy, t.slug)),\n }))\n const comments: RawComment[] = it.comments.map((c) => ({\n id: num(c.id),\n post: id,\n post_type: (it.type as string) || 'post',\n parent: num(c.parent) || null,\n parent_resolved: null,\n author: (c.author as string) ?? '',\n email: (c.email as string) || null,\n url: (c.url as string) || null,\n date: iso(c.date as string, c.date_gmt as string),\n date_gmt: ts(c.date_gmt as string),\n content: (c.content as string) ?? '',\n approved: (c.approved as string | undefined) ?? '1',\n type: (c.type as string) || 'comment',\n user_id: num(c.user_id) || null,\n meta: decodeMeta((c.meta as Array<{ key?: string; value?: string }>) ?? []).meta,\n }))\n return {\n id,\n type: (it.type as string) || 'post',\n status: (it.status as string) || 'publish',\n slug: (it.slug as string) || '',\n title: (it.title as string) ?? '',\n link: (it.link as string) || null,\n guid: (it.guid as string) || null,\n author: (it.author as string) || null,\n date: iso(it.date as string, it.date_gmt as string),\n modified: iso(it.modified as string, it.modified_gmt as string),\n content: (it.content as string) ?? '',\n excerpt: (it.excerpt as string) ?? '',\n parent: num(it.parent) || null,\n menu_order: num(it.menu_order),\n sticky: it.sticky === '1',\n password: it.password ? PROTECTED : null,\n comment_status: (it.comment_status as string) || null,\n ping_status: (it.ping_status as string) || null,\n terms: termRefs,\n meta: m,\n serialized_keys: serializedKeys,\n acf,\n // Polylang exports a post's language as a `language` taxonomy term.\n lang: termRefs.find((t) => t.taxonomy === 'language')?.slug || null,\n attachment_url: (it.attachment_url as string) || null,\n _comments: comments,\n }\n })\n for (const r of records) {\n for (const t of r.terms) if (!t.resolved && r.type !== 'nav_menu_item') stats.unresolved_terms++\n }\n\n const byId = new Map(records.map((r) => [r.id, r]))\n const posts: RawPost[] = records\n .filter((r) => r.type !== 'attachment' && r.type !== 'nav_menu_item')\n .map(({ attachment_url: _a, _comments: _c, ...p }) => p)\n // Polylang groups translations under a shared `post_translations` term\n // (`pll_…`); every post in a group is a translation of the others.\n const groups = new Map<string, RawPost[]>()\n for (const p of posts) {\n const group = p.terms.find((t) => t.taxonomy === 'post_translations')?.slug\n if (!group) continue\n groups.set(group, [...(groups.get(group) ?? []), p])\n }\n const languagePairs: RawLanguagePair[] = []\n for (const members of groups.values()) {\n const translations: Record<string, number> = {}\n for (const m of members) if (m.lang) translations[m.lang] = m.id\n if (Object.keys(translations).length > 1) languagePairs.push({ post: members[0]!.id, translations })\n }\n const attachments: RawAttachment[] = records\n .filter((r) => r.type === 'attachment')\n .map((r) => ({\n id: r.id,\n title: r.title,\n slug: r.slug,\n url: r.attachment_url ?? r.guid ?? null,\n alt: typeof r.meta._wp_attachment_image_alt === 'string' ? r.meta._wp_attachment_image_alt : '',\n caption: r.excerpt,\n description: r.content,\n file: typeof r.meta._wp_attached_file === 'string' ? r.meta._wp_attached_file : null,\n image_meta: r.meta._wp_attachment_metadata ?? null,\n mime: guessMime(r.attachment_url ?? r.guid ?? ''),\n parent: r.parent,\n parent_resolved: r.parent ? byId.has(r.parent) : null,\n // The attachment page (`<link>`), where the site serves one.\n // Kept only when there is no parent or the parent is public: the page sits under the parent's address.\n link: !r.parent || (byId.get(r.parent)?.status === 'publish' && !byId.get(r.parent)?.password) ? (r.link || null) : null,\n author: r.author,\n date: r.date,\n status: r.status,\n meta: r.meta,\n }))\n\n // ── menus: nav_menu terms + nav_menu_item posts (targets from meta) ──\n const postById = new Map(posts.map((p) => [p.id, p]))\n const termByIdNum = new Map(terms.map((t) => [num(t.id), t]))\n const menus: RawMenu[] = terms\n .filter((t) => t.taxonomy === 'nav_menu')\n .map((mt) => ({ id: num(mt.id) || null, slug: mt.slug ?? '', name: mt.name ?? '', items: [] as RawMenuItem[] }))\n const menuBySlug = new Map(menus.map((m) => [m.slug, m]))\n for (const r of records.filter((x) => x.type === 'nav_menu_item')) {\n const m = r.meta\n const type = m._menu_item_type as string | undefined\n const object = m._menu_item_object as string | undefined\n const objectId = num(m._menu_item_object_id)\n let target: RawMenuTarget\n if (type === 'custom') target = { kind: 'url', url: String(m._menu_item_url ?? ''), resolved: true }\n else if (type === 'post_type') {\n const p = postById.get(objectId)\n target = { kind: 'post', post_type: object ?? '', id: objectId || null, slug: p?.slug ?? null, resolved: !!p }\n } else if (type === 'taxonomy') {\n const t = termByIdNum.get(objectId)\n target = { kind: 'term', taxonomy: object ?? '', id: objectId || null, slug: t?.slug ?? null, resolved: !!t }\n } else if (type === 'post_type_archive') target = { kind: 'archive', post_type: object ?? '', resolved: true }\n else target = { kind: 'unknown', resolved: false }\n const parent = num(m._menu_item_menu_item_parent) || null\n const itemRec: RawMenuItem = {\n id: r.id,\n title: r.title || (('slug' in target && target.slug) || '') || '',\n order: r.menu_order,\n parent,\n url: (m._menu_item_url as string) || null,\n target,\n target_attr: (m._menu_item_target as string) || null,\n classes: ([] as string[]).concat((m._menu_item_classes as string[]) ?? []).filter(Boolean),\n description: r.content,\n status: r.status,\n }\n const menuSlug = r.terms.find((t) => t.taxonomy === 'nav_menu')?.slug\n const menu = menuSlug ? menuBySlug.get(menuSlug) : undefined\n if (menu) menu.items.push(itemRec)\n }\n const allMenuItemIds = new Set(menus.flatMap((m) => m.items.map((i) => i.id)))\n for (const m of menus) {\n for (const i of m.items) if (i.parent && !allMenuItemIds.has(i.parent)) i.parent_unresolved = true\n }\n\n // ── comments: threaded, parent resolution within the same post ──\n const comments: RawComment[] = []\n for (const r of records) {\n const ids = new Set(r._comments.map((c) => c.id))\n for (const c of r._comments) comments.push({ ...c, parent_resolved: c.parent ? ids.has(c.parent) : null })\n }\n\n const rawAuthors: RawAuthor[] = authors.map((a) => ({\n id: num(a.id) || null,\n login: a.login ?? '',\n email: a.email || null,\n display_name: a.display_name || a.login || '',\n first_name: a.first_name || null,\n last_name: a.last_name || null,\n }))\n const rawTerms: RawTerm[] = terms\n .filter((t) => t.taxonomy !== 'nav_menu')\n .map((t) => ({\n id: num(t.id) || null,\n taxonomy: t.taxonomy ?? '',\n slug: t.slug ?? '',\n name: t.name ?? '',\n parent: t.parent || null,\n parent_resolved: t.parent ? termSet.has(termKey(t.taxonomy ?? '', t.parent)) : null,\n description: t.description || '',\n }))\n\n stats.serialized.keys = [...serializedKeySet].toSorted()\n stats.counts = {\n items: records.length,\n posts: posts.length,\n attachments: attachments.length,\n terms: rawTerms.length,\n authors: rawAuthors.length,\n menus: menus.length,\n comments: comments.length,\n }\n\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind: 'wxr', tool: opts?.tool ?? '@contentrain/wp-import' },\n site: {\n url: String(site.link ?? channelText.link ?? ''),\n title: strip(channelText.title),\n description: strip(channelText.description) || undefined,\n base_site_url: channelText.base_site_url,\n base_blog_url: channelText.base_blog_url,\n language: channelText.language ?? null,\n generator: (site.generator as string) ?? null,\n export_date: (site.export_date as string) ?? null,\n wxr_version: channelText.wxr_version ?? null,\n },\n authors: rawAuthors,\n terms: rawTerms,\n posts,\n attachments,\n menus,\n comments,\n ...(languagePairs.length ? { language_pairs: languagePairs } : {}),\n }\n return { raw, stats }\n}\n\nconst MIME: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp3: 'audio/mpeg',\n mp4: 'video/mp4',\n pdf: 'application/pdf',\n}\nfunction guessMime(u: string): string | null {\n const e = (u.split('?')[0]?.split('.').pop() ?? '').toLowerCase()\n return MIME[e] ?? null\n}\n","// ACF / Secure Custom Fields → Contentrain field types. One deterministic, versioned table.\n//\n// The ACF type is read from the source where it is stated — SCF's REST `<name>_source.type`, a\n// Bridge export's field schema — and only inferred from the value's shape when nothing states it\n// (plain ACF REST, WXR meta). Content is never retyped: a value is carried, converted to the shape its\n// Contentrain type promises (an image object becomes its URL, a link its `{ url, title, target }`).\n//\n// Relations (post object, relationship, taxonomy, user, gallery, page link) are resolved by the\n// caller, which knows the store's entry ids; this module says which kind of reference each one is.\n\nimport type { FieldDef, FieldType } from '@contentrain/types'\nimport { byValue, strip } from './core.js'\n\n/** Table version: bump when a mapping changes, so a store says which rules made it. */\nexport const ACF_MAPPING_VERSION = 1\n\n/** ACF types that never carry content (layout) or must never be read (secrets). */\nexport const ACF_LAYOUT_TYPES = new Set(['tab', 'accordion', 'message'])\nexport const ACF_SECRET_TYPES = new Set(['password'])\n\n/**\n * ACF type → Contentrain type, for types whose value maps without a lookup.\n * `select` with `multiple` and `checkbox` are arrays of their options; see `acfFieldDef`.\n */\nexport const ACF_SCALAR_TYPES: Readonly<Record<string, FieldType>> = {\n text: 'string',\n textarea: 'text',\n wysiwyg: 'richtext',\n email: 'email',\n url: 'url',\n oembed: 'url',\n number: 'number',\n range: 'number',\n true_false: 'boolean',\n date_picker: 'date',\n date_time_picker: 'datetime',\n time_picker: 'string',\n color_picker: 'color',\n icon_picker: 'icon',\n select: 'select',\n radio: 'select',\n button_group: 'select',\n image: 'image',\n file: 'file',\n}\n\n/** References the caller resolves to store entries. */\nexport type AcfReference = 'post' | 'term' | 'user' | 'media' | 'address'\nexport const ACF_REFERENCE_TYPES: Readonly<Record<string, AcfReference>> = {\n post_object: 'post',\n relationship: 'post',\n taxonomy: 'term',\n user: 'user',\n gallery: 'media',\n page_link: 'address',\n}\n\n/**\n * Names that mean a secret whatever the field's type, for sources that do not state the type: whole words\n * of the name (`user_pass`, `apiKey`, `client-secret`), so `passage_text` or `compass` stay content.\n */\nconst SECRET_NAME = /(?:^|_)(?:pass(?:word|wd)?|secret|token|api_?key|private_?key|credentials?)(?:_|$)/i\nconst secretName = (name: string): boolean => SECRET_NAME.test(name.replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/-/g, '_'))\n\n/** Whether a field must never be read: a secret by type, or — when the type is unknown — by name. */\nexport function acfIsSecret(name: string, type: string | undefined): boolean {\n if (type) return ACF_SECRET_TYPES.has(type)\n return secretName(name)\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\nconst SOURCE = '_source'\n/** The ACF type SCF states for a sub-field of a row or group (`<name>_source.type`). */\nconst statedType = (row: Record<string, unknown>, k: string): string | undefined => {\n const s = row[`${k}${SOURCE}`]\n return isRecord(s) && typeof s.type === 'string' ? s.type : undefined\n}\n/** A sub-field that carries nothing to keep: a secret (stated, or by name) or a layout field. */\nconst droppedKey = (row: Record<string, unknown>, k: string): boolean => {\n const t = statedType(row, k)\n return (t !== undefined && ACF_LAYOUT_TYPES.has(t)) || acfIsSecret(k, t)\n}\n\n/**\n * An ACF value with every secret sub-field removed, at any depth: repeater rows, groups, flexible layouts.\n * A sub-field's `_source` keeps only its type and label — its `formatted_value` repeats the value.\n */\nexport function acfScrub(value: unknown, secret: ReadonlySet<string> = new Set()): unknown {\n if (Array.isArray(value)) {\n // Rows of one repeater or layout share their sub-fields: a key one row states as secret is secret in every row.\n const rows = value.filter(isRecord)\n const shared = new Set([...secret, ...rows.flatMap((r) => Object.keys(r).filter((k) => !k.endsWith(SOURCE) && droppedKey(r, k)))])\n return value.map((v) => acfScrub(v, shared))\n }\n if (!isRecord(value)) return value\n const gone = (k: string) => secret.has(k) || droppedKey(value, k)\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (k.endsWith(SOURCE) && k.length > SOURCE.length) {\n const base = k.slice(0, -SOURCE.length)\n if (gone(base) || !isRecord(v)) continue\n out[k] = { ...(typeof v.type === 'string' ? { type: v.type } : {}), ...(typeof v.label === 'string' ? { label: v.label } : {}) }\n continue\n }\n if (gone(k)) continue\n out[k] = acfScrub(v)\n }\n return out\n}\n/** ACF's image/file array (`return_format: array`): `{ ID, url, filename, … }`. */\nconst isAttachment = (v: unknown): v is { url: string } => isRecord(v) && typeof v.url === 'string' && ('ID' in v || 'id' in v) && ('filename' in v || 'mime_type' in v)\nconst isLink = (v: unknown): v is { url: string; title?: string; target?: string } => isRecord(v) && typeof v.url === 'string' && 'title' in v && 'target' in v && Object.keys(v).length <= 3\nconst isMap = (v: unknown): boolean => isRecord(v) && typeof v.lat === 'number' && typeof v.lng === 'number'\n/** A date picker's stored value (`Ymd`) → ISO date. */\nconst ymd = (v: unknown): string | null => (typeof v === 'string' && /^\\d{8}$/.test(v) ? `${v.slice(0, 4)}-${v.slice(4, 6)}-${v.slice(6, 8)}` : null)\n/** `Y-m-d H:i:s` → ISO local datetime (site time: WordPress stores it without a zone). */\nconst dt = (v: unknown): string | null => (typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(v) ? v.replace(' ', 'T') : null)\n\nconst pad = (n: number): string => String(Math.floor(n)).padStart(2, '0')\n/** Minutes east of UTC → `+03:00`. */\nconst offsetText = (minutes: number): string => `${minutes < 0 ? '-' : '+'}${pad(Math.abs(minutes) / 60)}:${pad(Math.abs(minutes) % 60)}`\n\n/** The offset of an IANA zone at a wall-clock time there (DST included), in minutes east of UTC; `null` for an unknown zone. */\nfunction zoneOffset(local: string, timeZone: string): number | null {\n let fmt: Intl.DateTimeFormat\n try { fmt = new Intl.DateTimeFormat('en-US', { timeZone, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }) } catch { return null }\n const wall = Date.parse(`${local}Z`)\n const at = (utc: number): number => {\n const p = Object.fromEntries(fmt.formatToParts(new Date(utc)).map((x) => [x.type, x.value]))\n return (Date.UTC(Number(p.year), Number(p.month) - 1, Number(p.day), Number(p.hour), Number(p.minute), Number(p.second)) - utc) / 60000\n }\n // The offset at the instant the wall time names: guess with the wall time read as UTC, then correct once.\n const first = at(wall)\n return at(wall - first * 60000)\n}\n\n/** How a site's local date-times get their zone. */\nexport interface AcfZone {\n /** IANA zone (`timezone_string`); wins over `gmtOffset`. */\n timeZone?: string | null\n /** Fixed offset in hours (`gmt_offset`). */\n gmtOffset?: number | null\n}\n\n/** A local ISO datetime with the site's offset for that moment; the local value when the site's zone is unknown. */\nexport function zonedDateTime(local: string, zone: AcfZone = {}): { value: string; zoned: boolean } {\n const tz = zone.timeZone ? zoneOffset(local, zone.timeZone) : null\n const minutes = tz ?? (typeof zone.gmtOffset === 'number' && Number.isFinite(zone.gmtOffset) ? Math.round(zone.gmtOffset * 60) : null)\n return minutes === null ? { value: local, zoned: false } : { value: `${local}${offsetText(minutes)}`, zoned: true }\n}\n\nconst LINK_FIELDS: Record<string, FieldDef> = { url: { type: 'url' }, title: { type: 'string' }, target: { type: 'string' } }\nconst MAP_FIELDS: Record<string, FieldDef> = { address: { type: 'string' }, lat: { type: 'decimal' }, lng: { type: 'decimal' }, zoom: { type: 'integer' } }\n\n/** Contentrain type of a sub-value whose ACF type is not stated (a repeater row, a group member). */\nfunction inferDef(value: unknown): FieldDef | null {\n if (value === null || value === undefined || value === '') return null\n if (isAttachment(value)) return { type: /\\.(jpe?g|png|gif|webp|avif|svg)(\\?|$)/i.test(value.url) ? 'image' : 'file' }\n if (isLink(value)) return { type: 'object', fields: LINK_FIELDS }\n if (isMap(value)) return { type: 'object', fields: MAP_FIELDS }\n if (Array.isArray(value)) {\n if (value.every(isRecord)) return { type: 'array', items: { type: 'object', fields: rowFields(value as Record<string, unknown>[]) } }\n const item = value.map(inferDef).find(Boolean)\n return { type: 'array', items: item?.type === 'object' ? item : (item?.type ?? 'string') }\n }\n if (isRecord(value)) return { type: 'object', fields: rowFields([value]) }\n if (ymd(value)) return { type: 'date' }\n const t = byValue(value)\n return t ? { type: t as FieldType } : null\n}\n\n/**\n * The union of the fields every row states; a name typed two ways falls back to `string`. A sub-field whose ACF\n * type the row states (SCF's `<name>_source`) is typed by the table like a top-level field; a reference inside a\n * row is not resolved, so it — and any sub-field without a stated type — is typed from its value.\n */\nfunction rowFields(rows: Record<string, unknown>[]): Record<string, FieldDef> {\n const out: Record<string, FieldDef> = {}\n for (const row of rows) {\n for (const [k, v] of Object.entries(row)) {\n if (k.endsWith(SOURCE) || droppedKey(row, k)) continue\n const stated = statedType(row, k)\n const source = row[`${k}${SOURCE}`]\n const label = isRecord(source) && typeof source.label === 'string' ? source.label : undefined\n const d = stated && !ACF_REFERENCE_TYPES[stated] ? acfFieldDef(k, v, { type: stated, ...(label ? { label } : {}) }) : inferDef(v)\n if (!d) continue\n const seen = out[k]\n if (!seen) out[k] = d\n else if (seen.type !== d.type) out[k] = { type: 'string' }\n }\n }\n return out\n}\n\nexport interface AcfValueContext extends AcfZone {\n /** Called for a stored value outside its field's stated choices: it is left out, not kept as free text. */\n dropped?: (value: unknown, options: readonly string[]) => void\n /** Called for a date-time written without a zone, because the site's zone is unknown. */\n unzoned?: (value: string) => void\n}\n\n/** A value in the shape its field definition promises; `undefined` = nothing to store. */\nexport function acfValue(def: FieldDef, value: unknown, ctx: AcfValueContext = {}): unknown {\n if (value === null || value === undefined || value === '' || (Array.isArray(value) && !value.length)) return undefined\n switch (def.type) {\n case 'image':\n case 'file':\n case 'video':\n return isAttachment(value) ? value.url : typeof value === 'string' ? value : undefined\n case 'date':\n return ymd(value) ?? (typeof value === 'string' ? value : undefined)\n case 'datetime': {\n const local = dt(value)\n if (!local) return typeof value === 'string' ? value : undefined\n const out = zonedDateTime(local, ctx)\n if (!out.zoned) ctx.unzoned?.(out.value)\n return out.value\n }\n case 'boolean':\n return value === true || value === 1 || value === '1'\n case 'number':\n case 'integer':\n case 'decimal':\n return typeof value === 'number' ? value : typeof value === 'string' && value.trim() !== '' && !Number.isNaN(Number(value)) ? Number(value) : undefined\n case 'icon':\n return isRecord(value) && typeof value.value === 'string' ? value.value : typeof value === 'string' ? value : undefined\n case 'object': {\n if (!isRecord(value)) return undefined\n const out: Record<string, unknown> = {}\n for (const [k, sub] of Object.entries(def.fields ?? {})) {\n // Another row may have typed the name; this one says it is a secret.\n if (droppedKey(value, k)) continue\n const v = acfValue(sub, value[k], ctx)\n if (v !== undefined) out[k] = v\n }\n return Object.keys(out).length ? out : undefined\n }\n case 'array': {\n if (!Array.isArray(value)) return undefined\n const item: FieldDef = typeof def.items === 'string' ? { type: def.items as FieldType } : (def.items ?? { type: 'string' })\n const out = value.map((v) => acfValue(item, v, ctx)).filter((v) => v !== undefined)\n return out.length ? out : undefined\n }\n case 'select': {\n const v = typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n // A value the field no longer offers (the choice was removed after it was saved): not a valid select value.\n if (v !== undefined && def.options?.length && !def.options.includes(v)) {\n ctx.dropped?.(v, def.options)\n return undefined\n }\n return v\n }\n case 'richtext':\n case 'text':\n case 'string':\n case 'url':\n case 'email':\n case 'color':\n return typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n default:\n return value\n }\n}\n\nexport interface AcfStated {\n /** ACF type as the source states it (`_source.type`, Bridge schema); absent = infer from the value. */\n type?: string\n label?: string\n /** Choices of a select/radio/checkbox/button group, when the source states them. */\n choices?: string[]\n multiple?: boolean\n}\n\n/**\n * Field definition for one ACF field value, or `null` when it carries no content, is a secret, or is a\n * reference (the caller resolves those: see `ACF_REFERENCE_TYPES`).\n */\nexport function acfFieldDef(name: string, value: unknown, stated: AcfStated = {}): FieldDef | null {\n const t = stated.type\n if (t && (ACF_LAYOUT_TYPES.has(t) || ACF_REFERENCE_TYPES[t])) return null\n if (acfIsSecret(name, t)) return null\n const label = stated.label ? strip(stated.label) : undefined\n const withLabel = (d: FieldDef): FieldDef => (label ? { ...d, label } : d)\n if (!t) {\n const inferred = inferDef(value)\n return inferred ? withLabel({ ...inferred, description: 'ACF (type inferred from the value)' }) : null\n }\n const choices = stated.choices?.length ? stated.choices : undefined\n if (t === 'checkbox' || (t === 'select' && (stated.multiple || Array.isArray(value)))) {\n return withLabel({ type: 'array', items: choices ? { type: 'select', options: choices } : 'string' })\n }\n if (ACF_SCALAR_TYPES[t]) {\n const type = ACF_SCALAR_TYPES[t]!\n if (type === 'select') return withLabel(choices ? { type, options: choices } : { type: 'string' })\n return withLabel({ type })\n }\n if (t === 'link') return withLabel({ type: 'object', fields: LINK_FIELDS })\n if (t === 'google_map') return withLabel({ type: 'object', fields: MAP_FIELDS })\n if (t === 'group') return withLabel({ type: 'object', fields: rowFields(isRecord(value) ? [value] : []) })\n if (t === 'repeater') return withLabel({ type: 'array', items: { type: 'object', fields: rowFields(Array.isArray(value) ? value.filter(isRecord) : []) } })\n if (t === 'flexible_content') {\n // One row per layout instance, in order; `layout` names which layout made it, the rest is the union of their fields.\n const rows = Array.isArray(value) ? value.filter(isRecord) : []\n const fields = rowFields(rows.map(({ acf_fc_layout: _l, ...rest }) => rest))\n const layouts = [...new Set(rows.map((r) => String(r.acf_fc_layout ?? '')).filter(Boolean))].toSorted()\n return withLabel({ type: 'array', items: { type: 'object', fields: { layout: { type: 'select', options: layouts, required: true }, ...fields } } })\n }\n // An ACF type this table does not know (a third-party field type): infer, and say so.\n const inferred = inferDef(value)\n return inferred ? withLabel({ ...inferred, description: `ACF ${t} (type inferred from the value)` }) : null\n}\n\n/** Merge two definitions of the same field seen on different entries (union of object fields and options). */\nexport function mergeFieldDef(a: FieldDef, b: FieldDef): FieldDef {\n if (a.type !== b.type) return a\n const out: FieldDef = { ...a }\n if (a.options || b.options) out.options = [...new Set([...(a.options ?? []), ...(b.options ?? [])])].toSorted()\n if (a.fields || b.fields) {\n const fields: Record<string, FieldDef> = { ...a.fields }\n for (const [k, d] of Object.entries(b.fields ?? {})) fields[k] = fields[k] ? mergeFieldDef(fields[k]!, d) : d\n out.fields = fields\n }\n if (typeof a.items === 'object' && typeof b.items === 'object') out.items = mergeFieldDef(a.items, b.items)\n return out\n}\n\n/** Flexible content rows keep their layout name under `layout`. */\nexport function acfRows(value: unknown): unknown {\n return Array.isArray(value) ? value.map((r) => (isRecord(r) && 'acf_fc_layout' in r ? (({ acf_fc_layout, ...rest }) => ({ layout: acf_fc_layout, ...rest }))(r) : r)) : value\n}\n","// Redirect rules over REST → RawRedirect[] / RawRedirectExcluded[].\n//\n// REST reaches one source: the Redirection plugin (`redirection/v1`), with an application password of a user who\n// may manage it. Yoast Premium, Rank Math, Safe Redirect Manager and `.htaccess` keep their rules where REST cannot\n// read them — only the Bridge export does. The rules are shaped exactly as the Bridge shapes Redirection's\n// (`class-contentrain-bridge-redirects.php`): every rule lands in `redirects` (the site serves it) or `excluded`\n// (with the reason), so the two together account for the plugin's whole table.\n\nimport type { RawRedirect, RawRedirectExcluded, RawRedirectQuery } from '@contentrain/types'\n\n/** A rule as `redirection/v1/redirect` lists it. */\nexport interface RestRedirection {\n id: number\n url?: string\n regex?: boolean\n group_id?: number\n enabled?: boolean\n /** Older releases state `status: 'enabled' | 'disabled'` instead of `enabled`. */\n status?: string\n action_type?: string\n action_code?: number | string\n action_data?: { url?: string } | string | null\n match_type?: string\n match_data?: { source?: { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown; flag_regex?: unknown } } | null\n}\n\n/**\n * Redirection's site-wide defaults (`redirection/v1/setting`, which answers them merged over the plugin's own): a\n * rule without its own flags takes these.\n */\nexport interface RestRedirectionOptions { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown }\n\n/** Redirection's own defaults, under a site that states none. */\nconst DEFAULTS = { flag_query: 'exact', flag_case: false, flag_trailing: false } as const\n\n/** A group as `redirection/v1/group` lists it. `module_id`: 1 WordPress, 2 Apache, 3 nginx. */\nexport interface RestRedirectionGroup { id: number; module_id?: number; enabled?: boolean; status?: string }\n\nconst MODULES: Record<number, string> = { 2: 'apache', 3: 'nginx' }\n/** Codes that say an address is gone: served as that answer, with no target. */\nconst GONE = new Set([410, 451])\n/** Redirection's query modes; `exactorder` (the same parameters in the same order) is read as `exact`. */\nconst QUERY: Record<string, RawRedirectQuery> = { exact: 'exact', exactorder: 'exact', ignore: 'ignore', pass: 'pass' }\n\ntype Flags = { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown }\n/** The flags one layer states, as Redirection accepts them: a known query mode, a true boolean (not `\"1\"`). */\nconst valid = (f: Flags | undefined): Flags => ({\n ...(typeof f?.flag_query === 'string' && f.flag_query in QUERY ? { flag_query: f.flag_query } : {}),\n ...(typeof f?.flag_case === 'boolean' ? { flag_case: f.flag_case } : {}),\n ...(typeof f?.flag_trailing === 'boolean' ? { flag_trailing: f.flag_trailing } : {}),\n})\n\n/** A login rule's two addresses, and nothing else its data may hold. */\nconst loginCondition = (data: unknown): { logged_in: string, logged_out: string } | null => {\n if (!data || typeof data !== 'object') return null\n const d = data as Record<string, unknown>\n return { logged_in: typeof d.logged_in === 'string' ? d.logged_in : '', logged_out: typeof d.logged_out === 'string' ? d.logged_out : '' }\n}\n\n/** By id as bytes, as the Bridge sorts (`strcmp`). */\nconst order = (a: { id?: string }, b: { id?: string }): number => ((a.id ?? '') < (b.id ?? '') ? -1 : (a.id ?? '') > (b.id ?? '') ? 1 : 0)\n\nconst on = (x: { enabled?: boolean; status?: string }): boolean => (x.enabled ?? (x.status === undefined || x.status === 'enabled'))\n\n/** Same-site targets become root-relative, like every `from`; other hosts stay absolute (as the Bridge does). */\nfunction relative(url: string, origin: string): string {\n try {\n const home = new URL(origin)\n const u = new URL(url, `${origin}/`)\n if (u.host.toLowerCase() !== home.host.toLowerCase()) return url\n return `${u.pathname}${u.search}${u.hash}`\n } catch { return url }\n}\n\n/**\n * Redirection's rules and groups → the rules the site serves and the ones it does not, sorted by id.\n * A rule's query, case and trailing-slash modes are what Redirection applies to it: its own flags, else the site's\n * (`options`), else the plugin's defaults. Without `options` (not readable) only a rule's own flags are stated.\n */\nexport function redirectionRules(items: RestRedirection[], groups: RestRedirectionGroup[], origin: string, options?: RestRedirectionOptions): { redirects: RawRedirect[]; excluded: RawRedirectExcluded[] } {\n const site: Flags = options ? { ...DEFAULTS, ...valid(options) } : {}\n const byId = new Map(groups.map((g) => [g.id, g]))\n const redirects: RawRedirect[] = []\n const excluded: RawRedirectExcluded[] = []\n for (const item of items) {\n const group = item.group_id === undefined ? undefined : byId.get(item.group_id)\n const code = Number(item.action_code ?? 301)\n const data = item.action_data\n const target = typeof data === 'string' ? data : (data?.url ?? '')\n const own = item.match_data?.source ?? {}\n const flags = { ...site, ...valid(own) }\n // Without `to`: an excluded rule carries none, as the Bridge's; a served one gets its own below.\n const rule: Omit<RawRedirect, 'to'> & { id: string; source: string } = { id: `redirection:${item.id}`, from: item.url ?? '', source: 'redirection', match: 'url', regex: item.regex === true || own.flag_regex === true }\n const served = group?.module_id !== undefined ? MODULES[group.module_id] : undefined\n if (served) rule.served_by = served\n // A regular expression matches the query as written: Redirection compares it exactly.\n if (rule.regex) rule.query = 'exact'\n else if (typeof flags.flag_query === 'string') rule.query = QUERY[flags.flag_query]\n if (typeof flags.flag_case === 'boolean') rule.case_insensitive = flags.flag_case\n if (typeof flags.flag_trailing === 'boolean') rule.trailing_slash = flags.flag_trailing ? 'ignore' : 'exact'\n const matchType = item.match_type ?? 'url'\n const actionType = item.action_type ?? 'url'\n if (!on(item) || (group && !on(group))) {\n excluded.push({ ...rule, reason: 'disabled' })\n } else if (actionType === 'error' && GONE.has(code) && matchType === 'url') {\n // \"Gone\" (410) and \"unavailable for legal reasons\" (451): the address answers that, and leads nowhere.\n redirects.push({ ...rule, to: '', status: code })\n } else if (actionType !== 'url') {\n // A 404 error, pass-through, \"do nothing\", random post: not a from→to rule.\n excluded.push({ ...rule, status: code, reason: `not-a-redirect:${actionType}` })\n } else if (matchType !== 'url') {\n // Login, referrer, agent, cookie, header, IP, server…: the target depends on the request.\n // Its own match type (`login`), as the Bridge states it. Only a login rule keeps its condition (two addresses):\n // a cookie, header, IP, role, agent or server condition holds the very value a visitor must present — often a\n // secret — and never leaves the site; its type is in the reason.\n excluded.push({ ...rule, match: matchType, status: code, ...(matchType === 'login' ? { condition: loginCondition(data) } : {}), reason: `conditional-match:${matchType}` })\n } else {\n const move = code >= 300 && code < 400\n redirects.push({ ...rule, to: relative(target, origin), status: move ? code : 301, ...(move ? {} : { status_note: `source status ${code} is not a redirect code; 301 assumed` }) })\n }\n }\n return { redirects: redirects.toSorted(order), excluded: excluded.toSorted(order) }\n}\n","// Menus over REST → RawMenu[].\n//\n// Two sources, both behind `edit_theme_options` (an application password):\n// - classic menus: `/wp/v2/menus` (with the theme locations each is assigned to) and `/wp/v2/menu-items`;\n// - block-theme navigation: published `wp_navigation` posts, whose block markup is the menu. A block\n// menu's location is the template part (`header` / `footer`) that references it — or, for a\n// navigation block without a `ref`, the most recent published one, which is what WordPress shows;\n// - inline navigation: a navigation block in a template part that carries its own links (Twenty\n// Twenty-Five's footer columns). It is a menu of that part's area, with no WordPress record behind it.\n// Only template parts a template uses count: a theme ships alternatives (`footer-columns`, `header-large-title`)\n// that no page shows. Block menu items, and inline menus, have no ids of their own; they get negative ids,\n// unique within the import, so they can never collide with a WordPress id.\n\nimport type { RawMenu, RawMenuItem, RawMenuTarget } from '@contentrain/types'\nimport { strip } from './core.js'\n\nexport interface RestMenu { id: number; name?: string; slug?: string; locations?: string[] }\n\nexport interface RestMenuItem {\n id: number\n title?: { rendered?: string; raw?: string }\n status?: string\n url?: string\n description?: string\n type?: string\n object?: string\n object_id?: number\n parent?: number\n menu_order?: number\n target?: string\n classes?: string[]\n menus?: number\n}\n\nexport interface RestNavigation {\n id: number\n slug?: string\n date_gmt?: string\n status?: string\n title?: { rendered?: string; raw?: string }\n content?: { raw?: string }\n}\n\nexport interface RestTemplatePart { slug?: string; area?: string; title?: { rendered?: string; raw?: string }; content?: { raw?: string } }\nexport interface RestTemplate { slug?: string; content?: { raw?: string } }\n\n/** What a target is checked against: the posts and terms this import read. */\nexport interface MenuContext {\n origin: string\n /**\n * Slug of a post this import read and saw published and unprotected — the only kind a menu item may\n * point at. Anything else (a draft, a private or scheduled post, one behind a password, or one this\n * import never read: a type outside REST, past a page cap) is left out, fail-closed: a menu item's label\n * is often its target's title, and that title must not reach the store.\n */\n postSlug: (id: number) => string | undefined\n termSlug: (taxonomy: string, id: number) => string | undefined\n /**\n * Public address of such a post or term. A menu item that names one points there, whatever address the item\n * kept: a block stores the url it had when it was saved (`/old-about/`), and a typed `?page_id=5` is a form the\n * migrated site cannot serve.\n */\n postLink?: (id: number) => string | undefined\n termLink?: (taxonomy: string, id: number) => string | undefined\n /** Published pages, for `core/page-list` (id, parent, order, title, link). */\n pages: Array<{ id: number; parent: number | null; menu_order: number; title: string; link: string | null; slug: string }>\n}\n\nconst targetOf = (kind: string | undefined, object: string | undefined, id: number | undefined, url: string | undefined, ctx: MenuContext): RawMenuTarget => {\n const objectId = id && id > 0 ? id : null\n if (kind === 'post_type' && object) {\n const slug = objectId ? ctx.postSlug(objectId) : undefined\n return { kind: 'post', post_type: object, id: objectId, slug: slug ?? null, resolved: slug !== undefined }\n }\n if (kind === 'taxonomy' && object) {\n const slug = objectId ? ctx.termSlug(object, objectId) : undefined\n return { kind: 'term', taxonomy: object, id: objectId, slug: slug ?? null, resolved: slug !== undefined }\n }\n if (kind === 'post_type_archive' && object) return { kind: 'archive', post_type: object, resolved: true }\n if (url) return { kind: 'url', url, resolved: true }\n return { kind: 'unknown', resolved: false }\n}\n\n/** The public address of the post or term a target names, when it is one this import proved public. */\nconst publicLink = (target: RawMenuTarget, ctx: MenuContext): string | undefined => {\n if (!target.resolved || !('id' in target) || !target.id) return undefined\n if (target.kind === 'post') return ctx.postLink?.(target.id)\n if (target.kind === 'term') return ctx.termLink?.(target.taxonomy, target.id)\n return undefined\n}\n\n/**\n * Items that are left out: a draft item, or one whose post target is not proven visible. Their children move up\n * to the nearest kept ancestor, as WordPress's walker shows them.\n */\nfunction hiddenItems(items: RestMenuItem[], drop: (i: RestMenuItem) => boolean): { gone: Set<number>; lift: (parent: number | null) => number | null } {\n const parentOf = new Map(items.filter(drop).map((i) => [i.id, i.parent || null]))\n const lift = (parent: number | null): number | null => {\n const seen = new Set<number>()\n let p = parent\n while (p !== null && parentOf.has(p) && !seen.has(p)) { seen.add(p); p = parentOf.get(p) ?? null }\n return p\n }\n return { gone: new Set(parentOf.keys()), lift }\n}\n\n/** A host without case or a leading `www.`: example.com and www.example.com are one site (as the Bridge reads it). */\nconst bareHost = (u: URL): string => u.hostname.toLowerCase().replace(/^www\\./, '')\n\n/**\n * The post a plain permalink names (`/?page_id=14`, `/?p=14`) on this site, `www.` or not: a custom link typed by\n * hand carries no post id, but it points at a post all the same, and its label is often that post's title.\n */\nexport function plainPostId(url: string | undefined, origin: string): number | undefined {\n if (!url || !url.includes('?')) return undefined\n try {\n const u = new URL(url, `${origin}/`)\n if (bareHost(u) !== bareHost(new URL(origin))) return undefined\n const id = Number(u.searchParams.get('page_id') ?? u.searchParams.get('p'))\n return Number.isSafeInteger(id) && id > 0 ? id : undefined\n } catch { return undefined }\n}\n\n/** Classic menus and their items; each menu names the theme locations it is assigned to. `dropped` counts left-out items. */\nexport function classicMenus(menus: RestMenu[], items: RestMenuItem[], ctx: MenuContext, dropped = { count: 0 }): RawMenu[] {\n const out: RawMenu[] = []\n for (const m of [...menus].toSorted((a, b) => a.id - b.id)) {\n const all = items.filter((i) => i.menus === m.id).toSorted((a, b) => (a.menu_order ?? 0) - (b.menu_order ?? 0) || a.id - b.id)\n const hidden = (i: RestMenuItem): boolean => {\n if ((i.status ?? 'publish') !== 'publish') return true\n if (i.type === 'post_type') return !(i.object_id && ctx.postSlug(i.object_id))\n // A custom link to `?page_id=` / `?p=` names a post: the same proof applies.\n const id = plainPostId(i.url, ctx.origin)\n return id !== undefined && !ctx.postSlug(id)\n }\n const { gone, lift } = hiddenItems(all, hidden)\n dropped.count += gone.size\n const own = all.filter((i) => !gone.has(i.id))\n const ids = new Set(own.map((i) => i.id))\n const menu: RawMenu = {\n id: m.id,\n slug: m.slug ?? '',\n name: strip(m.name ?? m.slug ?? ''),\n items: own.map((i) => {\n const target = targetOf(i.type, i.object, i.object_id, i.url, ctx)\n const typed = target.kind === 'url' ? plainPostId(i.url, ctx.origin) : undefined\n const item: RawMenuItem = {\n id: i.id,\n title: i.title?.raw || i.title?.rendered || '',\n order: i.menu_order ?? 0,\n parent: lift(i.parent || null),\n url: publicLink(target, ctx) ?? (typed !== undefined ? ctx.postLink?.(typed) : undefined) ?? (i.url || null),\n target,\n target_attr: i.target || null,\n classes: (i.classes ?? []).filter(Boolean),\n description: i.description ?? '',\n status: i.status ?? 'publish',\n }\n if (item.parent && !ids.has(item.parent)) item.parent_unresolved = true\n return item\n }),\n }\n const locations = (m.locations ?? []).filter(Boolean).toSorted()\n if (locations.length) menu.locations = locations\n out.push(menu)\n }\n return out\n}\n\n// ── Block navigation ─────────────────────────────────────────────────────────\n\ninterface Block { name: string; attrs: Record<string, unknown>; children: Block[] }\n\n/** Serialized block comments (`<!-- wp:name {attrs} /-->`, `<!-- /wp:name -->`). Same grammar as the facts builder parser. */\nconst BLOCK_TOKEN = /<!--\\s+(\\/)?wp:([a-z][a-z0-9_-]*\\/)?([a-z][a-z0-9_-]*)\\s+({(?:(?!}\\s+\\/?-->)[\\s\\S])*?}\\s+)?(\\/)?-->/g\n\nexport function parseBlocks(content: string): Block[] {\n const root: Block = { name: 'root', attrs: {}, children: [] }\n const stack: Block[] = [root]\n const token = new RegExp(BLOCK_TOKEN.source, 'g')\n let m: RegExpExecArray | null\n while ((m = token.exec(content))) {\n const [, closer, ns, local, json, selfClose] = m\n if (closer) {\n if (stack.length > 1) stack.pop()\n continue\n }\n let attrs: Record<string, unknown> = {}\n if (json) {\n try { attrs = JSON.parse(json) as Record<string, unknown> } catch { attrs = {} }\n }\n const block: Block = { name: `${ns ? ns.slice(0, -1) : 'core'}/${local}`, attrs, children: [] }\n stack[stack.length - 1]!.children.push(block)\n if (!selfClose) stack.push(block)\n }\n return root.children\n}\n\nconst str = (v: unknown): string | undefined => (typeof v === 'string' && v ? v : undefined)\nconst absolute = (url: string | undefined, origin: string): string | undefined => {\n if (!url) return undefined\n // `#` (a placeholder link) stays on the page it is on; made absolute it would point at the home page.\n if (url.startsWith('#')) return url\n try { return new URL(url, `${origin}/`).href } catch { return url }\n}\n/** The block editor's link kinds → the classic menu item types. */\nconst KIND: Record<string, string> = { 'post-type': 'post_type', taxonomy: 'taxonomy', custom: 'custom' }\n\n/**\n * Menu items of one `wp_navigation` body. Links and submenus become items; a page list becomes the\n * published pages it lists; a home link points at `/`. Other blocks (search, social icons, spacers) are not links.\n */\nexport function navigationItems(content: string, ctx: MenuContext, nextId: () => number, dropped = { count: 0 }): RawMenuItem[] {\n return blockItems(parseBlocks(content), ctx, nextId, dropped)\n}\n\n/** Menu items of navigation blocks already parsed (a `wp_navigation` body, or an inline navigation's links). */\nfunction blockItems(tree: Block[], ctx: MenuContext, nextId: () => number, dropped: { count: number }): RawMenuItem[] {\n const items: RawMenuItem[] = []\n const push = (b: { title: string; url?: string; kind?: string; object?: string; id?: number; typed?: number; newTab?: boolean; className?: string; description?: string }, parent: number | null): number => {\n const id = nextId()\n const url = absolute(b.url, ctx.origin)\n const target = targetOf(b.kind, b.object, b.id, url, ctx)\n items.push({\n id,\n title: b.title,\n order: items.length + 1,\n parent,\n // A public post or term is linked at its public address (see `MenuContext.postLink`).\n url: publicLink(target, ctx) ?? (b.typed !== undefined ? ctx.postLink?.(b.typed) : undefined) ?? url ?? null,\n target,\n target_attr: b.newTab ? '_blank' : null,\n classes: (b.className ?? '').split(/\\s+/).filter(Boolean),\n description: b.description ?? '',\n status: 'publish',\n })\n return id\n }\n const pageList = (parentPage: number, parent: number | null) => {\n const kids = ctx.pages.filter((p) => (p.parent ?? 0) === parentPage).toSorted((a, b) => a.menu_order - b.menu_order || a.title.localeCompare(b.title))\n for (const p of kids) {\n const id = push({ title: p.title, url: p.link ?? undefined, kind: 'post_type', object: 'page', id: p.id }, parent)\n pageList(p.id, id)\n }\n }\n const walk = (blocks: Block[], parent: number | null) => {\n for (const b of blocks) {\n const a = b.attrs\n if (b.name === 'core/navigation-link' || b.name === 'core/navigation-submenu') {\n const kind = KIND[str(a.kind) ?? ''] ?? (str(a.type) === 'category' || str(a.type) === 'tag' || str(a.type) === 'post_tag' ? 'taxonomy' : a.id ? 'post_type' : 'custom')\n const object = kind === 'taxonomy' && str(a.type) === 'tag' ? 'post_tag' : str(a.type)\n // A link to a post not proven visible is left out (fail-closed); its children show in its place. A custom link\n // to `?page_id=` / `?p=` names a post too.\n const postId = kind === 'post_type' && typeof a.id === 'number' ? a.id : kind === 'custom' ? plainPostId(str(a.url), ctx.origin) : undefined\n if (postId !== undefined && !ctx.postSlug(postId)) {\n dropped.count++\n walk(b.children, parent)\n continue\n }\n const id = push({ title: strip(a.label), url: str(a.url), kind, object, id: typeof a.id === 'number' ? a.id : undefined, typed: kind === 'custom' ? postId : undefined, newTab: a.opensInNewTab === true, className: str(a.className), description: str(a.description) }, parent)\n walk(b.children, id)\n } else if (b.name === 'core/home-link') {\n push({ title: strip(a.label) || 'Home', url: '/', className: str(a.className) }, parent)\n } else if (b.name === 'core/page-list') {\n pageList(typeof a.parentPageID === 'number' ? a.parentPageID : 0, parent)\n } else {\n walk(b.children, parent)\n }\n }\n }\n walk(tree, null)\n return items\n}\n\n/** Template-part slugs the templates use, at any depth (a part inside a group, a part inside a part is not followed). */\nfunction partSlugs(blocks: Block[], out = new Set<string>()): Set<string> {\n for (const b of blocks) {\n if (b.name === 'core/template-part' && typeof b.attrs.slug === 'string') out.add(b.attrs.slug)\n partSlugs(b.children, out)\n }\n return out\n}\n\n/**\n * The template parts a page can show: those a template references. Without the templates (not readable), the\n * part named after its area (`header`, `footer`) — what a theme's templates use unless they say otherwise.\n * Parts without a slug (older callers) all count.\n */\nexport function usedParts(parts: RestTemplatePart[], templates: RestTemplate[] = []): RestTemplatePart[] {\n const used = new Set<string>()\n for (const t of templates) if (t.content?.raw) partSlugs(parseBlocks(t.content.raw), used)\n return parts.filter((p) => !p.slug || (used.size ? used.has(p.slug) : p.slug === p.area))\n}\n\nconst AREA_ORDER = ['header', 'footer']\nconst areaOf = (p: RestTemplatePart): string | undefined => (p.area && p.area !== 'uncategorized' ? p.area : undefined)\n\n/**\n * A part's blocks with the parts it holds in their place (a header holding a `navigation` part), each part once:\n * what the part shows, in its area.\n */\nfunction partTree(part: RestTemplatePart, all: RestTemplatePart[]): Block[] {\n const bySlug = new Map(all.filter((p) => p.slug).map((p) => [p.slug!, p]))\n const seen = new Set(part.slug ? [part.slug] : [])\n const expand = (blocks: Block[]): Block[] => blocks.flatMap((b) => {\n if (b.name === 'core/template-part') {\n const inner = typeof b.attrs.slug === 'string' ? bySlug.get(b.attrs.slug) : undefined\n if (!inner?.content?.raw || seen.has(inner.slug!)) return []\n seen.add(inner.slug!)\n return expand(parseBlocks(inner.content.raw))\n }\n return [{ ...b, children: expand(b.children) }]\n })\n return expand(parseBlocks(part.content?.raw ?? ''))\n}\nconst titleCase = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1)\nconst slugOf = (s: string): string => s.toLowerCase().normalize('NFKD').replace(/[̀-ͯ]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')\n\n/**\n * Inline navigations of the used template parts → RawMenu[], in area order (header, footer, others) and document\n * order within a part. A part's single inline navigation is named after its area (`Footer navigation`), several\n * are numbered; a navigation's own `ariaLabel` wins. Links keep their order and nesting; a link to content not\n * proven public is left out, as in every other menu.\n */\nexport function inlineMenus(parts: RestTemplatePart[], ctx: MenuContext, taken: Set<string>, nextId: () => number, dropped = { count: 0 }, all: RestTemplatePart[] = parts): RawMenu[] {\n const out: RawMenu[] = []\n const ordered = parts.filter((p) => areaOf(p) && p.content?.raw).toSorted((a, b) => (AREA_ORDER.indexOf(areaOf(a)!) + 1 || 99) - (AREA_ORDER.indexOf(areaOf(b)!) + 1 || 99))\n for (const p of ordered) {\n const area = areaOf(p)!\n const navs: Block[] = []\n const find = (blocks: Block[]) => { for (const b of blocks) { if (b.name === 'core/navigation') { if (typeof b.attrs.ref !== 'number' && b.children.length) navs.push(b) } else find(b.children) } }\n find(partTree(p, all))\n navs.forEach((nav, i) => {\n const name = strip(nav.attrs.ariaLabel) || `${titleCase(area)} navigation${navs.length > 1 ? ` ${i + 1}` : ''}`\n const base = slugOf(name) || `${area}-navigation`\n let slug = base\n for (let k = 2; taken.has(slug); k++) slug = `${base}-${k}`\n taken.add(slug)\n const items = blockItems(nav.children, ctx, nextId, dropped)\n if (items.length) out.push({ id: nextId(), slug, name, items, locations: [area] })\n })\n }\n return out\n}\n\n/**\n * Where each navigation is shown: the template parts (`header`, `footer`) whose navigation block\n * refers to it. An empty navigation block without a `ref` shows the fallback — the most recent published one;\n * one with links of its own shows those (an inline menu, not a `wp_navigation` post).\n */\nexport function navigationLocations(parts: RestTemplatePart[], navigations: RestNavigation[], all: RestTemplatePart[] = parts): Map<number, string[]> {\n const out = new Map<number, Set<string>>()\n const fallback = [...navigations].toSorted((a, b) => (b.date_gmt ?? '').localeCompare(a.date_gmt ?? '') || b.id - a.id)[0]?.id\n const find = (blocks: Block[], area: string) => {\n for (const b of blocks) {\n if (b.name === 'core/navigation') {\n // No ref and links of its own: an inline navigation, not any wp_navigation post. No ref, empty: the fallback.\n const ref = typeof b.attrs.ref === 'number' ? b.attrs.ref : b.children.length ? undefined : fallback\n if (ref !== undefined) (out.get(ref) ?? out.set(ref, new Set()).get(ref)!).add(area)\n continue\n }\n find(b.children, area)\n }\n }\n for (const p of parts) {\n const area = areaOf(p)\n if (area && p.content?.raw) find(partTree(p, all), area)\n }\n return new Map([...out].map(([id, set]) => [id, [...set].toSorted()]))\n}\n\n/**\n * Published `wp_navigation` posts, then the inline navigations of the used template parts → RawMenu[], slugs kept\n * unique against the classic menus already read. `templates` says which parts are used (see `usedParts`).\n */\nexport function blockMenus(navigations: RestNavigation[], allParts: RestTemplatePart[], ctx: MenuContext, taken: Set<string>, dropped = { count: 0 }, templates: RestTemplate[] = []): RawMenu[] {\n const parts = usedParts(allParts, templates)\n const published = navigations.filter((n) => (n.status ?? 'publish') === 'publish').toSorted((a, b) => a.id - b.id)\n const locations = navigationLocations(parts, published, allParts)\n let next = 0\n const out: RawMenu[] = []\n for (const n of published) {\n let slug = n.slug || `navigation-${n.id}`\n while (taken.has(slug)) slug = `${slug}-nav`\n taken.add(slug)\n const menu: RawMenu = {\n id: n.id,\n slug,\n name: strip(n.title?.raw || n.title?.rendered || '') || slug,\n items: navigationItems(n.content?.raw ?? '', ctx, () => -++next, dropped),\n }\n const where = locations.get(n.id)\n if (where?.length) menu.locations = where\n out.push(menu)\n }\n out.push(...inlineMenus(parts, ctx, taken, () => -++next, dropped, allParts))\n return out\n}\n","// Public/authenticated WordPress REST → RawIR.\n//\n// The lowest rungs of the source-access ladder. What REST cannot see (rest:false\n// CPTs, unregistered meta; menus without an application password) is absent from the result —\n// absence at a low rung is information, not an error, and the manifest layer\n// decides what to recommend about it.\n\nimport type { RawAcfValue, RawIR, RawAttachment, RawComment, RawLanguagePair, RawMenu, RawPost, RawRedirect, RawRedirectExcluded, RawTerm, RawTermRef, SourceAccessKind } from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { strip, SKIP_TYPES, PROTECTED } from './core.js'\nimport { acfIsSecret, acfScrub } from './acf.js'\nimport { redirectionRules, type RestRedirection, type RestRedirectionGroup, type RestRedirectionOptions } from './rest-redirects.js'\nimport { blockMenus, classicMenus, type MenuContext, type RestMenu, type RestMenuItem, type RestNavigation, type RestTemplate, type RestTemplatePart } from './rest-menus.js'\n\nconst iso = (gmt: string | undefined): string | null => (gmt ? `${gmt}Z` : null)\nconst approvedOf = (status: string | undefined): RawComment['approved'] =>\n status === 'approved' ? '1' : status === 'hold' ? '0' : status === 'spam' ? 'spam' : status === 'trash' ? 'trash' : (status ?? '1')\n\nexport interface RestImportOptions {\n origin: string\n /** Injectable for tests and for hosts that need custom dispatch. */\n fetchImpl?: typeof fetch\n /**\n * WordPress Application Password credentials — lifts the rung to rest_auth.\n * With them, post types are listed with every non-trash status\n * (`AUTH_POST_STATUSES`) in the edit context, and comments with held ones\n * too; anonymous REST only ever returns published posts and approved\n * comments. A credential the site refuses for that falls back to the\n * public listing, with a warning.\n */\n auth?: { user: string; appPassword: string }\n perPage?: number\n /**\n * Requests in flight at once, across every collection. Default 4. A site\n * with 74 pages of posts, 40 of media and 37 of comments used to receive\n * ~150 simultaneous requests — enough to trip a host's rate limit or WAF.\n */\n concurrency?: number\n /**\n * Pages fetched per collection at most. Unset = all. A truncated collection\n * is named in `warnings` (with what was skipped), never silently shortened.\n */\n maxPages?: number\n tool?: string\n}\n\nexport interface RestImportResult {\n raw: RawIR\n warnings: string[]\n /**\n * Whether the credential was honoured, for callers that must act on it\n * without reading `warnings`. `none`: no `auth` given. `accepted`: every\n * listing it unlocks was read with it. `rejected`: at least one was not —\n * `fell_back` names each (`posts`, `pages`, a CPT's rest base, `comments`,\n * `comments:hold`), and those came from the public listing instead, or not\n * at all for `comments:hold`, which has none.\n */\n credential: { status: 'none' | 'accepted' | 'rejected'; fell_back: string[] }\n /**\n * What this rung could not read, as codes a caller can act on (the text is in `warnings`).\n * `menus_require_auth`: menus and block navigation are only readable with an application password\n * of a user who may edit theme options — none was given, the site rejected it, or it lacks that right.\n * `redirects_partial`: always, over REST — it reads only the Redirection plugin's rules; Yoast Premium, Rank Math,\n * Safe Redirect Manager and `.htaccess` keep theirs where only the Bridge export reads them.\n * `redirects_require_auth`: the site runs Redirection, and its rules need an application password of a user who\n * may manage it — none was given, the site rejected it, or it lacks that right.\n * `acf_partial`: the site runs ACF / Secure Custom Fields; REST shows only the field groups set to\n * `show_in_rest` (off by default) and no options page — the Bridge export reads the rest. Where the site\n * states no field types (plain ACF, no `<name>_source`), a secret field is recognised by its name only.\n */\n gaps: string[]\n}\n\ninterface RestPost {\n id: number\n slug: string\n status?: string\n type?: string\n link?: string\n title?: { rendered?: string }\n content?: { rendered?: string }\n excerpt?: { rendered?: string }\n date_gmt?: string\n modified_gmt?: string\n author?: number\n parent?: number\n menu_order?: number\n sticky?: boolean\n /** Edit context only. */\n password?: string\n comment_status?: string\n ping_status?: string\n featured_media?: number\n categories?: number[]\n tags?: number[]\n meta?: Record<string, unknown>\n /**\n * ACF / SCF fields of the groups shown in REST (`show_in_rest`). SCF adds `<name>_source`\n * (`{ type, label, formatted_value }`) beside each value; plain ACF sends the value only.\n */\n acf?: Record<string, unknown> | unknown[]\n /** Polylang: language slug of the post and its translation group (`{ en: 12, tr: 34 }`, self included). */\n lang?: string\n translations?: Record<string, number>\n /** WPML: locale of the post and its other translations. */\n wpml_current_locale?: string\n wpml_translations?: Array<{ locale?: string; id?: number }>\n}\n\n/** What a credential lists beyond `publish`: drafts, scheduled, in-review and private posts. Trash stays out. */\nexport const AUTH_POST_STATUSES = ['publish', 'future', 'draft', 'pending', 'private'] as const\n/** Comment listings for a credential: WP's `status` takes one value, so approved and held are two requests. */\nconst AUTH_COMMENT_STATUSES = ['approve', 'hold'] as const\nconst DENIED = new Set([400, 401, 403])\n/** REST taxonomies that hold no content: menus, block-pattern categories, multilingual bookkeeping. */\nconst NOT_CONTENT_TAXONOMIES = new Set(['category', 'post_tag', 'nav_menu', 'wp_pattern_category', 'post_format', 'language', 'post_translations', 'term_language', 'term_translations'])\n/** A comment listing's name in `credential.fell_back`: `comments` (approved) or `comments:hold`. */\nconst commentKey = (status: string): string => (status === 'approve' ? 'comments' : `comments:${status}`)\n\n/**\n * ACF fields of one REST post. `<name>_source` (SCF) states each field's type and label; a secret — a\n * `password` field, or, when no type is stated, a field named like one — is never read. ACF answers `[]`\n * for a post with no field group in REST.\n */\nfunction acfOf(acf: RestPost['acf']): { acf?: Record<string, RawAcfValue> } {\n if (!acf || Array.isArray(acf) || typeof acf !== 'object') return {}\n const out: Record<string, RawAcfValue> = {}\n for (const [name, value] of Object.entries(acf)) {\n if (name.endsWith('_source') && name.slice(0, -'_source'.length) in acf) continue\n const source = acf[`${name}_source`] as { type?: unknown; label?: unknown } | undefined\n const type = typeof source?.type === 'string' ? source.type : undefined\n if (acfIsSecret(name, type)) continue\n out[name] = { value: acfScrub(value), ...(type ? { type } : {}), ...(typeof source?.label === 'string' && source.label ? { label: source.label } : {}) }\n }\n return Object.keys(out).length ? { acf: out } : {}\n}\n\n/** What a visitor can open: published, not behind a post password. */\nconst visible = (p: RawPost): boolean => p.status === 'publish' && !p.password\n\nconst positiveInteger = (name: string, value: number): number => {\n if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${name} must be a positive safe integer`)\n return value\n}\n\nexport async function fetchRestRawIR(options: RestImportOptions): Promise<RestImportResult> {\n const origin = options.origin.replace(/\\/$/, '')\n const doFetch = options.fetchImpl ?? fetch\n const perPage = positiveInteger('perPage', options.perPage ?? 100)\n if (perPage > 100) throw new RangeError('perPage must be at most 100')\n const concurrency = positiveInteger('concurrency', options.concurrency ?? 4)\n const maxPages = options.maxPages !== undefined ? positiveInteger('maxPages', options.maxPages) : undefined\n const warnings: string[] = []\n // One pool for the whole import: page fetches of every collection queue here,\n // so the cap holds even though collections are requested \"in parallel\".\n const queue: Array<() => Promise<void>> = []\n let running = 0\n const schedule = <T>(task: () => Promise<T>): Promise<T> =>\n new Promise<T>((resolve, reject) => {\n queue.push(() => task().then(resolve, reject))\n pump()\n })\n const pump = (): void => {\n while (running < concurrency && queue.length) {\n const task = queue.shift()!\n running++\n void task().finally(() => {\n running--\n pump()\n })\n }\n }\n const anonymous: Record<string, string> = { accept: 'application/json' }\n let headers = anonymous\n if (options.auth) {\n headers = { ...anonymous, authorization: `Basic ${Buffer.from(`${options.auth.user}:${options.auth.appPassword}`).toString('base64')}` }\n }\n const fellBack = new Set<string>()\n // WordPress answers a wrong Application Password with 401 on every route,\n // public ones too, so a rejected credential is found once and dropped:\n // sent on, it would also empty the public listings the import falls back to.\n let rejected = false\n if (options.auth) {\n const me = await doFetch(`${origin}/wp-json/wp/v2/users/me`, { headers })\n await me.body?.cancel()\n if (me.status === 401 || me.status === 403) {\n rejected = true\n headers = anonymous\n warnings.push(`credential: HTTP ${me.status} on users/me — the site rejected it; imported the public listings only`)\n }\n }\n\n /**\n * Every page of `path`. With `fallback`, a first page the site refuses\n * (400/401/403 — the credential may not list those statuses or the edit\n * context) is retried as `fallback` instead of dropping the collection;\n * an empty `fallback` means there is nothing public to retry, so it is\n * skipped with that warning. The retry is anonymous, and `key` goes into\n * `credential.fell_back`.\n */\n const getAll = async <T>(path: string, fallback?: string, key?: string, send = headers): Promise<T[]> => {\n const label = path.split('?')[0]!\n const url = (page: number) => `${origin}/wp-json/wp/v2/${path}${path.includes('?') ? '&' : '?'}per_page=${perPage}&page=${page}`\n // Hold the slot until the body is consumed, not merely until headers arrive.\n const pageData = (page: number) => schedule(async () => {\n const response = await doFetch(url(page), { headers: send })\n if (!response.ok) {\n await response.body?.cancel()\n if (page === 1 && fallback !== undefined && DENIED.has(response.status)) return { items: [] as T[], pages: 1, denied: response.status }\n warnings.push(`${label}: page ${page} HTTP ${response.status} — skipped`)\n return { items: [] as T[], pages: 1 }\n }\n const pages = Number(response.headers.get('x-wp-totalpages') ?? '1')\n if (!Number.isSafeInteger(pages) || pages < 0) throw new Error(`${path}: invalid x-wp-totalpages`)\n const items = await response.json() as T[]\n if (!Array.isArray(items)) throw new Error(`${path}: page ${page} is not a collection`)\n return { items, pages: Math.max(1, pages), denied: undefined as number | undefined }\n })\n const first = await pageData(1)\n if (first.denied !== undefined) {\n warnings.push(`${label}: HTTP ${first.denied} for ${path.split('?')[1]} with the credential — ${fallback ? 'fell back to the public listing' : 'skipped (no public listing)'}`)\n fellBack.add(key ?? label)\n return fallback ? getAll<T>(fallback, undefined, undefined, anonymous) : []\n }\n const totalPages = first.pages\n const firstPage = first.items\n const wanted = maxPages !== undefined ? Math.min(totalPages, maxPages) : totalPages\n if (wanted < totalPages) {\n warnings.push(`${label}: ${totalPages} pages, fetched ${wanted} (maxPages) — ${totalPages - wanted} pages skipped`)\n }\n if (wanted <= 1) return firstPage\n const rest = await Promise.all(\n Array.from({ length: wanted - 1 }, (_v, i) =>\n pageData(i + 2).then((r) => r.items),\n ),\n )\n return firstPage.concat(...rest)\n }\n\n // The site's own name and tagline (`/wp-json/` index, public): without them the store's site singleton says \"Site\".\n // Advisory: an index that does not answer leaves them out, as before.\n const about = await schedule(async () => {\n try {\n const index = await doFetch(`${origin}/wp-json/`, { headers })\n if (!index.ok) { await index.body?.cancel(); return null }\n return (await index.json()) as { name?: unknown; description?: unknown; url?: unknown; home?: unknown; timezone_string?: unknown; gmt_offset?: unknown; namespaces?: unknown } | null\n } catch { return null }\n })\n\n interface RestType { slug: string; rest_base?: string; viewable?: boolean }\n // `viewable` (has public addresses) is only in the edit context: with a credential, ask for it.\n let typesResp = await doFetch(`${origin}/wp-json/wp/v2/types${options.auth && !rejected ? '?context=edit' : ''}`, { headers })\n if (!typesResp.ok && options.auth && !rejected) {\n await typesResp.body?.cancel()\n typesResp = await doFetch(`${origin}/wp-json/wp/v2/types`, { headers: anonymous })\n }\n const types: Record<string, RestType> = typesResp.ok ? ((await typesResp.json()) as Record<string, RestType>) : {}\n if (!typesResp.ok) warnings.push(`types: HTTP ${typesResp.status} — importing posts and pages only`)\n const postTypes = Object.values(types).filter(\n (t) => t.rest_base && !SKIP_TYPES.test(t.slug) && t.slug !== 'attachment',\n )\n // A type WordPress says has no public address (`viewable: false`, e.g. testimonials used inside pages)\n // is still content, but its REST `link` is not an address: it is imported without one.\n const notViewable = new Set(postTypes.filter((t) => t.viewable === false).map((t) => t.slug))\n const bases = postTypes.length ? postTypes.map((t) => ({ slug: t.slug, base: t.rest_base! })) : [\n { slug: 'post', base: 'posts' },\n { slug: 'page', base: 'pages' },\n ]\n\n interface RestTerm { id: number; slug: string; name: string; taxonomy?: string; parent?: number; description?: string; link?: string }\n interface RestUser { id: number; slug: string; name: string }\n interface RestMedia {\n id: number\n slug: string\n title?: { rendered?: string }\n source_url?: string\n alt_text?: string\n caption?: { rendered?: string }\n mime_type?: string\n media_details?: { width?: number; height?: number; file?: string }\n post?: number | null\n date_gmt?: string\n /** The attachment page. */\n link?: string\n }\n interface RestComment {\n id: number\n post: number\n parent?: number\n author?: number\n author_name?: string\n author_url?: string\n date_gmt?: string\n content?: { rendered?: string }\n status?: string\n type?: string\n }\n\n // Anonymous: WP's defaults (published posts, approved comments). With a\n // credential: every non-trash status, and held comments as a second listing.\n // A credential rejected outright unlocks nothing: every listing it would have read fell back.\n if (rejected) {\n for (const b of bases) fellBack.add(b.base)\n for (const status of AUTH_COMMENT_STATUSES) fellBack.add(commentKey(status))\n }\n const authed = options.auth !== undefined && !rejected\n const postListing = (base: string): Promise<RestPost[]> =>\n authed ? getAll<RestPost>(`${base}?status=${AUTH_POST_STATUSES.join(',')}&context=edit`, base, base) : getAll<RestPost>(base)\n const commentListing = async (): Promise<RestComment[]> => {\n if (!authed) return getAll<RestComment>('comments')\n const lists = await Promise.all(AUTH_COMMENT_STATUSES.map((status) =>\n // Approved comments are public, so a refused credential still gets them; held ones have no public listing.\n getAll<RestComment>(`comments?status=${status}&context=edit`, status === 'approve' ? 'comments' : '', commentKey(status))))\n const byId = new Map<number, RestComment>()\n for (const c of lists.flat()) if (!byId.has(c.id)) byId.set(c.id, c)\n return [...byId.values()]\n }\n // Custom taxonomies in REST (a CPT's `project_type`): their terms and each post's links to them.\n // Menus, block-pattern categories and multilingual bookkeeping are not content taxonomies.\n interface RestTaxonomy { slug: string; rest_base?: string }\n const taxResp = await schedule(async () => {\n try {\n const r = await doFetch(`${origin}/wp-json/wp/v2/taxonomies`, { headers })\n if (!r.ok) { await r.body?.cancel(); return {} }\n return (await r.json()) as Record<string, RestTaxonomy>\n } catch { return {} }\n })\n const extraTaxonomies = Object.values(taxResp && typeof taxResp === 'object' ? taxResp : {})\n .filter((t) => t.rest_base && /^[\\w-]+$/.test(t.rest_base) && !NOT_CONTENT_TAXONOMIES.has(t.slug))\n .map((t) => ({ taxonomy: t.slug, base: t.rest_base! }))\n .toSorted((a, b) => a.taxonomy.localeCompare(b.taxonomy))\n const [categories, tags, users, media, restComments, ...lists] = await Promise.all([\n getAll<RestTerm>('categories'),\n getAll<RestTerm>('tags'),\n getAll<RestUser>('users'),\n getAll<RestMedia>('media'),\n commentListing(),\n ...extraTaxonomies.map((t) => getAll<RestTerm>(t.base)),\n ...bases.map((b) => postListing(b.base)),\n ])\n const extraTerms = lists.slice(0, extraTaxonomies.length) as RestTerm[][]\n const postLists = lists.slice(extraTaxonomies.length) as RestPost[][]\n\n const termsById = new Map<number, RawTerm>()\n /** A term's public address, for menu items that name it; RawTerm carries none. */\n const termLinks = new Map<number, string>()\n for (const [tax, list] of [\n ['category', categories],\n ['post_tag', tags],\n ...extraTaxonomies.map((t, i) => [t.taxonomy, extraTerms[i] ?? []] as const),\n ] as const) {\n for (const t of list) {\n if (t.link) termLinks.set(t.id, t.link)\n termsById.set(t.id, {\n id: t.id,\n taxonomy: tax,\n slug: t.slug,\n name: strip(t.name),\n parent: t.parent ? (list.find((x) => x.id === t.parent)?.slug ?? null) : null,\n parent_resolved: t.parent ? list.some((x) => x.id === t.parent) : null,\n description: t.description ?? '',\n })\n }\n }\n const userById = new Map(users.map((u) => [u.id, u]))\n\n const posts: RawPost[] = []\n // Translation groups, one pair per group. Polylang's `translations` already\n // includes the post itself; WPML lists the OTHER translations, so add self.\n const languagePairs: RawLanguagePair[] = []\n const seenGroups = new Set<string>()\n const recordGroup = (self: RestPost, lang: string | null) => {\n const translations: Record<string, number> = {}\n if (self.translations && typeof self.translations === 'object') {\n for (const [code, id] of Object.entries(self.translations)) if (typeof id === 'number') translations[code] = id\n } else if (Array.isArray(self.wpml_translations)) {\n for (const t of self.wpml_translations) if (t.locale && typeof t.id === 'number') translations[t.locale] = t.id\n if (lang) translations[lang] = self.id\n }\n const ids = Object.values(translations)\n if (ids.length < 2) return\n const key = [...ids].toSorted((a, b) => a - b).join(',')\n if (seenGroups.has(key)) return\n seenGroups.add(key)\n languagePairs.push({ post: self.id, translations })\n }\n for (const [i, base] of bases.entries()) {\n for (const p of postLists[i] ?? []) {\n const custom = extraTaxonomies.flatMap((t) => {\n const ids = (p as unknown as Record<string, unknown>)[t.base]\n return Array.isArray(ids) ? ids.filter((id): id is number => typeof id === 'number') : []\n })\n const termRefs: RawTermRef[] = [...(p.categories ?? []), ...(p.tags ?? []), ...custom].map((id) => {\n const t = termsById.get(id)\n return t\n ? { taxonomy: t.taxonomy, slug: t.slug, name: t.name, resolved: true }\n : { taxonomy: 'category', slug: String(id), name: String(id), resolved: false }\n })\n const author = p.author ? (userById.get(p.author)?.slug ?? null) : null\n const meta: Record<string, unknown> = { ...(p.meta && typeof p.meta === 'object' ? p.meta : {}) }\n if (p.featured_media) meta._thumbnail_id = String(p.featured_media)\n const lang = (typeof p.lang === 'string' && p.lang) || (typeof p.wpml_current_locale === 'string' && p.wpml_current_locale) || null\n recordGroup(p, lang)\n posts.push({\n ...(lang ? { lang } : {}),\n id: p.id,\n type: base.slug,\n status: p.status ?? 'publish',\n slug: p.slug,\n title: p.title?.rendered ?? '',\n link: notViewable.has(base.slug) ? null : (p.link ?? null),\n guid: null,\n author,\n date: iso(p.date_gmt),\n modified: iso(p.modified_gmt),\n content: p.content?.rendered ?? '',\n excerpt: p.excerpt?.rendered ?? '',\n parent: p.parent || null,\n menu_order: p.menu_order ?? 0,\n sticky: p.sticky ?? false,\n password: p.password ? PROTECTED : null,\n comment_status: p.comment_status ?? null,\n ping_status: p.ping_status ?? null,\n terms: termRefs,\n meta,\n ...acfOf(p.acf),\n })\n }\n }\n\n const attachments: RawAttachment[] = media.map((m) => ({\n id: m.id,\n title: strip(m.title?.rendered) || m.slug,\n slug: m.slug,\n url: m.source_url ?? null,\n alt: m.alt_text ?? '',\n caption: strip(m.caption?.rendered),\n file: m.media_details?.file ?? null,\n image_meta: m.media_details ?? null,\n mime: m.mime_type ?? null,\n parent: m.post ?? null,\n parent_resolved: m.post ? posts.some((p) => p.id === m.post) : null,\n // The attachment page sits under its parent's address (`/secret-draft/photo/`): kept only when there is no parent or\n // the parent is proven public, else it would carry a draft's, a private or a scheduled post's slug.\n link: (!m.post || posts.some((p) => p.id === m.post && visible(p))) ? (m.link || null) : null,\n date: iso(m.date_gmt),\n }))\n\n // ── menus: classic menus + published block navigation; both need `edit_theme_options` ──\n const gaps: string[] = []\n // ACF answers `acf` (at least `[]`) on every post of a type it knows: then REST shows only the field\n // groups set to `show_in_rest` (off by default) and never an options page. What it hides, only Bridge reads.\n if (postLists.some((list) => list.some((p) => p.acf !== undefined))) gaps.push('acf_partial')\n let menus: RawMenu[] = []\n if (!authed) {\n // Not a warning: without a working credential this is the rung's known limit, named for the caller in `gaps`.\n gaps.push('menus_require_auth')\n } else {\n const listing = async <T>(path: string): Promise<{ items: T[]; status: number }> => {\n const url = (page: number) => `${origin}/wp-json/wp/v2/${path}${path.includes('?') ? '&' : '?'}per_page=${perPage}&page=${page}`\n const first = await schedule(async () => {\n const r = await doFetch(url(1), { headers })\n if (!r.ok) { await r.body?.cancel(); return { items: [] as T[], status: r.status, pages: 1 } }\n const items = await r.json() as T[]\n return { items: Array.isArray(items) ? items : [], status: r.status, pages: Math.max(1, Number(r.headers.get('x-wp-totalpages') ?? '1') || 1) }\n })\n const wanted = maxPages !== undefined ? Math.min(first.pages, maxPages) : first.pages\n const rest = await Promise.all(Array.from({ length: wanted - 1 }, (_v, i) => schedule(async () => {\n const r = await doFetch(url(i + 2), { headers })\n if (!r.ok) { await r.body?.cancel(); warnings.push(`${path.split('?')[0]}: page ${i + 2} HTTP ${r.status} — skipped`); return [] as T[] }\n const items = await r.json() as T[]\n return Array.isArray(items) ? items : []\n })))\n return { items: first.items.concat(...rest), status: first.status }\n }\n const [classic, items, navs, parts, templates] = await Promise.all([\n listing<RestMenu>('menus?context=edit'),\n listing<RestMenuItem>('menu-items?context=edit'),\n listing<RestNavigation>('navigation?context=edit&status=publish'),\n listing<RestTemplatePart>('template-parts?context=edit'),\n // Which template parts the pages use: a theme ships alternatives no template shows.\n listing<RestTemplate>('templates?context=edit&_fields=slug,content'),\n ])\n const denied = [classic, items, navs].filter((l) => DENIED.has(l.status))\n if (denied.length) {\n gaps.push('menus_require_auth')\n warnings.push(`menus: HTTP ${denied[0]!.status} with the credential — the user may not edit theme options; menus not read`)\n }\n for (const [name, l] of [['menus', classic], ['menu-items', items], ['navigation', navs]] as const) {\n if (!l.status || (l.status >= 400 && !DENIED.has(l.status) && l.status !== 404)) warnings.push(`${name}: HTTP ${l.status} — skipped`)\n }\n const slugOf = new Map(posts.filter(visible).map((p) => [p.id, p.slug]))\n const linkOf = new Map(posts.filter(visible).flatMap((p) => (p.link ? [[p.id, p.link] as const] : [])))\n const ctx: MenuContext = {\n origin,\n postSlug: (id) => slugOf.get(id),\n termSlug: (taxonomy, id) => { const t = termsById.get(id); return t && t.taxonomy === taxonomy ? t.slug : undefined },\n postLink: (id) => linkOf.get(id),\n termLink: (taxonomy, id) => (termsById.get(id)?.taxonomy === taxonomy ? termLinks.get(id) : undefined),\n pages: posts.filter((p) => p.type === 'page' && p.status === 'publish' && !p.password).map((p) => ({ id: p.id, parent: p.parent ?? null, menu_order: p.menu_order ?? 0, title: strip(p.title), link: p.link ?? null, slug: p.slug })),\n }\n const dropped = { count: 0 }\n menus = classicMenus(DENIED.has(classic.status) ? [] : classic.items, DENIED.has(items.status) ? [] : items.items, ctx, dropped)\n menus.push(...blockMenus(DENIED.has(navs.status) ? [] : navs.items, parts.status < 400 ? parts.items : [], ctx, new Set(menus.map((m) => m.slug)), dropped, templates.status < 400 ? templates.items : []))\n // A count only: the titles of what was left out are exactly what must not travel.\n if (dropped.count) warnings.push(`menus: ${dropped.count} item(s) are drafts or point at content not proven public (unpublished, password-protected, or not read by this import) — left out`)\n }\n\n const postIds = new Set(posts.map((p) => p.id))\n const commentIds = new Set(restComments.map((c) => c.id))\n const comments: RawComment[] = restComments.map((c) => ({\n id: c.id,\n post: c.post,\n post_type: posts.find((p) => p.id === c.post)?.type,\n parent: c.parent || null,\n parent_resolved: c.parent ? commentIds.has(c.parent) : null,\n author: strip(c.author_name) || 'anonymous',\n email: null,\n url: c.author_url || null,\n date: iso(c.date_gmt),\n date_gmt: c.date_gmt ?? null,\n content: c.content?.rendered ?? '',\n approved: approvedOf(c.status),\n type: c.type ?? 'comment',\n user_id: c.author || null,\n }))\n for (const c of comments) if (!postIds.has(c.post)) warnings.push(`comment ${c.id}: post ${c.post} not in fetched set`)\n\n // The rung is what was actually read: a credential rejected outright read nothing.\n // ── redirects: the Redirection plugin's rules (`redirection/v1`), with a credential that may manage them ──\n let redirects: RawRedirect[] = []\n let redirectsExcluded: RawRedirectExcluded[] = []\n gaps.push('redirects_partial')\n const namespaces = Array.isArray(about?.namespaces) ? (about.namespaces as unknown[]) : undefined\n const redirection = namespaces ? namespaces.includes('redirection/v1') : undefined\n if (redirection && !authed) gaps.push('redirects_require_auth')\n else if (authed && redirection !== false) {\n // Redirection pages from 0 and answers `{ items, total }`.\n const all = async <T extends { id: number }>(path: string): Promise<{ items: T[]; status: number }> => {\n const items: T[] = []\n const seen = new Set<number>()\n for (let page = 0; page < (maxPages ?? 500); page++) {\n // oxlint-disable-next-line no-await-in-loop -- `total` is only known from the page before\n const r = await schedule(() => doFetch(`${origin}/wp-json/redirection/v1/${path}?per_page=200&page=${page}`, { headers }))\n if (!r.ok) { await r.body?.cancel(); return { items, status: r.status } }\n // oxlint-disable-next-line no-await-in-loop -- the body of the page just fetched\n const body = await r.json() as { items?: T[]; total?: number }\n const fresh = (Array.isArray(body.items) ? body.items : []).filter((x) => !seen.has(x.id))\n for (const x of fresh) { seen.add(x.id); items.push(x) }\n if (!fresh.length || items.length >= Number(body.total ?? 0)) break\n }\n return { items, status: 200 }\n }\n // The site-wide match defaults a rule without its own flags takes; answered as `{ settings }`.\n const settings = async (): Promise<RestRedirectionOptions | undefined> => {\n try {\n const r = await schedule(() => doFetch(`${origin}/wp-json/redirection/v1/setting`, { headers }))\n if (!r.ok) { await r.body?.cancel(); return undefined }\n const body = await r.json() as { settings?: RestRedirectionOptions } | null\n return body?.settings && typeof body.settings === 'object' ? body.settings : undefined\n } catch { return undefined }\n }\n const [rules, groups, siteFlags] = await Promise.all([all<RestRedirection>('redirect'), all<RestRedirectionGroup>('group'), settings()])\n if (DENIED.has(rules.status)) {\n gaps.push('redirects_require_auth')\n warnings.push(`redirects: HTTP ${rules.status} with the credential — the user may not manage Redirection; its rules not read`)\n } else if (rules.status === 200) {\n ;({ redirects, excluded: redirectsExcluded } = redirectionRules(rules.items, groups.status === 200 ? groups.items : [], origin, siteFlags))\n } else if (redirection) warnings.push(`redirects: HTTP ${rules.status} — Redirection's rules not read`)\n }\n\n const kind: SourceAccessKind = authed ? 'rest_auth' : 'rest_public'\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind, tool: options.tool ?? '@contentrain/wp-import' },\n site: {\n url: origin,\n ...(typeof about?.name === 'string' && strip(about.name) ? { title: strip(about.name) } : {}),\n ...(typeof about?.description === 'string' && strip(about.description) ? { description: strip(about.description) } : {}),\n // Where WordPress is installed and where the site is served, as WXR names them (they differ for a subdirectory install).\n ...(typeof about?.url === 'string' && about.url ? { base_site_url: about.url } : {}),\n ...(typeof about?.home === 'string' && about.home ? { base_blog_url: about.home } : {}),\n // The zone the site's local date-times (ACF date time pickers) are written in.\n ...(typeof about?.timezone_string === 'string' && about.timezone_string ? { timezone: about.timezone_string } : {}),\n ...(about?.gmt_offset !== undefined && about.gmt_offset !== null && about.gmt_offset !== '' && Number.isFinite(Number(about.gmt_offset)) ? { gmt_offset: Number(about.gmt_offset) } : {}),\n },\n authors: users.map((u) => ({ id: u.id, login: u.slug, display_name: strip(u.name) || u.slug, email: null })),\n terms: [...termsById.values()],\n posts,\n attachments,\n comments,\n ...(menus.length ? { menus } : {}),\n ...(redirects.length ? { redirects } : {}),\n ...(redirectsExcluded.length ? { redirects_excluded: redirectsExcluded } : {}),\n ...(languagePairs.length ? { language_pairs: languagePairs } : {}),\n }\n const credential: RestImportResult['credential'] = {\n status: !options.auth ? 'none' : fellBack.size ? 'rejected' : 'accepted',\n fell_back: [...fellBack].toSorted(),\n }\n return { raw, warnings, credential, gaps }\n}\n","// RawIR → .contentrain content store, as a pure file map.\n//\n// Ported from the measured import chain (the \"deviations from r4i\" it carried\n// are already folded in: PATH_PATTERNS-conformant layout, ContentrainConfig\n// shape, meta files per locale). Two properties are load-bearing:\n//\n// 1. Identity formulas — hexId('posts:' + slug), hexId('category:' + slug) —\n// are shared with the REST path, so the same site imported twice (or via a\n// later delta) lands on the same entry ids.\n// 2. The EntrySourceMap (wp post id → entry address) is produced HERE and only\n// here: this is the one place that knows both sides of the mapping, and the\n// comments intake downstream cannot exist without it.\n\nimport type { EntrySourceMap, FieldDef, ModelDefinition, RawAcfOptionsPage, RawAcfValue, RawIR, RawPost } from '@contentrain/types'\nimport { ACF_REFERENCE_TYPES, acfFieldDef, acfRows, acfScrub, acfValue, mergeFieldDef, type AcfReference } from './acf.js'\nimport {\n byValue,\n canon,\n coreFields,\n decodeSlug,\n hexId,\n PLUGIN_META,\n SKIP_TYPES,\n addressSlug,\n slugify,\n strip,\n taxModelId,\n} from './core.js'\n\n/** A post whose imported slug is not the address it was served at: it gets a 301 from `from`. */\nexport interface SlugMove {\n wp_id: number\n type: string\n /** The path the source site served it at (its `link`), when the source named one. */\n from: string | null\n /** The slug the entry was written under. */\n slug: string\n /**\n * `empty`: the source slug left no word, `collision`: another entry of the same type already holds it,\n * `rewritten`: characters outside the slug alphabet (ZWNJ/ZWJ, `・`, an NFD spelling...) were changed.\n */\n reason: 'empty' | 'collision' | 'rewritten'\n}\n\nconst utf8Length = (s: string): number => new TextEncoder().encode(s).length\n\n/** `s` cut on a code-point boundary to at most `max` UTF-8 bytes, without a trailing hyphen. */\nconst fitBytes = (s: string, max: number): string => {\n let out = ''\n let bytes = 0\n for (const ch of s) {\n const n = utf8Length(ch)\n if (bytes + n > max) break\n out += ch\n bytes += n\n }\n return out.replace(/-+$/, '')\n}\n\nexport interface ImportReport {\n slug_rewritten: number\n slug_fallback: number\n /** Posts whose address changed (empty or colliding slug): each needs a 301 from its old address. */\n slug_moves: SlugMove[]\n title_fallback: number\n meta_fields: Record<string, string>\n acf_fields: Record<string, string>\n /** ACF Options Page fields written to the `site` entry (`field: type`), prefixed `<page>_` on a name clash. */\n acf_options: Record<string, string>\n /** ACF Options Page fields whose name was already taken, written under a counter (`new name: <page slug>.<field>`). */\n acf_options_renamed: Record<string, string>\n /** ACF select/checkbox values outside their field's stated choices, left out (`field: count`). */\n acf_outside_choices: Record<string, number>\n /** ACF date-times written without a zone because the source named none (`timezone_string` / `gmt_offset`). */\n acf_datetime_unzoned: number\n skipped_types: string[]\n dropped_relations: number\n models: Record<string, { kind: string; domain: string; fields: number; entries: number }>\n /** Default first, then every other language seen on a post. One entry on a monolingual site. */\n locales: string[]\n /** Translation groups that were folded into one entry id across locales. */\n translation_groups: number\n /**\n * Password-protected posts imported as `draft`, whatever their WordPress\n * status. Their body is the protected text, and nothing downstream (query\n * SDK, emitter) enforces `visibility: password`, so publishing one would\n * put that text on a public site. Publish only after deciding what to show.\n */\n password_protected_drafts: number\n /**\n * The source named no site title (no REST index name, no WXR channel title): the `site` entry has no\n * `title`. The field stays required, so the store says what is missing rather than inventing a name.\n */\n site_title_missing: boolean\n}\n\nexport interface ContentrainResult {\n files: Record<string, string>\n entry_source_map: EntrySourceMap\n report: ImportReport\n}\n\ntype Entry = Record<string, unknown>\ntype Meta = { status: string; source: string; updated_by: string; publish_at?: string }\n\nconst pick = (o: Record<string, unknown>, keys: Set<string>): Entry =>\n Object.fromEntries(Object.entries(o).filter(([k, v]) => keys.has(k) && v !== undefined && v !== null && v !== ''))\nconst typeModelId = (t: string): string => (t === 'post' ? 'posts' : t === 'page' ? 'pages' : t.replace(/_/g, '-'))\nconst domainOf = (t: string): string => (t === 'post' ? 'blog' : t === 'page' ? 'site' : 'custom')\n\n/** `en_US` / `tr-TR` / `en` → `en`: the store's locale is the primary subtag. */\nconst normLocale = (code: string | null | undefined): string => (code ?? '').split(/[-_]/)[0]?.toLowerCase() ?? ''\n\n/** Multilingual-plugin taxonomies that carry language bookkeeping, not content. */\nconst LANGUAGE_TAXONOMIES = new Set(['language', 'post_translations', 'term_language', 'term_translations'])\n\n/**\n * A relation field over `targets`: its declared model, and how a reference into\n * it is stored.\n *\n * With several targets the id alone does not say which model's entry it is, so\n * the reference is the pair `{ model, ref }`. With one there is nothing to\n * choose between: the field is single-target and stores the entry id. Writing\n * the pair there fails the same validator that requires it when there are\n * several — so the choice is made in one place, from the same list the model\n * declares.\n */\nfunction relationOver(targets: string[]): {\n model: string | string[]\n ref: (entry: { model: string; ref: string }) => string | { model: string; ref: string }\n} {\n const single = targets.length === 1\n return { model: single ? targets[0]! : targets, ref: (entry) => (single ? entry.ref : entry) }\n}\n\n/** Post, term, user or attachment ids of an ACF reference value: ids, numeric strings or `{ ID }` objects. */\nconst idsOf = (v: unknown): number[] =>\n (Array.isArray(v) ? v : [v])\n .map((x) => (typeof x === 'number' ? x : typeof x === 'string' && /^\\d+$/.test(x) ? Number(x) : x && typeof x === 'object' ? Number((x as { ID?: unknown; id?: unknown; term_id?: unknown }).ID ?? (x as { id?: unknown }).id ?? (x as { term_id?: unknown }).term_id) : Number.NaN))\n .filter((n) => Number.isSafeInteger(n) && n > 0)\n\nexport function rawToContentrain(raw: RawIR, opts?: { updatedBy?: string }): ContentrainResult {\n const updatedBy = opts?.updatedBy ?? '@contentrain/wp-import'\n const locale = normLocale(raw.site.language) || 'en'\n const models: Record<string, ModelDefinition> = {}\n const contents: Record<string, Record<string, Entry>> = {}\n const metas: Record<string, Record<string, Meta>> = {}\n // Per-locale buckets for i18n models (post types on a multilingual site).\n const localeContents: Record<string, Record<string, Record<string, Entry>>> = {}\n const localeMetas: Record<string, Record<string, Record<string, Meta>>> = {}\n\n // ── languages ──\n // A post's language comes from the plugin (`lang`) or, in WXR, from the\n // `language` taxonomy term Polylang attaches. Posts without one belong to the\n // site's default locale. More than one locale seen → post-type models are\n // i18n and content is written per locale.\n const postLocale = (p: RawPost): string =>\n normLocale(p.lang ?? p.terms.find((t) => t.taxonomy === 'language')?.slug) || locale\n const locales = [locale, ...[...new Set(raw.posts.filter((p) => !SKIP_TYPES.test(p.type)).map(postLocale))].filter((l) => l !== locale).toSorted()]\n const multilingual = locales.length > 1\n // Translation groups → one canonical post per group. Its entry id is shared\n // by every translation, which is how an i18n collection addresses one entry\n // in several locales. The canonical member is the default-locale post when\n // there is one, else the lowest id — deterministic either way.\n const postById = new Map(raw.posts.map((p) => [p.id, p]))\n const canonicalOf = new Map<number, number>()\n let translationGroups = 0\n for (const pair of raw.language_pairs ?? []) {\n const members = [...new Set(Object.values(pair.translations))].filter((id) => postById.has(id) && !SKIP_TYPES.test(postById.get(id)!.type))\n if (members.length < 2) continue\n const memberLocales = members.map((id) => postLocale(postById.get(id)!))\n if (new Set(memberLocales).size !== members.length)\n throw new Error(`Translation group ${pair.post} has multiple posts in the same normalized locale; refusing to overwrite a translation`)\n const canonical = members.find((id) => postLocale(postById.get(id)!) === locale) ?? Math.min(...members)\n for (const id of members) canonicalOf.set(id, canonical)\n translationGroups++\n }\n let siteEntry: Entry = {}\n let siteMeta: Meta | null = null\n const report: ImportReport = {\n slug_rewritten: 0,\n slug_fallback: 0,\n slug_moves: [],\n title_fallback: 0,\n meta_fields: {},\n acf_fields: {},\n acf_options: {},\n acf_options_renamed: {},\n acf_outside_choices: {},\n acf_datetime_unzoned: 0,\n skipped_types: [],\n dropped_relations: 0,\n models: {},\n locales,\n translation_groups: translationGroups,\n password_protected_drafts: 0,\n site_title_missing: false,\n }\n const importMeta = (status: string, extra: Partial<Meta> = {}): Meta => ({\n status,\n source: 'import',\n updated_by: updatedBy,\n ...extra,\n })\n const mapStatus = (p: RawPost): Meta => {\n // Checked first: a protected post must never come in published or scheduled.\n if (p.password && p.status !== 'trash') {\n report.password_protected_drafts++\n return importMeta('draft')\n }\n if (p.status === 'future' && (!p.date || !Number.isFinite(Date.parse(p.date))))\n throw new Error(`Scheduled WordPress post ${p.id} has no valid publication date`)\n return p.status === 'publish' || p.status === 'inherit'\n ? importMeta('published')\n : p.status === 'future'\n ? importMeta('published', { publish_at: p.date! })\n : p.status === 'pending'\n ? importMeta('in_review')\n : p.status === 'trash'\n ? importMeta('archived')\n : importMeta('draft')\n }\n const addModel = (m: ModelDefinition): void => {\n models[m.id] = m\n contents[m.id] ??= {}\n metas[m.id] ??= {}\n }\n\n // ── identities (shared formulas — REST and WXR must agree) ──\n const authorId = (login: string): string => hexId(`authors:${login}`)\n const termId = (tax: string, slug: string): string => hexId(`${tax}:${slug}`)\n const usedSlugs = new Map<string, number>()\n const postSlug = (p: RawPost): string => {\n // The slug is the page's address: kept as the source served it (any script), not transliterated.\n let s = addressSlug(p.slug)\n const moved = (reason: SlugMove['reason'], slug: string): void => {\n let from: string | null = null\n try { from = p.link ? new URL(p.link).pathname : null } catch { from = null }\n report.slug_moves.push({ wp_id: p.id, type: p.type, from, slug, reason })\n }\n let empty = false\n let rewritten = false\n if (!s) {\n s = `${p.type}-${p.id}`\n empty = true\n report.slug_fallback++\n } else if (s !== decodeSlug(p.slug)) {\n report.slug_rewritten++\n // Case alone is not a move (WP serves post_name lowercase); anything else changes the address.\n rewritten = s !== decodeSlug(p.slug).toLowerCase()\n }\n // Slugs are unique per type — and per locale on a multilingual site, where\n // `/about/` and `/tr/about/` are different entries with the same slug.\n const key = multilingual ? `${p.type}:${postLocale(p)}:${s}` : `${p.type}:${s}`\n const n = usedSlugs.get(key) ?? 0\n usedSlugs.set(key, n + 1)\n if (n) {\n const suffix = `-${p.id}`\n const unique = `${fitBytes(s, 200 - utf8Length(suffix))}${suffix}`\n moved('collision', unique)\n return unique\n }\n if (empty) moved('empty', s)\n else if (rewritten) moved('rewritten', s)\n return s\n }\n const slugOf = new Map<number, string>()\n const postEntry = new Map<number, { model: string; ref: string }>()\n for (const p of raw.posts.toSorted((a, b) => a.id - b.id)) {\n // Only exported entries may be relation targets or appear in the source map.\n if (SKIP_TYPES.test(p.type)) continue\n slugOf.set(p.id, postSlug(p))\n }\n // Keep established slug identities unless distinct translation groups collide.\n // Prefer the default-locale group, then the lowest WP id, independently of\n // REST pagination/WXR order. A colliding group gets a WP-id namespace.\n const identityOwner = new Map<string, number>()\n const exported = raw.posts.filter((p) => !SKIP_TYPES.test(p.type))\n const canonicalPosts = exported.filter((p) => (canonicalOf.get(p.id) ?? p.id) === p.id)\n .toSorted((a, b) => Number(postLocale(b) === locale) - Number(postLocale(a) === locale) || a.id - b.id)\n for (const p of canonicalPosts) {\n const key = `${typeModelId(p.type)}:${slugOf.get(p.id)!}`\n if (!identityOwner.has(key)) identityOwner.set(key, p.id)\n }\n for (const p of exported) {\n const canonical = canonicalOf.get(p.id) ?? p.id\n const mid = typeModelId(p.type)\n const key = `${mid}:${slugOf.get(canonical) ?? slugOf.get(p.id)!}`\n postEntry.set(p.id, { model: mid, ref: hexId(identityOwner.get(key) === canonical ? key : `${mid}:wp:${canonical}`) })\n }\n const mediaRef = (id: number): string | null => (raw.attachments.some((a) => a.id === id) ? hexId(`media:${id}`) : null)\n\n // ── ACF references: the store entry each id points at ──\n const termById = new Map(raw.terms.map((t) => [t.id, t]))\n const authorById = new Map(raw.authors.filter((a) => a.id !== null).map((a) => [a.id!, a]))\n const refOf = (kind: AcfReference, id: number): { model: string; ref: string } | null => {\n if (kind === 'post') return postEntry.get(id) ?? null\n if (kind === 'media') { const m = mediaRef(id); return m ? { model: 'media', ref: m } : null }\n if (kind === 'user') { const a = authorById.get(id); return a && models.authors ? { model: 'authors', ref: authorId(slugify(a.login)) } : null }\n if (kind === 'term') { const t = termById.get(id); return t && models[taxModelId(t.taxonomy)] ? { model: taxModelId(t.taxonomy), ref: termId(t.taxonomy, t.slug) } : null }\n return null\n }\n interface AcfFieldPlan { def?: FieldDef; kind?: AcfReference; multiple: boolean; models: Set<string> }\n /** Every ACF field on these posts: its definition, or — for a reference — its kind and target models. */\n const acfPlan = (items: RawPost[], taken: (k: string) => boolean): Map<string, AcfFieldPlan> => {\n const out = new Map<string, AcfFieldPlan>()\n for (const p of items) {\n for (const [k, acf] of Object.entries(p.acf ?? {})) {\n if (taken(k) || acf.value === null || acf.value === undefined || acf.value === '' || acf.value === false && acf.type !== 'true_false') continue\n const kind = acf.type ? ACF_REFERENCE_TYPES[acf.type] : undefined\n if (kind === 'address') {\n const def: FieldDef = Array.isArray(acf.value) ? { type: 'array', items: 'url' } : { type: 'url' }\n const cur = out.get(k)\n out.set(k, { def: cur?.def ?? { ...def, ...(acf.label ? { label: strip(acf.label) } : {}) }, kind, multiple: false, models: new Set() })\n continue\n }\n if (kind) {\n const cur = out.get(k) ?? { kind, multiple: acf.type === 'relationship' || acf.type === 'gallery', models: new Set<string>() }\n if (Array.isArray(acf.value)) cur.multiple = true\n for (const id of idsOf(acf.value)) { const r = refOf(kind, id); if (r) cur.models.add(r.model) }\n out.set(k, cur)\n continue\n }\n const def = acfFieldDef(k, acfScrub(acf.value), { type: acf.type, label: acf.label })\n if (!def) continue\n const cur = out.get(k)\n out.set(k, { def: cur?.def ? mergeFieldDef(cur.def, def) : def, multiple: false, models: new Set() })\n }\n }\n // A reference none of whose targets is in the store has no model to point at: it is left out.\n for (const [k, plan] of out) if (!plan.def && !plan.models.size) out.delete(k)\n return out\n }\n const acfRefs = (plan: AcfFieldPlan, value: unknown): unknown => {\n const refs = idsOf(value).map((id) => refOf(plan.kind!, id)).filter((r): r is { model: string; ref: string } => !!r)\n const missing = idsOf(value).length - refs.length\n if (missing > 0) report.dropped_relations += missing\n if (!refs.length) return undefined\n const poly = plan.models.size > 1\n const one = (r: { model: string; ref: string }) => (poly ? r : r.ref)\n return plan.multiple ? refs.map(one) : one(refs[0]!)\n }\n // page_link: an id is the address of that post as it is now.\n // Only a published, unprotected target's address: a draft's `?page_id=` is no address to keep.\n const addressOf = (v: unknown): unknown => {\n if (Array.isArray(v)) return v.map(addressOf).filter(Boolean)\n if (typeof v !== 'number') return v\n const t = postById.get(v)\n return t && t.status === 'publish' && !t.password ? (t.link ?? undefined) : undefined\n }\n /** An ACF value as the store holds it: typed by the plan, references resolved; `undefined` = nothing to write. */\n const acfEntryValue = (k: string, plan: AcfFieldPlan, value: unknown): unknown => {\n const ctx = {\n timeZone: raw.site.timezone, gmtOffset: raw.site.gmt_offset,\n dropped: () => { report.acf_outside_choices[k] = (report.acf_outside_choices[k] ?? 0) + 1 },\n unzoned: () => { report.acf_datetime_unzoned++ },\n }\n return plan.def ? acfValue(plan.def, plan.kind === 'address' ? addressOf(value) : acfRows(acfScrub(value)), ctx) : acfRefs(plan, value)\n }\n const titleOf = (p: RawPost): string => {\n const t = strip(p.title)\n if (t) return t\n report.title_fallback++\n return slugOf.get(p.id) ?? `#${p.id}`\n }\n\n // ── authors ──\n addModel({\n id: 'authors', name: 'Authors', kind: 'collection', domain: 'blog', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n email: { type: 'email', label: 'Email', order: 30 },\n wp_id: { type: 'integer', label: 'WP user ID', order: 40 },\n },\n })\n for (const a of raw.authors) {\n const id = authorId(slugify(a.login))\n contents.authors![id] = pick(\n { name: strip(a.display_name), slug: slugify(a.login), email: a.email, wp_id: a.id },\n new Set(['name', 'slug', 'email', 'wp_id']),\n )\n metas.authors![id] = importMeta('published')\n }\n for (const p of raw.posts) {\n if (p.author && !contents.authors![authorId(slugify(p.author))]) {\n contents.authors![authorId(slugify(p.author))] = { name: p.author, slug: slugify(p.author) }\n metas.authors![authorId(slugify(p.author))] = importMeta('published')\n }\n }\n\n // ── taxonomies (nav_menu and post_format excluded; post_format → select field) ──\n const taxonomies = [...new Set(raw.terms.map((t) => t.taxonomy))].filter(\n (t) => t !== 'nav_menu' && t !== 'post_format' && !LANGUAGE_TAXONOMIES.has(t),\n )\n for (const tax of taxonomies) {\n const mid = taxModelId(tax)\n addModel({\n id: mid, name: mid, kind: 'collection', domain: 'blog', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n description: { type: 'text', label: 'Description', order: 30 },\n parent: { type: 'relation', model: mid, label: 'Parent', order: 40 },\n wp_id: { type: 'integer', label: 'WP term ID', order: 50 },\n },\n })\n for (const t of raw.terms.filter((x) => x.taxonomy === tax)) {\n const id = termId(tax, t.slug)\n contents[mid]![id] = pick(\n {\n name: strip(t.name),\n slug: addressSlug(t.slug) || `term-${t.id}`,\n description: strip(t.description),\n parent: t.parent && t.parent_resolved ? termId(tax, t.parent) : null,\n wp_id: t.id,\n },\n new Set(['name', 'slug', 'description', 'parent', 'wp_id']),\n )\n metas[mid]![id] = importMeta('published')\n }\n }\n // referenced-but-unlisted terms join the pool (marked resolved:false upstream, never dropped)\n for (const p of raw.posts) {\n for (const t of p.terms) {\n if (t.taxonomy === 'nav_menu' || t.taxonomy === 'post_format' || t.resolved) continue\n const mid = taxModelId(t.taxonomy)\n if (!models[mid]) continue\n const id = termId(t.taxonomy, t.slug)\n contents[mid]![id] ??= { name: strip(t.name), slug: addressSlug(t.slug) || `term-${hexId(`${t.taxonomy}:${t.slug}`).slice(0, 8)}` }\n metas[mid]![id] ??= importMeta('published')\n }\n }\n\n const postTypes = [...new Set(raw.posts.map((p) => p.type))].filter((t) => {\n if (SKIP_TYPES.test(t)) {\n report.skipped_types.push(t)\n return false\n }\n return true\n })\n const contentModelIds = postTypes.map(typeModelId)\n const toContent = relationOver(contentModelIds)\n\n // ── media ──\n addModel({\n id: 'media', name: 'Media', kind: 'collection', domain: 'assets', i18n: false, title_field: 'title',\n fields: {\n title: { type: 'string', required: true, label: 'Title', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n url: { type: 'url', required: true, label: 'Source URL', order: 30 },\n alt: { type: 'string', label: 'Alt text', order: 40 },\n caption: { type: 'text', label: 'Caption', order: 50 },\n description: { type: 'text', label: 'Description', order: 60 },\n mime: { type: 'string', label: 'MIME type', order: 70 },\n width: { type: 'integer', label: 'Width', order: 80 },\n height: { type: 'integer', label: 'Height', order: 90 },\n file: { type: 'string', label: 'Upload path', order: 100 },\n parent: { type: 'relation', model: toContent.model, label: 'Attached to', order: 110 },\n wp_id: { type: 'integer', label: 'WP attachment ID', order: 120 },\n uploaded_at: { type: 'datetime', label: 'Uploaded at', order: 130 },\n },\n })\n const mediaSlugs = new Set<string>()\n for (const a of raw.attachments) {\n const id = hexId(`media:${a.id}`)\n let slug = addressSlug(a.slug) || `media-${a.id}`\n if (mediaSlugs.has(slug)) slug = `${slug}-${a.id}`\n mediaSlugs.add(slug)\n const target = a.parent ? postEntry.get(a.parent) : undefined\n if (a.parent && !target) report.dropped_relations++\n const parent = target ? toContent.ref(target) : null\n const im = (a.image_meta ?? null) as { width?: number; height?: number } | null\n contents.media![id] = pick(\n {\n title: strip(a.title) || slug,\n slug,\n url: a.url,\n alt: strip(a.alt),\n caption: strip(a.caption),\n description: strip(a.description),\n mime: a.mime,\n width: im?.width,\n height: im?.height,\n file: a.file,\n parent,\n wp_id: a.id,\n uploaded_at: a.date,\n },\n new Set(['title', 'slug', 'url', 'alt', 'caption', 'description', 'mime', 'width', 'height', 'file', 'parent', 'wp_id', 'uploaded_at']),\n )\n metas.media![id] = importMeta('published')\n }\n\n // ── post types (post, page, CPTs) ──\n for (const type of postTypes) {\n const typeItems = raw.posts.filter((p) => p.type === type)\n const mid = typeModelId(type)\n const taxes = [...new Set(typeItems.flatMap((p) => p.terms.map((t) => t.taxonomy)))].filter((t) => models[taxModelId(t)])\n const { fields, order } = coreFields({\n excerpt: typeItems.some((p) => p.excerpt),\n body: typeItems.some((p) => p.content),\n date: typeItems.some((p) => p.date),\n author: typeItems.some((p) => p.author),\n taxes,\n cover: typeItems.some((p) => p.meta._thumbnail_id),\n })\n let o = order\n fields.wp_id = { type: 'integer', required: true, unique: true, label: 'WP post ID', order: (o += 10) }\n fields.modified_at = { type: 'datetime', label: 'Modified at', order: (o += 10) }\n fields.link = { type: 'url', label: 'Original permalink', order: (o += 10) }\n const parentModels = [...new Set(typeItems.flatMap((p) => {\n const parent = p.parent ? postEntry.get(p.parent) : undefined\n return parent ? [parent.model] : []\n }))].toSorted()\n if (typeItems.some((p) => p.parent)) fields.parent = {\n type: 'relation',\n model: parentModels.length > 1 ? parentModels : (parentModels[0] ?? mid),\n label: 'Parent', order: (o += 10),\n }\n if (typeItems.some((p) => p.menu_order)) fields.menu_order = { type: 'integer', label: 'Menu order', order: (o += 10) }\n if (typeItems.some((p) => p.sticky)) fields.sticky = { type: 'boolean', label: 'Sticky', order: (o += 10) }\n if (typeItems.some((p) => typeof p.meta._wp_page_template === 'string' && p.meta._wp_page_template !== 'default'))\n fields.template = { type: 'string', label: 'Page template', order: (o += 10) }\n const formats = [\n ...new Set(\n typeItems.flatMap((p) =>\n p.terms.filter((t) => t.taxonomy === 'post_format').map((t) => t.slug.replace(/^post-format-/, '')),\n ),\n ),\n ].toSorted()\n if (formats.length) fields.format = { type: 'select', options: formats, label: 'Post format', order: (o += 10) }\n if (typeItems.some((p) => p.status === 'private' || p.password))\n fields.visibility = { type: 'select', options: ['public', 'private', 'password'], label: 'Visibility', order: (o += 10) }\n if (typeItems.some((p) => p.comment_status))\n fields.comments_open = { type: 'boolean', label: 'Comments open', order: (o += 10) }\n for (const p of typeItems) {\n for (const [k, v] of Object.entries(p.meta)) {\n if (k.startsWith('_') || fields[k] || PLUGIN_META.test(k) || k === 'enclosure') continue\n const t = byValue(v)\n if (t && t !== 'object') {\n fields[k] = { type: t as FieldDef['type'], label: k, order: (o += 10) }\n report.meta_fields[k] = t\n }\n }\n }\n // ACF: one field per ACF field, typed by the mapping table (acf.ts); references resolved to store entries.\n const acfFields = acfPlan(typeItems, (k) => !!fields[k])\n for (const [k, plan] of acfFields) {\n const def = plan.def ?? { type: plan.multiple ? 'relations' : 'relation', model: plan.models.size > 1 ? [...plan.models].toSorted() : [...plan.models][0]! } as FieldDef\n fields[k] = { ...def, ...(def.label ? {} : { label: k }), description: def.description ?? 'ACF', order: (o += 10) }\n report.acf_fields[k] = plan.def ? plan.def.type : `${def.type}:${[...plan.models].toSorted().join('|')}`\n }\n // The locales this type actually has content in. A partially-translated\n // site — pages in one language, posts in three — used to fail validation on\n // every untranslated entry, because parity was checked against the whole\n // project list. Declaring the real coverage says so once, in the model.\n //\n // The default locale is always in: it is the site's source of truth, and a\n // post that carries no language tag belongs to it (`postLocale`), so its\n // absence here would be the importer's uncertainty, not a fact about the\n // site. Full coverage writes nothing — absent already means \"all\", and a\n // redundant list would then have to be maintained as locales are added.\n const covered = locales.filter(l => l === locale || typeItems.some((p) => postLocale(p) === l))\n addModel({\n id: mid,\n name: type === 'post' ? 'Posts' : type === 'page' ? 'Pages' : mid,\n kind: 'collection',\n domain: domainOf(type),\n i18n: multilingual,\n ...(multilingual && covered.length < locales.length ? { locales: covered } : {}),\n title_field: 'title',\n fields,\n })\n for (const p of typeItems) {\n const id = postEntry.get(p.id)!.ref\n const loc = postLocale(p)\n const contentBucket = multilingual ? ((localeContents[mid] ??= {})[loc] ??= {}) : contents[mid]!\n const metaBucket = multilingual ? ((localeMetas[mid] ??= {})[loc] ??= {}) : metas[mid]!\n const e: Entry = { title: titleOf(p), slug: slugOf.get(p.id), wp_id: p.id }\n if (fields.excerpt) e.excerpt = strip(p.excerpt)\n if (fields.body) e.body = p.content // Gutenberg comments and shortcodes verbatim (known gap)\n if (fields.published_at && p.date) e.published_at = p.date\n if (p.modified) e.modified_at = p.modified\n if (p.link) e.link = p.link\n if (fields.author && p.author) e.author = authorId(slugify(p.author))\n for (const t of taxes) {\n e[taxModelId(t)] = p.terms\n .filter((x) => x.taxonomy === t && contents[taxModelId(t)]![termId(t, x.slug)])\n .map((x) => termId(t, x.slug))\n }\n if (fields.cover && p.meta._thumbnail_id) {\n const m = mediaRef(Number(p.meta._thumbnail_id))\n if (m) e.cover = m\n else report.dropped_relations++\n }\n if (fields.parent && p.parent) {\n const pe = postEntry.get(p.parent)\n if (pe) e.parent = parentModels.length > 1 ? pe : pe.ref\n else report.dropped_relations++\n }\n if (fields.menu_order && p.menu_order) e.menu_order = p.menu_order\n if (fields.sticky) e.sticky = p.sticky ?? false\n if (fields.template && typeof p.meta._wp_page_template === 'string' && p.meta._wp_page_template !== 'default')\n e.template = p.meta._wp_page_template\n if (fields.format) {\n const f = p.terms.find((t) => t.taxonomy === 'post_format')\n if (f) e.format = f.slug.replace(/^post-format-/, '')\n }\n if (fields.visibility) e.visibility = p.password ? 'password' : p.status === 'private' ? 'private' : 'public'\n if (fields.comments_open) e.comments_open = p.comment_status === 'open'\n for (const k of Object.keys(fields)) if (k in p.meta && !(k in e) && !k.startsWith('_')) e[k] = p.meta[k]\n for (const [k, acf] of Object.entries(p.acf ?? {})) {\n const plan = acfFields.get(k)\n if (!plan || k in e) continue\n const v = acfEntryValue(k, plan, acf.value)\n if (v !== undefined) e[k] = v\n }\n contentBucket[id] = e\n metaBucket[id] = mapStatus(p)\n }\n }\n\n // ── menus ──\n const menus = raw.menus ?? []\n if (menus.length) {\n addModel({\n id: 'menus', name: 'Menus', kind: 'collection', domain: 'site', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n items: { type: 'relations', model: 'menu-items', label: 'Items', order: 30 },\n wp_id: { type: 'integer', label: 'WP term ID', order: 40 },\n // Only when the source said where its menus are shown: stores from sources that do not know stay as they were.\n ...(menus.some((m) => m.locations?.length) ? { locations: { type: 'array', items: 'string', label: 'Locations', order: 50 } as FieldDef } : {}),\n },\n })\n const toTarget = relationOver([...contentModelIds, ...taxonomies.map(taxModelId)])\n addModel({\n id: 'menu-items', name: 'Menu items', kind: 'collection', domain: 'site', i18n: false, title_field: 'title',\n fields: {\n title: { type: 'string', required: true, label: 'Label', order: 10 },\n menu: { type: 'relation', model: 'menus', required: true, label: 'Menu', order: 20 },\n order: { type: 'integer', label: 'Order', order: 30 },\n parent: { type: 'relation', model: 'menu-items', label: 'Parent item', order: 40 },\n type: { type: 'select', options: ['custom', 'post_type', 'taxonomy', 'post_type_archive'], label: 'Type', order: 50 },\n url: { type: 'url', label: 'URL', order: 60 },\n target: { type: 'relation', model: toTarget.model, label: 'Target', order: 70 },\n open_in_new_tab: { type: 'boolean', label: 'Open in new tab', order: 80 },\n classes: { type: 'array', items: 'string', label: 'CSS classes', order: 90 },\n description: { type: 'text', label: 'Description', order: 100 },\n wp_id: { type: 'integer', label: 'WP post ID', order: 110 },\n },\n })\n const itemRef = (id: number): string => hexId(`menu-items:${id}`)\n for (const m of menus) {\n const mid = hexId(`menus:${m.slug}`)\n contents.menus![mid] = {\n name: strip(m.name),\n slug: addressSlug(m.slug) || `menu-${m.id}`,\n items: m.items.map((i) => itemRef(i.id)),\n // An inline navigation has no WordPress record (a negative placeholder): none is claimed.\n ...(m.id !== null && m.id > 0 ? { wp_id: m.id } : {}),\n ...(m.locations?.length ? { locations: m.locations } : {}),\n }\n metas.menus![mid] = importMeta('published')\n for (const i of m.items) {\n const e: Entry = {\n title: strip(i.title) || i.url || `item-${i.id}`,\n menu: mid,\n order: i.order,\n type: i.target.kind === 'url' ? 'custom' : i.target.kind === 'post' ? 'post_type' : i.target.kind === 'term' ? 'taxonomy' : i.target.kind === 'archive' ? 'post_type_archive' : 'custom',\n // A block navigation's items have no WordPress id (negative placeholders): none is claimed.\n ...(i.id > 0 ? { wp_id: i.id } : {}),\n open_in_new_tab: i.target_attr === '_blank',\n }\n if (i.parent && !i.parent_unresolved) e.parent = itemRef(i.parent)\n // An archive has no entry to point at: its address is all the store can keep, and the site serves it only when the type has one.\n if ((i.target.kind === 'url' || i.target.kind === 'archive') && i.url) e.url = i.url\n if (i.target.kind === 'post' && i.target.resolved && i.target.id != null) {\n const pe = postEntry.get(i.target.id)\n if (pe) e.target = toTarget.ref(pe)\n else report.dropped_relations++\n }\n if (i.target.kind === 'term' && i.target.resolved && i.target.slug && models[taxModelId(i.target.taxonomy)])\n e.target = toTarget.ref({ model: taxModelId(i.target.taxonomy), ref: termId(i.target.taxonomy, i.target.slug) })\n if (i.classes?.length) e.classes = i.classes\n if (i.description) e.description = strip(i.description)\n contents['menu-items']![itemRef(i.id)] = e\n metas['menu-items']![itemRef(i.id)] = importMeta(i.status === 'publish' ? 'published' : 'draft')\n }\n }\n }\n\n // ── comments (frozen archive collection; the live-service path is CommentsExport) ──\n const comments = raw.comments ?? []\n if (comments.length) {\n addModel({\n id: 'comments', name: 'Comments', kind: 'collection', domain: 'blog', i18n: false, title_field: 'author',\n fields: {\n author: { type: 'string', required: true, label: 'Author', order: 10 },\n email: { type: 'email', label: 'Email', order: 20 },\n url: { type: 'url', label: 'Website', order: 30 },\n body: { type: 'richtext', label: 'Body', order: 40 },\n published_at: { type: 'datetime', label: 'Date', order: 50 },\n post: { type: 'relation', model: toContent.model, required: true, label: 'Post', order: 60 },\n parent: { type: 'relation', model: 'comments', label: 'In reply to', order: 70 },\n type: { type: 'string', label: 'Type', order: 80 },\n user: { type: 'relation', model: 'authors', label: 'User', order: 90 },\n wp_id: { type: 'integer', label: 'WP comment ID', order: 100 },\n },\n })\n const cRef = (id: number): string => hexId(`comments:${id}`)\n const userById = new Map(raw.authors.filter((a) => a.id != null).map((a) => [a.id, authorId(slugify(a.login))]))\n for (const c of comments) {\n const post = postEntry.get(c.post)\n if (!post) {\n report.dropped_relations++\n continue\n }\n contents.comments![cRef(c.id)] = pick(\n {\n author: strip(c.author) || 'anonymous',\n email: c.email,\n url: c.url,\n body: c.content,\n published_at: c.date,\n post: toContent.ref(post),\n parent: c.parent && c.parent_resolved ? cRef(c.parent) : null,\n type: c.type,\n user: c.user_id ? userById.get(c.user_id) : null,\n wp_id: c.id,\n },\n new Set(['author', 'email', 'url', 'body', 'published_at', 'post', 'parent', 'type', 'user', 'wp_id']),\n )\n metas.comments![cRef(c.id)] = importMeta(\n c.approved === '1' ? 'published' : c.approved === 'spam' || c.approved === 'trash' ? 'archived' : 'in_review',\n )\n }\n }\n\n // ── site singleton + vocabulary ──\n const siteFields: Record<string, FieldDef> = {\n title: { type: 'string', required: true, label: 'Site title', order: 10 },\n tagline: { type: 'string', label: 'Tagline', order: 20 },\n url: { type: 'url', label: 'URL', order: 30 },\n language: { type: 'string', label: 'Language', order: 40 },\n }\n // ACF Options Pages (Bridge): site-wide fields that belong to no post, typed like a post's ACF. A name that is a\n // core field or sits on more than one page takes the page's slug as a prefix (ACF's default `acf-options-` left\n // off), so no page overwrites another. A name still taken after that gets a counter and a line in the report.\n const optionPages = raw.acf_options ?? []\n const pagesOf = new Map<string, number>()\n for (const page of optionPages) for (const k of Object.keys(page.fields)) pagesOf.set(k, (pagesOf.get(k) ?? 0) + 1)\n const optionFields: Record<string, RawAcfValue> = {}\n const claim = (page: RawAcfOptionsPage, k: string, want: string) => {\n let name = want\n for (let n = 2; siteFields[name] || name in optionFields; n++) name = `${want}_${n}`\n if (name !== want) report.acf_options_renamed[name] = `${page.slug}.${k}`\n optionFields[name] = page.fields[k]!\n }\n const prefixed: [RawAcfOptionsPage, string][] = []\n for (const page of optionPages) {\n for (const k of Object.keys(page.fields)) {\n if (siteFields[k] || pagesOf.get(k)! > 1) prefixed.push([page, k])\n else claim(page, k, k)\n }\n }\n // Plain names first: a field literally named `footer_phone` keeps it; the prefixed one takes the counter.\n for (const [page, k] of prefixed) claim(page, k, `${page.slug.replace(/^acf-options-(?=.)/, '').replace(/-/g, '_')}_${k}`)\n const optionPlan = acfPlan([{ acf: optionFields } as RawPost], (k) => !!siteFields[k])\n let so = 40\n for (const [k, plan] of optionPlan) {\n const def = plan.def ?? { type: plan.multiple ? 'relations' : 'relation', model: plan.models.size > 1 ? [...plan.models].toSorted() : [...plan.models][0]! } as FieldDef\n siteFields[k] = { ...def, ...(def.label ? {} : { label: k }), description: def.description ?? 'ACF', order: (so += 10) }\n report.acf_options[k] = plan.def ? plan.def.type : `${def.type}:${[...plan.models].toSorted().join('|')}`\n }\n addModel({ id: 'site', name: 'Site', kind: 'singleton', domain: 'site', i18n: false, title_field: 'title', fields: siteFields })\n siteEntry = pick(\n { title: strip(raw.site.title), tagline: raw.site.description, url: raw.site.url, language: raw.site.language },\n new Set(['title', 'tagline', 'url', 'language']),\n )\n for (const [k, plan] of optionPlan) {\n const v = acfEntryValue(k, plan, optionFields[k]!.value)\n if (v !== undefined) siteEntry[k] = v\n }\n siteMeta = importMeta('published')\n report.site_title_missing = !siteEntry.title\n const vocabTerms: Record<string, Record<string, string>> = {}\n for (const m of menus) {\n for (const i of m.items) {\n const k = slugify(strip(i.title))\n if (k && !vocabTerms[k]) vocabTerms[k] = { [locale]: strip(i.title) }\n }\n }\n\n // ── file map (canonical serialization; PATH_PATTERNS layout) ──\n const files: Record<string, string> = {}\n const domains = [...new Set(Object.values(models).map((m) => m.domain))].toSorted()\n for (const m of Object.values(models)) {\n files[`.contentrain/models/${m.id}.json`] = canon(m)\n if (m.i18n) {\n // One content + meta file per locale; an entry id recurs across the\n // locales it has a translation in.\n const perLocale = localeContents[m.id] ?? {}\n const ids = new Set<string>()\n for (const loc of Object.keys(perLocale).toSorted()) {\n files[`.contentrain/content/${m.domain}/${m.id}/${loc}.json`] = canon(perLocale[loc])\n files[`.contentrain/meta/${m.id}/${loc}.json`] = canon(localeMetas[m.id]?.[loc] ?? {})\n for (const id of Object.keys(perLocale[loc]!)) ids.add(id)\n }\n report.models[m.id] = { kind: m.kind, domain: m.domain, fields: Object.keys(m.fields ?? {}).length, entries: ids.size }\n continue\n }\n const content = m.kind === 'singleton' ? siteEntry : contents[m.id]!\n const meta = m.kind === 'singleton' ? siteMeta : metas[m.id]!\n files[`.contentrain/content/${m.domain}/${m.id}/data.json`] = canon(content)\n files[`.contentrain/meta/${m.id}/${locale}.json`] = canon(meta)\n report.models[m.id] = {\n kind: m.kind,\n domain: m.domain,\n fields: Object.keys(m.fields ?? {}).length,\n entries: m.kind === 'singleton' ? 1 : Object.keys(contents[m.id]!).length,\n }\n }\n files['.contentrain/config.json'] = canon({\n version: 1,\n stack: 'astro',\n platform: 'web',\n workflow: 'review',\n locales: { default: locale, supported: locales },\n domains,\n })\n files['.contentrain/vocabulary.json'] = canon({ version: 1, terms: vocabTerms })\n\n const entrySourceMap: EntrySourceMap = {}\n for (const [wpId, ref] of postEntry) {\n entrySourceMap[String(wpId)] = { model_id: ref.model, entry_id: ref.ref, locale: postLocale(postById.get(wpId)!) }\n }\n\n files['import-report.json'] = canon(report)\n return { files, entry_source_map: entrySourceMap, report }\n}\n","// CommentsExport builder — the bridge from a migrated static site to a live\n// comments service. Everything the receiving side needs travels here: the\n// entry addresses (WordPress ids mean nothing after migration), the verbatim\n// comments, and which threads were closed at the source.\n\nimport type { CommentsExport, EntrySourceMap, HandoffComments, RawComment, RawIR } from '@contentrain/types'\nimport { COMMENTS_EXPORT_FORMAT, MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\n\n/**\n * The comments that may leave the source site (see `CommentsExport.comments`). An allowlist, so it\n * fails closed: a comment travels only when its entry is in this RawIR and public, and its status is\n * approved (`'1'`, or none) or pending (`'0'`). Everything else is counted in `excluded`: spam, trash,\n * WordPress's `post-trashed`, a plugin's own status, a post this RawIR does not hold.\n */\nexport function selectComments(raw: RawIR): { comments: RawComment[]; excluded: NonNullable<CommentsExport['excluded']> } {\n const posts = new Map(raw.posts.map((p) => [p.id, p]))\n const excluded: NonNullable<CommentsExport['excluded']> = {}\n const count = (key: keyof typeof excluded) => { excluded[key] = (excluded[key] ?? 0) + 1 }\n const comments: RawComment[] = []\n for (const c of raw.comments ?? []) {\n const post = posts.get(c.post)\n if (!post) { count('unknown_entry'); continue }\n if (post.status !== 'publish' || (post.password !== null && post.password !== undefined && post.password !== '')) { count('non_public_entry'); continue }\n const status = c.approved ?? '1'\n if (status === '1' || status === '0') { comments.push(c); continue }\n count(status === 'spam' ? 'spam' : status === 'trash' ? 'trash' : 'other_status')\n }\n return { comments, excluded }\n}\n\nexport function buildCommentsExport(raw: RawIR, entries: EntrySourceMap, opts?: { generated_at?: string }): CommentsExport {\n const threadsClosed = raw.posts.filter((p) => p.comment_status && p.comment_status !== 'open').map((p) => p.id)\n const { comments, excluded } = selectComments(raw)\n return {\n version: MIGRATION_CONTRACT_VERSION,\n format: COMMENTS_EXPORT_FORMAT,\n source: raw.provenance,\n site_url: raw.site.url || undefined,\n generated_at: opts?.generated_at ?? new Date().toISOString(),\n entries,\n threads_closed: threadsClosed.length ? threadsClosed : undefined,\n comments,\n excluded: Object.keys(excluded).length ? excluded : undefined,\n }\n}\n\n/** Handoff summary for the export: counts + closed threads + what could not be addressed. */\nexport function summarizeComments(exp: CommentsExport): HandoffComments {\n const byStatus: Record<string, number> = {}\n const byType: Record<string, number> = {}\n const unresolved: Array<{ comment_id: number; post: number; reason: string }> = []\n for (const c of exp.comments) {\n byStatus[c.approved ?? '1'] = (byStatus[c.approved ?? '1'] ?? 0) + 1\n byType[c.type ?? 'comment'] = (byType[c.type ?? 'comment'] ?? 0) + 1\n if (!exp.entries[String(c.post)]) unresolved.push({ comment_id: c.id, post: c.post, reason: 'post has no entry mapping' })\n }\n return {\n total: exp.comments.length,\n by_status: byStatus,\n types: byType,\n export: { format: exp.format },\n threads_closed: exp.threads_closed,\n unresolved: unresolved.length ? unresolved : undefined,\n excluded: exp.excluded,\n }\n}\n","// SourceDeltaPlan (as a bridge produces it) + the repository's store → a plan\n// a person can review: every origin record placed in the store, or said to be\n// unplaceable and why.\n//\n// The bridge knows what changed at the origin and nothing about the store; the\n// store knows its entries and nothing about the origin. The EntrySourceMap\n// written at import time is the only link, so this module lives next to the\n// code that writes it. Pure over file maps, like `rawToContentrain`: no git,\n// no provider, and nothing is written — applying a plan is a governed write\n// that belongs to whoever reviews it.\n//\n// What the planner refuses to do is decide. A record the repository also\n// edited is flagged, not overwritten; a trashed record stays distinguishable\n// from a purged one; a record it cannot place says why instead of vanishing.\n\nimport type { EntryMeta, EntrySourceMap, ModelDefinition, SourceDeltaEntry, SourceDeltaPlan } from '@contentrain/types'\nimport { canon, taxModelId } from './core.js'\n\n/** A `.contentrain` store as a file map (repo-relative path → file text), with the source map it was built from. */\nexport interface DeltaStore {\n files: Record<string, string>\n entry_source_map: EntrySourceMap\n}\n\nexport interface PlanSourceDeltaInput {\n /** The origin delta, as the bridge wrote it. */\n delta: SourceDeltaPlan\n /** The repository's store, as it is now — including edits made since the import. */\n store: DeltaStore\n /** The new export the delta describes. Without it the plan has no field-level differences and no address for a created record. */\n incoming?: DeltaStore\n /**\n * Origin types that are taxonomies. Their ids are term ids, which the\n * source map (post ids) must never be consulted for: post 6 and category 6\n * are different records. Defaults to WordPress core's.\n */\n taxonomies?: string[]\n /**\n * `updated_by` values that mean \"written by an import\". Meta with any other\n * writer — or with a `source` other than `import` — is a repository edit.\n */\n importers?: string[]\n}\n\nexport const DEFAULT_TAXONOMIES = ['category', 'post_tag', 'nav_menu', 'post_format'] as const\nexport const DEFAULT_IMPORTERS = ['contentrain-bridge', '@contentrain/wp-import'] as const\n\ninterface Placed {\n model: ModelDefinition\n entry_id: string\n locale: string\n}\n\ntype Placement = Placed | { unmapped: NonNullable<SourceDeltaEntry['unmapped']> }\n\n/** A stored entry, reduced to what a comparison needs: each field's value as text, and its meta. */\ninterface StoredEntry {\n fields: Record<string, string>\n meta?: EntryMeta\n}\n\n// ─── Store reading ───\n\nconst parseJson = (text: string | undefined): unknown => {\n if (text === undefined) return undefined\n try {\n return JSON.parse(text)\n }\n catch {\n return undefined\n }\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined\n\nfunction readModel(files: Record<string, string>, id: string): ModelDefinition | undefined {\n const model = asRecord(parseJson(files[`.contentrain/models/${id}.json`]))\n return model && model.id === id ? (model as unknown as ModelDefinition) : undefined\n}\n\nfunction defaultLocale(files: Record<string, string>): string {\n const config = asRecord(parseJson(files['.contentrain/config.json']))\n const locales = asRecord(config?.locales)\n return typeof locales?.default === 'string' ? locales.default : 'en'\n}\n\n/** The model's own directory. A custom `content_path` or locale strategy is not read — the entry is reported as not found. */\nconst contentDir = (model: ModelDefinition): string | undefined =>\n model.content_path || (model.locale_strategy && model.locale_strategy !== 'file')\n ? undefined\n : `.contentrain/content/${model.domain}/${model.id}`\n\n/**\n * A markdown document's fields as raw text: each top-level frontmatter key\n * with its value lines (a list's items included), and `body`. Compared as\n * written — the store is canonical, so equal values are equal text.\n */\nfunction documentFields(text: string): Record<string, string> {\n const fields: Record<string, string> = {}\n const match = /^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/.exec(text)\n if (!match) return { body: text }\n let key: string | undefined\n for (const line of match[1]!.split('\\n')) {\n const top = /^([^\\s:#][^:]*):(.*)$/.exec(line)\n if (top) {\n key = top[1]!.trim()\n fields[key] = top[2]!.trim()\n }\n else if (key !== undefined) {\n fields[key] += `\\n${line}`\n }\n }\n fields.body = match[2]!\n return fields\n}\n\nfunction readEntry(files: Record<string, string>, at: Placed): StoredEntry | undefined {\n const { model, entry_id: id, locale } = at\n const dir = contentDir(model)\n if (!dir) return undefined\n if (model.kind === 'document') {\n const text = files[model.i18n ? `${dir}/${id}/${locale}.md` : `${dir}/${id}.md`]\n if (text === undefined) return undefined\n const meta = asRecord(parseJson(files[`.contentrain/meta/${model.id}/${id}/${locale}.json`]))\n return { fields: documentFields(text), meta: meta as EntryMeta | undefined }\n }\n if (model.kind !== 'collection') return undefined\n const entries = asRecord(parseJson(files[`${dir}/${model.i18n ? locale : 'data'}.json`]))\n const entry = asRecord(entries?.[id])\n if (!entry) return undefined\n const metas = asRecord(parseJson(files[`.contentrain/meta/${model.id}/${locale}.json`]))\n const fields = Object.fromEntries(Object.entries(entry).map(([key, value]) => [key, canon(value)]))\n return { fields, meta: asRecord(metas?.[id]) as EntryMeta | undefined }\n}\n\n/** The entry in `model` whose `wp_id` is `wpId`, for records the source map does not list (terms, media). */\nfunction findByWpId(files: Record<string, string>, model: ModelDefinition, wpId: number, locale: string): string | undefined {\n const dir = contentDir(model)\n if (!dir) return undefined\n if (model.kind === 'collection') {\n const entries = asRecord(parseJson(files[`${dir}/${model.i18n ? locale : 'data'}.json`])) ?? {}\n return Object.keys(entries).find(id => asRecord(entries[id])?.wp_id === wpId)\n }\n if (model.kind !== 'document') return undefined\n const suffix = model.i18n ? `/${locale}.md` : '.md'\n for (const [path, text] of Object.entries(files)) {\n if (!path.startsWith(`${dir}/`) || !path.endsWith(suffix)) continue\n if (documentFields(text).wp_id === String(wpId)) {\n const rest = path.slice(dir.length + 1, -suffix.length)\n if (!rest.includes('/')) return rest\n }\n }\n return undefined\n}\n\n/** Store models that can hold records of an origin type the source map does not cover. */\nfunction typeModelIds(wpType: string): string[] {\n if (wpType === 'attachment') return ['wp-media', 'media']\n return [`wp-tax-${wpType.replace(/_/g, '-')}`, taxModelId(wpType)]\n}\n\nfunction place(store: DeltaStore, wpType: string | undefined, wpId: number, taxonomies: Set<string>): Placement {\n const { files } = store\n const locale = defaultLocale(files)\n const models = wpType ? typeModelIds(wpType).map(id => readModel(files, id)).filter(model => model !== undefined) : []\n // A listed taxonomy, media, or any type the store has a model of its own for\n // is found by `wp_id` in that model. Only what is left falls to the map.\n if (wpType && (wpType === 'attachment' || taxonomies.has(wpType) || models.length)) {\n if (!models.length) return { unmapped: 'no-model-for-type' }\n for (const model of models) {\n const entryId = findByWpId(files, model, wpId, locale)\n if (entryId) return { model, entry_id: entryId, locale }\n }\n return { unmapped: 'entry-not-found' }\n }\n const ref = store.entry_source_map[String(wpId)]\n if (!ref) return { unmapped: 'not-in-source-map' }\n const model = readModel(files, ref.model_id)\n if (!model) return { unmapped: 'no-model-for-type' }\n return { model, entry_id: ref.entry_id, locale: ref.locale ?? locale }\n}\n\n// ─── Planning ───\n\nconst isPlaced = (placement: Placement): placement is Placed => 'model' in placement\n\nfunction repoEdit(meta: EntryMeta | undefined, importers: Set<string>): SourceDeltaEntry['repo_edit'] {\n if (!meta) return undefined\n if (meta.source === 'import' && importers.has(meta.updated_by)) return undefined\n return {\n updated_by: meta.updated_by,\n ...(meta.updated_at ? { updated_at: meta.updated_at } : {}),\n source: meta.source,\n }\n}\n\nfunction changedFields(before: StoredEntry, after: StoredEntry): string[] {\n const keys = new Set([...Object.keys(before.fields), ...Object.keys(after.fields)])\n return [...keys].filter(key => before.fields[key] !== after.fields[key]).toSorted()\n}\n\nconst DELETED_DETAIL = {\n trashed: 'tombstone: trashed at the origin — it can still come back',\n purged: 'tombstone: purged from the origin',\n} as const\n\nfunction planEntry(entry: SourceDeltaEntry, input: PlanSourceDeltaInput, taxonomies: Set<string>, importers: Set<string>): SourceDeltaEntry {\n const { store, incoming } = input\n const out: SourceDeltaEntry = { ...entry }\n // The bridge's detail for a deletion is the kind itself; the tombstone note below says it in full.\n const notes: string[] = entry.detail && entry.detail !== entry.deleted_kind ? [entry.detail] : []\n\n // A created record is not in the store yet; its address comes from the export that carries it.\n const target = entry.op === 'created'\n ? (incoming ? place(incoming, entry.wp_type, entry.wp_id, taxonomies) : { unmapped: 'not-in-source-map' as const })\n : place(store, entry.wp_type, entry.wp_id, taxonomies)\n\n if (!isPlaced(target)) {\n out.unmapped = target.unmapped\n if (entry.op === 'created' && !incoming) notes.push('no incoming export to place it')\n if (entry.op === 'deleted' && entry.deleted_kind) notes.push(DELETED_DETAIL[entry.deleted_kind])\n out.detail = notes.join('; ')\n return out\n }\n\n out.model = target.model.id\n out.entry_id = target.entry_id\n out.locale = target.locale\n const stored = readEntry(store.files, target)\n\n if (entry.op === 'created') {\n if (stored) notes.push('the store already has an entry at this address')\n }\n else if (!stored) {\n out.unmapped = 'entry-not-found'\n }\n\n if (entry.op === 'deleted' && entry.deleted_kind) notes.push(DELETED_DETAIL[entry.deleted_kind])\n\n if ((entry.op === 'updated' || entry.op === 'moved') && stored) {\n const after = incoming ? place(incoming, entry.wp_type, entry.wp_id, taxonomies) : undefined\n const next = after && isPlaced(after) ? readEntry(incoming!.files, after) : undefined\n if (next) {\n out.fields_changed = changedFields(stored, next)\n if (isPlaced(after!) && after.entry_id !== target.entry_id) out.entry_id_after = after.entry_id\n }\n else {\n notes.push(incoming ? 'not in the incoming export' : 'no incoming export to compare with')\n }\n }\n\n const edit = repoEdit(stored?.meta, importers)\n if (edit) {\n out.conflict = true\n out.repo_edit = edit\n notes.push(`also edited in the repository by ${edit.updated_by}${edit.updated_at ? ` at ${edit.updated_at}` : ''} — not overwritten`)\n }\n\n if (notes.length) out.detail = notes.join('; ')\n return out\n}\n\n/**\n * Place a bridge's source delta in the repository's store.\n *\n * Every entry keeps the bridge's facts (op, ids, fingerprints, paths,\n * `deleted_kind`) and gains its store address — or `unmapped` with the reason.\n * `updated` and `moved` gain `fields_changed` against the incoming export; a\n * record the repository also edited gets `conflict: true` and `repo_edit`;\n * every `moved` whose address changed adds a 301 to `redirects`.\n *\n * Nothing is written and nothing is decided: a conflict is reported for a\n * person to resolve, and applying the plan is a separate, governed step.\n */\nexport function planSourceDelta(input: PlanSourceDeltaInput): SourceDeltaPlan {\n const taxonomies = new Set<string>(input.taxonomies ?? DEFAULT_TAXONOMIES)\n const importers = new Set<string>(input.importers ?? DEFAULT_IMPORTERS)\n const { delta } = input\n const entries = delta.entries.map(entry => planEntry(entry, input, taxonomies, importers))\n\n const redirects = [...(delta.redirects ?? [])]\n const seen = new Set(redirects.map(redirect => redirect.from))\n for (const entry of entries) {\n if (entry.op !== 'moved' || !entry.path_before || !entry.path_after || entry.path_before === entry.path_after) continue\n if (seen.has(entry.path_before)) continue\n seen.add(entry.path_before)\n redirects.push({ from: entry.path_before, to: entry.path_after, status: 301 })\n }\n\n const warnings = [...(delta.warnings ?? [])]\n if (!delta.deletions_detectable) warnings.push('deletions could not be determined from this cursor; the absence of a deleted entry does not mean nothing was deleted')\n if (delta.deletions_undetectable_types?.length) warnings.push(`deletions could not be determined for: ${delta.deletions_undetectable_types.join(', ')}`)\n if (!input.incoming) warnings.push('no incoming export: no field-level differences and no address for created records')\n\n return {\n ...delta,\n entries,\n ...(redirects.length ? { redirects } : {}),\n ...(warnings.length ? { warnings } : {}),\n }\n}\n\n// ─── Report ───\n\nconst address = (entry: SourceDeltaEntry): string =>\n entry.model && entry.entry_id ? `${entry.model}/${entry.entry_id}${entry.entry_id_after ? ` → ${entry.entry_id_after}` : ''}` : `unmapped (${entry.unmapped})`\n\n/** The plan as text, for a dry run: one line per record, then conflicts, unmapped records, redirects and warnings. */\nexport function formatSourceDeltaReport(plan: SourceDeltaPlan): string {\n const counts = new Map<string, number>()\n for (const entry of plan.entries) counts.set(entry.op, (counts.get(entry.op) ?? 0) + 1)\n const summary = [...counts].map(([op, n]) => `${n} ${op}`).join(', ') || 'no changes'\n const { cursor } = plan\n const lines = [\n `Source delta: ${plan.entries.length} records (${summary})`,\n `Cursor: ${[cursor.kind, cursor.inventory_hash ?? cursor.modified_after ?? cursor.export_id, `(${cursor.taken_at})`].filter(Boolean).join(' ')}`,\n `Deletions: ${plan.deletions_detectable ? 'detectable' : 'NOT detectable'}`,\n '',\n ]\n for (const entry of plan.entries) {\n const parts = [`${entry.op.padEnd(8)} ${entry.wp_type ?? '?'} ${entry.wp_id}`, address(entry)]\n if (entry.op === 'moved' && entry.path_before) parts.push(`${entry.path_before} → ${entry.path_after}`)\n if (entry.deleted_kind) parts.push(entry.deleted_kind)\n if (entry.fields_changed) parts.push(`fields: ${entry.fields_changed.join(', ') || 'none'}`)\n if (entry.conflict) parts.push('CONFLICT')\n lines.push(` ${parts.join(' ')}`)\n }\n const conflicts = plan.entries.filter(entry => entry.conflict)\n const unmapped = plan.entries.filter(entry => entry.unmapped)\n lines.push('', `Conflicts (${conflicts.length})${conflicts.length ? ':' : ''}`)\n for (const entry of conflicts) lines.push(` ${entry.wp_type} ${entry.wp_id} → ${address(entry)}: edited by ${entry.repo_edit?.updated_by}${entry.repo_edit?.updated_at ? ` at ${entry.repo_edit.updated_at}` : ''}`)\n lines.push(`Unmapped (${unmapped.length})${unmapped.length ? ':' : ''}`)\n for (const entry of unmapped) lines.push(` ${entry.op} ${entry.wp_type} ${entry.wp_id}: ${entry.unmapped}`)\n lines.push(`Redirects (${plan.redirects?.length ?? 0})${plan.redirects?.length ? ':' : ''}`)\n for (const redirect of plan.redirects ?? []) lines.push(` ${redirect.from} → ${redirect.to} (${redirect.status})`)\n for (const warning of plan.warnings ?? []) lines.push(`Warning: ${warning}`)\n lines.push('', 'Dry run: nothing was written. Applying a plan goes through review.')\n return `${lines.join('\\n')}\\n`\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["iso"],"sources":["../src/php-unserialize.ts","../src/core.ts","../src/wxr.ts","../src/acf.ts","../src/rest-redirects.ts","../src/rest-menus.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/delta.ts"],"sourcesContent":["// Small PHP serialize() decoder, ported from the measured import chain.\n// Supported: s (byte-length strings), i, d, b, N, a (array → list or object), O (object → { __class, … }).\n// PHP string lengths are BYTES, so the walk happens over a Buffer, not a JS string.\n\nexport interface UnserializeResult {\n ok: boolean\n serialized: boolean\n value: unknown\n error?: string\n}\n\nexport function looksSerialized(s: unknown): s is string {\n return typeof s === 'string' && /^(a|O):\\d+:[{\"]|^(s|i|d|b):[^;]+;?$|^N;$/.test(s)\n}\n\nexport function phpUnserialize(str: string): unknown {\n const buf = Buffer.from(str, 'utf8')\n let p = 0\n const fail = (m: string): never => {\n throw new Error(`unserialize: ${m} at byte ${p}`)\n }\n const readUntil = (ch: string): string => {\n const i = buf.indexOf(ch, p)\n if (i < 0) fail(`expected ${ch}`)\n const s = buf.toString('utf8', p, i)\n p = i + 1\n return s\n }\n const expect = (ch: string): void => {\n if (buf[p] !== ch.charCodeAt(0)) fail(`expected '${ch}' got '${String.fromCharCode(buf[p] ?? 0)}'`)\n p++\n }\n const value = (): unknown => {\n const t = String.fromCharCode(buf[p] ?? 0)\n p++\n switch (t) {\n case 'N':\n expect(';')\n return null\n case 'b': {\n expect(':')\n return readUntil(';') === '1'\n }\n case 'i': {\n expect(':')\n return Number(readUntil(';'))\n }\n case 'd': {\n expect(':')\n const v = readUntil(';')\n return v === 'INF' ? Infinity : v === '-INF' ? -Infinity : v === 'NAN' ? Number.NaN : Number(v)\n }\n case 's': {\n expect(':')\n const n = Number(readUntil(':'))\n expect('\"')\n const s = buf.toString('utf8', p, p + n)\n p += n\n expect('\"')\n expect(';')\n return s\n }\n case 'a': {\n expect(':')\n const n = Number(readUntil(':'))\n expect('{')\n const entries: Array<[unknown, unknown]> = []\n for (let i = 0; i < n; i++) {\n const k = value()\n const v = value()\n entries.push([k, v])\n }\n expect('}')\n // consecutive 0..n-1 integer keys → JSON list; anything else → object\n const isList = entries.every(([k], i) => k === i)\n return isList ? entries.map(([, v]) => v) : Object.fromEntries(entries.map(([k, v]) => [String(k), v]))\n }\n case 'O': {\n expect(':')\n readUntil(':')\n expect('\"')\n const cls = readUntil('\"')\n expect(':')\n const n = Number(readUntil(':'))\n expect('{')\n const o: Record<string, unknown> = { __class: cls }\n for (let i = 0; i < n; i++) {\n const k = value()\n const v = value()\n o[String(k).split('\\u0000').at(-1) ?? String(k)] = v\n }\n expect('}')\n return o\n }\n default:\n return fail(`unknown type '${t}'`)\n }\n }\n const v = value()\n if (p !== buf.length) fail(`trailing ${buf.length - p} bytes`)\n return v\n}\n\n/** Attempt a decode; on failure the value stays exactly as it was. */\nexport function tryUnserialize(s: string): UnserializeResult {\n if (!looksSerialized(s)) return { ok: false, serialized: false, value: s }\n try {\n return { ok: true, serialized: true, value: phpUnserialize(s) }\n } catch (e) {\n return { ok: false, serialized: true, value: s, error: e instanceof Error ? e.message : String(e) }\n }\n}\n","// Shared conversion helpers, ported from the measured induction core.\n// The identity formulas here are load-bearing: hexId('posts:' + slug) must\n// produce the same entry id whether the site arrived via WXR or REST, or a\n// later delta import would duplicate every entry.\n\nimport { createHash } from 'node:crypto'\nimport type { FieldDef } from '@contentrain/types'\n\nexport const norm = (s: unknown): string => String(s ?? '').replace(/\\s+/g, ' ').trim()\n\n// The same table as the starter's summarize() (templates/astro-starter/src/lib/seo.ts);\n// kept here because a package cannot depend on a template.\nconst ENTITIES: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ', hellip: '…', mdash: '—', ndash: '–', rsquo: '’', lsquo: '‘', rdquo: '”', ldquo: '“' }\n\n/**\n * Decode character references once: `&amp;lt;` is `&lt;`, not `<`. A plain-text field\n * is escaped where it is printed (Astro's text escaping), so a reference left in it\n * would print as `&amp;hellip;`. An unknown name or a code point out of range stays.\n */\nexport const decodeEntities = (s: string): string =>\n s.replace(/&(?:#(\\d+)|#x([0-9a-f]+)|([a-z]+));/gi, (m, dec?: string, hex?: string, name?: string) => {\n if (name !== undefined) return ENTITIES[name] ?? ENTITIES[name.toLowerCase()] ?? m\n const code = dec !== undefined ? Number(dec) : Number.parseInt(hex!, 16)\n try {\n return String.fromCodePoint(code)\n } catch {\n return m\n }\n })\n\n/** Plain text from markup: tags out first (so `&lt;b&gt;` survives as text), then references decoded. */\nexport const strip = (s: unknown): string => norm(decodeEntities(String(s ?? '').replace(/<[^>]*>/g, ' ')))\n\n/** Entry id: deterministic hex from a stable key (model:slug style). */\nexport const hexId = (s: string): string => createHash('sha1').update(s).digest('hex').slice(0, 24)\n\nconst sortDeep = (v: unknown): unknown =>\n Array.isArray(v)\n ? v.map(sortDeep)\n : v && typeof v === 'object'\n ? Object.fromEntries(\n Object.keys(v as Record<string, unknown>)\n .toSorted()\n .map((k) => [k, sortDeep((v as Record<string, unknown>)[k])]),\n )\n : v\n\n/** Canonical serialization: sorted keys, 2-space indent, trailing newline. */\nexport const canon = (o: unknown): string => `${JSON.stringify(sortDeep(o), null, 2)}\\n`\n\n/** Field-type inference from a value (open meta / ACF fields). */\nexport const byValue = (v: unknown): string | null => {\n if (typeof v === 'boolean') return 'boolean'\n if (typeof v === 'number') return Number.isInteger(v) ? 'integer' : 'decimal'\n if (Array.isArray(v)) return 'array'\n if (v && typeof v === 'object') return 'object'\n const s = String(v ?? '').trim()\n if (!s) return null\n if (/^https?:\\/\\/\\S+\\.(mp3|m4a|wav|pdf|zip|docx?)(\\?|$)/i.test(s)) return 'file'\n if (/^https?:\\/\\/\\S+\\.(jpe?g|png|gif|webp|avif|svg)(\\?|$)/i.test(s)) return 'image'\n if (/^https?:\\/\\//.test(s)) return 'url'\n if (/^[^@\\s]+@[^@\\s]+\\.[a-z]{2,}$/i.test(s)) return 'email'\n if (/^\\d{4}-\\d{2}-\\d{2}([T ]\\d{2}:\\d{2})/.test(s)) return 'datetime'\n if (/<[a-z][\\s\\S]*>/i.test(s)) return 'richtext'\n return s.length > 200 ? 'text' : 'string'\n}\n\n/** What `RawPost.password` holds for a protected post: the fact, never the password. */\nexport const PROTECTED = '[protected]'\n\n/**\n * WP post types that never become content models: core plumbing (`wp_*`\n * covers `wp_global_styles`, `wp_navigation`, `wp_block`, `wp_template*`),\n * Jetpack, and theme/page-builder internals that store design, not content —\n * GeneratePress elements, GenerateBlocks styles, Elementor templates and\n * Contact Form 7 / WPForms definitions. ACF field/group records stay in:\n * their cross-model parent links are part of the lossless import contract.\n * Whether a stored record gets a public route is the route producer's decision.\n */\nexport const SKIP_TYPES =\n /^(attachment|nav_menu_item|wp_|jp_|pattern|revision|oembed_cache|customize_changeset|user_request|custom_css|gblocks_|gblocks-|gp_elements|gp-elements|elementor_library|e-landing-page|wpcf7_contact_form|wpforms)/\n\n/** Open meta keys that are plugin plumbing, not editorial fields. */\nexport const PLUGIN_META = /^(jetpack|wpdc|discourse|footnotes|inline_featured|spay_|advanced_seo|rank_math|yoast)/i\n\n/** WP core/plumbing meta keys (never editorial). */\nexport const CORE_META =\n /^(_edit_last|_edit_lock|_thumbnail_id|_wp_page_template|_wp_old_slug|_wp_attached_file|_wp_attachment_metadata|_wp_attachment_image_alt|_wp_attachment_backup_sizes|_wp_desired_post_slug|_wp_trash_meta_.*|_menu_item_.*|_oembed_.*|_publicize_.*|_wpas_.*|_pingme|_encloseme|enclosure|_last_editor_used_jetpack|_rest_api_.*|_wp_attachment_context|_wp_attachment_is_custom_header|_wp_attachment_is_custom_background|_customize_.*|_elementor_.*|_wpcom_.*|_wp_suggested_privacy_policy_content|geo_.*|_jetpack_.*|_links_to.*|_format_.*)$/\n\n/** Taxonomy → model id. */\nexport const taxModelId = (t: string): string =>\n t === 'post_tag' ? 'tags' : t === 'category' ? 'categories' : t.replace(/_/g, '-')\n\nexport const slugify = (s: unknown): string =>\n String(s ?? '')\n .normalize('NFKD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n/**\n * A WordPress `post_name` as the address it is: percent-encoded UTF-8 decoded, NFC, lowercase, anything outside letters,\n * digits and marks (the contract's slug alphabet) a hyphen. Nothing is transliterated: `日本語`, `ışık` and `straße`\n * stay what the source site served, because the slug is the page's address. ASCII comes out exactly as `slugify`\n * gives it. Empty when nothing of a word is left, or when the slug would not fit a file name (200 bytes).\n */\nexport const addressSlug = (raw: string): string => {\n const slug = decodeSlug(raw)\n .normalize('NFC')\n .toLowerCase()\n .normalize('NFC')\n .replace(/[^\\p{Ll}\\p{Lo}\\p{Lm}\\p{N}\\p{M}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n return new TextEncoder().encode(slug).length > 200 ? '' : slug\n}\n\nexport const decodeSlug = (s: string): string => {\n try {\n return decodeURIComponent(s)\n } catch {\n return s\n }\n}\n\n/** The measured core field skeleton for content models (same order/labels). */\nexport function coreFields(opts: {\n excerpt: boolean\n body: boolean\n date: boolean\n author: boolean\n taxes: string[]\n cover: boolean\n}): { fields: Record<string, FieldDef>; order: number } {\n const fields: Record<string, FieldDef> = {\n title: { type: 'string', required: true, label: 'Title', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n }\n let o = 30\n if (opts.excerpt) fields.excerpt = { type: 'text', label: 'Excerpt', order: (o += 10) }\n if (opts.body) fields.body = { type: 'richtext', label: 'Body', order: (o += 10) }\n if (opts.date) fields.published_at = { type: 'datetime', label: 'Published at', order: (o += 10) }\n if (opts.author) fields.author = { type: 'relation', model: 'authors', label: 'Author', order: (o += 10) }\n for (const t of opts.taxes) fields[taxModelId(t)] = { type: 'relations', model: taxModelId(t), label: t, order: (o += 10) }\n if (opts.cover) fields.cover = { type: 'relation', model: 'media', label: 'Cover', order: (o += 10) }\n return { fields, order: o }\n}\n","// WXR (WordPress eXtended RSS) → RawIR.\n//\n// Streaming (sax) parse: a 100 MB export holds only its records in memory,\n// never the XML. Ported from the measured import chain — the state machine,\n// the meta decoding, and the resolution passes are the parts three sessions\n// of corpus work already debugged; they are transliterated, not redesigned.\n\nimport sax from 'sax'\nimport type { Readable } from 'node:stream'\nimport type {\n RawIR,\n RawPost,\n RawLanguagePair,\n RawAttachment,\n RawAuthor,\n RawComment,\n RawMenu,\n RawMenuItem,\n RawMenuTarget,\n RawTerm,\n RawTermRef,\n RawAcfValue,\n} from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { tryUnserialize } from './php-unserialize.js'\nimport { strip, PROTECTED } from './core.js'\n\nexport interface WxrStats {\n serialized: { detected: number; decoded: number; failed: number; keys: string[] }\n acf_fields: number\n unresolved_terms: number\n counts: Record<string, number>\n}\n\nexport interface WxrParseResult {\n raw: RawIR\n stats: WxrStats\n}\n\ninterface XItem {\n [k: string]: unknown\n terms: Array<{ taxonomy: string; slug: string; name?: string }>\n postmeta: Array<{ key?: string; value?: string }>\n comments: Array<Record<string, string | Array<{ key?: string; value?: string }>>>\n}\n\nconst ts = (s: string | undefined): string | null =>\n !s || s.startsWith('0000-00-00') ? null : s.replace(' ', 'T')\nconst iso = (local: string | undefined, gmt: string | undefined): string | null =>\n gmt && !gmt.startsWith('0000') ? `${ts(gmt)}Z` : ts(local)\nconst num = (s: unknown): number => (s === '' || s == null ? 0 : Number(s))\nconst termKey = (tax: string, slug: string): string => `${tax}:${slug}`\n\nexport async function parseWxr(input: string | Readable, opts?: { tool?: string }): Promise<WxrParseResult> {\n const site: Record<string, unknown> = {}\n const authors: Array<Record<string, string>> = []\n const terms: Array<Record<string, string>> = []\n const items: XItem[] = []\n const stats: WxrStats = {\n serialized: { detected: 0, decoded: 0, failed: 0, keys: [] },\n acf_fields: 0,\n unresolved_terms: 0,\n counts: {},\n }\n const serializedKeySet = new Set<string>()\n\n // ── sax state machine (ported verbatim) ──\n const parser = sax.createStream(true, { trim: false })\n const path: string[] = []\n let text = ''\n let item: XItem | null = null\n let meta: { key?: string; value?: string } | null = null\n let comment: Record<string, string | Array<{ key?: string; value?: string }>> | null = null\n let cmeta: { key?: string; value?: string } | null = null\n let author: Record<string, string> | null = null\n let term: (Record<string, string> & { _tag?: string }) | null = null\n const channelText: Record<string, string> = {}\n\n const leaf = (name: string, into: Record<string, unknown>, map: Record<string, string>): void => {\n const target = map[name]\n if (target) into[target] = text\n }\n parser.on('opentag', (node) => {\n path.push(node.name)\n text = ''\n const n = node.name\n if (n === 'item') item = { terms: [], postmeta: [], comments: [] }\n else if (n === 'wp:postmeta') meta = {}\n else if (n === 'wp:comment') comment = { meta: [] }\n else if (n === 'wp:commentmeta') cmeta = {}\n else if (n === 'wp:author') author = {}\n else if (n === 'wp:category' || n === 'wp:tag' || n === 'wp:term') term = { _tag: n }\n else if (n === 'category' && item) {\n const attrs = node.attributes as Record<string, string>\n item.terms.push({ taxonomy: attrs.domain ?? '', slug: attrs.nicename ?? '' })\n }\n })\n parser.on('text', (t) => {\n text += t\n })\n parser.on('cdata', (t) => {\n text += t\n })\n parser.on('comment', (c) => {\n const m = /generator=\"([^\"]*)\"\\s+created=\"([^\"]*)\"/.exec(c)\n if (m) {\n site.generator = m[1]\n site.export_date = m[2]\n }\n })\n parser.on('closetag', (n) => {\n const parent = path[path.length - 2]\n if (cmeta) {\n if (n === 'wp:meta_key') cmeta.key = text\n else if (n === 'wp:meta_value') cmeta.value = text\n else if (n === 'wp:commentmeta') {\n ;(comment!.meta as Array<{ key?: string; value?: string }>).push(cmeta)\n cmeta = null\n }\n } else if (comment) {\n const map: Record<string, string> = {\n 'wp:comment_id': 'id',\n 'wp:comment_author': 'author',\n 'wp:comment_author_email': 'email',\n 'wp:comment_author_url': 'url',\n 'wp:comment_date': 'date',\n 'wp:comment_date_gmt': 'date_gmt',\n 'wp:comment_content': 'content',\n 'wp:comment_approved': 'approved',\n 'wp:comment_type': 'type',\n 'wp:comment_parent': 'parent',\n 'wp:comment_user_id': 'user_id',\n }\n leaf(n, comment, map)\n if (n === 'wp:comment') {\n item!.comments.push(comment)\n comment = null\n }\n } else if (meta) {\n if (n === 'wp:meta_key') meta.key = text\n else if (n === 'wp:meta_value') meta.value = text\n else if (n === 'wp:postmeta') {\n item!.postmeta.push(meta)\n meta = null\n }\n } else if (item) {\n if (n === 'category') {\n const t = item.terms.at(-1)\n if (t) t.name = text\n } else {\n const map: Record<string, string> = {\n title: 'title',\n link: 'link',\n 'dc:creator': 'author',\n guid: 'guid',\n description: 'description',\n 'content:encoded': 'content',\n 'excerpt:encoded': 'excerpt',\n 'wp:post_id': 'id',\n 'wp:post_date': 'date',\n 'wp:post_date_gmt': 'date_gmt',\n 'wp:post_modified': 'modified',\n 'wp:post_modified_gmt': 'modified_gmt',\n 'wp:comment_status': 'comment_status',\n 'wp:ping_status': 'ping_status',\n 'wp:post_name': 'slug',\n 'wp:status': 'status',\n 'wp:post_parent': 'parent',\n 'wp:menu_order': 'menu_order',\n 'wp:post_type': 'type',\n 'wp:post_password': 'password',\n 'wp:is_sticky': 'sticky',\n 'wp:attachment_url': 'attachment_url',\n }\n leaf(n, item, map)\n if (n === 'item') {\n items.push(item)\n item = null\n }\n }\n } else if (author) {\n leaf(n, author, {\n 'wp:author_id': 'id',\n 'wp:author_login': 'login',\n 'wp:author_email': 'email',\n 'wp:author_display_name': 'display_name',\n 'wp:author_first_name': 'first_name',\n 'wp:author_last_name': 'last_name',\n })\n if (n === 'wp:author') {\n authors.push(author)\n author = null\n }\n } else if (term) {\n leaf(n, term, {\n 'wp:term_id': 'id',\n 'wp:category_nicename': 'slug',\n 'wp:category_parent': 'parent',\n 'wp:cat_name': 'name',\n 'wp:category_description': 'description',\n 'wp:tag_slug': 'slug',\n 'wp:tag_name': 'name',\n 'wp:tag_description': 'description',\n 'wp:term_taxonomy': 'taxonomy',\n 'wp:term_slug': 'slug',\n 'wp:term_parent': 'parent',\n 'wp:term_name': 'name',\n 'wp:term_description': 'description',\n })\n if (n === term._tag) {\n term.taxonomy = term._tag === 'wp:category' ? 'category' : term._tag === 'wp:tag' ? 'post_tag' : (term.taxonomy ?? '')\n delete term._tag\n terms.push(term)\n term = null\n }\n } else if (parent === 'channel') {\n leaf(n, channelText, {\n title: 'title',\n link: 'link',\n description: 'description',\n language: 'language',\n 'wp:wxr_version': 'wxr_version',\n 'wp:base_site_url': 'base_site_url',\n 'wp:base_blog_url': 'base_blog_url',\n })\n }\n path.pop()\n text = ''\n })\n\n await new Promise<void>((resolve, reject) => {\n parser.on('end', () => resolve())\n parser.on('error', reject)\n if (typeof input === 'string') {\n parser.end(input)\n } else {\n input.pipe(parser)\n }\n })\n Object.assign(site, channelText)\n\n // ── post-processing: meta decode, ACF pairing, entity split, resolution flags ──\n const decodeMeta = (list: Array<{ key?: string; value?: string }>): { meta: Record<string, unknown>; serializedKeys: string[] } => {\n const out: Record<string, unknown> = {}\n const serializedKeys: string[] = []\n for (const { key, value } of list) {\n if (!key) continue\n const r = tryUnserialize(value ?? '')\n if (r.serialized) {\n stats.serialized.detected++\n serializedKeySet.add(key)\n if (r.ok) {\n stats.serialized.decoded++\n serializedKeys.push(key)\n } else stats.serialized.failed++\n }\n const v = r.ok ? r.value : (value ?? '')\n out[key] = key in out ? ([] as unknown[]).concat(out[key] as unknown[], [v]) : v\n }\n return { meta: out, serializedKeys }\n }\n const extractAcf = (metaObj: Record<string, unknown>): Record<string, RawAcfValue> => {\n const acf: Record<string, RawAcfValue> = {}\n for (const [k, v] of Object.entries(metaObj)) {\n if (k.startsWith('_') && typeof v === 'string' && /^field_[0-9a-f]+$/.test(v) && k.slice(1) in metaObj) {\n acf[k.slice(1)] = { value: metaObj[k.slice(1)], field_key: v }\n }\n }\n return acf\n }\n\n const termSet = new Set(terms.map((t) => termKey(t.taxonomy ?? '', t.slug ?? '')))\n\n interface Rec extends RawPost {\n attachment_url: string | null\n _comments: RawComment[]\n }\n const records: Rec[] = items.map((it) => {\n const { meta: m, serializedKeys } = decodeMeta(it.postmeta)\n const acf = extractAcf(m)\n stats.acf_fields += Object.keys(acf).length\n const id = num(it.id)\n const termRefs: RawTermRef[] = it.terms.map((t) => ({\n taxonomy: t.taxonomy,\n slug: t.slug,\n name: t.name ?? '',\n resolved: termSet.has(termKey(t.taxonomy, t.slug)),\n }))\n const comments: RawComment[] = it.comments.map((c) => ({\n id: num(c.id),\n post: id,\n post_type: (it.type as string) || 'post',\n parent: num(c.parent) || null,\n parent_resolved: null,\n author: (c.author as string) ?? '',\n email: (c.email as string) || null,\n url: (c.url as string) || null,\n date: iso(c.date as string, c.date_gmt as string),\n date_gmt: ts(c.date_gmt as string),\n content: (c.content as string) ?? '',\n approved: (c.approved as string | undefined) ?? '1',\n type: (c.type as string) || 'comment',\n user_id: num(c.user_id) || null,\n meta: decodeMeta((c.meta as Array<{ key?: string; value?: string }>) ?? []).meta,\n }))\n return {\n id,\n type: (it.type as string) || 'post',\n status: (it.status as string) || 'publish',\n slug: (it.slug as string) || '',\n title: (it.title as string) ?? '',\n link: (it.link as string) || null,\n guid: (it.guid as string) || null,\n author: (it.author as string) || null,\n date: iso(it.date as string, it.date_gmt as string),\n modified: iso(it.modified as string, it.modified_gmt as string),\n content: (it.content as string) ?? '',\n excerpt: (it.excerpt as string) ?? '',\n parent: num(it.parent) || null,\n menu_order: num(it.menu_order),\n sticky: it.sticky === '1',\n password: it.password ? PROTECTED : null,\n comment_status: (it.comment_status as string) || null,\n ping_status: (it.ping_status as string) || null,\n terms: termRefs,\n meta: m,\n serialized_keys: serializedKeys,\n acf,\n // Polylang exports a post's language as a `language` taxonomy term.\n lang: termRefs.find((t) => t.taxonomy === 'language')?.slug || null,\n attachment_url: (it.attachment_url as string) || null,\n _comments: comments,\n }\n })\n for (const r of records) {\n for (const t of r.terms) if (!t.resolved && r.type !== 'nav_menu_item') stats.unresolved_terms++\n }\n\n const byId = new Map(records.map((r) => [r.id, r]))\n const posts: RawPost[] = records\n .filter((r) => r.type !== 'attachment' && r.type !== 'nav_menu_item')\n .map(({ attachment_url: _a, _comments: _c, ...p }) => p)\n // Polylang groups translations under a shared `post_translations` term\n // (`pll_…`); every post in a group is a translation of the others.\n const groups = new Map<string, RawPost[]>()\n for (const p of posts) {\n const group = p.terms.find((t) => t.taxonomy === 'post_translations')?.slug\n if (!group) continue\n groups.set(group, [...(groups.get(group) ?? []), p])\n }\n const languagePairs: RawLanguagePair[] = []\n for (const members of groups.values()) {\n const translations: Record<string, number> = {}\n for (const m of members) if (m.lang) translations[m.lang] = m.id\n if (Object.keys(translations).length > 1) languagePairs.push({ post: members[0]!.id, translations })\n }\n const attachments: RawAttachment[] = records\n .filter((r) => r.type === 'attachment')\n .map((r) => ({\n id: r.id,\n title: r.title,\n slug: r.slug,\n url: r.attachment_url ?? r.guid ?? null,\n alt: typeof r.meta._wp_attachment_image_alt === 'string' ? r.meta._wp_attachment_image_alt : '',\n caption: r.excerpt,\n description: r.content,\n file: typeof r.meta._wp_attached_file === 'string' ? r.meta._wp_attached_file : null,\n image_meta: r.meta._wp_attachment_metadata ?? null,\n mime: guessMime(r.attachment_url ?? r.guid ?? ''),\n parent: r.parent,\n parent_resolved: r.parent ? byId.has(r.parent) : null,\n // The attachment page (`<link>`), where the site serves one.\n // Kept only when there is no parent or the parent is public: the page sits under the parent's address.\n link: !r.parent || (byId.get(r.parent)?.status === 'publish' && !byId.get(r.parent)?.password) ? (r.link || null) : null,\n author: r.author,\n date: r.date,\n status: r.status,\n meta: r.meta,\n }))\n\n // ── menus: nav_menu terms + nav_menu_item posts (targets from meta) ──\n const postById = new Map(posts.map((p) => [p.id, p]))\n const termByIdNum = new Map(terms.map((t) => [num(t.id), t]))\n const menus: RawMenu[] = terms\n .filter((t) => t.taxonomy === 'nav_menu')\n .map((mt) => ({ id: num(mt.id) || null, slug: mt.slug ?? '', name: mt.name ?? '', items: [] as RawMenuItem[] }))\n const menuBySlug = new Map(menus.map((m) => [m.slug, m]))\n for (const r of records.filter((x) => x.type === 'nav_menu_item')) {\n const m = r.meta\n const type = m._menu_item_type as string | undefined\n const object = m._menu_item_object as string | undefined\n const objectId = num(m._menu_item_object_id)\n let target: RawMenuTarget\n if (type === 'custom') target = { kind: 'url', url: String(m._menu_item_url ?? ''), resolved: true }\n else if (type === 'post_type') {\n const p = postById.get(objectId)\n target = { kind: 'post', post_type: object ?? '', id: objectId || null, slug: p?.slug ?? null, resolved: !!p }\n } else if (type === 'taxonomy') {\n const t = termByIdNum.get(objectId)\n target = { kind: 'term', taxonomy: object ?? '', id: objectId || null, slug: t?.slug ?? null, resolved: !!t }\n } else if (type === 'post_type_archive') target = { kind: 'archive', post_type: object ?? '', resolved: true }\n else target = { kind: 'unknown', resolved: false }\n const parent = num(m._menu_item_menu_item_parent) || null\n const itemRec: RawMenuItem = {\n id: r.id,\n title: r.title || (('slug' in target && target.slug) || '') || '',\n order: r.menu_order,\n parent,\n url: (m._menu_item_url as string) || null,\n target,\n target_attr: (m._menu_item_target as string) || null,\n classes: ([] as string[]).concat((m._menu_item_classes as string[]) ?? []).filter(Boolean),\n description: r.content,\n status: r.status,\n }\n const menuSlug = r.terms.find((t) => t.taxonomy === 'nav_menu')?.slug\n const menu = menuSlug ? menuBySlug.get(menuSlug) : undefined\n if (menu) menu.items.push(itemRec)\n }\n const allMenuItemIds = new Set(menus.flatMap((m) => m.items.map((i) => i.id)))\n for (const m of menus) {\n for (const i of m.items) if (i.parent && !allMenuItemIds.has(i.parent)) i.parent_unresolved = true\n }\n\n // ── comments: threaded, parent resolution within the same post ──\n const comments: RawComment[] = []\n for (const r of records) {\n const ids = new Set(r._comments.map((c) => c.id))\n for (const c of r._comments) comments.push({ ...c, parent_resolved: c.parent ? ids.has(c.parent) : null })\n }\n\n const rawAuthors: RawAuthor[] = authors.map((a) => ({\n id: num(a.id) || null,\n login: a.login ?? '',\n email: a.email || null,\n display_name: a.display_name || a.login || '',\n first_name: a.first_name || null,\n last_name: a.last_name || null,\n }))\n const rawTerms: RawTerm[] = terms\n .filter((t) => t.taxonomy !== 'nav_menu')\n .map((t) => ({\n id: num(t.id) || null,\n taxonomy: t.taxonomy ?? '',\n slug: t.slug ?? '',\n name: t.name ?? '',\n parent: t.parent || null,\n parent_resolved: t.parent ? termSet.has(termKey(t.taxonomy ?? '', t.parent)) : null,\n description: t.description || '',\n }))\n\n stats.serialized.keys = [...serializedKeySet].toSorted()\n stats.counts = {\n items: records.length,\n posts: posts.length,\n attachments: attachments.length,\n terms: rawTerms.length,\n authors: rawAuthors.length,\n menus: menus.length,\n comments: comments.length,\n }\n\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind: 'wxr', tool: opts?.tool ?? '@contentrain/wp-import' },\n site: {\n url: String(site.link ?? channelText.link ?? ''),\n title: strip(channelText.title),\n description: strip(channelText.description) || undefined,\n base_site_url: channelText.base_site_url,\n base_blog_url: channelText.base_blog_url,\n language: channelText.language ?? null,\n generator: (site.generator as string) ?? null,\n export_date: (site.export_date as string) ?? null,\n wxr_version: channelText.wxr_version ?? null,\n },\n authors: rawAuthors,\n terms: rawTerms,\n posts,\n attachments,\n menus,\n comments,\n ...(languagePairs.length ? { language_pairs: languagePairs } : {}),\n }\n return { raw, stats }\n}\n\nconst MIME: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp3: 'audio/mpeg',\n mp4: 'video/mp4',\n pdf: 'application/pdf',\n}\nfunction guessMime(u: string): string | null {\n const e = (u.split('?')[0]?.split('.').pop() ?? '').toLowerCase()\n return MIME[e] ?? null\n}\n","// ACF / Secure Custom Fields → Contentrain field types. One deterministic, versioned table.\n//\n// The ACF type is read from the source where it is stated — SCF's REST `<name>_source.type`, a\n// Bridge export's field schema — and only inferred from the value's shape when nothing states it\n// (plain ACF REST, WXR meta). Content is never retyped: a value is carried, converted to the shape its\n// Contentrain type promises (an image object becomes its URL, a link its `{ url, title, target }`).\n//\n// Relations (post object, relationship, taxonomy, user, gallery, page link) are resolved by the\n// caller, which knows the store's entry ids; this module says which kind of reference each one is.\n\nimport type { FieldDef, FieldType } from '@contentrain/types'\nimport { byValue, strip } from './core.js'\n\n/** Table version: bump when a mapping changes, so a store says which rules made it. */\nexport const ACF_MAPPING_VERSION = 1\n\n/** ACF types that never carry content (layout) or must never be read (secrets). */\nexport const ACF_LAYOUT_TYPES = new Set(['tab', 'accordion', 'message'])\nexport const ACF_SECRET_TYPES = new Set(['password'])\n\n/**\n * ACF type → Contentrain type, for types whose value maps without a lookup.\n * `select` with `multiple` and `checkbox` are arrays of their options; see `acfFieldDef`.\n */\nexport const ACF_SCALAR_TYPES: Readonly<Record<string, FieldType>> = {\n text: 'string',\n textarea: 'text',\n wysiwyg: 'richtext',\n email: 'email',\n url: 'url',\n oembed: 'url',\n number: 'number',\n range: 'number',\n true_false: 'boolean',\n date_picker: 'date',\n date_time_picker: 'datetime',\n time_picker: 'string',\n color_picker: 'color',\n icon_picker: 'icon',\n select: 'select',\n radio: 'select',\n button_group: 'select',\n image: 'image',\n file: 'file',\n}\n\n/** References the caller resolves to store entries. */\nexport type AcfReference = 'post' | 'term' | 'user' | 'media' | 'address'\nexport const ACF_REFERENCE_TYPES: Readonly<Record<string, AcfReference>> = {\n post_object: 'post',\n relationship: 'post',\n taxonomy: 'term',\n user: 'user',\n gallery: 'media',\n page_link: 'address',\n}\n\n/**\n * Names that mean a secret whatever the field's type, for sources that do not state the type: whole words\n * of the name (`user_pass`, `apiKey`, `client-secret`), so `passage_text` or `compass` stay content.\n */\nconst SECRET_NAME = /(?:^|_)(?:pass(?:word|wd)?|secret|token|api_?key|private_?key|credentials?)(?:_|$)/i\nconst secretName = (name: string): boolean => SECRET_NAME.test(name.replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/-/g, '_'))\n\n/** Whether a field must never be read: a secret by type, or — when the type is unknown — by name. */\nexport function acfIsSecret(name: string, type: string | undefined): boolean {\n if (type) return ACF_SECRET_TYPES.has(type)\n return secretName(name)\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\nconst SOURCE = '_source'\n/** The ACF type SCF states for a sub-field of a row or group (`<name>_source.type`). */\nconst statedType = (row: Record<string, unknown>, k: string): string | undefined => {\n const s = row[`${k}${SOURCE}`]\n return isRecord(s) && typeof s.type === 'string' ? s.type : undefined\n}\n/** A sub-field that carries nothing to keep: a secret (stated, or by name) or a layout field. */\nconst droppedKey = (row: Record<string, unknown>, k: string): boolean => {\n const t = statedType(row, k)\n return (t !== undefined && ACF_LAYOUT_TYPES.has(t)) || acfIsSecret(k, t)\n}\n\n/**\n * An ACF value with every secret sub-field removed, at any depth: repeater rows, groups, flexible layouts.\n * A sub-field's `_source` keeps only its type and label — its `formatted_value` repeats the value.\n */\nexport function acfScrub(value: unknown, secret: ReadonlySet<string> = new Set()): unknown {\n if (Array.isArray(value)) {\n // Rows of one repeater or layout share their sub-fields: a key one row states as secret is secret in every row.\n const rows = value.filter(isRecord)\n const shared = new Set([...secret, ...rows.flatMap((r) => Object.keys(r).filter((k) => !k.endsWith(SOURCE) && droppedKey(r, k)))])\n return value.map((v) => acfScrub(v, shared))\n }\n if (!isRecord(value)) return value\n const gone = (k: string) => secret.has(k) || droppedKey(value, k)\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (k.endsWith(SOURCE) && k.length > SOURCE.length) {\n const base = k.slice(0, -SOURCE.length)\n if (gone(base) || !isRecord(v)) continue\n out[k] = { ...(typeof v.type === 'string' ? { type: v.type } : {}), ...(typeof v.label === 'string' ? { label: v.label } : {}) }\n continue\n }\n if (gone(k)) continue\n out[k] = acfScrub(v)\n }\n return out\n}\n/** ACF's image/file array (`return_format: array`): `{ ID, url, filename, … }`. */\nconst isAttachment = (v: unknown): v is { url: string } => isRecord(v) && typeof v.url === 'string' && ('ID' in v || 'id' in v) && ('filename' in v || 'mime_type' in v)\nconst isLink = (v: unknown): v is { url: string; title?: string; target?: string } => isRecord(v) && typeof v.url === 'string' && 'title' in v && 'target' in v && Object.keys(v).length <= 3\nconst isMap = (v: unknown): boolean => isRecord(v) && typeof v.lat === 'number' && typeof v.lng === 'number'\n/** A date picker's stored value (`Ymd`) → ISO date. */\nconst ymd = (v: unknown): string | null => (typeof v === 'string' && /^\\d{8}$/.test(v) ? `${v.slice(0, 4)}-${v.slice(4, 6)}-${v.slice(6, 8)}` : null)\n/** `Y-m-d H:i:s` → ISO local datetime (site time: WordPress stores it without a zone). */\nconst dt = (v: unknown): string | null => (typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(v) ? v.replace(' ', 'T') : null)\n\nconst pad = (n: number): string => String(Math.floor(n)).padStart(2, '0')\n/** Minutes east of UTC → `+03:00`. */\nconst offsetText = (minutes: number): string => `${minutes < 0 ? '-' : '+'}${pad(Math.abs(minutes) / 60)}:${pad(Math.abs(minutes) % 60)}`\n\n/** The offset of an IANA zone at a wall-clock time there (DST included), in minutes east of UTC; `null` for an unknown zone. */\nfunction zoneOffset(local: string, timeZone: string): number | null {\n let fmt: Intl.DateTimeFormat\n try { fmt = new Intl.DateTimeFormat('en-US', { timeZone, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }) } catch { return null }\n const wall = Date.parse(`${local}Z`)\n const at = (utc: number): number => {\n const p = Object.fromEntries(fmt.formatToParts(new Date(utc)).map((x) => [x.type, x.value]))\n return (Date.UTC(Number(p.year), Number(p.month) - 1, Number(p.day), Number(p.hour), Number(p.minute), Number(p.second)) - utc) / 60000\n }\n // The offset at the instant the wall time names: guess with the wall time read as UTC, then correct once.\n const first = at(wall)\n return at(wall - first * 60000)\n}\n\n/** How a site's local date-times get their zone. */\nexport interface AcfZone {\n /** IANA zone (`timezone_string`); wins over `gmtOffset`. */\n timeZone?: string | null\n /** Fixed offset in hours (`gmt_offset`). */\n gmtOffset?: number | null\n}\n\n/** A local ISO datetime with the site's offset for that moment; the local value when the site's zone is unknown. */\nexport function zonedDateTime(local: string, zone: AcfZone = {}): { value: string; zoned: boolean } {\n const tz = zone.timeZone ? zoneOffset(local, zone.timeZone) : null\n const minutes = tz ?? (typeof zone.gmtOffset === 'number' && Number.isFinite(zone.gmtOffset) ? Math.round(zone.gmtOffset * 60) : null)\n return minutes === null ? { value: local, zoned: false } : { value: `${local}${offsetText(minutes)}`, zoned: true }\n}\n\nconst LINK_FIELDS: Record<string, FieldDef> = { url: { type: 'url' }, title: { type: 'string' }, target: { type: 'string' } }\nconst MAP_FIELDS: Record<string, FieldDef> = { address: { type: 'string' }, lat: { type: 'decimal' }, lng: { type: 'decimal' }, zoom: { type: 'integer' } }\n\n/** Contentrain type of a sub-value whose ACF type is not stated (a repeater row, a group member). */\nfunction inferDef(value: unknown): FieldDef | null {\n if (value === null || value === undefined || value === '') return null\n if (isAttachment(value)) return { type: /\\.(jpe?g|png|gif|webp|avif|svg)(\\?|$)/i.test(value.url) ? 'image' : 'file' }\n if (isLink(value)) return { type: 'object', fields: LINK_FIELDS }\n if (isMap(value)) return { type: 'object', fields: MAP_FIELDS }\n if (Array.isArray(value)) {\n if (value.every(isRecord)) return { type: 'array', items: { type: 'object', fields: rowFields(value as Record<string, unknown>[]) } }\n const item = value.map(inferDef).find(Boolean)\n return { type: 'array', items: item?.type === 'object' ? item : (item?.type ?? 'string') }\n }\n if (isRecord(value)) return { type: 'object', fields: rowFields([value]) }\n if (ymd(value)) return { type: 'date' }\n const t = byValue(value)\n return t ? { type: t as FieldType } : null\n}\n\n/**\n * The union of the fields every row states; a name typed two ways falls back to `string`. A sub-field whose ACF\n * type the row states (SCF's `<name>_source`) is typed by the table like a top-level field; a reference inside a\n * row is not resolved, so it — and any sub-field without a stated type — is typed from its value.\n */\nfunction rowFields(rows: Record<string, unknown>[]): Record<string, FieldDef> {\n const out: Record<string, FieldDef> = {}\n for (const row of rows) {\n for (const [k, v] of Object.entries(row)) {\n if (k.endsWith(SOURCE) || droppedKey(row, k)) continue\n const stated = statedType(row, k)\n const source = row[`${k}${SOURCE}`]\n const label = isRecord(source) && typeof source.label === 'string' ? source.label : undefined\n const d = stated && !ACF_REFERENCE_TYPES[stated] ? acfFieldDef(k, v, { type: stated, ...(label ? { label } : {}) }) : inferDef(v)\n if (!d) continue\n const seen = out[k]\n if (!seen) out[k] = d\n else if (seen.type !== d.type) out[k] = { type: 'string' }\n }\n }\n return out\n}\n\nexport interface AcfValueContext extends AcfZone {\n /** Called for a stored value outside its field's stated choices: it is left out, not kept as free text. */\n dropped?: (value: unknown, options: readonly string[]) => void\n /** Called for a date-time written without a zone, because the site's zone is unknown. */\n unzoned?: (value: string) => void\n}\n\n/** A value in the shape its field definition promises; `undefined` = nothing to store. */\nexport function acfValue(def: FieldDef, value: unknown, ctx: AcfValueContext = {}): unknown {\n if (value === null || value === undefined || value === '' || (Array.isArray(value) && !value.length)) return undefined\n switch (def.type) {\n case 'image':\n case 'file':\n case 'video':\n return isAttachment(value) ? value.url : typeof value === 'string' ? value : undefined\n case 'date':\n return ymd(value) ?? (typeof value === 'string' ? value : undefined)\n case 'datetime': {\n const local = dt(value)\n if (!local) return typeof value === 'string' ? value : undefined\n const out = zonedDateTime(local, ctx)\n if (!out.zoned) ctx.unzoned?.(out.value)\n return out.value\n }\n case 'boolean':\n return value === true || value === 1 || value === '1'\n case 'number':\n case 'integer':\n case 'decimal':\n return typeof value === 'number' ? value : typeof value === 'string' && value.trim() !== '' && !Number.isNaN(Number(value)) ? Number(value) : undefined\n case 'icon':\n return isRecord(value) && typeof value.value === 'string' ? value.value : typeof value === 'string' ? value : undefined\n case 'object': {\n if (!isRecord(value)) return undefined\n const out: Record<string, unknown> = {}\n for (const [k, sub] of Object.entries(def.fields ?? {})) {\n // Another row may have typed the name; this one says it is a secret.\n if (droppedKey(value, k)) continue\n const v = acfValue(sub, value[k], ctx)\n if (v !== undefined) out[k] = v\n }\n return Object.keys(out).length ? out : undefined\n }\n case 'array': {\n if (!Array.isArray(value)) return undefined\n const item: FieldDef = typeof def.items === 'string' ? { type: def.items as FieldType } : (def.items ?? { type: 'string' })\n const out = value.map((v) => acfValue(item, v, ctx)).filter((v) => v !== undefined)\n return out.length ? out : undefined\n }\n case 'select': {\n const v = typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n // A value the field no longer offers (the choice was removed after it was saved): not a valid select value.\n if (v !== undefined && def.options?.length && !def.options.includes(v)) {\n ctx.dropped?.(v, def.options)\n return undefined\n }\n return v\n }\n case 'richtext':\n case 'text':\n case 'string':\n case 'url':\n case 'email':\n case 'color':\n return typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n default:\n return value\n }\n}\n\nexport interface AcfStated {\n /** ACF type as the source states it (`_source.type`, Bridge schema); absent = infer from the value. */\n type?: string\n label?: string\n /** Choices of a select/radio/checkbox/button group, when the source states them. */\n choices?: string[]\n multiple?: boolean\n}\n\n/**\n * Field definition for one ACF field value, or `null` when it carries no content, is a secret, or is a\n * reference (the caller resolves those: see `ACF_REFERENCE_TYPES`).\n */\nexport function acfFieldDef(name: string, value: unknown, stated: AcfStated = {}): FieldDef | null {\n const t = stated.type\n if (t && (ACF_LAYOUT_TYPES.has(t) || ACF_REFERENCE_TYPES[t])) return null\n if (acfIsSecret(name, t)) return null\n const label = stated.label ? strip(stated.label) : undefined\n const withLabel = (d: FieldDef): FieldDef => (label ? { ...d, label } : d)\n if (!t) {\n const inferred = inferDef(value)\n return inferred ? withLabel({ ...inferred, description: 'ACF (type inferred from the value)' }) : null\n }\n const choices = stated.choices?.length ? stated.choices : undefined\n if (t === 'checkbox' || (t === 'select' && (stated.multiple || Array.isArray(value)))) {\n return withLabel({ type: 'array', items: choices ? { type: 'select', options: choices } : 'string' })\n }\n if (ACF_SCALAR_TYPES[t]) {\n const type = ACF_SCALAR_TYPES[t]!\n if (type === 'select') return withLabel(choices ? { type, options: choices } : { type: 'string' })\n return withLabel({ type })\n }\n if (t === 'link') return withLabel({ type: 'object', fields: LINK_FIELDS })\n if (t === 'google_map') return withLabel({ type: 'object', fields: MAP_FIELDS })\n if (t === 'group') return withLabel({ type: 'object', fields: rowFields(isRecord(value) ? [value] : []) })\n if (t === 'repeater') return withLabel({ type: 'array', items: { type: 'object', fields: rowFields(Array.isArray(value) ? value.filter(isRecord) : []) } })\n if (t === 'flexible_content') {\n // One row per layout instance, in order; `layout` names which layout made it, the rest is the union of their fields.\n const rows = Array.isArray(value) ? value.filter(isRecord) : []\n const fields = rowFields(rows.map(({ acf_fc_layout: _l, ...rest }) => rest))\n const layouts = [...new Set(rows.map((r) => String(r.acf_fc_layout ?? '')).filter(Boolean))].toSorted()\n return withLabel({ type: 'array', items: { type: 'object', fields: { layout: { type: 'select', options: layouts, required: true }, ...fields } } })\n }\n // An ACF type this table does not know (a third-party field type): infer, and say so.\n const inferred = inferDef(value)\n return inferred ? withLabel({ ...inferred, description: `ACF ${t} (type inferred from the value)` }) : null\n}\n\n/** Merge two definitions of the same field seen on different entries (union of object fields and options). */\nexport function mergeFieldDef(a: FieldDef, b: FieldDef): FieldDef {\n if (a.type !== b.type) return a\n const out: FieldDef = { ...a }\n if (a.options || b.options) out.options = [...new Set([...(a.options ?? []), ...(b.options ?? [])])].toSorted()\n if (a.fields || b.fields) {\n const fields: Record<string, FieldDef> = { ...a.fields }\n for (const [k, d] of Object.entries(b.fields ?? {})) fields[k] = fields[k] ? mergeFieldDef(fields[k]!, d) : d\n out.fields = fields\n }\n if (typeof a.items === 'object' && typeof b.items === 'object') out.items = mergeFieldDef(a.items, b.items)\n return out\n}\n\n/** Flexible content rows keep their layout name under `layout`. */\nexport function acfRows(value: unknown): unknown {\n return Array.isArray(value) ? value.map((r) => (isRecord(r) && 'acf_fc_layout' in r ? (({ acf_fc_layout, ...rest }) => ({ layout: acf_fc_layout, ...rest }))(r) : r)) : value\n}\n","// Redirect rules over REST → RawRedirect[] / RawRedirectExcluded[].\n//\n// REST reaches one source: the Redirection plugin (`redirection/v1`), with an application password of a user who\n// may manage it. Yoast Premium, Rank Math, Safe Redirect Manager and `.htaccess` keep their rules where REST cannot\n// read them — only the Bridge export does. The rules are shaped exactly as the Bridge shapes Redirection's\n// (`class-contentrain-bridge-redirects.php`): every rule lands in `redirects` (the site serves it) or `excluded`\n// (with the reason), so the two together account for the plugin's whole table.\n\nimport type { RawRedirect, RawRedirectExcluded, RawRedirectQuery } from '@contentrain/types'\n\n/** A rule as `redirection/v1/redirect` lists it. */\nexport interface RestRedirection {\n id: number\n url?: string\n regex?: boolean\n group_id?: number\n enabled?: boolean\n /** Older releases state `status: 'enabled' | 'disabled'` instead of `enabled`. */\n status?: string\n action_type?: string\n action_code?: number | string\n action_data?: { url?: string } | string | null\n match_type?: string\n match_data?: { source?: { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown; flag_regex?: unknown } } | null\n}\n\n/**\n * Redirection's site-wide defaults (`redirection/v1/setting`, which answers them merged over the plugin's own): a\n * rule without its own flags takes these.\n */\nexport interface RestRedirectionOptions { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown }\n\n/** Redirection's own defaults, under a site that states none. */\nconst DEFAULTS = { flag_query: 'exact', flag_case: false, flag_trailing: false } as const\n\n/** A group as `redirection/v1/group` lists it. `module_id`: 1 WordPress, 2 Apache, 3 nginx. */\nexport interface RestRedirectionGroup { id: number; module_id?: number; enabled?: boolean; status?: string }\n\nconst MODULES: Record<number, string> = { 2: 'apache', 3: 'nginx' }\n/** Codes that say an address is gone: served as that answer, with no target. */\nconst GONE = new Set([410, 451])\n/** Redirection's query modes; `exactorder` (the same parameters in the same order) is read as `exact`. */\nconst QUERY: Record<string, RawRedirectQuery> = { exact: 'exact', exactorder: 'exact', ignore: 'ignore', pass: 'pass' }\n\ntype Flags = { flag_query?: unknown; flag_case?: unknown; flag_trailing?: unknown }\n/** The flags one layer states, as Redirection accepts them: a known query mode, a true boolean (not `\"1\"`). */\nconst valid = (f: Flags | undefined): Flags => ({\n ...(typeof f?.flag_query === 'string' && f.flag_query in QUERY ? { flag_query: f.flag_query } : {}),\n ...(typeof f?.flag_case === 'boolean' ? { flag_case: f.flag_case } : {}),\n ...(typeof f?.flag_trailing === 'boolean' ? { flag_trailing: f.flag_trailing } : {}),\n})\n\n/** A login rule's two addresses, and nothing else its data may hold. */\nconst loginCondition = (data: unknown): { logged_in: string, logged_out: string } | null => {\n if (!data || typeof data !== 'object') return null\n const d = data as Record<string, unknown>\n return { logged_in: typeof d.logged_in === 'string' ? d.logged_in : '', logged_out: typeof d.logged_out === 'string' ? d.logged_out : '' }\n}\n\n/** By id as bytes, as the Bridge sorts (`strcmp`). */\nconst order = (a: { id?: string }, b: { id?: string }): number => ((a.id ?? '') < (b.id ?? '') ? -1 : (a.id ?? '') > (b.id ?? '') ? 1 : 0)\n\nconst on = (x: { enabled?: boolean; status?: string }): boolean => (x.enabled ?? (x.status === undefined || x.status === 'enabled'))\n\n/** Same-site targets become root-relative, like every `from`; other hosts stay absolute (as the Bridge does). */\nfunction relative(url: string, origin: string): string {\n try {\n const home = new URL(origin)\n const u = new URL(url, `${origin}/`)\n if (u.host.toLowerCase() !== home.host.toLowerCase()) return url\n return `${u.pathname}${u.search}${u.hash}`\n } catch { return url }\n}\n\n/**\n * Redirection's rules and groups → the rules the site serves and the ones it does not, sorted by id.\n * A rule's query, case and trailing-slash modes are what Redirection applies to it: its own flags, else the site's\n * (`options`), else the plugin's defaults. Without `options` (not readable) only a rule's own flags are stated.\n */\nexport function redirectionRules(items: RestRedirection[], groups: RestRedirectionGroup[], origin: string, options?: RestRedirectionOptions): { redirects: RawRedirect[]; excluded: RawRedirectExcluded[] } {\n const site: Flags = options ? { ...DEFAULTS, ...valid(options) } : {}\n const byId = new Map(groups.map((g) => [g.id, g]))\n const redirects: RawRedirect[] = []\n const excluded: RawRedirectExcluded[] = []\n for (const item of items) {\n const group = item.group_id === undefined ? undefined : byId.get(item.group_id)\n const code = Number(item.action_code ?? 301)\n const data = item.action_data\n const target = typeof data === 'string' ? data : (data?.url ?? '')\n const own = item.match_data?.source ?? {}\n const flags = { ...site, ...valid(own) }\n // Without `to`: an excluded rule carries none, as the Bridge's; a served one gets its own below.\n const rule: Omit<RawRedirect, 'to'> & { id: string; source: string } = { id: `redirection:${item.id}`, from: item.url ?? '', source: 'redirection', match: 'url', regex: item.regex === true || own.flag_regex === true }\n const served = group?.module_id !== undefined ? MODULES[group.module_id] : undefined\n if (served) rule.served_by = served\n // A regular expression matches the query as written: Redirection compares it exactly.\n if (rule.regex) rule.query = 'exact'\n else if (typeof flags.flag_query === 'string') rule.query = QUERY[flags.flag_query]\n if (typeof flags.flag_case === 'boolean') rule.case_insensitive = flags.flag_case\n if (typeof flags.flag_trailing === 'boolean') rule.trailing_slash = flags.flag_trailing ? 'ignore' : 'exact'\n const matchType = item.match_type ?? 'url'\n const actionType = item.action_type ?? 'url'\n if (!on(item) || (group && !on(group))) {\n excluded.push({ ...rule, reason: 'disabled' })\n } else if (actionType === 'error' && GONE.has(code) && matchType === 'url') {\n // \"Gone\" (410) and \"unavailable for legal reasons\" (451): the address answers that, and leads nowhere.\n redirects.push({ ...rule, to: '', status: code })\n } else if (actionType !== 'url') {\n // A 404 error, pass-through, \"do nothing\", random post: not a from→to rule.\n excluded.push({ ...rule, status: code, reason: `not-a-redirect:${actionType}` })\n } else if (matchType !== 'url') {\n // Login, referrer, agent, cookie, header, IP, server…: the target depends on the request.\n // Its own match type (`login`), as the Bridge states it. Only a login rule keeps its condition (two addresses):\n // a cookie, header, IP, role, agent or server condition holds the very value a visitor must present — often a\n // secret — and never leaves the site; its type is in the reason.\n excluded.push({ ...rule, match: matchType, status: code, ...(matchType === 'login' ? { condition: loginCondition(data) } : {}), reason: `conditional-match:${matchType}` })\n } else {\n const move = code >= 300 && code < 400\n redirects.push({ ...rule, to: relative(target, origin), status: move ? code : 301, ...(move ? {} : { status_note: `source status ${code} is not a redirect code; 301 assumed` }) })\n }\n }\n return { redirects: redirects.toSorted(order), excluded: excluded.toSorted(order) }\n}\n","// Menus over REST → RawMenu[].\n//\n// Two sources, both behind `edit_theme_options` (an application password):\n// - classic menus: `/wp/v2/menus` (with the theme locations each is assigned to) and `/wp/v2/menu-items`;\n// - block-theme navigation: published `wp_navigation` posts, whose block markup is the menu. A block\n// menu's location is the template part (`header` / `footer`) that references it — or, for a\n// navigation block without a `ref`, the most recent published one, which is what WordPress shows;\n// - inline navigation: a navigation block in a template part that carries its own links (Twenty\n// Twenty-Five's footer columns). It is a menu of that part's area, with no WordPress record behind it.\n// Only template parts a template uses count: a theme ships alternatives (`footer-columns`, `header-large-title`)\n// that no page shows. Block menu items, and inline menus, have no ids of their own; they get negative ids,\n// unique within the import, so they can never collide with a WordPress id.\n\nimport type { RawMenu, RawMenuItem, RawMenuTarget } from '@contentrain/types'\nimport { strip } from './core.js'\n\nexport interface RestMenu { id: number; name?: string; slug?: string; locations?: string[] }\n\nexport interface RestMenuItem {\n id: number\n title?: { rendered?: string; raw?: string }\n status?: string\n url?: string\n description?: string\n type?: string\n object?: string\n object_id?: number\n parent?: number\n menu_order?: number\n target?: string\n classes?: string[]\n menus?: number\n}\n\nexport interface RestNavigation {\n id: number\n slug?: string\n date_gmt?: string\n status?: string\n title?: { rendered?: string; raw?: string }\n content?: { raw?: string }\n}\n\nexport interface RestTemplatePart { slug?: string; area?: string; title?: { rendered?: string; raw?: string }; content?: { raw?: string } }\nexport interface RestTemplate { slug?: string; content?: { raw?: string } }\n\n/** What a target is checked against: the posts and terms this import read. */\nexport interface MenuContext {\n origin: string\n /**\n * Slug of a post this import read and saw published and unprotected — the only kind a menu item may\n * point at. Anything else (a draft, a private or scheduled post, one behind a password, or one this\n * import never read: a type outside REST, past a page cap) is left out, fail-closed: a menu item's label\n * is often its target's title, and that title must not reach the store.\n */\n postSlug: (id: number) => string | undefined\n termSlug: (taxonomy: string, id: number) => string | undefined\n /**\n * Public address of such a post or term. A menu item that names one points there, whatever address the item\n * kept: a block stores the url it had when it was saved (`/old-about/`), and a typed `?page_id=5` is a form the\n * migrated site cannot serve.\n */\n postLink?: (id: number) => string | undefined\n termLink?: (taxonomy: string, id: number) => string | undefined\n /** Published pages, for `core/page-list` (id, parent, order, title, link). */\n pages: Array<{ id: number; parent: number | null; menu_order: number; title: string; link: string | null; slug: string }>\n}\n\nconst targetOf = (kind: string | undefined, object: string | undefined, id: number | undefined, url: string | undefined, ctx: MenuContext): RawMenuTarget => {\n const objectId = id && id > 0 ? id : null\n if (kind === 'post_type' && object) {\n const slug = objectId ? ctx.postSlug(objectId) : undefined\n return { kind: 'post', post_type: object, id: objectId, slug: slug ?? null, resolved: slug !== undefined }\n }\n if (kind === 'taxonomy' && object) {\n const slug = objectId ? ctx.termSlug(object, objectId) : undefined\n return { kind: 'term', taxonomy: object, id: objectId, slug: slug ?? null, resolved: slug !== undefined }\n }\n if (kind === 'post_type_archive' && object) return { kind: 'archive', post_type: object, resolved: true }\n if (url) return { kind: 'url', url, resolved: true }\n return { kind: 'unknown', resolved: false }\n}\n\n/** The public address of the post or term a target names, when it is one this import proved public. */\nconst publicLink = (target: RawMenuTarget, ctx: MenuContext): string | undefined => {\n if (!target.resolved || !('id' in target) || !target.id) return undefined\n if (target.kind === 'post') return ctx.postLink?.(target.id)\n if (target.kind === 'term') return ctx.termLink?.(target.taxonomy, target.id)\n return undefined\n}\n\n/**\n * Items that are left out: a draft item, or one whose post target is not proven visible. Their children move up\n * to the nearest kept ancestor, as WordPress's walker shows them.\n */\nfunction hiddenItems(items: RestMenuItem[], drop: (i: RestMenuItem) => boolean): { gone: Set<number>; lift: (parent: number | null) => number | null } {\n const parentOf = new Map(items.filter(drop).map((i) => [i.id, i.parent || null]))\n const lift = (parent: number | null): number | null => {\n const seen = new Set<number>()\n let p = parent\n while (p !== null && parentOf.has(p) && !seen.has(p)) { seen.add(p); p = parentOf.get(p) ?? null }\n return p\n }\n return { gone: new Set(parentOf.keys()), lift }\n}\n\n/** A host without case or a leading `www.`: example.com and www.example.com are one site (as the Bridge reads it). */\nconst bareHost = (u: URL): string => u.hostname.toLowerCase().replace(/^www\\./, '')\n\n/**\n * The post a plain permalink names (`/?page_id=14`, `/?p=14`) on this site, `www.` or not: a custom link typed by\n * hand carries no post id, but it points at a post all the same, and its label is often that post's title.\n */\nexport function plainPostId(url: string | undefined, origin: string): number | undefined {\n if (!url || !url.includes('?')) return undefined\n try {\n const u = new URL(url, `${origin}/`)\n if (bareHost(u) !== bareHost(new URL(origin))) return undefined\n const id = Number(u.searchParams.get('page_id') ?? u.searchParams.get('p'))\n return Number.isSafeInteger(id) && id > 0 ? id : undefined\n } catch { return undefined }\n}\n\n/** Classic menus and their items; each menu names the theme locations it is assigned to. `dropped` counts left-out items. */\nexport function classicMenus(menus: RestMenu[], items: RestMenuItem[], ctx: MenuContext, dropped = { count: 0 }): RawMenu[] {\n const out: RawMenu[] = []\n for (const m of [...menus].toSorted((a, b) => a.id - b.id)) {\n const all = items.filter((i) => i.menus === m.id).toSorted((a, b) => (a.menu_order ?? 0) - (b.menu_order ?? 0) || a.id - b.id)\n const hidden = (i: RestMenuItem): boolean => {\n if ((i.status ?? 'publish') !== 'publish') return true\n if (i.type === 'post_type') return !(i.object_id && ctx.postSlug(i.object_id))\n // A custom link to `?page_id=` / `?p=` names a post: the same proof applies.\n const id = plainPostId(i.url, ctx.origin)\n return id !== undefined && !ctx.postSlug(id)\n }\n const { gone, lift } = hiddenItems(all, hidden)\n dropped.count += gone.size\n const own = all.filter((i) => !gone.has(i.id))\n const ids = new Set(own.map((i) => i.id))\n const menu: RawMenu = {\n id: m.id,\n slug: m.slug ?? '',\n name: strip(m.name ?? m.slug ?? ''),\n items: own.map((i) => {\n const target = targetOf(i.type, i.object, i.object_id, i.url, ctx)\n const typed = target.kind === 'url' ? plainPostId(i.url, ctx.origin) : undefined\n const item: RawMenuItem = {\n id: i.id,\n title: i.title?.raw || i.title?.rendered || '',\n order: i.menu_order ?? 0,\n parent: lift(i.parent || null),\n url: publicLink(target, ctx) ?? (typed !== undefined ? ctx.postLink?.(typed) : undefined) ?? (i.url || null),\n target,\n target_attr: i.target || null,\n classes: (i.classes ?? []).filter(Boolean),\n description: i.description ?? '',\n status: i.status ?? 'publish',\n }\n if (item.parent && !ids.has(item.parent)) item.parent_unresolved = true\n return item\n }),\n }\n const locations = (m.locations ?? []).filter(Boolean).toSorted()\n if (locations.length) menu.locations = locations\n out.push(menu)\n }\n return out\n}\n\n// ── Block navigation ─────────────────────────────────────────────────────────\n\ninterface Block { name: string; attrs: Record<string, unknown>; children: Block[] }\n\n/** Serialized block comments (`<!-- wp:name {attrs} /-->`, `<!-- /wp:name -->`). Same grammar as the facts builder parser. */\nconst BLOCK_TOKEN = /<!--\\s+(\\/)?wp:([a-z][a-z0-9_-]*\\/)?([a-z][a-z0-9_-]*)\\s+({(?:(?!}\\s+\\/?-->)[\\s\\S])*?}\\s+)?(\\/)?-->/g\n\nexport function parseBlocks(content: string): Block[] {\n const root: Block = { name: 'root', attrs: {}, children: [] }\n const stack: Block[] = [root]\n const token = new RegExp(BLOCK_TOKEN.source, 'g')\n let m: RegExpExecArray | null\n while ((m = token.exec(content))) {\n const [, closer, ns, local, json, selfClose] = m\n if (closer) {\n if (stack.length > 1) stack.pop()\n continue\n }\n let attrs: Record<string, unknown> = {}\n if (json) {\n try { attrs = JSON.parse(json) as Record<string, unknown> } catch { attrs = {} }\n }\n const block: Block = { name: `${ns ? ns.slice(0, -1) : 'core'}/${local}`, attrs, children: [] }\n stack[stack.length - 1]!.children.push(block)\n if (!selfClose) stack.push(block)\n }\n return root.children\n}\n\nconst str = (v: unknown): string | undefined => (typeof v === 'string' && v ? v : undefined)\nconst absolute = (url: string | undefined, origin: string): string | undefined => {\n if (!url) return undefined\n // `#` (a placeholder link) stays on the page it is on; made absolute it would point at the home page.\n if (url.startsWith('#')) return url\n try { return new URL(url, `${origin}/`).href } catch { return url }\n}\n/** The block editor's link kinds → the classic menu item types. */\nconst KIND: Record<string, string> = { 'post-type': 'post_type', taxonomy: 'taxonomy', custom: 'custom' }\n\n/**\n * Menu items of one `wp_navigation` body. Links and submenus become items; a page list becomes the\n * published pages it lists; a home link points at `/`. Other blocks (search, social icons, spacers) are not links.\n */\nexport function navigationItems(content: string, ctx: MenuContext, nextId: () => number, dropped = { count: 0 }): RawMenuItem[] {\n return blockItems(parseBlocks(content), ctx, nextId, dropped)\n}\n\n/** Menu items of navigation blocks already parsed (a `wp_navigation` body, or an inline navigation's links). */\nfunction blockItems(tree: Block[], ctx: MenuContext, nextId: () => number, dropped: { count: number }): RawMenuItem[] {\n const items: RawMenuItem[] = []\n const push = (b: { title: string; url?: string; kind?: string; object?: string; id?: number; typed?: number; newTab?: boolean; className?: string; description?: string }, parent: number | null): number => {\n const id = nextId()\n const url = absolute(b.url, ctx.origin)\n const target = targetOf(b.kind, b.object, b.id, url, ctx)\n items.push({\n id,\n title: b.title,\n order: items.length + 1,\n parent,\n // A public post or term is linked at its public address (see `MenuContext.postLink`).\n url: publicLink(target, ctx) ?? (b.typed !== undefined ? ctx.postLink?.(b.typed) : undefined) ?? url ?? null,\n target,\n target_attr: b.newTab ? '_blank' : null,\n classes: (b.className ?? '').split(/\\s+/).filter(Boolean),\n description: b.description ?? '',\n status: 'publish',\n })\n return id\n }\n const pageList = (parentPage: number, parent: number | null) => {\n const kids = ctx.pages.filter((p) => (p.parent ?? 0) === parentPage).toSorted((a, b) => a.menu_order - b.menu_order || a.title.localeCompare(b.title))\n for (const p of kids) {\n const id = push({ title: p.title, url: p.link ?? undefined, kind: 'post_type', object: 'page', id: p.id }, parent)\n pageList(p.id, id)\n }\n }\n const walk = (blocks: Block[], parent: number | null) => {\n for (const b of blocks) {\n const a = b.attrs\n if (b.name === 'core/navigation-link' || b.name === 'core/navigation-submenu') {\n const kind = KIND[str(a.kind) ?? ''] ?? (str(a.type) === 'category' || str(a.type) === 'tag' || str(a.type) === 'post_tag' ? 'taxonomy' : a.id ? 'post_type' : 'custom')\n const object = kind === 'taxonomy' && str(a.type) === 'tag' ? 'post_tag' : str(a.type)\n // A link to a post not proven visible is left out (fail-closed); its children show in its place. A custom link\n // to `?page_id=` / `?p=` names a post too.\n const postId = kind === 'post_type' && typeof a.id === 'number' ? a.id : kind === 'custom' ? plainPostId(str(a.url), ctx.origin) : undefined\n if (postId !== undefined && !ctx.postSlug(postId)) {\n dropped.count++\n walk(b.children, parent)\n continue\n }\n const id = push({ title: strip(a.label), url: str(a.url), kind, object, id: typeof a.id === 'number' ? a.id : undefined, typed: kind === 'custom' ? postId : undefined, newTab: a.opensInNewTab === true, className: str(a.className), description: str(a.description) }, parent)\n walk(b.children, id)\n } else if (b.name === 'core/home-link') {\n push({ title: strip(a.label) || 'Home', url: '/', className: str(a.className) }, parent)\n } else if (b.name === 'core/page-list') {\n pageList(typeof a.parentPageID === 'number' ? a.parentPageID : 0, parent)\n } else {\n walk(b.children, parent)\n }\n }\n }\n walk(tree, null)\n return items\n}\n\n/** Template-part slugs the templates use, at any depth (a part inside a group, a part inside a part is not followed). */\nfunction partSlugs(blocks: Block[], out = new Set<string>()): Set<string> {\n for (const b of blocks) {\n if (b.name === 'core/template-part' && typeof b.attrs.slug === 'string') out.add(b.attrs.slug)\n partSlugs(b.children, out)\n }\n return out\n}\n\n/**\n * The template parts a page can show: those a template references. Without the templates (not readable), the\n * part named after its area (`header`, `footer`) — what a theme's templates use unless they say otherwise.\n * Parts without a slug (older callers) all count.\n */\nexport function usedParts(parts: RestTemplatePart[], templates: RestTemplate[] = []): RestTemplatePart[] {\n const used = new Set<string>()\n for (const t of templates) if (t.content?.raw) partSlugs(parseBlocks(t.content.raw), used)\n return parts.filter((p) => !p.slug || (used.size ? used.has(p.slug) : p.slug === p.area))\n}\n\nconst AREA_ORDER = ['header', 'footer']\nconst areaOf = (p: RestTemplatePart): string | undefined => (p.area && p.area !== 'uncategorized' ? p.area : undefined)\n\n/**\n * A part's blocks with the parts it holds in their place (a header holding a `navigation` part), each part once:\n * what the part shows, in its area.\n */\nfunction partTree(part: RestTemplatePart, all: RestTemplatePart[]): Block[] {\n const bySlug = new Map(all.filter((p) => p.slug).map((p) => [p.slug!, p]))\n const seen = new Set(part.slug ? [part.slug] : [])\n const expand = (blocks: Block[]): Block[] => blocks.flatMap((b) => {\n if (b.name === 'core/template-part') {\n const inner = typeof b.attrs.slug === 'string' ? bySlug.get(b.attrs.slug) : undefined\n if (!inner?.content?.raw || seen.has(inner.slug!)) return []\n seen.add(inner.slug!)\n return expand(parseBlocks(inner.content.raw))\n }\n return [{ ...b, children: expand(b.children) }]\n })\n return expand(parseBlocks(part.content?.raw ?? ''))\n}\nconst titleCase = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1)\nconst slugOf = (s: string): string => s.toLowerCase().normalize('NFKD').replace(/[̀-ͯ]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')\n\n/**\n * Inline navigations of the used template parts → RawMenu[], in area order (header, footer, others) and document\n * order within a part. A part's single inline navigation is named after its area (`Footer navigation`), several\n * are numbered; a navigation's own `ariaLabel` wins. Links keep their order and nesting; a link to content not\n * proven public is left out, as in every other menu.\n */\nexport function inlineMenus(parts: RestTemplatePart[], ctx: MenuContext, taken: Set<string>, nextId: () => number, dropped = { count: 0 }, all: RestTemplatePart[] = parts): RawMenu[] {\n const out: RawMenu[] = []\n const ordered = parts.filter((p) => areaOf(p) && p.content?.raw).toSorted((a, b) => (AREA_ORDER.indexOf(areaOf(a)!) + 1 || 99) - (AREA_ORDER.indexOf(areaOf(b)!) + 1 || 99))\n for (const p of ordered) {\n const area = areaOf(p)!\n const navs: Block[] = []\n const find = (blocks: Block[]) => { for (const b of blocks) { if (b.name === 'core/navigation') { if (typeof b.attrs.ref !== 'number' && b.children.length) navs.push(b) } else find(b.children) } }\n find(partTree(p, all))\n navs.forEach((nav, i) => {\n const name = strip(nav.attrs.ariaLabel) || `${titleCase(area)} navigation${navs.length > 1 ? ` ${i + 1}` : ''}`\n const base = slugOf(name) || `${area}-navigation`\n let slug = base\n for (let k = 2; taken.has(slug); k++) slug = `${base}-${k}`\n taken.add(slug)\n const items = blockItems(nav.children, ctx, nextId, dropped)\n if (items.length) out.push({ id: nextId(), slug, name, items, locations: [area] })\n })\n }\n return out\n}\n\n/**\n * Where each navigation is shown: the template parts (`header`, `footer`) whose navigation block\n * refers to it. An empty navigation block without a `ref` shows the fallback — the most recent published one;\n * one with links of its own shows those (an inline menu, not a `wp_navigation` post).\n */\nexport function navigationLocations(parts: RestTemplatePart[], navigations: RestNavigation[], all: RestTemplatePart[] = parts): Map<number, string[]> {\n const out = new Map<number, Set<string>>()\n const fallback = [...navigations].toSorted((a, b) => (b.date_gmt ?? '').localeCompare(a.date_gmt ?? '') || b.id - a.id)[0]?.id\n const find = (blocks: Block[], area: string) => {\n for (const b of blocks) {\n if (b.name === 'core/navigation') {\n // No ref and links of its own: an inline navigation, not any wp_navigation post. No ref, empty: the fallback.\n const ref = typeof b.attrs.ref === 'number' ? b.attrs.ref : b.children.length ? undefined : fallback\n if (ref !== undefined) (out.get(ref) ?? out.set(ref, new Set()).get(ref)!).add(area)\n continue\n }\n find(b.children, area)\n }\n }\n for (const p of parts) {\n const area = areaOf(p)\n if (area && p.content?.raw) find(partTree(p, all), area)\n }\n return new Map([...out].map(([id, set]) => [id, [...set].toSorted()]))\n}\n\n/**\n * Published `wp_navigation` posts, then the inline navigations of the used template parts → RawMenu[], slugs kept\n * unique against the classic menus already read. `templates` says which parts are used (see `usedParts`).\n */\nexport function blockMenus(navigations: RestNavigation[], allParts: RestTemplatePart[], ctx: MenuContext, taken: Set<string>, dropped = { count: 0 }, templates: RestTemplate[] = []): RawMenu[] {\n const parts = usedParts(allParts, templates)\n const published = navigations.filter((n) => (n.status ?? 'publish') === 'publish').toSorted((a, b) => a.id - b.id)\n const locations = navigationLocations(parts, published, allParts)\n let next = 0\n const out: RawMenu[] = []\n for (const n of published) {\n let slug = n.slug || `navigation-${n.id}`\n while (taken.has(slug)) slug = `${slug}-nav`\n taken.add(slug)\n const menu: RawMenu = {\n id: n.id,\n slug,\n name: strip(n.title?.raw || n.title?.rendered || '') || slug,\n items: navigationItems(n.content?.raw ?? '', ctx, () => -++next, dropped),\n }\n const where = locations.get(n.id)\n if (where?.length) menu.locations = where\n out.push(menu)\n }\n out.push(...inlineMenus(parts, ctx, taken, () => -++next, dropped, allParts))\n return out\n}\n","// Public/authenticated WordPress REST → RawIR.\n//\n// The lowest rungs of the source-access ladder. What REST cannot see (rest:false\n// CPTs, unregistered meta; menus without an application password) is absent from the result —\n// absence at a low rung is information, not an error, and the manifest layer\n// decides what to recommend about it.\n\nimport type { RawAcfValue, RawIR, RawAttachment, RawComment, RawLanguagePair, RawMenu, RawPost, RawRedirect, RawRedirectExcluded, RawTerm, RawTermRef, SourceAccessKind } from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { strip, SKIP_TYPES, PROTECTED } from './core.js'\nimport { acfIsSecret, acfScrub } from './acf.js'\nimport { redirectionRules, type RestRedirection, type RestRedirectionGroup, type RestRedirectionOptions } from './rest-redirects.js'\nimport { blockMenus, classicMenus, type MenuContext, type RestMenu, type RestMenuItem, type RestNavigation, type RestTemplate, type RestTemplatePart } from './rest-menus.js'\n\nconst iso = (gmt: string | undefined): string | null => (gmt ? `${gmt}Z` : null)\nconst approvedOf = (status: string | undefined): RawComment['approved'] =>\n status === 'approved' ? '1' : status === 'hold' ? '0' : status === 'spam' ? 'spam' : status === 'trash' ? 'trash' : (status ?? '1')\n\nexport interface RestImportOptions {\n origin: string\n /** Injectable for tests and for hosts that need custom dispatch. */\n fetchImpl?: typeof fetch\n /**\n * WordPress Application Password credentials — lifts the rung to rest_auth.\n * With them, post types are listed with every non-trash status\n * (`AUTH_POST_STATUSES`) in the edit context, and comments with held ones\n * too; anonymous REST only ever returns published posts and approved\n * comments. A credential the site refuses for that falls back to the\n * public listing, with a warning.\n */\n auth?: { user: string; appPassword: string }\n perPage?: number\n /**\n * Requests in flight at once, across every collection. Default 4. A site\n * with 74 pages of posts, 40 of media and 37 of comments used to receive\n * ~150 simultaneous requests — enough to trip a host's rate limit or WAF.\n */\n concurrency?: number\n /**\n * Pages fetched per collection at most. Unset = all. A truncated collection\n * is named in `warnings` (with what was skipped), never silently shortened.\n */\n maxPages?: number\n tool?: string\n}\n\nexport interface RestImportResult {\n raw: RawIR\n warnings: string[]\n /**\n * Whether the credential was honoured, for callers that must act on it\n * without reading `warnings`. `none`: no `auth` given. `accepted`: every\n * listing it unlocks was read with it. `rejected`: at least one was not —\n * `fell_back` names each (`posts`, `pages`, a CPT's rest base, `comments`,\n * `comments:hold`), and those came from the public listing instead, or not\n * at all for `comments:hold`, which has none.\n */\n credential: { status: 'none' | 'accepted' | 'rejected'; fell_back: string[] }\n /**\n * What this rung could not read, as codes a caller can act on (the text is in `warnings`).\n * `menus_require_auth`: menus and block navigation are only readable with an application password\n * of a user who may edit theme options — none was given, the site rejected it, or it lacks that right.\n * `redirects_partial`: always, over REST — it reads only the Redirection plugin's rules; Yoast Premium, Rank Math,\n * Safe Redirect Manager and `.htaccess` keep theirs where only the Bridge export reads them.\n * `redirects_require_auth`: the site runs Redirection, and its rules need an application password of a user who\n * may manage it — none was given, the site rejected it, or it lacks that right.\n * `acf_partial`: the site runs ACF / Secure Custom Fields; REST shows only the field groups set to\n * `show_in_rest` (off by default) and no options page — the Bridge export reads the rest. Where the site\n * states no field types (plain ACF, no `<name>_source`), a secret field is recognised by its name only.\n */\n gaps: string[]\n}\n\ninterface RestPost {\n id: number\n slug: string\n status?: string\n type?: string\n link?: string\n title?: { rendered?: string }\n content?: { rendered?: string }\n excerpt?: { rendered?: string }\n date_gmt?: string\n modified_gmt?: string\n author?: number\n parent?: number\n menu_order?: number\n sticky?: boolean\n /** Edit context only. */\n password?: string\n comment_status?: string\n ping_status?: string\n featured_media?: number\n categories?: number[]\n tags?: number[]\n meta?: Record<string, unknown>\n /**\n * ACF / SCF fields of the groups shown in REST (`show_in_rest`). SCF adds `<name>_source`\n * (`{ type, label, formatted_value }`) beside each value; plain ACF sends the value only.\n */\n acf?: Record<string, unknown> | unknown[]\n /** Polylang: language slug of the post and its translation group (`{ en: 12, tr: 34 }`, self included). */\n lang?: string\n translations?: Record<string, number>\n /** WPML: locale of the post and its other translations. */\n wpml_current_locale?: string\n wpml_translations?: Array<{ locale?: string; id?: number }>\n}\n\n/** What a credential lists beyond `publish`: drafts, scheduled, in-review and private posts. Trash stays out. */\nexport const AUTH_POST_STATUSES = ['publish', 'future', 'draft', 'pending', 'private'] as const\n/** Comment listings for a credential: WP's `status` takes one value, so approved and held are two requests. */\nconst AUTH_COMMENT_STATUSES = ['approve', 'hold'] as const\nconst DENIED = new Set([400, 401, 403])\n/** REST taxonomies that hold no content: menus, block-pattern categories, multilingual bookkeeping. */\nconst NOT_CONTENT_TAXONOMIES = new Set(['category', 'post_tag', 'nav_menu', 'wp_pattern_category', 'post_format', 'language', 'post_translations', 'term_language', 'term_translations'])\n/** A comment listing's name in `credential.fell_back`: `comments` (approved) or `comments:hold`. */\nconst commentKey = (status: string): string => (status === 'approve' ? 'comments' : `comments:${status}`)\n\n/**\n * ACF fields of one REST post. `<name>_source` (SCF) states each field's type and label; a secret — a\n * `password` field, or, when no type is stated, a field named like one — is never read. ACF answers `[]`\n * for a post with no field group in REST.\n */\nfunction acfOf(acf: RestPost['acf']): { acf?: Record<string, RawAcfValue> } {\n if (!acf || Array.isArray(acf) || typeof acf !== 'object') return {}\n const out: Record<string, RawAcfValue> = {}\n for (const [name, value] of Object.entries(acf)) {\n if (name.endsWith('_source') && name.slice(0, -'_source'.length) in acf) continue\n const source = acf[`${name}_source`] as { type?: unknown; label?: unknown } | undefined\n const type = typeof source?.type === 'string' ? source.type : undefined\n if (acfIsSecret(name, type)) continue\n out[name] = { value: acfScrub(value), ...(type ? { type } : {}), ...(typeof source?.label === 'string' && source.label ? { label: source.label } : {}) }\n }\n return Object.keys(out).length ? { acf: out } : {}\n}\n\n/** What a visitor can open: published, not behind a post password. */\nconst visible = (p: RawPost): boolean => p.status === 'publish' && !p.password\n\nconst positiveInteger = (name: string, value: number): number => {\n if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${name} must be a positive safe integer`)\n return value\n}\n\nexport async function fetchRestRawIR(options: RestImportOptions): Promise<RestImportResult> {\n const origin = options.origin.replace(/\\/$/, '')\n const doFetch = options.fetchImpl ?? fetch\n const perPage = positiveInteger('perPage', options.perPage ?? 100)\n if (perPage > 100) throw new RangeError('perPage must be at most 100')\n const concurrency = positiveInteger('concurrency', options.concurrency ?? 4)\n const maxPages = options.maxPages !== undefined ? positiveInteger('maxPages', options.maxPages) : undefined\n const warnings: string[] = []\n // One pool for the whole import: page fetches of every collection queue here,\n // so the cap holds even though collections are requested \"in parallel\".\n const queue: Array<() => Promise<void>> = []\n let running = 0\n const schedule = <T>(task: () => Promise<T>): Promise<T> =>\n new Promise<T>((resolve, reject) => {\n queue.push(() => task().then(resolve, reject))\n pump()\n })\n const pump = (): void => {\n while (running < concurrency && queue.length) {\n const task = queue.shift()!\n running++\n void task().finally(() => {\n running--\n pump()\n })\n }\n }\n const anonymous: Record<string, string> = { accept: 'application/json' }\n let headers = anonymous\n if (options.auth) {\n headers = { ...anonymous, authorization: `Basic ${Buffer.from(`${options.auth.user}:${options.auth.appPassword}`).toString('base64')}` }\n }\n const fellBack = new Set<string>()\n // WordPress answers a wrong Application Password with 401 on every route,\n // public ones too, so a rejected credential is found once and dropped:\n // sent on, it would also empty the public listings the import falls back to.\n let rejected = false\n if (options.auth) {\n const me = await doFetch(`${origin}/wp-json/wp/v2/users/me`, { headers })\n await me.body?.cancel()\n if (me.status === 401 || me.status === 403) {\n rejected = true\n headers = anonymous\n warnings.push(`credential: HTTP ${me.status} on users/me — the site rejected it; imported the public listings only`)\n }\n }\n\n /**\n * Every page of `path`. With `fallback`, a first page the site refuses\n * (400/401/403 — the credential may not list those statuses or the edit\n * context) is retried as `fallback` instead of dropping the collection;\n * an empty `fallback` means there is nothing public to retry, so it is\n * skipped with that warning. The retry is anonymous, and `key` goes into\n * `credential.fell_back`.\n */\n const getAll = async <T>(path: string, fallback?: string, key?: string, send = headers): Promise<T[]> => {\n const label = path.split('?')[0]!\n const url = (page: number) => `${origin}/wp-json/wp/v2/${path}${path.includes('?') ? '&' : '?'}per_page=${perPage}&page=${page}`\n // Hold the slot until the body is consumed, not merely until headers arrive.\n const pageData = (page: number) => schedule(async () => {\n const response = await doFetch(url(page), { headers: send })\n if (!response.ok) {\n await response.body?.cancel()\n if (page === 1 && fallback !== undefined && DENIED.has(response.status)) return { items: [] as T[], pages: 1, denied: response.status }\n warnings.push(`${label}: page ${page} HTTP ${response.status} — skipped`)\n return { items: [] as T[], pages: 1 }\n }\n const pages = Number(response.headers.get('x-wp-totalpages') ?? '1')\n if (!Number.isSafeInteger(pages) || pages < 0) throw new Error(`${path}: invalid x-wp-totalpages`)\n const items = await response.json() as T[]\n if (!Array.isArray(items)) throw new Error(`${path}: page ${page} is not a collection`)\n return { items, pages: Math.max(1, pages), denied: undefined as number | undefined }\n })\n const first = await pageData(1)\n if (first.denied !== undefined) {\n warnings.push(`${label}: HTTP ${first.denied} for ${path.split('?')[1]} with the credential — ${fallback ? 'fell back to the public listing' : 'skipped (no public listing)'}`)\n fellBack.add(key ?? label)\n return fallback ? getAll<T>(fallback, undefined, undefined, anonymous) : []\n }\n const totalPages = first.pages\n const firstPage = first.items\n const wanted = maxPages !== undefined ? Math.min(totalPages, maxPages) : totalPages\n if (wanted < totalPages) {\n warnings.push(`${label}: ${totalPages} pages, fetched ${wanted} (maxPages) — ${totalPages - wanted} pages skipped`)\n }\n if (wanted <= 1) return firstPage\n const rest = await Promise.all(\n Array.from({ length: wanted - 1 }, (_v, i) =>\n pageData(i + 2).then((r) => r.items),\n ),\n )\n return firstPage.concat(...rest)\n }\n\n // The site's own name and tagline (`/wp-json/` index, public): without them the store's site singleton says \"Site\".\n // Advisory: an index that does not answer leaves them out, as before.\n const about = await schedule(async () => {\n try {\n const index = await doFetch(`${origin}/wp-json/`, { headers })\n if (!index.ok) { await index.body?.cancel(); return null }\n return (await index.json()) as { name?: unknown; description?: unknown; url?: unknown; home?: unknown; timezone_string?: unknown; gmt_offset?: unknown; namespaces?: unknown } | null\n } catch { return null }\n })\n\n interface RestType { slug: string; rest_base?: string; viewable?: boolean }\n // `viewable` (has public addresses) is only in the edit context: with a credential, ask for it.\n let typesResp = await doFetch(`${origin}/wp-json/wp/v2/types${options.auth && !rejected ? '?context=edit' : ''}`, { headers })\n if (!typesResp.ok && options.auth && !rejected) {\n await typesResp.body?.cancel()\n typesResp = await doFetch(`${origin}/wp-json/wp/v2/types`, { headers: anonymous })\n }\n const types: Record<string, RestType> = typesResp.ok ? ((await typesResp.json()) as Record<string, RestType>) : {}\n if (!typesResp.ok) warnings.push(`types: HTTP ${typesResp.status} — importing posts and pages only`)\n const postTypes = Object.values(types).filter(\n (t) => t.rest_base && !SKIP_TYPES.test(t.slug) && t.slug !== 'attachment',\n )\n // A type WordPress says has no public address (`viewable: false`, e.g. testimonials used inside pages)\n // is still content, but its REST `link` is not an address: it is imported without one.\n const notViewable = new Set(postTypes.filter((t) => t.viewable === false).map((t) => t.slug))\n const bases = postTypes.length ? postTypes.map((t) => ({ slug: t.slug, base: t.rest_base! })) : [\n { slug: 'post', base: 'posts' },\n { slug: 'page', base: 'pages' },\n ]\n\n interface RestTerm { id: number; slug: string; name: string; taxonomy?: string; parent?: number; description?: string; link?: string }\n interface RestUser { id: number; slug: string; name: string }\n interface RestMedia {\n id: number\n slug: string\n title?: { rendered?: string }\n source_url?: string\n alt_text?: string\n caption?: { rendered?: string }\n mime_type?: string\n media_details?: { width?: number; height?: number; file?: string }\n post?: number | null\n date_gmt?: string\n /** The attachment page. */\n link?: string\n }\n interface RestComment {\n id: number\n post: number\n parent?: number\n author?: number\n author_name?: string\n author_url?: string\n date_gmt?: string\n content?: { rendered?: string }\n status?: string\n type?: string\n }\n\n // Anonymous: WP's defaults (published posts, approved comments). With a\n // credential: every non-trash status, and held comments as a second listing.\n // A credential rejected outright unlocks nothing: every listing it would have read fell back.\n if (rejected) {\n for (const b of bases) fellBack.add(b.base)\n for (const status of AUTH_COMMENT_STATUSES) fellBack.add(commentKey(status))\n }\n const authed = options.auth !== undefined && !rejected\n const postListing = (base: string): Promise<RestPost[]> =>\n authed ? getAll<RestPost>(`${base}?status=${AUTH_POST_STATUSES.join(',')}&context=edit`, base, base) : getAll<RestPost>(base)\n const commentListing = async (): Promise<RestComment[]> => {\n if (!authed) return getAll<RestComment>('comments')\n const lists = await Promise.all(AUTH_COMMENT_STATUSES.map((status) =>\n // Approved comments are public, so a refused credential still gets them; held ones have no public listing.\n getAll<RestComment>(`comments?status=${status}&context=edit`, status === 'approve' ? 'comments' : '', commentKey(status))))\n const byId = new Map<number, RestComment>()\n for (const c of lists.flat()) if (!byId.has(c.id)) byId.set(c.id, c)\n return [...byId.values()]\n }\n // Custom taxonomies in REST (a CPT's `project_type`): their terms and each post's links to them.\n // Menus, block-pattern categories and multilingual bookkeeping are not content taxonomies.\n interface RestTaxonomy { slug: string; rest_base?: string }\n const taxResp = await schedule(async () => {\n try {\n const r = await doFetch(`${origin}/wp-json/wp/v2/taxonomies`, { headers })\n if (!r.ok) { await r.body?.cancel(); return {} }\n return (await r.json()) as Record<string, RestTaxonomy>\n } catch { return {} }\n })\n const extraTaxonomies = Object.values(taxResp && typeof taxResp === 'object' ? taxResp : {})\n .filter((t) => t.rest_base && /^[\\w-]+$/.test(t.rest_base) && !NOT_CONTENT_TAXONOMIES.has(t.slug))\n .map((t) => ({ taxonomy: t.slug, base: t.rest_base! }))\n .toSorted((a, b) => a.taxonomy.localeCompare(b.taxonomy))\n const [categories, tags, users, media, restComments, ...lists] = await Promise.all([\n getAll<RestTerm>('categories'),\n getAll<RestTerm>('tags'),\n getAll<RestUser>('users'),\n getAll<RestMedia>('media'),\n commentListing(),\n ...extraTaxonomies.map((t) => getAll<RestTerm>(t.base)),\n ...bases.map((b) => postListing(b.base)),\n ])\n const extraTerms = lists.slice(0, extraTaxonomies.length) as RestTerm[][]\n const postLists = lists.slice(extraTaxonomies.length) as RestPost[][]\n\n const termsById = new Map<number, RawTerm>()\n /** A term's public address, for menu items that name it; RawTerm carries none. */\n const termLinks = new Map<number, string>()\n for (const [tax, list] of [\n ['category', categories],\n ['post_tag', tags],\n ...extraTaxonomies.map((t, i) => [t.taxonomy, extraTerms[i] ?? []] as const),\n ] as const) {\n for (const t of list) {\n if (t.link) termLinks.set(t.id, t.link)\n termsById.set(t.id, {\n id: t.id,\n taxonomy: tax,\n slug: t.slug,\n name: strip(t.name),\n parent: t.parent ? (list.find((x) => x.id === t.parent)?.slug ?? null) : null,\n parent_resolved: t.parent ? list.some((x) => x.id === t.parent) : null,\n description: t.description ?? '',\n })\n }\n }\n const userById = new Map(users.map((u) => [u.id, u]))\n\n const posts: RawPost[] = []\n // Translation groups, one pair per group. Polylang's `translations` already\n // includes the post itself; WPML lists the OTHER translations, so add self.\n const languagePairs: RawLanguagePair[] = []\n const seenGroups = new Set<string>()\n const recordGroup = (self: RestPost, lang: string | null) => {\n const translations: Record<string, number> = {}\n if (self.translations && typeof self.translations === 'object') {\n for (const [code, id] of Object.entries(self.translations)) if (typeof id === 'number') translations[code] = id\n } else if (Array.isArray(self.wpml_translations)) {\n for (const t of self.wpml_translations) if (t.locale && typeof t.id === 'number') translations[t.locale] = t.id\n if (lang) translations[lang] = self.id\n }\n const ids = Object.values(translations)\n if (ids.length < 2) return\n const key = [...ids].toSorted((a, b) => a - b).join(',')\n if (seenGroups.has(key)) return\n seenGroups.add(key)\n languagePairs.push({ post: self.id, translations })\n }\n for (const [i, base] of bases.entries()) {\n for (const p of postLists[i] ?? []) {\n const custom = extraTaxonomies.flatMap((t) => {\n const ids = (p as unknown as Record<string, unknown>)[t.base]\n return Array.isArray(ids) ? ids.filter((id): id is number => typeof id === 'number') : []\n })\n const termRefs: RawTermRef[] = [...(p.categories ?? []), ...(p.tags ?? []), ...custom].map((id) => {\n const t = termsById.get(id)\n return t\n ? { taxonomy: t.taxonomy, slug: t.slug, name: t.name, resolved: true }\n : { taxonomy: 'category', slug: String(id), name: String(id), resolved: false }\n })\n const author = p.author ? (userById.get(p.author)?.slug ?? null) : null\n const meta: Record<string, unknown> = { ...(p.meta && typeof p.meta === 'object' ? p.meta : {}) }\n if (p.featured_media) meta._thumbnail_id = String(p.featured_media)\n const lang = (typeof p.lang === 'string' && p.lang) || (typeof p.wpml_current_locale === 'string' && p.wpml_current_locale) || null\n recordGroup(p, lang)\n posts.push({\n ...(lang ? { lang } : {}),\n id: p.id,\n type: base.slug,\n status: p.status ?? 'publish',\n slug: p.slug,\n title: p.title?.rendered ?? '',\n link: notViewable.has(base.slug) ? null : (p.link ?? null),\n guid: null,\n author,\n date: iso(p.date_gmt),\n modified: iso(p.modified_gmt),\n content: p.content?.rendered ?? '',\n excerpt: p.excerpt?.rendered ?? '',\n parent: p.parent || null,\n menu_order: p.menu_order ?? 0,\n sticky: p.sticky ?? false,\n password: p.password ? PROTECTED : null,\n comment_status: p.comment_status ?? null,\n ping_status: p.ping_status ?? null,\n terms: termRefs,\n meta,\n ...acfOf(p.acf),\n })\n }\n }\n\n const attachments: RawAttachment[] = media.map((m) => ({\n id: m.id,\n title: strip(m.title?.rendered) || m.slug,\n slug: m.slug,\n url: m.source_url ?? null,\n alt: m.alt_text ?? '',\n caption: strip(m.caption?.rendered),\n file: m.media_details?.file ?? null,\n image_meta: m.media_details ?? null,\n mime: m.mime_type ?? null,\n parent: m.post ?? null,\n parent_resolved: m.post ? posts.some((p) => p.id === m.post) : null,\n // The attachment page sits under its parent's address (`/secret-draft/photo/`): kept only when there is no parent or\n // the parent is proven public, else it would carry a draft's, a private or a scheduled post's slug.\n link: (!m.post || posts.some((p) => p.id === m.post && visible(p))) ? (m.link || null) : null,\n date: iso(m.date_gmt),\n }))\n\n // ── menus: classic menus + published block navigation; both need `edit_theme_options` ──\n const gaps: string[] = []\n // ACF answers `acf` (at least `[]`) on every post of a type it knows: then REST shows only the field\n // groups set to `show_in_rest` (off by default) and never an options page. What it hides, only Bridge reads.\n if (postLists.some((list) => list.some((p) => p.acf !== undefined))) gaps.push('acf_partial')\n let menus: RawMenu[] = []\n if (!authed) {\n // Not a warning: without a working credential this is the rung's known limit, named for the caller in `gaps`.\n gaps.push('menus_require_auth')\n } else {\n const listing = async <T>(path: string): Promise<{ items: T[]; status: number }> => {\n const url = (page: number) => `${origin}/wp-json/wp/v2/${path}${path.includes('?') ? '&' : '?'}per_page=${perPage}&page=${page}`\n const first = await schedule(async () => {\n const r = await doFetch(url(1), { headers })\n if (!r.ok) { await r.body?.cancel(); return { items: [] as T[], status: r.status, pages: 1 } }\n const items = await r.json() as T[]\n return { items: Array.isArray(items) ? items : [], status: r.status, pages: Math.max(1, Number(r.headers.get('x-wp-totalpages') ?? '1') || 1) }\n })\n const wanted = maxPages !== undefined ? Math.min(first.pages, maxPages) : first.pages\n const rest = await Promise.all(Array.from({ length: wanted - 1 }, (_v, i) => schedule(async () => {\n const r = await doFetch(url(i + 2), { headers })\n if (!r.ok) { await r.body?.cancel(); warnings.push(`${path.split('?')[0]}: page ${i + 2} HTTP ${r.status} — skipped`); return [] as T[] }\n const items = await r.json() as T[]\n return Array.isArray(items) ? items : []\n })))\n return { items: first.items.concat(...rest), status: first.status }\n }\n const [classic, items, navs, parts, templates] = await Promise.all([\n listing<RestMenu>('menus?context=edit'),\n listing<RestMenuItem>('menu-items?context=edit'),\n listing<RestNavigation>('navigation?context=edit&status=publish'),\n listing<RestTemplatePart>('template-parts?context=edit'),\n // Which template parts the pages use: a theme ships alternatives no template shows.\n listing<RestTemplate>('templates?context=edit&_fields=slug,content'),\n ])\n const denied = [classic, items, navs].filter((l) => DENIED.has(l.status))\n if (denied.length) {\n gaps.push('menus_require_auth')\n warnings.push(`menus: HTTP ${denied[0]!.status} with the credential — the user may not edit theme options; menus not read`)\n }\n for (const [name, l] of [['menus', classic], ['menu-items', items], ['navigation', navs]] as const) {\n if (!l.status || (l.status >= 400 && !DENIED.has(l.status) && l.status !== 404)) warnings.push(`${name}: HTTP ${l.status} — skipped`)\n }\n const slugOf = new Map(posts.filter(visible).map((p) => [p.id, p.slug]))\n const linkOf = new Map(posts.filter(visible).flatMap((p) => (p.link ? [[p.id, p.link] as const] : [])))\n const ctx: MenuContext = {\n origin,\n postSlug: (id) => slugOf.get(id),\n termSlug: (taxonomy, id) => { const t = termsById.get(id); return t && t.taxonomy === taxonomy ? t.slug : undefined },\n postLink: (id) => linkOf.get(id),\n termLink: (taxonomy, id) => (termsById.get(id)?.taxonomy === taxonomy ? termLinks.get(id) : undefined),\n pages: posts.filter((p) => p.type === 'page' && p.status === 'publish' && !p.password).map((p) => ({ id: p.id, parent: p.parent ?? null, menu_order: p.menu_order ?? 0, title: strip(p.title), link: p.link ?? null, slug: p.slug })),\n }\n const dropped = { count: 0 }\n menus = classicMenus(DENIED.has(classic.status) ? [] : classic.items, DENIED.has(items.status) ? [] : items.items, ctx, dropped)\n menus.push(...blockMenus(DENIED.has(navs.status) ? [] : navs.items, parts.status < 400 ? parts.items : [], ctx, new Set(menus.map((m) => m.slug)), dropped, templates.status < 400 ? templates.items : []))\n // A count only: the titles of what was left out are exactly what must not travel.\n if (dropped.count) warnings.push(`menus: ${dropped.count} item(s) are drafts or point at content not proven public (unpublished, password-protected, or not read by this import) — left out`)\n }\n\n const postIds = new Set(posts.map((p) => p.id))\n const commentIds = new Set(restComments.map((c) => c.id))\n const comments: RawComment[] = restComments.map((c) => ({\n id: c.id,\n post: c.post,\n post_type: posts.find((p) => p.id === c.post)?.type,\n parent: c.parent || null,\n parent_resolved: c.parent ? commentIds.has(c.parent) : null,\n author: strip(c.author_name) || 'anonymous',\n email: null,\n url: c.author_url || null,\n date: iso(c.date_gmt),\n date_gmt: c.date_gmt ?? null,\n content: c.content?.rendered ?? '',\n approved: approvedOf(c.status),\n type: c.type ?? 'comment',\n user_id: c.author || null,\n }))\n for (const c of comments) if (!postIds.has(c.post)) warnings.push(`comment ${c.id}: post ${c.post} not in fetched set`)\n\n // The rung is what was actually read: a credential rejected outright read nothing.\n // ── redirects: the Redirection plugin's rules (`redirection/v1`), with a credential that may manage them ──\n let redirects: RawRedirect[] = []\n let redirectsExcluded: RawRedirectExcluded[] = []\n gaps.push('redirects_partial')\n const namespaces = Array.isArray(about?.namespaces) ? (about.namespaces as unknown[]) : undefined\n const redirection = namespaces ? namespaces.includes('redirection/v1') : undefined\n if (redirection && !authed) gaps.push('redirects_require_auth')\n else if (authed && redirection !== false) {\n // Redirection pages from 0 and answers `{ items, total }`.\n const all = async <T extends { id: number }>(path: string): Promise<{ items: T[]; status: number }> => {\n const items: T[] = []\n const seen = new Set<number>()\n for (let page = 0; page < (maxPages ?? 500); page++) {\n // oxlint-disable-next-line no-await-in-loop -- `total` is only known from the page before\n const r = await schedule(() => doFetch(`${origin}/wp-json/redirection/v1/${path}?per_page=200&page=${page}`, { headers }))\n if (!r.ok) { await r.body?.cancel(); return { items, status: r.status } }\n // oxlint-disable-next-line no-await-in-loop -- the body of the page just fetched\n const body = await r.json() as { items?: T[]; total?: number }\n const fresh = (Array.isArray(body.items) ? body.items : []).filter((x) => !seen.has(x.id))\n for (const x of fresh) { seen.add(x.id); items.push(x) }\n if (!fresh.length || items.length >= Number(body.total ?? 0)) break\n }\n return { items, status: 200 }\n }\n // The site-wide match defaults a rule without its own flags takes; answered as `{ settings }`.\n const settings = async (): Promise<RestRedirectionOptions | undefined> => {\n try {\n const r = await schedule(() => doFetch(`${origin}/wp-json/redirection/v1/setting`, { headers }))\n if (!r.ok) { await r.body?.cancel(); return undefined }\n const body = await r.json() as { settings?: RestRedirectionOptions } | null\n return body?.settings && typeof body.settings === 'object' ? body.settings : undefined\n } catch { return undefined }\n }\n const [rules, groups, siteFlags] = await Promise.all([all<RestRedirection>('redirect'), all<RestRedirectionGroup>('group'), settings()])\n if (DENIED.has(rules.status)) {\n gaps.push('redirects_require_auth')\n warnings.push(`redirects: HTTP ${rules.status} with the credential — the user may not manage Redirection; its rules not read`)\n } else if (rules.status === 200) {\n ;({ redirects, excluded: redirectsExcluded } = redirectionRules(rules.items, groups.status === 200 ? groups.items : [], origin, siteFlags))\n } else if (redirection) warnings.push(`redirects: HTTP ${rules.status} — Redirection's rules not read`)\n }\n\n const kind: SourceAccessKind = authed ? 'rest_auth' : 'rest_public'\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind, tool: options.tool ?? '@contentrain/wp-import' },\n site: {\n url: origin,\n ...(typeof about?.name === 'string' && strip(about.name) ? { title: strip(about.name) } : {}),\n ...(typeof about?.description === 'string' && strip(about.description) ? { description: strip(about.description) } : {}),\n // Where WordPress is installed and where the site is served, as WXR names them (they differ for a subdirectory install).\n ...(typeof about?.url === 'string' && about.url ? { base_site_url: about.url } : {}),\n ...(typeof about?.home === 'string' && about.home ? { base_blog_url: about.home } : {}),\n // The zone the site's local date-times (ACF date time pickers) are written in.\n ...(typeof about?.timezone_string === 'string' && about.timezone_string ? { timezone: about.timezone_string } : {}),\n ...(about?.gmt_offset !== undefined && about.gmt_offset !== null && about.gmt_offset !== '' && Number.isFinite(Number(about.gmt_offset)) ? { gmt_offset: Number(about.gmt_offset) } : {}),\n },\n authors: users.map((u) => ({ id: u.id, login: u.slug, display_name: strip(u.name) || u.slug, email: null })),\n terms: [...termsById.values()],\n posts,\n attachments,\n comments,\n ...(menus.length ? { menus } : {}),\n ...(redirects.length ? { redirects } : {}),\n ...(redirectsExcluded.length ? { redirects_excluded: redirectsExcluded } : {}),\n ...(languagePairs.length ? { language_pairs: languagePairs } : {}),\n }\n const credential: RestImportResult['credential'] = {\n status: !options.auth ? 'none' : fellBack.size ? 'rejected' : 'accepted',\n fell_back: [...fellBack].toSorted(),\n }\n return { raw, warnings, credential, gaps }\n}\n","// RawIR → .contentrain content store, as a pure file map.\n//\n// Ported from the measured import chain (the \"deviations from r4i\" it carried\n// are already folded in: PATH_PATTERNS-conformant layout, ContentrainConfig\n// shape, meta files per locale). Two properties are load-bearing:\n//\n// 1. Identity formulas — hexId('posts:' + slug), hexId('category:' + slug) —\n// are shared with the REST path, so the same site imported twice (or via a\n// later delta) lands on the same entry ids.\n// 2. The EntrySourceMap (wp post id → entry address) is produced HERE and only\n// here: this is the one place that knows both sides of the mapping, and the\n// comments intake downstream cannot exist without it.\n\nimport type { EntrySourceMap, FieldDef, ModelDefinition, RawAcfOptionsPage, RawAcfValue, RawIR, RawPost } from '@contentrain/types'\nimport { ACF_REFERENCE_TYPES, acfFieldDef, acfRows, acfScrub, acfValue, mergeFieldDef, type AcfReference } from './acf.js'\nimport {\n byValue,\n canon,\n coreFields,\n decodeSlug,\n hexId,\n PLUGIN_META,\n SKIP_TYPES,\n addressSlug,\n slugify,\n strip,\n taxModelId,\n} from './core.js'\n\n/** A post whose imported slug is not the address it was served at: it gets a 301 from `from`. */\nexport interface SlugMove {\n wp_id: number\n type: string\n /** The path the source site served it at (its `link`), when the source named one. */\n from: string | null\n /** The slug the entry was written under. */\n slug: string\n /**\n * `empty`: the source slug left no word, `collision`: another entry of the same type already holds it,\n * `rewritten`: characters outside the slug alphabet (ZWNJ/ZWJ, `・`, an NFD spelling...) were changed.\n */\n reason: 'empty' | 'collision' | 'rewritten'\n}\n\nconst utf8Length = (s: string): number => new TextEncoder().encode(s).length\n\n/** `s` cut on a code-point boundary to at most `max` UTF-8 bytes, without a trailing hyphen. */\nconst fitBytes = (s: string, max: number): string => {\n let out = ''\n let bytes = 0\n for (const ch of s) {\n const n = utf8Length(ch)\n if (bytes + n > max) break\n out += ch\n bytes += n\n }\n return out.replace(/-+$/, '')\n}\n\nexport interface ImportReport {\n slug_rewritten: number\n slug_fallback: number\n /** Posts whose address changed (empty or colliding slug): each needs a 301 from its old address. */\n slug_moves: SlugMove[]\n title_fallback: number\n meta_fields: Record<string, string>\n acf_fields: Record<string, string>\n /** ACF Options Page fields written to the `site` entry (`field: type`), prefixed `<page>_` on a name clash. */\n acf_options: Record<string, string>\n /** ACF Options Page fields whose name was already taken, written under a counter (`new name: <page slug>.<field>`). */\n acf_options_renamed: Record<string, string>\n /** ACF select/checkbox values outside their field's stated choices, left out (`field: count`). */\n acf_outside_choices: Record<string, number>\n /** ACF date-times written without a zone because the source named none (`timezone_string` / `gmt_offset`). */\n acf_datetime_unzoned: number\n skipped_types: string[]\n dropped_relations: number\n models: Record<string, { kind: string; domain: string; fields: number; entries: number }>\n /** Default first, then every other language seen on a post. One entry on a monolingual site. */\n locales: string[]\n /** Translation groups that were folded into one entry id across locales. */\n translation_groups: number\n /**\n * Password-protected posts imported as `draft`, whatever their WordPress\n * status. Their body is the protected text, and nothing downstream (query\n * SDK, emitter) enforces `visibility: password`, so publishing one would\n * put that text on a public site. Publish only after deciding what to show.\n */\n password_protected_drafts: number\n /**\n * The source named no site title (no REST index name, no WXR channel title): the `site` entry has no\n * `title`. The field stays required, so the store says what is missing rather than inventing a name.\n */\n site_title_missing: boolean\n}\n\nexport interface ContentrainResult {\n files: Record<string, string>\n entry_source_map: EntrySourceMap\n report: ImportReport\n}\n\ntype Entry = Record<string, unknown>\ntype Meta = { status: string; source: string; updated_by: string; publish_at?: string }\n\nconst pick = (o: Record<string, unknown>, keys: Set<string>): Entry =>\n Object.fromEntries(Object.entries(o).filter(([k, v]) => keys.has(k) && v !== undefined && v !== null && v !== ''))\nconst typeModelId = (t: string): string => (t === 'post' ? 'posts' : t === 'page' ? 'pages' : t.replace(/_/g, '-'))\nconst domainOf = (t: string): string => (t === 'post' ? 'blog' : t === 'page' ? 'site' : 'custom')\n\n/** `en_US` / `tr-TR` / `en` → `en`: the store's locale is the primary subtag. */\nconst normLocale = (code: string | null | undefined): string => (code ?? '').split(/[-_]/)[0]?.toLowerCase() ?? ''\n\n/** Multilingual-plugin taxonomies that carry language bookkeeping, not content. */\nconst LANGUAGE_TAXONOMIES = new Set(['language', 'post_translations', 'term_language', 'term_translations'])\n\n/**\n * A relation field over `targets`: its declared model, and how a reference into\n * it is stored.\n *\n * With several targets the id alone does not say which model's entry it is, so\n * the reference is the pair `{ model, ref }`. With one there is nothing to\n * choose between: the field is single-target and stores the entry id. Writing\n * the pair there fails the same validator that requires it when there are\n * several — so the choice is made in one place, from the same list the model\n * declares.\n */\nfunction relationOver(targets: string[]): {\n model: string | string[]\n ref: (entry: { model: string; ref: string }) => string | { model: string; ref: string }\n} {\n const single = targets.length === 1\n return { model: single ? targets[0]! : targets, ref: (entry) => (single ? entry.ref : entry) }\n}\n\n/** Post, term, user or attachment ids of an ACF reference value: ids, numeric strings or `{ ID }` objects. */\nconst idsOf = (v: unknown): number[] =>\n (Array.isArray(v) ? v : [v])\n .map((x) => (typeof x === 'number' ? x : typeof x === 'string' && /^\\d+$/.test(x) ? Number(x) : x && typeof x === 'object' ? Number((x as { ID?: unknown; id?: unknown; term_id?: unknown }).ID ?? (x as { id?: unknown }).id ?? (x as { term_id?: unknown }).term_id) : Number.NaN))\n .filter((n) => Number.isSafeInteger(n) && n > 0)\n\nexport function rawToContentrain(raw: RawIR, opts?: { updatedBy?: string }): ContentrainResult {\n const updatedBy = opts?.updatedBy ?? '@contentrain/wp-import'\n const locale = normLocale(raw.site.language) || 'en'\n const models: Record<string, ModelDefinition> = {}\n const contents: Record<string, Record<string, Entry>> = {}\n const metas: Record<string, Record<string, Meta>> = {}\n // Per-locale buckets for i18n models (post types on a multilingual site).\n const localeContents: Record<string, Record<string, Record<string, Entry>>> = {}\n const localeMetas: Record<string, Record<string, Record<string, Meta>>> = {}\n\n // ── languages ──\n // A post's language comes from the plugin (`lang`) or, in WXR, from the\n // `language` taxonomy term Polylang attaches. Posts without one belong to the\n // site's default locale. More than one locale seen → post-type models are\n // i18n and content is written per locale.\n const postLocale = (p: RawPost): string =>\n normLocale(p.lang ?? p.terms.find((t) => t.taxonomy === 'language')?.slug) || locale\n const locales = [locale, ...[...new Set(raw.posts.filter((p) => !SKIP_TYPES.test(p.type)).map(postLocale))].filter((l) => l !== locale).toSorted()]\n const multilingual = locales.length > 1\n // Translation groups → one canonical post per group. Its entry id is shared\n // by every translation, which is how an i18n collection addresses one entry\n // in several locales. The canonical member is the default-locale post when\n // there is one, else the lowest id — deterministic either way.\n const postById = new Map(raw.posts.map((p) => [p.id, p]))\n const canonicalOf = new Map<number, number>()\n let translationGroups = 0\n for (const pair of raw.language_pairs ?? []) {\n const members = [...new Set(Object.values(pair.translations))].filter((id) => postById.has(id) && !SKIP_TYPES.test(postById.get(id)!.type))\n if (members.length < 2) continue\n const memberLocales = members.map((id) => postLocale(postById.get(id)!))\n if (new Set(memberLocales).size !== members.length)\n throw new Error(`Translation group ${pair.post} has multiple posts in the same normalized locale; refusing to overwrite a translation`)\n const canonical = members.find((id) => postLocale(postById.get(id)!) === locale) ?? Math.min(...members)\n for (const id of members) canonicalOf.set(id, canonical)\n translationGroups++\n }\n let siteEntry: Entry = {}\n let siteMeta: Meta | null = null\n const report: ImportReport = {\n slug_rewritten: 0,\n slug_fallback: 0,\n slug_moves: [],\n title_fallback: 0,\n meta_fields: {},\n acf_fields: {},\n acf_options: {},\n acf_options_renamed: {},\n acf_outside_choices: {},\n acf_datetime_unzoned: 0,\n skipped_types: [],\n dropped_relations: 0,\n models: {},\n locales,\n translation_groups: translationGroups,\n password_protected_drafts: 0,\n site_title_missing: false,\n }\n const importMeta = (status: string, extra: Partial<Meta> = {}): Meta => ({\n status,\n source: 'import',\n updated_by: updatedBy,\n ...extra,\n })\n const mapStatus = (p: RawPost): Meta => {\n // Checked first: a protected post must never come in published or scheduled.\n if (p.password && p.status !== 'trash') {\n report.password_protected_drafts++\n return importMeta('draft')\n }\n if (p.status === 'future' && (!p.date || !Number.isFinite(Date.parse(p.date))))\n throw new Error(`Scheduled WordPress post ${p.id} has no valid publication date`)\n return p.status === 'publish' || p.status === 'inherit'\n ? importMeta('published')\n : p.status === 'future'\n ? importMeta('published', { publish_at: p.date! })\n : p.status === 'pending'\n ? importMeta('in_review')\n : p.status === 'trash'\n ? importMeta('archived')\n : importMeta('draft')\n }\n const addModel = (m: ModelDefinition): void => {\n models[m.id] = m\n contents[m.id] ??= {}\n metas[m.id] ??= {}\n }\n\n // ── identities (shared formulas — REST and WXR must agree) ──\n const authorId = (login: string): string => hexId(`authors:${login}`)\n const termId = (tax: string, slug: string): string => hexId(`${tax}:${slug}`)\n const usedSlugs = new Map<string, number>()\n const postSlug = (p: RawPost): string => {\n // The slug is the page's address: kept as the source served it (any script), not transliterated.\n let s = addressSlug(p.slug)\n const moved = (reason: SlugMove['reason'], slug: string): void => {\n let from: string | null = null\n try { from = p.link ? new URL(p.link).pathname : null } catch { from = null }\n report.slug_moves.push({ wp_id: p.id, type: p.type, from, slug, reason })\n }\n let empty = false\n let rewritten = false\n if (!s) {\n s = `${p.type}-${p.id}`\n empty = true\n report.slug_fallback++\n } else if (s !== decodeSlug(p.slug)) {\n report.slug_rewritten++\n // Case alone is not a move (WP serves post_name lowercase); anything else changes the address.\n rewritten = s !== decodeSlug(p.slug).toLowerCase()\n }\n // Slugs are unique per type — and per locale on a multilingual site, where\n // `/about/` and `/tr/about/` are different entries with the same slug.\n const key = multilingual ? `${p.type}:${postLocale(p)}:${s}` : `${p.type}:${s}`\n const n = usedSlugs.get(key) ?? 0\n usedSlugs.set(key, n + 1)\n if (n) {\n const suffix = `-${p.id}`\n const unique = `${fitBytes(s, 200 - utf8Length(suffix))}${suffix}`\n moved('collision', unique)\n return unique\n }\n if (empty) moved('empty', s)\n else if (rewritten) moved('rewritten', s)\n return s\n }\n const slugOf = new Map<number, string>()\n const postEntry = new Map<number, { model: string; ref: string }>()\n for (const p of raw.posts.toSorted((a, b) => a.id - b.id)) {\n // Only exported entries may be relation targets or appear in the source map.\n if (SKIP_TYPES.test(p.type)) continue\n slugOf.set(p.id, postSlug(p))\n }\n // Keep established slug identities unless distinct translation groups collide.\n // Prefer the default-locale group, then the lowest WP id, independently of\n // REST pagination/WXR order. A colliding group gets a WP-id namespace.\n const identityOwner = new Map<string, number>()\n const exported = raw.posts.filter((p) => !SKIP_TYPES.test(p.type))\n const canonicalPosts = exported.filter((p) => (canonicalOf.get(p.id) ?? p.id) === p.id)\n .toSorted((a, b) => Number(postLocale(b) === locale) - Number(postLocale(a) === locale) || a.id - b.id)\n for (const p of canonicalPosts) {\n const key = `${typeModelId(p.type)}:${slugOf.get(p.id)!}`\n if (!identityOwner.has(key)) identityOwner.set(key, p.id)\n }\n for (const p of exported) {\n const canonical = canonicalOf.get(p.id) ?? p.id\n const mid = typeModelId(p.type)\n const key = `${mid}:${slugOf.get(canonical) ?? slugOf.get(p.id)!}`\n postEntry.set(p.id, { model: mid, ref: hexId(identityOwner.get(key) === canonical ? key : `${mid}:wp:${canonical}`) })\n }\n const mediaRef = (id: number): string | null => (raw.attachments.some((a) => a.id === id) ? hexId(`media:${id}`) : null)\n\n // ── ACF references: the store entry each id points at ──\n const termById = new Map(raw.terms.map((t) => [t.id, t]))\n const authorById = new Map(raw.authors.filter((a) => a.id !== null).map((a) => [a.id!, a]))\n const refOf = (kind: AcfReference, id: number): { model: string; ref: string } | null => {\n if (kind === 'post') return postEntry.get(id) ?? null\n if (kind === 'media') { const m = mediaRef(id); return m ? { model: 'media', ref: m } : null }\n if (kind === 'user') { const a = authorById.get(id); return a && models.authors ? { model: 'authors', ref: authorId(slugify(a.login)) } : null }\n if (kind === 'term') { const t = termById.get(id); return t && models[taxModelId(t.taxonomy)] ? { model: taxModelId(t.taxonomy), ref: termId(t.taxonomy, t.slug) } : null }\n return null\n }\n interface AcfFieldPlan { def?: FieldDef; kind?: AcfReference; multiple: boolean; models: Set<string> }\n /** Every ACF field on these posts: its definition, or — for a reference — its kind and target models. */\n const acfPlan = (items: RawPost[], taken: (k: string) => boolean): Map<string, AcfFieldPlan> => {\n const out = new Map<string, AcfFieldPlan>()\n // An untyped field (the source states no ACF type: a Bridge export, WXR meta) whose every value is an attachment id is\n // an image or file field the value's shape cannot show — a bare number reads as one. Tracked per field below.\n const untyped = new Map<string, { values: unknown[]; typed: boolean }>()\n for (const p of items) {\n for (const [k, acf] of Object.entries(p.acf ?? {})) {\n if (taken(k) || acf.value === null || acf.value === undefined || acf.value === '' || acf.value === false && acf.type !== 'true_false') continue\n const kind = acf.type ? ACF_REFERENCE_TYPES[acf.type] : undefined\n if (kind === 'address') {\n const def: FieldDef = Array.isArray(acf.value) ? { type: 'array', items: 'url' } : { type: 'url' }\n const cur = out.get(k)\n out.set(k, { def: cur?.def ?? { ...def, ...(acf.label ? { label: strip(acf.label) } : {}) }, kind, multiple: false, models: new Set() })\n continue\n }\n if (kind) {\n const cur = out.get(k) ?? { kind, multiple: acf.type === 'relationship' || acf.type === 'gallery', models: new Set<string>() }\n if (Array.isArray(acf.value)) cur.multiple = true\n for (const id of idsOf(acf.value)) { const r = refOf(kind, id); if (r) cur.models.add(r.model) }\n out.set(k, cur)\n continue\n }\n const seen = untyped.get(k) ?? untyped.set(k, { values: [], typed: false }).get(k)!\n if (acf.type) seen.typed = true\n else seen.values.push(acf.value)\n const def = acfFieldDef(k, acfScrub(acf.value), { type: acf.type, label: acf.label })\n if (!def) continue\n const cur = out.get(k)\n out.set(k, { def: cur?.def ? mergeFieldDef(cur.def, def) : def, multiple: false, models: new Set() })\n }\n }\n // Every non-empty value an id in the media library (and at least one value): a media reference, not a number. One value\n // that is not (a count that happens to match an id) keeps the field what its values say.\n const isMediaId = (v: unknown): boolean => (typeof v === 'number' ? Number.isSafeInteger(v) && v > 0 : typeof v === 'string' && /^\\d+$/.test(v)) && mediaRef(Number(v)) !== null\n for (const [k, seen] of untyped) {\n const plan = out.get(k)\n if (!plan?.def || seen.typed || !seen.values.length) continue\n const all = seen.values.every((v) => (Array.isArray(v) ? v.length > 0 && v.every(isMediaId) : isMediaId(v)))\n if (all) out.set(k, { kind: 'media', multiple: seen.values.some(Array.isArray), models: new Set(['media']) })\n }\n // A reference none of whose targets is in the store has no model to point at: it is left out.\n for (const [k, plan] of out) if (!plan.def && !plan.models.size) out.delete(k)\n return out\n }\n const acfRefs = (plan: AcfFieldPlan, value: unknown): unknown => {\n const refs = idsOf(value).map((id) => refOf(plan.kind!, id)).filter((r): r is { model: string; ref: string } => !!r)\n const missing = idsOf(value).length - refs.length\n if (missing > 0) report.dropped_relations += missing\n if (!refs.length) return undefined\n const poly = plan.models.size > 1\n const one = (r: { model: string; ref: string }) => (poly ? r : r.ref)\n return plan.multiple ? refs.map(one) : one(refs[0]!)\n }\n // page_link: an id is the address of that post as it is now.\n // Only a published, unprotected target's address: a draft's `?page_id=` is no address to keep.\n const addressOf = (v: unknown): unknown => {\n if (Array.isArray(v)) return v.map(addressOf).filter(Boolean)\n if (typeof v !== 'number') return v\n const t = postById.get(v)\n return t && t.status === 'publish' && !t.password ? (t.link ?? undefined) : undefined\n }\n /** An ACF value as the store holds it: typed by the plan, references resolved; `undefined` = nothing to write. */\n const acfEntryValue = (k: string, plan: AcfFieldPlan, value: unknown): unknown => {\n const ctx = {\n timeZone: raw.site.timezone, gmtOffset: raw.site.gmt_offset,\n dropped: () => { report.acf_outside_choices[k] = (report.acf_outside_choices[k] ?? 0) + 1 },\n unzoned: () => { report.acf_datetime_unzoned++ },\n }\n return plan.def ? acfValue(plan.def, plan.kind === 'address' ? addressOf(value) : acfRows(acfScrub(value)), ctx) : acfRefs(plan, value)\n }\n const titleOf = (p: RawPost): string => {\n const t = strip(p.title)\n if (t) return t\n report.title_fallback++\n return slugOf.get(p.id) ?? `#${p.id}`\n }\n\n // ── authors ──\n addModel({\n id: 'authors', name: 'Authors', kind: 'collection', domain: 'blog', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n email: { type: 'email', label: 'Email', order: 30 },\n wp_id: { type: 'integer', label: 'WP user ID', order: 40 },\n },\n })\n for (const a of raw.authors) {\n const id = authorId(slugify(a.login))\n contents.authors![id] = pick(\n { name: strip(a.display_name), slug: slugify(a.login), email: a.email, wp_id: a.id },\n new Set(['name', 'slug', 'email', 'wp_id']),\n )\n metas.authors![id] = importMeta('published')\n }\n for (const p of raw.posts) {\n if (p.author && !contents.authors![authorId(slugify(p.author))]) {\n contents.authors![authorId(slugify(p.author))] = { name: p.author, slug: slugify(p.author) }\n metas.authors![authorId(slugify(p.author))] = importMeta('published')\n }\n }\n\n // ── taxonomies (nav_menu and post_format excluded; post_format → select field) ──\n const taxonomies = [...new Set(raw.terms.map((t) => t.taxonomy))].filter(\n (t) => t !== 'nav_menu' && t !== 'post_format' && !LANGUAGE_TAXONOMIES.has(t),\n )\n for (const tax of taxonomies) {\n const mid = taxModelId(tax)\n addModel({\n id: mid, name: mid, kind: 'collection', domain: 'blog', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n description: { type: 'text', label: 'Description', order: 30 },\n parent: { type: 'relation', model: mid, label: 'Parent', order: 40 },\n wp_id: { type: 'integer', label: 'WP term ID', order: 50 },\n },\n })\n for (const t of raw.terms.filter((x) => x.taxonomy === tax)) {\n const id = termId(tax, t.slug)\n contents[mid]![id] = pick(\n {\n name: strip(t.name),\n slug: addressSlug(t.slug) || `term-${t.id}`,\n description: strip(t.description),\n parent: t.parent && t.parent_resolved ? termId(tax, t.parent) : null,\n wp_id: t.id,\n },\n new Set(['name', 'slug', 'description', 'parent', 'wp_id']),\n )\n metas[mid]![id] = importMeta('published')\n }\n }\n // referenced-but-unlisted terms join the pool (marked resolved:false upstream, never dropped)\n for (const p of raw.posts) {\n for (const t of p.terms) {\n if (t.taxonomy === 'nav_menu' || t.taxonomy === 'post_format' || t.resolved) continue\n const mid = taxModelId(t.taxonomy)\n if (!models[mid]) continue\n const id = termId(t.taxonomy, t.slug)\n contents[mid]![id] ??= { name: strip(t.name), slug: addressSlug(t.slug) || `term-${hexId(`${t.taxonomy}:${t.slug}`).slice(0, 8)}` }\n metas[mid]![id] ??= importMeta('published')\n }\n }\n\n const postTypes = [...new Set(raw.posts.map((p) => p.type))].filter((t) => {\n if (SKIP_TYPES.test(t)) {\n report.skipped_types.push(t)\n return false\n }\n return true\n })\n const contentModelIds = postTypes.map(typeModelId)\n const toContent = relationOver(contentModelIds)\n\n // ── media ──\n addModel({\n id: 'media', name: 'Media', kind: 'collection', domain: 'assets', i18n: false, title_field: 'title',\n fields: {\n title: { type: 'string', required: true, label: 'Title', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n url: { type: 'url', required: true, label: 'Source URL', order: 30 },\n alt: { type: 'string', label: 'Alt text', order: 40 },\n caption: { type: 'text', label: 'Caption', order: 50 },\n description: { type: 'text', label: 'Description', order: 60 },\n mime: { type: 'string', label: 'MIME type', order: 70 },\n width: { type: 'integer', label: 'Width', order: 80 },\n height: { type: 'integer', label: 'Height', order: 90 },\n file: { type: 'string', label: 'Upload path', order: 100 },\n parent: { type: 'relation', model: toContent.model, label: 'Attached to', order: 110 },\n wp_id: { type: 'integer', label: 'WP attachment ID', order: 120 },\n uploaded_at: { type: 'datetime', label: 'Uploaded at', order: 130 },\n },\n })\n const mediaSlugs = new Set<string>()\n for (const a of raw.attachments) {\n const id = hexId(`media:${a.id}`)\n let slug = addressSlug(a.slug) || `media-${a.id}`\n if (mediaSlugs.has(slug)) slug = `${slug}-${a.id}`\n mediaSlugs.add(slug)\n const target = a.parent ? postEntry.get(a.parent) : undefined\n if (a.parent && !target) report.dropped_relations++\n const parent = target ? toContent.ref(target) : null\n const im = (a.image_meta ?? null) as { width?: number; height?: number } | null\n contents.media![id] = pick(\n {\n title: strip(a.title) || slug,\n slug,\n url: a.url,\n alt: strip(a.alt),\n caption: strip(a.caption),\n description: strip(a.description),\n mime: a.mime,\n width: im?.width,\n height: im?.height,\n file: a.file,\n parent,\n wp_id: a.id,\n uploaded_at: a.date,\n },\n new Set(['title', 'slug', 'url', 'alt', 'caption', 'description', 'mime', 'width', 'height', 'file', 'parent', 'wp_id', 'uploaded_at']),\n )\n metas.media![id] = importMeta('published')\n }\n\n // ── post types (post, page, CPTs) ──\n for (const type of postTypes) {\n const typeItems = raw.posts.filter((p) => p.type === type)\n const mid = typeModelId(type)\n const taxes = [...new Set(typeItems.flatMap((p) => p.terms.map((t) => t.taxonomy)))].filter((t) => models[taxModelId(t)])\n const { fields, order } = coreFields({\n excerpt: typeItems.some((p) => p.excerpt),\n body: typeItems.some((p) => p.content),\n date: typeItems.some((p) => p.date),\n author: typeItems.some((p) => p.author),\n taxes,\n cover: typeItems.some((p) => p.meta._thumbnail_id),\n })\n let o = order\n fields.wp_id = { type: 'integer', required: true, unique: true, label: 'WP post ID', order: (o += 10) }\n fields.modified_at = { type: 'datetime', label: 'Modified at', order: (o += 10) }\n fields.link = { type: 'url', label: 'Original permalink', order: (o += 10) }\n const parentModels = [...new Set(typeItems.flatMap((p) => {\n const parent = p.parent ? postEntry.get(p.parent) : undefined\n return parent ? [parent.model] : []\n }))].toSorted()\n if (typeItems.some((p) => p.parent)) fields.parent = {\n type: 'relation',\n model: parentModels.length > 1 ? parentModels : (parentModels[0] ?? mid),\n label: 'Parent', order: (o += 10),\n }\n if (typeItems.some((p) => p.menu_order)) fields.menu_order = { type: 'integer', label: 'Menu order', order: (o += 10) }\n if (typeItems.some((p) => p.sticky)) fields.sticky = { type: 'boolean', label: 'Sticky', order: (o += 10) }\n if (typeItems.some((p) => typeof p.meta._wp_page_template === 'string' && p.meta._wp_page_template !== 'default'))\n fields.template = { type: 'string', label: 'Page template', order: (o += 10) }\n const formats = [\n ...new Set(\n typeItems.flatMap((p) =>\n p.terms.filter((t) => t.taxonomy === 'post_format').map((t) => t.slug.replace(/^post-format-/, '')),\n ),\n ),\n ].toSorted()\n if (formats.length) fields.format = { type: 'select', options: formats, label: 'Post format', order: (o += 10) }\n if (typeItems.some((p) => p.status === 'private' || p.password))\n fields.visibility = { type: 'select', options: ['public', 'private', 'password'], label: 'Visibility', order: (o += 10) }\n if (typeItems.some((p) => p.comment_status))\n fields.comments_open = { type: 'boolean', label: 'Comments open', order: (o += 10) }\n for (const p of typeItems) {\n for (const [k, v] of Object.entries(p.meta)) {\n if (k.startsWith('_') || fields[k] || PLUGIN_META.test(k) || k === 'enclosure') continue\n const t = byValue(v)\n if (t && t !== 'object') {\n fields[k] = { type: t as FieldDef['type'], label: k, order: (o += 10) }\n report.meta_fields[k] = t\n }\n }\n }\n // ACF: one field per ACF field, typed by the mapping table (acf.ts); references resolved to store entries.\n const acfFields = acfPlan(typeItems, (k) => !!fields[k])\n for (const [k, plan] of acfFields) {\n const def = plan.def ?? { type: plan.multiple ? 'relations' : 'relation', model: plan.models.size > 1 ? [...plan.models].toSorted() : [...plan.models][0]! } as FieldDef\n fields[k] = { ...def, ...(def.label ? {} : { label: k }), description: def.description ?? 'ACF', order: (o += 10) }\n report.acf_fields[k] = plan.def ? plan.def.type : `${def.type}:${[...plan.models].toSorted().join('|')}`\n }\n // The locales this type actually has content in. A partially-translated\n // site — pages in one language, posts in three — used to fail validation on\n // every untranslated entry, because parity was checked against the whole\n // project list. Declaring the real coverage says so once, in the model.\n //\n // The default locale is always in: it is the site's source of truth, and a\n // post that carries no language tag belongs to it (`postLocale`), so its\n // absence here would be the importer's uncertainty, not a fact about the\n // site. Full coverage writes nothing — absent already means \"all\", and a\n // redundant list would then have to be maintained as locales are added.\n const covered = locales.filter(l => l === locale || typeItems.some((p) => postLocale(p) === l))\n addModel({\n id: mid,\n name: type === 'post' ? 'Posts' : type === 'page' ? 'Pages' : mid,\n kind: 'collection',\n domain: domainOf(type),\n i18n: multilingual,\n ...(multilingual && covered.length < locales.length ? { locales: covered } : {}),\n title_field: 'title',\n fields,\n })\n for (const p of typeItems) {\n const id = postEntry.get(p.id)!.ref\n const loc = postLocale(p)\n const contentBucket = multilingual ? ((localeContents[mid] ??= {})[loc] ??= {}) : contents[mid]!\n const metaBucket = multilingual ? ((localeMetas[mid] ??= {})[loc] ??= {}) : metas[mid]!\n const e: Entry = { title: titleOf(p), slug: slugOf.get(p.id), wp_id: p.id }\n if (fields.excerpt) e.excerpt = strip(p.excerpt)\n if (fields.body) e.body = p.content // Gutenberg comments and shortcodes verbatim (known gap)\n if (fields.published_at && p.date) e.published_at = p.date\n if (p.modified) e.modified_at = p.modified\n if (p.link) e.link = p.link\n if (fields.author && p.author) e.author = authorId(slugify(p.author))\n for (const t of taxes) {\n e[taxModelId(t)] = p.terms\n .filter((x) => x.taxonomy === t && contents[taxModelId(t)]![termId(t, x.slug)])\n .map((x) => termId(t, x.slug))\n }\n if (fields.cover && p.meta._thumbnail_id) {\n const m = mediaRef(Number(p.meta._thumbnail_id))\n if (m) e.cover = m\n else report.dropped_relations++\n }\n if (fields.parent && p.parent) {\n const pe = postEntry.get(p.parent)\n if (pe) e.parent = parentModels.length > 1 ? pe : pe.ref\n else report.dropped_relations++\n }\n if (fields.menu_order && p.menu_order) e.menu_order = p.menu_order\n if (fields.sticky) e.sticky = p.sticky ?? false\n if (fields.template && typeof p.meta._wp_page_template === 'string' && p.meta._wp_page_template !== 'default')\n e.template = p.meta._wp_page_template\n if (fields.format) {\n const f = p.terms.find((t) => t.taxonomy === 'post_format')\n if (f) e.format = f.slug.replace(/^post-format-/, '')\n }\n if (fields.visibility) e.visibility = p.password ? 'password' : p.status === 'private' ? 'private' : 'public'\n if (fields.comments_open) e.comments_open = p.comment_status === 'open'\n for (const k of Object.keys(fields)) if (k in p.meta && !(k in e) && !k.startsWith('_')) e[k] = p.meta[k]\n for (const [k, acf] of Object.entries(p.acf ?? {})) {\n const plan = acfFields.get(k)\n if (!plan || k in e) continue\n const v = acfEntryValue(k, plan, acf.value)\n if (v !== undefined) e[k] = v\n }\n contentBucket[id] = e\n metaBucket[id] = mapStatus(p)\n }\n }\n\n // ── menus ──\n const menus = raw.menus ?? []\n if (menus.length) {\n addModel({\n id: 'menus', name: 'Menus', kind: 'collection', domain: 'site', i18n: false, title_field: 'name',\n fields: {\n name: { type: 'string', required: true, label: 'Name', order: 10 },\n slug: { type: 'slug', required: true, unique: true, label: 'Slug', order: 20 },\n items: { type: 'relations', model: 'menu-items', label: 'Items', order: 30 },\n wp_id: { type: 'integer', label: 'WP term ID', order: 40 },\n // Only when the source said where its menus are shown: stores from sources that do not know stay as they were.\n ...(menus.some((m) => m.locations?.length) ? { locations: { type: 'array', items: 'string', label: 'Locations', order: 50 } as FieldDef } : {}),\n },\n })\n const toTarget = relationOver([...contentModelIds, ...taxonomies.map(taxModelId)])\n addModel({\n id: 'menu-items', name: 'Menu items', kind: 'collection', domain: 'site', i18n: false, title_field: 'title',\n fields: {\n title: { type: 'string', required: true, label: 'Label', order: 10 },\n menu: { type: 'relation', model: 'menus', required: true, label: 'Menu', order: 20 },\n order: { type: 'integer', label: 'Order', order: 30 },\n parent: { type: 'relation', model: 'menu-items', label: 'Parent item', order: 40 },\n type: { type: 'select', options: ['custom', 'post_type', 'taxonomy', 'post_type_archive'], label: 'Type', order: 50 },\n url: { type: 'url', label: 'URL', order: 60 },\n target: { type: 'relation', model: toTarget.model, label: 'Target', order: 70 },\n open_in_new_tab: { type: 'boolean', label: 'Open in new tab', order: 80 },\n classes: { type: 'array', items: 'string', label: 'CSS classes', order: 90 },\n description: { type: 'text', label: 'Description', order: 100 },\n wp_id: { type: 'integer', label: 'WP post ID', order: 110 },\n },\n })\n const itemRef = (id: number): string => hexId(`menu-items:${id}`)\n for (const m of menus) {\n const mid = hexId(`menus:${m.slug}`)\n contents.menus![mid] = {\n name: strip(m.name),\n slug: addressSlug(m.slug) || `menu-${m.id}`,\n items: m.items.map((i) => itemRef(i.id)),\n // An inline navigation has no WordPress record (a negative placeholder): none is claimed.\n ...(m.id !== null && m.id > 0 ? { wp_id: m.id } : {}),\n ...(m.locations?.length ? { locations: m.locations } : {}),\n }\n metas.menus![mid] = importMeta('published')\n for (const i of m.items) {\n const e: Entry = {\n title: strip(i.title) || i.url || `item-${i.id}`,\n menu: mid,\n order: i.order,\n type: i.target.kind === 'url' ? 'custom' : i.target.kind === 'post' ? 'post_type' : i.target.kind === 'term' ? 'taxonomy' : i.target.kind === 'archive' ? 'post_type_archive' : 'custom',\n // A block navigation's items have no WordPress id (negative placeholders): none is claimed.\n ...(i.id > 0 ? { wp_id: i.id } : {}),\n open_in_new_tab: i.target_attr === '_blank',\n }\n if (i.parent && !i.parent_unresolved) e.parent = itemRef(i.parent)\n // An archive has no entry to point at: its address is all the store can keep, and the site serves it only when the type has one.\n if ((i.target.kind === 'url' || i.target.kind === 'archive') && i.url) e.url = i.url\n if (i.target.kind === 'post' && i.target.resolved && i.target.id != null) {\n const pe = postEntry.get(i.target.id)\n if (pe) e.target = toTarget.ref(pe)\n else report.dropped_relations++\n }\n if (i.target.kind === 'term' && i.target.resolved && i.target.slug && models[taxModelId(i.target.taxonomy)])\n e.target = toTarget.ref({ model: taxModelId(i.target.taxonomy), ref: termId(i.target.taxonomy, i.target.slug) })\n if (i.classes?.length) e.classes = i.classes\n if (i.description) e.description = strip(i.description)\n contents['menu-items']![itemRef(i.id)] = e\n metas['menu-items']![itemRef(i.id)] = importMeta(i.status === 'publish' ? 'published' : 'draft')\n }\n }\n }\n\n // ── comments (frozen archive collection; the live-service path is CommentsExport) ──\n const comments = raw.comments ?? []\n if (comments.length) {\n addModel({\n id: 'comments', name: 'Comments', kind: 'collection', domain: 'blog', i18n: false, title_field: 'author',\n fields: {\n author: { type: 'string', required: true, label: 'Author', order: 10 },\n email: { type: 'email', label: 'Email', order: 20 },\n url: { type: 'url', label: 'Website', order: 30 },\n body: { type: 'richtext', label: 'Body', order: 40 },\n published_at: { type: 'datetime', label: 'Date', order: 50 },\n post: { type: 'relation', model: toContent.model, required: true, label: 'Post', order: 60 },\n parent: { type: 'relation', model: 'comments', label: 'In reply to', order: 70 },\n type: { type: 'string', label: 'Type', order: 80 },\n user: { type: 'relation', model: 'authors', label: 'User', order: 90 },\n wp_id: { type: 'integer', label: 'WP comment ID', order: 100 },\n },\n })\n const cRef = (id: number): string => hexId(`comments:${id}`)\n const userById = new Map(raw.authors.filter((a) => a.id != null).map((a) => [a.id, authorId(slugify(a.login))]))\n for (const c of comments) {\n const post = postEntry.get(c.post)\n if (!post) {\n report.dropped_relations++\n continue\n }\n contents.comments![cRef(c.id)] = pick(\n {\n author: strip(c.author) || 'anonymous',\n email: c.email,\n url: c.url,\n body: c.content,\n published_at: c.date,\n post: toContent.ref(post),\n parent: c.parent && c.parent_resolved ? cRef(c.parent) : null,\n type: c.type,\n user: c.user_id ? userById.get(c.user_id) : null,\n wp_id: c.id,\n },\n new Set(['author', 'email', 'url', 'body', 'published_at', 'post', 'parent', 'type', 'user', 'wp_id']),\n )\n metas.comments![cRef(c.id)] = importMeta(\n c.approved === '1' ? 'published' : c.approved === 'spam' || c.approved === 'trash' ? 'archived' : 'in_review',\n )\n }\n }\n\n // ── site singleton + vocabulary ──\n const siteFields: Record<string, FieldDef> = {\n title: { type: 'string', required: true, label: 'Site title', order: 10 },\n tagline: { type: 'string', label: 'Tagline', order: 20 },\n url: { type: 'url', label: 'URL', order: 30 },\n language: { type: 'string', label: 'Language', order: 40 },\n }\n // ACF Options Pages (Bridge): site-wide fields that belong to no post, typed like a post's ACF. A name that is a\n // core field or sits on more than one page takes the page's slug as a prefix (ACF's default `acf-options-` left\n // off), so no page overwrites another. A name still taken after that gets a counter and a line in the report.\n const optionPages = raw.acf_options ?? []\n const pagesOf = new Map<string, number>()\n for (const page of optionPages) for (const k of Object.keys(page.fields)) pagesOf.set(k, (pagesOf.get(k) ?? 0) + 1)\n const optionFields: Record<string, RawAcfValue> = {}\n const claim = (page: RawAcfOptionsPage, k: string, want: string) => {\n let name = want\n for (let n = 2; siteFields[name] || name in optionFields; n++) name = `${want}_${n}`\n if (name !== want) report.acf_options_renamed[name] = `${page.slug}.${k}`\n optionFields[name] = page.fields[k]!\n }\n const prefixed: [RawAcfOptionsPage, string][] = []\n for (const page of optionPages) {\n for (const k of Object.keys(page.fields)) {\n if (siteFields[k] || pagesOf.get(k)! > 1) prefixed.push([page, k])\n else claim(page, k, k)\n }\n }\n // Plain names first: a field literally named `footer_phone` keeps it; the prefixed one takes the counter.\n for (const [page, k] of prefixed) claim(page, k, `${page.slug.replace(/^acf-options-(?=.)/, '').replace(/-/g, '_')}_${k}`)\n const optionPlan = acfPlan([{ acf: optionFields } as RawPost], (k) => !!siteFields[k])\n let so = 40\n for (const [k, plan] of optionPlan) {\n const def = plan.def ?? { type: plan.multiple ? 'relations' : 'relation', model: plan.models.size > 1 ? [...plan.models].toSorted() : [...plan.models][0]! } as FieldDef\n siteFields[k] = { ...def, ...(def.label ? {} : { label: k }), description: def.description ?? 'ACF', order: (so += 10) }\n report.acf_options[k] = plan.def ? plan.def.type : `${def.type}:${[...plan.models].toSorted().join('|')}`\n }\n addModel({ id: 'site', name: 'Site', kind: 'singleton', domain: 'site', i18n: false, title_field: 'title', fields: siteFields })\n siteEntry = pick(\n { title: strip(raw.site.title), tagline: raw.site.description, url: raw.site.url, language: raw.site.language },\n new Set(['title', 'tagline', 'url', 'language']),\n )\n for (const [k, plan] of optionPlan) {\n const v = acfEntryValue(k, plan, optionFields[k]!.value)\n if (v !== undefined) siteEntry[k] = v\n }\n siteMeta = importMeta('published')\n report.site_title_missing = !siteEntry.title\n const vocabTerms: Record<string, Record<string, string>> = {}\n for (const m of menus) {\n for (const i of m.items) {\n const k = slugify(strip(i.title))\n if (k && !vocabTerms[k]) vocabTerms[k] = { [locale]: strip(i.title) }\n }\n }\n\n // ── file map (canonical serialization; PATH_PATTERNS layout) ──\n const files: Record<string, string> = {}\n const domains = [...new Set(Object.values(models).map((m) => m.domain))].toSorted()\n for (const m of Object.values(models)) {\n files[`.contentrain/models/${m.id}.json`] = canon(m)\n if (m.i18n) {\n // One content + meta file per locale; an entry id recurs across the\n // locales it has a translation in.\n const perLocale = localeContents[m.id] ?? {}\n const ids = new Set<string>()\n for (const loc of Object.keys(perLocale).toSorted()) {\n files[`.contentrain/content/${m.domain}/${m.id}/${loc}.json`] = canon(perLocale[loc])\n files[`.contentrain/meta/${m.id}/${loc}.json`] = canon(localeMetas[m.id]?.[loc] ?? {})\n for (const id of Object.keys(perLocale[loc]!)) ids.add(id)\n }\n report.models[m.id] = { kind: m.kind, domain: m.domain, fields: Object.keys(m.fields ?? {}).length, entries: ids.size }\n continue\n }\n const content = m.kind === 'singleton' ? siteEntry : contents[m.id]!\n const meta = m.kind === 'singleton' ? siteMeta : metas[m.id]!\n files[`.contentrain/content/${m.domain}/${m.id}/data.json`] = canon(content)\n files[`.contentrain/meta/${m.id}/${locale}.json`] = canon(meta)\n report.models[m.id] = {\n kind: m.kind,\n domain: m.domain,\n fields: Object.keys(m.fields ?? {}).length,\n entries: m.kind === 'singleton' ? 1 : Object.keys(contents[m.id]!).length,\n }\n }\n files['.contentrain/config.json'] = canon({\n version: 1,\n stack: 'astro',\n platform: 'web',\n workflow: 'review',\n locales: { default: locale, supported: locales },\n domains,\n })\n files['.contentrain/vocabulary.json'] = canon({ version: 1, terms: vocabTerms })\n\n const entrySourceMap: EntrySourceMap = {}\n for (const [wpId, ref] of postEntry) {\n entrySourceMap[String(wpId)] = { model_id: ref.model, entry_id: ref.ref, locale: postLocale(postById.get(wpId)!) }\n }\n\n files['import-report.json'] = canon(report)\n return { files, entry_source_map: entrySourceMap, report }\n}\n","// CommentsExport builder — the bridge from a migrated static site to a live\n// comments service. Everything the receiving side needs travels here: the\n// entry addresses (WordPress ids mean nothing after migration), the verbatim\n// comments, and which threads were closed at the source.\n\nimport type { CommentsExport, EntrySourceMap, HandoffComments, RawComment, RawIR } from '@contentrain/types'\nimport { COMMENTS_EXPORT_FORMAT, MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\n\n/**\n * The comments that may leave the source site (see `CommentsExport.comments`). An allowlist, so it\n * fails closed: a comment travels only when its entry is in this RawIR and public, and its status is\n * approved (`'1'`, or none) or pending (`'0'`). Everything else is counted in `excluded`: spam, trash,\n * WordPress's `post-trashed`, a plugin's own status, a post this RawIR does not hold.\n */\nexport function selectComments(raw: RawIR): { comments: RawComment[]; excluded: NonNullable<CommentsExport['excluded']> } {\n const posts = new Map(raw.posts.map((p) => [p.id, p]))\n const excluded: NonNullable<CommentsExport['excluded']> = {}\n const count = (key: keyof typeof excluded) => { excluded[key] = (excluded[key] ?? 0) + 1 }\n const comments: RawComment[] = []\n for (const c of raw.comments ?? []) {\n const post = posts.get(c.post)\n if (!post) { count('unknown_entry'); continue }\n if (post.status !== 'publish' || (post.password !== null && post.password !== undefined && post.password !== '')) { count('non_public_entry'); continue }\n const status = c.approved ?? '1'\n if (status === '1' || status === '0') { comments.push(c); continue }\n count(status === 'spam' ? 'spam' : status === 'trash' ? 'trash' : 'other_status')\n }\n return { comments, excluded }\n}\n\nexport function buildCommentsExport(raw: RawIR, entries: EntrySourceMap, opts?: { generated_at?: string }): CommentsExport {\n const threadsClosed = raw.posts.filter((p) => p.comment_status && p.comment_status !== 'open').map((p) => p.id)\n const { comments, excluded } = selectComments(raw)\n return {\n version: MIGRATION_CONTRACT_VERSION,\n format: COMMENTS_EXPORT_FORMAT,\n source: raw.provenance,\n site_url: raw.site.url || undefined,\n generated_at: opts?.generated_at ?? new Date().toISOString(),\n entries,\n threads_closed: threadsClosed.length ? threadsClosed : undefined,\n comments,\n excluded: Object.keys(excluded).length ? excluded : undefined,\n }\n}\n\n/** Handoff summary for the export: counts + closed threads + what could not be addressed. */\nexport function summarizeComments(exp: CommentsExport): HandoffComments {\n const byStatus: Record<string, number> = {}\n const byType: Record<string, number> = {}\n const unresolved: Array<{ comment_id: number; post: number; reason: string }> = []\n for (const c of exp.comments) {\n byStatus[c.approved ?? '1'] = (byStatus[c.approved ?? '1'] ?? 0) + 1\n byType[c.type ?? 'comment'] = (byType[c.type ?? 'comment'] ?? 0) + 1\n if (!exp.entries[String(c.post)]) unresolved.push({ comment_id: c.id, post: c.post, reason: 'post has no entry mapping' })\n }\n return {\n total: exp.comments.length,\n by_status: byStatus,\n types: byType,\n export: { format: exp.format },\n threads_closed: exp.threads_closed,\n unresolved: unresolved.length ? unresolved : undefined,\n excluded: exp.excluded,\n }\n}\n","// SourceDeltaPlan (as a bridge produces it) + the repository's store → a plan\n// a person can review: every origin record placed in the store, or said to be\n// unplaceable and why.\n//\n// The bridge knows what changed at the origin and nothing about the store; the\n// store knows its entries and nothing about the origin. The EntrySourceMap\n// written at import time is the only link, so this module lives next to the\n// code that writes it. Pure over file maps, like `rawToContentrain`: no git,\n// no provider, and nothing is written — applying a plan is a governed write\n// that belongs to whoever reviews it.\n//\n// What the planner refuses to do is decide. A record the repository also\n// edited is flagged, not overwritten; a trashed record stays distinguishable\n// from a purged one; a record it cannot place says why instead of vanishing.\n\nimport type { EntryMeta, EntrySourceMap, ModelDefinition, SourceDeltaEntry, SourceDeltaPlan } from '@contentrain/types'\nimport { canon, taxModelId } from './core.js'\n\n/** A `.contentrain` store as a file map (repo-relative path → file text), with the source map it was built from. */\nexport interface DeltaStore {\n files: Record<string, string>\n entry_source_map: EntrySourceMap\n}\n\nexport interface PlanSourceDeltaInput {\n /** The origin delta, as the bridge wrote it. */\n delta: SourceDeltaPlan\n /** The repository's store, as it is now — including edits made since the import. */\n store: DeltaStore\n /** The new export the delta describes. Without it the plan has no field-level differences and no address for a created record. */\n incoming?: DeltaStore\n /**\n * Origin types that are taxonomies. Their ids are term ids, which the\n * source map (post ids) must never be consulted for: post 6 and category 6\n * are different records. Defaults to WordPress core's.\n */\n taxonomies?: string[]\n /**\n * `updated_by` values that mean \"written by an import\". Meta with any other\n * writer — or with a `source` other than `import` — is a repository edit.\n */\n importers?: string[]\n}\n\nexport const DEFAULT_TAXONOMIES = ['category', 'post_tag', 'nav_menu', 'post_format'] as const\nexport const DEFAULT_IMPORTERS = ['contentrain-bridge', '@contentrain/wp-import'] as const\n\ninterface Placed {\n model: ModelDefinition\n entry_id: string\n locale: string\n}\n\ntype Placement = Placed | { unmapped: NonNullable<SourceDeltaEntry['unmapped']> }\n\n/** A stored entry, reduced to what a comparison needs: each field's value as text, and its meta. */\ninterface StoredEntry {\n fields: Record<string, string>\n meta?: EntryMeta\n}\n\n// ─── Store reading ───\n\nconst parseJson = (text: string | undefined): unknown => {\n if (text === undefined) return undefined\n try {\n return JSON.parse(text)\n }\n catch {\n return undefined\n }\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined\n\nfunction readModel(files: Record<string, string>, id: string): ModelDefinition | undefined {\n const model = asRecord(parseJson(files[`.contentrain/models/${id}.json`]))\n return model && model.id === id ? (model as unknown as ModelDefinition) : undefined\n}\n\nfunction defaultLocale(files: Record<string, string>): string {\n const config = asRecord(parseJson(files['.contentrain/config.json']))\n const locales = asRecord(config?.locales)\n return typeof locales?.default === 'string' ? locales.default : 'en'\n}\n\n/** The model's own directory. A custom `content_path` or locale strategy is not read — the entry is reported as not found. */\nconst contentDir = (model: ModelDefinition): string | undefined =>\n model.content_path || (model.locale_strategy && model.locale_strategy !== 'file')\n ? undefined\n : `.contentrain/content/${model.domain}/${model.id}`\n\n/**\n * A markdown document's fields as raw text: each top-level frontmatter key\n * with its value lines (a list's items included), and `body`. Compared as\n * written — the store is canonical, so equal values are equal text.\n */\nfunction documentFields(text: string): Record<string, string> {\n const fields: Record<string, string> = {}\n const match = /^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/.exec(text)\n if (!match) return { body: text }\n let key: string | undefined\n for (const line of match[1]!.split('\\n')) {\n const top = /^([^\\s:#][^:]*):(.*)$/.exec(line)\n if (top) {\n key = top[1]!.trim()\n fields[key] = top[2]!.trim()\n }\n else if (key !== undefined) {\n fields[key] += `\\n${line}`\n }\n }\n fields.body = match[2]!\n return fields\n}\n\nfunction readEntry(files: Record<string, string>, at: Placed): StoredEntry | undefined {\n const { model, entry_id: id, locale } = at\n const dir = contentDir(model)\n if (!dir) return undefined\n if (model.kind === 'document') {\n const text = files[model.i18n ? `${dir}/${id}/${locale}.md` : `${dir}/${id}.md`]\n if (text === undefined) return undefined\n const meta = asRecord(parseJson(files[`.contentrain/meta/${model.id}/${id}/${locale}.json`]))\n return { fields: documentFields(text), meta: meta as EntryMeta | undefined }\n }\n if (model.kind !== 'collection') return undefined\n const entries = asRecord(parseJson(files[`${dir}/${model.i18n ? locale : 'data'}.json`]))\n const entry = asRecord(entries?.[id])\n if (!entry) return undefined\n const metas = asRecord(parseJson(files[`.contentrain/meta/${model.id}/${locale}.json`]))\n const fields = Object.fromEntries(Object.entries(entry).map(([key, value]) => [key, canon(value)]))\n return { fields, meta: asRecord(metas?.[id]) as EntryMeta | undefined }\n}\n\n/** The entry in `model` whose `wp_id` is `wpId`, for records the source map does not list (terms, media). */\nfunction findByWpId(files: Record<string, string>, model: ModelDefinition, wpId: number, locale: string): string | undefined {\n const dir = contentDir(model)\n if (!dir) return undefined\n if (model.kind === 'collection') {\n const entries = asRecord(parseJson(files[`${dir}/${model.i18n ? locale : 'data'}.json`])) ?? {}\n return Object.keys(entries).find(id => asRecord(entries[id])?.wp_id === wpId)\n }\n if (model.kind !== 'document') return undefined\n const suffix = model.i18n ? `/${locale}.md` : '.md'\n for (const [path, text] of Object.entries(files)) {\n if (!path.startsWith(`${dir}/`) || !path.endsWith(suffix)) continue\n if (documentFields(text).wp_id === String(wpId)) {\n const rest = path.slice(dir.length + 1, -suffix.length)\n if (!rest.includes('/')) return rest\n }\n }\n return undefined\n}\n\n/** Store models that can hold records of an origin type the source map does not cover. */\nfunction typeModelIds(wpType: string): string[] {\n if (wpType === 'attachment') return ['wp-media', 'media']\n return [`wp-tax-${wpType.replace(/_/g, '-')}`, taxModelId(wpType)]\n}\n\nfunction place(store: DeltaStore, wpType: string | undefined, wpId: number, taxonomies: Set<string>): Placement {\n const { files } = store\n const locale = defaultLocale(files)\n const models = wpType ? typeModelIds(wpType).map(id => readModel(files, id)).filter(model => model !== undefined) : []\n // A listed taxonomy, media, or any type the store has a model of its own for\n // is found by `wp_id` in that model. Only what is left falls to the map.\n if (wpType && (wpType === 'attachment' || taxonomies.has(wpType) || models.length)) {\n if (!models.length) return { unmapped: 'no-model-for-type' }\n for (const model of models) {\n const entryId = findByWpId(files, model, wpId, locale)\n if (entryId) return { model, entry_id: entryId, locale }\n }\n return { unmapped: 'entry-not-found' }\n }\n const ref = store.entry_source_map[String(wpId)]\n if (!ref) return { unmapped: 'not-in-source-map' }\n const model = readModel(files, ref.model_id)\n if (!model) return { unmapped: 'no-model-for-type' }\n return { model, entry_id: ref.entry_id, locale: ref.locale ?? locale }\n}\n\n// ─── Planning ───\n\nconst isPlaced = (placement: Placement): placement is Placed => 'model' in placement\n\nfunction repoEdit(meta: EntryMeta | undefined, importers: Set<string>): SourceDeltaEntry['repo_edit'] {\n if (!meta) return undefined\n if (meta.source === 'import' && importers.has(meta.updated_by)) return undefined\n return {\n updated_by: meta.updated_by,\n ...(meta.updated_at ? { updated_at: meta.updated_at } : {}),\n source: meta.source,\n }\n}\n\nfunction changedFields(before: StoredEntry, after: StoredEntry): string[] {\n const keys = new Set([...Object.keys(before.fields), ...Object.keys(after.fields)])\n return [...keys].filter(key => before.fields[key] !== after.fields[key]).toSorted()\n}\n\nconst DELETED_DETAIL = {\n trashed: 'tombstone: trashed at the origin — it can still come back',\n purged: 'tombstone: purged from the origin',\n} as const\n\nfunction planEntry(entry: SourceDeltaEntry, input: PlanSourceDeltaInput, taxonomies: Set<string>, importers: Set<string>): SourceDeltaEntry {\n const { store, incoming } = input\n const out: SourceDeltaEntry = { ...entry }\n // The bridge's detail for a deletion is the kind itself; the tombstone note below says it in full.\n const notes: string[] = entry.detail && entry.detail !== entry.deleted_kind ? [entry.detail] : []\n\n // A created record is not in the store yet; its address comes from the export that carries it.\n const target = entry.op === 'created'\n ? (incoming ? place(incoming, entry.wp_type, entry.wp_id, taxonomies) : { unmapped: 'not-in-source-map' as const })\n : place(store, entry.wp_type, entry.wp_id, taxonomies)\n\n if (!isPlaced(target)) {\n out.unmapped = target.unmapped\n if (entry.op === 'created' && !incoming) notes.push('no incoming export to place it')\n if (entry.op === 'deleted' && entry.deleted_kind) notes.push(DELETED_DETAIL[entry.deleted_kind])\n out.detail = notes.join('; ')\n return out\n }\n\n out.model = target.model.id\n out.entry_id = target.entry_id\n out.locale = target.locale\n const stored = readEntry(store.files, target)\n\n if (entry.op === 'created') {\n if (stored) notes.push('the store already has an entry at this address')\n }\n else if (!stored) {\n out.unmapped = 'entry-not-found'\n }\n\n if (entry.op === 'deleted' && entry.deleted_kind) notes.push(DELETED_DETAIL[entry.deleted_kind])\n\n if ((entry.op === 'updated' || entry.op === 'moved') && stored) {\n const after = incoming ? place(incoming, entry.wp_type, entry.wp_id, taxonomies) : undefined\n const next = after && isPlaced(after) ? readEntry(incoming!.files, after) : undefined\n if (next) {\n out.fields_changed = changedFields(stored, next)\n if (isPlaced(after!) && after.entry_id !== target.entry_id) out.entry_id_after = after.entry_id\n }\n else {\n notes.push(incoming ? 'not in the incoming export' : 'no incoming export to compare with')\n }\n }\n\n const edit = repoEdit(stored?.meta, importers)\n if (edit) {\n out.conflict = true\n out.repo_edit = edit\n notes.push(`also edited in the repository by ${edit.updated_by}${edit.updated_at ? ` at ${edit.updated_at}` : ''} — not overwritten`)\n }\n\n if (notes.length) out.detail = notes.join('; ')\n return out\n}\n\n/**\n * Place a bridge's source delta in the repository's store.\n *\n * Every entry keeps the bridge's facts (op, ids, fingerprints, paths,\n * `deleted_kind`) and gains its store address — or `unmapped` with the reason.\n * `updated` and `moved` gain `fields_changed` against the incoming export; a\n * record the repository also edited gets `conflict: true` and `repo_edit`;\n * every `moved` whose address changed adds a 301 to `redirects`.\n *\n * Nothing is written and nothing is decided: a conflict is reported for a\n * person to resolve, and applying the plan is a separate, governed step.\n */\nexport function planSourceDelta(input: PlanSourceDeltaInput): SourceDeltaPlan {\n const taxonomies = new Set<string>(input.taxonomies ?? DEFAULT_TAXONOMIES)\n const importers = new Set<string>(input.importers ?? DEFAULT_IMPORTERS)\n const { delta } = input\n const entries = delta.entries.map(entry => planEntry(entry, input, taxonomies, importers))\n\n const redirects = [...(delta.redirects ?? [])]\n const seen = new Set(redirects.map(redirect => redirect.from))\n for (const entry of entries) {\n if (entry.op !== 'moved' || !entry.path_before || !entry.path_after || entry.path_before === entry.path_after) continue\n if (seen.has(entry.path_before)) continue\n seen.add(entry.path_before)\n redirects.push({ from: entry.path_before, to: entry.path_after, status: 301 })\n }\n\n const warnings = [...(delta.warnings ?? [])]\n if (!delta.deletions_detectable) warnings.push('deletions could not be determined from this cursor; the absence of a deleted entry does not mean nothing was deleted')\n if (delta.deletions_undetectable_types?.length) warnings.push(`deletions could not be determined for: ${delta.deletions_undetectable_types.join(', ')}`)\n if (!input.incoming) warnings.push('no incoming export: no field-level differences and no address for created records')\n\n return {\n ...delta,\n entries,\n ...(redirects.length ? { redirects } : {}),\n ...(warnings.length ? { warnings } : {}),\n }\n}\n\n// ─── Report ───\n\nconst address = (entry: SourceDeltaEntry): string =>\n entry.model && entry.entry_id ? `${entry.model}/${entry.entry_id}${entry.entry_id_after ? ` → ${entry.entry_id_after}` : ''}` : `unmapped (${entry.unmapped})`\n\n/** The plan as text, for a dry run: one line per record, then conflicts, unmapped records, redirects and warnings. */\nexport function formatSourceDeltaReport(plan: SourceDeltaPlan): string {\n const counts = new Map<string, number>()\n for (const entry of plan.entries) counts.set(entry.op, (counts.get(entry.op) ?? 0) + 1)\n const summary = [...counts].map(([op, n]) => `${n} ${op}`).join(', ') || 'no changes'\n const { cursor } = plan\n const lines = [\n `Source delta: ${plan.entries.length} records (${summary})`,\n `Cursor: ${[cursor.kind, cursor.inventory_hash ?? cursor.modified_after ?? cursor.export_id, `(${cursor.taken_at})`].filter(Boolean).join(' ')}`,\n `Deletions: ${plan.deletions_detectable ? 'detectable' : 'NOT detectable'}`,\n '',\n ]\n for (const entry of plan.entries) {\n const parts = [`${entry.op.padEnd(8)} ${entry.wp_type ?? '?'} ${entry.wp_id}`, address(entry)]\n if (entry.op === 'moved' && entry.path_before) parts.push(`${entry.path_before} → ${entry.path_after}`)\n if (entry.deleted_kind) parts.push(entry.deleted_kind)\n if (entry.fields_changed) parts.push(`fields: ${entry.fields_changed.join(', ') || 'none'}`)\n if (entry.conflict) parts.push('CONFLICT')\n lines.push(` ${parts.join(' ')}`)\n }\n const conflicts = plan.entries.filter(entry => entry.conflict)\n const unmapped = plan.entries.filter(entry => entry.unmapped)\n lines.push('', `Conflicts (${conflicts.length})${conflicts.length ? ':' : ''}`)\n for (const entry of conflicts) lines.push(` ${entry.wp_type} ${entry.wp_id} → ${address(entry)}: edited by ${entry.repo_edit?.updated_by}${entry.repo_edit?.updated_at ? ` at ${entry.repo_edit.updated_at}` : ''}`)\n lines.push(`Unmapped (${unmapped.length})${unmapped.length ? ':' : ''}`)\n for (const entry of unmapped) lines.push(` ${entry.op} ${entry.wp_type} ${entry.wp_id}: ${entry.unmapped}`)\n lines.push(`Redirects (${plan.redirects?.length ?? 0})${plan.redirects?.length ? ':' : ''}`)\n for (const redirect of plan.redirects ?? []) lines.push(` ${redirect.from} → ${redirect.to} (${redirect.status})`)\n for (const warning of plan.warnings ?? []) lines.push(`Warning: ${warning}`)\n lines.push('', 'Dry run: nothing was written. Applying a plan goes through review.')\n return `${lines.join('\\n')}\\n`\n}\n"],"mappings":"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"}