@open-mercato/cli 0.6.3 → 0.6.4-canary.3910.1.0ff5e9e9be

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.
@@ -1,4 +1,4 @@
1
- [build:cli] found 74 entry points
1
+ [build:cli] found 73 entry points
2
2
  Copied create-app/agentic/ → dist/agentic/
3
3
  Discovered 16 standalone guides → dist/agentic/guides/
4
4
  [build:cli] built successfully
package/AGENTS.md CHANGED
@@ -72,7 +72,7 @@ The structural cache purge does two things:
72
72
  1. Deletes Redis cache keys matching `nav:*` so navigation/sidebar caches are rebuilt next render.
73
73
  2. Touches every `*.generated.ts` and `*.generated.checksum` file in the current app's `.mercato/generated/` directory by rewriting them with identical bytes. This advances mtime without changing content, which forces Turbopack's filesystem watcher to invalidate the import graph and recompile leaf files that imported a barrel. Without this, Turbopack can keep serving a cached compile error against a since-fixed module file until the dev server is restarted.
74
74
 
75
- The dev escape hatch is `yarn dev:reset`, which clears the configured Next dev cache (`.mercato/next/dev`) plus legacy `.next` cache directories for the rare case where Turbopack's internal cache stays stuck after a structural purge.
75
+ The dev escape hatch is `yarn dev:reset`, which clears `.next/cache/turbopack` and `.next/cache/webpack` for the rare case where Turbopack's internal cache stays stuck after a structural purge.
76
76
 
77
77
  ## Database Migrations
78
78
 
@@ -201,7 +201,6 @@ When the user asks to **create a new application** or a **new module**, do not i
201
201
  - Entity classes belong in `src/modules/<module>/data/entities.ts` and use decorators from `@mikro-orm/decorators/legacy`
202
202
  - Standalone apps expose `yarn mercato configs cache ...` because the template enables the `configs` module from `@open-mercato/core`
203
203
  - `yarn generate` automatically runs a best-effort structural cache purge (`yarn mercato configs cache structural --all-tenants`) after successful generation; if the cache command is unavailable, generation still succeeds
204
- - Use `yarn dev:reset` only as the stale-Turbopack escape hatch; it clears `.mercato/next/dev` plus legacy `.next` caches.
205
204
  - Detail/read-model APIs that expose `customFields` MUST return bare field keys via `normalizeCustomFieldResponse()` (for example `{ priority: 3 }`). Keep `cf_` / `cf:` prefixes for request payloads, filters, and form field IDs only.
206
205
  - Sidebar icons MUST use `lucide-react` components — never inline SVG via `React.createElement`
207
206
  - `page.meta.ts` MUST include `pageGroup`, `pageGroupKey`, and `pageOrder` for sidebar grouping
@@ -1,7 +1,6 @@
1
1
  import dotenv from "dotenv";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
- const RUNTIME_GRAPH_FILE_PATTERN = /\.generated(?:\.[a-z0-9]+)?(?:\.tsx?|\.checksum)$/i;
5
4
  const DEV_ENV_PRIORITY = [
6
5
  ".env",
7
6
  ".env.development",
@@ -82,47 +81,9 @@ function watchDevEnvFiles(appDir, onChange, options = {}) {
82
81
  }
83
82
  };
84
83
  }
85
- function watchDevRuntimeFiles(appDir, onChange, options = {}) {
86
- const debounceMs = options.debounceMs ?? 250;
87
- const generatedDir = path.join(appDir, ".mercato", "generated");
88
- const timers = /* @__PURE__ */ new Map();
89
- if (!fs.existsSync(generatedDir)) {
90
- return () => {
91
- };
92
- }
93
- let watcher = null;
94
- try {
95
- watcher = fs.watch(generatedDir, (eventType, fileName) => {
96
- if (eventType !== "change" && eventType !== "rename") return;
97
- const name = String(fileName ?? "");
98
- if (!name) return;
99
- if (!RUNTIME_GRAPH_FILE_PATTERN.test(name)) return;
100
- const filePath = path.join(generatedDir, name);
101
- const existingTimer = timers.get(filePath);
102
- if (existingTimer) {
103
- clearTimeout(existingTimer);
104
- }
105
- timers.set(filePath, setTimeout(() => {
106
- timers.delete(filePath);
107
- onChange(filePath);
108
- }, debounceMs));
109
- });
110
- } catch {
111
- return () => {
112
- };
113
- }
114
- return () => {
115
- for (const timer of timers.values()) {
116
- clearTimeout(timer);
117
- }
118
- timers.clear();
119
- watcher?.close();
120
- };
121
- }
122
84
  export {
123
85
  createDevEnvReloader,
124
86
  resolveDevEnvFilePaths,
125
- watchDevEnvFiles,
126
- watchDevRuntimeFiles
87
+ watchDevEnvFiles
127
88
  };
128
89
  //# sourceMappingURL=dev-env-reload.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/dev-env-reload.ts"],
4
- "sourcesContent": ["import dotenv from 'dotenv'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nconst RUNTIME_GRAPH_FILE_PATTERN = /\\.generated(?:\\.[a-z0-9]+)?(?:\\.tsx?|\\.checksum)$/i\n\nconst DEV_ENV_PRIORITY = [\n '.env',\n '.env.development',\n '.env.local',\n '.env.development.local',\n] as const\n\nexport type DevEnvReloader = {\n reload: () => void\n getWatchedFiles: () => string[]\n}\n\nexport function resolveDevEnvFilePaths(appDir: string): string[] {\n return DEV_ENV_PRIORITY.map((fileName) => path.join(appDir, fileName))\n}\n\nexport function createDevEnvReloader(\n appDir: string,\n environment: NodeJS.ProcessEnv = process.env,\n baseEnvironmentEntries: Iterable<[string, string | undefined]> = Object.entries(environment),\n): DevEnvReloader {\n const baseEnvironment = new Map<string, string | undefined>(\n Array.from(baseEnvironmentEntries, ([key, value]) => [key, value]),\n )\n const managedKeys = new Set<string>()\n const envFilePaths = resolveDevEnvFilePaths(appDir)\n\n const resetManagedKeys = () => {\n for (const key of managedKeys) {\n const baseValue = baseEnvironment.get(key)\n if (baseValue === undefined) {\n delete environment[key]\n } else {\n environment[key] = baseValue\n }\n }\n managedKeys.clear()\n }\n\n const reload = () => {\n resetManagedKeys()\n\n for (const envFilePath of envFilePaths) {\n if (!fs.existsSync(envFilePath)) continue\n\n const parsed = dotenv.parse(fs.readFileSync(envFilePath))\n for (const [key, value] of Object.entries(parsed)) {\n if (baseEnvironment.has(key) && baseEnvironment.get(key) !== undefined) {\n continue\n }\n environment[key] = value\n managedKeys.add(key)\n }\n }\n }\n\n return {\n reload,\n getWatchedFiles: () => [...envFilePaths],\n }\n}\n\nexport function watchDevEnvFiles(\n appDir: string,\n onChange: (filePath: string) => void,\n options: { debounceMs?: number } = {},\n): () => void {\n const debounceMs = options.debounceMs ?? 250\n const envFilePaths = resolveDevEnvFilePaths(appDir)\n const timers = new Map<string, NodeJS.Timeout>()\n const watchers = envFilePaths.map((envFilePath) => {\n const watchDir = path.dirname(envFilePath)\n const watchFileName = path.basename(envFilePath)\n\n if (!fs.existsSync(watchDir)) return null\n\n try {\n return fs.watch(watchDir, (eventType, fileName) => {\n if (eventType !== 'change' && eventType !== 'rename') return\n if (String(fileName ?? '') !== watchFileName) return\n\n const existingTimer = timers.get(envFilePath)\n if (existingTimer) {\n clearTimeout(existingTimer)\n }\n\n timers.set(envFilePath, setTimeout(() => {\n timers.delete(envFilePath)\n onChange(envFilePath)\n }, debounceMs))\n })\n } catch {\n return null\n }\n }).filter((watcher): watcher is fs.FSWatcher => watcher !== null)\n\n return () => {\n for (const timer of timers.values()) {\n clearTimeout(timer)\n }\n timers.clear()\n for (const watcher of watchers) {\n watcher.close()\n }\n }\n}\n\nexport function watchDevRuntimeFiles(\n appDir: string,\n onChange: (filePath: string) => void,\n options: { debounceMs?: number } = {},\n): () => void {\n const debounceMs = options.debounceMs ?? 250\n const generatedDir = path.join(appDir, '.mercato', 'generated')\n const timers = new Map<string, NodeJS.Timeout>()\n\n if (!fs.existsSync(generatedDir)) {\n return () => {}\n }\n\n let watcher: fs.FSWatcher | null = null\n try {\n watcher = fs.watch(generatedDir, (eventType, fileName) => {\n if (eventType !== 'change' && eventType !== 'rename') return\n const name = String(fileName ?? '')\n if (!name) return\n if (!RUNTIME_GRAPH_FILE_PATTERN.test(name)) return\n\n const filePath = path.join(generatedDir, name)\n const existingTimer = timers.get(filePath)\n if (existingTimer) {\n clearTimeout(existingTimer)\n }\n\n timers.set(filePath, setTimeout(() => {\n timers.delete(filePath)\n onChange(filePath)\n }, debounceMs))\n })\n } catch {\n return () => {}\n }\n\n return () => {\n for (const timer of timers.values()) {\n clearTimeout(timer)\n }\n timers.clear()\n watcher?.close()\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import dotenv from 'dotenv'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nconst DEV_ENV_PRIORITY = [\n '.env',\n '.env.development',\n '.env.local',\n '.env.development.local',\n] as const\n\nexport type DevEnvReloader = {\n reload: () => void\n getWatchedFiles: () => string[]\n}\n\nexport function resolveDevEnvFilePaths(appDir: string): string[] {\n return DEV_ENV_PRIORITY.map((fileName) => path.join(appDir, fileName))\n}\n\nexport function createDevEnvReloader(\n appDir: string,\n environment: NodeJS.ProcessEnv = process.env,\n baseEnvironmentEntries: Iterable<[string, string | undefined]> = Object.entries(environment),\n): DevEnvReloader {\n const baseEnvironment = new Map<string, string | undefined>(\n Array.from(baseEnvironmentEntries, ([key, value]) => [key, value]),\n )\n const managedKeys = new Set<string>()\n const envFilePaths = resolveDevEnvFilePaths(appDir)\n\n const resetManagedKeys = () => {\n for (const key of managedKeys) {\n const baseValue = baseEnvironment.get(key)\n if (baseValue === undefined) {\n delete environment[key]\n } else {\n environment[key] = baseValue\n }\n }\n managedKeys.clear()\n }\n\n const reload = () => {\n resetManagedKeys()\n\n for (const envFilePath of envFilePaths) {\n if (!fs.existsSync(envFilePath)) continue\n\n const parsed = dotenv.parse(fs.readFileSync(envFilePath))\n for (const [key, value] of Object.entries(parsed)) {\n if (baseEnvironment.has(key) && baseEnvironment.get(key) !== undefined) {\n continue\n }\n environment[key] = value\n managedKeys.add(key)\n }\n }\n }\n\n return {\n reload,\n getWatchedFiles: () => [...envFilePaths],\n }\n}\n\nexport function watchDevEnvFiles(\n appDir: string,\n onChange: (filePath: string) => void,\n options: { debounceMs?: number } = {},\n): () => void {\n const debounceMs = options.debounceMs ?? 250\n const envFilePaths = resolveDevEnvFilePaths(appDir)\n const timers = new Map<string, NodeJS.Timeout>()\n const watchers = envFilePaths.map((envFilePath) => {\n const watchDir = path.dirname(envFilePath)\n const watchFileName = path.basename(envFilePath)\n\n if (!fs.existsSync(watchDir)) return null\n\n try {\n return fs.watch(watchDir, (eventType, fileName) => {\n if (eventType !== 'change' && eventType !== 'rename') return\n if (String(fileName ?? '') !== watchFileName) return\n\n const existingTimer = timers.get(envFilePath)\n if (existingTimer) {\n clearTimeout(existingTimer)\n }\n\n timers.set(envFilePath, setTimeout(() => {\n timers.delete(envFilePath)\n onChange(envFilePath)\n }, debounceMs))\n })\n } catch {\n return null\n }\n }).filter((watcher): watcher is fs.FSWatcher => watcher !== null)\n\n return () => {\n for (const timer of timers.values()) {\n clearTimeout(timer)\n }\n timers.clear()\n for (const watcher of watchers) {\n watcher.close()\n }\n }\n}\n"],
5
+ "mappings": "AAAA,OAAO,YAAY;AACnB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,MAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,SAAS,uBAAuB,QAA0B;AAC/D,SAAO,iBAAiB,IAAI,CAAC,aAAa,KAAK,KAAK,QAAQ,QAAQ,CAAC;AACvE;AAEO,SAAS,qBACd,QACA,cAAiC,QAAQ,KACzC,yBAAiE,OAAO,QAAQ,WAAW,GAC3E;AAChB,QAAM,kBAAkB,IAAI;AAAA,IAC1B,MAAM,KAAK,wBAAwB,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,KAAK,CAAC;AAAA,EACnE;AACA,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,eAAe,uBAAuB,MAAM;AAElD,QAAM,mBAAmB,MAAM;AAC7B,eAAW,OAAO,aAAa;AAC7B,YAAM,YAAY,gBAAgB,IAAI,GAAG;AACzC,UAAI,cAAc,QAAW;AAC3B,eAAO,YAAY,GAAG;AAAA,MACxB,OAAO;AACL,oBAAY,GAAG,IAAI;AAAA,MACrB;AAAA,IACF;AACA,gBAAY,MAAM;AAAA,EACpB;AAEA,QAAM,SAAS,MAAM;AACnB,qBAAiB;AAEjB,eAAW,eAAe,cAAc;AACtC,UAAI,CAAC,GAAG,WAAW,WAAW,EAAG;AAEjC,YAAM,SAAS,OAAO,MAAM,GAAG,aAAa,WAAW,CAAC;AACxD,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAI,gBAAgB,IAAI,GAAG,KAAK,gBAAgB,IAAI,GAAG,MAAM,QAAW;AACtE;AAAA,QACF;AACA,oBAAY,GAAG,IAAI;AACnB,oBAAY,IAAI,GAAG;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,MAAM,CAAC,GAAG,YAAY;AAAA,EACzC;AACF;AAEO,SAAS,iBACd,QACA,UACA,UAAmC,CAAC,GACxB;AACZ,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,eAAe,uBAAuB,MAAM;AAClD,QAAM,SAAS,oBAAI,IAA4B;AAC/C,QAAM,WAAW,aAAa,IAAI,CAAC,gBAAgB;AACjD,UAAM,WAAW,KAAK,QAAQ,WAAW;AACzC,UAAM,gBAAgB,KAAK,SAAS,WAAW;AAE/C,QAAI,CAAC,GAAG,WAAW,QAAQ,EAAG,QAAO;AAErC,QAAI;AACF,aAAO,GAAG,MAAM,UAAU,CAAC,WAAW,aAAa;AACjD,YAAI,cAAc,YAAY,cAAc,SAAU;AACtD,YAAI,OAAO,YAAY,EAAE,MAAM,cAAe;AAE9C,cAAM,gBAAgB,OAAO,IAAI,WAAW;AAC5C,YAAI,eAAe;AACjB,uBAAa,aAAa;AAAA,QAC5B;AAEA,eAAO,IAAI,aAAa,WAAW,MAAM;AACvC,iBAAO,OAAO,WAAW;AACzB,mBAAS,WAAW;AAAA,QACtB,GAAG,UAAU,CAAC;AAAA,MAChB,CAAC;AAAA,IACH,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC,EAAE,OAAO,CAAC,YAAqC,YAAY,IAAI;AAEhE,SAAO,MAAM;AACX,eAAW,SAAS,OAAO,OAAO,GAAG;AACnC,mBAAa,KAAK;AAAA,IACpB;AACA,WAAO,MAAM;AACb,eAAW,WAAW,UAAU;AAC9B,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -2352,13 +2352,6 @@ async function startEphemeralEnvironment(options) {
2352
2352
  // on `DEMO_MODE !== 'false'` in the backend layout, so opting out here
2353
2353
  // only affects the integration test runtime — dev + prod stay unchanged.
2354
2354
  DEMO_MODE: "false",
2355
- // Disable the feature-toggle resolution cache. Tests flip overrides
2356
- // (e.g. example_customers_sync enabled/bidirectional) between cases; the
2357
- // 1-minute resolution cache can serve a stale value across set/clear
2358
- // under fast churn, which made the example.todo.* persistent subscribers
2359
- // skip enqueueing inbound sync jobs (TC-CRM-028 inbound trio flake).
2360
- // Fresh DB reads make flag-gated sync deterministic in tests only.
2361
- OM_FEATURE_TOGGLES_CACHE_DISABLED: "1",
2362
2355
  OM_CLI_QUIET: "1",
2363
2356
  MERCATO_QUIET: "1",
2364
2357
  QUEUE_BASE_DIR: EPHEMERAL_QUEUE_BASE_DIR,