{"version":3,"file":"export-BWR6h88F.mjs","names":[],"sources":["../src/seed/export.ts"],"sourcesContent":["/**\n * Export a live database as a seed file — the inverse of `applySeed`. Used by\n * the `export-seed` CLI and by the platform's theme registration (a project\n * marked as a theme has its seed committed into its repo for copies to apply).\n */\n\nimport type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport { ContentRepository } from \"../database/repositories/content.js\";\nimport { MediaRepository } from \"../database/repositories/media.js\";\nimport { OptionsRepository } from \"../database/repositories/options.js\";\nimport { TaxonomyRepository } from \"../database/repositories/taxonomy.js\";\nimport type { Database } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { getI18nConfig, isI18nEnabled } from \"../i18n/config.js\";\nimport { SchemaRegistry } from \"../schema/registry.js\";\nimport type { FieldType } from \"../schema/types.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\nimport { slugify } from \"../utils/slugify.js\";\nimport type {\n\tSeedFile,\n\tSeedCollection,\n\tSeedField,\n\tSeedTaxonomy,\n\tSeedTaxonomyTerm,\n\tSeedMenu,\n\tSeedMenuItem,\n\tSeedWidgetArea,\n\tSeedWidget,\n\tSeedContentEntry,\n\tSeedByline,\n\tSeedBylineCredit,\n} from \"./types.js\";\n\nconst SETTINGS_PREFIX = \"site:\";\n\n/**\n * Export database to seed file format\n */\nexport async function exportSeed(db: Kysely<Database>, withContent?: string): Promise<SeedFile> {\n\tconst seed: SeedFile = {\n\t\t$schema: \"https://emdashcms.com/seed.schema.json\",\n\t\tversion: \"1\",\n\t\tmeta: {\n\t\t\tname: \"Exported Seed\",\n\t\t\tdescription: \"Exported from existing EmDash database\",\n\t\t},\n\t};\n\n\t// 1. Export settings\n\tseed.settings = await exportSettings(db);\n\n\t// 2. Export collections and fields\n\tseed.collections = await exportCollections(db);\n\n\t// Decide locale-awareness from the data. The runtime sets the i18n config via\n\t// middleware, but the CLI never does, so `isI18nEnabled()` is always false\n\t// under `emdash export-seed` (#1330). Detecting multiple locales in the data\n\t// keeps the export locale-aware without the runtime flag.\n\tconst { i18nEnabled, defaultLocale } = await detectLocaleInfo(db, seed.collections);\n\n\t// Self-describe the default locale so a non-`en` single-locale project\n\t// survives the round-trip: `emdash seed` runs outside the runtime and would\n\t// otherwise backfill omitted locales as `en` (#1421).\n\tif (defaultLocale) seed.defaultLocale = defaultLocale;\n\n\t// 3. Export taxonomy definitions and terms\n\tseed.taxonomies = await exportTaxonomies(db, i18nEnabled);\n\n\t// 4. Export menus\n\tseed.menus = await exportMenus(db, i18nEnabled);\n\n\t// 5. Export widget areas\n\tseed.widgetAreas = await exportWidgetAreas(db);\n\n\t// 6. Export byline profiles. The returned map (translation_group -> seed-local\n\t// id) lets content credits below reference the same ids the root list emits.\n\tconst { bylines, groupToSeedId } = await exportBylines(db);\n\tif (bylines.length > 0) {\n\t\tseed.bylines = bylines;\n\t}\n\n\t// 7. Export content (if requested)\n\tif (withContent !== undefined) {\n\t\t// Treat \"all\" as a synonym for the bare flag and \"true\". The args help\n\t\t// text documents `all` as a valid value, but without this the literal\n\t\t// string is read as a collection name and matches no collection (#1329).\n\t\tconst includeAll = withContent === \"\" || withContent === \"true\" || withContent === \"all\";\n\t\tconst collections = includeAll\n\t\t\t? null // all collections\n\t\t\t: withContent\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((s) => s.trim())\n\t\t\t\t\t.filter(Boolean);\n\n\t\tseed.content = await exportContent(\n\t\t\tdb,\n\t\t\tseed.collections || [],\n\t\t\tcollections,\n\t\t\tgroupToSeedId,\n\t\t\ti18nEnabled,\n\t\t);\n\t}\n\n\treturn seed;\n}\n\n/**\n * Export byline profiles as root-level `bylines[]`.\n *\n * `SeedByline` has no locale axis, so locale siblings of the same byline\n * (sharing a `translation_group`) collapse to a single profile. The returned\n * `groupToSeedId` map keys on `translation_group` — the value stored in\n * `_emdash_content_bylines.byline_id` — so content credits can resolve to the\n * emitted seed id.\n */\nasync function exportBylines(\n\tdb: Kysely<Database>,\n): Promise<{ bylines: SeedByline[]; groupToSeedId: Map<string, string> }> {\n\tconst bylineRepo = new BylineRepository(db);\n\tconst bylines: SeedByline[] = [];\n\tconst groupToSeedId = new Map<string, string>();\n\tconst usedSeedIds = new Set<string>();\n\n\tlet cursor: string | undefined;\n\tdo {\n\t\tconst result = await bylineRepo.findMany({ limit: 100, cursor });\n\t\tfor (const byline of result.items) {\n\t\t\tconst group = byline.translationGroup ?? byline.id;\n\t\t\t// One seed entry per translation group; first row seen wins.\n\t\t\tif (groupToSeedId.has(group)) continue;\n\n\t\t\tlet seedId = `byline:${byline.slug}`;\n\t\t\t// Disambiguate the rare case of two distinct groups sharing a slug\n\t\t\t// (slug is unique per-locale, not globally) so seed ids stay unique.\n\t\t\tif (usedSeedIds.has(seedId)) seedId = `byline:${byline.slug}:${group}`;\n\t\t\tusedSeedIds.add(seedId);\n\t\t\tgroupToSeedId.set(group, seedId);\n\n\t\t\tbylines.push({\n\t\t\t\tid: seedId,\n\t\t\t\tslug: byline.slug,\n\t\t\t\tdisplayName: byline.displayName,\n\t\t\t\tbio: byline.bio || undefined,\n\t\t\t\twebsiteUrl: byline.websiteUrl || undefined,\n\t\t\t\tisGuest: byline.isGuest || undefined,\n\t\t\t});\n\t\t}\n\t\tcursor = result.nextCursor;\n\t} while (cursor);\n\n\treturn { bylines, groupToSeedId };\n}\n\n/**\n * Determine locale-awareness and the data's default locale for the export.\n *\n * The runtime initializes the i18n config in middleware, but the CLI never does,\n * so `isI18nEnabled()` is always false under `emdash export-seed` (#1330). When\n * the flag is unset, fall back to the data: a project is multi-locale when its\n * i18n-aware tables hold rows in more than one distinct locale. `locale` is\n * NOT NULL (defaulting to the site's default locale), so a per-row presence\n * check is not enough — only the *count* of distinct locales distinguishes a\n * genuinely single-locale project from a multi-locale one. This keeps\n * single-locale exports on bare ids and gives multi-locale exports the\n * per-locale suffix they need to avoid duplicate seed ids.\n *\n * `defaultLocale` self-describes the single-locale case so a non-`en` default\n * survives the round-trip (#1421). When more than one locale is present every\n * row already carries its own `locale`, so no fallback is needed and we leave it\n * undefined rather than guess which locale is the \"default\" without the runtime\n * config.\n */\nasync function detectLocaleInfo(\n\tdb: Kysely<Database>,\n\tcollections: SeedCollection[],\n): Promise<{ i18nEnabled: boolean; defaultLocale: string | undefined }> {\n\tconst config = getI18nConfig();\n\tif (isI18nEnabled() && config) {\n\t\treturn { i18nEnabled: true, defaultLocale: config.defaultLocale };\n\t}\n\n\tconst locales = new Set<string>();\n\tconst collectDistinctLocales = async (tableRef: ReturnType<typeof sql.ref>): Promise<void> => {\n\t\tconst result = await sql<{ locale: string | null }>`\n\t\t\tSELECT DISTINCT locale FROM ${tableRef}\n\t\t`.execute(db);\n\t\tfor (const row of result.rows) {\n\t\t\tif (row.locale) locales.add(row.locale);\n\t\t}\n\t};\n\n\tawait collectDistinctLocales(sql.ref(\"_emdash_taxonomy_defs\"));\n\tawait collectDistinctLocales(sql.ref(\"_emdash_menus\"));\n\n\tfor (const collection of collections) {\n\t\tvalidateIdentifier(collection.slug, \"collection slug\");\n\t\t// On D1, deleteCollection is non-atomic, so a collection row can outlive\n\t\t// its ec_* table. Skip missing tables rather than crashing the export.\n\t\ttry {\n\t\t\tawait collectDistinctLocales(sql.ref(`ec_${collection.slug}`));\n\t\t} catch (error) {\n\t\t\tif (!isMissingTableError(error)) throw error;\n\t\t}\n\t}\n\n\treturn {\n\t\ti18nEnabled: locales.size > 1,\n\t\tdefaultLocale: locales.size === 1 ? [...locales][0] : undefined,\n\t};\n}\n\n/**\n * Export site settings\n */\nasync function exportSettings(db: Kysely<Database>): Promise<SeedFile[\"settings\"]> {\n\tconst options = new OptionsRepository(db);\n\tconst allOptions = await options.getByPrefix(SETTINGS_PREFIX);\n\n\tconst settings: Record<string, unknown> = {};\n\tfor (const [key, value] of allOptions) {\n\t\tconst settingKey = key.replace(SETTINGS_PREFIX, \"\");\n\t\tsettings[settingKey] = value;\n\t}\n\n\treturn Object.keys(settings).length > 0 ? settings : undefined;\n}\n\n/**\n * Export collections and their fields\n */\nasync function exportCollections(db: Kysely<Database>): Promise<SeedCollection[]> {\n\tconst registry = new SchemaRegistry(db);\n\tconst collections = await registry.listCollections();\n\tconst result: SeedCollection[] = [];\n\n\tfor (const collection of collections) {\n\t\tconst fields = await registry.listFields(collection.id);\n\n\t\tconst seedCollection: SeedCollection = {\n\t\t\tslug: collection.slug,\n\t\t\tlabel: collection.label,\n\t\t\tlabelSingular: collection.labelSingular || undefined,\n\t\t\tdescription: collection.description || undefined,\n\t\t\ticon: collection.icon || undefined,\n\t\t\tadmin: collection.admin,\n\t\t\tsupports: collection.supports.length > 0 ? collection.supports : undefined,\n\t\t\turlPattern: collection.urlPattern || undefined,\n\t\t\troutable: collection.routable === false ? false : undefined,\n\t\t\thidden: collection.hidden || undefined,\n\t\t\tsortOrder: collection.sortOrder,\n\t\t\tfields: fields.map(\n\t\t\t\t(field): SeedField => ({\n\t\t\t\t\tslug: field.slug,\n\t\t\t\t\tlabel: field.label,\n\t\t\t\t\ttype: field.type,\n\t\t\t\t\trequired: field.required || undefined,\n\t\t\t\t\tunique: field.unique || undefined,\n\t\t\t\t\tsearchable: field.searchable || undefined,\n\t\t\t\t\tindexed: field.indexed || undefined,\n\t\t\t\t\tdefaultValue: field.defaultValue,\n\t\t\t\t\tvalidation: field.validation ? { ...field.validation } : undefined,\n\t\t\t\t\twidget: field.widget || undefined,\n\t\t\t\t\toptions: field.options || undefined,\n\t\t\t\t}),\n\t\t\t),\n\t\t};\n\n\t\tresult.push(seedCollection);\n\t}\n\n\treturn result;\n}\n\n/**\n * Export taxonomy definitions and terms\n */\nasync function exportTaxonomies(\n\tdb: Kysely<Database>,\n\ti18nEnabled: boolean,\n): Promise<SeedTaxonomy[]> {\n\t// Mirrors the content export pattern: one entry per (name, locale), stable\n\t// seed-local id, translations linked via `translationOf` to the anchor's id.\n\tconst defs = await db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.selectAll()\n\t\t.orderBy([\"name\", \"locale\"])\n\t\t.execute();\n\n\tconst result: SeedTaxonomy[] = [];\n\tconst termRepo = new TaxonomyRepository(db);\n\n\t// translation_group -> seed-local id of first def we emitted in that group.\n\tconst defGroupToSeedId = new Map<string, string>();\n\n\tfor (const def of defs) {\n\t\tconst defSeedId =\n\t\t\ti18nEnabled && def.locale ? `tax:${def.name}:${def.locale}` : `tax:${def.name}`;\n\n\t\t// Terms in this def's locale.\n\t\tconst terms = await termRepo.findByName(def.name, { locale: def.locale });\n\n\t\t// translation_group -> slug for parent resolution within this locale.\n\t\t// `parentId` stores the parent's translation_group, not a row id.\n\t\tconst groupToSlug = new Map<string, string>();\n\t\tfor (const term of terms) groupToSlug.set(term.translationGroup ?? term.id, term.slug);\n\n\t\t// translation_group -> seed id of the anchor term.\n\t\tconst termGroupToSeedId = new Map<string, string>();\n\n\t\tconst seedTerms: SeedTaxonomyTerm[] = [];\n\t\tfor (const term of terms) {\n\t\t\tconst termSeedId =\n\t\t\t\ti18nEnabled && term.locale\n\t\t\t\t\t? `term:${def.name}:${term.slug}:${term.locale}`\n\t\t\t\t\t: `term:${def.name}:${term.slug}`;\n\n\t\t\tconst seedTerm: SeedTaxonomyTerm = {\n\t\t\t\tid: termSeedId,\n\t\t\t\tslug: term.slug,\n\t\t\t\tlabel: term.label,\n\t\t\t\tdescription: typeof term.data?.description === \"string\" ? term.data.description : undefined,\n\t\t\t};\n\n\t\t\tif (term.parentId) seedTerm.parent = groupToSlug.get(term.parentId);\n\n\t\t\tif (i18nEnabled && term.locale) {\n\t\t\t\tseedTerm.locale = term.locale;\n\t\t\t\tif (term.translationGroup) {\n\t\t\t\t\tconst anchor = termGroupToSeedId.get(term.translationGroup);\n\t\t\t\t\tif (anchor) seedTerm.translationOf = anchor;\n\t\t\t\t\telse termGroupToSeedId.set(term.translationGroup, termSeedId);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tseedTerms.push(seedTerm);\n\t\t}\n\n\t\t// Anchors first so import can resolve `translationOf`.\n\t\tseedTerms.sort((a, b) => Number(!!a.translationOf) - Number(!!b.translationOf));\n\n\t\tconst taxonomy: SeedTaxonomy = {\n\t\t\tid: defSeedId,\n\t\t\tname: def.name,\n\t\t\tlabel: def.label,\n\t\t\tlabelSingular: def.label_singular || undefined,\n\t\t\thierarchical: def.hierarchical === 1,\n\t\t\tcollections: def.collections ? JSON.parse(def.collections) : [],\n\t\t};\n\n\t\tif (i18nEnabled && def.locale) {\n\t\t\ttaxonomy.locale = def.locale;\n\t\t\tif (def.translation_group) {\n\t\t\t\tconst anchor = defGroupToSeedId.get(def.translation_group);\n\t\t\t\tif (anchor) taxonomy.translationOf = anchor;\n\t\t\t\telse defGroupToSeedId.set(def.translation_group, defSeedId);\n\t\t\t}\n\t\t}\n\n\t\tif (seedTerms.length > 0) taxonomy.terms = seedTerms;\n\n\t\tresult.push(taxonomy);\n\t}\n\n\t// Anchors first at def level too.\n\tresult.sort((a, b) => Number(!!a.translationOf) - Number(!!b.translationOf));\n\n\treturn result;\n}\n\n/**\n * Export menus with their items\n */\nasync function exportMenus(db: Kysely<Database>, i18nEnabled: boolean): Promise<SeedMenu[]> {\n\tconst menus = await db\n\t\t.selectFrom(\"_emdash_menus\")\n\t\t.selectAll()\n\t\t.orderBy([\"name\", \"locale\"])\n\t\t.execute();\n\n\tconst result: SeedMenu[] = [];\n\t// translation_group -> seed-local id of the anchor menu in that group.\n\tconst groupToSeedId = new Map<string, string>();\n\t// Shared across menus: translated items reference anchor items in sibling menus.\n\tconst itemGroupToSeedId = new Map<string, string>();\n\tconst usedItemSeedIds = new Set<string>();\n\n\tfor (const menu of menus) {\n\t\tconst seedId =\n\t\t\ti18nEnabled && menu.locale ? `menu:${menu.name}:${menu.locale}` : `menu:${menu.name}`;\n\n\t\tconst items = await db\n\t\t\t.selectFrom(\"_emdash_menu_items\")\n\t\t\t.selectAll()\n\t\t\t.where(\"menu_id\", \"=\", menu.id)\n\t\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\tconst seedItems = buildMenuItemTree(items, {\n\t\t\ti18nEnabled,\n\t\t\tmenuName: menu.name,\n\t\t\tmenuLocale: menu.locale ?? null,\n\t\t\titemGroupToSeedId,\n\t\t\tusedItemSeedIds,\n\t\t});\n\n\t\tconst seedMenu: SeedMenu = {\n\t\t\tid: seedId,\n\t\t\tname: menu.name,\n\t\t\tlabel: menu.label,\n\t\t\titems: seedItems,\n\t\t};\n\n\t\tif (i18nEnabled && menu.locale) {\n\t\t\tseedMenu.locale = menu.locale;\n\t\t\tif (menu.translation_group) {\n\t\t\t\tconst anchor = groupToSeedId.get(menu.translation_group);\n\t\t\t\tif (anchor) seedMenu.translationOf = anchor;\n\t\t\t\telse groupToSeedId.set(menu.translation_group, seedId);\n\t\t\t}\n\t\t}\n\n\t\tresult.push(seedMenu);\n\t}\n\n\t// Anchors first so import can resolve `translationOf`.\n\tresult.sort((a, b) => Number(!!a.translationOf) - Number(!!b.translationOf));\n\n\treturn result;\n}\n\n/** Type guard for valid widget types */\nfunction isWidgetType(t: string): t is SeedWidget[\"type\"] {\n\treturn t === \"content\" || t === \"menu\" || t === \"component\";\n}\n\n/**\n * Build hierarchical menu item tree from flat array\n */\nfunction buildMenuItemTree(\n\titems: Array<{\n\t\tid: string;\n\t\tparent_id: string | null;\n\t\ttype: string;\n\t\tlabel: string;\n\t\tcustom_url: string | null;\n\t\treference_collection: string | null;\n\t\treference_id: string | null;\n\t\ttarget: string | null;\n\t\ttitle_attr: string | null;\n\t\tcss_classes: string | null;\n\t\tlocale?: string | null;\n\t\ttranslation_group?: string | null;\n\t}>,\n\ti18nCtx: {\n\t\ti18nEnabled: boolean;\n\t\tmenuName: string;\n\t\tmenuLocale: string | null;\n\t\t// translation_group -> seed-local id of the anchor item in that group.\n\t\titemGroupToSeedId: Map<string, string>;\n\t\tusedItemSeedIds: Set<string>;\n\t},\n): SeedMenuItem[] {\n\t// Build parent -> children map\n\tconst childMap = new Map<string | null, typeof items>();\n\n\tfor (const item of items) {\n\t\tconst parentId = item.parent_id;\n\t\tif (!childMap.has(parentId)) {\n\t\t\tchildMap.set(parentId, []);\n\t\t}\n\t\tchildMap.get(parentId)!.push(item);\n\t}\n\n\tfunction makeSeedId(item: (typeof items)[number]): string {\n\t\tconst base = slugify(item.label || \"\") || item.id;\n\t\tconst locale = i18nCtx.i18nEnabled ? (item.locale ?? i18nCtx.menuLocale) : null;\n\t\tconst candidate = locale\n\t\t\t? `item:${i18nCtx.menuName}:${base}:${locale}`\n\t\t\t: `item:${i18nCtx.menuName}:${base}`;\n\t\tif (!i18nCtx.usedItemSeedIds.has(candidate)) {\n\t\t\ti18nCtx.usedItemSeedIds.add(candidate);\n\t\t\treturn candidate;\n\t\t}\n\t\t// Collision fallback: append DB id to disambiguate duplicate labels.\n\t\tconst fallback = locale\n\t\t\t? `item:${i18nCtx.menuName}:${base}:${item.id}:${locale}`\n\t\t\t: `item:${i18nCtx.menuName}:${base}:${item.id}`;\n\t\ti18nCtx.usedItemSeedIds.add(fallback);\n\t\treturn fallback;\n\t}\n\n\t// Recursively build tree\n\tfunction buildLevel(parentId: string | null): SeedMenuItem[] {\n\t\tconst children = childMap.get(parentId) || [];\n\t\tconst result = children.map((item) => {\n\t\t\tconst seedItem: SeedMenuItem = {\n\t\t\t\ttype: item.type,\n\t\t\t\tlabel: item.label || undefined,\n\t\t\t};\n\n\t\t\tif (item.type === \"custom\") {\n\t\t\t\tseedItem.url = item.custom_url || undefined;\n\t\t\t} else {\n\t\t\t\tseedItem.ref = item.reference_id || undefined;\n\t\t\t\tseedItem.collection = item.reference_collection || undefined;\n\t\t\t}\n\n\t\t\tif (item.target === \"_blank\") {\n\t\t\t\tseedItem.target = \"_blank\";\n\t\t\t}\n\t\t\tif (item.title_attr) {\n\t\t\t\tseedItem.titleAttr = item.title_attr;\n\t\t\t}\n\t\t\tif (item.css_classes) {\n\t\t\t\tseedItem.cssClasses = item.css_classes;\n\t\t\t}\n\n\t\t\tif (i18nCtx.i18nEnabled) {\n\t\t\t\tconst itemLocale = item.locale ?? i18nCtx.menuLocale;\n\t\t\t\tconst seedId = makeSeedId(item);\n\t\t\t\tseedItem.id = seedId;\n\t\t\t\tif (itemLocale) seedItem.locale = itemLocale;\n\t\t\t\tif (item.translation_group) {\n\t\t\t\t\tconst anchor = i18nCtx.itemGroupToSeedId.get(item.translation_group);\n\t\t\t\t\tif (anchor && anchor !== seedId) seedItem.translationOf = anchor;\n\t\t\t\t\telse if (!anchor) i18nCtx.itemGroupToSeedId.set(item.translation_group, seedId);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add children\n\t\t\tconst itemChildren = buildLevel(item.id);\n\t\t\tif (itemChildren.length > 0) {\n\t\t\t\tseedItem.children = itemChildren;\n\t\t\t}\n\n\t\t\treturn seedItem;\n\t\t});\n\n\t\t// Sibling order is preserved (maps to sort_order on import). Cross-menu\n\t\t// `translationOf` already resolves because exportMenus sorts anchors first.\n\t\treturn result;\n\t}\n\n\treturn buildLevel(null);\n}\n\n/**\n * Export widget areas with their widgets\n */\nasync function exportWidgetAreas(db: Kysely<Database>): Promise<SeedWidgetArea[]> {\n\t// Get all widget areas\n\tconst areas = await db.selectFrom(\"_emdash_widget_areas\").selectAll().execute();\n\n\tconst result: SeedWidgetArea[] = [];\n\n\tfor (const area of areas) {\n\t\t// Get widgets for this area\n\t\tconst widgets = await db\n\t\t\t.selectFrom(\"_emdash_widgets\")\n\t\t\t.selectAll()\n\t\t\t.where(\"area_id\", \"=\", area.id)\n\t\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\tconst seedWidgets: SeedWidget[] = widgets\n\t\t\t.filter((w) => isWidgetType(w.type))\n\t\t\t.map((widget) => {\n\t\t\t\tconst wType: SeedWidget[\"type\"] = isWidgetType(widget.type) ? widget.type : \"content\";\n\t\t\t\tconst seedWidget: SeedWidget = {\n\t\t\t\t\ttype: wType,\n\t\t\t\t};\n\n\t\t\t\tif (widget.title) {\n\t\t\t\t\tseedWidget.title = widget.title;\n\t\t\t\t}\n\n\t\t\t\tif (widget.type === \"content\" && widget.content) {\n\t\t\t\t\tseedWidget.content = JSON.parse(widget.content);\n\t\t\t\t} else if (widget.type === \"menu\" && widget.menu_name) {\n\t\t\t\t\tseedWidget.menuName = widget.menu_name;\n\t\t\t\t} else if (widget.type === \"component\") {\n\t\t\t\t\tif (widget.component_id) {\n\t\t\t\t\t\tseedWidget.componentId = widget.component_id;\n\t\t\t\t\t}\n\t\t\t\t\tif (widget.component_props) {\n\t\t\t\t\t\tseedWidget.props = JSON.parse(widget.component_props);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn seedWidget;\n\t\t\t});\n\n\t\tresult.push({\n\t\t\tname: area.name,\n\t\t\tlabel: area.label,\n\t\t\tdescription: area.description || undefined,\n\t\t\twidgets: seedWidgets,\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Export content from collections\n */\nasync function exportContent(\n\tdb: Kysely<Database>,\n\tcollections: SeedCollection[],\n\tincludeCollections: string[] | null,\n\tbylineGroupToSeedId: Map<string, string>,\n\ti18nEnabled: boolean,\n): Promise<Record<string, SeedContentEntry[]>> {\n\tconst content: Record<string, SeedContentEntry[]> = {};\n\tconst contentRepo = new ContentRepository(db);\n\tconst taxonomyRepo = new TaxonomyRepository(db);\n\tconst mediaRepo = new MediaRepository(db);\n\n\t// Build media id -> info map for $media conversion\n\tconst mediaMap = new Map<\n\t\tstring,\n\t\t{ url: string; filename: string; alt?: string; caption?: string }\n\t>();\n\ttry {\n\t\tlet cursor: string | undefined;\n\t\tdo {\n\t\t\tconst result = await mediaRepo.findMany({\n\t\t\t\tlimit: 100,\n\t\t\t\tcursor,\n\t\t\t\tstatus: \"all\",\n\t\t\t});\n\t\t\tfor (const media of result.items) {\n\t\t\t\tmediaMap.set(media.id, {\n\t\t\t\t\turl: `/_emdash/api/media/file/${media.storageKey}`,\n\t\t\t\t\tfilename: media.filename,\n\t\t\t\t\talt: media.alt || undefined,\n\t\t\t\t\tcaption: media.caption || undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcursor = result.nextCursor;\n\t\t} while (cursor);\n\t} catch {\n\t\t// Media table might not exist or be empty\n\t}\n\n\tfor (const collection of collections) {\n\t\t// Skip if not in include list\n\t\tif (includeCollections && !includeCollections.includes(collection.slug)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst entries: SeedContentEntry[] = [];\n\t\tlet cursor: string | undefined;\n\n\t\t// When i18n is enabled, track translation_group -> seed ID so that\n\t\t// translations can reference the source entry's seed-local ID.\n\t\t// Key: EmDash translation_group ULID, Value: seed-local ID of the first entry in that group\n\t\tconst translationGroupToSeedId = new Map<string, string>();\n\n\t\t// Paginate through all entries\n\t\tdo {\n\t\t\tconst result = await contentRepo.findMany(collection.slug, {\n\t\t\t\tlimit: 100,\n\t\t\t\tcursor,\n\t\t\t});\n\n\t\t\tfor (const item of result.items) {\n\t\t\t\t// Generate seed ID from collection:slug:locale for stable references\n\t\t\t\tconst seedId = item.slug\n\t\t\t\t\t? i18nEnabled && item.locale\n\t\t\t\t\t\t? `${collection.slug}:${item.slug}:${item.locale}`\n\t\t\t\t\t\t: `${collection.slug}:${item.slug}`\n\t\t\t\t\t: item.id;\n\n\t\t\t\t// Process data fields for $media conversion\n\t\t\t\tconst processedData = processDataForExport(item.data, collection.fields, mediaMap);\n\n\t\t\t\tconst entry: SeedContentEntry = {\n\t\t\t\t\tid: seedId,\n\t\t\t\t\tslug: item.slug?.trim() ? item.slug : collection.routable === false ? undefined : item.id,\n\t\t\t\t\tstatus: item.status === \"published\" || item.status === \"draft\" ? item.status : undefined,\n\t\t\t\t\tdata: processedData,\n\t\t\t\t};\n\n\t\t\t\t// Add i18n fields when enabled\n\t\t\t\tif (i18nEnabled && item.locale) {\n\t\t\t\t\tentry.locale = item.locale;\n\n\t\t\t\t\tif (item.translationGroup) {\n\t\t\t\t\t\tconst sourceSeedId = translationGroupToSeedId.get(item.translationGroup);\n\t\t\t\t\t\tif (sourceSeedId) {\n\t\t\t\t\t\t\t// This is a translation — reference the source entry\n\t\t\t\t\t\t\tentry.translationOf = sourceSeedId;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// First entry in this translation group — track it\n\t\t\t\t\t\t\ttranslationGroupToSeedId.set(item.translationGroup, seedId);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Get taxonomy assignments\n\t\t\t\tconst taxonomies = await getTaxonomyAssignments(taxonomyRepo, collection.slug, item.id);\n\t\t\t\tif (Object.keys(taxonomies).length > 0) {\n\t\t\t\t\tentry.taxonomies = taxonomies;\n\t\t\t\t}\n\n\t\t\t\t// Get byline credits. Read the junction directly: its `byline_id`\n\t\t\t\t// stores the translation_group, which is exactly the key in\n\t\t\t\t// `bylineGroupToSeedId`. This is locale-agnostic (one row per\n\t\t\t\t// credit) and avoids the locale-sibling fan-out a hydrated read\n\t\t\t\t// would produce.\n\t\t\t\tconst bylines = await getBylineCredits(db, collection.slug, item.id, bylineGroupToSeedId);\n\t\t\t\tif (bylines.length > 0) {\n\t\t\t\t\tentry.bylines = bylines;\n\t\t\t\t}\n\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\n\t\t\tcursor = result.nextCursor;\n\t\t} while (cursor);\n\n\t\tif (i18nEnabled && entries.length > 0) {\n\t\t\t// Sort entries so source locale entries appear before their translations.\n\t\t\t// Entries without translationOf come first; entries with translationOf come after.\n\t\t\tentries.sort((a, b) => {\n\t\t\t\tif (a.translationOf && !b.translationOf) return 1;\n\t\t\t\tif (!a.translationOf && b.translationOf) return -1;\n\t\t\t\treturn 0;\n\t\t\t});\n\t\t}\n\n\t\tif (entries.length > 0) {\n\t\t\tcontent[collection.slug] = entries;\n\t\t}\n\t}\n\n\treturn content;\n}\n\n/**\n * Process content data for export, converting image fields to $media syntax\n */\nfunction processDataForExport(\n\tdata: Record<string, unknown>,\n\tfields: SeedField[],\n\tmediaMap: Map<string, { url: string; filename: string; alt?: string; caption?: string }>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\n\t// Create field type lookup\n\tconst fieldTypes = new Map<string, FieldType>();\n\tfor (const field of fields) {\n\t\tfieldTypes.set(field.slug, field.type);\n\t}\n\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst fieldType = fieldTypes.get(key);\n\n\t\tif (fieldType === \"image\" && value && typeof value === \"object\") {\n\t\t\t// Convert image field to $media syntax\n\t\t\tconst imageValue = value as { id?: string; src?: string; alt?: string };\n\t\t\tif (imageValue.id) {\n\t\t\t\tconst mediaInfo = mediaMap.get(imageValue.id);\n\t\t\t\tif (mediaInfo) {\n\t\t\t\t\tresult[key] = {\n\t\t\t\t\t\t$media: {\n\t\t\t\t\t\t\turl: mediaInfo.url,\n\t\t\t\t\t\t\tfilename: mediaInfo.filename,\n\t\t\t\t\t\t\talt: imageValue.alt || mediaInfo.alt,\n\t\t\t\t\t\t\tcaption: mediaInfo.caption,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback: keep as-is if no media info found\n\t\t\tresult[key] = value;\n\t\t} else if (fieldType === \"reference\" && typeof value === \"string\") {\n\t\t\t// Convert reference to $ref syntax (assumes same collection for now)\n\t\t\tresult[key] = `$ref:${value}`;\n\t\t} else if (Array.isArray(value)) {\n\t\t\t// Process arrays (could contain references or images)\n\t\t\tresult[key] = value.map((item) => {\n\t\t\t\tif (typeof item === \"string\" && fieldType === \"reference\") {\n\t\t\t\t\treturn `$ref:${item}`;\n\t\t\t\t}\n\t\t\t\treturn item;\n\t\t\t});\n\t\t} else {\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Get ordered byline credits for a content entry as `SeedBylineCredit[]`.\n *\n * The `_emdash_content_bylines.byline_id` column stores the credited byline's\n * `translation_group`, so it maps straight through `groupToSeedId`. Credits\n * whose group wasn't emitted in the root `bylines[]` are skipped (defensive;\n * shouldn't happen for a consistent DB).\n */\nasync function getBylineCredits(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\tgroupToSeedId: Map<string, string>,\n): Promise<SeedBylineCredit[]> {\n\tconst rows = await db\n\t\t.selectFrom(\"_emdash_content_bylines\")\n\t\t.select([\"byline_id\", \"role_label\"])\n\t\t.where(\"collection_slug\", \"=\", collection)\n\t\t.where(\"content_id\", \"=\", entryId)\n\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t.execute();\n\n\tconst credits: SeedBylineCredit[] = [];\n\tfor (const row of rows) {\n\t\tconst seedId = groupToSeedId.get(row.byline_id);\n\t\tif (!seedId) continue;\n\t\tconst credit: SeedBylineCredit = { byline: seedId };\n\t\tif (row.role_label) credit.roleLabel = row.role_label;\n\t\tcredits.push(credit);\n\t}\n\n\treturn credits;\n}\n\n/**\n * Get taxonomy term assignments for a content entry\n */\nasync function getTaxonomyAssignments(\n\ttaxonomyRepo: TaxonomyRepository,\n\tcollection: string,\n\tentryId: string,\n): Promise<Record<string, string[]>> {\n\tconst terms = await taxonomyRepo.getTermsForEntry(collection, entryId);\n\tconst result: Record<string, string[]> = {};\n\n\tfor (const term of terms) {\n\t\tif (!result[term.name]) {\n\t\t\tresult[term.name] = [];\n\t\t}\n\t\tresult[term.name].push(term.slug);\n\t}\n\n\treturn result;\n}\n"],"mappings":"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"}