@backmatter/next 0.0.29 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backmatter/next",
3
- "version": "0.0.29",
3
+ "version": "0.0.30",
4
4
  "description": "Experimental Next.js adapter for Backmatter. APIs will break. Not ready for production.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -47,10 +47,10 @@
47
47
  "test": "bun test"
48
48
  },
49
49
  "dependencies": {
50
- "@backmatter/core": "^0.0.23",
50
+ "@backmatter/core": "^0.0.24",
51
51
  "@mdx-js/mdx": "^3.1.1",
52
52
  "remark-gfm": "^4.0.1",
53
- "@backmatter/studio": "^0.0.6"
53
+ "@backmatter/studio": "^0.0.7"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "next": ">=16.3.0",
package/src/routes.ts CHANGED
@@ -6,14 +6,17 @@
6
6
  import { Fragment, Suspense, createElement, type ReactNode } from "react";
7
7
  import { HeldPreview, HoldPreview } from "./preview-hold";
8
8
  import {
9
+ decodeDocLocale,
9
10
  DEFAULT_TEMPLATE_SLUG,
10
11
  isRoutable,
11
12
  isTemplateSlug,
12
13
  matchRoute,
13
14
  PREVIEW_CHECKOUT_QUERY,
14
15
  PREVIEW_COOKIE,
16
+ PREVIEW_LOCALE_QUERY,
15
17
  readPreviewCookie,
16
18
  routeSegments,
19
+ routeTemplate,
17
20
  type BackmatterDoc,
18
21
  type ModelDef,
19
22
  type SourceDef,
@@ -137,6 +140,18 @@ export function previewReplacesPublished(
137
140
 
138
141
  type RouteHit = { locale: string; type: string; slug: string };
139
142
 
143
+ async function previewLocaleQuery(
144
+ searchParams: Promise<CatchAllSearchParams> | CatchAllSearchParams | undefined,
145
+ ): Promise<string | undefined> {
146
+ if (!searchParams) return undefined;
147
+ const query = await searchParams;
148
+ const raw = query[PREVIEW_LOCALE_QUERY];
149
+ if (raw === undefined) return undefined;
150
+ const value = Array.isArray(raw) ? raw[0] : raw;
151
+ if (value === undefined) return undefined;
152
+ return decodeDocLocale(value);
153
+ }
154
+
140
155
  async function checkoutQueryToken(
141
156
  searchParams: Promise<CatchAllSearchParams> | CatchAllSearchParams | undefined,
142
157
  ): Promise<string | undefined> {
@@ -390,12 +405,28 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
390
405
  return failFor();
391
406
  }
392
407
 
408
+ /**
409
+ * Routes without `{locale}` always match as the default locale. The editor
410
+ * puts the file's locale on the preview URL so a conflicted or translated
411
+ * copy is the document that gets fetched.
412
+ */
413
+ async function previewHit(
414
+ hit: RouteHit,
415
+ searchParams: Promise<CatchAllSearchParams> | CatchAllSearchParams | undefined,
416
+ ): Promise<RouteHit> {
417
+ const model = byType.get(hit.type);
418
+ if (!model || routeTemplate(model).includes("{locale}")) return hit;
419
+ const locale = await previewLocaleQuery(searchParams);
420
+ if (locale === undefined) return hit;
421
+ return { ...hit, locale };
422
+ }
423
+
393
424
  const CmsRoute: CatchAllRoute["CmsRoute"] = async ({ params, searchParams }) => {
394
425
  const resolved = await cachedRouteParams(params);
395
426
  const hit = resolve(resolved[CATCH_ALL_PARAM]);
396
427
  if (!hit) return failFor();
397
428
  const preview = await resolvePreviewState(cms, options.preview, searchParams);
398
- if (previewReplacesPublished(preview)) return loadPreviewDoc(hit, preview);
429
+ if (previewReplacesPublished(preview)) return loadPreviewDoc(await previewHit(hit, searchParams), preview);
399
430
  return publishedBody(hit.locale, hit.type, hit.slug);
400
431
  };
401
432
 
@@ -425,6 +456,7 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
425
456
  if (!hit) return null;
426
457
  const preview = await resolvePreviewState(cms, options.preview, searchParams);
427
458
  if (!previewReplacesPublished(preview)) return null;
459
+ const docHit = await previewHit(hit, searchParams);
428
460
  return createElement(
429
461
  HoldPreview,
430
462
  null,
@@ -436,8 +468,8 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
436
468
  __html: "[data-backmatter-published]{display:none!important}",
437
469
  },
438
470
  }),
439
- docBridge(hit),
440
- await loadPreviewDoc(hit, preview),
471
+ docBridge(docHit),
472
+ await loadPreviewDoc(docHit, preview),
441
473
  ),
442
474
  );
443
475
  };
package/src/site-doc.ts CHANGED
@@ -11,11 +11,10 @@ export function parseSiteDoc(content: string | null | undefined): SiteDocRef | n
11
11
  try {
12
12
  const value = JSON.parse(content) as Record<string, unknown>;
13
13
  if (
14
- typeof value.locale !== "string" ||
14
+ (value.locale !== undefined && typeof value.locale !== "string") ||
15
15
  typeof value.type !== "string" ||
16
16
  typeof value.slug !== "string" ||
17
17
  typeof value.workspaceId !== "string" ||
18
- !value.locale ||
19
18
  !value.type ||
20
19
  !value.slug ||
21
20
  !value.workspaceId
@@ -23,7 +22,7 @@ export function parseSiteDoc(content: string | null | undefined): SiteDocRef | n
23
22
  return null;
24
23
  }
25
24
  return {
26
- locale: value.locale,
25
+ locale: value.locale ?? "",
27
26
  type: value.type,
28
27
  slug: value.slug,
29
28
  workspaceId: value.workspaceId,
@@ -43,7 +42,7 @@ export function readSiteDoc(): SiteDocRef | null {
43
42
  slug: marked.getAttribute("data-slug") ?? "",
44
43
  workspaceId: marked.getAttribute("data-workspace") ?? "",
45
44
  };
46
- if (doc.locale && doc.type && doc.slug && doc.workspaceId) return doc;
45
+ if (doc.type && doc.slug && doc.workspaceId) return doc;
47
46
  }
48
47
  return parseSiteDoc(document.querySelector('meta[name="backmatter:doc"]')?.getAttribute("content"));
49
48
  }