@decocms/blocks 7.11.1 → 7.12.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/blocks",
3
- "version": "7.11.1",
3
+ "version": "7.12.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -306,6 +306,47 @@ describe("commerce loader auto-injects URL search params as props", () => {
306
306
  });
307
307
  });
308
308
 
309
+ describe("commerce loader resolves legacy .ts-suffixed resolveType", () => {
310
+ beforeEach(() => clearCommerceLoaders());
311
+ afterEach(() => clearCommerceLoaders());
312
+
313
+ it("matches a manifest key (no extension) against a decofile .ts resolveType", async () => {
314
+ const calls: Array<Record<string, unknown>> = [];
315
+ // Split-package manifests register WITHOUT the file extension.
316
+ registerCommerceLoader("shopify/loaders/ProductDetailsPage", async (props) => {
317
+ calls.push({ ...props });
318
+ return null;
319
+ });
320
+
321
+ // Legacy (Fresh/Deno) decofile references it WITH the .ts extension.
322
+ await resolveValue(
323
+ { __resolveType: "shopify/loaders/ProductDetailsPage.ts", slug: "oversize-t-shirt-123" },
324
+ undefined,
325
+ { url: "https://store.com/products/oversize-t-shirt-123", path: "/products/oversize-t-shirt-123" },
326
+ );
327
+
328
+ expect(calls).toHaveLength(1);
329
+ expect(calls[0]).toMatchObject({ slug: "oversize-t-shirt-123" });
330
+ });
331
+
332
+ it("prefers an exact .ts registration over the stripped fallback", async () => {
333
+ const hits: string[] = [];
334
+ registerCommerceLoader("shopify/loaders/X", async () => {
335
+ hits.push("plain");
336
+ return null;
337
+ });
338
+ registerCommerceLoader("shopify/loaders/X.ts", async () => {
339
+ hits.push("dotts");
340
+ return null;
341
+ });
342
+ await resolveValue({ __resolveType: "shopify/loaders/X.ts" }, undefined, {
343
+ url: "https://s.com/",
344
+ path: "/",
345
+ });
346
+ expect(hits).toEqual(["dotts"]);
347
+ });
348
+ });
349
+
309
350
  // ---------------------------------------------------------------------------
310
351
  // Async rendering: the admin (CMS Lazy ⚡ toggle) is the source of truth
311
352
  // ---------------------------------------------------------------------------
@@ -495,6 +495,19 @@ export function clearCommerceLoaders(): void {
495
495
  for (const key of Object.keys(commerceLoaders)) delete commerceLoaders[key];
496
496
  }
497
497
 
498
+ /**
499
+ * Look up a commerce loader tolerant of a legacy `.ts`/`.tsx` resolveType
500
+ * suffix. Fresh/Deno decofiles reference app loaders with the file extension
501
+ * (`shopify/loaders/ProductDetailsPage.ts`), but the split-package app
502
+ * manifests register them WITHOUT it (`shopify/loaders/ProductDetailsPage`).
503
+ * Exact key wins (so an explicitly-registered `.ts` alias — e.g. a site's
504
+ * wrapped loader — still takes precedence); otherwise fall back to the
505
+ * extension-stripped key so existing content keeps resolving after a migration.
506
+ */
507
+ export function getCommerceLoader(resolveType: string): CommerceLoader | undefined {
508
+ return commerceLoaders[resolveType] ?? commerceLoaders[resolveType.replace(/\.tsx?$/, "")];
509
+ }
510
+
498
511
  // ---------------------------------------------------------------------------
499
512
  // Custom matchers
500
513
  // ---------------------------------------------------------------------------
@@ -832,7 +845,7 @@ async function internalResolve(value: unknown, rctx: ResolveContext): Promise<un
832
845
  }
833
846
 
834
847
  // Commerce loaders
835
- const commerceLoader = commerceLoaders[resolveType];
848
+ const commerceLoader = getCommerceLoader(resolveType);
836
849
  if (commerceLoader) {
837
850
  const { __resolveType: _, ...loaderProps } = obj;
838
851
  const resolvedProps = await resolveProps(loaderProps, childCtx);
@@ -1186,7 +1199,7 @@ function resolvesToCommerceLoader(value: unknown, depth = 0): boolean {
1186
1199
  const rt = obj.__resolveType as string | undefined;
1187
1200
  if (!rt) return false;
1188
1201
 
1189
- if (commerceLoaders[rt]) return true;
1202
+ if (getCommerceLoader(rt)) return true;
1190
1203
 
1191
1204
  if (rt === WELL_KNOWN_TYPES.LAZY) return resolvesToCommerceLoader(obj.section, depth + 1);
1192
1205
  if (rt === WELL_KNOWN_TYPES.DEFERRED) {