@open-mercato/cli 0.6.6-develop.6381.1.042df302c3 → 0.6.6-develop.6382.1.4b9b9091ab

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.
Files changed (31) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/agentic/guides/core.md +3 -38
  3. package/dist/agentic/guides/module-system.md +130 -0
  4. package/dist/agentic/shared/AGENTS.md.template +4 -12
  5. package/dist/lib/generators/index.js +2 -0
  6. package/dist/lib/generators/index.js.map +2 -2
  7. package/dist/lib/generators/module-facts-generate.js +52 -0
  8. package/dist/lib/generators/module-facts-generate.js.map +7 -0
  9. package/dist/lib/generators/module-facts.js +734 -0
  10. package/dist/lib/generators/module-facts.js.map +7 -0
  11. package/dist/mercato.js +3 -1
  12. package/dist/mercato.js.map +2 -2
  13. package/package.json +5 -5
  14. package/src/__tests__/mercato.test.ts +5 -0
  15. package/src/lib/generators/__tests__/module-facts.auth-source.test.ts +83 -0
  16. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +56 -0
  17. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +69 -0
  18. package/src/lib/generators/__tests__/module-facts.malformed.test.ts +76 -0
  19. package/src/lib/generators/index.ts +1 -0
  20. package/src/lib/generators/module-facts-generate.ts +68 -0
  21. package/src/lib/generators/module-facts.ts +958 -0
  22. package/src/mercato.ts +2 -0
  23. package/dist/agentic/guides/core.auth.md +0 -101
  24. package/dist/agentic/guides/core.catalog.md +0 -79
  25. package/dist/agentic/guides/core.currencies.md +0 -43
  26. package/dist/agentic/guides/core.customer_accounts.md +0 -129
  27. package/dist/agentic/guides/core.customers.md +0 -138
  28. package/dist/agentic/guides/core.data_sync.md +0 -107
  29. package/dist/agentic/guides/core.integrations.md +0 -113
  30. package/dist/agentic/guides/core.sales.md +0 -104
  31. package/dist/agentic/guides/core.workflows.md +0 -152
@@ -1,4 +1,4 @@
1
- [build:cli] found 91 entry points
1
+ [build:cli] found 93 entry points
2
2
  Copied create-app/agentic/ → dist/agentic/
3
- Discovered 16 standalone guides → dist/agentic/guides/
3
+ Discovered 7 standalone guides → dist/agentic/guides/
4
4
  [build:cli] built successfully
@@ -2,44 +2,9 @@
2
2
 
3
3
  `@open-mercato/core` contains all built-in business modules. This guide covers module development patterns for standalone apps that build on top of these modules.
4
4
 
5
- ## Auto-Discovery Paths
6
-
7
- Place files in your module directory (`src/modules/<module>/`) the framework discovers them automatically:
8
-
9
- | Path Pattern | Becomes |
10
- |---|---|
11
- | `frontend/<path>.tsx` | `/<path>` (public page) |
12
- | `backend/<path>.tsx` | `/backend/<path>` (admin page) |
13
- | `backend/page.tsx` | `/backend/<module>` (module root page) |
14
- | `api/<method>/<path>.ts` | `/api/<path>` dispatched by HTTP method |
15
- | `subscribers/*.ts` | Event subscriber (export `metadata` + default handler) |
16
- | `workers/*.ts` | Background worker (export `metadata` + default handler) |
17
-
18
- Run `yarn generate` after adding any auto-discovered file.
19
-
20
- ## Module Files Reference
21
-
22
- | File | Export | Purpose |
23
- |------|--------|---------|
24
- | `index.ts` | `metadata` | Module metadata |
25
- | `di.ts` | `register(container)` | DI registrations (Awilix) |
26
- | `acl.ts` | `features` | Permission features: `['mod.view', 'mod.create', ...]` |
27
- | `setup.ts` | `setup: ModuleSetupConfig` | Tenant init, role features, seed data |
28
- | `ce.ts` | `entities` | Custom entities / custom field sets |
29
- | `events.ts` | `eventsConfig` | Typed event declarations |
30
- | `search.ts` | `searchConfig` | Search indexing config |
31
- | `translations.ts` | `translatableFields` | Translatable fields per entity |
32
- | `notifications.ts` | `notificationTypes` | Notification type definitions |
33
- | `notifications.client.ts` | — | Client-side notification renderers |
34
- | `notifications.handlers.ts` | `notificationHandlers` | Reactive notification side-effects |
35
- | `data/entities.ts` | — | MikroORM entity classes |
36
- | `data/validators.ts` | — | Zod validation schemas |
37
- | `data/extensions.ts` | `extensions` | Entity extensions (cross-module links) |
38
- | `data/enrichers.ts` | `enrichers` | Response enrichers |
39
- | `api/interceptors.ts` | `interceptors` | API route interception hooks |
40
- | `widgets/injection/` | — | Injected UI widgets |
41
- | `widgets/injection-table.ts` | — | Widget-to-slot mappings |
42
- | `widgets/components.ts` | `componentOverrides` | Component replacement/wrapper definitions |
5
+ ## Module anatomy, auto-discovery & convention files
6
+
7
+ > Moved to the conceptual guide. See **`.ai/guides/module-system.md` Module anatomy** for the auto-discovery path table and the convention-file reference — they are framework-wide, not core-specific. The sections below cover `@open-mercato/core`-specific development patterns.
43
8
 
44
9
  ## API Routes
45
10
 
@@ -0,0 +1,130 @@
1
+ # Open Mercato Module System — Conceptual Guide
2
+
3
+ This is the **hand-written, conceptual** layer of the module guides. It explains how an Open Mercato module is structured and how to build or extend one — the timeless concepts that rarely change. It is framework-wide; it does **not** describe any single module's data.
4
+
5
+ ## How the guides are layered
6
+
7
+ - **Layer 1 — this file (`.ai/guides/module-system.md`):** conceptual and framework-wide. Module anatomy, auto-discovery, naming, the mandatory mechanisms, data-integrity rules, and the generate/migration workflow.
8
+ - **Layer 2 — generated per-module fact-sheets (`.ai/guides/modules/<module>.md` + `.ai/guides/module-facts.json`):** the concrete **facts** for one module, extracted from its source — entity IDs, events, ACL features, API routes with per-method auth, DI service tokens, searchable entities, host extension tokens, notifications, and CLI commands. These are generated; never hand-write them here.
9
+ - **Package guides (`.ai/guides/core.md`, `ui.md`, `shared.md`, …):** package-specific depth (patterns, helpers, deeper APIs).
10
+
11
+ When you need a concrete fact about a specific module — which events it emits, its entity IDs, which feature gates a route — open that module's fact-sheet. Do not infer module facts from this conceptual guide.
12
+
13
+ ## Module anatomy
14
+
15
+ Each module lives in `src/modules/<id>/` and is **auto-discovered**. The only registration is one entry in `src/modules.ts` (`{ id: '<id>', from: '@app' }`). Run `yarn generate` after adding or changing any auto-discovered file.
16
+
17
+ ```
18
+ src/modules/<id>/
19
+ ├── index.ts # Module metadata
20
+ ├── data/
21
+ │ ├── entities.ts # MikroORM entity classes (decorators from @mikro-orm/decorators/legacy)
22
+ │ ├── validators.ts # Zod validation schemas
23
+ │ ├── extensions.ts # Cross-module entity links (export `extensions`)
24
+ │ └── enrichers.ts # Response enrichers (export `enrichers`)
25
+ ├── api/
26
+ │ ├── <resource>/route.ts # REST handlers (auto-discovered by method) + `metadata` + `openApi`
27
+ │ └── interceptors.ts # API route interception hooks (export `interceptors`)
28
+ ├── backend/ # Admin UI pages (auto-discovered) + paired `page.meta.ts`
29
+ ├── frontend/ # Public pages (auto-discovered); customer portal under `[orgSlug]/portal/`
30
+ ├── subscribers/ # Event handlers (export `metadata` + default handler)
31
+ ├── workers/ # Background jobs (export `metadata` + default handler)
32
+ ├── widgets/
33
+ │ ├── injection/ # UI widgets injected into other modules
34
+ │ ├── injection-table.ts # Widget-to-slot mappings
35
+ │ └── components.ts # Component replacement/wrapper definitions (export `componentOverrides`)
36
+ ├── di.ts # Awilix DI registrations (export `register(container)`)
37
+ ├── acl.ts # Permission features (export `features`)
38
+ ├── setup.ts # Tenant init, role features, seed data (export `setup`)
39
+ ├── events.ts # Typed event declarations (export `eventsConfig`)
40
+ ├── search.ts # Search indexing configuration (export `searchConfig`)
41
+ ├── ce.ts # Custom entities / custom field sets (export `entities`)
42
+ ├── translations.ts # Translatable fields per entity
43
+ ├── notifications.ts # Notification type definitions (export `notificationTypes`)
44
+ └── encryption.ts # Tenant data encryption maps for sensitive / GDPR fields
45
+ ```
46
+
47
+ ### Auto-discovery paths
48
+
49
+ | Path pattern | Becomes |
50
+ |---|---|
51
+ | `frontend/<path>.tsx` | `/<path>` (public page) |
52
+ | `frontend/[orgSlug]/portal/<path>/page.tsx` | `/{orgSlug}/portal/<path>` (customer portal page; `[orgSlug]` MUST be first) |
53
+ | `backend/<path>.tsx` | `/backend/<path>` (admin page) |
54
+ | `backend/page.tsx` | `/backend/<module>` (module root page) |
55
+ | `api/<method>/<path>.ts` | `/api/<path>` dispatched by HTTP method |
56
+ | `subscribers/*.ts` | event subscriber (export `metadata` + default handler) |
57
+ | `workers/*.ts` | background worker (export `metadata` + default handler) |
58
+
59
+ ### Convention-file reference
60
+
61
+ | File | Export | Purpose |
62
+ |------|--------|---------|
63
+ | `index.ts` | `metadata` | Module metadata |
64
+ | `di.ts` | `register(container)` | DI registrations (Awilix) |
65
+ | `acl.ts` | `features` | Permission features (`['mod.view', 'mod.manage', …]`) |
66
+ | `setup.ts` | `setup` | Tenant init, default role features, seed data |
67
+ | `ce.ts` | `entities` | Custom entities / custom field sets |
68
+ | `events.ts` | `eventsConfig` | Typed event declarations (`createModuleEvents`) |
69
+ | `search.ts` | `searchConfig` | Search indexing config |
70
+ | `translations.ts` | `translatableFields` | Translatable fields per entity |
71
+ | `notifications.ts` | `notificationTypes` | Notification type definitions |
72
+ | `data/entities.ts` | — | MikroORM entity classes |
73
+ | `data/validators.ts` | — | Zod validation schemas |
74
+ | `data/extensions.ts` | `extensions` | Entity extensions (cross-module links) |
75
+ | `data/enrichers.ts` | `enrichers` | Response enrichers |
76
+ | `api/interceptors.ts` | `interceptors` | API route interception hooks |
77
+ | `widgets/components.ts` | `componentOverrides` | Component replacement/wrapper definitions |
78
+
79
+ ## Naming conventions
80
+
81
+ - **Module IDs:** plural, snake_case (`order_items`). Special cases: `auth`, `example`.
82
+ - **Event IDs:** `module.entity.action` (singular entity, past-tense action, e.g. `sales.order.created`).
83
+ - **Entity IDs:** colon form `module:entity` (e.g. `customers:customer_person_profile`) — the canonical interop token, **not** the raw class name and **not** the dotted friendly alias some enrichers use.
84
+ - **DB tables:** plural, snake_case with a module prefix (`catalog_products`).
85
+ - **DB columns:** snake_case (`created_at`, `organization_id`). Common columns: `id`, `created_at`, `updated_at`, `deleted_at`, `is_active`, `organization_id`, `tenant_id`.
86
+ - **Feature IDs:** `<module>.<action>` (`my_module.view`, `my_module.manage`). FROZEN once shipped — rename by adding the new ID alongside and keeping the old as a deprecated alias.
87
+ - **JS/TS identifiers:** camelCase. UUID primary keys, explicit foreign keys, junction tables for M2M.
88
+
89
+ ## Mandatory module mechanisms
90
+
91
+ The framework provides **one canonical primitive per concern**. Do not invent your own routing, auth, persistence, forms, caching, or cross-module calls. If a feature is not listed here, ask before rolling your own.
92
+
93
+ | Concern | Canonical mechanism |
94
+ |---|---|
95
+ | Module structure & auto-discovery | `src/modules/<id>/{api,backend,frontend,data,subscribers,workers,widgets}` + `index.ts` + one line in `src/modules.ts` — discovered by `yarn generate` |
96
+ | API routes | Files under `api/**/route.ts` exporting handlers + per-method `metadata` (`requireAuth` / `requireFeatures`) + `openApi`. NEVER a top-level `export const requireAuth` — the registry ignores it |
97
+ | CRUD APIs | `makeCrudRoute({ orm, list, create, update, del, indexer })` from `@open-mercato/shared/lib/crud/factory`. Always set `indexer` for query-index coverage. Custom (non-factory) write routes MUST run the mutation guard registry (`runMutationGuards`) |
98
+ | CRUD forms | `<CrudForm />` from `@open-mercato/ui/backend/CrudForm` + `createCrud`/`updateCrud`/`deleteCrud`. Never raw `<form>`, never raw `fetch` |
99
+ | Data tables | `<DataTable entityId apiPath … />` from `@open-mercato/ui/backend/DataTable`. Keep `entityId` / `extensionTableId` stable so widget injection keeps working |
100
+ | HTTP from the client | `apiCall` / `apiCallOrThrow` from `@open-mercato/ui/backend/utils/apiCall` — never raw `fetch` |
101
+ | Authorization (RBAC) | Declare features in `acl.ts`, grant in `setup.ts` `defaultRoleFeatures`, gate with `requireFeatures` in `metadata` / `page.meta.ts`. NEVER `requireRoles` (role names mutate). Treat `module.*` / `*` wildcard grants as part of the contract |
102
+ | Multi-tenant scoping | Every tenant-scoped entity has indexed `organization_id` + `tenant_id`; every read/write filters by them. The CRUD factory injects scope — do not bypass it. Ad-hoc queries use `withScopedPayload` |
103
+ | Encryption for sensitive data | Declare `encryption.ts` `defaultEncryptionMaps`; read via `findWithDecryption` / `findOneWithDecryption`. NEVER hand-roll AES/KMS, NEVER `em.find` on encrypted columns |
104
+ | Cache | Resolve from DI (`container.resolve('cache')`) — never `new Redis(...)`. Tag with `tenant:<id>` / `org:<id>` so invalidation stays tenant-scoped |
105
+ | Background workers | `workers/*.ts` exporting `metadata: { queue, id?, concurrency? }` + default handler. Never spin up custom queues |
106
+ | Events between modules | `events.ts` with `createModuleEvents({ moduleId, events } as const)`; subscribe in `subscribers/`. Never call another module's services directly across boundaries |
107
+ | Domain writes | Implement through the Command pattern so audit, undo, cache, events, and indexing stay consistent — do not mutate domain state directly in route handlers |
108
+ | i18n | `useT()` client-side, `resolveTranslations()` server-side; keys in `src/i18n/<locale>.json`. Never hard-code user-facing strings |
109
+
110
+ > Rule of thumb: if you reach for raw `fetch`, raw `<form>`, ad-hoc `crypto`, ad-hoc `Redis`, or a manual cross-module join, stop and check the row above — there is a canonical helper.
111
+
112
+ ## Entity-update safety & data integrity
113
+
114
+ - **`withAtomicFlush`.** MikroORM can silently discard pending scalar changes when a query (`em.find`/`em.findOne`/sync helper) runs on the same `EntityManager` between a scalar mutation and `em.flush()`. Multi-phase mutations MUST use `withAtomicFlush(em, phases, { transaction: true })` from `@open-mercato/shared/lib/commands/flush`. Keep `emitCrudSideEffects` and cache invalidation **outside** the block — they fire only after the DB write commits. For entity + custom fields + side effects in one write, prefer `runCrudCommandWrite`.
115
+ - **Optimistic locking (default ON).** Every **new user-editable entity** MUST carry an `updated_at` column and return `updatedAt` in its list/detail responses, so the OSS optimistic lock can detect concurrent edits. `CrudForm` auto-derives the lock header from `initialValues.updatedAt` (covers update and delete). Append-only logs, junction/assignment tables, session/token rows, and parent-guarded sub-resource lines are exempt.
116
+ - **Encryption.** Sensitive / GDPR fields go through the encryption-maps mechanism (`encryption.ts` + `findWithDecryption`), never hand-rolled crypto. Always pass `tenantId` and `organizationId` to the decryption helpers.
117
+ - **Tenant isolation.** Never expose cross-tenant data; always filter by `organization_id` (and `tenant_id`). Never create direct ORM relationships between modules — reference by FK id and fetch separately.
118
+
119
+ ## Generate & migration workflow
120
+
121
+ - **After editing `src/modules.ts` or any structural module file:** run `yarn generate`. Never hand-edit anything under `.mercato/generated/*`.
122
+ - **After editing `data/entities.ts`:** run `yarn db:generate` as a schema-diff probe. Default to the generated SQL; if it emits unrelated churn from another module's stale snapshot, keep only the SQL for your change and update that module's `migrations/.snapshot-open-mercato.json` in the same commit.
123
+ - **Do not run `yarn db:migrate`** unless the user explicitly asks. A PR should normally include the migration file plus snapshot, not local DB state. Never hand-edit a migration that has already shipped — add a new one.
124
+ - **New ACL features must be visible immediately:** add the feature to `acl.ts` **and** to `setup.ts` `defaultRoleFeatures`, then run `yarn mercato auth sync-role-acls` so existing tenants pick it up.
125
+
126
+ ## Where to go next
127
+
128
+ - A specific module's surface (entities, events, routes, auth, search, CLI): its **fact-sheet** at `.ai/guides/modules/<module>.md`.
129
+ - Deeper package patterns: the matching **package guide** (`core.md`, `ui.md`, `shared.md`, `events.md`, `queue.md`, `cache.md`, `search.md`).
130
+ - Scaffolding a module end-to-end: the `om-module-scaffold` skill.
@@ -21,6 +21,7 @@ step, you WILL produce incorrect imports and miss required patterns.
21
21
 
22
22
  | Task | Load |
23
23
  |---|---|
24
+ | Understand the module system (anatomy, auto-discovery, naming, mandatory mechanisms, data integrity, migrations) | `.ai/guides/module-system.md` |
24
25
  | Scaffold a new module from scratch | `.ai/skills/om-module-scaffold/SKILL.md` |
25
26
  | Design entities and relationships | `.ai/skills/om-data-model-design/SKILL.md` |
26
27
  | Build backend UI (forms, tables, pages) | `.ai/skills/om-backend-ui-design/SKILL.md` |
@@ -60,19 +61,10 @@ step, you WILL produce incorrect imports and miss required patterns.
60
61
 
61
62
  ### Module-Specific Guides
62
63
 
63
- These guides ship automatically when the corresponding module is installed.
64
+ These per-module fact-sheets are **generated from source** and bundled for the modules enabled in this app. The list below is regenerated on scaffold from your enabled module set — do not edit between the markers.
64
65
 
65
- | Task | Load |
66
- |---|---|
67
- | Build CRUD modules — reference patterns, commands, custom fields, search | `.ai/guides/core.customers.md` (if available) |
68
- | Use workflow automation, triggers, user tasks, signals | `.ai/guides/core.workflows.md` (if available) |
69
- | Use product catalog, pricing engine, variants, offers | `.ai/guides/core.catalog.md` (if available) |
70
- | Use sales orders, quotes, invoices, shipments, payments | `.ai/guides/core.sales.md` (if available) |
71
- | Use staff authentication, RBAC, roles, feature guards | `.ai/guides/core.auth.md` (if available) |
72
- | Use multi-currency, exchange rates, dual recording | `.ai/guides/core.currencies.md` (if available) |
73
- | Build integration providers, credentials, health checks | `.ai/guides/core.integrations.md` (if available) |
74
- | Build data sync adapters, import/export connectors | `.ai/guides/core.data_sync.md` (if available) |
75
- | Use customer portal auth, customer RBAC, portal pages | `.ai/guides/core.customer_accounts.md` (if available) |
66
+ <!-- om:module-guides:start -->
67
+ <!-- om:module-guides:end -->
76
68
 
77
69
  ### Quality & Process
78
70
 
@@ -4,10 +4,12 @@ import { generateModuleEntities } from "./module-entities.js";
4
4
  import { generateModuleDi } from "./module-di.js";
5
5
  import { generateModulePackageSources } from "./module-package-sources.js";
6
6
  import { generateOpenApi } from "./openapi.js";
7
+ import { generateModuleFacts } from "./module-facts-generate.js";
7
8
  export {
8
9
  generateEntityIds,
9
10
  generateModuleDi,
10
11
  generateModuleEntities,
12
+ generateModuleFacts,
11
13
  generateModulePackageSources,
12
14
  generateModuleRegistry,
13
15
  generateModuleRegistryApp,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/generators/index.ts"],
4
- "sourcesContent": ["export { generateEntityIds, type EntityIdsOptions } from './entity-ids'\nexport { generateModuleRegistry, generateModuleRegistryApp, generateModuleRegistryCli, type ModuleRegistryOptions } from './module-registry'\nexport { generateModuleEntities, type ModuleEntitiesOptions } from './module-entities'\nexport { generateModuleDi, type ModuleDiOptions } from './module-di'\nexport { generateModulePackageSources, type ModulePackageSourcesOptions } from './module-package-sources'\nexport { generateOpenApi, type GenerateOpenApiOptions } from './openapi'\n"],
5
- "mappings": "AAAA,SAAS,yBAAgD;AACzD,SAAS,wBAAwB,2BAA2B,iCAA6D;AACzH,SAAS,8BAA0D;AACnE,SAAS,wBAA8C;AACvD,SAAS,oCAAsE;AAC/E,SAAS,uBAAoD;",
4
+ "sourcesContent": ["export { generateEntityIds, type EntityIdsOptions } from './entity-ids'\nexport { generateModuleRegistry, generateModuleRegistryApp, generateModuleRegistryCli, type ModuleRegistryOptions } from './module-registry'\nexport { generateModuleEntities, type ModuleEntitiesOptions } from './module-entities'\nexport { generateModuleDi, type ModuleDiOptions } from './module-di'\nexport { generateModulePackageSources, type ModulePackageSourcesOptions } from './module-package-sources'\nexport { generateOpenApi, type GenerateOpenApiOptions } from './openapi'\nexport { generateModuleFacts, type ModuleFactsOptions } from './module-facts-generate'\n"],
5
+ "mappings": "AAAA,SAAS,yBAAgD;AACzD,SAAS,wBAAwB,2BAA2B,iCAA6D;AACzH,SAAS,8BAA0D;AACnE,SAAS,wBAA8C;AACvD,SAAS,oCAAsE;AAC/E,SAAS,uBAAoD;AAC7D,SAAS,2BAAoD;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,52 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ createGeneratorResult,
5
+ ensureDir,
6
+ logGenerationResult
7
+ } from "../utils.js";
8
+ import { extractAllModuleFacts, renderModuleFactsJson } from "./module-facts.js";
9
+ function readCoreVersion(coreSrcRoot) {
10
+ const corePackageJsonPath = path.resolve(coreSrcRoot, "..", "..", "package.json");
11
+ if (!fs.existsSync(corePackageJsonPath)) return null;
12
+ try {
13
+ const parsed = JSON.parse(fs.readFileSync(corePackageJsonPath, "utf8"));
14
+ return typeof parsed.version === "string" ? parsed.version : null;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ async function generateModuleFacts(options) {
20
+ const { resolver, quiet } = options;
21
+ const result = createGeneratorResult();
22
+ const rootDir = resolver.getRootDir();
23
+ const coreSrcRoot = path.join(rootDir, "packages", "core", "src", "modules");
24
+ if (!fs.existsSync(coreSrcRoot)) {
25
+ if (!quiet) {
26
+ console.warn(`[module-facts] core module sources not found at ${coreSrcRoot}; skipping module-facts generation`);
27
+ }
28
+ return result;
29
+ }
30
+ const registryPath = path.join(resolver.getOutputDir(), "modules.runtime.generated.ts");
31
+ const coreVersion = readCoreVersion(coreSrcRoot);
32
+ const { factsByModule, warnings } = extractAllModuleFacts({ coreSrcRoot, registryPath, coreVersion });
33
+ for (const warning of warnings) {
34
+ console.warn(warning);
35
+ }
36
+ const content = renderModuleFactsJson(factsByModule);
37
+ const outFile = path.join(resolver.getAppDir(), "src", "module-facts.generated.json");
38
+ const existing = fs.existsSync(outFile) ? fs.readFileSync(outFile, "utf8") : null;
39
+ if (existing === content) {
40
+ result.filesUnchanged.push(outFile);
41
+ return result;
42
+ }
43
+ ensureDir(outFile);
44
+ fs.writeFileSync(outFile, content);
45
+ result.filesWritten.push(outFile);
46
+ logGenerationResult(path.relative(process.cwd(), outFile), true);
47
+ return result;
48
+ }
49
+ export {
50
+ generateModuleFacts
51
+ };
52
+ //# sourceMappingURL=module-facts-generate.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/generators/module-facts-generate.ts"],
4
+ "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { PackageResolver } from '../resolver'\nimport {\n createGeneratorResult,\n ensureDir,\n logGenerationResult,\n type GeneratorResult,\n} from '../utils'\nimport { extractAllModuleFacts, renderModuleFactsJson } from './module-facts'\n\nexport interface ModuleFactsOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\nfunction readCoreVersion(coreSrcRoot: string): string | null {\n const corePackageJsonPath = path.resolve(coreSrcRoot, '..', '..', 'package.json')\n if (!fs.existsSync(corePackageJsonPath)) return null\n try {\n const parsed = JSON.parse(fs.readFileSync(corePackageJsonPath, 'utf8')) as { version?: unknown }\n return typeof parsed.version === 'string' ? parsed.version : null\n } catch {\n return null\n }\n}\n\n/**\n * Emits the versioned `apps/mercato/src/module-facts.generated.json` artifact from\n * monorepo core module sources. Must run AFTER `generateModuleRegistry` because\n * per-route API auth is read from the generated `modules.runtime.generated.ts`\n * registry (`apis[].metadata`). Registry-derived warnings are non-fatal.\n */\nexport async function generateModuleFacts(options: ModuleFactsOptions): Promise<GeneratorResult> {\n const { resolver, quiet } = options\n const result = createGeneratorResult()\n\n const rootDir = resolver.getRootDir()\n const coreSrcRoot = path.join(rootDir, 'packages', 'core', 'src', 'modules')\n if (!fs.existsSync(coreSrcRoot)) {\n if (!quiet) {\n console.warn(`[module-facts] core module sources not found at ${coreSrcRoot}; skipping module-facts generation`)\n }\n return result\n }\n\n const registryPath = path.join(resolver.getOutputDir(), 'modules.runtime.generated.ts')\n const coreVersion = readCoreVersion(coreSrcRoot)\n\n const { factsByModule, warnings } = extractAllModuleFacts({ coreSrcRoot, registryPath, coreVersion })\n for (const warning of warnings) {\n console.warn(warning)\n }\n\n const content = renderModuleFactsJson(factsByModule)\n const outFile = path.join(resolver.getAppDir(), 'src', 'module-facts.generated.json')\n const existing = fs.existsSync(outFile) ? fs.readFileSync(outFile, 'utf8') : null\n if (existing === content) {\n result.filesUnchanged.push(outFile)\n return result\n }\n\n ensureDir(outFile)\n fs.writeFileSync(outFile, content)\n result.filesWritten.push(outFile)\n logGenerationResult(path.relative(process.cwd(), outFile), true)\n return result\n}\n"],
5
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,uBAAuB,6BAA6B;AAO7D,SAAS,gBAAgB,aAAoC;AAC3D,QAAM,sBAAsB,KAAK,QAAQ,aAAa,MAAM,MAAM,cAAc;AAChF,MAAI,CAAC,GAAG,WAAW,mBAAmB,EAAG,QAAO;AAChD,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,qBAAqB,MAAM,CAAC;AACtE,WAAO,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,EAC/D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,oBAAoB,SAAuD;AAC/F,QAAM,EAAE,UAAU,MAAM,IAAI;AAC5B,QAAM,SAAS,sBAAsB;AAErC,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,cAAc,KAAK,KAAK,SAAS,YAAY,QAAQ,OAAO,SAAS;AAC3E,MAAI,CAAC,GAAG,WAAW,WAAW,GAAG;AAC/B,QAAI,CAAC,OAAO;AACV,cAAQ,KAAK,mDAAmD,WAAW,oCAAoC;AAAA,IACjH;AACA,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,KAAK,KAAK,SAAS,aAAa,GAAG,8BAA8B;AACtF,QAAM,cAAc,gBAAgB,WAAW;AAE/C,QAAM,EAAE,eAAe,SAAS,IAAI,sBAAsB,EAAE,aAAa,cAAc,YAAY,CAAC;AACpG,aAAW,WAAW,UAAU;AAC9B,YAAQ,KAAK,OAAO;AAAA,EACtB;AAEA,QAAM,UAAU,sBAAsB,aAAa;AACnD,QAAM,UAAU,KAAK,KAAK,SAAS,UAAU,GAAG,OAAO,6BAA6B;AACpF,QAAM,WAAW,GAAG,WAAW,OAAO,IAAI,GAAG,aAAa,SAAS,MAAM,IAAI;AAC7E,MAAI,aAAa,SAAS;AACxB,WAAO,eAAe,KAAK,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,YAAU,OAAO;AACjB,KAAG,cAAc,SAAS,OAAO;AACjC,SAAO,aAAa,KAAK,OAAO;AAChC,sBAAoB,KAAK,SAAS,QAAQ,IAAI,GAAG,OAAO,GAAG,IAAI;AAC/D,SAAO;AACT;",
6
+ "names": []
7
+ }