@open-mercato/cli 0.6.8-develop.7100.1.fbf66fca35 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/.turbo/turbo-build.log +1 -7
  2. package/dist/agentic/guides/module-facts.json +598 -5508
  3. package/dist/agentic/guides/module-facts.v2.json +598 -5594
  4. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  5. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_keys/exact-override-targets.md +0 -1
  7. package/dist/agentic/guides/modules/api_keys/index.md +2 -4
  8. package/dist/agentic/guides/modules/attachments/di-registrations-rich.md +5 -6
  9. package/dist/agentic/guides/modules/attachments/di-service-tokens.md +4 -5
  10. package/dist/agentic/guides/modules/attachments/exact-override-targets.md +5 -6
  11. package/dist/agentic/guides/modules/attachments/index.md +2 -2
  12. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  13. package/dist/agentic/guides/modules/auth/di-registrations-rich.md +2 -3
  14. package/dist/agentic/guides/modules/auth/di-service-tokens.md +2 -3
  15. package/dist/agentic/guides/modules/auth/exact-override-targets.md +2 -3
  16. package/dist/agentic/guides/modules/auth/index.md +1 -1
  17. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  18. package/dist/agentic/guides/modules/catalog/incoming-installed-contributions.md +0 -3
  19. package/dist/agentic/guides/modules/catalog/index.md +2 -2
  20. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  21. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  22. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  23. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  24. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  25. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  26. package/dist/agentic/guides/modules/communication_channels/di-registrations-rich.md +8 -9
  27. package/dist/agentic/guides/modules/communication_channels/exact-override-targets.md +8 -9
  28. package/dist/agentic/guides/modules/communication_channels/incoming-installed-contributions.md +0 -2
  29. package/dist/agentic/guides/modules/communication_channels/index.md +3 -3
  30. package/dist/agentic/guides/modules/configs/index.md +1 -1
  31. package/dist/agentic/guides/modules/content/index.md +1 -1
  32. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  33. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  34. package/dist/agentic/guides/modules/customers/active-extension-bindings.md +3 -6
  35. package/dist/agentic/guides/modules/customers/contribution-resolutions.md +0 -1
  36. package/dist/agentic/guides/modules/customers/events.md +1 -2
  37. package/dist/agentic/guides/modules/customers/incoming-installed-contributions.md +0 -7
  38. package/dist/agentic/guides/modules/customers/index.md +4 -4
  39. package/dist/agentic/guides/modules/customers/umes-contributions.md +0 -1
  40. package/dist/agentic/guides/modules/customers/umes-hosts.md +0 -1
  41. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  42. package/dist/agentic/guides/modules/data_sync/exact-override-targets.md +2 -2
  43. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  44. package/dist/agentic/guides/modules/data_sync/workers.md +2 -2
  45. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  46. package/dist/agentic/guides/modules/devices/index.md +1 -1
  47. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  48. package/dist/agentic/guides/modules/directory/exact-override-targets.md +0 -2
  49. package/dist/agentic/guides/modules/directory/index.md +3 -5
  50. package/dist/agentic/guides/modules/entities/index.md +1 -1
  51. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  52. package/dist/agentic/guides/modules/events/index.md +1 -1
  53. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  54. package/dist/agentic/guides/modules/gateway_stripe/exact-override-targets.md +1 -1
  55. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  56. package/dist/agentic/guides/modules/gateway_stripe/workers.md +1 -1
  57. package/dist/agentic/guides/modules/generators/index.md +1 -1
  58. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  59. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  60. package/dist/agentic/guides/modules/messages/index.md +1 -1
  61. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  62. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  63. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  64. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  65. package/dist/agentic/guides/modules/planner/index.md +1 -1
  66. package/dist/agentic/guides/modules/portal/index.md +1 -1
  67. package/dist/agentic/guides/modules/progress/index.md +1 -1
  68. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  69. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  70. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  71. package/dist/agentic/guides/modules/resources/index.md +1 -1
  72. package/dist/agentic/guides/modules/sales/active-extension-bindings.md +0 -1
  73. package/dist/agentic/guides/modules/sales/contribution-resolutions.md +0 -1
  74. package/dist/agentic/guides/modules/sales/exact-override-targets.md +4 -5
  75. package/dist/agentic/guides/modules/sales/host-extension-points.md +1 -1
  76. package/dist/agentic/guides/modules/sales/incoming-installed-contributions.md +0 -2
  77. package/dist/agentic/guides/modules/sales/index.md +3 -3
  78. package/dist/agentic/guides/modules/sales/setup.md +1 -1
  79. package/dist/agentic/guides/modules/sales/umes-contributions.md +0 -1
  80. package/dist/agentic/guides/modules/sales/umes-diagnostics.md +0 -1
  81. package/dist/agentic/guides/modules/sales/umes-hosts.md +0 -9
  82. package/dist/agentic/guides/modules/scheduler/cli-commands.md +0 -1
  83. package/dist/agentic/guides/modules/scheduler/exact-override-targets.md +1 -3
  84. package/dist/agentic/guides/modules/scheduler/index.md +2 -2
  85. package/dist/agentic/guides/modules/scheduler/workers.md +1 -2
  86. package/dist/agentic/guides/modules/search/index.md +1 -1
  87. package/dist/agentic/guides/modules/security/index.md +1 -1
  88. package/dist/agentic/guides/modules/security/owned-contract-module-metadata.md +1 -1
  89. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  90. package/dist/agentic/guides/modules/sso/index.md +1 -1
  91. package/dist/agentic/guides/modules/staff/index.md +1 -1
  92. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  93. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  94. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  95. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  96. package/dist/agentic/guides/modules/translations/index.md +1 -1
  97. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  98. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  99. package/dist/agentic/guides/modules/wms/index.md +1 -1
  100. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  101. package/dist/agentic/guides/reference-module-facts.json +2 -2
  102. package/dist/agentic/guides/reference-modules/example/index.md +1 -1
  103. package/dist/agentic/guides/upstream/manifest.json +1 -1
  104. package/dist/agentic/shared/AGENTS.md.template +3 -3
  105. package/dist/agentic/shared/ai/harness/README.md +2 -2
  106. package/dist/agentic/shared/ai/harness/RELEASE.md +6 -8
  107. package/dist/agentic/shared/ai/harness/cases.json +0 -83
  108. package/dist/agentic/shared/ai/harness/cases.schema.json +4 -4
  109. package/dist/agentic/shared/ai/harness/validators.json +1 -1
  110. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.7-to-0.7.0/SKILL.md +12 -3
  111. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +11 -37
  112. package/dist/lib/generators/ast/index.js +1 -4
  113. package/dist/lib/generators/ast/index.js.map +2 -2
  114. package/dist/lib/generators/ast/source-file.js +1 -8
  115. package/dist/lib/generators/ast/source-file.js.map +2 -2
  116. package/dist/lib/generators/ast/writers.js +1 -9
  117. package/dist/lib/generators/ast/writers.js.map +2 -2
  118. package/dist/lib/generators/module-registry.js +189 -424
  119. package/dist/lib/generators/module-registry.js.map +2 -2
  120. package/dist/lib/generators/route-manifest-shards.js +1 -4
  121. package/dist/lib/generators/route-manifest-shards.js.map +2 -2
  122. package/dist/lib/spawn.js +2 -3
  123. package/dist/lib/spawn.js.map +2 -2
  124. package/dist/lib/testing/integration.js +24 -162
  125. package/dist/lib/testing/integration.js.map +2 -2
  126. package/dist/mercato.js +0 -14
  127. package/dist/mercato.js.map +2 -2
  128. package/package.json +7 -8
  129. package/src/lib/__tests__/spawn.test.ts +0 -23
  130. package/src/lib/generators/__tests__/metadata-extraction.test.ts +0 -44
  131. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +8 -32
  132. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -4
  133. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +1 -1
  134. package/src/lib/generators/__tests__/module-subset.test.ts +72 -96
  135. package/src/lib/generators/__tests__/output-snapshots.test.ts +1 -1
  136. package/src/lib/generators/__tests__/route-manifest-shards.test.ts +0 -15
  137. package/src/lib/generators/__tests__/structural-contracts.test.ts +3 -7
  138. package/src/lib/generators/ast/index.ts +1 -2
  139. package/src/lib/generators/ast/source-file.ts +0 -13
  140. package/src/lib/generators/ast/writers.ts +1 -26
  141. package/src/lib/generators/module-registry.ts +227 -534
  142. package/src/lib/generators/route-manifest-shards.ts +1 -8
  143. package/src/lib/spawn.ts +4 -5
  144. package/src/lib/testing/__tests__/integration.test.ts +0 -435
  145. package/src/lib/testing/integration.ts +32 -254
  146. package/src/mercato.ts +0 -27
  147. package/dist/agentic/guides/modules/api_keys/di-registrations-rich.md +0 -11
  148. package/dist/agentic/guides/modules/api_keys/di-service-tokens.md +0 -11
  149. package/dist/agentic/guides/modules/channel_discord/acl-features.md +0 -13
  150. package/dist/agentic/guides/modules/channel_discord/ai-agents.md +0 -11
  151. package/dist/agentic/guides/modules/channel_discord/backend-pages.md +0 -11
  152. package/dist/agentic/guides/modules/channel_discord/cli-commands.md +0 -13
  153. package/dist/agentic/guides/modules/channel_discord/contribution-resolutions.md +0 -14
  154. package/dist/agentic/guides/modules/channel_discord/di-registrations-rich.md +0 -12
  155. package/dist/agentic/guides/modules/channel_discord/exact-override-targets.md +0 -26
  156. package/dist/agentic/guides/modules/channel_discord/index.md +0 -22
  157. package/dist/agentic/guides/modules/channel_discord/owned-contract-module-metadata.md +0 -11
  158. package/dist/agentic/guides/modules/channel_discord/setup.md +0 -11
  159. package/dist/agentic/guides/modules/channel_discord/umes-contributions.md +0 -14
  160. package/dist/agentic/guides/modules/channel_discord/workers.md +0 -12
  161. package/dist/agentic/guides/modules/directory/di-registrations-rich.md +0 -12
  162. package/dist/agentic/guides/modules/directory/di-service-tokens.md +0 -12
  163. package/dist/agentic/guides/modules/documents/acl-features.md +0 -17
  164. package/dist/agentic/guides/modules/documents/backend-pages.md +0 -13
  165. package/dist/agentic/guides/modules/documents/contribution-resolutions.md +0 -27
  166. package/dist/agentic/guides/modules/documents/di-registrations-rich.md +0 -21
  167. package/dist/agentic/guides/modules/documents/domain-commands.md +0 -37
  168. package/dist/agentic/guides/modules/documents/encryption.md +0 -11
  169. package/dist/agentic/guides/modules/documents/entities.md +0 -21
  170. package/dist/agentic/guides/modules/documents/events.md +0 -25
  171. package/dist/agentic/guides/modules/documents/exact-override-targets.md +0 -39
  172. package/dist/agentic/guides/modules/documents/index.md +0 -25
  173. package/dist/agentic/guides/modules/documents/notifications.md +0 -13
  174. package/dist/agentic/guides/modules/documents/owned-contract-module-metadata.md +0 -11
  175. package/dist/agentic/guides/modules/documents/setup.md +0 -11
  176. package/dist/agentic/guides/modules/documents/umes-contributions.md +0 -27
  177. package/dist/agentic/guides/modules/documents/umes-hosts.md +0 -36
  178. package/src/__tests__/resolve-queue-abandon-hook.test.ts +0 -39
  179. package/src/lib/generators/__tests__/__snapshots__/bootstrap-registrations.test.ts.snap +0 -14
  180. package/src/lib/generators/__tests__/__snapshots__/command-loaders.test.ts.snap +0 -23
  181. package/src/lib/generators/__tests__/ast-writers-escaping.test.ts +0 -64
  182. package/src/lib/generators/__tests__/bootstrap-registrations.test.ts +0 -176
  183. package/src/lib/generators/__tests__/command-loaders.test.ts +0 -239
  184. package/src/lib/generators/__tests__/generated-registry-imports.test.ts +0 -128
  185. package/src/lib/generators/__tests__/registry-variant-parity.test.ts +0 -258
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.6.8-develop.7100.1.fbf66fca35",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,9 +60,9 @@
60
60
  "@mikro-orm/decorators": "^7.1.8",
61
61
  "@mikro-orm/migrations": "^7.1.8",
62
62
  "@mikro-orm/postgresql": "^7.1.8",
63
- "@open-mercato/queue": "0.6.8-develop.7100.1.fbf66fca35",
64
- "@open-mercato/shared": "0.6.8-develop.7100.1.fbf66fca35",
65
- "@open-mercato/telemetry": "0.6.8-develop.7100.1.fbf66fca35",
63
+ "@open-mercato/queue": "0.7.0",
64
+ "@open-mercato/shared": "0.7.0",
65
+ "@open-mercato/telemetry": "0.7.0",
66
66
  "cross-spawn": "^7.0.6",
67
67
  "pg": "8.22.0",
68
68
  "semver": "^7.8.5",
@@ -73,10 +73,10 @@
73
73
  "typescript-js": "npm:typescript@6.0.3"
74
74
  },
75
75
  "peerDependencies": {
76
- "@open-mercato/shared": "0.6.8-develop.7100.1.fbf66fca35"
76
+ "@open-mercato/shared": "0.7.0"
77
77
  },
78
78
  "devDependencies": {
79
- "@open-mercato/shared": "0.6.8-develop.7100.1.fbf66fca35",
79
+ "@open-mercato/shared": "0.7.0",
80
80
  "@types/jest": "^30.0.0",
81
81
  "jest": "^30.4.2",
82
82
  "ts-jest": "^29.4.12"
@@ -88,6 +88,5 @@
88
88
  "type": "git",
89
89
  "url": "https://github.com/open-mercato/open-mercato",
90
90
  "directory": "packages/cli"
91
- },
92
- "stableVersion": "0.6.7"
91
+ }
93
92
  }
@@ -39,26 +39,3 @@ describe('resolveSpawnCommand', () => {
39
39
  )
40
40
  })
41
41
  })
42
-
43
- describe('resolveSpawnCommand detached passthrough', () => {
44
- // The whole process-group teardown in the ephemeral harness rests on this flag reaching `spawn`:
45
- // without it the app tree stays in the runner's group and the negated-pid kill has nothing of its
46
- // own to signal.
47
- it('passes detached through on the POSIX branch', () => {
48
- const result = resolveSpawnCommand('yarn', ['start'], { platform: 'linux', detached: true })
49
-
50
- expect(result.spawnOptions).toEqual({ detached: true })
51
- })
52
-
53
- it('passes detached through on the Windows cmd branch', () => {
54
- const result = resolveSpawnCommand('yarn.cmd', ['start'], { platform: 'win32', detached: true })
55
-
56
- expect(result.spawnOptions).toEqual({ detached: true })
57
- })
58
-
59
- it('omits detached entirely when the caller does not ask for it', () => {
60
- expect(resolveSpawnCommand('yarn', ['start'], { platform: 'linux' }).spawnOptions).toEqual({})
61
- expect(resolveSpawnCommand('yarn', ['start']).spawnOptions).not.toHaveProperty('detached')
62
- expect(resolveSpawnCommand('yarn', ['start'], { platform: 'linux', detached: false }).spawnOptions).toEqual({})
63
- })
64
- })
@@ -4,7 +4,6 @@ import os from 'node:os'
4
4
  import {
5
5
  extractNamedObjectLiteralExport,
6
6
  hasNamedExport,
7
- namedObjectLiteralDeclaresProperty,
8
7
  resolveNamedObjectExport,
9
8
  } from '../module-registry'
10
9
 
@@ -219,46 +218,3 @@ describe('hasNamedExport', () => {
219
218
  expect(hasNamedExport(file, 'metadata')).toBe(false)
220
219
  })
221
220
  })
222
-
223
- describe('namedObjectLiteralDeclaresProperty', () => {
224
- // A worker declaring `onJobAbandoned: someImportedFn` is the case that broke: the value resolvers
225
- // cannot evaluate an imported identifier, so "is it declared" has to be answered from the syntax.
226
- // Getting this wrong is silent — the generator simply never emits the hook.
227
- it('sees a property whose value is an unresolvable identifier', () => {
228
- const file = writeSource('worker.ts', `
229
- import { failAbandonedRun } from '../lib/abandoned-run'
230
- export const metadata = {
231
- queue: 'data-sync-import',
232
- concurrency: 5,
233
- onJobAbandoned: failAbandonedRun,
234
- }
235
- `)
236
- expect(namedObjectLiteralDeclaresProperty(file, 'metadata', 'onJobAbandoned')).toBe(true)
237
- expect(extractNamedObjectLiteralExport(file, 'metadata')?.onJobAbandoned).toBeUndefined()
238
- })
239
-
240
- it('sees a property declared as an inline function', () => {
241
- const file = writeSource('worker.ts', `
242
- export const metadata = {
243
- queue: 'q',
244
- onJobAbandoned: async () => {},
245
- }
246
- `)
247
- expect(namedObjectLiteralDeclaresProperty(file, 'metadata', 'onJobAbandoned')).toBe(true)
248
- })
249
-
250
- it('reports absence for a worker that declares no hook', () => {
251
- const file = writeSource('worker.ts', `
252
- export const metadata = { queue: 'q', concurrency: 1 }
253
- `)
254
- expect(namedObjectLiteralDeclaresProperty(file, 'metadata', 'onJobAbandoned')).toBe(false)
255
- })
256
-
257
- it('reports absence for a metadata export that is not an object literal', () => {
258
- const file = writeSource('worker.ts', `
259
- const base = buildMetadata()
260
- export const metadata = base
261
- `)
262
- expect(namedObjectLiteralDeclaresProperty(file, 'metadata', 'onJobAbandoned')).toBe(false)
263
- })
264
- })
@@ -149,46 +149,22 @@ describe('module-facts BC resolve guard (T2)', () => {
149
149
  // wms, staff, integrations and checkout were therefore invisible to every fact
150
150
  // consumer — `integrations` published no contributions at all. Reading them costs
151
151
  // ~28KB, which is the fix working, not drift.
152
- // The additive EUDR and Documents modules contribute their real routes, ACL,
153
- // events, entities, and extension surfaces without changing the extraction
154
- // shape.
152
+ // The additive EUDR module contributes its real routes, ACL, events,
153
+ // entities, and extension surfaces without changing the extraction shape.
155
154
  //
156
155
  // JSON cap raised a fifth time by the devices/push-notifications stack: the
157
156
  // `devices` and `push_notifications` modules plus the `channel-fcm`,
158
157
  // `channel-apns` and `channel-expo` provider packages add their own facts,
159
158
  // provenance entries and override targets to every render. The
160
- // `warranty_claims` module (see above) and the additive Documents module
161
- // land alongside it.
162
- //
163
- // Raised again here for a reason unlike every raise above: those all tracked
164
- // a schema or extraction change, this one tracks ordinary repo growth. The
165
- // additive `channel_discord` module costs ~15.9KB JSON and ~9.2KB markdown
166
- // (`channel_gmail` costs 6,886 / `channel_imap` 6,798; the difference is a
167
- // gateway worker, a CLI command, a signed route and a subscriber, spread
168
- // proportionally across overrideTargets, extensionSurfaces, factSources and
169
- // ownedContracts — no duplicated payloads).
170
- //
171
- // The numbers below are MEASURED ON THE MERGED TREE, not transcribed from
172
- // either side of the merge: neither side's cap covers the union. A cap that
173
- // sits a fraction of a percent above the current measurement has stopped
174
- // detecting blow-ups and started rejecting the next additive module of any
175
- // size, whichever PR happens to add it — so keep bounded headroom over the
176
- // measured size. A real blow-up here is multiplicative (a duplicated
177
- // provenance payload, a contribution body copied per resolution), not one
178
- // provider's worth of references.
179
- expect(Buffer.byteLength(completeJson)).toBeLessThan(4_700_000)
180
- // Measured on the merged tree (`yarn jest module-facts.bc-guard`):
181
- // completeJson 4,120,374 · legacy delta 1,795,214 · markdown 1,558,590 ·
182
- // directory markdown 1,709,511.
183
- // The delta cap is raised alongside the JSON one for the same reason: at
184
- // 1,800,000 it sat 0.27% above the measurement, which is not a guard.
185
- expect(Buffer.byteLength(completeJson) - Buffer.byteLength(legacyJson)).toBeLessThan(2_050_000)
159
+ // `warranty_claims` module (see above) lands alongside it, so the cap
160
+ // absorbs both additions.
161
+ expect(Buffer.byteLength(completeJson)).toBeLessThan(4_000_000)
162
+ expect(Buffer.byteLength(completeJson) - Buffer.byteLength(legacyJson)).toBeLessThan(1_800_000)
186
163
  // Markdown cap raised with the source-link contract: entities, events, ACL
187
164
  // features, DI tokens, search entities, notifications, UMES hosts and UMES
188
165
  // contributions all render a resolved Source cell, and contribution
189
- // resolutions render as their own source-linked section — plus the additive
190
- // `channel_discord` module's own render, per the growth note above.
191
- expect(markdownBytes).toBeLessThan(1_800_000)
166
+ // resolutions render as their own source-linked section.
167
+ expect(markdownBytes).toBeLessThan(1_750_000)
192
168
  expect(directoryMarkdownBytes).toBeLessThan(2_050_000)
193
169
  })
194
170
 
@@ -28,10 +28,7 @@ describe('module-facts customers fixture (T1 anti-drift guard)', () => {
28
28
  })
29
29
 
30
30
  it('locks customers events, acl, search, and notification surfaces', () => {
31
- // 50 since #5114 added `customers.person.company_assignment.detached` — the profile-only
32
- // sibling of the person_company_link CRUD events. Bump deliberately: this guard exists to
33
- // make an event-surface change visible, not to be silenced.
34
- expect(facts.events).toHaveLength(50)
31
+ expect(facts.events).toHaveLength(49)
35
32
  expect(facts.aclFeatures).toHaveLength(21)
36
33
  expect(facts.searchEntities).toEqual([
37
34
  'customers:customer_person_profile',
@@ -103,6 +103,6 @@ describe('module-facts extension host extraction', () => {
103
103
  ])
104
104
 
105
105
  const sales = extractModuleFacts({ moduleId: 'sales', coreSrcRoot })
106
- expect(sales.hostTokens.tableIds).toEqual(['sales.orders', 'sales.payments', 'sales.quotes'])
106
+ expect(sales.hostTokens.tableIds).toEqual(['sales.orders', 'sales.quotes'])
107
107
  })
108
108
  })
@@ -186,65 +186,65 @@ describe('generateModuleRegistry with module subsets', () => {
186
186
  expect(output).toContain('export default modules')
187
187
  })
188
188
 
189
- it('pins the exact emitted empty output format for the refactored registry files', async () => {
189
+ it('preserves exact legacy empty output format for the refactored registry files', async () => {
190
190
  const resolver = createMockResolver(tmpDir, [])
191
191
  const result = await generateModuleRegistry({ resolver, quiet: true })
192
192
 
193
193
  expect(result.errors).toEqual([])
194
194
  expect(readGenerated(tmpDir, 'modules.generated.ts')).toBe(dedent(`
195
195
  // AUTO-GENERATED by mercato generate registry
196
- import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from "@open-mercato/shared/modules/registry";
196
+ import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from '@open-mercato/shared/modules/registry'
197
197
 
198
- export const modules: Module[] = [];
199
-
200
- export default modules;
201
-
202
- export const modulesInfo = modules.map((m) => ({
203
- id: m.id,
204
- ...m.info || {}
205
- }));
198
+ export const modules: Module[] = [
199
+
200
+ ]
201
+ export const modulesInfo = modules.map(m => ({ id: m.id, ...(m.info || {}) }))
202
+ export default modules
206
203
  `))
207
204
  expect(readGenerated(tmpDir, 'modules.runtime.generated.ts')).toBe(dedent(`
208
205
  // AUTO-GENERATED by mercato generate registry
209
- import { createElement } from "react";
210
- import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from "@open-mercato/shared/modules/registry";
211
-
212
- export const modules: Module[] = [];
206
+ import { createElement } from 'react'
207
+ import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from '@open-mercato/shared/modules/registry'
213
208
 
214
- export default modules;
215
-
216
- export const modulesInfo = modules.map((m) => ({
217
- id: m.id,
218
- ...m.info || {}
219
- }));
209
+ export const modules: Module[] = [
210
+
211
+ ]
212
+ export const modulesInfo = modules.map(m => ({ id: m.id, ...(m.info || {}) }))
213
+ export default modules
220
214
  `))
221
215
  expect(readGenerated(tmpDir, 'frontend-routes.generated.ts')).toBe(dedent(`
222
216
  // AUTO-GENERATED by mercato generate registry
223
- import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
217
+ import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from '@open-mercato/shared/modules/registry'
224
218
 
225
- export const frontendRoutes: FrontendRouteManifestEntry[] = [];
219
+ export const frontendRoutes: FrontendRouteManifestEntry[] = [
220
+
221
+ ]
226
222
 
227
- export default frontendRoutes;
223
+ export default frontendRoutes
228
224
  `))
229
225
  expect(readGenerated(tmpDir, 'backend-routes.generated.ts')).toBe(dedent(`
230
226
  // AUTO-GENERATED by mercato generate registry
231
- import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
227
+ import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from '@open-mercato/shared/modules/registry'
232
228
 
233
- export const backendRoutes: BackendRouteManifestEntry[] = [];
229
+ export const backendRoutes: BackendRouteManifestEntry[] = [
230
+
231
+ ]
234
232
 
235
- export default backendRoutes;
233
+ export default backendRoutes
236
234
  `))
237
235
  expect(readGenerated(tmpDir, 'api-routes.generated.ts')).toBe(dedent(`
238
236
  // AUTO-GENERATED by mercato generate registry
239
- import type { ApiRouteManifestEntry } from "@open-mercato/shared/modules/registry";
237
+ import type { ApiRouteManifestEntry } from '@open-mercato/shared/modules/registry'
240
238
 
241
- export const apiRoutes: ApiRouteManifestEntry[] = [];
239
+ export const apiRoutes: ApiRouteManifestEntry[] = [
240
+
241
+ ]
242
242
 
243
- export default apiRoutes;
243
+ export default apiRoutes
244
244
  `))
245
245
  })
246
246
 
247
- it('pins the exact emitted populated output format for the refactored registry files', async () => {
247
+ it('preserves exact legacy populated output format for the refactored registry files', async () => {
248
248
  touchFile(
249
249
  path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'orders', 'index.ts'),
250
250
  "export const metadata = { id: 'orders', label: 'Orders' }\n",
@@ -267,99 +267,75 @@ describe('generateModuleRegistry with module subsets', () => {
267
267
 
268
268
  expect(result.errors).toEqual([])
269
269
  const modulesGenerated = readGenerated(tmpDir, 'modules.generated.ts')
270
- expect(modulesGenerated).toContain(`import { createElement } from "react"`)
270
+ expect(modulesGenerated).toContain(`import { createElement } from 'react'`)
271
271
  expect(modulesGenerated).toContain(`import * as I0_orders from "@open-mercato/core/modules/orders/index"`)
272
272
  expect(modulesGenerated).not.toContain(`import C1_orders_index`)
273
273
  expect(modulesGenerated).not.toContain(`import B5_orders_index`)
274
- expect(modulesGenerated).toMatch(/frontendRoutes:\s*\[\s*\{ pattern: "\/"/)
275
- expect(modulesGenerated).toMatch(/backendRoutes:\s*\[\s*\{ pattern: "\/backend\/orders"/)
274
+ expect(modulesGenerated).toContain(`frontendRoutes: [{ pattern: "/"`)
275
+ expect(modulesGenerated).toContain(`backendRoutes: [{ pattern: "/backend/orders"`)
276
276
  expect(modulesGenerated).toContain(`Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/frontend/page")`)
277
277
  expect(modulesGenerated).toContain(`Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/backend/page")`)
278
- expect(modulesGenerated).toMatch(/apis:\s*\[\s*\{ path: \(\(R9_orders_orders as any\)\.metadata\?\.path/)
279
- expect(modulesGenerated).toContain(`{ path: ((R9_orders_orders as any).metadata?.path ?? "/orders/orders"), metadata: (R9_orders_orders as any).metadata, handlers: R9_orders_orders as any }`)
278
+ expect(modulesGenerated).toContain(`apis: [{ path: ((R9_orders_orders as any).metadata?.path ?? "/orders/orders"), metadata: (R9_orders_orders as any).metadata, handlers: R9_orders_orders as any }]`)
280
279
  expect(readGenerated(tmpDir, 'modules.runtime.generated.ts')).toBe(dedent(`
281
280
  // AUTO-GENERATED by mercato generate registry
282
- import { createElement } from "react";
283
- import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from "@open-mercato/shared/modules/registry";
284
- import * as I0_orders from "@open-mercato/core/modules/orders/index";
285
- import * as MRuntime3_orders_index from "@open-mercato/core/modules/orders/frontend/page";
286
- import * as BMRuntime7_orders_index from "@open-mercato/core/modules/orders/backend/page";
281
+ import { createElement } from 'react'
282
+ import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from '@open-mercato/shared/modules/registry'
283
+ import * as I0_orders from "@open-mercato/core/modules/orders/index"
284
+ import * as MRuntime3_orders_index from "@open-mercato/core/modules/orders/frontend/page"
285
+ import * as BMRuntime7_orders_index from "@open-mercato/core/modules/orders/backend/page"
287
286
 
288
287
  export const modules: Module[] = [
289
- {
288
+ {
290
289
  id: "orders",
291
290
  info: I0_orders.metadata,
292
- frontendRoutes: [
293
- { pattern: "/", requireAuth: ((((MRuntime3_orders_index as any).metadata) as any))?.requireAuth, requireRoles: ((((MRuntime3_orders_index as any).metadata) as any))?.requireRoles, requireFeatures: ((((MRuntime3_orders_index as any).metadata) as any))?.requireFeatures, requireCustomerAuth: ((((MRuntime3_orders_index as any).metadata) as any))?.requireCustomerAuth, requireCustomerFeatures: ((((MRuntime3_orders_index as any).metadata) as any))?.requireCustomerFeatures, nav: ((((MRuntime3_orders_index as any).metadata) as any))?.nav, title: ((((MRuntime3_orders_index as any).metadata) as any))?.pageTitle ?? ((((MRuntime3_orders_index as any).metadata) as any))?.title, titleKey: ((((MRuntime3_orders_index as any).metadata) as any))?.pageTitleKey ?? ((((MRuntime3_orders_index as any).metadata) as any))?.titleKey, group: ((((MRuntime3_orders_index as any).metadata) as any))?.pageGroup ?? ((((MRuntime3_orders_index as any).metadata) as any))?.group, groupKey: ((((MRuntime3_orders_index as any).metadata) as any))?.pageGroupKey ?? ((((MRuntime3_orders_index as any).metadata) as any))?.groupKey, icon: ((((MRuntime3_orders_index as any).metadata) as any))?.icon, order: ((((MRuntime3_orders_index as any).metadata) as any))?.pageOrder ?? ((((MRuntime3_orders_index as any).metadata) as any))?.order, priority: ((((MRuntime3_orders_index as any).metadata) as any))?.pagePriority ?? ((((MRuntime3_orders_index as any).metadata) as any))?.priority, navHidden: ((((MRuntime3_orders_index as any).metadata) as any))?.navHidden, visible: ((((MRuntime3_orders_index as any).metadata) as any))?.visible, enabled: ((((MRuntime3_orders_index as any).metadata) as any))?.enabled, breadcrumb: ((((MRuntime3_orders_index as any).metadata) as any))?.breadcrumb, pageContext: ((((MRuntime3_orders_index as any).metadata) as any))?.pageContext, placement: ((((MRuntime3_orders_index as any).metadata) as any))?.placement, Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/frontend/page"); const Component = (mod.default ?? mod) as any; return createElement(Component, props) } }
294
- ],
295
- backendRoutes: [
296
- { pattern: "/backend/orders", requireAuth: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireAuth, requireRoles: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireRoles, requireFeatures: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireFeatures, requireCustomerAuth: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireCustomerAuth, requireCustomerFeatures: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireCustomerFeatures, nav: ((((BMRuntime7_orders_index as any).metadata) as any))?.nav, title: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageTitle ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.title, titleKey: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageTitleKey ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.titleKey, group: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageGroup ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.group, groupKey: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageGroupKey ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.groupKey, icon: ((((BMRuntime7_orders_index as any).metadata) as any))?.icon, order: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageOrder ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.order, priority: ((((BMRuntime7_orders_index as any).metadata) as any))?.pagePriority ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.priority, navHidden: ((((BMRuntime7_orders_index as any).metadata) as any))?.navHidden, visible: ((((BMRuntime7_orders_index as any).metadata) as any))?.visible, enabled: ((((BMRuntime7_orders_index as any).metadata) as any))?.enabled, breadcrumb: ((((BMRuntime7_orders_index as any).metadata) as any))?.breadcrumb, pageContext: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageContext, placement: ((((BMRuntime7_orders_index as any).metadata) as any))?.placement, Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/backend/page"); const Component = (mod.default ?? mod) as any; return createElement(Component, props) } }
297
- ],
298
- apis: [
299
- { path: "/orders/orders", metadata: undefined, handlers: { GET: async (req: Request, ctx?: any) => { const mod = await import("@open-mercato/core/modules/orders/api/orders/route"); return (mod as any).GET(req, ctx) } } }
300
- ],
301
- customFieldSets: []
291
+ frontendRoutes: [{ pattern: "/", requireAuth: ((((MRuntime3_orders_index as any).metadata) as any))?.requireAuth, requireRoles: ((((MRuntime3_orders_index as any).metadata) as any))?.requireRoles, requireFeatures: ((((MRuntime3_orders_index as any).metadata) as any))?.requireFeatures, requireCustomerAuth: ((((MRuntime3_orders_index as any).metadata) as any))?.requireCustomerAuth, requireCustomerFeatures: ((((MRuntime3_orders_index as any).metadata) as any))?.requireCustomerFeatures, nav: ((((MRuntime3_orders_index as any).metadata) as any))?.nav, title: ((((MRuntime3_orders_index as any).metadata) as any))?.pageTitle ?? ((((MRuntime3_orders_index as any).metadata) as any))?.title, titleKey: ((((MRuntime3_orders_index as any).metadata) as any))?.pageTitleKey ?? ((((MRuntime3_orders_index as any).metadata) as any))?.titleKey, group: ((((MRuntime3_orders_index as any).metadata) as any))?.pageGroup ?? ((((MRuntime3_orders_index as any).metadata) as any))?.group, groupKey: ((((MRuntime3_orders_index as any).metadata) as any))?.pageGroupKey ?? ((((MRuntime3_orders_index as any).metadata) as any))?.groupKey, icon: ((((MRuntime3_orders_index as any).metadata) as any))?.icon, order: ((((MRuntime3_orders_index as any).metadata) as any))?.pageOrder ?? ((((MRuntime3_orders_index as any).metadata) as any))?.order, priority: ((((MRuntime3_orders_index as any).metadata) as any))?.pagePriority ?? ((((MRuntime3_orders_index as any).metadata) as any))?.priority, navHidden: ((((MRuntime3_orders_index as any).metadata) as any))?.navHidden, visible: ((((MRuntime3_orders_index as any).metadata) as any))?.visible, enabled: ((((MRuntime3_orders_index as any).metadata) as any))?.enabled, breadcrumb: ((((MRuntime3_orders_index as any).metadata) as any))?.breadcrumb, pageContext: ((((MRuntime3_orders_index as any).metadata) as any))?.pageContext, placement: ((((MRuntime3_orders_index as any).metadata) as any))?.placement, Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/frontend/page"); const Component = (mod.default ?? mod) as any; return createElement(Component, props) } }],
292
+ backendRoutes: [{ pattern: "/backend/orders", requireAuth: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireAuth, requireRoles: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireRoles, requireFeatures: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireFeatures, requireCustomerAuth: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireCustomerAuth, requireCustomerFeatures: ((((BMRuntime7_orders_index as any).metadata) as any))?.requireCustomerFeatures, nav: ((((BMRuntime7_orders_index as any).metadata) as any))?.nav, title: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageTitle ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.title, titleKey: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageTitleKey ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.titleKey, group: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageGroup ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.group, groupKey: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageGroupKey ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.groupKey, icon: ((((BMRuntime7_orders_index as any).metadata) as any))?.icon, order: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageOrder ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.order, priority: ((((BMRuntime7_orders_index as any).metadata) as any))?.pagePriority ?? ((((BMRuntime7_orders_index as any).metadata) as any))?.priority, navHidden: ((((BMRuntime7_orders_index as any).metadata) as any))?.navHidden, visible: ((((BMRuntime7_orders_index as any).metadata) as any))?.visible, enabled: ((((BMRuntime7_orders_index as any).metadata) as any))?.enabled, breadcrumb: ((((BMRuntime7_orders_index as any).metadata) as any))?.breadcrumb, pageContext: ((((BMRuntime7_orders_index as any).metadata) as any))?.pageContext, placement: ((((BMRuntime7_orders_index as any).metadata) as any))?.placement, Component: async (props: any) => { const mod = await import("@open-mercato/core/modules/orders/backend/page"); const Component = (mod.default ?? mod) as any; return createElement(Component, props) } }],
293
+ apis: [{ path: "/orders/orders", metadata: undefined, handlers: { GET: async (req: Request, ctx?: any) => { const mod = await import("@open-mercato/core/modules/orders/api/orders/route"); return (mod as any).GET(req, ctx) } } }],
294
+
295
+
296
+
297
+
298
+ customFieldSets: [],
299
+
300
+
301
+
302
+
303
+
304
+
302
305
  }
303
- ];
304
-
305
- export default modules;
306
-
307
- export const modulesInfo = modules.map((m) => ({
308
- id: m.id,
309
- ...m.info || {}
310
- }));
306
+ ]
307
+ export const modulesInfo = modules.map(m => ({ id: m.id, ...(m.info || {}) }))
308
+ export default modules
311
309
  `))
312
310
  expect(readGenerated(tmpDir, 'frontend-routes.generated.ts')).toBe(dedent(`
313
311
  // AUTO-GENERATED by mercato generate registry
314
- import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
312
+ import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from '@open-mercato/shared/modules/registry'
315
313
 
316
314
  export const frontendRoutes: FrontendRouteManifestEntry[] = [
317
- {
318
- moduleId: "orders",
319
- ...resolvePageRouteMetadata("/", (undefined as any)),
320
- load: async () => {
321
- const mod = await import("@open-mercato/core/modules/orders/frontend/page");
322
- return ((mod.default ?? mod) as any);
323
- }
324
- }
325
- ];
315
+ { moduleId: "orders", ...resolvePageRouteMetadata("/", (undefined as any)), load: async () => { const mod = await import("@open-mercato/core/modules/orders/frontend/page"); return (mod.default ?? mod) as any } }
316
+ ]
326
317
 
327
- export default frontendRoutes;
318
+ export default frontendRoutes
328
319
  `))
329
320
  expect(readGenerated(tmpDir, 'backend-routes.generated.ts')).toBe(dedent(`
330
321
  // AUTO-GENERATED by mercato generate registry
331
- import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
322
+ import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from '@open-mercato/shared/modules/registry'
332
323
 
333
324
  export const backendRoutes: BackendRouteManifestEntry[] = [
334
- {
335
- moduleId: "orders",
336
- ...resolvePageRouteMetadata("/backend/orders", (undefined as any)),
337
- load: async () => {
338
- const mod = await import("@open-mercato/core/modules/orders/backend/page");
339
- return ((mod.default ?? mod) as any);
340
- }
341
- }
342
- ];
325
+ { moduleId: "orders", ...resolvePageRouteMetadata("/backend/orders", (undefined as any)), load: async () => { const mod = await import("@open-mercato/core/modules/orders/backend/page"); return (mod.default ?? mod) as any } }
326
+ ]
343
327
 
344
- export default backendRoutes;
328
+ export default backendRoutes
345
329
  `))
346
330
  expect(readGenerated(tmpDir, 'api-routes.generated.ts')).toBe(dedent(`
347
331
  // AUTO-GENERATED by mercato generate registry
348
- import type { ApiRouteManifestEntry } from "@open-mercato/shared/modules/registry";
332
+ import type { ApiRouteManifestEntry } from '@open-mercato/shared/modules/registry'
349
333
 
350
334
  export const apiRoutes: ApiRouteManifestEntry[] = [
351
- {
352
- moduleId: "orders",
353
- kind: "route-file",
354
- path: "/orders/orders",
355
- methods: [
356
- "GET"
357
- ],
358
- load: async () => import("@open-mercato/core/modules/orders/api/orders/route")
359
- }
360
- ];
335
+ { moduleId: "orders", kind: "route-file", path: "/orders/orders", methods: ["GET"], load: async () => import("@open-mercato/core/modules/orders/api/orders/route") }
336
+ ]
361
337
 
362
- export default apiRoutes;
338
+ export default apiRoutes
363
339
  `))
364
340
  })
365
341
 
@@ -599,7 +575,7 @@ export { POST, PUT, DELETE }
599
575
  expect(result.errors).toEqual([])
600
576
  const apiRoutes = readGenerated(tmpDir, 'api-routes.generated.ts')!
601
577
  expect(apiRoutes).toContain('path: "/customers/people"')
602
- expect(apiRoutes).toMatch(/methods:\s*\[[\s\S]*?"GET",[\s\S]*?"POST",[\s\S]*?"PUT",[\s\S]*?"DELETE"[\s\S]*?\]/)
578
+ expect(apiRoutes).toContain('methods: ["GET", "POST", "PUT", "DELETE"]')
603
579
  })
604
580
 
605
581
  it('partitions API and backend loader graphs while preserving legacy manifests', async () => {
@@ -684,7 +660,7 @@ export const { metadata, GET, POST, PUT, DELETE } = crud
684
660
  expect(result.errors).toEqual([])
685
661
  const apiRoutes = readGenerated(tmpDir, 'api-routes.generated.ts')!
686
662
  expect(apiRoutes).toContain('path: "/example/todos"')
687
- expect(apiRoutes).toMatch(/methods:\s*\[[\s\S]*?"GET",[\s\S]*?"POST",[\s\S]*?"PUT",[\s\S]*?"DELETE"[\s\S]*?\]/)
663
+ expect(apiRoutes).toContain('methods: ["GET", "POST", "PUT", "DELETE"]')
688
664
  })
689
665
 
690
666
  it('uses metadata.path in api route manifests when source import fails during generation', async () => {
@@ -1071,7 +1047,7 @@ export function GET() {
1071
1047
  )
1072
1048
 
1073
1049
  expect(output).toContain('@open-mercato/core/modules/customers/i18n/en.json')
1074
- expect(output).toMatch(/['"]en['"]:/)
1050
+ expect(output).toContain(`'en':`)
1075
1051
  })
1076
1052
  })
1077
1053
 
@@ -832,7 +832,7 @@ describe('generator output compatibility', () => {
832
832
  expect(content).toContain(`import { backendRouteFacades } from "./backend-route-shards.generated"`)
833
833
  expect(content).toContain(`import { frontendRoutes } from "./frontend-routes.generated"`)
834
834
  expect(content).toContain(
835
- `import { registerBackendRouteManifests, registerFrontendRouteManifests } from "@open-mercato/shared/modules/registry"`,
835
+ `import { registerBackendRouteManifests, registerFrontendRouteManifests } from '@open-mercato/shared/modules/registry'`,
836
836
  )
837
837
  expect(content).toMatch(/export function runBootstrapRegistrations\(\): void \{[\s\S]*registerBackendRouteManifests\(backendRouteFacades\)[\s\S]*\}/)
838
838
  expect(content).toMatch(/export function runBootstrapRegistrations\(\): void \{[\s\S]*registerFrontendRouteManifests\(frontendRoutes\)[\s\S]*\}/)
@@ -47,21 +47,6 @@ describe('route manifest shards', () => {
47
47
  expect(loader).toContain(`const ROUTE_SHARD_KEYS = ["customers","__dynamic","customers","__root"]`)
48
48
  })
49
49
 
50
- it('indents every line of a multi-line declaration inside the shard array', () => {
51
- const declaration = ['{', ' moduleId: "customers",', ' path: "/customers"', '} as any'].join('\n')
52
- const outputs = renderRouteManifestShardOutputs('api', [{ path: '/customers', declaration }])
53
- const shard = outputs.find((entry) => entry.fileName.includes('route-shard.'))?.content ?? ''
54
-
55
- expect(shard).toContain([
56
- 'export const routes: ApiRouteManifestEntry[] = [',
57
- ' {',
58
- ' moduleId: "customers",',
59
- ' path: "/customers"',
60
- ' } as any',
61
- ']',
62
- ].join('\n'))
63
- })
64
-
65
50
  it('renders metadata without load functions while retaining metadata imports', () => {
66
51
  const output = renderRouteMetadataOutput('backend', [{
67
52
  path: '/backend/settings',
@@ -186,7 +186,6 @@ function scaffoldFixture(): ModuleEntry[] {
186
186
  touchFile(pkgModulePath('orders', 'subscribers', 'on-created.ts'), "export const metadata = { event: 'orders.order.created', persistent: true }\nexport default async function handler() {}\n")
187
187
  touchFile(pkgModulePath('orders', 'subscribers', 'on-payment.ts'), "export const metadata = { event: 'payments.payment.completed', persistent: true }\nexport default async function handler() {}\n")
188
188
  touchFile(pkgModulePath('orders', 'workers', 'sync-job.ts'), "export const metadata = { queue: 'orders.sync', concurrency: 2 }\nexport default async function handler() {}\n")
189
- touchFile(pkgModulePath('orders', 'workers', 'safe-job.ts'), "export const metadata = { queue: 'orders.safe', schedulerSafe: true }\nexport default async function handler() {}\n")
190
189
  touchFile(pkgModulePath('orders', 'widgets', 'dashboard', 'revenue', 'widget.tsx'), 'export default function RevenueWidget() { return null }\n')
191
190
  touchFile(pkgModulePath('orders', 'widgets', 'injection', 'sidebar', 'widget.tsx'), 'export default function SidebarWidget() { return null }\n')
192
191
  touchFile(pkgModulePath('orders', 'widgets', 'injection-table.ts'), `export const injectionTable = {\n 'crud-form:orders:sales_order:fields': [{ widgetId: 'orders.sidebar', kind: 'section', priority: 50 }],\n}\nexport default injectionTable\n`)
@@ -508,8 +507,8 @@ describe('modules.generated.ts', () => {
508
507
  })
509
508
 
510
509
  it('modules include translation locale keys', () => {
511
- expect(content).toMatch(/['"]en['"]:/)
512
- expect(content).toMatch(/['"]pl['"]:/)
510
+ expect(content).toContain("'en':")
511
+ expect(content).toContain("'pl':")
513
512
  })
514
513
 
515
514
  it('modules include customFieldSets reference from ce.ts', () => {
@@ -636,7 +635,7 @@ describe('api-routes.generated.ts', () => {
636
635
 
637
636
  it('products API route has all 4 methods', () => {
638
637
  expect(content).toContain('path: "/products"')
639
- expect(content).toMatch(/methods:\s*\[\s*"GET",\s*"POST",\s*"PUT",\s*"DELETE",?\s*\]/)
638
+ expect(content).toMatch(/methods:.*GET.*POST.*PUT.*DELETE/)
640
639
  })
641
640
 
642
641
  it('keeps API handler imports lazy in route entries', () => {
@@ -1266,9 +1265,6 @@ describe('modules.bootstrap.generated.ts', () => {
1266
1265
  expect(content).toContain('orders.order.created')
1267
1266
  expect(content).toContain('setup:')
1268
1267
  expect(content).toContain('features:')
1269
- // worker metadata flags must survive into the registry the server registers
1270
- expect(content).toContain("queue: \"orders.safe\"")
1271
- expect(content).toContain('schedulerSafe: true')
1272
1268
 
1273
1269
  expect(content).not.toContain('frontendRoutes:')
1274
1270
  expect(content).not.toContain('backendRoutes:')
@@ -1,5 +1,5 @@
1
1
  export { addImportSpec, addImportSpecs, addImportStatement, addImportStatements, type GeneratedImportSpec } from './imports'
2
- export { addAutoGeneratedComment, createGeneratedSourceFile, getSourceText, renderGeneratedValue } from './source-file'
2
+ export { addAutoGeneratedComment, createGeneratedSourceFile, getSourceText } from './source-file'
3
3
  export {
4
4
  arrayLiteral,
5
5
  assignmentStatement,
@@ -11,7 +11,6 @@ export {
11
11
  callExpression,
12
12
  conditionalExpression,
13
13
  elementAccess,
14
- escapeGeneratedJsonLiteral,
15
14
  expressionStatement,
16
15
  forOfStatement,
17
16
  identifier,
@@ -1,5 +1,4 @@
1
1
  import { IndentationText, Project, type SourceFile } from 'ts-morph'
2
- import { writeValue, type GeneratedValue } from './writers'
3
2
 
4
3
  let sharedProject: Project | null = null
5
4
 
@@ -27,18 +26,6 @@ export function createGeneratedSourceFile(fileName: string): SourceFile {
27
26
  return project.createSourceFile(fileName, '', { overwrite: true })
28
27
  }
29
28
 
30
- /**
31
- * Renders a single generated value to source text, outside of any source file. Generators
32
- * that hand a pre-rendered expression to a consumer expecting a string (route manifest
33
- * shards) use this instead of concatenating the expression by hand, so the AST writers stay
34
- * the one place an expression is constructed.
35
- */
36
- export function renderGeneratedValue(value: GeneratedValue): string {
37
- const writer = getProject().createWriter()
38
- writeValue(writer, value)
39
- return writer.toString()
40
- }
41
-
42
29
  export function addAutoGeneratedComment(sourceFile: SourceFile, generator: string): void {
43
30
  sourceFile.insertText(0, `// AUTO-GENERATED by mercato generate ${generator}\n`)
44
31
  }
@@ -22,31 +22,6 @@ export interface SpreadPropertyWriter {
22
22
  export type GeneratedObjectEntry = ObjectPropertyWriter | SpreadPropertyWriter
23
23
  export type StatementWriter = WriterFunction
24
24
 
25
- /**
26
- * Escapes the characters that are legal inside a JSON string but hazardous inside a
27
- * generated JavaScript source file: `<` and `>` so an emitted value can never close a
28
- * surrounding script context, and U+2028 / U+2029 which older JavaScript parsers reject
29
- * inside a string literal. The escape sequences denote the same runtime string, so this
30
- * only ever changes the emitted text, never the emitted value.
31
- */
32
- export function escapeGeneratedJsonLiteral(json: string): string {
33
- return json
34
- .replace(/</g, '\\u003c')
35
- .replace(/>/g, '\\u003e')
36
- .replace(/\u2028/g, '\\u2028')
37
- .replace(/\u2029/g, '\\u2029')
38
- }
39
-
40
- /**
41
- * The single point where a string value becomes source text on the AST path. The string
42
- * paths that are still emitted as templates share the escaping step above rather than
43
- * this function, because they also serialize objects, whose nested strings need the same
44
- * hardening.
45
- */
46
- export function stringLiteral(value: string): string {
47
- return escapeGeneratedJsonLiteral(JSON.stringify(value))
48
- }
49
-
50
25
  export function writeLiteral(writer: CodeBlockWriter, value: Exclude<GeneratedValue, WriterFunction>): void {
51
26
  if (value === undefined) {
52
27
  writer.write('undefined')
@@ -59,7 +34,7 @@ export function writeLiteral(writer: CodeBlockWriter, value: Exclude<GeneratedVa
59
34
  }
60
35
 
61
36
  if (typeof value === 'string') {
62
- writer.write(stringLiteral(value))
37
+ writer.write(JSON.stringify(value))
63
38
  return
64
39
  }
65
40