@open-mercato/cli 0.10.1-develop.7990.1.82d0a183c5 → 0.10.1-develop.8004.1.a8a79ee43f

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 (182) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build.mjs +1 -0
  3. package/dist/agentic/guides/module-facts.json +162 -162
  4. package/dist/agentic/guides/module-facts.v2.json +162 -162
  5. package/dist/agentic/guides/module-tool.md +21 -0
  6. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  7. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  8. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  9. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  10. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  11. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  12. package/dist/agentic/guides/modules/auth/index.md +1 -1
  13. package/dist/agentic/guides/modules/availability/index.md +1 -1
  14. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  15. package/dist/agentic/guides/modules/carrier_inpost/index.md +1 -1
  16. package/dist/agentic/guides/modules/cart/index.md +1 -1
  17. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  18. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  19. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  20. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  21. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  22. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  23. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  24. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  25. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  26. package/dist/agentic/guides/modules/channel_smtp/index.md +1 -1
  27. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  28. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  29. package/dist/agentic/guides/modules/configs/index.md +1 -1
  30. package/dist/agentic/guides/modules/content/index.md +1 -1
  31. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  32. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  33. package/dist/agentic/guides/modules/customer_groups/index.md +1 -1
  34. package/dist/agentic/guides/modules/customers/index.md +1 -1
  35. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  36. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  37. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  38. package/dist/agentic/guides/modules/devices/index.md +1 -1
  39. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  40. package/dist/agentic/guides/modules/directory/index.md +1 -1
  41. package/dist/agentic/guides/modules/documents/index.md +1 -1
  42. package/dist/agentic/guides/modules/ecommerce/index.md +1 -1
  43. package/dist/agentic/guides/modules/entities/index.md +1 -1
  44. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  45. package/dist/agentic/guides/modules/events/index.md +1 -1
  46. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  47. package/dist/agentic/guides/modules/forms/index.md +1 -1
  48. package/dist/agentic/guides/modules/gateway_autopay/index.md +1 -1
  49. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  50. package/dist/agentic/guides/modules/gateway_tpay/index.md +1 -1
  51. package/dist/agentic/guides/modules/generators/index.md +1 -1
  52. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  53. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  54. package/dist/agentic/guides/modules/messages/index.md +1 -1
  55. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  56. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  57. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  58. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  59. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  60. package/dist/agentic/guides/modules/planner/index.md +1 -1
  61. package/dist/agentic/guides/modules/portal/index.md +1 -1
  62. package/dist/agentic/guides/modules/progress/index.md +1 -1
  63. package/dist/agentic/guides/modules/promotions/index.md +1 -1
  64. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  65. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  66. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  67. package/dist/agentic/guides/modules/resources/index.md +1 -1
  68. package/dist/agentic/guides/modules/sales/index.md +1 -1
  69. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  70. package/dist/agentic/guides/modules/search/index.md +1 -1
  71. package/dist/agentic/guides/modules/security/index.md +1 -1
  72. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  73. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  74. package/dist/agentic/guides/modules/sso/index.md +1 -1
  75. package/dist/agentic/guides/modules/staff/index.md +1 -1
  76. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  77. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  78. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  79. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  80. package/dist/agentic/guides/modules/telemetry/index.md +1 -1
  81. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  82. package/dist/agentic/guides/modules/translations/index.md +1 -1
  83. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  84. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  85. package/dist/agentic/guides/modules/wms/index.md +1 -1
  86. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  87. package/dist/agentic/guides/reference-module-facts.json +1 -1
  88. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +4 -0
  89. package/dist/agentic/guides/upstream/manifest.json +2 -2
  90. package/dist/agentic/shared/ai/harness/cases.json +23 -9
  91. package/dist/agentic/shared/ai/harness/source-link-inventory.json +90 -4
  92. package/dist/i18n/de.json +4 -0
  93. package/dist/i18n/en.json +4 -0
  94. package/dist/i18n/es.json +4 -0
  95. package/dist/i18n/ko.json +4 -0
  96. package/dist/i18n/pl.json +4 -0
  97. package/dist/lib/__fixtures__/module-search/built-in.json +235 -0
  98. package/dist/lib/__fixtures__/module-search/catalog-parity.json +4076 -0
  99. package/dist/lib/__fixtures__/module-search/modules-index.json +1980 -0
  100. package/dist/lib/__fixtures__/official-module-package/package.json +33 -0
  101. package/dist/lib/__integration__/TC-INT-007.spec.js +207 -19
  102. package/dist/lib/__integration__/TC-INT-007.spec.js.map +2 -2
  103. package/dist/lib/__integration__/TC-INT-009.spec.js +267 -0
  104. package/dist/lib/__integration__/TC-INT-009.spec.js.map +7 -0
  105. package/dist/lib/eject.js +25 -9
  106. package/dist/lib/eject.js.map +2 -2
  107. package/dist/lib/generators/entity-ids.js +2 -0
  108. package/dist/lib/generators/entity-ids.js.map +2 -2
  109. package/dist/lib/generators/module-di.js +2 -0
  110. package/dist/lib/generators/module-di.js.map +2 -2
  111. package/dist/lib/generators/module-entities.js +2 -0
  112. package/dist/lib/generators/module-entities.js.map +2 -2
  113. package/dist/lib/generators/module-package-sources.js +6 -4
  114. package/dist/lib/generators/module-package-sources.js.map +2 -2
  115. package/dist/lib/generators/module-registry.js +32 -86
  116. package/dist/lib/generators/module-registry.js.map +2 -2
  117. package/dist/lib/generators/openapi.js +2 -0
  118. package/dist/lib/generators/openapi.js.map +2 -2
  119. package/dist/lib/generators/source-exports.js +73 -0
  120. package/dist/lib/generators/source-exports.js.map +7 -0
  121. package/dist/lib/init-secrets.js +33 -1
  122. package/dist/lib/init-secrets.js.map +2 -2
  123. package/dist/lib/init-summary.js +44 -0
  124. package/dist/lib/init-summary.js.map +7 -0
  125. package/dist/lib/module-github.js +98 -0
  126. package/dist/lib/module-github.js.map +7 -0
  127. package/dist/lib/module-identity.js +131 -0
  128. package/dist/lib/module-identity.js.map +7 -0
  129. package/dist/lib/module-inspection.js +124 -0
  130. package/dist/lib/module-inspection.js.map +7 -0
  131. package/dist/lib/module-install.js +150 -21
  132. package/dist/lib/module-install.js.map +3 -3
  133. package/dist/lib/module-package.js +205 -15
  134. package/dist/lib/module-package.js.map +2 -2
  135. package/dist/lib/modules-config.js +69 -30
  136. package/dist/lib/modules-config.js.map +2 -2
  137. package/dist/lib/resolver.js +33 -34
  138. package/dist/lib/resolver.js.map +2 -2
  139. package/dist/mercato.js +17 -37
  140. package/dist/mercato.js.map +2 -2
  141. package/package.json +7 -7
  142. package/src/__tests__/mercato.test.ts +71 -4
  143. package/src/i18n/de.json +4 -0
  144. package/src/i18n/en.json +4 -0
  145. package/src/i18n/es.json +4 -0
  146. package/src/i18n/ko.json +4 -0
  147. package/src/i18n/pl.json +4 -0
  148. package/src/lib/__fixtures__/official-module-package/dist/modules/test_package/widgets/injection/test/widget.js +1 -0
  149. package/src/lib/__integration__/TC-INT-007.spec.ts +219 -19
  150. package/src/lib/__integration__/TC-INT-009.spec.ts +279 -0
  151. package/src/lib/__tests__/eject.test.ts +98 -4
  152. package/src/lib/__tests__/init-secrets.test.ts +85 -1
  153. package/src/lib/__tests__/init-summary.test.ts +50 -0
  154. package/src/lib/__tests__/module-github.test.ts +108 -0
  155. package/src/lib/__tests__/module-identity.test.ts +144 -0
  156. package/src/lib/__tests__/module-inspection.test.ts +195 -0
  157. package/src/lib/__tests__/module-install.test.ts +399 -10
  158. package/src/lib/__tests__/module-package.test.ts +154 -0
  159. package/src/lib/__tests__/modules-config.test.ts +55 -0
  160. package/src/lib/__tests__/resolver.packages.test.ts +29 -0
  161. package/src/lib/eject.ts +28 -10
  162. package/src/lib/generators/__tests__/module-id-collisions.test.ts +146 -0
  163. package/src/lib/generators/__tests__/module-package-sources.test.ts +19 -2
  164. package/src/lib/generators/__tests__/module-requirements.test.ts +56 -0
  165. package/src/lib/generators/entity-ids.ts +2 -0
  166. package/src/lib/generators/module-di.ts +2 -0
  167. package/src/lib/generators/module-entities.ts +2 -0
  168. package/src/lib/generators/module-package-sources.ts +7 -5
  169. package/src/lib/generators/module-registry.ts +33 -115
  170. package/src/lib/generators/openapi.ts +3 -0
  171. package/src/lib/generators/source-exports.ts +93 -0
  172. package/src/lib/init-secrets.ts +37 -0
  173. package/src/lib/init-summary.ts +54 -0
  174. package/src/lib/module-github.ts +109 -0
  175. package/src/lib/module-identity.ts +145 -0
  176. package/src/lib/module-inspection.ts +133 -0
  177. package/src/lib/module-install.ts +170 -22
  178. package/src/lib/module-package.ts +243 -16
  179. package/src/lib/modules-config.ts +80 -32
  180. package/src/lib/resolver.ts +35 -39
  181. package/src/mercato.ts +18 -44
  182. package/src/types/cross-spawn.d.ts +2 -2
@@ -0,0 +1,267 @@
1
+ import { expect, test } from "@playwright/test";
2
+ import { execFileSync, spawnSync } from "node:child_process";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..", "..");
8
+ const cliBin = path.join(repoRoot, "packages", "cli", "dist", "bin.js");
9
+ function writeFile(filePath, content) {
10
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
11
+ fs.writeFileSync(filePath, content);
12
+ }
13
+ function createPackage(packageRoot, packageName, moduleIds) {
14
+ writeFile(path.join(packageRoot, "package.json"), JSON.stringify({ name: packageName, version: "0.4.7", type: "module" }));
15
+ for (const moduleId of moduleIds) {
16
+ writeFile(path.join(packageRoot, "src", "modules", moduleId, "index.ts"), `export const metadata = { id: '${moduleId}', title: '${moduleId}', ejectable: true }
17
+ `);
18
+ writeFile(path.join(packageRoot, "dist", "modules", moduleId, "index.js"), `export const metadata = { id: '${moduleId}', title: '${moduleId}', ejectable: true }
19
+ `);
20
+ writeFile(path.join(packageRoot, "src", "modules", moduleId, "di.ts"), "export function register() {}\n");
21
+ writeFile(path.join(packageRoot, "dist", "modules", moduleId, "di.js"), "export function register() {}\n");
22
+ }
23
+ }
24
+ function createApp(appDir, dependencies = {}) {
25
+ writeFile(path.join(appDir, "package.json"), JSON.stringify({ name: "module-collision-integration", private: true, dependencies: { "@open-mercato/core": "0.4.7", ...dependencies } }));
26
+ writeFile(path.join(appDir, "yarn.lock"), "");
27
+ writeFile(path.join(appDir, "src", "modules.ts"), "export const enabledModules = []\n");
28
+ createPackage(path.join(appDir, "node_modules", "@open-mercato", "core"), "@open-mercato/core", []);
29
+ }
30
+ function runMercato(args, appDir, environment = {}) {
31
+ const result = spawnSync(process.execPath, [cliBin, ...args], {
32
+ cwd: appDir,
33
+ encoding: "utf8",
34
+ env: { ...process.env, FORCE_COLOR: "0", NODE_NO_WARNINGS: "1", ...environment }
35
+ });
36
+ if (result.error) throw result.error;
37
+ return { status: result.status, output: `${result.stdout}
38
+ ${result.stderr}` };
39
+ }
40
+ function installCommandStubs(appDir, candidateName, candidateModuleId) {
41
+ const executableDir = path.join(appDir, "bin");
42
+ const marker = path.join(appDir, "yarn-invoked");
43
+ const yarnPath = path.join(executableDir, process.platform === "win32" ? "yarn.cmd" : "yarn");
44
+ const yarnScript = `require('node:fs').writeFileSync(${JSON.stringify(marker)}, 'invoked'); process.exit(1)
45
+ `;
46
+ writeFile(yarnPath, process.platform === "win32" ? `@"${process.execPath}" "%~dp0yarn-stub.cjs" %*\r
47
+ ` : `#!${process.execPath}
48
+ ${yarnScript}`);
49
+ writeFile(path.join(executableDir, "yarn-stub.cjs"), yarnScript);
50
+ fs.chmodSync(yarnPath, 493);
51
+ if (candidateName && candidateModuleId) {
52
+ const manifest = Buffer.from(JSON.stringify({ name: candidateName })).toString("base64");
53
+ const ghScript = `const endpoint = process.argv[3] || ''
54
+ const value = endpoint === 'user' ? { login: 'candidate' }
55
+ : endpoint.includes('/commits/') ? { sha: 'a'.repeat(40) }
56
+ : endpoint.includes('/contents/') ? { encoding: 'base64', content: ${JSON.stringify(manifest)} }
57
+ : endpoint.includes('/git/trees/') ? { tree: [{ path: 'src/modules/${candidateModuleId}/index.ts' }, { path: 'dist/modules/${candidateModuleId}/index.js' }] }
58
+ : { default_branch: 'main' }
59
+ process.stdout.write(JSON.stringify(value))
60
+ `;
61
+ const ghPath = path.join(executableDir, process.platform === "win32" ? "gh.cmd" : "gh");
62
+ writeFile(ghPath, process.platform === "win32" ? `@"${process.execPath}" "%~dp0gh-stub.cjs" %*\r
63
+ ` : `#!${process.execPath}
64
+ ${ghScript}`);
65
+ writeFile(path.join(executableDir, "gh-stub.cjs"), ghScript);
66
+ fs.chmodSync(ghPath, 493);
67
+ }
68
+ return { PATH: executableDir + path.delimiter + process.env.PATH };
69
+ }
70
+ function snapshotDirectory(directory) {
71
+ if (!fs.existsSync(directory)) return {};
72
+ const files = {};
73
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
74
+ const fullPath = path.join(directory, entry.name);
75
+ if (entry.isDirectory()) {
76
+ for (const [relativePath, content] of Object.entries(snapshotDirectory(fullPath))) files[path.join(entry.name, relativePath)] = content;
77
+ } else {
78
+ files[entry.name] = fs.readFileSync(fullPath).toString("base64");
79
+ }
80
+ }
81
+ return files;
82
+ }
83
+ test.describe("TC-INT-009: CLI source collision lifecycle safeguards", () => {
84
+ for (const kind of ["directory", "archive"]) {
85
+ test(`rejects a local ${kind} with unknown provenance before replacing an active npm binding`, () => {
86
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-file-origin-"));
87
+ const appDir = path.join(root, "app");
88
+ try {
89
+ const binding = "@publisher/consents";
90
+ createApp(appDir, { [binding]: "0.4.7" });
91
+ createPackage(path.join(appDir, "node_modules", binding), binding, ["consents"]);
92
+ const packageRoot = path.join(root, "package");
93
+ createPackage(packageRoot, binding, ["consents"]);
94
+ if (kind === "archive") execFileSync("tar", ["-czf", path.join(root, "candidate.tgz"), "-C", root, "package"]);
95
+ const modulesSource = `export const enabledModules = [{ id: 'consents', from: '${binding}', locator: 'npm:${binding}' }]
96
+ `;
97
+ writeFile(path.join(appDir, "src", "modules.ts"), modulesSource);
98
+ const manifestBefore = fs.readFileSync(path.join(appDir, "package.json"), "utf8");
99
+ const installedBefore = snapshotDirectory(path.join(appDir, "node_modules"));
100
+ const environment = installCommandStubs(appDir);
101
+ const locator = kind === "archive" ? "file:../candidate.tgz" : "file:../package";
102
+ const result = runMercato(["module", "add", `${binding}@${locator}`, "--eject", "--allow-third-party"], appDir, environment);
103
+ expect(result.status, result.output).not.toBe(0);
104
+ expect(result.output).toContain("Package binding collision");
105
+ expect(result.output).toContain("unknown origin");
106
+ expect(result.output).toContain("consents");
107
+ expect(fs.existsSync(path.join(appDir, "yarn-invoked"))).toBe(false);
108
+ expect(fs.readFileSync(path.join(appDir, "src", "modules.ts"), "utf8")).toBe(modulesSource);
109
+ expect(fs.readFileSync(path.join(appDir, "package.json"), "utf8")).toBe(manifestBefore);
110
+ expect(snapshotDirectory(path.join(appDir, "node_modules"))).toEqual(installedBefore);
111
+ expect(fs.existsSync(path.join(appDir, "src", "modules", "consents"))).toBe(false);
112
+ expect(fs.existsSync(path.join(appDir, ".mercato", "generated"))).toBe(false);
113
+ } finally {
114
+ fs.rmSync(root, { recursive: true, force: true });
115
+ }
116
+ });
117
+ }
118
+ test("rejects a GitHub replacement of an active binding even when the selected module ID differs", () => {
119
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-binding-collision-"));
120
+ try {
121
+ const binding = "@publisher/shared-package";
122
+ createApp(appDir, { [binding]: "github:existing/provider#main" });
123
+ createPackage(path.join(appDir, "node_modules", binding), binding, ["active_module"]);
124
+ const modulesSource = `export const enabledModules = [{ id: 'active_module', from: '${binding}', locator: 'github:existing/provider', packageName: '${binding}' }]
125
+ `;
126
+ writeFile(path.join(appDir, "src", "modules.ts"), modulesSource);
127
+ const manifestBefore = fs.readFileSync(path.join(appDir, "package.json"), "utf8");
128
+ const environment = installCommandStubs(appDir, binding, "candidate_module");
129
+ const result = runMercato(["module", "add", "github:candidate/provider", "--allow-third-party"], appDir, environment);
130
+ expect(result.status, result.output).not.toBe(0);
131
+ expect(result.output).toContain("active_module");
132
+ expect(result.output).toContain(binding);
133
+ expect(result.output).toContain("github:existing/provider");
134
+ expect(result.output).toContain("github:candidate/provider");
135
+ expect(fs.existsSync(path.join(appDir, "yarn-invoked"))).toBe(false);
136
+ expect(fs.readFileSync(path.join(appDir, "src", "modules.ts"), "utf8")).toBe(modulesSource);
137
+ expect(fs.readFileSync(path.join(appDir, "package.json"), "utf8")).toBe(manifestBefore);
138
+ expect(fs.existsSync(path.join(appDir, "src", "modules", "candidate_module"))).toBe(false);
139
+ } finally {
140
+ fs.rmSync(appDir, { recursive: true, force: true });
141
+ }
142
+ });
143
+ test("rejects an npm file package runtime ID collision before invoking Yarn or copying sources", () => {
144
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-file-collision-"));
145
+ try {
146
+ createApp(appDir);
147
+ const candidateDir = path.join(appDir, "candidate");
148
+ createPackage(candidateDir, "@publisher/candidate", ["consents"]);
149
+ const modulesSource = "export const enabledModules = [{ id: 'consents', from: '@app', locator: 'github:existing/consents' }]\n";
150
+ writeFile(path.join(appDir, "src", "modules.ts"), modulesSource);
151
+ writeFile(path.join(appDir, "src", "modules", "consents", "index.ts"), "export const metadata = { ejectable: true }\n");
152
+ const sourceBefore = snapshotDirectory(path.join(appDir, "src"));
153
+ const manifestBefore = fs.readFileSync(path.join(appDir, "package.json"), "utf8");
154
+ const result = runMercato(["module", "add", "@publisher/candidate@file:./candidate", "--allow-third-party", "--eject"], appDir, installCommandStubs(appDir));
155
+ expect(result.status, result.output).not.toBe(0);
156
+ expect(result.output).toContain("consents");
157
+ expect(result.output).toMatch(/collision|already registered|conflict/i);
158
+ expect(fs.existsSync(path.join(appDir, "yarn-invoked"))).toBe(false);
159
+ expect(snapshotDirectory(path.join(appDir, "src"))).toEqual(sourceBefore);
160
+ expect(fs.readFileSync(path.join(appDir, "package.json"), "utf8")).toBe(manifestBefore);
161
+ } finally {
162
+ fs.rmSync(appDir, { recursive: true, force: true });
163
+ }
164
+ });
165
+ test("every generate command rejects duplicate effective registrations before changing existing output", () => {
166
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-generate-duplicates-"));
167
+ try {
168
+ createApp(appDir);
169
+ writeFile(path.join(appDir, "src", "modules.ts"), "export const enabledModules = [{ id: 'consents', from: '@app' }]\nif (process.env.COLLISION_DUPLICATE_ENABLED === 'true') enabledModules.push({ id: 'consents', from: '@app' })\n");
170
+ writeFile(path.join(appDir, "src", "modules", "consents", "index.ts"), "export const metadata = {}\n");
171
+ const outputDir = path.join(appDir, ".mercato", "generated");
172
+ for (const file of ["entities.ids.generated.ts", "modules.generated.ts", "entities.generated.ts", "di.generated.ts", "module-package-sources.css"]) writeFile(path.join(outputDir, file), "preserved output\n");
173
+ const before = snapshotDirectory(outputDir);
174
+ for (const command of ["all", "entity-ids", "registry", "entities", "di"]) {
175
+ const result = runMercato(["generate", command, "--quiet"], appDir, { COLLISION_DUPLICATE_ENABLED: "true" });
176
+ expect(result.status, `${command}: ${result.output}`).not.toBe(0);
177
+ expect(result.output).toContain("Duplicate enabled module ID 'consents'");
178
+ expect(snapshotDirectory(outputDir), command).toEqual(before);
179
+ }
180
+ const singleProvider = runMercato(["generate", "all", "--quiet"], appDir, { COLLISION_DUPLICATE_ENABLED: "false" });
181
+ expect(singleProvider.status, singleProvider.output).toBe(0);
182
+ } finally {
183
+ fs.rmSync(appDir, { recursive: true, force: true });
184
+ }
185
+ });
186
+ test("an installed alias generates binding imports, ejects with canonical provenance, and disables cleanly", () => {
187
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-alias-lifecycle-"));
188
+ try {
189
+ const binding = "consents_candidate";
190
+ const canonicalName = "@publisher/consents";
191
+ createApp(appDir, { [binding]: `npm:${canonicalName}@0.4.7` });
192
+ const packageRoot = path.join(appDir, "node_modules", binding);
193
+ createPackage(packageRoot, canonicalName, ["consents", "sibling"]);
194
+ writeFile(path.join(packageRoot, "src", "modules", "consents", "sibling.ts"), "export { metadata } from '../sibling'\n");
195
+ const enabled = runMercato(["module", "enable", binding, "--module", "consents", "--allow-third-party"], appDir);
196
+ expect(enabled.status, enabled.output).toBe(0);
197
+ const outputDir = path.join(appDir, ".mercato", "generated");
198
+ const modulesSource = fs.readFileSync(path.join(appDir, "src", "modules.ts"), "utf8");
199
+ expect(modulesSource).toContain(`from: '${binding}'`);
200
+ expect(modulesSource).toContain(`packageName: '${canonicalName}'`);
201
+ expect(fs.readFileSync(path.join(outputDir, "di.generated.ts"), "utf8")).toContain(`${binding}/modules/consents/di`);
202
+ expect(fs.readFileSync(path.join(outputDir, "module-package-sources.css"), "utf8")).toContain(`node_modules/${binding}/src/`);
203
+ const ejected = runMercato(["module", "eject", "consents"], appDir);
204
+ expect(ejected.status, ejected.output).toBe(0);
205
+ const ejectedSource = fs.readFileSync(path.join(appDir, "src", "modules.ts"), "utf8");
206
+ expect(ejectedSource).toContain("from: '@app'");
207
+ expect(ejectedSource).toContain(`packageName: '${canonicalName}'`);
208
+ expect(ejectedSource).toContain(`locator: 'npm:${canonicalName}'`);
209
+ expect(fs.readFileSync(path.join(appDir, "src", "modules", "consents", "sibling.ts"), "utf8")).toContain(`${binding}/modules/sibling`);
210
+ writeFile(path.join(appDir, "src", "modules.ts"), "export const enabledModules = []\n");
211
+ const disabled = runMercato(["generate", "all", "--quiet"], appDir);
212
+ expect(disabled.status, disabled.output).toBe(0);
213
+ expect(fs.readFileSync(path.join(outputDir, "di.generated.ts"), "utf8")).not.toContain("consents");
214
+ expect(fs.readFileSync(path.join(outputDir, "module-package-sources.css"), "utf8")).toBe("");
215
+ expect(fs.existsSync(path.join(packageRoot, "package.json"))).toBe(true);
216
+ expect(fs.existsSync(path.join(appDir, "src", "modules", "consents", "index.ts"))).toBe(true);
217
+ } finally {
218
+ fs.rmSync(appDir, { recursive: true, force: true });
219
+ }
220
+ });
221
+ test("missing alias exports fail enable and direct eject before source or config changes", () => {
222
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-alias-exports-"));
223
+ try {
224
+ const binding = "consents_candidate";
225
+ createApp(appDir, { [binding]: "npm:@publisher/consents@0.4.7" });
226
+ const packageRoot = path.join(appDir, "node_modules", binding);
227
+ createPackage(packageRoot, "@publisher/consents", ["consents"]);
228
+ writeFile(path.join(packageRoot, "package.json"), JSON.stringify({ name: "@publisher/consents", exports: { ".": "./dist/modules/consents/index.js" } }));
229
+ const configPath = path.join(appDir, "src", "modules.ts");
230
+ const emptyConfig = fs.readFileSync(configPath, "utf8");
231
+ const enabled = runMercato(["module", "enable", binding, "--module", "consents", "--eject", "--allow-third-party"], appDir);
232
+ expect(enabled.status, enabled.output).not.toBe(0);
233
+ expect(enabled.output).toContain(`${binding}/modules/consents/`);
234
+ expect(fs.readFileSync(configPath, "utf8")).toBe(emptyConfig);
235
+ expect(fs.existsSync(path.join(appDir, "src", "modules", "consents"))).toBe(false);
236
+ const registeredConfig = `export const enabledModules = [{ id: 'consents', from: '${binding}' }]
237
+ `;
238
+ writeFile(configPath, registeredConfig);
239
+ const ejected = runMercato(["module", "eject", "consents"], appDir);
240
+ expect(ejected.status, ejected.output).not.toBe(0);
241
+ expect(ejected.output).toContain(`${binding}/modules/consents/`);
242
+ expect(fs.readFileSync(configPath, "utf8")).toBe(registeredConfig);
243
+ expect(fs.existsSync(path.join(appDir, "src", "modules", "consents"))).toBe(false);
244
+ } finally {
245
+ fs.rmSync(appDir, { recursive: true, force: true });
246
+ }
247
+ });
248
+ test("a single package registration with a local overlay remains valid", () => {
249
+ const appDir = fs.mkdtempSync(path.join(os.tmpdir(), "mercato-single-overlay-"));
250
+ try {
251
+ const binding = "@publisher/consents";
252
+ createApp(appDir, { [binding]: "0.4.7" });
253
+ createPackage(path.join(appDir, "node_modules", binding), binding, ["consents"]);
254
+ writeFile(path.join(appDir, "src", "modules.ts"), `export const enabledModules = [{ id: 'consents', from: '${binding}' }]
255
+ `);
256
+ writeFile(path.join(appDir, "src", "modules", "consents", "index.ts"), "export const metadata = { title: 'Local overlay' }\n");
257
+ const before = snapshotDirectory(path.join(appDir, "src"));
258
+ const result = runMercato(["generate", "all", "--quiet"], appDir);
259
+ expect(result.status, result.output).toBe(0);
260
+ expect(snapshotDirectory(path.join(appDir, "src"))).toEqual(before);
261
+ expect(fs.readFileSync(path.join(appDir, ".mercato", "generated", "di.generated.ts"), "utf8")).toContain(`${binding}/modules/consents/di`);
262
+ } finally {
263
+ fs.rmSync(appDir, { recursive: true, force: true });
264
+ }
265
+ });
266
+ });
267
+ //# sourceMappingURL=TC-INT-009.spec.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/__integration__/TC-INT-009.spec.ts"],
4
+ "sourcesContent": ["import { expect, test } from '@playwright/test'\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..', '..')\nconst cliBin = path.join(repoRoot, 'packages', 'cli', 'dist', 'bin.js')\n\nfunction writeFile(filePath: string, content: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content)\n}\n\nfunction createPackage(packageRoot: string, packageName: string, moduleIds: string[]): void {\n writeFile(path.join(packageRoot, 'package.json'), JSON.stringify({ name: packageName, version: '0.4.7', type: 'module' }))\n for (const moduleId of moduleIds) {\n writeFile(path.join(packageRoot, 'src', 'modules', moduleId, 'index.ts'), `export const metadata = { id: '${moduleId}', title: '${moduleId}', ejectable: true }\\n`)\n writeFile(path.join(packageRoot, 'dist', 'modules', moduleId, 'index.js'), `export const metadata = { id: '${moduleId}', title: '${moduleId}', ejectable: true }\\n`)\n writeFile(path.join(packageRoot, 'src', 'modules', moduleId, 'di.ts'), 'export function register() {}\\n')\n writeFile(path.join(packageRoot, 'dist', 'modules', moduleId, 'di.js'), 'export function register() {}\\n')\n }\n}\n\nfunction createApp(appDir: string, dependencies: Record<string, string> = {}): void {\n writeFile(path.join(appDir, 'package.json'), JSON.stringify({ name: 'module-collision-integration', private: true, dependencies: { '@open-mercato/core': '0.4.7', ...dependencies } }))\n writeFile(path.join(appDir, 'yarn.lock'), '')\n writeFile(path.join(appDir, 'src', 'modules.ts'), 'export const enabledModules = []\\n')\n createPackage(path.join(appDir, 'node_modules', '@open-mercato', 'core'), '@open-mercato/core', [])\n}\n\nfunction runMercato(args: string[], appDir: string, environment: NodeJS.ProcessEnv = {}): { status: number | null; output: string } {\n const result = spawnSync(process.execPath, [cliBin, ...args], {\n cwd: appDir,\n encoding: 'utf8',\n env: { ...process.env, FORCE_COLOR: '0', NODE_NO_WARNINGS: '1', ...environment },\n })\n if (result.error) throw result.error\n return { status: result.status, output: `${result.stdout}\\n${result.stderr}` }\n}\n\nfunction installCommandStubs(appDir: string, candidateName?: string, candidateModuleId?: string): NodeJS.ProcessEnv {\n const executableDir = path.join(appDir, 'bin')\n const marker = path.join(appDir, 'yarn-invoked')\n const yarnPath = path.join(executableDir, process.platform === 'win32' ? 'yarn.cmd' : 'yarn')\n const yarnScript = `require('node:fs').writeFileSync(${JSON.stringify(marker)}, 'invoked'); process.exit(1)\\n`\n writeFile(yarnPath, process.platform === 'win32'\n ? `@\"${process.execPath}\" \"%~dp0yarn-stub.cjs\" %*\\r\\n`\n : `#!${process.execPath}\\n${yarnScript}`)\n writeFile(path.join(executableDir, 'yarn-stub.cjs'), yarnScript)\n fs.chmodSync(yarnPath, 0o755)\n if (candidateName && candidateModuleId) {\n const manifest = Buffer.from(JSON.stringify({ name: candidateName })).toString('base64')\n const ghScript = `const endpoint = process.argv[3] || ''\nconst value = endpoint === 'user' ? { login: 'candidate' }\n : endpoint.includes('/commits/') ? { sha: 'a'.repeat(40) }\n : endpoint.includes('/contents/') ? { encoding: 'base64', content: ${JSON.stringify(manifest)} }\n : endpoint.includes('/git/trees/') ? { tree: [{ path: 'src/modules/${candidateModuleId}/index.ts' }, { path: 'dist/modules/${candidateModuleId}/index.js' }] }\n : { default_branch: 'main' }\nprocess.stdout.write(JSON.stringify(value))\\n`\n const ghPath = path.join(executableDir, process.platform === 'win32' ? 'gh.cmd' : 'gh')\n writeFile(ghPath, process.platform === 'win32'\n ? `@\"${process.execPath}\" \"%~dp0gh-stub.cjs\" %*\\r\\n`\n : `#!${process.execPath}\\n${ghScript}`)\n writeFile(path.join(executableDir, 'gh-stub.cjs'), ghScript)\n fs.chmodSync(ghPath, 0o755)\n }\n return { PATH: executableDir + path.delimiter + process.env.PATH }\n}\n\nfunction snapshotDirectory(directory: string): Record<string, string> {\n if (!fs.existsSync(directory)) return {}\n const files: Record<string, string> = {}\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const fullPath = path.join(directory, entry.name)\n if (entry.isDirectory()) {\n for (const [relativePath, content] of Object.entries(snapshotDirectory(fullPath))) files[path.join(entry.name, relativePath)] = content\n } else {\n files[entry.name] = fs.readFileSync(fullPath).toString('base64')\n }\n }\n return files\n}\n\ntest.describe('TC-INT-009: CLI source collision lifecycle safeguards', () => {\n for (const kind of ['directory', 'archive']) {\n test(`rejects a local ${kind} with unknown provenance before replacing an active npm binding`, () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-file-origin-'))\n const appDir = path.join(root, 'app')\n try {\n const binding = '@publisher/consents'\n createApp(appDir, { [binding]: '0.4.7' })\n createPackage(path.join(appDir, 'node_modules', binding), binding, ['consents'])\n const packageRoot = path.join(root, 'package')\n createPackage(packageRoot, binding, ['consents'])\n if (kind === 'archive') execFileSync('tar', ['-czf', path.join(root, 'candidate.tgz'), '-C', root, 'package'])\n const modulesSource = `export const enabledModules = [{ id: 'consents', from: '${binding}', locator: 'npm:${binding}' }]\\n`\n writeFile(path.join(appDir, 'src', 'modules.ts'), modulesSource)\n const manifestBefore = fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')\n const installedBefore = snapshotDirectory(path.join(appDir, 'node_modules'))\n const environment = installCommandStubs(appDir)\n const locator = kind === 'archive' ? 'file:../candidate.tgz' : 'file:../package'\n const result = runMercato(['module', 'add', `${binding}@${locator}`, '--eject', '--allow-third-party'], appDir, environment)\n\n expect(result.status, result.output).not.toBe(0)\n expect(result.output).toContain('Package binding collision')\n expect(result.output).toContain('unknown origin')\n expect(result.output).toContain('consents')\n expect(fs.existsSync(path.join(appDir, 'yarn-invoked'))).toBe(false)\n expect(fs.readFileSync(path.join(appDir, 'src', 'modules.ts'), 'utf8')).toBe(modulesSource)\n expect(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')).toBe(manifestBefore)\n expect(snapshotDirectory(path.join(appDir, 'node_modules'))).toEqual(installedBefore)\n expect(fs.existsSync(path.join(appDir, 'src', 'modules', 'consents'))).toBe(false)\n expect(fs.existsSync(path.join(appDir, '.mercato', 'generated'))).toBe(false)\n } finally { fs.rmSync(root, { recursive: true, force: true }) }\n })\n }\n\n test('rejects a GitHub replacement of an active binding even when the selected module ID differs', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-binding-collision-'))\n try {\n const binding = '@publisher/shared-package'\n createApp(appDir, { [binding]: 'github:existing/provider#main' })\n createPackage(path.join(appDir, 'node_modules', binding), binding, ['active_module'])\n const modulesSource = `export const enabledModules = [{ id: 'active_module', from: '${binding}', locator: 'github:existing/provider', packageName: '${binding}' }]\\n`\n writeFile(path.join(appDir, 'src', 'modules.ts'), modulesSource)\n const manifestBefore = fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')\n const environment = installCommandStubs(appDir, binding, 'candidate_module')\n const result = runMercato(['module', 'add', 'github:candidate/provider', '--allow-third-party'], appDir, environment)\n\n expect(result.status, result.output).not.toBe(0)\n expect(result.output).toContain('active_module')\n expect(result.output).toContain(binding)\n expect(result.output).toContain('github:existing/provider')\n expect(result.output).toContain('github:candidate/provider')\n expect(fs.existsSync(path.join(appDir, 'yarn-invoked'))).toBe(false)\n expect(fs.readFileSync(path.join(appDir, 'src', 'modules.ts'), 'utf8')).toBe(modulesSource)\n expect(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')).toBe(manifestBefore)\n expect(fs.existsSync(path.join(appDir, 'src', 'modules', 'candidate_module'))).toBe(false)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n\n test('rejects an npm file package runtime ID collision before invoking Yarn or copying sources', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-file-collision-'))\n try {\n createApp(appDir)\n const candidateDir = path.join(appDir, 'candidate')\n createPackage(candidateDir, '@publisher/candidate', ['consents'])\n const modulesSource = \"export const enabledModules = [{ id: 'consents', from: '@app', locator: 'github:existing/consents' }]\\n\"\n writeFile(path.join(appDir, 'src', 'modules.ts'), modulesSource)\n writeFile(path.join(appDir, 'src', 'modules', 'consents', 'index.ts'), 'export const metadata = { ejectable: true }\\n')\n const sourceBefore = snapshotDirectory(path.join(appDir, 'src'))\n const manifestBefore = fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')\n const result = runMercato(['module', 'add', '@publisher/candidate@file:./candidate', '--allow-third-party', '--eject'], appDir, installCommandStubs(appDir))\n\n expect(result.status, result.output).not.toBe(0)\n expect(result.output).toContain('consents')\n expect(result.output).toMatch(/collision|already registered|conflict/i)\n expect(fs.existsSync(path.join(appDir, 'yarn-invoked'))).toBe(false)\n expect(snapshotDirectory(path.join(appDir, 'src'))).toEqual(sourceBefore)\n expect(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')).toBe(manifestBefore)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n\n test('every generate command rejects duplicate effective registrations before changing existing output', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-generate-duplicates-'))\n try {\n createApp(appDir)\n writeFile(path.join(appDir, 'src', 'modules.ts'), \"export const enabledModules = [{ id: 'consents', from: '@app' }]\\nif (process.env.COLLISION_DUPLICATE_ENABLED === 'true') enabledModules.push({ id: 'consents', from: '@app' })\\n\")\n writeFile(path.join(appDir, 'src', 'modules', 'consents', 'index.ts'), 'export const metadata = {}\\n')\n const outputDir = path.join(appDir, '.mercato', 'generated')\n for (const file of ['entities.ids.generated.ts', 'modules.generated.ts', 'entities.generated.ts', 'di.generated.ts', 'module-package-sources.css']) writeFile(path.join(outputDir, file), 'preserved output\\n')\n const before = snapshotDirectory(outputDir)\n\n for (const command of ['all', 'entity-ids', 'registry', 'entities', 'di']) {\n const result = runMercato(['generate', command, '--quiet'], appDir, { COLLISION_DUPLICATE_ENABLED: 'true' })\n expect(result.status, `${command}: ${result.output}`).not.toBe(0)\n expect(result.output).toContain(\"Duplicate enabled module ID 'consents'\")\n expect(snapshotDirectory(outputDir), command).toEqual(before)\n }\n const singleProvider = runMercato(['generate', 'all', '--quiet'], appDir, { COLLISION_DUPLICATE_ENABLED: 'false' })\n expect(singleProvider.status, singleProvider.output).toBe(0)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n\n test('an installed alias generates binding imports, ejects with canonical provenance, and disables cleanly', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-alias-lifecycle-'))\n try {\n const binding = 'consents_candidate'\n const canonicalName = '@publisher/consents'\n createApp(appDir, { [binding]: `npm:${canonicalName}@0.4.7` })\n const packageRoot = path.join(appDir, 'node_modules', binding)\n createPackage(packageRoot, canonicalName, ['consents', 'sibling'])\n writeFile(path.join(packageRoot, 'src', 'modules', 'consents', 'sibling.ts'), \"export { metadata } from '../sibling'\\n\")\n const enabled = runMercato(['module', 'enable', binding, '--module', 'consents', '--allow-third-party'], appDir)\n expect(enabled.status, enabled.output).toBe(0)\n const outputDir = path.join(appDir, '.mercato', 'generated')\n const modulesSource = fs.readFileSync(path.join(appDir, 'src', 'modules.ts'), 'utf8')\n expect(modulesSource).toContain(`from: '${binding}'`)\n expect(modulesSource).toContain(`packageName: '${canonicalName}'`)\n expect(fs.readFileSync(path.join(outputDir, 'di.generated.ts'), 'utf8')).toContain(`${binding}/modules/consents/di`)\n expect(fs.readFileSync(path.join(outputDir, 'module-package-sources.css'), 'utf8')).toContain(`node_modules/${binding}/src/`)\n\n const ejected = runMercato(['module', 'eject', 'consents'], appDir)\n expect(ejected.status, ejected.output).toBe(0)\n const ejectedSource = fs.readFileSync(path.join(appDir, 'src', 'modules.ts'), 'utf8')\n expect(ejectedSource).toContain(\"from: '@app'\")\n expect(ejectedSource).toContain(`packageName: '${canonicalName}'`)\n expect(ejectedSource).toContain(`locator: 'npm:${canonicalName}'`)\n expect(fs.readFileSync(path.join(appDir, 'src', 'modules', 'consents', 'sibling.ts'), 'utf8')).toContain(`${binding}/modules/sibling`)\n\n writeFile(path.join(appDir, 'src', 'modules.ts'), 'export const enabledModules = []\\n')\n const disabled = runMercato(['generate', 'all', '--quiet'], appDir)\n expect(disabled.status, disabled.output).toBe(0)\n expect(fs.readFileSync(path.join(outputDir, 'di.generated.ts'), 'utf8')).not.toContain('consents')\n expect(fs.readFileSync(path.join(outputDir, 'module-package-sources.css'), 'utf8')).toBe('')\n expect(fs.existsSync(path.join(packageRoot, 'package.json'))).toBe(true)\n expect(fs.existsSync(path.join(appDir, 'src', 'modules', 'consents', 'index.ts'))).toBe(true)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n\n test('missing alias exports fail enable and direct eject before source or config changes', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-alias-exports-'))\n try {\n const binding = 'consents_candidate'\n createApp(appDir, { [binding]: 'npm:@publisher/consents@0.4.7' })\n const packageRoot = path.join(appDir, 'node_modules', binding)\n createPackage(packageRoot, '@publisher/consents', ['consents'])\n writeFile(path.join(packageRoot, 'package.json'), JSON.stringify({ name: '@publisher/consents', exports: { '.': './dist/modules/consents/index.js' } }))\n const configPath = path.join(appDir, 'src', 'modules.ts')\n const emptyConfig = fs.readFileSync(configPath, 'utf8')\n\n const enabled = runMercato(['module', 'enable', binding, '--module', 'consents', '--eject', '--allow-third-party'], appDir)\n expect(enabled.status, enabled.output).not.toBe(0)\n expect(enabled.output).toContain(`${binding}/modules/consents/`)\n expect(fs.readFileSync(configPath, 'utf8')).toBe(emptyConfig)\n expect(fs.existsSync(path.join(appDir, 'src', 'modules', 'consents'))).toBe(false)\n\n const registeredConfig = `export const enabledModules = [{ id: 'consents', from: '${binding}' }]\\n`\n writeFile(configPath, registeredConfig)\n const ejected = runMercato(['module', 'eject', 'consents'], appDir)\n expect(ejected.status, ejected.output).not.toBe(0)\n expect(ejected.output).toContain(`${binding}/modules/consents/`)\n expect(fs.readFileSync(configPath, 'utf8')).toBe(registeredConfig)\n expect(fs.existsSync(path.join(appDir, 'src', 'modules', 'consents'))).toBe(false)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n\n test('a single package registration with a local overlay remains valid', () => {\n const appDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-single-overlay-'))\n try {\n const binding = '@publisher/consents'\n createApp(appDir, { [binding]: '0.4.7' })\n createPackage(path.join(appDir, 'node_modules', binding), binding, ['consents'])\n writeFile(path.join(appDir, 'src', 'modules.ts'), `export const enabledModules = [{ id: 'consents', from: '${binding}' }]\\n`)\n writeFile(path.join(appDir, 'src', 'modules', 'consents', 'index.ts'), \"export const metadata = { title: 'Local overlay' }\\n\")\n const before = snapshotDirectory(path.join(appDir, 'src'))\n\n const result = runMercato(['generate', 'all', '--quiet'], appDir)\n\n expect(result.status, result.output).toBe(0)\n expect(snapshotDirectory(path.join(appDir, 'src'))).toEqual(before)\n expect(fs.readFileSync(path.join(appDir, '.mercato', 'generated', 'di.generated.ts'), 'utf8')).toContain(`${binding}/modules/consents/di`)\n } finally {\n fs.rmSync(appDir, { recursive: true, force: true })\n }\n })\n})\n"],
5
+ "mappings": "AAAA,SAAS,QAAQ,YAAY;AAC7B,SAAS,cAAc,iBAAiB;AACxC,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,MAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,MAAM,MAAM,MAAM,MAAM,IAAI;AACxG,MAAM,SAAS,KAAK,KAAK,UAAU,YAAY,OAAO,QAAQ,QAAQ;AAEtE,SAAS,UAAU,UAAkB,SAAuB;AAC1D,KAAG,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,KAAG,cAAc,UAAU,OAAO;AACpC;AAEA,SAAS,cAAc,aAAqB,aAAqB,WAA2B;AAC1F,YAAU,KAAK,KAAK,aAAa,cAAc,GAAG,KAAK,UAAU,EAAE,MAAM,aAAa,SAAS,SAAS,MAAM,SAAS,CAAC,CAAC;AACzH,aAAW,YAAY,WAAW;AAChC,cAAU,KAAK,KAAK,aAAa,OAAO,WAAW,UAAU,UAAU,GAAG,kCAAkC,QAAQ,cAAc,QAAQ;AAAA,CAAwB;AAClK,cAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,UAAU,UAAU,GAAG,kCAAkC,QAAQ,cAAc,QAAQ;AAAA,CAAwB;AACnK,cAAU,KAAK,KAAK,aAAa,OAAO,WAAW,UAAU,OAAO,GAAG,iCAAiC;AACxG,cAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,UAAU,OAAO,GAAG,iCAAiC;AAAA,EAC3G;AACF;AAEA,SAAS,UAAU,QAAgB,eAAuC,CAAC,GAAS;AAClF,YAAU,KAAK,KAAK,QAAQ,cAAc,GAAG,KAAK,UAAU,EAAE,MAAM,gCAAgC,SAAS,MAAM,cAAc,EAAE,sBAAsB,SAAS,GAAG,aAAa,EAAE,CAAC,CAAC;AACtL,YAAU,KAAK,KAAK,QAAQ,WAAW,GAAG,EAAE;AAC5C,YAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,oCAAoC;AACtF,gBAAc,KAAK,KAAK,QAAQ,gBAAgB,iBAAiB,MAAM,GAAG,sBAAsB,CAAC,CAAC;AACpG;AAEA,SAAS,WAAW,MAAgB,QAAgB,cAAiC,CAAC,GAA8C;AAClI,QAAM,SAAS,UAAU,QAAQ,UAAU,CAAC,QAAQ,GAAG,IAAI,GAAG;AAAA,IAC5D,KAAK;AAAA,IACL,UAAU;AAAA,IACV,KAAK,EAAE,GAAG,QAAQ,KAAK,aAAa,KAAK,kBAAkB,KAAK,GAAG,YAAY;AAAA,EACjF,CAAC;AACD,MAAI,OAAO,MAAO,OAAM,OAAO;AAC/B,SAAO,EAAE,QAAQ,OAAO,QAAQ,QAAQ,GAAG,OAAO,MAAM;AAAA,EAAK,OAAO,MAAM,GAAG;AAC/E;AAEA,SAAS,oBAAoB,QAAgB,eAAwB,mBAA+C;AAClH,QAAM,gBAAgB,KAAK,KAAK,QAAQ,KAAK;AAC7C,QAAM,SAAS,KAAK,KAAK,QAAQ,cAAc;AAC/C,QAAM,WAAW,KAAK,KAAK,eAAe,QAAQ,aAAa,UAAU,aAAa,MAAM;AAC5F,QAAM,aAAa,oCAAoC,KAAK,UAAU,MAAM,CAAC;AAAA;AAC7E,YAAU,UAAU,QAAQ,aAAa,UACrC,KAAK,QAAQ,QAAQ;AAAA,IACrB,KAAK,QAAQ,QAAQ;AAAA,EAAK,UAAU,EAAE;AAC1C,YAAU,KAAK,KAAK,eAAe,eAAe,GAAG,UAAU;AAC/D,KAAG,UAAU,UAAU,GAAK;AAC5B,MAAI,iBAAiB,mBAAmB;AACtC,UAAM,WAAW,OAAO,KAAK,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC,CAAC,EAAE,SAAS,QAAQ;AACvF,UAAM,WAAW;AAAA;AAAA;AAAA,uEAGkD,KAAK,UAAU,QAAQ,CAAC;AAAA,uEACxB,iBAAiB,uCAAuC,iBAAiB;AAAA;AAAA;AAAA;AAG5I,UAAM,SAAS,KAAK,KAAK,eAAe,QAAQ,aAAa,UAAU,WAAW,IAAI;AACtF,cAAU,QAAQ,QAAQ,aAAa,UACnC,KAAK,QAAQ,QAAQ;AAAA,IACrB,KAAK,QAAQ,QAAQ;AAAA,EAAK,QAAQ,EAAE;AACxC,cAAU,KAAK,KAAK,eAAe,aAAa,GAAG,QAAQ;AAC3D,OAAG,UAAU,QAAQ,GAAK;AAAA,EAC5B;AACA,SAAO,EAAE,MAAM,gBAAgB,KAAK,YAAY,QAAQ,IAAI,KAAK;AACnE;AAEA,SAAS,kBAAkB,WAA2C;AACpE,MAAI,CAAC,GAAG,WAAW,SAAS,EAAG,QAAO,CAAC;AACvC,QAAM,QAAgC,CAAC;AACvC,aAAW,SAAS,GAAG,YAAY,WAAW,EAAE,eAAe,KAAK,CAAC,GAAG;AACtE,UAAM,WAAW,KAAK,KAAK,WAAW,MAAM,IAAI;AAChD,QAAI,MAAM,YAAY,GAAG;AACvB,iBAAW,CAAC,cAAc,OAAO,KAAK,OAAO,QAAQ,kBAAkB,QAAQ,CAAC,EAAG,OAAM,KAAK,KAAK,MAAM,MAAM,YAAY,CAAC,IAAI;AAAA,IAClI,OAAO;AACL,YAAM,MAAM,IAAI,IAAI,GAAG,aAAa,QAAQ,EAAE,SAAS,QAAQ;AAAA,IACjE;AAAA,EACF;AACA,SAAO;AACT;AAEA,KAAK,SAAS,yDAAyD,MAAM;AAC3E,aAAW,QAAQ,CAAC,aAAa,SAAS,GAAG;AAC3C,SAAK,mBAAmB,IAAI,mEAAmE,MAAM;AACnG,YAAM,OAAO,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,sBAAsB,CAAC;AAC1E,YAAM,SAAS,KAAK,KAAK,MAAM,KAAK;AACpC,UAAI;AACF,cAAM,UAAU;AAChB,kBAAU,QAAQ,EAAE,CAAC,OAAO,GAAG,QAAQ,CAAC;AACxC,sBAAc,KAAK,KAAK,QAAQ,gBAAgB,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC;AAC/E,cAAM,cAAc,KAAK,KAAK,MAAM,SAAS;AAC7C,sBAAc,aAAa,SAAS,CAAC,UAAU,CAAC;AAChD,YAAI,SAAS,UAAW,cAAa,OAAO,CAAC,QAAQ,KAAK,KAAK,MAAM,eAAe,GAAG,MAAM,MAAM,SAAS,CAAC;AAC7G,cAAM,gBAAgB,2DAA2D,OAAO,oBAAoB,OAAO;AAAA;AACnH,kBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,aAAa;AAC/D,cAAM,iBAAiB,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM;AAChF,cAAM,kBAAkB,kBAAkB,KAAK,KAAK,QAAQ,cAAc,CAAC;AAC3E,cAAM,cAAc,oBAAoB,MAAM;AAC9C,cAAM,UAAU,SAAS,YAAY,0BAA0B;AAC/D,cAAM,SAAS,WAAW,CAAC,UAAU,OAAO,GAAG,OAAO,IAAI,OAAO,IAAI,WAAW,qBAAqB,GAAG,QAAQ,WAAW;AAE3H,eAAO,OAAO,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC;AAC/C,eAAO,OAAO,MAAM,EAAE,UAAU,2BAA2B;AAC3D,eAAO,OAAO,MAAM,EAAE,UAAU,gBAAgB;AAChD,eAAO,OAAO,MAAM,EAAE,UAAU,UAAU;AAC1C,eAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,cAAc,CAAC,CAAC,EAAE,KAAK,KAAK;AACnE,eAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,MAAM,CAAC,EAAE,KAAK,aAAa;AAC1F,eAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM,CAAC,EAAE,KAAK,cAAc;AACtF,eAAO,kBAAkB,KAAK,KAAK,QAAQ,cAAc,CAAC,CAAC,EAAE,QAAQ,eAAe;AACpF,eAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,OAAO,WAAW,UAAU,CAAC,CAAC,EAAE,KAAK,KAAK;AACjF,eAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,YAAY,WAAW,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MAC9E,UAAE;AAAU,WAAG,OAAO,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,MAAE;AAAA,IAChE,CAAC;AAAA,EACH;AAEA,OAAK,8FAA8F,MAAM;AACvG,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,4BAA4B,CAAC;AAClF,QAAI;AACF,YAAM,UAAU;AAChB,gBAAU,QAAQ,EAAE,CAAC,OAAO,GAAG,gCAAgC,CAAC;AAChE,oBAAc,KAAK,KAAK,QAAQ,gBAAgB,OAAO,GAAG,SAAS,CAAC,eAAe,CAAC;AACpF,YAAM,gBAAgB,gEAAgE,OAAO,yDAAyD,OAAO;AAAA;AAC7J,gBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,aAAa;AAC/D,YAAM,iBAAiB,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM;AAChF,YAAM,cAAc,oBAAoB,QAAQ,SAAS,kBAAkB;AAC3E,YAAM,SAAS,WAAW,CAAC,UAAU,OAAO,6BAA6B,qBAAqB,GAAG,QAAQ,WAAW;AAEpH,aAAO,OAAO,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC;AAC/C,aAAO,OAAO,MAAM,EAAE,UAAU,eAAe;AAC/C,aAAO,OAAO,MAAM,EAAE,UAAU,OAAO;AACvC,aAAO,OAAO,MAAM,EAAE,UAAU,0BAA0B;AAC1D,aAAO,OAAO,MAAM,EAAE,UAAU,2BAA2B;AAC3D,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,cAAc,CAAC,CAAC,EAAE,KAAK,KAAK;AACnE,aAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,MAAM,CAAC,EAAE,KAAK,aAAa;AAC1F,aAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM,CAAC,EAAE,KAAK,cAAc;AACtF,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,OAAO,WAAW,kBAAkB,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,IAC3F,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AAED,OAAK,4FAA4F,MAAM;AACrG,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,yBAAyB,CAAC;AAC/E,QAAI;AACF,gBAAU,MAAM;AAChB,YAAM,eAAe,KAAK,KAAK,QAAQ,WAAW;AAClD,oBAAc,cAAc,wBAAwB,CAAC,UAAU,CAAC;AAChE,YAAM,gBAAgB;AACtB,gBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,aAAa;AAC/D,gBAAU,KAAK,KAAK,QAAQ,OAAO,WAAW,YAAY,UAAU,GAAG,+CAA+C;AACtH,YAAM,eAAe,kBAAkB,KAAK,KAAK,QAAQ,KAAK,CAAC;AAC/D,YAAM,iBAAiB,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM;AAChF,YAAM,SAAS,WAAW,CAAC,UAAU,OAAO,yCAAyC,uBAAuB,SAAS,GAAG,QAAQ,oBAAoB,MAAM,CAAC;AAE3J,aAAO,OAAO,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC;AAC/C,aAAO,OAAO,MAAM,EAAE,UAAU,UAAU;AAC1C,aAAO,OAAO,MAAM,EAAE,QAAQ,wCAAwC;AACtE,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,cAAc,CAAC,CAAC,EAAE,KAAK,KAAK;AACnE,aAAO,kBAAkB,KAAK,KAAK,QAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,YAAY;AACxE,aAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,cAAc,GAAG,MAAM,CAAC,EAAE,KAAK,cAAc;AAAA,IACxF,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AAED,OAAK,oGAAoG,MAAM;AAC7G,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,8BAA8B,CAAC;AACpF,QAAI;AACF,gBAAU,MAAM;AAChB,gBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,mLAAmL;AACrO,gBAAU,KAAK,KAAK,QAAQ,OAAO,WAAW,YAAY,UAAU,GAAG,8BAA8B;AACrG,YAAM,YAAY,KAAK,KAAK,QAAQ,YAAY,WAAW;AAC3D,iBAAW,QAAQ,CAAC,6BAA6B,wBAAwB,yBAAyB,mBAAmB,4BAA4B,EAAG,WAAU,KAAK,KAAK,WAAW,IAAI,GAAG,oBAAoB;AAC9M,YAAM,SAAS,kBAAkB,SAAS;AAE1C,iBAAW,WAAW,CAAC,OAAO,cAAc,YAAY,YAAY,IAAI,GAAG;AACzE,cAAM,SAAS,WAAW,CAAC,YAAY,SAAS,SAAS,GAAG,QAAQ,EAAE,6BAA6B,OAAO,CAAC;AAC3G,eAAO,OAAO,QAAQ,GAAG,OAAO,KAAK,OAAO,MAAM,EAAE,EAAE,IAAI,KAAK,CAAC;AAChE,eAAO,OAAO,MAAM,EAAE,UAAU,wCAAwC;AACxE,eAAO,kBAAkB,SAAS,GAAG,OAAO,EAAE,QAAQ,MAAM;AAAA,MAC9D;AACA,YAAM,iBAAiB,WAAW,CAAC,YAAY,OAAO,SAAS,GAAG,QAAQ,EAAE,6BAA6B,QAAQ,CAAC;AAClH,aAAO,eAAe,QAAQ,eAAe,MAAM,EAAE,KAAK,CAAC;AAAA,IAC7D,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AAED,OAAK,wGAAwG,MAAM;AACjH,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,0BAA0B,CAAC;AAChF,QAAI;AACF,YAAM,UAAU;AAChB,YAAM,gBAAgB;AACtB,gBAAU,QAAQ,EAAE,CAAC,OAAO,GAAG,OAAO,aAAa,SAAS,CAAC;AAC7D,YAAM,cAAc,KAAK,KAAK,QAAQ,gBAAgB,OAAO;AAC7D,oBAAc,aAAa,eAAe,CAAC,YAAY,SAAS,CAAC;AACjE,gBAAU,KAAK,KAAK,aAAa,OAAO,WAAW,YAAY,YAAY,GAAG,yCAAyC;AACvH,YAAM,UAAU,WAAW,CAAC,UAAU,UAAU,SAAS,YAAY,YAAY,qBAAqB,GAAG,MAAM;AAC/G,aAAO,QAAQ,QAAQ,QAAQ,MAAM,EAAE,KAAK,CAAC;AAC7C,YAAM,YAAY,KAAK,KAAK,QAAQ,YAAY,WAAW;AAC3D,YAAM,gBAAgB,GAAG,aAAa,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,MAAM;AACpF,aAAO,aAAa,EAAE,UAAU,UAAU,OAAO,GAAG;AACpD,aAAO,aAAa,EAAE,UAAU,iBAAiB,aAAa,GAAG;AACjE,aAAO,GAAG,aAAa,KAAK,KAAK,WAAW,iBAAiB,GAAG,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,sBAAsB;AACnH,aAAO,GAAG,aAAa,KAAK,KAAK,WAAW,4BAA4B,GAAG,MAAM,CAAC,EAAE,UAAU,gBAAgB,OAAO,OAAO;AAE5H,YAAM,UAAU,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,MAAM;AAClE,aAAO,QAAQ,QAAQ,QAAQ,MAAM,EAAE,KAAK,CAAC;AAC7C,YAAM,gBAAgB,GAAG,aAAa,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,MAAM;AACpF,aAAO,aAAa,EAAE,UAAU,cAAc;AAC9C,aAAO,aAAa,EAAE,UAAU,iBAAiB,aAAa,GAAG;AACjE,aAAO,aAAa,EAAE,UAAU,iBAAiB,aAAa,GAAG;AACjE,aAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,OAAO,WAAW,YAAY,YAAY,GAAG,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,kBAAkB;AAErI,gBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,oCAAoC;AACtF,YAAM,WAAW,WAAW,CAAC,YAAY,OAAO,SAAS,GAAG,MAAM;AAClE,aAAO,SAAS,QAAQ,SAAS,MAAM,EAAE,KAAK,CAAC;AAC/C,aAAO,GAAG,aAAa,KAAK,KAAK,WAAW,iBAAiB,GAAG,MAAM,CAAC,EAAE,IAAI,UAAU,UAAU;AACjG,aAAO,GAAG,aAAa,KAAK,KAAK,WAAW,4BAA4B,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE;AAC3F,aAAO,GAAG,WAAW,KAAK,KAAK,aAAa,cAAc,CAAC,CAAC,EAAE,KAAK,IAAI;AACvE,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,OAAO,WAAW,YAAY,UAAU,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,IAC9F,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AAED,OAAK,sFAAsF,MAAM;AAC/F,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,wBAAwB,CAAC;AAC9E,QAAI;AACF,YAAM,UAAU;AAChB,gBAAU,QAAQ,EAAE,CAAC,OAAO,GAAG,gCAAgC,CAAC;AAChE,YAAM,cAAc,KAAK,KAAK,QAAQ,gBAAgB,OAAO;AAC7D,oBAAc,aAAa,uBAAuB,CAAC,UAAU,CAAC;AAC9D,gBAAU,KAAK,KAAK,aAAa,cAAc,GAAG,KAAK,UAAU,EAAE,MAAM,uBAAuB,SAAS,EAAE,KAAK,mCAAmC,EAAE,CAAC,CAAC;AACvJ,YAAM,aAAa,KAAK,KAAK,QAAQ,OAAO,YAAY;AACxD,YAAM,cAAc,GAAG,aAAa,YAAY,MAAM;AAEtD,YAAM,UAAU,WAAW,CAAC,UAAU,UAAU,SAAS,YAAY,YAAY,WAAW,qBAAqB,GAAG,MAAM;AAC1H,aAAO,QAAQ,QAAQ,QAAQ,MAAM,EAAE,IAAI,KAAK,CAAC;AACjD,aAAO,QAAQ,MAAM,EAAE,UAAU,GAAG,OAAO,oBAAoB;AAC/D,aAAO,GAAG,aAAa,YAAY,MAAM,CAAC,EAAE,KAAK,WAAW;AAC5D,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,OAAO,WAAW,UAAU,CAAC,CAAC,EAAE,KAAK,KAAK;AAEjF,YAAM,mBAAmB,2DAA2D,OAAO;AAAA;AAC3F,gBAAU,YAAY,gBAAgB;AACtC,YAAM,UAAU,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,MAAM;AAClE,aAAO,QAAQ,QAAQ,QAAQ,MAAM,EAAE,IAAI,KAAK,CAAC;AACjD,aAAO,QAAQ,MAAM,EAAE,UAAU,GAAG,OAAO,oBAAoB;AAC/D,aAAO,GAAG,aAAa,YAAY,MAAM,CAAC,EAAE,KAAK,gBAAgB;AACjE,aAAO,GAAG,WAAW,KAAK,KAAK,QAAQ,OAAO,WAAW,UAAU,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,IACnF,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AAED,OAAK,oEAAoE,MAAM;AAC7E,UAAM,SAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,yBAAyB,CAAC;AAC/E,QAAI;AACF,YAAM,UAAU;AAChB,gBAAU,QAAQ,EAAE,CAAC,OAAO,GAAG,QAAQ,CAAC;AACxC,oBAAc,KAAK,KAAK,QAAQ,gBAAgB,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC;AAC/E,gBAAU,KAAK,KAAK,QAAQ,OAAO,YAAY,GAAG,2DAA2D,OAAO;AAAA,CAAQ;AAC5H,gBAAU,KAAK,KAAK,QAAQ,OAAO,WAAW,YAAY,UAAU,GAAG,sDAAsD;AAC7H,YAAM,SAAS,kBAAkB,KAAK,KAAK,QAAQ,KAAK,CAAC;AAEzD,YAAM,SAAS,WAAW,CAAC,YAAY,OAAO,SAAS,GAAG,MAAM;AAEhE,aAAO,OAAO,QAAQ,OAAO,MAAM,EAAE,KAAK,CAAC;AAC3C,aAAO,kBAAkB,KAAK,KAAK,QAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,MAAM;AAClE,aAAO,GAAG,aAAa,KAAK,KAAK,QAAQ,YAAY,aAAa,iBAAiB,GAAG,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,sBAAsB;AAAA,IAC3I,UAAE;AACA,SAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
package/dist/lib/eject.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import path from "node:path";
2
2
  import fs from "node:fs";
3
- import { setModuleRegistrationSource } from "./modules-config.js";
4
- import { resolveInstalledOfficialModulePackage } from "./module-package.js";
3
+ import { prepareModuleRegistrationSource, setModuleRegistrationSource } from "./modules-config.js";
4
+ import { isModulePackageExportError, resolveInstalledOfficialModulePackage, resolveInstalledPackageRoot } from "./module-package.js";
5
+ import { normalizeModuleLocator } from "@open-mercato/shared/modules/module-locators";
6
+ import { getEnabledModuleIdentities } from "./module-identity.js";
5
7
  const SKIP_DIRS = /* @__PURE__ */ new Set(["__tests__", "__mocks__", "node_modules"]);
6
8
  const SOURCE_FILE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
7
9
  function shouldSkipEntryName(name) {
@@ -129,8 +131,8 @@ function copyDirRecursive(src, dest) {
129
131
  }
130
132
  }
131
133
  }
132
- function updateModulesTs(modulesPath, moduleId) {
133
- setModuleRegistrationSource(modulesPath, moduleId, "@app");
134
+ function updateModulesTs(modulesPath, moduleId, provenance) {
135
+ setModuleRegistrationSource(modulesPath, moduleId, "@app", provenance);
134
136
  }
135
137
  function resolveModuleSourceBase(resolver, entry) {
136
138
  const { pkgBase } = resolver.getModulePaths(entry);
@@ -164,7 +166,8 @@ function resolveModuleSource(resolver, entry) {
164
166
  description: modulePackage.moduleInfo.description
165
167
  }
166
168
  };
167
- } catch {
169
+ } catch (error) {
170
+ if (isModulePackageExportError(error)) throw error;
168
171
  return { pkgBase, metadata: fallbackMetadata };
169
172
  }
170
173
  }
@@ -187,7 +190,9 @@ function listEjectableModules(resolver) {
187
190
  }
188
191
  function ejectModule(resolver, moduleId) {
189
192
  const modules = resolver.loadEnabledModules();
190
- const entry = modules.find((m) => m.id === moduleId);
193
+ const identities = getEnabledModuleIdentities(resolver, modules);
194
+ const matches = modules.filter((module) => module.id === moduleId);
195
+ const entry = matches[0];
191
196
  if (!entry) {
192
197
  throw new Error(
193
198
  `Module "${moduleId}" is not listed in src/modules.ts. Available modules: ${modules.map((m) => m.id).join(", ")}`
@@ -212,13 +217,24 @@ function ejectModule(resolver, moduleId) {
212
217
  }
213
218
  if (fs.existsSync(appBase)) {
214
219
  throw new Error(
215
- `Destination directory already exists: ${appBase}. Remove it first or resolve the conflict manually.`
220
+ `Destination directory already exists: ${appBase}. Keep the existing local source and review the destination conflict before ejecting.`
216
221
  );
217
222
  }
223
+ const locators = identities.find((identity) => identity.id === moduleId)?.locators ?? [];
224
+ const packageRoot = resolveInstalledPackageRoot(resolver, entry.from || "@open-mercato/core");
225
+ const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
226
+ const packageName = manifest && typeof manifest === "object" && "name" in manifest && typeof manifest.name === "string" ? manifest.name : void 0;
227
+ if (!packageName || normalizeModuleLocator(`npm:${packageName}`) !== `npm:${packageName}`) {
228
+ throw new Error(`Cannot retain source provenance for module "${moduleId}": the installed package manifest has no valid name.`);
229
+ }
230
+ const locator = locators.find((identity) => identity.startsWith("github:")) ?? locators.find((identity) => identity.startsWith("npm:"));
231
+ const provenance = { ...packageName ? { packageName } : {}, ...locator ? { locator } : {} };
232
+ const modulesPath = resolver.getModulesConfigPath();
233
+ const originalConfig = fs.readFileSync(modulesPath, "utf8");
234
+ const updatedConfig = prepareModuleRegistrationSource(originalConfig, moduleId, "@app", provenance);
218
235
  copyDirRecursive(pkgBase, appBase);
219
236
  rewriteCrossModuleImports(pkgBase, appBase, moduleId, entry.from || "@open-mercato/core");
220
- const modulesPath = resolver.getModulesConfigPath();
221
- updateModulesTs(modulesPath, moduleId);
237
+ fs.writeFileSync(modulesPath, updatedConfig);
222
238
  }
223
239
  export {
224
240
  copyDirRecursive,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/eject.ts"],
4
- "sourcesContent": ["import path from 'node:path'\nimport fs from 'node:fs'\nimport { setModuleRegistrationSource } from './modules-config'\nimport type { PackageResolver, ModuleEntry } from './resolver'\nimport { resolveInstalledOfficialModulePackage } from './module-package'\n\ntype ModuleMetadata = {\n ejectable?: boolean\n title?: string\n description?: string\n}\n\nconst SKIP_DIRS = new Set(['__tests__', '__mocks__', 'node_modules'])\nconst SOURCE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\n\nfunction shouldSkipEntryName(name: string): boolean {\n return SKIP_DIRS.has(name) || name === '.DS_Store' || name.startsWith('._')\n}\n\nfunction collectSourceFiles(dir: string): string[] {\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n files.push(...collectSourceFiles(fullPath))\n continue\n }\n const ext = path.extname(entry.name)\n if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue\n files.push(fullPath)\n }\n return files\n}\n\nfunction resolveRelativeImportTarget(sourceFile: string, importPath: string): string | null {\n if (!importPath.startsWith('.')) return null\n\n const basePath = path.resolve(path.dirname(sourceFile), importPath)\n const candidates = [basePath]\n\n for (const ext of SOURCE_FILE_EXTENSIONS) {\n candidates.push(`${basePath}${ext}`)\n candidates.push(path.join(basePath, `index${ext}`))\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\nfunction rewriteRelativeSpecifier(\n sourceFile: string,\n specifier: string,\n modulesRoot: string,\n moduleId: string,\n packageName: string,\n): string {\n const resolvedTarget = resolveRelativeImportTarget(sourceFile, specifier)\n if (!resolvedTarget) return specifier\n\n const modulesRootPrefix = `${modulesRoot}${path.sep}`\n if (!resolvedTarget.startsWith(modulesRootPrefix)) return specifier\n\n const relativeFromModules = path.relative(modulesRoot, resolvedTarget)\n let normalizedRelative = relativeFromModules.split(path.sep).join('/')\n const matchedExt = SOURCE_FILE_EXTENSIONS.find((ext) => normalizedRelative.endsWith(ext))\n if (matchedExt) {\n normalizedRelative = normalizedRelative.slice(0, -matchedExt.length)\n }\n if (normalizedRelative.endsWith('/index')) {\n normalizedRelative = normalizedRelative.slice(0, -'/index'.length)\n }\n const segments = normalizedRelative.split('/')\n const targetModuleId = segments[0]\n\n if (!targetModuleId || targetModuleId === moduleId) return specifier\n\n return `${packageName}/modules/${normalizedRelative}`\n}\n\nexport function rewriteCrossModuleImports(\n pkgBase: string,\n appBase: string,\n moduleId: string,\n packageName: string,\n): void {\n const modulesRoot = path.resolve(pkgBase, '..')\n const appFiles = collectSourceFiles(appBase)\n\n for (const appFile of appFiles) {\n const relativePath = path.relative(appBase, appFile)\n const sourceFile = path.join(pkgBase, relativePath)\n\n if (!fs.existsSync(sourceFile)) continue\n\n const content = fs.readFileSync(appFile, 'utf8')\n let updated = content\n\n updated = updated.replace(\n /(\\bfrom\\s*['\"])([^'\"]+)(['\"])/g,\n (_match, prefix: string, specifier: string, suffix: string) => {\n const rewritten = rewriteRelativeSpecifier(\n sourceFile,\n specifier,\n modulesRoot,\n moduleId,\n packageName,\n )\n return `${prefix}${rewritten}${suffix}`\n },\n )\n\n updated = updated.replace(\n /(\\bimport\\s*\\(\\s*['\"])([^'\"]+)(['\"]\\s*\\))/g,\n (_match, prefix: string, specifier: string, suffix: string) => {\n const rewritten = rewriteRelativeSpecifier(\n sourceFile,\n specifier,\n modulesRoot,\n moduleId,\n packageName,\n )\n return `${prefix}${rewritten}${suffix}`\n },\n )\n\n if (updated !== content) {\n fs.writeFileSync(appFile, updated)\n }\n }\n}\n\nexport function parseModuleMetadata(indexPath: string): ModuleMetadata {\n if (!fs.existsSync(indexPath)) return {}\n\n const source = fs.readFileSync(indexPath, 'utf8')\n const result: ModuleMetadata = {}\n\n const ejectableMatch = source.match(/ejectable\\s*:\\s*(true|false)/)\n if (ejectableMatch) {\n result.ejectable = ejectableMatch[1] === 'true'\n }\n\n const titleMatch = source.match(/title\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (titleMatch) {\n result.title = titleMatch[1]\n }\n\n const descMatch = source.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) {\n result.description = descMatch[1]\n }\n\n return result\n}\n\nexport function copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true })\n\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else {\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\nexport function updateModulesTs(modulesPath: string, moduleId: string): void {\n setModuleRegistrationSource(modulesPath, moduleId, '@app')\n}\n\nexport type EjectableModule = {\n id: string\n title?: string\n description?: string\n from: string\n}\n\ntype ResolvedModuleSource = {\n pkgBase: string\n metadata: ModuleMetadata\n}\n\n// Standalone installs resolve getModulePaths' pkgBase to the package's\n// dist/modules tree when it exists (compiled JS, no index.ts), which made every\n// ejectable module read as \"not ejectable\" and eject copies of compiled output\n// (#4272). Prefer the shipped TypeScript sources under src/modules; fall back\n// to the resolved base for packages that ship dist only.\nfunction resolveModuleSourceBase(resolver: PackageResolver, entry: ModuleEntry): string {\n const { pkgBase } = resolver.getModulePaths(entry)\n const from = entry.from || '@open-mercato/core'\n if (from === '@app') return pkgBase\n const sourceBase = path.join(resolver.getPackageRoot(from), 'src', 'modules', entry.id)\n if (path.resolve(sourceBase) !== path.resolve(pkgBase) && fs.existsSync(sourceBase)) {\n return sourceBase\n }\n return pkgBase\n}\n\nfunction readModuleMetadata(moduleDir: string): ModuleMetadata {\n const tsIndex = path.join(moduleDir, 'index.ts')\n if (fs.existsSync(tsIndex)) return parseModuleMetadata(tsIndex)\n return parseModuleMetadata(path.join(moduleDir, 'index.js'))\n}\n\nfunction resolveModuleSource(\n resolver: PackageResolver,\n entry: ModuleEntry,\n): ResolvedModuleSource {\n const pkgBase = resolveModuleSourceBase(resolver, entry)\n const fallbackMetadata = readModuleMetadata(pkgBase)\n const from = entry.from || '@open-mercato/core'\n\n if (from === '@app' || from === '@open-mercato/core') {\n return { pkgBase, metadata: fallbackMetadata }\n }\n\n try {\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, from, entry.id)\n\n return {\n pkgBase: modulePackage.sourceModuleDir,\n metadata: {\n ejectable: modulePackage.metadata.ejectable,\n title: modulePackage.moduleInfo.title ?? modulePackage.metadata.moduleId,\n description: modulePackage.moduleInfo.description,\n },\n }\n } catch {\n return { pkgBase, metadata: fallbackMetadata }\n }\n}\n\nexport function listEjectableModules(resolver: PackageResolver): EjectableModule[] {\n const modules = resolver.loadEnabledModules()\n const ejectable: EjectableModule[] = []\n\n for (const entry of modules) {\n if (entry.from === '@app') continue\n\n const { metadata } = resolveModuleSource(resolver, entry)\n\n if (metadata.ejectable) {\n ejectable.push({\n id: entry.id,\n title: metadata.title,\n description: metadata.description,\n from: entry.from || '@open-mercato/core',\n })\n }\n }\n\n return ejectable\n}\n\nexport function ejectModule(resolver: PackageResolver, moduleId: string): void {\n const modules = resolver.loadEnabledModules()\n const entry = modules.find((m: ModuleEntry) => m.id === moduleId)\n\n if (!entry) {\n throw new Error(\n `Module \"${moduleId}\" is not listed in src/modules.ts. ` +\n `Available modules: ${modules.map((m: ModuleEntry) => m.id).join(', ')}`,\n )\n }\n\n if (entry.from === '@app') {\n throw new Error(\n `Module \"${moduleId}\" is already local (from: '@app'). Nothing to eject.`,\n )\n }\n\n const { appBase } = resolver.getModulePaths(entry)\n const { pkgBase, metadata } = resolveModuleSource(resolver, entry)\n\n if (!fs.existsSync(pkgBase)) {\n throw new Error(\n `Package source directory not found: ${pkgBase}. ` +\n `Make sure the package is installed.`,\n )\n }\n\n if (!metadata.ejectable) {\n throw new Error(\n `Module \"${moduleId}\" is not marked as ejectable. Only modules with \\`ejectable: true\\` in their metadata can be ejected.`,\n )\n }\n\n if (fs.existsSync(appBase)) {\n throw new Error(\n `Destination directory already exists: ${appBase}. ` +\n `Remove it first or resolve the conflict manually.`,\n )\n }\n\n copyDirRecursive(pkgBase, appBase)\n rewriteCrossModuleImports(pkgBase, appBase, moduleId, entry.from || '@open-mercato/core')\n\n const modulesPath = resolver.getModulesConfigPath()\n updateModulesTs(modulesPath, moduleId)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import path from 'node:path'\nimport fs from 'node:fs'\nimport { prepareModuleRegistrationSource, setModuleRegistrationSource } from './modules-config'\nimport type { PackageResolver, ModuleEntry } from './resolver'\nimport { isModulePackageExportError, resolveInstalledOfficialModulePackage, resolveInstalledPackageRoot } from './module-package'\nimport { normalizeModuleLocator } from '@open-mercato/shared/modules/module-locators'\nimport { getEnabledModuleIdentities } from './module-identity'\n\ntype ModuleMetadata = {\n ejectable?: boolean\n title?: string\n description?: string\n}\n\nconst SKIP_DIRS = new Set(['__tests__', '__mocks__', 'node_modules'])\nconst SOURCE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\n\nfunction shouldSkipEntryName(name: string): boolean {\n return SKIP_DIRS.has(name) || name === '.DS_Store' || name.startsWith('._')\n}\n\nfunction collectSourceFiles(dir: string): string[] {\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n files.push(...collectSourceFiles(fullPath))\n continue\n }\n const ext = path.extname(entry.name)\n if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue\n files.push(fullPath)\n }\n return files\n}\n\nfunction resolveRelativeImportTarget(sourceFile: string, importPath: string): string | null {\n if (!importPath.startsWith('.')) return null\n\n const basePath = path.resolve(path.dirname(sourceFile), importPath)\n const candidates = [basePath]\n\n for (const ext of SOURCE_FILE_EXTENSIONS) {\n candidates.push(`${basePath}${ext}`)\n candidates.push(path.join(basePath, `index${ext}`))\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\nfunction rewriteRelativeSpecifier(\n sourceFile: string,\n specifier: string,\n modulesRoot: string,\n moduleId: string,\n packageName: string,\n): string {\n const resolvedTarget = resolveRelativeImportTarget(sourceFile, specifier)\n if (!resolvedTarget) return specifier\n\n const modulesRootPrefix = `${modulesRoot}${path.sep}`\n if (!resolvedTarget.startsWith(modulesRootPrefix)) return specifier\n\n const relativeFromModules = path.relative(modulesRoot, resolvedTarget)\n let normalizedRelative = relativeFromModules.split(path.sep).join('/')\n const matchedExt = SOURCE_FILE_EXTENSIONS.find((ext) => normalizedRelative.endsWith(ext))\n if (matchedExt) {\n normalizedRelative = normalizedRelative.slice(0, -matchedExt.length)\n }\n if (normalizedRelative.endsWith('/index')) {\n normalizedRelative = normalizedRelative.slice(0, -'/index'.length)\n }\n const segments = normalizedRelative.split('/')\n const targetModuleId = segments[0]\n\n if (!targetModuleId || targetModuleId === moduleId) return specifier\n\n return `${packageName}/modules/${normalizedRelative}`\n}\n\nexport function rewriteCrossModuleImports(\n pkgBase: string,\n appBase: string,\n moduleId: string,\n packageName: string,\n): void {\n const modulesRoot = path.resolve(pkgBase, '..')\n const appFiles = collectSourceFiles(appBase)\n\n for (const appFile of appFiles) {\n const relativePath = path.relative(appBase, appFile)\n const sourceFile = path.join(pkgBase, relativePath)\n\n if (!fs.existsSync(sourceFile)) continue\n\n const content = fs.readFileSync(appFile, 'utf8')\n let updated = content\n\n updated = updated.replace(\n /(\\bfrom\\s*['\"])([^'\"]+)(['\"])/g,\n (_match, prefix: string, specifier: string, suffix: string) => {\n const rewritten = rewriteRelativeSpecifier(\n sourceFile,\n specifier,\n modulesRoot,\n moduleId,\n packageName,\n )\n return `${prefix}${rewritten}${suffix}`\n },\n )\n\n updated = updated.replace(\n /(\\bimport\\s*\\(\\s*['\"])([^'\"]+)(['\"]\\s*\\))/g,\n (_match, prefix: string, specifier: string, suffix: string) => {\n const rewritten = rewriteRelativeSpecifier(\n sourceFile,\n specifier,\n modulesRoot,\n moduleId,\n packageName,\n )\n return `${prefix}${rewritten}${suffix}`\n },\n )\n\n if (updated !== content) {\n fs.writeFileSync(appFile, updated)\n }\n }\n}\n\nexport function parseModuleMetadata(indexPath: string): ModuleMetadata {\n if (!fs.existsSync(indexPath)) return {}\n\n const source = fs.readFileSync(indexPath, 'utf8')\n const result: ModuleMetadata = {}\n\n const ejectableMatch = source.match(/ejectable\\s*:\\s*(true|false)/)\n if (ejectableMatch) {\n result.ejectable = ejectableMatch[1] === 'true'\n }\n\n const titleMatch = source.match(/title\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (titleMatch) {\n result.title = titleMatch[1]\n }\n\n const descMatch = source.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) {\n result.description = descMatch[1]\n }\n\n return result\n}\n\nexport function copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true })\n\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else {\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\nexport function updateModulesTs(modulesPath: string, moduleId: string, provenance?: Pick<ModuleEntry, 'locator' | 'packageName'>): void {\n setModuleRegistrationSource(modulesPath, moduleId, '@app', provenance)\n}\n\nexport type EjectableModule = {\n id: string\n title?: string\n description?: string\n from: string\n}\n\ntype ResolvedModuleSource = {\n pkgBase: string\n metadata: ModuleMetadata\n}\n\n// Standalone installs resolve getModulePaths' pkgBase to the package's\n// dist/modules tree when it exists (compiled JS, no index.ts), which made every\n// ejectable module read as \"not ejectable\" and eject copies of compiled output\n// (#4272). Prefer the shipped TypeScript sources under src/modules; fall back\n// to the resolved base for packages that ship dist only.\nfunction resolveModuleSourceBase(resolver: PackageResolver, entry: ModuleEntry): string {\n const { pkgBase } = resolver.getModulePaths(entry)\n const from = entry.from || '@open-mercato/core'\n if (from === '@app') return pkgBase\n const sourceBase = path.join(resolver.getPackageRoot(from), 'src', 'modules', entry.id)\n if (path.resolve(sourceBase) !== path.resolve(pkgBase) && fs.existsSync(sourceBase)) {\n return sourceBase\n }\n return pkgBase\n}\n\nfunction readModuleMetadata(moduleDir: string): ModuleMetadata {\n const tsIndex = path.join(moduleDir, 'index.ts')\n if (fs.existsSync(tsIndex)) return parseModuleMetadata(tsIndex)\n return parseModuleMetadata(path.join(moduleDir, 'index.js'))\n}\n\nfunction resolveModuleSource(\n resolver: PackageResolver,\n entry: ModuleEntry,\n): ResolvedModuleSource {\n const pkgBase = resolveModuleSourceBase(resolver, entry)\n const fallbackMetadata = readModuleMetadata(pkgBase)\n const from = entry.from || '@open-mercato/core'\n\n if (from === '@app' || from === '@open-mercato/core') {\n return { pkgBase, metadata: fallbackMetadata }\n }\n\n try {\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, from, entry.id)\n\n return {\n pkgBase: modulePackage.sourceModuleDir,\n metadata: {\n ejectable: modulePackage.metadata.ejectable,\n title: modulePackage.moduleInfo.title ?? modulePackage.metadata.moduleId,\n description: modulePackage.moduleInfo.description,\n },\n }\n } catch (error) {\n if (isModulePackageExportError(error)) throw error\n return { pkgBase, metadata: fallbackMetadata }\n }\n}\n\nexport function listEjectableModules(resolver: PackageResolver): EjectableModule[] {\n const modules = resolver.loadEnabledModules()\n const ejectable: EjectableModule[] = []\n\n for (const entry of modules) {\n if (entry.from === '@app') continue\n\n const { metadata } = resolveModuleSource(resolver, entry)\n\n if (metadata.ejectable) {\n ejectable.push({\n id: entry.id,\n title: metadata.title,\n description: metadata.description,\n from: entry.from || '@open-mercato/core',\n })\n }\n }\n\n return ejectable\n}\n\nexport function ejectModule(resolver: PackageResolver, moduleId: string): void {\n const modules = resolver.loadEnabledModules()\n const identities = getEnabledModuleIdentities(resolver, modules)\n const matches = modules.filter((module: ModuleEntry) => module.id === moduleId)\n const entry = matches[0]\n\n if (!entry) {\n throw new Error(\n `Module \"${moduleId}\" is not listed in src/modules.ts. ` +\n `Available modules: ${modules.map((m: ModuleEntry) => m.id).join(', ')}`,\n )\n }\n\n if (entry.from === '@app') {\n throw new Error(\n `Module \"${moduleId}\" is already local (from: '@app'). Nothing to eject.`,\n )\n }\n\n const { appBase } = resolver.getModulePaths(entry)\n const { pkgBase, metadata } = resolveModuleSource(resolver, entry)\n\n if (!fs.existsSync(pkgBase)) {\n throw new Error(\n `Package source directory not found: ${pkgBase}. ` +\n `Make sure the package is installed.`,\n )\n }\n\n if (!metadata.ejectable) {\n throw new Error(\n `Module \"${moduleId}\" is not marked as ejectable. Only modules with \\`ejectable: true\\` in their metadata can be ejected.`,\n )\n }\n\n if (fs.existsSync(appBase)) {\n throw new Error(\n `Destination directory already exists: ${appBase}. ` +\n `Keep the existing local source and review the destination conflict before ejecting.`,\n )\n }\n\n const locators = identities.find((identity) => identity.id === moduleId)?.locators ?? []\n const packageRoot = resolveInstalledPackageRoot(resolver, entry.from || '@open-mercato/core')\n const manifest: unknown = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'))\n const packageName = manifest && typeof manifest === 'object' && 'name' in manifest && typeof manifest.name === 'string'\n ? manifest.name\n : undefined\n if (!packageName || normalizeModuleLocator(`npm:${packageName}`) !== `npm:${packageName}`) {\n throw new Error(`Cannot retain source provenance for module \"${moduleId}\": the installed package manifest has no valid name.`)\n }\n const locator = locators.find((identity) => identity.startsWith('github:')) ?? locators.find((identity) => identity.startsWith('npm:'))\n const provenance = { ...(packageName ? { packageName } : {}), ...(locator ? { locator } : {}) }\n const modulesPath = resolver.getModulesConfigPath()\n const originalConfig = fs.readFileSync(modulesPath, 'utf8')\n const updatedConfig = prepareModuleRegistrationSource(originalConfig, moduleId, '@app', provenance)\n\n copyDirRecursive(pkgBase, appBase)\n rewriteCrossModuleImports(pkgBase, appBase, moduleId, entry.from || '@open-mercato/core')\n fs.writeFileSync(modulesPath, updatedConfig)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { getEnabledModuleIdentities } from "../module-identity.js";
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import ts from "typescript-js";
@@ -242,6 +243,7 @@ async function generateEntityIds(options) {
242
243
  const outFile = path.join(outputDir, "entities.ids.generated.ts");
243
244
  const checksumFile = path.join(outputDir, "entities.ids.generated.checksum");
244
245
  const entries = resolver.loadEnabledModules();
246
+ getEnabledModuleIdentities(resolver, entries);
245
247
  const consolidated = {};
246
248
  const grouped = {};
247
249
  const modulesDict = {};