@decocms/blocks-cli 7.1.1 → 7.2.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-cli",
3
- "version": "7.1.1",
3
+ "version": "7.2.0",
4
4
  "type": "module",
5
5
  "description": "Deco codegen (generate-blocks, generate-schema, generate-invoke) and Fresh-to-TanStack migration tooling",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "lint:unused": "knip"
35
35
  },
36
36
  "dependencies": {
37
- "@decocms/blocks": "7.1.1",
37
+ "@decocms/blocks": "7.2.0",
38
38
  "ts-morph": "^27.0.0",
39
39
  "tsx": "^4.19.0"
40
40
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Integration test for scripts/generate-invoke.ts.
3
3
  *
4
- * The generator scans a `vtex/invoke.ts` file from @decocms/apps and emits a
4
+ * The generator scans an `invoke.ts` file from @decocms/apps-vtex and emits a
5
5
  * site-local `src/server/invoke.gen.ts` with top-level `createServerFn`
6
6
  * declarations. The piece we care most about locking is the Set-Cookie
7
7
  * bridge: every handler must call `forwardResponseCookies()` after the
@@ -81,20 +81,17 @@ describe("generate-invoke.ts — output shape", () => {
81
81
 
82
82
  beforeAll(() => {
83
83
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gen-invoke-"));
84
- appsDir = path.join(tmp, "apps");
84
+ // Mirrors @decocms/apps-vtex's actual layout post-migration: invoke.ts
85
+ // sits at the package root (no more vtex/ nesting — the old vtex/
86
+ // directory in apps-start IS this package's root now).
87
+ appsDir = path.join(tmp, "apps-vtex");
85
88
  siteDir = path.join(tmp, "site");
86
- fs.mkdirSync(path.join(appsDir, "vtex", "actions"), { recursive: true });
89
+ fs.mkdirSync(path.join(appsDir, "actions"), { recursive: true });
87
90
  fs.mkdirSync(path.join(siteDir, "src", "server"), { recursive: true });
88
- fs.writeFileSync(path.join(appsDir, "vtex", "invoke.ts"), FIXTURE_INVOKE_TS);
89
- fs.writeFileSync(
90
- path.join(appsDir, "vtex", "actions", "checkout.ts"),
91
- FIXTURE_ACTIONS_CHECKOUT_TS,
92
- );
93
- fs.writeFileSync(
94
- path.join(appsDir, "vtex", "actions", "session.ts"),
95
- FIXTURE_ACTIONS_SESSION_TS,
96
- );
97
- fs.writeFileSync(path.join(appsDir, "vtex", "types.ts"), FIXTURE_TYPES_TS);
91
+ fs.writeFileSync(path.join(appsDir, "invoke.ts"), FIXTURE_INVOKE_TS);
92
+ fs.writeFileSync(path.join(appsDir, "actions", "checkout.ts"), FIXTURE_ACTIONS_CHECKOUT_TS);
93
+ fs.writeFileSync(path.join(appsDir, "actions", "session.ts"), FIXTURE_ACTIONS_SESSION_TS);
94
+ fs.writeFileSync(path.join(appsDir, "types.ts"), FIXTURE_TYPES_TS);
98
95
  outFile = path.join(siteDir, "src", "server", "invoke.gen.ts");
99
96
 
100
97
  const result = spawnSync(
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env tsx
2
2
  /**
3
- * Scans @decocms/apps vtex/invoke.ts and generates a site-local invoke file
3
+ * Scans @decocms/apps-vtex's invoke.ts and generates a site-local invoke file
4
4
  * with top-level createServerFn declarations.
5
5
  *
6
6
  * TanStack Start's compiler only transforms createServerFn().handler() when
7
7
  * the call is at module top-level (assigned to a const). The factory pattern
8
- * used in @decocms/apps/vtex/invoke.ts causes the "fast path" in the compiler
8
+ * used in @decocms/apps-vtex/invoke.ts causes the "fast path" in the compiler
9
9
  * to skip the .handler() calls because they're inside a function body.
10
10
  *
11
11
  * This script generates an equivalent file where each server function is a
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * Env / CLI:
18
18
  * --out-file override output (default: src/server/invoke.gen.ts)
19
- * --apps-dir override @decocms/apps location (default: auto-resolve from node_modules)
19
+ * --apps-dir override @decocms/apps-vtex location (default: auto-resolve from node_modules)
20
20
  */
21
21
  import fs from "node:fs";
22
22
  import path from "node:path";
@@ -35,19 +35,23 @@ function resolveAppsDir(): string {
35
35
  const explicit = arg("apps-dir", "");
36
36
  if (explicit) return path.resolve(cwd, explicit);
37
37
 
38
- // Try common locations
38
+ // Try common locations. Both point at the directory that contains
39
+ // invoke.ts directly at its root: the installed @decocms/apps-vtex
40
+ // package (no more vtex/ nesting — that directory IS the package root
41
+ // now), or a raw apps-start checkout's vtex/ subdirectory as a legacy
42
+ // fallback for anyone still developing against the pre-split monorepo.
39
43
  const candidates = [
40
- path.resolve(cwd, "node_modules/@decocms/apps"),
41
- path.resolve(cwd, "../apps-start"),
44
+ path.resolve(cwd, "node_modules/@decocms/apps-vtex"),
45
+ path.resolve(cwd, "../apps-start/vtex"),
42
46
  ];
43
47
  for (const c of candidates) {
44
- if (fs.existsSync(path.join(c, "vtex/invoke.ts"))) return c;
48
+ if (fs.existsSync(path.join(c, "invoke.ts"))) return c;
45
49
  }
46
- throw new Error("Could not find @decocms/apps. Use --apps-dir to specify its location.");
50
+ throw new Error("Could not find @decocms/apps-vtex. Use --apps-dir to specify its location.");
47
51
  }
48
52
 
49
53
  const appsDir = resolveAppsDir();
50
- const invokeFile = path.join(appsDir, "vtex/invoke.ts");
54
+ const invokeFile = path.join(appsDir, "invoke.ts");
51
55
 
52
56
  if (!fs.existsSync(invokeFile)) {
53
57
  console.error(`invoke.ts not found at: ${invokeFile}`);
@@ -60,7 +64,7 @@ if (!fs.existsSync(invokeFile)) {
60
64
 
61
65
  interface ActionDef {
62
66
  name: string;
63
- /** The import source for the action function (e.g., "@decocms/apps/vtex/actions/checkout") */
67
+ /** The import source for the action function (e.g., "@decocms/apps-vtex/actions/checkout") */
64
68
  importSource: string;
65
69
  /** The imported function name (e.g., "addItemsToCart") */
66
70
  importedFn: string;
@@ -85,7 +89,7 @@ for (const imp of sourceFile.getImportDeclarations()) {
85
89
  const localName = named.getName();
86
90
  const importedName = named.getAliasNode()?.getText() || localName;
87
91
  importMap.set(localName, {
88
- source: source.startsWith("./") ? `@decocms/apps/vtex/${source.slice(2)}` : source,
92
+ source: source.startsWith("./") ? `@decocms/apps-vtex/${source.slice(2)}` : source,
89
93
  importedName: localName,
90
94
  });
91
95
  }
@@ -100,7 +104,7 @@ for (const imp of sourceFile.getImportDeclarations()) {
100
104
  const localName = named.getName();
101
105
  const source = imp.getModuleSpecifierValue();
102
106
  typeImportMap.set(localName, {
103
- source: source.startsWith("./") ? `@decocms/apps/vtex/${source.slice(2)}` : source,
107
+ source: source.startsWith("./") ? `@decocms/apps-vtex/${source.slice(2)}` : source,
104
108
  importedName: localName,
105
109
  });
106
110
  }
@@ -111,7 +115,7 @@ for (const imp of sourceFile.getImportDeclarations()) {
111
115
  for (const named of imp.getNamedImports()) {
112
116
  const localName = named.getName();
113
117
  typeImportMap.set(localName, {
114
- source: source.startsWith("./") ? `@decocms/apps/vtex/${source.slice(2)}` : source,
118
+ source: source.startsWith("./") ? `@decocms/apps-vtex/${source.slice(2)}` : source,
115
119
  importedName: localName,
116
120
  });
117
121
  }
@@ -376,7 +380,7 @@ for (const action of actions) {
376
380
 
377
381
  if (action.importedFn) {
378
382
  // Emit the wrapper body verbatim. The arrow function in
379
- // @decocms/apps/vtex/invoke.ts is the contract that maps the external
383
+ // @decocms/apps-vtex/invoke.ts is the contract that maps the external
380
384
  // invoke shape (what storefront callers send) to the internal action
381
385
  // shape (what vtex/actions/* expects). Most wrappers are direct
382
386
  // pass-throughs (`actionFn(data)`) but some adapt the payload
@@ -450,7 +454,7 @@ for (const action of actions) {
450
454
  out += `} as const;
451
455
 
452
456
  // Re-export OrderForm type (commonly imported from invoke by site components)
453
- export type { OrderForm } from "@decocms/apps/vtex/types";
457
+ export type { OrderForm } from "@decocms/apps-vtex/types";
454
458
 
455
459
  // ---------------------------------------------------------------------------
456
460
  // Default invoke object — import this if you don't need site extensions
@@ -839,14 +839,22 @@ function generateMeta(): MetaResponse {
839
839
  }
840
840
 
841
841
  // ---------------------------------------------------------------------------
842
- // App loaders pass: walk @decocms/apps/*/loaders/ directories and register
843
- // each .ts file as a CMS loader. CMS keys are derived from the file path
844
- // (e.g. "vtex/loaders/intelligentSearch/productList.ts").
842
+ // App loaders pass: walk each @decocms/apps-<namespace> package's src/loaders/
843
+ // directory and register each .ts file as a CMS loader. CMS keys are derived
844
+ // from the file path (e.g. "vtex/loaders/intelligentSearch/productList.ts")
845
+ // this key format is a CMS decofile convention, independent of the npm
846
+ // package layout, so it stays "<namespace>/loaders/..." even though the
847
+ // namespace now maps to its own "@decocms/apps-<namespace>" package rather
848
+ // than a subdirectory of one monolithic "@decocms/apps" package.
845
849
  //
846
850
  // Only apps installed in src/apps/ are scanned. An app bridge file that
847
- // re-exports from "@decocms/apps/{namespace}/mod" signals the namespace.
851
+ // re-exports from "@decocms/apps-{namespace}/mod" signals the namespace.
848
852
  // ---------------------------------------------------------------------------
849
- const appsPkgDir = path.resolve(root, "node_modules/@decocms/apps");
853
+
854
+ /** Absolute path to the installed @decocms/apps-<namespace> package, if present. */
855
+ function getAppPkgDir(namespace: string): string {
856
+ return path.resolve(root, `node_modules/@decocms/apps-${namespace}`);
857
+ }
850
858
 
851
859
  /** Detect installed app namespaces from src/apps/ bridge files. */
852
860
  function detectInstalledAppNamespaces(): Set<string> {
@@ -855,7 +863,7 @@ function generateMeta(): MetaResponse {
855
863
  if (!fs.existsSync(siteAppsDir)) return namespaces;
856
864
 
857
865
  const appFiles = findTsxFiles(siteAppsDir);
858
- const re = /["']@decocms\/apps\/([^/]+)\/mod["']/;
866
+ const re = /["']@decocms\/apps-([^/]+)\/mod["']/;
859
867
  for (const filePath of appFiles) {
860
868
  try {
861
869
  const content = fs.readFileSync(filePath, "utf-8");
@@ -869,13 +877,13 @@ function generateMeta(): MetaResponse {
869
877
  // Discover app loader files via filesystem walk (scoped to installed apps)
870
878
  function discoverAppLoaders(): Array<{ cmsKey: string; sourceFile: string; namespace: string }> {
871
879
  const result: Array<{ cmsKey: string; sourceFile: string; namespace: string }> = [];
872
- if (!fs.existsSync(appsPkgDir)) return result;
873
880
 
874
881
  const installed = detectInstalledAppNamespaces();
875
882
  if (installed.size === 0) return result;
876
883
 
877
884
  for (const namespace of installed) {
878
- const loadersDir = path.join(appsPkgDir, namespace, "loaders");
885
+ const pkgDir = getAppPkgDir(namespace);
886
+ const loadersDir = path.join(pkgDir, "src", "loaders");
879
887
  if (!fs.existsSync(loadersDir)) continue;
880
888
 
881
889
  const files = fs.readdirSync(loadersDir, { recursive: true }) as string[];
@@ -888,7 +896,9 @@ function generateMeta(): MetaResponse {
888
896
  if (rel.includes("__tests__") || rel.includes("__test__") || rel.endsWith(".test.ts")) continue;
889
897
 
890
898
  const cmsKey = `${namespace}/loaders/${rel.replace(/\\/g, "/")}`;
891
- const sourceFile = `${namespace}/loaders/${rel.replace(/\\/g, "/")}`;
899
+ // Absolute each namespace now resolves against its own package dir,
900
+ // not a single shared "appsPkgDir" (see absSourceFile below).
901
+ const sourceFile = path.join(loadersDir, rel);
892
902
  result.push({ cmsKey, sourceFile, namespace });
893
903
  }
894
904
  }
@@ -908,9 +918,9 @@ function generateMeta(): MetaResponse {
908
918
 
909
919
  const installedNs = detectInstalledAppNamespaces();
910
920
  console.log(`Installed app namespaces: ${[...installedNs].join(", ") || "(none)"}`);
911
- console.log(`Scanning app loaders from @decocms/apps (${appLoaders.length} files)...`);
921
+ console.log(`Scanning app loaders from ${[...installedNs].map((ns) => `@decocms/apps-${ns}`).join(", ") || "(none)"} (${appLoaders.length} files)...`);
912
922
  for (const appLoader of appLoaders) {
913
- const absSourceFile = path.resolve(appsPkgDir, appLoader.sourceFile);
923
+ const absSourceFile = appLoader.sourceFile;
914
924
 
915
925
  try {
916
926
  // Resolve the real path to de-duplicate re-exports pointing to the same file