@contentrain/wp-import 0.3.0 → 0.4.1

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.
package/README.md CHANGED
@@ -37,6 +37,24 @@ const commentsExport = buildCommentsExport(raw, entry_source_map)
37
37
 
38
38
  Streaming WXR parse (sax): a 100 MB export holds only its records in memory.
39
39
 
40
+ ## Multilingual sites
41
+
42
+ A post's language is read from the plugin — Polylang's `lang` (REST) or its
43
+ `language` taxonomy term (WXR), WPML's `wpml_current_locale` — and lands on
44
+ `RawPost.lang` verbatim. Translation groups become `RawIR.language_pairs`
45
+ (Polylang `translations` / `post_translations`, WPML `wpml_translations`), one
46
+ pair per group.
47
+
48
+ `rawToContentrain` turns more than one locale into an i18n store: post-type
49
+ models get `i18n: true`, content and meta are written per locale
50
+ (`content/{domain}/{model}/{locale}.json`), and every translation in a group
51
+ shares one entry id — the canonical member is the default-locale post (else
52
+ the lowest id), so `entry_source_map[wp_id]` addresses each post by that id
53
+ and its own locale. Locales are primary subtags (`tr_TR` → `tr`). Taxonomies
54
+ stay per-store; the `language` / `post_translations` bookkeeping taxonomies
55
+ never become models. `report.locales` and `report.translation_groups` say
56
+ what happened. A monolingual site is unchanged (`i18n: false`, `data.json`).
57
+
40
58
  ## REST limits and completeness
41
59
 
42
60
  `fetchRestRawIR` accepts `concurrency` (default 4), `maxPages` (optional cap per
@@ -46,3 +64,19 @@ collections and failed pages are named in `warnings`; callers must inspect
46
64
  these before claiming a complete migration. ACF field/group records and their
47
65
  cross-model parents remain in the content store; route discovery decides which
48
66
  records become public pages. Importing configuration does not execute a plugin.
67
+
68
+
69
+ ### Publication and translation identity
70
+
71
+ WordPress `future` posts become `status: published` metadata with `publish_at`,
72
+ preserving scheduled publication intent. A scheduled post without a valid date
73
+ fails import. Public consumers must filter the publication window, not status
74
+ alone; use the query generator/loader's public-build mode before deployment.
75
+ Previously imported future posts need re-importing or an explicit metadata update.
76
+
77
+ Translation groups share one entry identity across locales. Distinct groups
78
+ with the same canonical slug receive distinct deterministic identities; existing
79
+ non-colliding identities are unchanged. Rebuild the entry map and comments export
80
+ from the same corrected import. Locale normalization currently uses primary
81
+ language codes: a group whose regional translations collapse to the same locale
82
+ is rejected rather than silently overwritten.
package/dist/index.d.mts CHANGED
@@ -66,6 +66,10 @@ interface ImportReport {
66
66
  fields: number;
67
67
  entries: number;
68
68
  }>;
69
+ /** Default first, then every other language seen on a post. One entry on a monolingual site. */
70
+ locales: string[];
71
+ /** Translation groups that were folded into one entry id across locales. */
72
+ translation_groups: number;
69
73
  }
70
74
  interface ContentrainResult {
71
75
  files: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/wxr.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/php-unserialize.ts","../src/core.ts"],"mappings":";;;;UA0BiB,QAAA;EACf,UAAA;IAAc,QAAA;IAAkB,OAAA;IAAiB,MAAA;IAAgB,IAAA;EAAA;EACjE,UAAA;EACA,gBAAA;EACA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,cAAA;EACf,GAAA,EAAK,KAAA;EACL,KAAA,EAAO,QAAA;AAAA;AAAA,iBAiBa,QAAA,CAAS,KAAA,WAAgB,QAAA,EAAU,IAAA;EAAS,IAAA;AAAA,IAAkB,OAAA,CAAQ,cAAA;;;UCrC3E,iBAAA;EACf,MAAA;;EAEA,SAAA,UAAmB,KAAA;EDQI;ECNvB,IAAA;IAAS,IAAA;IAAc,WAAA;EAAA;EACvB,OAAA;EDMiD;;;;;ECAjD,WAAA;EDGc;;AAGhB;;ECDE,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,GAAA,EAAK,KAAA;EACL,QAAA;AAAA;AAAA,iBA+BoB,cAAA,CAAe,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;;;UC1CzD,YAAA;EACf,cAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;EACb,UAAA,EAAY,MAAA;EACZ,aAAA;EACA,iBAAA;EACA,MAAA,EAAQ,MAAA;IAAiB,IAAA;IAAc,MAAA;IAAgB,MAAA;IAAgB,OAAA;EAAA;AAAA;AAAA,UAGxD,iBAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;EAClB,MAAA,EAAQ,YAAA;AAAA;AAAA,iBAWM,gBAAA,CAAiB,GAAA,EAAK,KAAA,EAAO,IAAA;EAAS,SAAA;AAAA,IAAuB,iBAAA;;;iBC5C7D,mBAAA,CAAoB,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,cAAA,EAAgB,IAAA;EAAS,YAAA;AAAA,IAA0B,cAAA;AHkB5G;AAAA,iBGHgB,iBAAA,CAAkB,GAAA,EAAK,cAAA,GAAiB,eAAA;;;UCnBvC,iBAAA;EACf,EAAA;EACA,UAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,eAAA,CAAgB,CAAA,YAAa,CAAA;AAAA,iBAI7B,cAAA,CAAe,GAAA;;iBAyFf,cAAA,CAAe,CAAA,WAAY,iBAAA;;;cC9F9B,KAAA,GAAS,CAAA;;cAST,KAAA,GAAS,CAAA;;cAcT,KAAA,GAAS,CAAA;;;;;;;;;;cA4BT,UAAA,EAAU,MAAA;AL5BvB;AAAA,cKgCa,WAAA,EAAW,MAAA;;cAOX,UAAA,GAAc,CAAA;AAAA,cAGd,OAAA,GAAW,CAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/wxr.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/php-unserialize.ts","../src/core.ts"],"mappings":";;;;UA2BiB,QAAA;EACf,UAAA;IAAc,QAAA;IAAkB,OAAA;IAAiB,MAAA;IAAgB,IAAA;EAAA;EACjE,UAAA;EACA,gBAAA;EACA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,cAAA;EACf,GAAA,EAAK,KAAA;EACL,KAAA,EAAO,QAAA;AAAA;AAAA,iBAiBa,QAAA,CAAS,KAAA,WAAgB,QAAA,EAAU,IAAA;EAAS,IAAA;AAAA,IAAkB,OAAA,CAAQ,cAAA;;;UCtC3E,iBAAA;EACf,MAAA;;EAEA,SAAA,UAAmB,KAAA;EDSI;ECPvB,IAAA;IAAS,IAAA;IAAc,WAAA;EAAA;EACvB,OAAA;EDOiD;;;;;ECDjD,WAAA;EDIc;;AAGhB;;ECFE,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,GAAA,EAAK,KAAA;EACL,QAAA;AAAA;AAAA,iBAqCoB,cAAA,CAAe,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;;;UChDzD,YAAA;EACf,cAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;EACb,UAAA,EAAY,MAAA;EACZ,aAAA;EACA,iBAAA;EACA,MAAA,EAAQ,MAAA;IAAiB,IAAA;IAAc,MAAA;IAAgB,MAAA;IAAgB,OAAA;EAAA;EFJvE;EEMA,OAAA;EFNc;EEQd,kBAAA;AAAA;AAAA,UAGe,iBAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;EAClB,MAAA,EAAQ,YAAA;AAAA;AAAA,iBAiBM,gBAAA,CAAiB,GAAA,EAAK,KAAA,EAAO,IAAA;EAAS,SAAA;AAAA,IAAuB,iBAAA;;;iBCtD7D,mBAAA,CAAoB,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,cAAA,EAAgB,IAAA;EAAS,YAAA;AAAA,IAA0B,cAAA;AHmB5G;AAAA,iBGJgB,iBAAA,CAAkB,GAAA,EAAK,cAAA,GAAiB,eAAA;;;UCnBvC,iBAAA;EACf,EAAA;EACA,UAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,eAAA,CAAgB,CAAA,YAAa,CAAA;AAAA,iBAI7B,cAAA,CAAe,GAAA;;iBAyFf,cAAA,CAAe,CAAA,WAAY,iBAAA;;;cC9F9B,KAAA,GAAS,CAAA;;cAST,KAAA,GAAS,CAAA;;cAcT,KAAA,GAAS,CAAA;;;;;;;;;;cA4BT,UAAA,EAAU,MAAA;AL3BvB;AAAA,cK+Ba,WAAA,EAAW,MAAA;;cAOX,UAAA,GAAc,CAAA;AAAA,cAGd,OAAA,GAAW,CAAA"}
package/dist/index.mjs CHANGED
@@ -487,6 +487,7 @@ async function parseWxr(input, opts) {
487
487
  meta: m,
488
488
  serialized_keys: serializedKeys,
489
489
  acf,
490
+ lang: termRefs.find((t) => t.taxonomy === "language")?.slug || null,
490
491
  attachment_url: it.attachment_url || null,
491
492
  _comments: comments
492
493
  };
@@ -494,6 +495,21 @@ async function parseWxr(input, opts) {
494
495
  for (const r of records) for (const t of r.terms) if (!t.resolved && r.type !== "nav_menu_item") stats.unresolved_terms++;
495
496
  const byId = new Map(records.map((r) => [r.id, r]));
496
497
  const posts = records.filter((r) => r.type !== "attachment" && r.type !== "nav_menu_item").map(({ attachment_url: _a, _comments: _c, ...p }) => p);
498
+ const groups = /* @__PURE__ */ new Map();
499
+ for (const p of posts) {
500
+ const group = p.terms.find((t) => t.taxonomy === "post_translations")?.slug;
501
+ if (!group) continue;
502
+ groups.set(group, [...groups.get(group) ?? [], p]);
503
+ }
504
+ const languagePairs = [];
505
+ for (const members of groups.values()) {
506
+ const translations = {};
507
+ for (const m of members) if (m.lang) translations[m.lang] = m.id;
508
+ if (Object.keys(translations).length > 1) languagePairs.push({
509
+ post: members[0].id,
510
+ translations
511
+ });
512
+ }
497
513
  const attachments = records.filter((r) => r.type === "attachment").map((r) => ({
498
514
  id: r.id,
499
515
  title: r.title,
@@ -636,7 +652,8 @@ async function parseWxr(input, opts) {
636
652
  posts,
637
653
  attachments,
638
654
  menus,
639
- comments
655
+ comments,
656
+ ...languagePairs.length ? { language_pairs: languagePairs } : {}
640
657
  },
641
658
  stats
642
659
  };
@@ -753,6 +770,26 @@ async function fetchRestRawIR(options) {
753
770
  });
754
771
  const userById = new Map(users.map((u) => [u.id, u]));
755
772
  const posts = [];
773
+ const languagePairs = [];
774
+ const seenGroups = /* @__PURE__ */ new Set();
775
+ const recordGroup = (self, lang) => {
776
+ const translations = {};
777
+ if (self.translations && typeof self.translations === "object") {
778
+ for (const [code, id] of Object.entries(self.translations)) if (typeof id === "number") translations[code] = id;
779
+ } else if (Array.isArray(self.wpml_translations)) {
780
+ for (const t of self.wpml_translations) if (t.locale && typeof t.id === "number") translations[t.locale] = t.id;
781
+ if (lang) translations[lang] = self.id;
782
+ }
783
+ const ids = Object.values(translations);
784
+ if (ids.length < 2) return;
785
+ const key = [...ids].toSorted((a, b) => a - b).join(",");
786
+ if (seenGroups.has(key)) return;
787
+ seenGroups.add(key);
788
+ languagePairs.push({
789
+ post: self.id,
790
+ translations
791
+ });
792
+ };
756
793
  for (const [i, base] of bases.entries()) for (const p of postLists[i] ?? []) {
757
794
  const termRefs = [...p.categories ?? [], ...p.tags ?? []].map((id) => {
758
795
  const t = termsById.get(id);
@@ -771,7 +808,10 @@ async function fetchRestRawIR(options) {
771
808
  const author = p.author ? userById.get(p.author)?.slug ?? null : null;
772
809
  const meta = { ...p.meta && typeof p.meta === "object" ? p.meta : {} };
773
810
  if (p.featured_media) meta._thumbnail_id = String(p.featured_media);
811
+ const lang = typeof p.lang === "string" && p.lang || typeof p.wpml_current_locale === "string" && p.wpml_current_locale || null;
812
+ recordGroup(p, lang);
774
813
  posts.push({
814
+ ...lang ? { lang } : {},
775
815
  id: p.id,
776
816
  type: base.slug,
777
817
  status: p.status ?? "publish",
@@ -844,7 +884,8 @@ async function fetchRestRawIR(options) {
844
884
  terms: [...termsById.values()],
845
885
  posts,
846
886
  attachments,
847
- comments
887
+ comments,
888
+ ...languagePairs.length ? { language_pairs: languagePairs } : {}
848
889
  },
849
890
  warnings
850
891
  };
@@ -854,12 +895,38 @@ async function fetchRestRawIR(options) {
854
895
  const pick = (o, keys) => Object.fromEntries(Object.entries(o).filter(([k, v]) => keys.has(k) && v !== void 0 && v !== null && v !== ""));
855
896
  const typeModelId = (t) => t === "post" ? "posts" : t === "page" ? "pages" : t.replace(/_/g, "-");
856
897
  const domainOf = (t) => t === "post" ? "blog" : t === "page" ? "site" : "custom";
898
+ /** `en_US` / `tr-TR` / `en` → `en`: the store's locale is the primary subtag. */
899
+ const normLocale = (code) => (code ?? "").split(/[-_]/)[0]?.toLowerCase() ?? "";
900
+ /** Multilingual-plugin taxonomies that carry language bookkeeping, not content. */
901
+ const LANGUAGE_TAXONOMIES = new Set([
902
+ "language",
903
+ "post_translations",
904
+ "term_language",
905
+ "term_translations"
906
+ ]);
857
907
  function rawToContentrain(raw, opts) {
858
908
  const updatedBy = opts?.updatedBy ?? "@contentrain/wp-import";
859
- const locale = (raw.site.language ?? "en").split(/[-_]/)[0]?.toLowerCase() || "en";
909
+ const locale = normLocale(raw.site.language) || "en";
860
910
  const models = {};
861
911
  const contents = {};
862
912
  const metas = {};
913
+ const localeContents = {};
914
+ const localeMetas = {};
915
+ const postLocale = (p) => normLocale(p.lang ?? p.terms.find((t) => t.taxonomy === "language")?.slug) || locale;
916
+ const locales = [locale, ...[...new Set(raw.posts.filter((p) => !SKIP_TYPES.test(p.type)).map(postLocale))].filter((l) => l !== locale).toSorted()];
917
+ const multilingual = locales.length > 1;
918
+ const postById = new Map(raw.posts.map((p) => [p.id, p]));
919
+ const canonicalOf = /* @__PURE__ */ new Map();
920
+ let translationGroups = 0;
921
+ for (const pair of raw.language_pairs ?? []) {
922
+ const members = [...new Set(Object.values(pair.translations))].filter((id) => postById.has(id) && !SKIP_TYPES.test(postById.get(id).type));
923
+ if (members.length < 2) continue;
924
+ const memberLocales = members.map((id) => postLocale(postById.get(id)));
925
+ if (new Set(memberLocales).size !== members.length) throw new Error(`Translation group ${pair.post} has multiple posts in the same normalized locale; refusing to overwrite a translation`);
926
+ const canonical = members.find((id) => postLocale(postById.get(id)) === locale) ?? Math.min(...members);
927
+ for (const id of members) canonicalOf.set(id, canonical);
928
+ translationGroups++;
929
+ }
863
930
  let siteEntry = {};
864
931
  let siteMeta = null;
865
932
  const report = {
@@ -870,7 +937,9 @@ function rawToContentrain(raw, opts) {
870
937
  acf_fields: {},
871
938
  skipped_types: [],
872
939
  dropped_relations: 0,
873
- models: {}
940
+ models: {},
941
+ locales,
942
+ translation_groups: translationGroups
874
943
  };
875
944
  const importMeta = (status, extra = {}) => ({
876
945
  status,
@@ -878,7 +947,10 @@ function rawToContentrain(raw, opts) {
878
947
  updated_by: updatedBy,
879
948
  ...extra
880
949
  });
881
- const mapStatus = (p) => p.status === "publish" || p.status === "inherit" ? importMeta("published") : p.status === "future" ? importMeta("draft", p.date ? { publish_at: p.date } : {}) : p.status === "pending" ? importMeta("in_review") : p.status === "trash" ? importMeta("archived") : importMeta("draft");
950
+ const mapStatus = (p) => {
951
+ if (p.status === "future" && (!p.date || !Number.isFinite(Date.parse(p.date)))) throw new Error(`Scheduled WordPress post ${p.id} has no valid publication date`);
952
+ return p.status === "publish" || p.status === "inherit" ? importMeta("published") : p.status === "future" ? importMeta("published", { publish_at: p.date }) : p.status === "pending" ? importMeta("in_review") : p.status === "trash" ? importMeta("archived") : importMeta("draft");
953
+ };
882
954
  const addModel = (m) => {
883
955
  models[m.id] = m;
884
956
  contents[m.id] ??= {};
@@ -893,20 +965,31 @@ function rawToContentrain(raw, opts) {
893
965
  s = `${p.type}-${p.id}`;
894
966
  report.slug_fallback++;
895
967
  } else if (s !== p.slug) report.slug_rewritten++;
896
- const key = `${p.type}:${s}`;
968
+ const key = multilingual ? `${p.type}:${postLocale(p)}:${s}` : `${p.type}:${s}`;
897
969
  const n = usedSlugs.get(key) ?? 0;
898
970
  usedSlugs.set(key, n + 1);
899
971
  return n ? `${s}-${p.id}` : s;
900
972
  };
901
973
  const slugOf = /* @__PURE__ */ new Map();
902
974
  const postEntry = /* @__PURE__ */ new Map();
903
- for (const p of raw.posts) {
975
+ for (const p of raw.posts.toSorted((a, b) => a.id - b.id)) {
904
976
  if (SKIP_TYPES.test(p.type)) continue;
905
- const s = postSlug(p);
906
- slugOf.set(p.id, s);
977
+ slugOf.set(p.id, postSlug(p));
978
+ }
979
+ const identityOwner = /* @__PURE__ */ new Map();
980
+ const exported = raw.posts.filter((p) => !SKIP_TYPES.test(p.type));
981
+ const canonicalPosts = exported.filter((p) => (canonicalOf.get(p.id) ?? p.id) === p.id).toSorted((a, b) => Number(postLocale(b) === locale) - Number(postLocale(a) === locale) || a.id - b.id);
982
+ for (const p of canonicalPosts) {
983
+ const key = `${typeModelId(p.type)}:${slugOf.get(p.id)}`;
984
+ if (!identityOwner.has(key)) identityOwner.set(key, p.id);
985
+ }
986
+ for (const p of exported) {
987
+ const canonical = canonicalOf.get(p.id) ?? p.id;
988
+ const mid = typeModelId(p.type);
989
+ const key = `${mid}:${slugOf.get(canonical) ?? slugOf.get(p.id)}`;
907
990
  postEntry.set(p.id, {
908
- model: typeModelId(p.type),
909
- ref: hexId(`${typeModelId(p.type)}:${s}`)
991
+ model: mid,
992
+ ref: hexId(identityOwner.get(key) === canonical ? key : `${mid}:wp:${canonical}`)
910
993
  });
911
994
  }
912
995
  const mediaRef = (id) => raw.attachments.some((a) => a.id === id) ? hexId(`media:${id}`) : null;
@@ -971,7 +1054,7 @@ function rawToContentrain(raw, opts) {
971
1054
  };
972
1055
  metas.authors[authorId(slugify(p.author))] = importMeta("published");
973
1056
  }
974
- const taxonomies = [...new Set(raw.terms.map((t) => t.taxonomy))].filter((t) => t !== "nav_menu" && t !== "post_format");
1057
+ const taxonomies = [...new Set(raw.terms.map((t) => t.taxonomy))].filter((t) => t !== "nav_menu" && t !== "post_format" && !LANGUAGE_TAXONOMIES.has(t));
975
1058
  for (const tax of taxonomies) {
976
1059
  const mid = taxModelId(tax);
977
1060
  addModel({
@@ -1278,12 +1361,15 @@ function rawToContentrain(raw, opts) {
1278
1361
  name: type === "post" ? "Posts" : type === "page" ? "Pages" : mid,
1279
1362
  kind: "collection",
1280
1363
  domain: domainOf(type),
1281
- i18n: false,
1364
+ i18n: multilingual,
1282
1365
  title_field: "title",
1283
1366
  fields
1284
1367
  });
1285
1368
  for (const p of typeItems) {
1286
1369
  const id = postEntry.get(p.id).ref;
1370
+ const loc = postLocale(p);
1371
+ const contentBucket = multilingual ? (localeContents[mid] ??= {})[loc] ??= {} : contents[mid];
1372
+ const metaBucket = multilingual ? (localeMetas[mid] ??= {})[loc] ??= {} : metas[mid];
1287
1373
  const e = {
1288
1374
  title: titleOf(p),
1289
1375
  slug: slugOf.get(p.id),
@@ -1317,8 +1403,8 @@ function rawToContentrain(raw, opts) {
1317
1403
  if (fields.comments_open) e.comments_open = p.comment_status === "open";
1318
1404
  for (const k of Object.keys(fields)) if (k in p.meta && !(k in e) && !k.startsWith("_")) e[k] = p.meta[k];
1319
1405
  for (const [k, acf] of Object.entries(p.acf ?? {})) if (fields[k] && !(k in e)) e[k] = acf.value;
1320
- contents[mid][id] = e;
1321
- metas[mid][id] = mapStatus(p);
1406
+ contentBucket[id] = e;
1407
+ metaBucket[id] = mapStatus(p);
1322
1408
  }
1323
1409
  }
1324
1410
  const menus = raw.menus ?? [];
@@ -1624,6 +1710,22 @@ function rawToContentrain(raw, opts) {
1624
1710
  const domains = [...new Set(Object.values(models).map((m) => m.domain))].toSorted();
1625
1711
  for (const m of Object.values(models)) {
1626
1712
  files[`.contentrain/models/${m.id}.json`] = canon(m);
1713
+ if (m.i18n) {
1714
+ const perLocale = localeContents[m.id] ?? {};
1715
+ const ids = /* @__PURE__ */ new Set();
1716
+ for (const loc of Object.keys(perLocale).toSorted()) {
1717
+ files[`.contentrain/content/${m.domain}/${m.id}/${loc}.json`] = canon(perLocale[loc]);
1718
+ files[`.contentrain/meta/${m.id}/${loc}.json`] = canon(localeMetas[m.id]?.[loc] ?? {});
1719
+ for (const id of Object.keys(perLocale[loc])) ids.add(id);
1720
+ }
1721
+ report.models[m.id] = {
1722
+ kind: m.kind,
1723
+ domain: m.domain,
1724
+ fields: Object.keys(m.fields ?? {}).length,
1725
+ entries: ids.size
1726
+ };
1727
+ continue;
1728
+ }
1627
1729
  const content = m.kind === "singleton" ? siteEntry : contents[m.id];
1628
1730
  const meta = m.kind === "singleton" ? siteMeta : metas[m.id];
1629
1731
  files[`.contentrain/content/${m.domain}/${m.id}/data.json`] = canon(content);
@@ -1642,7 +1744,7 @@ function rawToContentrain(raw, opts) {
1642
1744
  workflow: "review",
1643
1745
  locales: {
1644
1746
  default: locale,
1645
- supported: [locale]
1747
+ supported: locales
1646
1748
  },
1647
1749
  domains
1648
1750
  });
@@ -1654,7 +1756,7 @@ function rawToContentrain(raw, opts) {
1654
1756
  for (const [wpId, ref] of postEntry) entrySourceMap[String(wpId)] = {
1655
1757
  model_id: ref.model,
1656
1758
  entry_id: ref.ref,
1657
- locale
1759
+ locale: postLocale(postById.get(wpId))
1658
1760
  };
1659
1761
  files["import-report.json"] = canon(report);
1660
1762
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["iso"],"sources":["../src/php-unserialize.ts","../src/core.ts","../src/wxr.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.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\nexport const strip = (s: unknown): string =>\n norm(\n String(s ?? '')\n .replace(/<[^>]*>/g, ' ')\n .replace(/&#(\\d+);/g, (_m, d: string) => String.fromCodePoint(Number(d)))\n .replace(/&amp;/g, '&'),\n )\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/**\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\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 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 } 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 as string) || 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 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 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 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 }\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","// Public/authenticated WordPress REST → RawIR.\n//\n// The lowest rungs of the source-access ladder. What REST cannot see (menus,\n// rest:false CPTs, unregistered meta) is simply 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 { RawIR, RawAttachment, RawComment, RawPost, RawTerm, RawTermRef, SourceAccessKind } from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { strip, SKIP_TYPES } from './core.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 /** WordPress Application Password credentials — lifts the rung to rest_auth. */\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\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 comment_status?: string\n ping_status?: string\n featured_media?: number\n categories?: number[]\n tags?: number[]\n meta?: Record<string, unknown>\n}\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 headers: Record<string, string> = { accept: 'application/json' }\n if (options.auth) {\n headers.authorization = `Basic ${Buffer.from(`${options.auth.user}:${options.auth.appPassword}`).toString('base64')}`\n }\n\n const getAll = async <T>(path: string): Promise<T[]> => {\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 })\n if (!response.ok) {\n warnings.push(`${path}: page ${page} HTTP ${response.status} — skipped`)\n await response.body?.cancel()\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) }\n })\n const first = await pageData(1)\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(`${path}: ${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 interface RestType { slug: string; rest_base?: string }\n const typesResp = await doFetch(`${origin}/wp-json/wp/v2/types`, { headers })\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 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 }\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 }\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 const [categories, tags, users, media, restComments, ...postLists] = await Promise.all([\n getAll<RestTerm>('categories'),\n getAll<RestTerm>('tags'),\n getAll<RestUser>('users'),\n getAll<RestMedia>('media'),\n getAll<RestComment>('comments'),\n ...bases.map((b) => getAll<RestPost>(b.base)),\n ])\n\n const termsById = new Map<number, RawTerm>()\n for (const [tax, list] of [\n ['category', categories],\n ['post_tag', tags],\n ] as const) {\n for (const t of list) {\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 for (const [i, base] of bases.entries()) {\n for (const p of postLists[i] ?? []) {\n const termRefs: RawTermRef[] = [...(p.categories ?? []), ...(p.tags ?? [])].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 posts.push({\n id: p.id,\n type: base.slug,\n status: p.status ?? 'publish',\n slug: p.slug,\n title: p.title?.rendered ?? '',\n link: 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: null,\n comment_status: p.comment_status ?? null,\n ping_status: p.ping_status ?? null,\n terms: termRefs,\n meta,\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 date: iso(m.date_gmt),\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 const kind: SourceAccessKind = options.auth ? 'rest_auth' : 'rest_public'\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind, tool: options.tool ?? '@contentrain/wp-import' },\n site: { url: origin },\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 }\n return { raw, warnings }\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, RawIR, RawPost } from '@contentrain/types'\nimport {\n byValue,\n canon,\n coreFields,\n decodeSlug,\n hexId,\n PLUGIN_META,\n SKIP_TYPES,\n slugify,\n strip,\n taxModelId,\n} from './core.js'\n\nexport interface ImportReport {\n slug_rewritten: number\n slug_fallback: number\n title_fallback: number\n meta_fields: Record<string, string>\n acf_fields: Record<string, string>\n skipped_types: string[]\n dropped_relations: number\n models: Record<string, { kind: string; domain: string; fields: number; entries: number }>\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\nexport function rawToContentrain(raw: RawIR, opts?: { updatedBy?: string }): ContentrainResult {\n const updatedBy = opts?.updatedBy ?? '@contentrain/wp-import'\n const locale = (raw.site.language ?? 'en').split(/[-_]/)[0]?.toLowerCase() || 'en'\n const models: Record<string, ModelDefinition> = {}\n const contents: Record<string, Record<string, Entry>> = {}\n const metas: Record<string, Record<string, Meta>> = {}\n let siteEntry: Entry = {}\n let siteMeta: Meta | null = null\n const report: ImportReport = {\n slug_rewritten: 0,\n slug_fallback: 0,\n title_fallback: 0,\n meta_fields: {},\n acf_fields: {},\n skipped_types: [],\n dropped_relations: 0,\n models: {},\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 p.status === 'publish' || p.status === 'inherit'\n ? importMeta('published')\n : p.status === 'future'\n ? importMeta('draft', p.date ? { publish_at: p.date } : {})\n : p.status === 'pending'\n ? importMeta('in_review')\n : p.status === 'trash'\n ? importMeta('archived')\n : importMeta('draft')\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 let s = slugify(decodeSlug(p.slug))\n if (!s) {\n s = `${p.type}-${p.id}`\n report.slug_fallback++\n } else if (s !== p.slug) report.slug_rewritten++\n const key = `${p.type}:${s}`\n const n = usedSlugs.get(key) ?? 0\n usedSlugs.set(key, n + 1)\n return n ? `${s}-${p.id}` : 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) {\n // Only exported entries may be relation targets or appear in the source map.\n if (SKIP_TYPES.test(p.type)) continue\n const s = postSlug(p)\n slugOf.set(p.id, s)\n postEntry.set(p.id, { model: typeModelId(p.type), ref: hexId(`${typeModelId(p.type)}:${s}`) })\n }\n const mediaRef = (id: number): string | null => (raw.attachments.some((a) => a.id === id) ? hexId(`media:${id}`) : null)\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((t) => t !== 'nav_menu' && t !== 'post_format')\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: slugify(decodeSlug(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: slugify(t.slug) }\n metas[mid]![id] ??= importMeta('published')\n }\n }\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: [], 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 = slugify(decodeSlug(a.slug)) || `media-${a.id}`\n if (mediaSlugs.has(slug)) slug = `${slug}-${a.id}`\n mediaSlugs.add(slug)\n const parent = a.parent ? (postEntry.get(a.parent) ?? null) : null\n if (a.parent && !parent) report.dropped_relations++\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 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 ;(models.media!.fields!.parent as FieldDef).model = contentModelIds\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 for (const [k, acf] of Object.entries(p.acf ?? {})) {\n if (fields[k]) continue\n const t = byValue(acf.value) ?? 'string'\n fields[k] = { type: (t === 'object' ? 'object' : t) as FieldDef['type'], label: k, description: 'ACF', order: (o += 10) }\n report.acf_fields[k] = t\n }\n }\n addModel({\n id: mid,\n name: type === 'post' ? 'Posts' : type === 'page' ? 'Pages' : mid,\n kind: 'collection',\n domain: domainOf(type),\n i18n: false,\n title_field: 'title',\n fields,\n })\n for (const p of typeItems) {\n const id = postEntry.get(p.id)!.ref\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 ?? {})) if (fields[k] && !(k in e)) e[k] = acf.value\n contents[mid]![id] = e\n metas[mid]![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 },\n })\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: [...contentModelIds, ...taxonomies.map(taxModelId)], 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: slugify(m.slug) || `menu-${m.id}`,\n items: m.items.map((i) => itemRef(i.id)),\n wp_id: m.id,\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 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 if (i.target.kind === 'url' && 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 = 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 = { 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: contentModelIds, 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,\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 addModel({\n id: 'site', name: 'Site', kind: 'singleton', domain: 'site', i18n: false, title_field: 'title',\n fields: {\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 })\n siteEntry = pick(\n { title: strip(raw.site.title) || 'Site', tagline: raw.site.description, url: raw.site.url, language: raw.site.language },\n new Set(['title', 'tagline', 'url', 'language']),\n )\n siteMeta = importMeta('published')\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 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: [locale] },\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) entrySourceMap[String(wpId)] = { model_id: ref.model, entry_id: ref.ref, locale }\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, RawIR } from '@contentrain/types'\nimport { COMMENTS_EXPORT_FORMAT, MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\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 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: raw.comments ?? [],\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 }\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/rest.ts","../src/contentrain.ts","../src/comments.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\nexport const strip = (s: unknown): string =>\n norm(\n String(s ?? '')\n .replace(/<[^>]*>/g, ' ')\n .replace(/&#(\\d+);/g, (_m, d: string) => String.fromCodePoint(Number(d)))\n .replace(/&amp;/g, '&'),\n )\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/**\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\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 } 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 as string) || 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 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","// Public/authenticated WordPress REST → RawIR.\n//\n// The lowest rungs of the source-access ladder. What REST cannot see (menus,\n// rest:false CPTs, unregistered meta) is simply 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 { RawIR, RawAttachment, RawComment, RawLanguagePair, RawPost, RawTerm, RawTermRef, SourceAccessKind } from '@contentrain/types'\nimport { MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\nimport { strip, SKIP_TYPES } from './core.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 /** WordPress Application Password credentials — lifts the rung to rest_auth. */\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\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 comment_status?: string\n ping_status?: string\n featured_media?: number\n categories?: number[]\n tags?: number[]\n meta?: Record<string, 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\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 headers: Record<string, string> = { accept: 'application/json' }\n if (options.auth) {\n headers.authorization = `Basic ${Buffer.from(`${options.auth.user}:${options.auth.appPassword}`).toString('base64')}`\n }\n\n const getAll = async <T>(path: string): Promise<T[]> => {\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 })\n if (!response.ok) {\n warnings.push(`${path}: page ${page} HTTP ${response.status} — skipped`)\n await response.body?.cancel()\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) }\n })\n const first = await pageData(1)\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(`${path}: ${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 interface RestType { slug: string; rest_base?: string }\n const typesResp = await doFetch(`${origin}/wp-json/wp/v2/types`, { headers })\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 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 }\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 }\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 const [categories, tags, users, media, restComments, ...postLists] = await Promise.all([\n getAll<RestTerm>('categories'),\n getAll<RestTerm>('tags'),\n getAll<RestUser>('users'),\n getAll<RestMedia>('media'),\n getAll<RestComment>('comments'),\n ...bases.map((b) => getAll<RestPost>(b.base)),\n ])\n\n const termsById = new Map<number, RawTerm>()\n for (const [tax, list] of [\n ['category', categories],\n ['post_tag', tags],\n ] as const) {\n for (const t of list) {\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 termRefs: RawTermRef[] = [...(p.categories ?? []), ...(p.tags ?? [])].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: 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: null,\n comment_status: p.comment_status ?? null,\n ping_status: p.ping_status ?? null,\n terms: termRefs,\n meta,\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 date: iso(m.date_gmt),\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 const kind: SourceAccessKind = options.auth ? 'rest_auth' : 'rest_public'\n const raw: RawIR = {\n version: MIGRATION_CONTRACT_VERSION,\n provenance: { kind, tool: options.tool ?? '@contentrain/wp-import' },\n site: { url: origin },\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 ...(languagePairs.length ? { language_pairs: languagePairs } : {}),\n }\n return { raw, warnings }\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, RawIR, RawPost } from '@contentrain/types'\nimport {\n byValue,\n canon,\n coreFields,\n decodeSlug,\n hexId,\n PLUGIN_META,\n SKIP_TYPES,\n slugify,\n strip,\n taxModelId,\n} from './core.js'\n\nexport interface ImportReport {\n slug_rewritten: number\n slug_fallback: number\n title_fallback: number\n meta_fields: Record<string, string>\n acf_fields: Record<string, string>\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\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\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 title_fallback: 0,\n meta_fields: {},\n acf_fields: {},\n skipped_types: [],\n dropped_relations: 0,\n models: {},\n locales,\n translation_groups: translationGroups,\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 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 let s = slugify(decodeSlug(p.slug))\n if (!s) {\n s = `${p.type}-${p.id}`\n report.slug_fallback++\n } else if (s !== p.slug) report.slug_rewritten++\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 return n ? `${s}-${p.id}` : 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 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: slugify(decodeSlug(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: slugify(t.slug) }\n metas[mid]![id] ??= importMeta('published')\n }\n }\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: [], 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 = slugify(decodeSlug(a.slug)) || `media-${a.id}`\n if (mediaSlugs.has(slug)) slug = `${slug}-${a.id}`\n mediaSlugs.add(slug)\n const parent = a.parent ? (postEntry.get(a.parent) ?? null) : null\n if (a.parent && !parent) report.dropped_relations++\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 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 ;(models.media!.fields!.parent as FieldDef).model = contentModelIds\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 for (const [k, acf] of Object.entries(p.acf ?? {})) {\n if (fields[k]) continue\n const t = byValue(acf.value) ?? 'string'\n fields[k] = { type: (t === 'object' ? 'object' : t) as FieldDef['type'], label: k, description: 'ACF', order: (o += 10) }\n report.acf_fields[k] = t\n }\n }\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 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 ?? {})) if (fields[k] && !(k in e)) e[k] = acf.value\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 },\n })\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: [...contentModelIds, ...taxonomies.map(taxModelId)], 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: slugify(m.slug) || `menu-${m.id}`,\n items: m.items.map((i) => itemRef(i.id)),\n wp_id: m.id,\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 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 if (i.target.kind === 'url' && 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 = 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 = { 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: contentModelIds, 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,\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 addModel({\n id: 'site', name: 'Site', kind: 'singleton', domain: 'site', i18n: false, title_field: 'title',\n fields: {\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 })\n siteEntry = pick(\n { title: strip(raw.site.title) || 'Site', tagline: raw.site.description, url: raw.site.url, language: raw.site.language },\n new Set(['title', 'tagline', 'url', 'language']),\n )\n siteMeta = importMeta('published')\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, RawIR } from '@contentrain/types'\nimport { COMMENTS_EXPORT_FORMAT, MIGRATION_CONTRACT_VERSION } from '@contentrain/types'\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 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: raw.comments ?? [],\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 }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentrain/wp-import",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "license": "MIT",
5
5
  "description": "WordPress importers for Contentrain — WXR and REST to RawIR, RawIR to a .contentrain content store",
6
6
  "type": "module",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "sax": "^1.4.1",
41
- "@contentrain/types": "1.12.0"
41
+ "@contentrain/types": "1.13.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^22.10.0",