@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.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +1 -1
- package/dist/agentic/shared/AGENTS.md.template +0 -1
- package/dist/lib/dev-env-reload.js +1 -40
- package/dist/lib/dev-env-reload.js.map +2 -2
- package/dist/lib/testing/integration.js +0 -7
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +98 -244
- package/dist/mercato.js.map +2 -2
- package/package.json +8 -7
- package/src/__tests__/mercato.test.ts +3 -13
- package/src/lib/__tests__/dev-env-reload.test.ts +1 -21
- package/src/lib/dev-env-reload.ts +0 -47
- package/src/lib/testing/integration.ts +0 -7
- package/src/mercato.ts +67 -241
- package/dist/lib/generate-watch-structure.js +0 -153
- package/dist/lib/generate-watch-structure.js.map +0 -7
- package/src/lib/__tests__/generate-watch-structure.test.ts +0 -80
- package/src/lib/generate-watch-structure.ts +0 -170
package/.turbo/turbo-build.log
CHANGED
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
|
|
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
|
|
5
|
-
"mappings": "AAAA,OAAO,YAAY;AACnB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,MAAM,
|
|
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,
|