@decocms/start 1.2.1 → 1.2.2

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/start",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "description": "Deco framework for TanStack Start - CMS bridge, admin protocol, hooks, schema generation",
6
6
  "main": "./src/index.ts",
@@ -281,12 +281,12 @@ for (const action of actions) {
281
281
  }
282
282
 
283
283
  // Count how many actually parsed vs. stubbed
284
- const parsed = actions.filter((a) => a.callBody && a.importedFn).length;
284
+ const parsed = actions.filter((a) => a.importedFn).length;
285
285
  const stubbed = actions.length - parsed;
286
286
  if (stubbed > 0) {
287
287
  console.warn(`⚠ ${stubbed} action(s) could not be parsed — generated as stubs:`);
288
288
  for (const a of actions) {
289
- if (!a.callBody || !a.importedFn) console.warn(` - ${a.name}`);
289
+ if (!a.importedFn) console.warn(` - ${a.name}`);
290
290
  }
291
291
  }
292
292
 
@@ -333,25 +333,22 @@ function unwrapResult<T>(result: unknown): T {
333
333
  for (const action of actions) {
334
334
  const varName = `$${action.name}`;
335
335
 
336
- if (action.callBody && action.importedFn) {
337
- // Replace "input" references with "data" in the call body.
338
- // The handler receives `{ data }` destructured from the validated input.
339
- let body = action.callBody;
340
- body = body.replace(/\binput\./g, "data.");
341
- body = body.replace(/\binput\b(?!\.)/g, "data");
342
-
336
+ if (action.importedFn) {
337
+ // All @decocms/apps action functions take a single props object.
338
+ // Pass the validated `data` object directly never destructure into
339
+ // positional arguments, which breaks when function signatures change.
343
340
  if (action.unwrap) {
344
341
  out += `\nconst ${varName} = createServerFn({ method: "POST" })
345
342
  .inputValidator((data: ${action.inputType}) => data)
346
343
  .handler(async ({ data }): Promise<any> => {
347
- const result = await ${body};
344
+ const result = await ${action.importedFn}(data);
348
345
  return unwrapResult(result);
349
346
  });\n`;
350
347
  } else {
351
348
  out += `\nconst ${varName} = createServerFn({ method: "POST" })
352
349
  .inputValidator((data: ${action.inputType}) => data)
353
350
  .handler(async ({ data }): Promise<any> => {
354
- return ${body};
351
+ return ${action.importedFn}(data);
355
352
  });\n`;
356
353
  }
357
354
  } else {
@@ -133,13 +133,15 @@ export const loadCmsPage = createServerFn({ method: "GET" })
133
133
  .inputValidator((data: unknown) => data as string)
134
134
  .handler(async (ctx) => {
135
135
  const fullPath = ctx.data;
136
- const [basePath] = fullPath.split("?");
137
136
 
138
- const existing = pageInflight.get(basePath);
137
+ // Use the full path (including query string) as the dedup key.
138
+ // Using basePath only caused /s?q=a and /s?q=b to share one promise,
139
+ // returning wrong/empty results for search and filtered PLPs.
140
+ const existing = pageInflight.get(fullPath);
139
141
  if (existing) return existing;
140
142
 
141
- const promise = loadCmsPageInternal(fullPath).finally(() => pageInflight.delete(basePath));
142
- pageInflight.set(basePath, promise);
143
+ const promise = loadCmsPageInternal(fullPath).finally(() => pageInflight.delete(fullPath));
144
+ pageInflight.set(fullPath, promise);
143
145
  return promise;
144
146
  });
145
147
 
@@ -519,6 +521,12 @@ export function cmsRouteConfig(options: CmsRouteOptions) {
519
521
  const ignoreSet = new Set(ignoreSearchParams);
520
522
 
521
523
  return {
524
+ // Catch-all search validation: preserve all URL search params so they
525
+ // reach loaderDeps. Without this, TanStack Router may strip unknown
526
+ // params (e.g. ?q=, filter.*, page, sort) during SPA navigation.
527
+ validateSearch: (search: Record<string, unknown>) =>
528
+ search as Record<string, string>,
529
+
522
530
  loaderDeps: ({ search }: { search: Record<string, string> }) => {
523
531
  const filtered = Object.fromEntries(
524
532
  Object.entries(search ?? {}).filter(([k]) => !ignoreSet.has(k)),