@emdash-cms/admin 0.19.0 → 0.20.0

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 (107) hide show
  1. package/dist/{LocaleDirectionProvider-xsHb49dm.js → LocaleDirectionProvider-D701o676.js} +25 -19
  2. package/dist/LocaleDirectionProvider-D701o676.js.map +1 -0
  3. package/dist/{config-76UcBWeH.d.ts → config-CPRInh7U.d.ts} +1 -1
  4. package/dist/{config-76UcBWeH.d.ts.map → config-CPRInh7U.d.ts.map} +1 -1
  5. package/dist/index.d.ts +9 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +667 -306
  8. package/dist/index.js.map +1 -1
  9. package/dist/locales/ar/messages.mjs +1 -1
  10. package/dist/locales/de/messages.mjs +1 -1
  11. package/dist/locales/en/messages.mjs +1 -1
  12. package/dist/locales/en-GB/messages.mjs +1 -0
  13. package/dist/locales/es-419/messages.mjs +1 -1
  14. package/dist/locales/es-ES/messages.mjs +1 -1
  15. package/dist/locales/eu/messages.mjs +1 -1
  16. package/dist/locales/fa/messages.mjs +1 -1
  17. package/dist/locales/fr/messages.mjs +1 -1
  18. package/dist/locales/id/messages.mjs +1 -1
  19. package/dist/locales/index.d.ts +1 -1
  20. package/dist/locales/index.js +1 -1
  21. package/dist/locales/ja/messages.mjs +1 -1
  22. package/dist/locales/ko/messages.mjs +1 -1
  23. package/dist/locales/nb/messages.mjs +1 -1
  24. package/dist/locales/pl/messages.mjs +1 -1
  25. package/dist/locales/pseudo/messages.mjs +1 -1
  26. package/dist/locales/pt-BR/messages.mjs +1 -1
  27. package/dist/locales/th/messages.mjs +1 -1
  28. package/dist/locales/zh-CN/messages.mjs +1 -1
  29. package/dist/locales/zh-TW/messages.mjs +1 -1
  30. package/dist/messages-BCdr0vs6.js +6 -0
  31. package/dist/messages-BCdr0vs6.js.map +1 -0
  32. package/dist/messages-BEba-i5h.js +6 -0
  33. package/dist/messages-BEba-i5h.js.map +1 -0
  34. package/dist/messages-BOJU79wz.js +6 -0
  35. package/dist/messages-BOJU79wz.js.map +1 -0
  36. package/dist/messages-B_776u_s.js +6 -0
  37. package/dist/messages-B_776u_s.js.map +1 -0
  38. package/dist/messages-BuTB8H87.js +6 -0
  39. package/dist/messages-BuTB8H87.js.map +1 -0
  40. package/dist/messages-BxxGIhf4.js +6 -0
  41. package/dist/messages-BxxGIhf4.js.map +1 -0
  42. package/dist/messages-CBkzQcd-.js +6 -0
  43. package/dist/messages-CBkzQcd-.js.map +1 -0
  44. package/dist/messages-CNCPtLaI.js +6 -0
  45. package/dist/messages-CNCPtLaI.js.map +1 -0
  46. package/dist/messages-CY65b3kz.js +6 -0
  47. package/dist/messages-CY65b3kz.js.map +1 -0
  48. package/dist/messages-CvaPem7G.js +6 -0
  49. package/dist/messages-CvaPem7G.js.map +1 -0
  50. package/dist/messages-DHo2mVqL.js +6 -0
  51. package/dist/messages-DHo2mVqL.js.map +1 -0
  52. package/dist/messages-DHqYoT8m.js +6 -0
  53. package/dist/messages-DHqYoT8m.js.map +1 -0
  54. package/dist/messages-DUYqNIID.js +6 -0
  55. package/dist/messages-DUYqNIID.js.map +1 -0
  56. package/dist/messages-DflNUNOT.js +6 -0
  57. package/dist/messages-DflNUNOT.js.map +1 -0
  58. package/dist/messages-DfrYsR2M.js +6 -0
  59. package/dist/messages-DfrYsR2M.js.map +1 -0
  60. package/dist/messages-DiOQ8Er0.js +6 -0
  61. package/dist/messages-DiOQ8Er0.js.map +1 -0
  62. package/dist/messages-MtFRSNif.js +6 -0
  63. package/dist/messages-MtFRSNif.js.map +1 -0
  64. package/dist/messages-TCMOQPXZ.js +6 -0
  65. package/dist/messages-TCMOQPXZ.js.map +1 -0
  66. package/dist/messages-Z5LBofRQ.js +6 -0
  67. package/dist/messages-Z5LBofRQ.js.map +1 -0
  68. package/dist/{plugins-BZzztFdK.js → plugins-G9Z9NQ7n.js} +26 -7
  69. package/dist/{plugins-BZzztFdK.js.map → plugins-G9Z9NQ7n.js.map} +1 -1
  70. package/package.json +8 -7
  71. package/dist/LocaleDirectionProvider-xsHb49dm.js.map +0 -1
  72. package/dist/messages-BMitdYCD.js +0 -6
  73. package/dist/messages-BMitdYCD.js.map +0 -1
  74. package/dist/messages-BQ-MRpT8.js +0 -6
  75. package/dist/messages-BQ-MRpT8.js.map +0 -1
  76. package/dist/messages-BXYYYOd2.js +0 -6
  77. package/dist/messages-BXYYYOd2.js.map +0 -1
  78. package/dist/messages-Bg8kLtZI.js +0 -6
  79. package/dist/messages-Bg8kLtZI.js.map +0 -1
  80. package/dist/messages-BwRtFSRk.js +0 -6
  81. package/dist/messages-BwRtFSRk.js.map +0 -1
  82. package/dist/messages-C1IVcXec.js +0 -6
  83. package/dist/messages-C1IVcXec.js.map +0 -1
  84. package/dist/messages-C5P0RJYN.js +0 -6
  85. package/dist/messages-C5P0RJYN.js.map +0 -1
  86. package/dist/messages-CH9Gmcpo.js +0 -6
  87. package/dist/messages-CH9Gmcpo.js.map +0 -1
  88. package/dist/messages-CJgGf1T1.js +0 -6
  89. package/dist/messages-CJgGf1T1.js.map +0 -1
  90. package/dist/messages-CWew0hcG.js +0 -6
  91. package/dist/messages-CWew0hcG.js.map +0 -1
  92. package/dist/messages-CmMy_HWT.js +0 -6
  93. package/dist/messages-CmMy_HWT.js.map +0 -1
  94. package/dist/messages-CzJu5dYn.js +0 -6
  95. package/dist/messages-CzJu5dYn.js.map +0 -1
  96. package/dist/messages-DQ5ZXmj9.js +0 -6
  97. package/dist/messages-DQ5ZXmj9.js.map +0 -1
  98. package/dist/messages-DYT85mDk.js +0 -6
  99. package/dist/messages-DYT85mDk.js.map +0 -1
  100. package/dist/messages-DinvbD0I.js +0 -6
  101. package/dist/messages-DinvbD0I.js.map +0 -1
  102. package/dist/messages-Dj-5xKz6.js +0 -6
  103. package/dist/messages-Dj-5xKz6.js.map +0 -1
  104. package/dist/messages-DnhGgBnH.js +0 -6
  105. package/dist/messages-DnhGgBnH.js.map +0 -1
  106. package/dist/messages-Tf8h9nIJ.js +0 -6
  107. package/dist/messages-Tf8h9nIJ.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { c as fetchAuthMode, d as throwResponseError, i as fetchPlugins, l as fetchManifest, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as parseApiResponse } from "./plugins-BZzztFdK.js";
2
- import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-xsHb49dm.js";
1
+ import { c as fetchAuthMode, d as throwResponseError, i as fetchPlugins, l as fetchManifest, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as parseApiResponse } from "./plugins-G9Z9NQ7n.js";
2
+ import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-D701o676.js";
3
3
  import "./locales/index.js";
4
- import { Autocomplete, Badge, Button, Checkbox, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
4
+ import { Autocomplete, Badge, Button, Checkbox, ClipboardText, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
5
5
  import { i18n } from "@lingui/core";
6
6
  import { I18nProvider, Trans, useLingui } from "@lingui/react";
7
7
  import { QueryClient, QueryClientProvider, keepPreviousData, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -40,6 +40,7 @@ import { BlockRenderer } from "@emdash-cms/blocks";
40
40
  import DOMPurify from "dompurify";
41
41
  import { Marked, Renderer } from "marked";
42
42
  import { checkEnvCompatibility, hostEnvFromVersions } from "@emdash-cms/registry-client/env";
43
+ import { declaredAccessToCapabilities } from "@emdash-cms/plugin-types";
43
44
  import { useHotkeys } from "react-hotkeys-hook";
44
45
 
45
46
  //#region src/components/ThemeProvider.tsx
@@ -279,7 +280,10 @@ function ArrowPrev({ className, ...props }) {
279
280
  function getMutationError(error) {
280
281
  if (!error) return null;
281
282
  if (error instanceof Error) return error.message;
282
- return "An error occurred";
283
+ return i18n._({
284
+ id: "Vw8l6h",
285
+ message: "An error occurred"
286
+ });
283
287
  }
284
288
  /** Inline error banner for use inside dialogs. */
285
289
  function DialogError({ message, className }) {
@@ -1437,7 +1441,22 @@ async function fetchMediaList(options) {
1437
1441
  const q = normalizeMediaSearch(options.search);
1438
1442
  if (q) params.set("q", q);
1439
1443
  }
1440
- return parseApiResponse(await apiFetch(`${API_BASE}/media${params.toString() ? `?${params}` : ""}`), "Failed to fetch media");
1444
+ return parseApiResponse(await apiFetch(`${API_BASE}/media${params.toString() ? `?${params}` : ""}`), i18n._({
1445
+ id: "gtFAk8",
1446
+ message: "Failed to fetch media"
1447
+ }));
1448
+ }
1449
+ /**
1450
+ * Fetch a single media item by id.
1451
+ *
1452
+ * Used to resolve an id-only reference (e.g. a byline's `avatarMediaId`)
1453
+ * back into a full media item for display.
1454
+ */
1455
+ async function fetchMediaItem(id) {
1456
+ return (await parseApiResponse(await apiFetch(`${API_BASE}/media/${id}`), i18n._({
1457
+ id: "8rtatN",
1458
+ message: "Failed to fetch media item"
1459
+ }))).item;
1441
1460
  }
1442
1461
  /**
1443
1462
  * Try to get a signed upload URL
@@ -1456,7 +1475,10 @@ async function getUploadUrl(file, opts) {
1456
1475
  })
1457
1476
  });
1458
1477
  if (response.status === 501) return null;
1459
- return parseApiResponse(response, "Failed to get upload URL");
1478
+ return parseApiResponse(response, i18n._({
1479
+ id: "YTKTMb",
1480
+ message: "Failed to get upload URL"
1481
+ }));
1460
1482
  } catch (error) {
1461
1483
  if (error instanceof TypeError && error.message.includes("fetch")) return null;
1462
1484
  throw error;
@@ -1470,7 +1492,10 @@ async function confirmUpload(mediaId, metadata) {
1470
1492
  method: "POST",
1471
1493
  headers: { "Content-Type": "application/json" },
1472
1494
  body: JSON.stringify(metadata || {})
1473
- }), "Failed to confirm upload")).item;
1495
+ }), i18n._({
1496
+ id: "QZDXMs",
1497
+ message: "Failed to confirm upload"
1498
+ }))).item;
1474
1499
  }
1475
1500
  /**
1476
1501
  * Upload directly to signed URL
@@ -1523,7 +1548,10 @@ async function uploadMediaDirect(file, opts) {
1523
1548
  return (await parseApiResponse(await apiFetch(`${API_BASE}/media`, {
1524
1549
  method: "POST",
1525
1550
  body: formData
1526
- }), "Failed to upload media")).item;
1551
+ }), i18n._({
1552
+ id: "5IFNMM",
1553
+ message: "Failed to upload media"
1554
+ }))).item;
1527
1555
  }
1528
1556
  /**
1529
1557
  * Upload media file
@@ -1560,13 +1588,19 @@ async function updateMedia(id, input) {
1560
1588
  method: "PUT",
1561
1589
  headers: { "Content-Type": "application/json" },
1562
1590
  body: JSON.stringify(input)
1563
- }), "Failed to update media")).item;
1591
+ }), i18n._({
1592
+ id: "nr0Bxd",
1593
+ message: "Failed to update media"
1594
+ }))).item;
1564
1595
  }
1565
1596
  /**
1566
1597
  * Fetch all configured media providers
1567
1598
  */
1568
1599
  async function fetchMediaProviders() {
1569
- return (await parseApiResponse(await apiFetch(`${API_BASE}/media/providers`), "Failed to fetch media providers")).items;
1600
+ return (await parseApiResponse(await apiFetch(`${API_BASE}/media/providers`), i18n._({
1601
+ id: "sj4xOB",
1602
+ message: "Failed to fetch media providers"
1603
+ }))).items;
1570
1604
  }
1571
1605
  /**
1572
1606
  * Fetch media items from a specific provider
@@ -1580,7 +1614,10 @@ async function fetchProviderMedia(providerId, options) {
1580
1614
  const value = Array.isArray(options.mimeType) ? options.mimeType.join(",") : options.mimeType;
1581
1615
  if (value) params.set("mimeType", value);
1582
1616
  }
1583
- return parseApiResponse(await apiFetch(`${API_BASE}/media/providers/${providerId}${params.toString() ? `?${params}` : ""}`), "Failed to fetch provider media");
1617
+ return parseApiResponse(await apiFetch(`${API_BASE}/media/providers/${providerId}${params.toString() ? `?${params}` : ""}`), i18n._({
1618
+ id: "ZrDiVv",
1619
+ message: "Failed to fetch provider media"
1620
+ }));
1584
1621
  }
1585
1622
  /**
1586
1623
  * Upload media to a specific provider
@@ -1592,7 +1629,10 @@ async function uploadToProvider(providerId, file, alt) {
1592
1629
  return (await parseApiResponse(await apiFetch(`${API_BASE}/media/providers/${providerId}`, {
1593
1630
  method: "POST",
1594
1631
  body: formData
1595
- }), "Failed to upload to provider")).item;
1632
+ }), i18n._({
1633
+ id: "j66jlb",
1634
+ message: "Failed to upload to provider"
1635
+ }))).item;
1596
1636
  }
1597
1637
  /**
1598
1638
  * Delete media from a specific provider
@@ -1739,7 +1779,10 @@ async function registerOrphanedTable(slug, options) {
1739
1779
  * Fetch site settings
1740
1780
  */
1741
1781
  async function fetchSettings() {
1742
- return parseApiResponse(await apiFetch(`${API_BASE}/settings`), "Failed to fetch settings");
1782
+ return parseApiResponse(await apiFetch(`${API_BASE}/settings`), i18n._({
1783
+ id: "naCprc",
1784
+ message: "Failed to fetch settings"
1785
+ }));
1743
1786
  }
1744
1787
  /**
1745
1788
  * Update site settings
@@ -1749,7 +1792,10 @@ async function updateSettings(settings) {
1749
1792
  method: "POST",
1750
1793
  headers: { "Content-Type": "application/json" },
1751
1794
  body: JSON.stringify(settings)
1752
- }), "Failed to update settings");
1795
+ }), i18n._({
1796
+ id: "tOcErW",
1797
+ message: "Failed to update settings"
1798
+ }));
1753
1799
  }
1754
1800
 
1755
1801
  //#endregion
@@ -2339,13 +2385,19 @@ async function fetchSections(options) {
2339
2385
  if (options?.search) params.set("search", options.search);
2340
2386
  if (options?.limit) params.set("limit", String(options.limit));
2341
2387
  if (options?.cursor) params.set("cursor", options.cursor);
2342
- return parseApiResponse(await apiFetch(params.toString() ? `${API_BASE}/sections?${params}` : `${API_BASE}/sections`), "Failed to fetch sections");
2388
+ return parseApiResponse(await apiFetch(params.toString() ? `${API_BASE}/sections?${params}` : `${API_BASE}/sections`), i18n._({
2389
+ id: "CEv4Y+",
2390
+ message: "Failed to fetch sections"
2391
+ }));
2343
2392
  }
2344
2393
  /**
2345
2394
  * Fetch a single section by slug
2346
2395
  */
2347
2396
  async function fetchSection(slug) {
2348
- return parseApiResponse(await apiFetch(`${API_BASE}/sections/${slug}`), "Failed to fetch section");
2397
+ return parseApiResponse(await apiFetch(`${API_BASE}/sections/${slug}`), i18n._({
2398
+ id: "FZmyhf",
2399
+ message: "Failed to fetch section"
2400
+ }));
2349
2401
  }
2350
2402
  /**
2351
2403
  * Create a section
@@ -2355,7 +2407,10 @@ async function createSection(input) {
2355
2407
  method: "POST",
2356
2408
  headers: { "Content-Type": "application/json" },
2357
2409
  body: JSON.stringify(input)
2358
- }), "Failed to create section");
2410
+ }), i18n._({
2411
+ id: "NL9xsV",
2412
+ message: "Failed to create section"
2413
+ }));
2359
2414
  }
2360
2415
  /**
2361
2416
  * Update a section
@@ -2365,7 +2420,10 @@ async function updateSection(slug, input) {
2365
2420
  method: "PUT",
2366
2421
  headers: { "Content-Type": "application/json" },
2367
2422
  body: JSON.stringify(input)
2368
- }), "Failed to update section");
2423
+ }), i18n._({
2424
+ id: "cCyATW",
2425
+ message: "Failed to update section"
2426
+ }));
2369
2427
  }
2370
2428
  /**
2371
2429
  * Delete a section
@@ -2727,7 +2785,10 @@ async function bulkCommentAction(ids, action) {
2727
2785
  * Fetch dashboard statistics
2728
2786
  */
2729
2787
  async function fetchDashboardStats() {
2730
- return parseApiResponse(await apiFetch(`${API_BASE}/dashboard`), "Failed to fetch dashboard stats");
2788
+ return parseApiResponse(await apiFetch(`${API_BASE}/dashboard`), i18n._({
2789
+ id: "IZPHXp",
2790
+ message: "Failed to fetch dashboard stats"
2791
+ }));
2731
2792
  }
2732
2793
 
2733
2794
  //#endregion
@@ -2747,7 +2808,13 @@ async function setSearchEnabled(collection, enabled, weights) {
2747
2808
  enabled,
2748
2809
  weights
2749
2810
  })
2750
- }), `Failed to ${enabled ? "enable" : "disable"} search`);
2811
+ }), enabled ? i18n._({
2812
+ id: "2DwuuY",
2813
+ message: "Failed to enable search"
2814
+ }) : i18n._({
2815
+ id: "5YQYqs",
2816
+ message: "Failed to disable search"
2817
+ }));
2751
2818
  }
2752
2819
 
2753
2820
  //#endregion
@@ -2924,14 +2991,20 @@ function describeCapability(capability, allowedHosts) {
2924
2991
  * Email settings API client functions
2925
2992
  */
2926
2993
  async function fetchEmailSettings() {
2927
- return parseApiResponse(await apiFetch(`${API_BASE}/settings/email`), "Failed to fetch email settings");
2994
+ return parseApiResponse(await apiFetch(`${API_BASE}/settings/email`), i18n._({
2995
+ id: "QxS/sM",
2996
+ message: "Failed to fetch email settings"
2997
+ }));
2928
2998
  }
2929
2999
  async function sendTestEmail(to) {
2930
3000
  return parseApiResponse(await apiFetch(`${API_BASE}/settings/email`, {
2931
3001
  method: "POST",
2932
3002
  headers: { "Content-Type": "application/json" },
2933
3003
  body: JSON.stringify({ to })
2934
- }), "Failed to send test email");
3004
+ }), i18n._({
3005
+ id: "aH/q8K",
3006
+ message: "Failed to send test email"
3007
+ }));
2935
3008
  }
2936
3009
 
2937
3010
  //#endregion
@@ -3042,7 +3115,10 @@ async function fetch404Summary(limit) {
3042
3115
  * Current user query — shared across Shell, Header, Sidebar, and CommandPalette.
3043
3116
  */
3044
3117
  async function fetchCurrentUser() {
3045
- return parseApiResponse(await apiFetch("/_emdash/api/auth/me"), "Failed to fetch user");
3118
+ return parseApiResponse(await apiFetch("/_emdash/api/auth/me"), i18n._({
3119
+ id: "z7Mflq",
3120
+ message: "Failed to fetch user"
3121
+ }));
3046
3122
  }
3047
3123
  function useCurrentUser() {
3048
3124
  return useQuery({
@@ -3126,6 +3202,57 @@ function providerItemToMediaItem(providerId, item) {
3126
3202
  meta: item.meta
3127
3203
  };
3128
3204
  }
3205
+ /** Root-absolute path prefix for locally stored media served by EmDash. */
3206
+ const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
3207
+ /**
3208
+ * Default rendered width (CSS px) for admin grid thumbnails, requested at ~2x
3209
+ * the largest grid cell (200px) so they stay crisp on HiDPI displays.
3210
+ */
3211
+ const MEDIA_THUMBNAIL_WIDTH = 400;
3212
+ /**
3213
+ * Build a display URL for a media thumbnail in the admin grid/list views.
3214
+ *
3215
+ * Large libraries were slow to browse and search because every grid cell loaded
3216
+ * the full-size original through the media proxy (#1488). This routes
3217
+ * same-origin raster images through Astro's runtime image endpoint (`/_image`)
3218
+ * to request a small resized rendition instead.
3219
+ *
3220
+ * Where a runtime image service transforms — sharp on Node, or the Cloudflare
3221
+ * Images binding on Workers (the `@astrojs/cloudflare` v13 default) — the grid
3222
+ * gets a lightweight thumbnail. Where none does (a `passthrough` config, or
3223
+ * behind Cloudflare Access where the endpoint's same-origin source fetch is
3224
+ * blocked) `/_image` streams the original, so this never renders worse than
3225
+ * before. Callers should still fall back to the original on image `error` for
3226
+ * the rare case where the endpoint rejects the request (e.g. a site whose
3227
+ * configured origin differs from the admin's).
3228
+ *
3229
+ * Returns the URL unchanged for non-raster media (an icon renders instead),
3230
+ * SVGs (vector — nothing to downscale, and some services reject them), and
3231
+ * anything not served from the local media route (external/provider URLs are
3232
+ * already remote renditions, not same-origin originals).
3233
+ */
3234
+ function getMediaThumbnailUrl(originalUrl, mimeType, width = MEDIA_THUMBNAIL_WIDTH) {
3235
+ if (!mimeType.startsWith("image/") || mimeType === "image/svg+xml") return originalUrl;
3236
+ if (!originalUrl.startsWith(INTERNAL_MEDIA_PREFIX)) return originalUrl;
3237
+ const origin = typeof window === "undefined" ? "" : window.location.origin;
3238
+ if (!origin) return originalUrl;
3239
+ return `/_image?${new URLSearchParams({
3240
+ href: `${origin}${originalUrl}`,
3241
+ w: String(width),
3242
+ f: "webp"
3243
+ }).toString()}`;
3244
+ }
3245
+ /**
3246
+ * `onError` fallback for grid thumbnails: if a `/_image` rendition fails to
3247
+ * load (e.g. the endpoint rejects the request on a site whose configured origin
3248
+ * differs from the admin's), swap in the original URL once. Guarded with a data
3249
+ * attribute so a failing original can't trigger a reload loop.
3250
+ */
3251
+ function fallbackToOriginalThumbnail(img, originalUrl) {
3252
+ if (img.dataset.thumbFallback) return;
3253
+ img.dataset.thumbFallback = "1";
3254
+ img.src = originalUrl;
3255
+ }
3129
3256
  function getFileIcon(mimeType) {
3130
3257
  if (mimeType.startsWith("video/")) return "🎬";
3131
3258
  if (mimeType.startsWith("audio/")) return "🎵";
@@ -3352,7 +3479,10 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3352
3479
  const activeProviderInfo = React$1.useMemo(() => {
3353
3480
  if (activeProvider === "local") return {
3354
3481
  id: "local",
3355
- name: "Library",
3482
+ name: _t({
3483
+ id: "exYcTF",
3484
+ message: "Library"
3485
+ }),
3356
3486
  icon: void 0,
3357
3487
  capabilities: {
3358
3488
  browse: true,
@@ -3362,7 +3492,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3362
3492
  }
3363
3493
  };
3364
3494
  return providers?.find((p) => p.id === activeProvider);
3365
- }, [activeProvider, providers]);
3495
+ }, [
3496
+ activeProvider,
3497
+ providers,
3498
+ _t
3499
+ ]);
3366
3500
  const mediaQueryKey = [
3367
3501
  "media",
3368
3502
  filters?.join(",") ?? "",
@@ -3580,7 +3714,10 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3580
3714
  const providerTabs = React$1.useMemo(() => {
3581
3715
  const tabs = [{
3582
3716
  id: "local",
3583
- name: "Library",
3717
+ name: _t({
3718
+ id: "exYcTF",
3719
+ message: "Library"
3720
+ }),
3584
3721
  icon: void 0
3585
3722
  }];
3586
3723
  if (providers && !localOnly) {
@@ -3591,7 +3728,11 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
3591
3728
  });
3592
3729
  }
3593
3730
  return tabs;
3594
- }, [providers, localOnly]);
3731
+ }, [
3732
+ providers,
3733
+ localOnly,
3734
+ _t
3735
+ ]);
3595
3736
  return /* @__PURE__ */ jsx(Dialog.Root, {
3596
3737
  open,
3597
3738
  onOpenChange: handleClose,
@@ -3915,6 +4056,7 @@ function MediaPickerItem({ item, selected, onClick, onDoubleClick, onDimensionsD
3915
4056
  const { _: _t2 } = useLingui();
3916
4057
  const isImage = item.mimeType.startsWith("image/");
3917
4058
  const needsDimensions = isImage && (!item.width || !item.height);
4059
+ const displayUrl = needsDimensions ? item.url : getMediaThumbnailUrl(item.url, item.mimeType);
3918
4060
  const handleImageLoad = React$1.useCallback((e) => {
3919
4061
  if (needsDimensions && onDimensionsDetected) {
3920
4062
  const img = e.currentTarget;
@@ -3946,10 +4088,11 @@ function MediaPickerItem({ item, selected, onClick, onDoubleClick, onDimensionsD
3946
4088
  }),
3947
4089
  children: [
3948
4090
  isImage ? /* @__PURE__ */ jsx("img", {
3949
- src: item.url,
4091
+ src: displayUrl,
3950
4092
  alt: "",
3951
4093
  className: "h-full w-full object-cover",
3952
- onLoad: handleImageLoad
4094
+ onLoad: handleImageLoad,
4095
+ onError: (e) => fallbackToOriginalThumbnail(e.currentTarget, item.url)
3953
4096
  }) : /* @__PURE__ */ jsx("div", {
3954
4097
  className: "flex h-full w-full items-center justify-center bg-kumo-tint",
3955
4098
  children: /* @__PURE__ */ jsx("span", {
@@ -4408,6 +4551,153 @@ function DocumentOutline({ editor, className }) {
4408
4551
  });
4409
4552
  }
4410
4553
 
4554
+ //#endregion
4555
+ //#region src/components/ImageFieldRenderer.tsx
4556
+ /**
4557
+ * Image field with media picker
4558
+ *
4559
+ * Stores full image metadata including dimensions for responsive images.
4560
+ * Handles backwards compatibility with legacy string URLs.
4561
+ *
4562
+ * Extracted from ContentEditor so non-top-level field UIs (e.g. repeater
4563
+ * sub-fields) can reuse the same picker without a circular import.
4564
+ */
4565
+ function ImageFieldRenderer({ id, label, description, value, onChange, required, allowedMimeTypes, fieldId }) {
4566
+ const { _: _t } = useLingui();
4567
+ const [pickerOpen, setPickerOpen] = React$1.useState(false);
4568
+ const [imageBroken, setImageBroken] = React$1.useState(false);
4569
+ const displayUrl = typeof value === "string" ? value : value?.previewUrl || value?.src || (value && (!value.provider || value.provider === "local") ? `/_emdash/api/media/file/${typeof value.meta?.storageKey === "string" ? value.meta.storageKey : value.id}` : void 0);
4570
+ React$1.useEffect(() => {
4571
+ setImageBroken(false);
4572
+ }, [displayUrl]);
4573
+ const handleSelect = (item) => {
4574
+ const isLocalProvider = !item.provider || item.provider === "local";
4575
+ onChange({
4576
+ id: item.id,
4577
+ provider: item.provider || "local",
4578
+ previewUrl: isLocalProvider ? void 0 : item.url,
4579
+ alt: item.alt || "",
4580
+ width: item.width,
4581
+ height: item.height,
4582
+ meta: isLocalProvider ? {
4583
+ ...item.meta,
4584
+ storageKey: item.storageKey
4585
+ } : item.meta
4586
+ });
4587
+ };
4588
+ const handleRemove = () => {
4589
+ onChange(null);
4590
+ };
4591
+ return /* @__PURE__ */ jsxs("div", {
4592
+ id,
4593
+ children: [
4594
+ /* @__PURE__ */ jsx(Label, { children: label }),
4595
+ displayUrl ? imageBroken ? /* @__PURE__ */ jsxs("div", {
4596
+ className: "mt-2 relative group",
4597
+ children: [/* @__PURE__ */ jsxs("div", {
4598
+ className: "min-h-20 rounded-lg border bg-kumo-muted flex items-center justify-center gap-2 text-kumo-subtle",
4599
+ children: [/* @__PURE__ */ jsx(ImageBroken, { className: "h-5 w-5" }), /* @__PURE__ */ jsx("span", {
4600
+ className: "text-sm",
4601
+ children: _t({
4602
+ id: "1pdLQw",
4603
+ message: "Image not found"
4604
+ })
4605
+ })]
4606
+ }), /* @__PURE__ */ jsxs("div", {
4607
+ className: "absolute top-2 end-2 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1",
4608
+ children: [/* @__PURE__ */ jsx(Button, {
4609
+ type: "button",
4610
+ size: "sm",
4611
+ variant: "secondary",
4612
+ onClick: () => setPickerOpen(true),
4613
+ children: _t({
4614
+ id: "o+XJ9D",
4615
+ message: "Change"
4616
+ })
4617
+ }), /* @__PURE__ */ jsx(Button, {
4618
+ type: "button",
4619
+ shape: "square",
4620
+ variant: "destructive",
4621
+ className: "h-8 w-8",
4622
+ onClick: handleRemove,
4623
+ "aria-label": _t({
4624
+ id: "5ywtDz",
4625
+ message: "Remove image"
4626
+ }),
4627
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
4628
+ })]
4629
+ })]
4630
+ }) : /* @__PURE__ */ jsxs("div", {
4631
+ className: "mt-2 relative group",
4632
+ children: [/* @__PURE__ */ jsx("img", {
4633
+ src: displayUrl,
4634
+ alt: "",
4635
+ className: "max-h-48 min-h-20 rounded-lg border object-cover",
4636
+ onError: () => setImageBroken(true)
4637
+ }), /* @__PURE__ */ jsxs("div", {
4638
+ className: "absolute top-2 end-2 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1",
4639
+ children: [/* @__PURE__ */ jsx(Button, {
4640
+ type: "button",
4641
+ size: "sm",
4642
+ variant: "secondary",
4643
+ onClick: () => setPickerOpen(true),
4644
+ children: _t({
4645
+ id: "o+XJ9D",
4646
+ message: "Change"
4647
+ })
4648
+ }), /* @__PURE__ */ jsx(Button, {
4649
+ type: "button",
4650
+ shape: "square",
4651
+ variant: "destructive",
4652
+ className: "h-8 w-8",
4653
+ onClick: handleRemove,
4654
+ "aria-label": _t({
4655
+ id: "5ywtDz",
4656
+ message: "Remove image"
4657
+ }),
4658
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
4659
+ })]
4660
+ })]
4661
+ }) : /* @__PURE__ */ jsx(Button, {
4662
+ type: "button",
4663
+ variant: "outline",
4664
+ className: "mt-2 w-full h-32 border-dashed",
4665
+ onClick: () => setPickerOpen(true),
4666
+ children: /* @__PURE__ */ jsxs("div", {
4667
+ className: "flex flex-col items-center gap-2 text-kumo-subtle",
4668
+ children: [/* @__PURE__ */ jsx(Image$1, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", { children: _t({
4669
+ id: "oDodff",
4670
+ message: "Select image"
4671
+ }) })]
4672
+ })
4673
+ }),
4674
+ /* @__PURE__ */ jsx(MediaPickerModal, {
4675
+ open: pickerOpen,
4676
+ onOpenChange: setPickerOpen,
4677
+ onSelect: handleSelect,
4678
+ mimeTypeFilters: allowedMimeTypes && allowedMimeTypes.length > 0 ? allowedMimeTypes : ["image/"],
4679
+ fieldId,
4680
+ title: _t({
4681
+ id: "pov/PW",
4682
+ message: "Select {label}",
4683
+ values: { label }
4684
+ })
4685
+ }),
4686
+ description && /* @__PURE__ */ jsx("p", {
4687
+ className: "text-xs text-kumo-subtle mt-1",
4688
+ children: description
4689
+ }),
4690
+ required && !displayUrl && /* @__PURE__ */ jsx("p", {
4691
+ className: "text-sm text-kumo-danger mt-1",
4692
+ children: _t({
4693
+ id: "B8AaMI",
4694
+ message: "This field is required"
4695
+ })
4696
+ })
4697
+ ]
4698
+ });
4699
+ }
4700
+
4411
4701
  //#endregion
4412
4702
  //#region src/components/PluginFieldErrorBoundary.tsx
4413
4703
  /**
@@ -4431,11 +4721,17 @@ var PluginFieldErrorBoundary = class extends React$1.Component {
4431
4721
  children: [
4432
4722
  /* @__PURE__ */ jsx("p", {
4433
4723
  className: "text-sm font-medium text-kumo-danger",
4434
- children: "Plugin widget error"
4724
+ children: /* @__PURE__ */ jsx(Trans, {
4725
+ id: "zyTWI0",
4726
+ message: "Plugin widget error"
4727
+ })
4435
4728
  }),
4436
4729
  /* @__PURE__ */ jsx("p", {
4437
4730
  className: "mt-1 text-xs text-kumo-subtle",
4438
- children: this.state.error?.message || "The plugin field widget failed to render."
4731
+ children: this.state.error?.message || /* @__PURE__ */ jsx(Trans, {
4732
+ id: "Q/HIiC",
4733
+ message: "The plugin field widget failed to render."
4734
+ })
4439
4735
  }),
4440
4736
  /* @__PURE__ */ jsx("button", {
4441
4737
  type: "button",
@@ -4444,7 +4740,10 @@ var PluginFieldErrorBoundary = class extends React$1.Component {
4444
4740
  hasError: false,
4445
4741
  error: void 0
4446
4742
  }),
4447
- children: "Retry"
4743
+ children: /* @__PURE__ */ jsx(Trans, {
4744
+ id: "6gRgw8",
4745
+ message: "Retry"
4746
+ })
4448
4747
  })
4449
4748
  ]
4450
4749
  });
@@ -4495,7 +4794,7 @@ function RepeaterField({ label, id, value, onChange, subFields, minItems = 0, ma
4495
4794
  const handleAdd = () => {
4496
4795
  if (maxItems && items.length >= maxItems) return;
4497
4796
  const newItem = { _key: `item-${Date.now()}` };
4498
- for (const sf of subFields) newItem[sf.slug] = sf.type === "boolean" ? false : sf.type === "number" || sf.type === "integer" ? null : "";
4797
+ for (const sf of subFields) newItem[sf.slug] = sf.type === "boolean" ? false : sf.type === "number" || sf.type === "integer" || sf.type === "image" ? null : "";
4499
4798
  emitChange([...items, newItem]);
4500
4799
  };
4501
4800
  const handleRemove = (key) => {
@@ -4703,6 +5002,12 @@ function SubFieldInput({ subField, value, onChange }) {
4703
5002
  ...Object.fromEntries((subField.options ?? []).map((opt) => [opt, opt]))
4704
5003
  }
4705
5004
  });
5005
+ case "image": return /* @__PURE__ */ jsx(ImageFieldRenderer, {
5006
+ label: subField.label,
5007
+ value: value != null && typeof value === "object" ? value : typeof value === "string" && value ? value : void 0,
5008
+ onChange: (v) => onChange(v),
5009
+ required: subField.required
5010
+ });
4706
5011
  default: return /* @__PURE__ */ jsx(Input, {
4707
5012
  label: subField.label,
4708
5013
  value: typeof value === "string" ? value : "",
@@ -5683,7 +5988,10 @@ var index_default = Suggestion;
5683
5988
  const CODE_BLOCK_LANGUAGES = [
5684
5989
  {
5685
5990
  id: "plaintext",
5686
- label: "Plain text",
5991
+ label: {
5992
+ id: "pOo4Aa",
5993
+ message: "Plain text"
5994
+ },
5687
5995
  aliases: [
5688
5996
  "text",
5689
5997
  "plain",
@@ -5692,11 +6000,17 @@ const CODE_BLOCK_LANGUAGES = [
5692
6000
  },
5693
6001
  {
5694
6002
  id: "astro",
5695
- label: "Astro"
6003
+ label: {
6004
+ id: "2qNhQ4",
6005
+ message: "Astro"
6006
+ }
5696
6007
  },
5697
6008
  {
5698
6009
  id: "bash",
5699
- label: "Bash",
6010
+ label: {
6011
+ id: "DjECRV",
6012
+ message: "Bash"
6013
+ },
5700
6014
  aliases: [
5701
6015
  "sh",
5702
6016
  "shell",
@@ -5705,137 +6019,227 @@ const CODE_BLOCK_LANGUAGES = [
5705
6019
  },
5706
6020
  {
5707
6021
  id: "c",
5708
- label: "C"
6022
+ label: {
6023
+ id: "qvh3Th",
6024
+ message: "C"
6025
+ }
5709
6026
  },
5710
6027
  {
5711
6028
  id: "cpp",
5712
- label: "C++",
6029
+ label: {
6030
+ id: "ZfVDhL",
6031
+ message: "C++"
6032
+ },
5713
6033
  aliases: ["c++"]
5714
6034
  },
5715
6035
  {
5716
6036
  id: "csharp",
5717
- label: "C#",
6037
+ label: {
6038
+ id: "JMN/Cx",
6039
+ message: "C#"
6040
+ },
5718
6041
  aliases: ["cs", "c#"]
5719
6042
  },
5720
6043
  {
5721
6044
  id: "css",
5722
- label: "CSS"
6045
+ label: {
6046
+ id: "Tfspdu",
6047
+ message: "CSS"
6048
+ }
5723
6049
  },
5724
6050
  {
5725
6051
  id: "diff",
5726
- label: "Diff",
6052
+ label: {
6053
+ id: "bspG20",
6054
+ message: "Diff"
6055
+ },
5727
6056
  aliases: ["patch"]
5728
6057
  },
5729
6058
  {
5730
6059
  id: "dockerfile",
5731
- label: "Dockerfile",
6060
+ label: {
6061
+ id: "xbo2Nv",
6062
+ message: "Dockerfile"
6063
+ },
5732
6064
  aliases: ["docker"]
5733
6065
  },
5734
6066
  {
5735
6067
  id: "go",
5736
- label: "Go",
6068
+ label: {
6069
+ id: "4pSxwB",
6070
+ message: "Go"
6071
+ },
5737
6072
  aliases: ["golang"]
5738
6073
  },
5739
6074
  {
5740
6075
  id: "graphql",
5741
- label: "GraphQL",
6076
+ label: {
6077
+ id: "gBiL6J",
6078
+ message: "GraphQL"
6079
+ },
5742
6080
  aliases: ["gql"]
5743
6081
  },
5744
6082
  {
5745
6083
  id: "html",
5746
- label: "HTML"
6084
+ label: {
6085
+ id: "FBknns",
6086
+ message: "HTML"
6087
+ }
5747
6088
  },
5748
6089
  {
5749
6090
  id: "java",
5750
- label: "Java"
6091
+ label: {
6092
+ id: "d/bW+Y",
6093
+ message: "Java"
6094
+ }
5751
6095
  },
5752
6096
  {
5753
6097
  id: "javascript",
5754
- label: "JavaScript",
6098
+ label: {
6099
+ id: "k8pHx9",
6100
+ message: "JavaScript"
6101
+ },
5755
6102
  aliases: ["js"]
5756
6103
  },
5757
6104
  {
5758
6105
  id: "json",
5759
- label: "JSON"
6106
+ label: {
6107
+ id: "B2Zb/F",
6108
+ message: "JSON"
6109
+ }
5760
6110
  },
5761
6111
  {
5762
6112
  id: "jsx",
5763
- label: "JSX"
6113
+ label: {
6114
+ id: "ijupPe",
6115
+ message: "JSX"
6116
+ }
5764
6117
  },
5765
6118
  {
5766
6119
  id: "kotlin",
5767
- label: "Kotlin",
6120
+ label: {
6121
+ id: "ouqXGV",
6122
+ message: "Kotlin"
6123
+ },
5768
6124
  aliases: ["kt"]
5769
6125
  },
5770
6126
  {
5771
6127
  id: "markdown",
5772
- label: "Markdown",
6128
+ label: {
6129
+ id: "u6Hp4N",
6130
+ message: "Markdown"
6131
+ },
5773
6132
  aliases: ["md"]
5774
6133
  },
5775
6134
  {
5776
6135
  id: "mdx",
5777
- label: "MDX"
6136
+ label: {
6137
+ id: "6TGIsL",
6138
+ message: "MDX"
6139
+ }
5778
6140
  },
5779
6141
  {
5780
6142
  id: "php",
5781
- label: "PHP"
6143
+ label: {
6144
+ id: "Zw6ISu",
6145
+ message: "PHP"
6146
+ }
5782
6147
  },
5783
6148
  {
5784
6149
  id: "python",
5785
- label: "Python",
6150
+ label: {
6151
+ id: "zY6PMh",
6152
+ message: "Python"
6153
+ },
5786
6154
  aliases: ["py"]
5787
6155
  },
5788
6156
  {
5789
6157
  id: "ruby",
5790
- label: "Ruby",
6158
+ label: {
6159
+ id: "7jTlsu",
6160
+ message: "Ruby"
6161
+ },
5791
6162
  aliases: ["rb"]
5792
6163
  },
5793
6164
  {
5794
6165
  id: "rust",
5795
- label: "Rust",
6166
+ label: {
6167
+ id: "Sc8PMh",
6168
+ message: "Rust"
6169
+ },
5796
6170
  aliases: ["rs"]
5797
6171
  },
5798
6172
  {
5799
6173
  id: "scss",
5800
- label: "SCSS",
6174
+ label: {
6175
+ id: "xEGQEX",
6176
+ message: "SCSS"
6177
+ },
5801
6178
  aliases: ["sass"]
5802
6179
  },
5803
6180
  {
5804
6181
  id: "sql",
5805
- label: "SQL"
6182
+ label: {
6183
+ id: "mZT1Nu",
6184
+ message: "SQL"
6185
+ }
5806
6186
  },
5807
6187
  {
5808
6188
  id: "svelte",
5809
- label: "Svelte"
6189
+ label: {
6190
+ id: "I0X6aq",
6191
+ message: "Svelte"
6192
+ }
5810
6193
  },
5811
6194
  {
5812
6195
  id: "swift",
5813
- label: "Swift"
6196
+ label: {
6197
+ id: "D8sGaA",
6198
+ message: "Swift"
6199
+ }
5814
6200
  },
5815
6201
  {
5816
6202
  id: "toml",
5817
- label: "TOML"
6203
+ label: {
6204
+ id: "ZmWJqk",
6205
+ message: "TOML"
6206
+ }
5818
6207
  },
5819
6208
  {
5820
6209
  id: "tsx",
5821
- label: "TSX"
6210
+ label: {
6211
+ id: "lFP3br",
6212
+ message: "TSX"
6213
+ }
5822
6214
  },
5823
6215
  {
5824
6216
  id: "typescript",
5825
- label: "TypeScript",
6217
+ label: {
6218
+ id: "49rpnf",
6219
+ message: "TypeScript"
6220
+ },
5826
6221
  aliases: ["ts"]
5827
6222
  },
5828
6223
  {
5829
6224
  id: "vue",
5830
- label: "Vue"
6225
+ label: {
6226
+ id: "M6Uejz",
6227
+ message: "Vue"
6228
+ }
5831
6229
  },
5832
6230
  {
5833
6231
  id: "xml",
5834
- label: "XML"
6232
+ label: {
6233
+ id: "8W/ILN",
6234
+ message: "XML"
6235
+ }
5835
6236
  },
5836
6237
  {
5837
6238
  id: "yaml",
5838
- label: "YAML",
6239
+ label: {
6240
+ id: "h51QFW",
6241
+ message: "YAML"
6242
+ },
5839
6243
  aliases: ["yml"]
5840
6244
  }
5841
6245
  ];
@@ -5845,11 +6249,11 @@ const CODE_BLOCK_LANGUAGES = [
5845
6249
  */
5846
6250
  function findLanguage(value) {
5847
6251
  if (!value) return null;
5848
- const needle = value.trim().toLowerCase();
5849
- if (!needle) return null;
6252
+ const searchText = value.trim().toLowerCase();
6253
+ if (!searchText) return null;
5850
6254
  for (const lang of CODE_BLOCK_LANGUAGES) {
5851
- if (lang.id === needle) return lang;
5852
- if (lang.aliases?.includes(needle)) return lang;
6255
+ if (lang.id === searchText) return lang;
6256
+ if (lang.aliases?.includes(searchText)) return lang;
5853
6257
  }
5854
6258
  return null;
5855
6259
  }
@@ -5882,8 +6286,11 @@ function normalizeLanguage(value) {
5882
6286
  * Human-readable label for a stored language id. Falls back to the id itself
5883
6287
  * for unknown values so the editor never shows "undefined".
5884
6288
  */
5885
- function languageLabel(value) {
5886
- if (!value) return "Plain text";
6289
+ function languageLabelDescriptor(value) {
6290
+ if (!value) return {
6291
+ id: "pOo4Aa",
6292
+ message: "Plain text"
6293
+ };
5887
6294
  const match = findLanguage(value);
5888
6295
  if (match) return match.label;
5889
6296
  return value;
@@ -5906,37 +6313,51 @@ function languageLabel(value) {
5906
6313
  * sanitized to a single safe CSS class token via `normalizeLanguage` so the
5907
6314
  * frontend's `language-{id}` class stays well-formed.
5908
6315
  */
5909
- const LANGUAGE_ITEMS = CODE_BLOCK_LANGUAGES.map((l) => l.label);
5910
- function filterLanguages(item, query) {
5911
- if (!query) return true;
5912
- const needle = query.toLowerCase();
5913
- const lang = CODE_BLOCK_LANGUAGES.find((l) => l.label === item);
5914
- if (!lang) return false;
5915
- if (lang.label.toLowerCase().includes(needle)) return true;
5916
- if (lang.id.toLowerCase().includes(needle)) return true;
5917
- return lang.aliases?.some((alias) => alias.toLowerCase().includes(needle)) ?? false;
5918
- }
5919
6316
  function CodeBlockNodeView({ node, updateAttributes, selected }) {
5920
6317
  const { _: _t } = useLingui();
5921
6318
  const [isEditing, setIsEditing] = React$1.useState(false);
5922
6319
  const storedLanguage = typeof node.attrs.language === "string" ? node.attrs.language : "";
5923
- const [draft, setDraft] = React$1.useState(() => languageLabel(storedLanguage));
6320
+ const labelText = React$1.useCallback((value) => {
6321
+ const label = languageLabelDescriptor(value);
6322
+ return typeof label === "string" ? label : _t(label);
6323
+ }, [_t]);
6324
+ const languageItems = React$1.useMemo(() => CODE_BLOCK_LANGUAGES.map((language) => _t(language.label)), [_t]);
6325
+ const findLanguageByDisplayLabel = React$1.useCallback((label) => CODE_BLOCK_LANGUAGES.find((language) => _t(language.label) === label), [_t]);
6326
+ const filterLanguages = React$1.useCallback((item, query) => {
6327
+ if (!query) return true;
6328
+ const searchText = query.toLowerCase();
6329
+ const lang = findLanguageByDisplayLabel(item);
6330
+ if (!lang) return false;
6331
+ if (_t(lang.label).toLowerCase().includes(searchText)) return true;
6332
+ if (lang.id.toLowerCase().includes(searchText)) return true;
6333
+ return lang.aliases?.some((alias) => alias.toLowerCase().includes(searchText)) ?? false;
6334
+ }, [findLanguageByDisplayLabel, _t]);
6335
+ const [draft, setDraft] = React$1.useState(() => labelText(storedLanguage));
5924
6336
  const popoverRef = React$1.useRef(null);
5925
6337
  React$1.useEffect(() => {
5926
- if (!isEditing) setDraft(languageLabel(storedLanguage));
5927
- }, [storedLanguage, isEditing]);
6338
+ if (!isEditing) setDraft(labelText(storedLanguage));
6339
+ }, [
6340
+ storedLanguage,
6341
+ isEditing,
6342
+ labelText
6343
+ ]);
5928
6344
  const openPicker = React$1.useCallback(() => {
5929
- setDraft(storedLanguage ? languageLabel(storedLanguage) : "");
6345
+ setDraft(storedLanguage ? labelText(storedLanguage) : "");
5930
6346
  setIsEditing(true);
5931
- }, [storedLanguage]);
6347
+ }, [storedLanguage, labelText]);
5932
6348
  const closePicker = React$1.useCallback(() => {
5933
6349
  setIsEditing(false);
5934
- setDraft(languageLabel(storedLanguage));
5935
- }, [storedLanguage]);
6350
+ setDraft(labelText(storedLanguage));
6351
+ }, [storedLanguage, labelText]);
5936
6352
  const commit = React$1.useCallback((value) => {
5937
- updateAttributes({ language: normalizeLanguage(value ?? draft) ?? null });
6353
+ const raw = value ?? draft;
6354
+ updateAttributes({ language: findLanguageByDisplayLabel(raw)?.id ?? normalizeLanguage(raw) ?? null });
5938
6355
  setIsEditing(false);
5939
- }, [draft, updateAttributes]);
6356
+ }, [
6357
+ draft,
6358
+ findLanguageByDisplayLabel,
6359
+ updateAttributes
6360
+ ]);
5940
6361
  const handleKeyDown = (e) => {
5941
6362
  if (e.key === "Enter") {
5942
6363
  e.preventDefault();
@@ -5955,7 +6376,7 @@ function CodeBlockNodeView({ node, updateAttributes, selected }) {
5955
6376
  document.addEventListener("mousedown", onMouseDown);
5956
6377
  return () => document.removeEventListener("mousedown", onMouseDown);
5957
6378
  }, [isEditing, closePicker]);
5958
- const label = languageLabel(storedLanguage);
6379
+ const label = labelText(storedLanguage);
5959
6380
  const chipPersistent = isEditing || Boolean(storedLanguage) || selected;
5960
6381
  return /* @__PURE__ */ jsxs(NodeViewWrapper, {
5961
6382
  className: "group relative my-4",
@@ -5972,7 +6393,7 @@ function CodeBlockNodeView({ node, updateAttributes, selected }) {
5972
6393
  onKeyDown: handleKeyDown,
5973
6394
  children: [
5974
6395
  /* @__PURE__ */ jsxs(Autocomplete, {
5975
- items: LANGUAGE_ITEMS,
6396
+ items: languageItems,
5976
6397
  value: draft,
5977
6398
  onValueChange: (next) => setDraft(next),
5978
6399
  filter: filterLanguages,
@@ -11711,8 +12132,7 @@ function ContentEditor({ collection, collectionLabel, item, fields, isNew, entry
11711
12132
  className: "mt-1 flex flex-wrap items-center gap-1.5",
11712
12133
  children: supportsDrafts ? /* @__PURE__ */ jsxs(Fragment, { children: [
11713
12134
  isLive && /* @__PURE__ */ jsx(Badge, {
11714
- variant: "primary",
11715
- className: "text-white",
12135
+ variant: "success",
11716
12136
  children: _t({
11717
12137
  id: "u3wRF+",
11718
12138
  message: "Published"
@@ -12295,141 +12715,6 @@ function JsonFieldEditor({ label, id, value, onChange, required }) {
12295
12715
  children: error
12296
12716
  })] });
12297
12717
  }
12298
- function ImageFieldRenderer({ id, label, description, value, onChange, required, allowedMimeTypes, fieldId }) {
12299
- const { _: _t5 } = useLingui();
12300
- const [pickerOpen, setPickerOpen] = React$1.useState(false);
12301
- const [imageBroken, setImageBroken] = React$1.useState(false);
12302
- const displayUrl = typeof value === "string" ? value : value?.previewUrl || value?.src || (value && (!value.provider || value.provider === "local") ? `/_emdash/api/media/file/${typeof value.meta?.storageKey === "string" ? value.meta.storageKey : value.id}` : void 0);
12303
- React$1.useEffect(() => {
12304
- setImageBroken(false);
12305
- }, [displayUrl]);
12306
- const handleSelect = (item) => {
12307
- const isLocalProvider = !item.provider || item.provider === "local";
12308
- onChange({
12309
- id: item.id,
12310
- provider: item.provider || "local",
12311
- previewUrl: isLocalProvider ? void 0 : item.url,
12312
- alt: item.alt || "",
12313
- width: item.width,
12314
- height: item.height,
12315
- meta: isLocalProvider ? {
12316
- ...item.meta,
12317
- storageKey: item.storageKey
12318
- } : item.meta
12319
- });
12320
- };
12321
- const handleRemove = () => {
12322
- onChange(null);
12323
- };
12324
- return /* @__PURE__ */ jsxs("div", {
12325
- id,
12326
- children: [
12327
- /* @__PURE__ */ jsx(Label, { children: label }),
12328
- displayUrl ? imageBroken ? /* @__PURE__ */ jsxs("div", {
12329
- className: "mt-2 relative group",
12330
- children: [/* @__PURE__ */ jsxs("div", {
12331
- className: "min-h-20 rounded-lg border bg-kumo-muted flex items-center justify-center gap-2 text-kumo-subtle",
12332
- children: [/* @__PURE__ */ jsx(ImageBroken, { className: "h-5 w-5" }), /* @__PURE__ */ jsx("span", {
12333
- className: "text-sm",
12334
- children: _t5({
12335
- id: "1pdLQw",
12336
- message: "Image not found"
12337
- })
12338
- })]
12339
- }), /* @__PURE__ */ jsxs("div", {
12340
- className: "absolute top-2 end-2 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1",
12341
- children: [/* @__PURE__ */ jsx(Button, {
12342
- type: "button",
12343
- size: "sm",
12344
- variant: "secondary",
12345
- onClick: () => setPickerOpen(true),
12346
- children: _t5({
12347
- id: "o+XJ9D",
12348
- message: "Change"
12349
- })
12350
- }), /* @__PURE__ */ jsx(Button, {
12351
- type: "button",
12352
- shape: "square",
12353
- variant: "destructive",
12354
- className: "h-8 w-8",
12355
- onClick: handleRemove,
12356
- "aria-label": _t5({
12357
- id: "5ywtDz",
12358
- message: "Remove image"
12359
- }),
12360
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
12361
- })]
12362
- })]
12363
- }) : /* @__PURE__ */ jsxs("div", {
12364
- className: "mt-2 relative group",
12365
- children: [/* @__PURE__ */ jsx("img", {
12366
- src: displayUrl,
12367
- alt: "",
12368
- className: "max-h-48 min-h-20 rounded-lg border object-cover",
12369
- onError: () => setImageBroken(true)
12370
- }), /* @__PURE__ */ jsxs("div", {
12371
- className: "absolute top-2 end-2 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1",
12372
- children: [/* @__PURE__ */ jsx(Button, {
12373
- type: "button",
12374
- size: "sm",
12375
- variant: "secondary",
12376
- onClick: () => setPickerOpen(true),
12377
- children: _t5({
12378
- id: "o+XJ9D",
12379
- message: "Change"
12380
- })
12381
- }), /* @__PURE__ */ jsx(Button, {
12382
- type: "button",
12383
- shape: "square",
12384
- variant: "destructive",
12385
- className: "h-8 w-8",
12386
- onClick: handleRemove,
12387
- "aria-label": _t5({
12388
- id: "5ywtDz",
12389
- message: "Remove image"
12390
- }),
12391
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
12392
- })]
12393
- })]
12394
- }) : /* @__PURE__ */ jsx(Button, {
12395
- type: "button",
12396
- variant: "outline",
12397
- className: "mt-2 w-full h-32 border-dashed",
12398
- onClick: () => setPickerOpen(true),
12399
- children: /* @__PURE__ */ jsxs("div", {
12400
- className: "flex flex-col items-center gap-2 text-kumo-subtle",
12401
- children: [/* @__PURE__ */ jsx(Image$1, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", { children: _t5({
12402
- id: "oDodff",
12403
- message: "Select image"
12404
- }) })]
12405
- })
12406
- }),
12407
- /* @__PURE__ */ jsx(MediaPickerModal, {
12408
- open: pickerOpen,
12409
- onOpenChange: setPickerOpen,
12410
- onSelect: handleSelect,
12411
- mimeTypeFilters: allowedMimeTypes && allowedMimeTypes.length > 0 ? allowedMimeTypes : ["image/"],
12412
- fieldId,
12413
- title: _t5({
12414
- id: "pov/PW",
12415
- message: "Select {label}",
12416
- values: { label }
12417
- })
12418
- }),
12419
- description && /* @__PURE__ */ jsx("p", {
12420
- className: "text-xs text-kumo-subtle mt-1",
12421
- children: description
12422
- }),
12423
- required && !displayUrl && /* @__PURE__ */ jsx("p", {
12424
- className: "text-sm text-kumo-danger mt-1",
12425
- children: _t5({
12426
- id: "B8AaMI",
12427
- message: "This field is required"
12428
- })
12429
- })
12430
- ]
12431
- });
12432
- }
12433
12718
  /**
12434
12719
  * File field with media picker
12435
12720
  *
@@ -12437,7 +12722,7 @@ function ImageFieldRenderer({ id, label, description, value, onChange, required,
12437
12722
  * icon, filename, and size instead of an image preview.
12438
12723
  */
12439
12724
  function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTypes, fieldId }) {
12440
- const { _: _t6 } = useLingui();
12725
+ const { _: _t5 } = useLingui();
12441
12726
  const [pickerOpen, setPickerOpen] = React$1.useState(false);
12442
12727
  const normalized = React$1.useMemo(() => {
12443
12728
  if (!value) return null;
@@ -12448,14 +12733,14 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12448
12733
  const externalUrl = !isLocal && value.src && isSafeUrl$1(value.src) ? value.src : void 0;
12449
12734
  return {
12450
12735
  displayUrl: localUrl ?? externalUrl,
12451
- filename: value.filename || _t6({
12736
+ filename: value.filename || _t5({
12452
12737
  id: "cChtk1",
12453
12738
  message: "Untitled file"
12454
12739
  }),
12455
12740
  mimeType: value.mimeType || "",
12456
12741
  size: value.size
12457
12742
  };
12458
- }, [value, _t6]);
12743
+ }, [value, _t5]);
12459
12744
  const handleSelect = (item) => {
12460
12745
  const isLocalProvider = !item.provider || item.provider === "local";
12461
12746
  onChange({
@@ -12516,7 +12801,7 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12516
12801
  size: "sm",
12517
12802
  variant: "secondary",
12518
12803
  onClick: () => setPickerOpen(true),
12519
- children: _t6({
12804
+ children: _t5({
12520
12805
  id: "o+XJ9D",
12521
12806
  message: "Change"
12522
12807
  })
@@ -12526,7 +12811,7 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12526
12811
  variant: "destructive",
12527
12812
  className: "h-8 w-8",
12528
12813
  onClick: handleRemove,
12529
- "aria-label": _t6({
12814
+ "aria-label": _t5({
12530
12815
  id: "HND1q3",
12531
12816
  message: "Remove {label}",
12532
12817
  values: { label }
@@ -12540,14 +12825,14 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12540
12825
  variant: "outline",
12541
12826
  className: "mt-2 w-full h-32 border-dashed",
12542
12827
  onClick: () => setPickerOpen(true),
12543
- "aria-label": _t6({
12828
+ "aria-label": _t5({
12544
12829
  id: "pov/PW",
12545
12830
  message: "Select {label}",
12546
12831
  values: { label }
12547
12832
  }),
12548
12833
  children: /* @__PURE__ */ jsxs("div", {
12549
12834
  className: "flex flex-col items-center gap-2 text-kumo-subtle",
12550
- children: [/* @__PURE__ */ jsx(Paperclip, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", { children: _t6({
12835
+ children: [/* @__PURE__ */ jsx(Paperclip, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", { children: _t5({
12551
12836
  id: "J6WI1B",
12552
12837
  message: "Select file"
12553
12838
  }) })]
@@ -12561,7 +12846,7 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12561
12846
  fieldId,
12562
12847
  hideUrlInput: true,
12563
12848
  mediaKind: "file",
12564
- title: _t6({
12849
+ title: _t5({
12565
12850
  id: "pov/PW",
12566
12851
  message: "Select {label}",
12567
12852
  values: { label }
@@ -12569,7 +12854,7 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12569
12854
  }),
12570
12855
  required && !normalized && /* @__PURE__ */ jsx("p", {
12571
12856
  className: "text-sm text-kumo-danger mt-1",
12572
- children: _t6({
12857
+ children: _t5({
12573
12858
  id: "B8AaMI",
12574
12859
  message: "This field is required"
12575
12860
  })
@@ -12578,7 +12863,7 @@ function FileFieldRenderer({ id, label, value, onChange, required, allowedMimeTy
12578
12863
  });
12579
12864
  }
12580
12865
  function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange, onQuickCreate, onQuickEdit, entryLocale, i18n, bylinesLoaded = true }) {
12581
- const { _: _t7 } = useLingui();
12866
+ const { _: _t6 } = useLingui();
12582
12867
  const [search, setSearch] = React$1.useState("");
12583
12868
  const debouncedSearch = useDebouncedValue$1(search, 300);
12584
12869
  const [quickName, setQuickName] = React$1.useState("");
@@ -12661,7 +12946,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12661
12946
  className: "rounded border border-dashed p-3 text-sm space-y-2",
12662
12947
  children: [/* @__PURE__ */ jsx("p", {
12663
12948
  className: "text-kumo-subtle",
12664
- children: _t7({
12949
+ children: _t6({
12665
12950
  id: "Tmb8Fw",
12666
12951
  message: "No bylines available in {entryLocale}. Create a variant from the Bylines page before crediting one on this entry.",
12667
12952
  values: { entryLocale }
@@ -12671,7 +12956,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12671
12956
  search: { locale: entryLocale ?? void 0 },
12672
12957
  variant: "secondary",
12673
12958
  size: "sm",
12674
- children: _t7({
12959
+ children: _t6({
12675
12960
  id: "yXD9HA",
12676
12961
  message: "Manage bylines in {entryLocale}",
12677
12962
  values: { entryLocale }
@@ -12684,18 +12969,18 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12684
12969
  /* @__PURE__ */ jsx(Input, {
12685
12970
  value: search,
12686
12971
  onChange: (e) => setSearch(e.target.value),
12687
- placeholder: _t7({
12972
+ placeholder: _t6({
12688
12973
  id: "96Um6i",
12689
12974
  message: "Search bylines to add..."
12690
12975
  }),
12691
- "aria-label": _t7({
12976
+ "aria-label": _t6({
12692
12977
  id: "4L2LjM",
12693
12978
  message: "Search bylines"
12694
12979
  })
12695
12980
  }),
12696
12981
  searchEnabled && searchResults.isLoading ? /* @__PURE__ */ jsx("p", {
12697
12982
  className: "text-sm text-kumo-subtle",
12698
- children: _t7({
12983
+ children: _t6({
12699
12984
  id: "Du+zn+",
12700
12985
  message: "Searching..."
12701
12986
  })
@@ -12716,7 +13001,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12716
13001
  })]
12717
13002
  }), /* @__PURE__ */ jsx("span", {
12718
13003
  className: "text-xs text-kumo-subtle",
12719
- children: _t7({
13004
+ children: _t6({
12720
13005
  id: "m16xKo",
12721
13006
  message: "Add"
12722
13007
  })
@@ -12724,20 +13009,20 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12724
13009
  }) }, b.id))
12725
13010
  }) : searchEnabled && searchResults.isError ? /* @__PURE__ */ jsx("p", {
12726
13011
  className: "text-sm text-kumo-danger",
12727
- children: _t7({
13012
+ children: _t6({
12728
13013
  id: "617r+T",
12729
13014
  message: "Couldn't search bylines. Please try again."
12730
13015
  })
12731
13016
  }) : searchEnabled ? /* @__PURE__ */ jsx("p", {
12732
13017
  className: "text-sm text-kumo-subtle",
12733
- children: _t7({
13018
+ children: _t6({
12734
13019
  id: "ncgkI9",
12735
13020
  message: "No matching bylines."
12736
13021
  })
12737
13022
  }) : null,
12738
13023
  hasMoreResults && /* @__PURE__ */ jsx("p", {
12739
13024
  className: "text-xs text-kumo-subtle",
12740
- children: _t7({
13025
+ children: _t6({
12741
13026
  id: "7Jpj2/",
12742
13027
  message: "Keep typing to narrow down more bylines."
12743
13028
  })
@@ -12767,7 +13052,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12767
13052
  variant: "ghost",
12768
13053
  size: "sm",
12769
13054
  onClick: () => move(index, -1),
12770
- children: _t7({
13055
+ children: _t6({
12771
13056
  id: "n+PHuv",
12772
13057
  message: "Up"
12773
13058
  })
@@ -12777,7 +13062,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12777
13062
  variant: "ghost",
12778
13063
  size: "sm",
12779
13064
  onClick: () => move(index, 1),
12780
- children: _t7({
13065
+ children: _t6({
12781
13066
  id: "gUjkl/",
12782
13067
  message: "Down"
12783
13068
  })
@@ -12787,7 +13072,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12787
13072
  variant: "ghost",
12788
13073
  size: "sm",
12789
13074
  onClick: () => openEditByline(byline),
12790
- children: _t7({
13075
+ children: _t6({
12791
13076
  id: "ePK91l",
12792
13077
  message: "Edit"
12793
13078
  })
@@ -12797,7 +13082,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12797
13082
  variant: "destructive",
12798
13083
  size: "sm",
12799
13084
  onClick: () => onChange(credits.filter((_, i) => i !== index)),
12800
- children: _t7({
13085
+ children: _t6({
12801
13086
  id: "t/YqKh",
12802
13087
  message: "Remove"
12803
13088
  })
@@ -12805,7 +13090,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12805
13090
  ]
12806
13091
  })]
12807
13092
  }), /* @__PURE__ */ jsx(Input, {
12808
- label: _t7({
13093
+ label: _t6({
12809
13094
  id: "QeScoL",
12810
13095
  message: "Role label"
12811
13096
  }),
@@ -12825,7 +13110,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12825
13110
  })
12826
13111
  }) : /* @__PURE__ */ jsx("p", {
12827
13112
  className: "text-sm text-kumo-subtle",
12828
- children: _t7({
13113
+ children: _t6({
12829
13114
  id: "dyZY24",
12830
13115
  message: "No bylines selected."
12831
13116
  })
@@ -12834,7 +13119,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12834
13119
  ...p,
12835
13120
  type: "button",
12836
13121
  variant: "secondary",
12837
- children: _t7({
13122
+ children: _t6({
12838
13123
  id: "gqa8eq",
12839
13124
  message: "Quick create byline"
12840
13125
  })
@@ -12844,7 +13129,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12844
13129
  children: [
12845
13130
  /* @__PURE__ */ jsx(Dialog.Title, {
12846
13131
  className: "text-lg font-semibold",
12847
- children: _t7({
13132
+ children: _t6({
12848
13133
  id: "d6HWlw",
12849
13134
  message: "Create byline"
12850
13135
  })
@@ -12853,7 +13138,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12853
13138
  className: "mt-4 space-y-3",
12854
13139
  children: [
12855
13140
  /* @__PURE__ */ jsx(Input, {
12856
- label: _t7({
13141
+ label: _t6({
12857
13142
  id: "pfa8F0",
12858
13143
  message: "Display name"
12859
13144
  }),
@@ -12864,7 +13149,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12864
13149
  }
12865
13150
  }),
12866
13151
  /* @__PURE__ */ jsx(Input, {
12867
- label: _t7({
13152
+ label: _t6({
12868
13153
  id: "L85WcV",
12869
13154
  message: "Slug"
12870
13155
  }),
@@ -12886,7 +13171,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12886
13171
  resetQuickCreate();
12887
13172
  p.onClick?.(e);
12888
13173
  },
12889
- children: _t7({
13174
+ children: _t6({
12890
13175
  id: "dEgA5A",
12891
13176
  message: "Cancel"
12892
13177
  })
@@ -12907,7 +13192,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12907
13192
  }]);
12908
13193
  resetQuickCreate();
12909
13194
  } catch (err) {
12910
- setQuickError(err instanceof Error ? err.message : _t7({
13195
+ setQuickError(err instanceof Error ? err.message : _t6({
12911
13196
  id: "Kd9Ewv",
12912
13197
  message: "Failed to create byline"
12913
13198
  }));
@@ -12915,10 +13200,10 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12915
13200
  setIsCreating(false);
12916
13201
  }
12917
13202
  },
12918
- children: isCreating ? _t7({
13203
+ children: isCreating ? _t6({
12919
13204
  id: "HM56Bx",
12920
13205
  message: "Creating..."
12921
- }) : _t7({
13206
+ }) : _t6({
12922
13207
  id: "hYgDIe",
12923
13208
  message: "Create"
12924
13209
  })
@@ -12935,7 +13220,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12935
13220
  children: [
12936
13221
  /* @__PURE__ */ jsx(Dialog.Title, {
12937
13222
  className: "text-lg font-semibold",
12938
- children: _t7({
13223
+ children: _t6({
12939
13224
  id: "d9lVyw",
12940
13225
  message: "Edit byline"
12941
13226
  })
@@ -12944,7 +13229,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12944
13229
  className: "mt-4 space-y-3",
12945
13230
  children: [
12946
13231
  /* @__PURE__ */ jsx(Input, {
12947
- label: _t7({
13232
+ label: _t6({
12948
13233
  id: "pfa8F0",
12949
13234
  message: "Display name"
12950
13235
  }),
@@ -12955,7 +13240,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12955
13240
  }
12956
13241
  }),
12957
13242
  /* @__PURE__ */ jsx(Input, {
12958
- label: _t7({
13243
+ label: _t6({
12959
13244
  id: "L85WcV",
12960
13245
  message: "Slug"
12961
13246
  }),
@@ -12974,7 +13259,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12974
13259
  type: "button",
12975
13260
  variant: "secondary",
12976
13261
  onClick: resetQuickEdit,
12977
- children: _t7({
13262
+ children: _t6({
12978
13263
  id: "dEgA5A",
12979
13264
  message: "Cancel"
12980
13265
  })
@@ -12991,7 +13276,7 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12991
13276
  });
12992
13277
  resetQuickEdit();
12993
13278
  } catch (err) {
12994
- setEditError(err instanceof Error ? err.message : _t7({
13279
+ setEditError(err instanceof Error ? err.message : _t6({
12995
13280
  id: "fd6o+d",
12996
13281
  message: "Failed to update byline"
12997
13282
  }));
@@ -12999,10 +13284,10 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
12999
13284
  setIsEditing(false);
13000
13285
  }
13001
13286
  },
13002
- children: isEditing ? _t7({
13287
+ children: isEditing ? _t6({
13003
13288
  id: "XvjC4F",
13004
13289
  message: "Saving..."
13005
- }) : _t7({
13290
+ }) : _t6({
13006
13291
  id: "tfDRzk",
13007
13292
  message: "Save"
13008
13293
  })
@@ -13015,9 +13300,9 @@ function BylineCreditsEditor({ credits, bylines, selectedBylineDetails, onChange
13015
13300
  });
13016
13301
  }
13017
13302
  function AuthorSelector({ authorId, users, onChange }) {
13018
- const { _: _t8 } = useLingui();
13303
+ const { _: _t7 } = useLingui();
13019
13304
  const currentAuthor = users.find((u) => u.id === authorId);
13020
- const authorItems = { unassigned: _t8({
13305
+ const authorItems = { unassigned: _t7({
13021
13306
  id: "EbMPZJ",
13022
13307
  message: "Unassigned"
13023
13308
  }) };
@@ -13032,7 +13317,7 @@ function AuthorSelector({ authorId, users, onChange }) {
13032
13317
  value: "unassigned",
13033
13318
  children: /* @__PURE__ */ jsx("span", {
13034
13319
  className: "text-kumo-subtle",
13035
- children: _t8({
13320
+ children: _t7({
13036
13321
  id: "EbMPZJ",
13037
13322
  message: "Unassigned"
13038
13323
  })
@@ -14952,6 +15237,10 @@ function FieldEditor({ open, onOpenChange, field, onSave, isSaving }) {
14952
15237
  url: _t({
14953
15238
  id: "IagCbF",
14954
15239
  message: "URL"
15240
+ }),
15241
+ image: _t({
15242
+ id: "hG89Ed",
15243
+ message: "Image"
14955
15244
  })
14956
15245
  }
14957
15246
  }) })]
@@ -15375,7 +15664,10 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
15375
15664
  }),
15376
15665
  value: labelSingular,
15377
15666
  onChange: (e) => handleSingularLabelChange(e.target.value),
15378
- placeholder: "Post",
15667
+ placeholder: _t({
15668
+ id: "y28hnO",
15669
+ message: "Post"
15670
+ }),
15379
15671
  disabled: isFromCode
15380
15672
  }),
15381
15673
  /* @__PURE__ */ jsx(Input, {
@@ -15385,7 +15677,10 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
15385
15677
  }),
15386
15678
  value: label,
15387
15679
  onChange: (e) => handleLabelChange(e.target.value),
15388
- placeholder: "Posts",
15680
+ placeholder: _t({
15681
+ id: "+owNNn",
15682
+ message: "Posts"
15683
+ }),
15389
15684
  disabled: isFromCode
15390
15685
  }),
15391
15686
  isNew && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input, {
@@ -15448,7 +15743,10 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
15448
15743
  ] }),
15449
15744
  /* @__PURE__ */ jsxs("div", {
15450
15745
  className: "space-y-3",
15451
- children: [/* @__PURE__ */ jsx(Label, { children: "Features" }), SUPPORT_OPTIONS.map((option) => /* @__PURE__ */ jsx("div", {
15746
+ children: [/* @__PURE__ */ jsx(Label, { children: _t({
15747
+ id: "PpZkda",
15748
+ message: "Features"
15749
+ }) }), SUPPORT_OPTIONS.map((option) => /* @__PURE__ */ jsx("div", {
15452
15750
  className: cn("p-2 rounded-md hover:bg-kumo-tint/50", isFromCode && "opacity-60"),
15453
15751
  children: /* @__PURE__ */ jsx(Checkbox, {
15454
15752
  checked: supports.includes(option.value),
@@ -20613,6 +20911,7 @@ function MediaDetailPanel({ item, onClose, onDeleted }) {
20613
20911
  setCaption(item.caption ?? "");
20614
20912
  }
20615
20913
  }, [item]);
20914
+ const fileUrl = item ? new URL(item.url, window.location.origin).href : "";
20616
20915
  const hasChanges = React$1.useMemo(() => {
20617
20916
  if (!item) return false;
20618
20917
  return filename !== item.filename || alt !== (item.alt ?? "") || caption !== (item.caption ?? "");
@@ -20780,6 +21079,28 @@ function MediaDetailPanel({ item, onClose, onDeleted }) {
20780
21079
  }),
20781
21080
  /* @__PURE__ */ jsx("span", { children: formatDate$1(item.createdAt) })
20782
21081
  ]
21082
+ }),
21083
+ /* @__PURE__ */ jsxs("div", {
21084
+ className: "flex items-center gap-2 text-sm",
21085
+ children: [
21086
+ /* @__PURE__ */ jsx(LinkSimple, { className: "h-4 w-4 text-kumo-subtle shrink-0" }),
21087
+ /* @__PURE__ */ jsx("span", {
21088
+ className: "text-kumo-subtle shrink-0",
21089
+ children: _t({
21090
+ id: "PQs7eb",
21091
+ message: "URL:"
21092
+ })
21093
+ }),
21094
+ /* @__PURE__ */ jsx(ClipboardText, {
21095
+ text: fileUrl,
21096
+ size: "sm",
21097
+ className: "min-w-0 flex-1",
21098
+ labels: { copyAction: _t({
21099
+ id: "E6nRW7",
21100
+ message: "Copy URL"
21101
+ }) }
21102
+ })
21103
+ ]
20783
21104
  })
20784
21105
  ]
20785
21106
  }),
@@ -21513,9 +21834,10 @@ function MediaGridItem({ item, selected, onClick }) {
21513
21834
  children: [/* @__PURE__ */ jsx("div", {
21514
21835
  className: "aspect-square",
21515
21836
  children: isImage ? /* @__PURE__ */ jsx("img", {
21516
- src: item.url,
21837
+ src: getMediaThumbnailUrl(item.url, item.mimeType, MEDIA_THUMBNAIL_WIDTH),
21517
21838
  alt: item.alt || item.filename,
21518
- className: "h-full w-full object-cover"
21839
+ className: "h-full w-full object-cover",
21840
+ onError: (e) => fallbackToOriginalThumbnail(e.currentTarget, item.url)
21519
21841
  }) : /* @__PURE__ */ jsx("div", {
21520
21842
  className: "flex h-full w-full items-center justify-center bg-kumo-tint",
21521
21843
  children: /* @__PURE__ */ jsx("span", {
@@ -21583,9 +21905,10 @@ function MediaListItem({ item, selected, onClick }) {
21583
21905
  children: /* @__PURE__ */ jsx("div", {
21584
21906
  className: "h-10 w-10 overflow-hidden rounded",
21585
21907
  children: isImage ? /* @__PURE__ */ jsx("img", {
21586
- src: item.url,
21908
+ src: getMediaThumbnailUrl(item.url, item.mimeType, 80),
21587
21909
  alt: item.alt || item.filename,
21588
- className: "h-full w-full object-cover"
21910
+ className: "h-full w-full object-cover",
21911
+ onError: (e) => fallbackToOriginalThumbnail(e.currentTarget, item.url)
21589
21912
  }) : /* @__PURE__ */ jsx("div", {
21590
21913
  className: "flex h-full w-full items-center justify-center bg-kumo-tint text-xl",
21591
21914
  children: getFileIcon(item.mimeType)
@@ -23975,7 +24298,7 @@ function RegistryPluginDetail({ pluginId, config }) {
23975
24298
  const { data: installedPlugins } = useQuery({
23976
24299
  queryKey: ["plugins"],
23977
24300
  queryFn: async () => {
23978
- const { fetchPlugins } = await import("./plugins-BZzztFdK.js").then((n) => n.a);
24301
+ const { fetchPlugins } = await import("./plugins-G9Z9NQ7n.js").then((n) => n.a);
23979
24302
  return fetchPlugins();
23980
24303
  }
23981
24304
  });
@@ -24038,7 +24361,7 @@ function RegistryPluginDetail({ pluginId, config }) {
24038
24361
  const release = React$1.useMemo(() => releases.find((r) => r.version === effectiveVersion), [releases, effectiveVersion]);
24039
24362
  const isPreRelease = release ? isPreReleaseVersion(release.version) : false;
24040
24363
  const ext = (release?.release?.extensions)?.["com.emdashcms.experimental.package.releaseExtension"];
24041
- const capabilities = Array.isArray(ext?.capabilities) ? canonicalCapabilitiesForDriftCheck(ext?.capabilities) : canonicalCapabilitiesForDriftCheck(declaredAccessToCapabilityList(ext?.declaredAccess));
24364
+ const capabilities = ext?.declaredAccess ? canonicalCapabilitiesForDriftCheck(declaredAccessToCapabilities(ext.declaredAccess).capabilities) : [];
24042
24365
  const pkgProfile = pkg?.profile ?? null;
24043
24366
  const displayName = pkgProfile?.name;
24044
24367
  const description = pkgProfile?.description;
@@ -24623,26 +24946,6 @@ function BackLink() {
24623
24946
  })]
24624
24947
  });
24625
24948
  }
24626
- /**
24627
- * Flatten an RFC-0001 `declaredAccess` block (`{ content: { read: true },
24628
- * email: { send: { allowedHosts: [...] } }, ... }`) into the legacy
24629
- * `capabilities: string[]` shape that the existing sandbox runtime
24630
- * enforces today. One entry per declared operation under each
24631
- * category. Unknown values are skipped silently -- the consent dialog
24632
- * shows only what the current runtime recognises.
24633
- */
24634
- function declaredAccessToCapabilityList(declaredAccess) {
24635
- if (!declaredAccess || typeof declaredAccess !== "object") return [];
24636
- const out = [];
24637
- for (const [category, value] of Object.entries(declaredAccess)) {
24638
- if (!value || typeof value !== "object") continue;
24639
- for (const [operation, opValue] of Object.entries(value)) {
24640
- if (opValue === false) continue;
24641
- out.push(`${category}:${operation}`);
24642
- }
24643
- }
24644
- return out;
24645
- }
24646
24949
  const PRE_RELEASE_VERSION_RE = /^\d+\.\d+\.\d+-/;
24647
24950
  /**
24648
24951
  * Detects semver pre-release identifiers (`1.0.0-alpha.1`, `2.0.0-rc.2`). The
@@ -37013,6 +37316,53 @@ function FieldRow({ field, isFirst, isLast, onMoveUp, onMoveDown, onEdit, onDele
37013
37316
  });
37014
37317
  }
37015
37318
 
37319
+ //#endregion
37320
+ //#region src/components/BylineAvatarField.tsx
37321
+ /**
37322
+ * Avatar picker for the byline editor (#1250).
37323
+ *
37324
+ * Bylines store only an `avatarMediaId` (the media item's id), not a
37325
+ * URL or embedded media object. This component resolves that id back
37326
+ * into a full media item so it can hand a populated value to the
37327
+ * shared {@link ImageFieldRenderer} — reusing its picker, preview, and
37328
+ * broken-image handling rather than duplicating the markup.
37329
+ *
37330
+ * On change it strips the resolved media back down to the bare id for
37331
+ * the byline update body.
37332
+ */
37333
+ function BylineAvatarField({ value, onChange }) {
37334
+ const { _: _t } = useLingui();
37335
+ const { data: media, isLoading } = useQuery({
37336
+ queryKey: ["media", value],
37337
+ queryFn: () => value ? fetchMediaItem(value) : Promise.resolve(null),
37338
+ enabled: !!value
37339
+ });
37340
+ if (value && isLoading) return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Label, { children: _t({
37341
+ id: "kfcRb0",
37342
+ message: "Avatar"
37343
+ }) }), /* @__PURE__ */ jsx("div", {
37344
+ className: "mt-2 flex h-32 items-center justify-center rounded-lg border",
37345
+ children: /* @__PURE__ */ jsx(Loader, {})
37346
+ })] });
37347
+ const fieldValue = value && media ? {
37348
+ id: media.id,
37349
+ provider: media.provider || "local",
37350
+ previewUrl: media.provider && media.provider !== "local" ? media.url : void 0,
37351
+ alt: media.alt ?? "",
37352
+ width: media.width,
37353
+ height: media.height,
37354
+ meta: media.storageKey ? { storageKey: media.storageKey } : void 0
37355
+ } : void 0;
37356
+ return /* @__PURE__ */ jsx(ImageFieldRenderer, {
37357
+ label: _t({
37358
+ id: "kfcRb0",
37359
+ message: "Avatar"
37360
+ }),
37361
+ value: fieldValue,
37362
+ onChange: (next) => onChange(next?.id ?? null)
37363
+ });
37364
+ }
37365
+
37016
37366
  //#endregion
37017
37367
  //#region src/routes/bylines.tsx
37018
37368
  /**
@@ -37030,6 +37380,7 @@ function toFormState(byline) {
37030
37380
  websiteUrl: "",
37031
37381
  userId: null,
37032
37382
  isGuest: false,
37383
+ avatarMediaId: null,
37033
37384
  customFields: {}
37034
37385
  };
37035
37386
  return {
@@ -37039,6 +37390,7 @@ function toFormState(byline) {
37039
37390
  websiteUrl: byline.websiteUrl ?? "",
37040
37391
  userId: byline.userId,
37041
37392
  isGuest: byline.isGuest,
37393
+ avatarMediaId: byline.avatarMediaId ?? null,
37042
37394
  customFields: byline.customFields ?? {}
37043
37395
  };
37044
37396
  }
@@ -37153,6 +37505,7 @@ function BylinesPage() {
37153
37505
  websiteUrl: form.websiteUrl || null,
37154
37506
  userId: form.userId,
37155
37507
  isGuest: form.isGuest,
37508
+ avatarMediaId: form.avatarMediaId,
37156
37509
  locale: activeLocale
37157
37510
  };
37158
37511
  if (!customFieldsError && Object.keys(form.customFields).length > 0) body.customFields = form.customFields;
@@ -37173,7 +37526,8 @@ function BylinesPage() {
37173
37526
  bio: form.bio || null,
37174
37527
  websiteUrl: form.websiteUrl || null,
37175
37528
  userId: form.userId,
37176
- isGuest: form.isGuest
37529
+ isGuest: form.isGuest,
37530
+ avatarMediaId: form.avatarMediaId
37177
37531
  };
37178
37532
  if (!customFieldsError) body.customFields = form.customFields;
37179
37533
  return updateByline(selectedId, body);
@@ -37421,6 +37775,13 @@ function BylinesPage() {
37421
37775
  })),
37422
37776
  rows: 5
37423
37777
  }),
37778
+ /* @__PURE__ */ jsx(BylineAvatarField, {
37779
+ value: form.avatarMediaId,
37780
+ onChange: (mediaId) => setForm((prev) => ({
37781
+ ...prev,
37782
+ avatarMediaId: mediaId
37783
+ }))
37784
+ }),
37424
37785
  /* @__PURE__ */ jsx(Select, {
37425
37786
  label: _t({
37426
37787
  id: "nti0N3",
@@ -40094,7 +40455,7 @@ function MarketplaceBrowsePage() {
40094
40455
  const { data: plugins } = useQuery({
40095
40456
  queryKey: ["plugins"],
40096
40457
  queryFn: async () => {
40097
- const { fetchPlugins } = await import("./plugins-BZzztFdK.js").then((n) => n.a);
40458
+ const { fetchPlugins } = await import("./plugins-G9Z9NQ7n.js").then((n) => n.a);
40098
40459
  return fetchPlugins();
40099
40460
  }
40100
40461
  });
@@ -40125,7 +40486,7 @@ function MarketplaceDetailPage() {
40125
40486
  const { data: plugins } = useQuery({
40126
40487
  queryKey: ["plugins"],
40127
40488
  queryFn: async () => {
40128
- const { fetchPlugins } = await import("./plugins-BZzztFdK.js").then((n) => n.a);
40489
+ const { fetchPlugins } = await import("./plugins-G9Z9NQ7n.js").then((n) => n.a);
40129
40490
  return fetchPlugins();
40130
40491
  }
40131
40492
  });
@@ -40608,5 +40969,5 @@ function AdminApp({ pluginAdmins = EMPTY_PLUGINS, authProviders = EMPTY_AUTH_PRO
40608
40969
  }
40609
40970
 
40610
40971
  //#endregion
40611
- export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, AuthProviderProvider, CAPABILITY_LABELS, ContentEditor, ContentList, DEFAULT_LOCALE, Dashboard, EditorHeader, Header, Link, LoginPage, MEDIA_SEARCH_MAX_LENGTH, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SUPPORTED_LOCALES, SUPPORTED_LOCALE_CODES, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createBylineField, createBylineTranslation, createCollection, createContent, createField, createMenu, createMenuItem, createMenuTranslation, createRedirect, createSection, createTaxonomy, createTerm, createTermTranslation, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteBylineField, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchAuthMode, fetchByline, fetchBylineTranslations, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentAuthors, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenuTranslations, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTermTranslations, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getBylineFieldUsage, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, listBylineFields, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderBylineFields, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, resolveLocale, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateBylineField, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useAuthProviderList, useAuthProviders, useCurrentUser, useLocale, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, validateInviteToken, verifySignupToken };
40972
+ export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, AuthProviderProvider, CAPABILITY_LABELS, ContentEditor, ContentList, DEFAULT_LOCALE, Dashboard, EditorHeader, Header, Link, LoginPage, MEDIA_SEARCH_MAX_LENGTH, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SUPPORTED_LOCALES, SUPPORTED_LOCALE_CODES, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createBylineField, createBylineTranslation, createCollection, createContent, createField, createMenu, createMenuItem, createMenuTranslation, createRedirect, createSection, createTaxonomy, createTerm, createTermTranslation, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteBylineField, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchAuthMode, fetchByline, fetchBylineTranslations, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentAuthors, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaItem, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenuTranslations, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTermTranslations, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getBylineFieldUsage, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, listBylineFields, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderBylineFields, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, resolveLocale, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateBylineField, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useAuthProviderList, useAuthProviders, useCurrentUser, useLocale, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, validateInviteToken, verifySignupToken };
40612
40973
  //# sourceMappingURL=index.js.map