emdash 0.17.0 → 0.17.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.
Files changed (56) hide show
  1. package/dist/{apply-CgamLmed.mjs → apply-CuuZG6op.mjs} +4 -4
  2. package/dist/{apply-CgamLmed.mjs.map → apply-CuuZG6op.mjs.map} +1 -1
  3. package/dist/astro/index.mjs +10 -1
  4. package/dist/astro/index.mjs.map +1 -1
  5. package/dist/astro/middleware.mjs +6 -6
  6. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +2 -2
  7. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +2 -2
  8. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +2 -2
  9. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +2 -2
  10. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +2 -2
  11. package/dist/astro/routes/api/admin/plugins/index.mjs +2 -2
  12. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +2 -2
  13. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +2 -2
  14. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +2 -2
  15. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +2 -2
  16. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +3 -3
  17. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +2 -2
  18. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +3 -3
  19. package/dist/astro/routes/api/admin/plugins/updates.mjs +2 -2
  20. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +2 -2
  21. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +2 -2
  22. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +1 -1
  23. package/dist/astro/routes/api/import/wordpress/execute.mjs +1 -1
  24. package/dist/astro/routes/api/manifest.mjs +1 -1
  25. package/dist/astro/routes/api/mcp.mjs +6 -6
  26. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +2 -2
  27. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +2 -2
  28. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +2 -2
  29. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +2 -2
  30. package/dist/astro/routes/api/schema/collections/index.mjs +2 -2
  31. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +2 -2
  32. package/dist/astro/routes/api/schema/orphans/index.mjs +2 -2
  33. package/dist/astro/routes/api/setup/dev-bypass.mjs +1 -1
  34. package/dist/astro/routes/api/setup/index.mjs +1 -1
  35. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +2 -2
  36. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +2 -2
  37. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +2 -2
  38. package/dist/astro/routes/api/taxonomies/index.mjs +2 -2
  39. package/dist/cli/index.mjs +113 -11
  40. package/dist/cli/index.mjs.map +1 -1
  41. package/dist/index.mjs +4 -4
  42. package/dist/{query-CuvjwhrE.mjs → query-Bt52mHXp.mjs} +9 -8
  43. package/dist/query-Bt52mHXp.mjs.map +1 -0
  44. package/dist/seed/index.mjs +1 -1
  45. package/dist/{taxonomies-CgpzAU6F.mjs → taxonomies-ByLlXrv5.mjs} +2 -2
  46. package/dist/{taxonomies-CgpzAU6F.mjs.map → taxonomies-ByLlXrv5.mjs.map} +1 -1
  47. package/dist/{taxonomies-D72gTOg_.mjs → taxonomies-CbO6v7EE.mjs} +2 -2
  48. package/dist/{taxonomies-D72gTOg_.mjs.map → taxonomies-CbO6v7EE.mjs.map} +1 -1
  49. package/dist/version-CWbvq9LG.mjs +7 -0
  50. package/dist/{version-FGcv0ooe.mjs.map → version-CWbvq9LG.mjs.map} +1 -1
  51. package/package.json +6 -6
  52. package/src/astro/integration/vite-config.ts +16 -0
  53. package/src/cli/commands/export-seed.ts +174 -12
  54. package/src/query.ts +7 -7
  55. package/dist/query-CuvjwhrE.mjs.map +0 -1
  56. package/dist/version-FGcv0ooe.mjs +0 -7
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as __exportAll, r as runMigrations, t as getMigrationStatus } from "../runner-eAgyIkeg.mjs";
3
3
  import { t as EmDashDatabaseError } from "../errors-9P_FDrJ_.mjs";
4
+ import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
4
5
  import { c as listTablesLike } from "../dialect-helpers-BKCvISIQ.mjs";
5
6
  import { r as isI18nEnabled } from "../config-CVssduLe.mjs";
6
7
  import { n as slugify } from "../slugify-Cjh1ssOZ.mjs";
@@ -13,7 +14,8 @@ import { t as OptionsRepository } from "../options-BL4X94qY.mjs";
13
14
  import "../redirect-BZUJltlj.mjs";
14
15
  import "../request-cache-BYMs-BGX.mjs";
15
16
  import "../byline-registry-CxK5g559.mjs";
16
- import "../byline-BrIVWLm-.mjs";
17
+ import { t as BylineRepository } from "../byline-BrIVWLm-.mjs";
18
+ import { n as isMissingTableError } from "../db-errors-CtzxKBxe.mjs";
17
19
  import "../fts-manager-DmUAk-kQ.mjs";
18
20
  import { n as SchemaRegistry } from "../registry-Dn6gsx3L.mjs";
19
21
  import { kyselyLogOption } from "../database/instrumentation.mjs";
@@ -24,7 +26,7 @@ import { n as isDeprecatedCapability, t as CAPABILITY_RENAMES } from "../types-C
24
26
  import "../ssrf-BsVGIE0Z.mjs";
25
27
  import "../ssrf-BvgVcfNQ.mjs";
26
28
  import { t as validateSeed } from "../validate-DactmcJG.mjs";
27
- import { t as applySeed } from "../apply-CgamLmed.mjs";
29
+ import { t as applySeed } from "../apply-CuuZG6op.mjs";
28
30
  import { n as fingerprintKey, r as generateEncryptionKey, t as EmDashSecretsError } from "../secrets-YYbTgB1w.mjs";
29
31
  import { LocalStorage } from "../storage/local.mjs";
30
32
  import { o as convertDataForRead } from "../transport--Ck3RBin.mjs";
@@ -1248,16 +1250,97 @@ async function exportSeed(db, withContent) {
1248
1250
  };
1249
1251
  seed.settings = await exportSettings(db);
1250
1252
  seed.collections = await exportCollections(db);
1251
- seed.taxonomies = await exportTaxonomies(db);
1252
- seed.menus = await exportMenus(db);
1253
+ const i18nEnabled = await detectI18nEnabled(db, seed.collections);
1254
+ seed.taxonomies = await exportTaxonomies(db, i18nEnabled);
1255
+ seed.menus = await exportMenus(db, i18nEnabled);
1253
1256
  seed.widgetAreas = await exportWidgetAreas(db);
1257
+ const { bylines, groupToSeedId } = await exportBylines(db);
1258
+ if (bylines.length > 0) seed.bylines = bylines;
1254
1259
  if (withContent !== void 0) {
1255
1260
  const collections = withContent === "" || withContent === "true" ? null : withContent.split(",").map((s) => s.trim()).filter(Boolean);
1256
- seed.content = await exportContent(db, seed.collections || [], collections);
1261
+ seed.content = await exportContent(db, seed.collections || [], collections, groupToSeedId, i18nEnabled);
1257
1262
  }
1258
1263
  return seed;
1259
1264
  }
1260
1265
  /**
1266
+ * Export byline profiles as root-level `bylines[]`.
1267
+ *
1268
+ * `SeedByline` has no locale axis, so locale siblings of the same byline
1269
+ * (sharing a `translation_group`) collapse to a single profile. The returned
1270
+ * `groupToSeedId` map keys on `translation_group` — the value stored in
1271
+ * `_emdash_content_bylines.byline_id` — so content credits can resolve to the
1272
+ * emitted seed id.
1273
+ */
1274
+ async function exportBylines(db) {
1275
+ const bylineRepo = new BylineRepository(db);
1276
+ const bylines = [];
1277
+ const groupToSeedId = /* @__PURE__ */ new Map();
1278
+ const usedSeedIds = /* @__PURE__ */ new Set();
1279
+ let cursor;
1280
+ do {
1281
+ const result = await bylineRepo.findMany({
1282
+ limit: 100,
1283
+ cursor
1284
+ });
1285
+ for (const byline of result.items) {
1286
+ const group = byline.translationGroup ?? byline.id;
1287
+ if (groupToSeedId.has(group)) continue;
1288
+ let seedId = `byline:${byline.slug}`;
1289
+ if (usedSeedIds.has(seedId)) seedId = `byline:${byline.slug}:${group}`;
1290
+ usedSeedIds.add(seedId);
1291
+ groupToSeedId.set(group, seedId);
1292
+ bylines.push({
1293
+ id: seedId,
1294
+ slug: byline.slug,
1295
+ displayName: byline.displayName,
1296
+ bio: byline.bio || void 0,
1297
+ websiteUrl: byline.websiteUrl || void 0,
1298
+ isGuest: byline.isGuest || void 0
1299
+ });
1300
+ }
1301
+ cursor = result.nextCursor;
1302
+ } while (cursor);
1303
+ return {
1304
+ bylines,
1305
+ groupToSeedId
1306
+ };
1307
+ }
1308
+ /**
1309
+ * Determine whether the export should emit locale-suffixed seed ids.
1310
+ *
1311
+ * The runtime initializes the i18n config in middleware, but the CLI never does,
1312
+ * so `isI18nEnabled()` is always false under `emdash export-seed` (#1330). When
1313
+ * the flag is unset, fall back to the data: a project is multi-locale when its
1314
+ * i18n-aware tables hold rows in more than one distinct locale. `locale` is
1315
+ * NOT NULL (defaulting to the site's default locale), so a per-row presence
1316
+ * check is not enough — only the *count* of distinct locales distinguishes a
1317
+ * genuinely single-locale project from a multi-locale one. This keeps
1318
+ * single-locale exports on bare ids and gives multi-locale exports the
1319
+ * per-locale suffix they need to avoid duplicate seed ids.
1320
+ */
1321
+ async function detectI18nEnabled(db, collections) {
1322
+ if (isI18nEnabled()) return true;
1323
+ const locales = /* @__PURE__ */ new Set();
1324
+ const collectDistinctLocales = async (tableRef) => {
1325
+ const result = await sql`
1326
+ SELECT DISTINCT locale FROM ${tableRef}
1327
+ `.execute(db);
1328
+ for (const row of result.rows) if (row.locale) locales.add(row.locale);
1329
+ return locales.size > 1;
1330
+ };
1331
+ if (await collectDistinctLocales(sql.ref("_emdash_taxonomy_defs"))) return true;
1332
+ if (await collectDistinctLocales(sql.ref("_emdash_menus"))) return true;
1333
+ for (const collection of collections) {
1334
+ validateIdentifier(collection.slug, "collection slug");
1335
+ try {
1336
+ if (await collectDistinctLocales(sql.ref(`ec_${collection.slug}`))) return true;
1337
+ } catch (error) {
1338
+ if (!isMissingTableError(error)) throw error;
1339
+ }
1340
+ }
1341
+ return false;
1342
+ }
1343
+ /**
1261
1344
  * Export site settings
1262
1345
  */
1263
1346
  async function exportSettings(db) {
@@ -1306,8 +1389,7 @@ async function exportCollections(db) {
1306
1389
  /**
1307
1390
  * Export taxonomy definitions and terms
1308
1391
  */
1309
- async function exportTaxonomies(db) {
1310
- const i18nEnabled = isI18nEnabled();
1392
+ async function exportTaxonomies(db, i18nEnabled) {
1311
1393
  const defs = await db.selectFrom("_emdash_taxonomy_defs").selectAll().orderBy(["name", "locale"]).execute();
1312
1394
  const result = [];
1313
1395
  const termRepo = new TaxonomyRepository(db);
@@ -1364,8 +1446,7 @@ async function exportTaxonomies(db) {
1364
1446
  /**
1365
1447
  * Export menus with their items
1366
1448
  */
1367
- async function exportMenus(db) {
1368
- const i18nEnabled = isI18nEnabled();
1449
+ async function exportMenus(db, i18nEnabled) {
1369
1450
  const menus = await db.selectFrom("_emdash_menus").selectAll().orderBy(["name", "locale"]).execute();
1370
1451
  const result = [];
1371
1452
  const groupToSeedId = /* @__PURE__ */ new Map();
@@ -1487,7 +1568,7 @@ async function exportWidgetAreas(db) {
1487
1568
  /**
1488
1569
  * Export content from collections
1489
1570
  */
1490
- async function exportContent(db, collections, includeCollections) {
1571
+ async function exportContent(db, collections, includeCollections, bylineGroupToSeedId, i18nEnabled) {
1491
1572
  const content = {};
1492
1573
  const contentRepo = new ContentRepository(db);
1493
1574
  const taxonomyRepo = new TaxonomyRepository(db);
@@ -1510,7 +1591,6 @@ async function exportContent(db, collections, includeCollections) {
1510
1591
  cursor = result.nextCursor;
1511
1592
  } while (cursor);
1512
1593
  } catch {}
1513
- const i18nEnabled = isI18nEnabled();
1514
1594
  for (const collection of collections) {
1515
1595
  if (includeCollections && !includeCollections.includes(collection.slug)) continue;
1516
1596
  const entries = [];
@@ -1540,6 +1620,8 @@ async function exportContent(db, collections, includeCollections) {
1540
1620
  }
1541
1621
  const taxonomies = await getTaxonomyAssignments(taxonomyRepo, collection.slug, item.id);
1542
1622
  if (Object.keys(taxonomies).length > 0) entry.taxonomies = taxonomies;
1623
+ const bylines = await getBylineCredits(db, collection.slug, item.id, bylineGroupToSeedId);
1624
+ if (bylines.length > 0) entry.bylines = bylines;
1543
1625
  entries.push(entry);
1544
1626
  }
1545
1627
  cursor = result.nextCursor;
@@ -1587,6 +1669,26 @@ function processDataForExport(data, fields, mediaMap) {
1587
1669
  return result;
1588
1670
  }
1589
1671
  /**
1672
+ * Get ordered byline credits for a content entry as `SeedBylineCredit[]`.
1673
+ *
1674
+ * The `_emdash_content_bylines.byline_id` column stores the credited byline's
1675
+ * `translation_group`, so it maps straight through `groupToSeedId`. Credits
1676
+ * whose group wasn't emitted in the root `bylines[]` are skipped (defensive;
1677
+ * shouldn't happen for a consistent DB).
1678
+ */
1679
+ async function getBylineCredits(db, collection, entryId, groupToSeedId) {
1680
+ const rows = await db.selectFrom("_emdash_content_bylines").select(["byline_id", "role_label"]).where("collection_slug", "=", collection).where("content_id", "=", entryId).orderBy("sort_order", "asc").execute();
1681
+ const credits = [];
1682
+ for (const row of rows) {
1683
+ const seedId = groupToSeedId.get(row.byline_id);
1684
+ if (!seedId) continue;
1685
+ const credit = { byline: seedId };
1686
+ if (row.role_label) credit.roleLabel = row.role_label;
1687
+ credits.push(credit);
1688
+ }
1689
+ return credits;
1690
+ }
1691
+ /**
1590
1692
  * Get taxonomy term assignments for a content entry
1591
1693
  */
1592
1694
  async function getTaxonomyAssignments(taxonomyRepo, collection, entryId) {