@open-mercato/cli 0.7.0 → 0.7.1-develop.7103.1.41ff100d93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -1
- package/dist/agentic/guides/module-facts.json +5509 -599
- package/dist/agentic/guides/module-facts.v2.json +5595 -599
- package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/di-registrations-rich.md +11 -0
- package/dist/agentic/guides/modules/api_keys/di-service-tokens.md +11 -0
- package/dist/agentic/guides/modules/api_keys/exact-override-targets.md +1 -0
- package/dist/agentic/guides/modules/api_keys/index.md +4 -2
- package/dist/agentic/guides/modules/attachments/di-registrations-rich.md +6 -5
- package/dist/agentic/guides/modules/attachments/di-service-tokens.md +5 -4
- package/dist/agentic/guides/modules/attachments/exact-override-targets.md +6 -5
- package/dist/agentic/guides/modules/attachments/index.md +2 -2
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/di-registrations-rich.md +3 -2
- package/dist/agentic/guides/modules/auth/di-service-tokens.md +3 -2
- package/dist/agentic/guides/modules/auth/exact-override-targets.md +3 -2
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/incoming-installed-contributions.md +3 -0
- package/dist/agentic/guides/modules/catalog/index.md +2 -2
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_discord/acl-features.md +13 -0
- package/dist/agentic/guides/modules/channel_discord/ai-agents.md +11 -0
- package/dist/agentic/guides/modules/channel_discord/backend-pages.md +11 -0
- package/dist/agentic/guides/modules/channel_discord/cli-commands.md +13 -0
- package/dist/agentic/guides/modules/channel_discord/contribution-resolutions.md +14 -0
- package/dist/agentic/guides/modules/channel_discord/di-registrations-rich.md +12 -0
- package/dist/agentic/guides/modules/channel_discord/exact-override-targets.md +26 -0
- package/dist/agentic/guides/modules/channel_discord/index.md +22 -0
- package/dist/agentic/guides/modules/channel_discord/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/channel_discord/setup.md +11 -0
- package/dist/agentic/guides/modules/channel_discord/umes-contributions.md +14 -0
- package/dist/agentic/guides/modules/channel_discord/workers.md +12 -0
- package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
- package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
- package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/di-registrations-rich.md +9 -8
- package/dist/agentic/guides/modules/communication_channels/exact-override-targets.md +9 -8
- package/dist/agentic/guides/modules/communication_channels/incoming-installed-contributions.md +2 -0
- package/dist/agentic/guides/modules/communication_channels/index.md +3 -3
- package/dist/agentic/guides/modules/configs/index.md +1 -1
- package/dist/agentic/guides/modules/content/index.md +1 -1
- package/dist/agentic/guides/modules/currencies/index.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
- package/dist/agentic/guides/modules/customers/active-extension-bindings.md +6 -3
- package/dist/agentic/guides/modules/customers/contribution-resolutions.md +1 -0
- package/dist/agentic/guides/modules/customers/events.md +2 -1
- package/dist/agentic/guides/modules/customers/incoming-installed-contributions.md +7 -0
- package/dist/agentic/guides/modules/customers/index.md +4 -4
- package/dist/agentic/guides/modules/customers/umes-contributions.md +1 -0
- package/dist/agentic/guides/modules/customers/umes-hosts.md +1 -0
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/exact-override-targets.md +2 -2
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/workers.md +2 -2
- package/dist/agentic/guides/modules/design_system/index.md +1 -1
- package/dist/agentic/guides/modules/devices/index.md +1 -1
- package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
- package/dist/agentic/guides/modules/directory/di-registrations-rich.md +12 -0
- package/dist/agentic/guides/modules/directory/di-service-tokens.md +12 -0
- package/dist/agentic/guides/modules/directory/exact-override-targets.md +2 -0
- package/dist/agentic/guides/modules/directory/index.md +5 -3
- package/dist/agentic/guides/modules/documents/acl-features.md +17 -0
- package/dist/agentic/guides/modules/documents/backend-pages.md +13 -0
- package/dist/agentic/guides/modules/documents/contribution-resolutions.md +27 -0
- package/dist/agentic/guides/modules/documents/di-registrations-rich.md +21 -0
- package/dist/agentic/guides/modules/documents/domain-commands.md +37 -0
- package/dist/agentic/guides/modules/documents/encryption.md +11 -0
- package/dist/agentic/guides/modules/documents/entities.md +21 -0
- package/dist/agentic/guides/modules/documents/events.md +25 -0
- package/dist/agentic/guides/modules/documents/exact-override-targets.md +39 -0
- package/dist/agentic/guides/modules/documents/index.md +25 -0
- package/dist/agentic/guides/modules/documents/notifications.md +13 -0
- package/dist/agentic/guides/modules/documents/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/documents/setup.md +11 -0
- package/dist/agentic/guides/modules/documents/umes-contributions.md +27 -0
- package/dist/agentic/guides/modules/documents/umes-hosts.md +36 -0
- package/dist/agentic/guides/modules/entities/index.md +1 -1
- package/dist/agentic/guides/modules/eudr/index.md +1 -1
- package/dist/agentic/guides/modules/events/index.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/exact-override-targets.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/workers.md +1 -1
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/index.md +1 -1
- package/dist/agentic/guides/modules/messages/index.md +1 -1
- package/dist/agentic/guides/modules/notifications/index.md +1 -1
- package/dist/agentic/guides/modules/onboarding/index.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
- package/dist/agentic/guides/modules/perspectives/index.md +1 -1
- package/dist/agentic/guides/modules/planner/index.md +1 -1
- package/dist/agentic/guides/modules/portal/index.md +1 -1
- package/dist/agentic/guides/modules/progress/index.md +1 -1
- package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
- package/dist/agentic/guides/modules/query_index/index.md +1 -1
- package/dist/agentic/guides/modules/record_locks/index.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/active-extension-bindings.md +1 -0
- package/dist/agentic/guides/modules/sales/contribution-resolutions.md +1 -0
- package/dist/agentic/guides/modules/sales/exact-override-targets.md +5 -4
- package/dist/agentic/guides/modules/sales/host-extension-points.md +1 -1
- package/dist/agentic/guides/modules/sales/incoming-installed-contributions.md +2 -0
- package/dist/agentic/guides/modules/sales/index.md +3 -3
- package/dist/agentic/guides/modules/sales/setup.md +1 -1
- package/dist/agentic/guides/modules/sales/umes-contributions.md +1 -0
- package/dist/agentic/guides/modules/sales/umes-diagnostics.md +1 -0
- package/dist/agentic/guides/modules/sales/umes-hosts.md +9 -0
- package/dist/agentic/guides/modules/scheduler/cli-commands.md +1 -0
- package/dist/agentic/guides/modules/scheduler/exact-override-targets.md +3 -1
- package/dist/agentic/guides/modules/scheduler/index.md +2 -2
- package/dist/agentic/guides/modules/scheduler/workers.md +2 -1
- package/dist/agentic/guides/modules/search/index.md +1 -1
- package/dist/agentic/guides/modules/security/index.md +1 -1
- package/dist/agentic/guides/modules/security/owned-contract-module-metadata.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
- package/dist/agentic/guides/modules/sso/index.md +1 -1
- package/dist/agentic/guides/modules/staff/index.md +1 -1
- package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
- package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/translations/index.md +1 -1
- package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
- package/dist/agentic/guides/modules/webhooks/index.md +1 -1
- package/dist/agentic/guides/modules/wms/index.md +1 -1
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +2 -2
- package/dist/agentic/guides/reference-modules/example/index.md +1 -1
- package/dist/agentic/guides/upstream/manifest.json +1 -1
- package/dist/agentic/shared/AGENTS.md.template +3 -3
- package/dist/agentic/shared/ai/harness/README.md +2 -2
- package/dist/agentic/shared/ai/harness/RELEASE.md +8 -6
- package/dist/agentic/shared/ai/harness/cases.json +83 -0
- package/dist/agentic/shared/ai/harness/cases.schema.json +4 -4
- package/dist/agentic/shared/ai/harness/validators.json +1 -1
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +37 -11
- package/dist/lib/generators/ast/index.js +4 -1
- package/dist/lib/generators/ast/index.js.map +2 -2
- package/dist/lib/generators/ast/source-file.js +8 -1
- package/dist/lib/generators/ast/source-file.js.map +2 -2
- package/dist/lib/generators/ast/writers.js +9 -1
- package/dist/lib/generators/ast/writers.js.map +2 -2
- package/dist/lib/generators/module-registry.js +424 -189
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/route-manifest-shards.js +4 -1
- package/dist/lib/generators/route-manifest-shards.js.map +2 -2
- package/dist/lib/spawn.js +3 -2
- package/dist/lib/spawn.js.map +2 -2
- package/dist/lib/testing/integration.js +162 -24
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +14 -0
- package/dist/mercato.js.map +2 -2
- package/package.json +8 -7
- package/src/__tests__/resolve-queue-abandon-hook.test.ts +39 -0
- package/src/lib/__tests__/spawn.test.ts +23 -0
- package/src/lib/generators/__tests__/__snapshots__/bootstrap-registrations.test.ts.snap +14 -0
- package/src/lib/generators/__tests__/__snapshots__/command-loaders.test.ts.snap +23 -0
- package/src/lib/generators/__tests__/ast-writers-escaping.test.ts +64 -0
- package/src/lib/generators/__tests__/bootstrap-registrations.test.ts +176 -0
- package/src/lib/generators/__tests__/command-loaders.test.ts +239 -0
- package/src/lib/generators/__tests__/generated-registry-imports.test.ts +128 -0
- package/src/lib/generators/__tests__/metadata-extraction.test.ts +44 -0
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +32 -8
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +4 -1
- package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +1 -1
- package/src/lib/generators/__tests__/module-subset.test.ts +96 -72
- package/src/lib/generators/__tests__/output-snapshots.test.ts +1 -1
- package/src/lib/generators/__tests__/registry-variant-parity.test.ts +258 -0
- package/src/lib/generators/__tests__/route-manifest-shards.test.ts +15 -0
- package/src/lib/generators/__tests__/structural-contracts.test.ts +7 -3
- package/src/lib/generators/ast/index.ts +2 -1
- package/src/lib/generators/ast/source-file.ts +13 -0
- package/src/lib/generators/ast/writers.ts +26 -1
- package/src/lib/generators/module-registry.ts +534 -227
- package/src/lib/generators/route-manifest-shards.ts +8 -1
- package/src/lib/spawn.ts +5 -4
- package/src/lib/testing/__tests__/integration.test.ts +435 -0
- package/src/lib/testing/integration.ts +254 -32
- package/src/mercato.ts +27 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import type { PackageResolver, ModuleEntry } from '../../resolver'
|
|
5
|
+
import { generateModuleRegistry, generateModuleRegistryApp, generateModuleRegistryCli } from '../module-registry'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The generator's output, not its helpers.
|
|
9
|
+
*
|
|
10
|
+
* A worker declaring `metadata.onJobAbandoned` makes the registry emit
|
|
11
|
+
* `createLazyModuleWorkerAbandonHook(...)`, and the import for it used to be opted into per render
|
|
12
|
+
* site. Forgetting it at one of the six sites produced a file referencing an undeclared name, which
|
|
13
|
+
* type-checks nowhere and surfaces only at `build:app` — every unit test stayed green because no
|
|
14
|
+
* fixture declared such a worker.
|
|
15
|
+
*
|
|
16
|
+
* These assertions are driven off the files the generators actually wrote, so a renderer added later
|
|
17
|
+
* is covered without anyone remembering to extend this test.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
let tmpDir: string
|
|
21
|
+
|
|
22
|
+
function touchFile(filePath: string, content = ''): void {
|
|
23
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
24
|
+
fs.writeFileSync(filePath, content)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createMockResolver(dir: string, enabled: ModuleEntry[]): PackageResolver {
|
|
28
|
+
const outputDir = path.join(dir, 'output', 'generated')
|
|
29
|
+
fs.mkdirSync(outputDir, { recursive: true })
|
|
30
|
+
return {
|
|
31
|
+
isMonorepo: () => true,
|
|
32
|
+
getRootDir: () => dir,
|
|
33
|
+
getAppDir: () => path.join(dir, 'app'),
|
|
34
|
+
getOutputDir: () => outputDir,
|
|
35
|
+
getModulesConfigPath: () => path.join(dir, 'app', 'src', 'modules.ts'),
|
|
36
|
+
discoverPackages: () => [],
|
|
37
|
+
loadEnabledModules: () => enabled,
|
|
38
|
+
getModulePaths: (entry: ModuleEntry) => ({
|
|
39
|
+
appBase: path.join(dir, 'app', 'src', 'modules', entry.id),
|
|
40
|
+
pkgBase: path.join(dir, 'packages', 'core', 'src', 'modules', entry.id),
|
|
41
|
+
}),
|
|
42
|
+
getModuleImportBase: (entry: ModuleEntry) => ({
|
|
43
|
+
appBase: `@/modules/${entry.id}`,
|
|
44
|
+
pkgBase: `@open-mercato/core/modules/${entry.id}`,
|
|
45
|
+
}),
|
|
46
|
+
getPackageOutputDir: () => outputDir,
|
|
47
|
+
getPackageRoot: () => path.join(dir, 'packages', 'core'),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scaffoldWorkerModule(dir: string, modId: string, workerSource: string): void {
|
|
52
|
+
touchFile(path.join(dir, 'packages', 'core', 'src', 'modules', modId, 'workers', 'sync.ts'), workerSource)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function generatedFiles(dir: string): Array<{ name: string; content: string }> {
|
|
56
|
+
const outputDir = path.join(dir, 'output', 'generated')
|
|
57
|
+
if (!fs.existsSync(outputDir)) return []
|
|
58
|
+
return fs.readdirSync(outputDir)
|
|
59
|
+
.filter((name) => name.endsWith('.ts'))
|
|
60
|
+
.map((name) => ({ name, content: fs.readFileSync(path.join(outputDir, name), 'utf8') }))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ABANDON_HOOK_FACTORY = 'createLazyModuleWorkerAbandonHook'
|
|
64
|
+
|
|
65
|
+
const WORKER_WITH_HOOK = `
|
|
66
|
+
import { failAbandonedRun } from '../lib/abandoned-run'
|
|
67
|
+
export const metadata = {
|
|
68
|
+
queue: 'demo-queue',
|
|
69
|
+
id: 'demo:worker',
|
|
70
|
+
concurrency: 2,
|
|
71
|
+
onJobAbandoned: failAbandonedRun,
|
|
72
|
+
}
|
|
73
|
+
export default async function handle() {}
|
|
74
|
+
`
|
|
75
|
+
|
|
76
|
+
const WORKER_WITHOUT_HOOK = `
|
|
77
|
+
export const metadata = {
|
|
78
|
+
queue: 'demo-queue',
|
|
79
|
+
id: 'demo:worker',
|
|
80
|
+
concurrency: 2,
|
|
81
|
+
}
|
|
82
|
+
export default async function handle() {}
|
|
83
|
+
`
|
|
84
|
+
|
|
85
|
+
async function generateAll(resolver: PackageResolver): Promise<void> {
|
|
86
|
+
await generateModuleRegistry({ resolver, quiet: true })
|
|
87
|
+
await generateModuleRegistryApp({ resolver, quiet: true })
|
|
88
|
+
await generateModuleRegistryCli({ resolver, quiet: true })
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'generated-registry-imports-'))
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
afterEach(() => {
|
|
96
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
describe('generated registries — emitted identifiers are imported', () => {
|
|
100
|
+
it('imports the abandon-hook helper in every file that calls it', async () => {
|
|
101
|
+
scaffoldWorkerModule(tmpDir, 'demo', WORKER_WITH_HOOK)
|
|
102
|
+
const resolver = createMockResolver(tmpDir, [{ id: 'demo', from: 'pkg' } as ModuleEntry])
|
|
103
|
+
|
|
104
|
+
await generateAll(resolver)
|
|
105
|
+
|
|
106
|
+
const files = generatedFiles(tmpDir)
|
|
107
|
+
const callers = files.filter(({ content }) => content.includes(`${ABANDON_HOOK_FACTORY}(`))
|
|
108
|
+
// The fixture must actually exercise the path, or this test passes vacuously — which is exactly
|
|
109
|
+
// how the missing import survived every existing suite.
|
|
110
|
+
expect(callers.length).toBeGreaterThan(0)
|
|
111
|
+
|
|
112
|
+
for (const { name, content } of callers) {
|
|
113
|
+
expect(`${name}: ${content.includes(`import { `) && new RegExp(`import \\{[^}]*\\b${ABANDON_HOOK_FACTORY}\\b[^}]*\\} from`, 's').test(content)}`)
|
|
114
|
+
.toBe(`${name}: true`)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('leaves output untouched for a module set whose workers declare no hook', async () => {
|
|
119
|
+
scaffoldWorkerModule(tmpDir, 'demo', WORKER_WITHOUT_HOOK)
|
|
120
|
+
const resolver = createMockResolver(tmpDir, [{ id: 'demo', from: 'pkg' } as ModuleEntry])
|
|
121
|
+
|
|
122
|
+
await generateAll(resolver)
|
|
123
|
+
|
|
124
|
+
for (const { name, content } of generatedFiles(tmpDir)) {
|
|
125
|
+
expect(`${name}: ${content.includes(ABANDON_HOOK_FACTORY)}`).toBe(`${name}: false`)
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
})
|
|
@@ -4,6 +4,7 @@ import os from 'node:os'
|
|
|
4
4
|
import {
|
|
5
5
|
extractNamedObjectLiteralExport,
|
|
6
6
|
hasNamedExport,
|
|
7
|
+
namedObjectLiteralDeclaresProperty,
|
|
7
8
|
resolveNamedObjectExport,
|
|
8
9
|
} from '../module-registry'
|
|
9
10
|
|
|
@@ -218,3 +219,46 @@ describe('hasNamedExport', () => {
|
|
|
218
219
|
expect(hasNamedExport(file, 'metadata')).toBe(false)
|
|
219
220
|
})
|
|
220
221
|
})
|
|
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,22 +149,46 @@ 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
|
|
153
|
-
// entities, and extension surfaces without changing the extraction
|
|
152
|
+
// The additive EUDR and Documents modules contribute their real routes, ACL,
|
|
153
|
+
// events, entities, and extension surfaces without changing the extraction
|
|
154
|
+
// shape.
|
|
154
155
|
//
|
|
155
156
|
// JSON cap raised a fifth time by the devices/push-notifications stack: the
|
|
156
157
|
// `devices` and `push_notifications` modules plus the `channel-fcm`,
|
|
157
158
|
// `channel-apns` and `channel-expo` provider packages add their own facts,
|
|
158
159
|
// provenance entries and override targets to every render. The
|
|
159
|
-
// `warranty_claims` module (see above)
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
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)
|
|
163
186
|
// Markdown cap raised with the source-link contract: entities, events, ACL
|
|
164
187
|
// features, DI tokens, search entities, notifications, UMES hosts and UMES
|
|
165
188
|
// contributions all render a resolved Source cell, and contribution
|
|
166
|
-
// resolutions render as their own source-linked section
|
|
167
|
-
|
|
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)
|
|
168
192
|
expect(directoryMarkdownBytes).toBeLessThan(2_050_000)
|
|
169
193
|
})
|
|
170
194
|
|
|
@@ -28,7 +28,10 @@ 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
|
-
|
|
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)
|
|
32
35
|
expect(facts.aclFeatures).toHaveLength(21)
|
|
33
36
|
expect(facts.searchEntities).toEqual([
|
|
34
37
|
'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.quotes'])
|
|
106
|
+
expect(sales.hostTokens.tableIds).toEqual(['sales.orders', 'sales.payments', '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('
|
|
189
|
+
it('pins the exact emitted 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
|
|
196
|
+
import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from "@open-mercato/shared/modules/registry";
|
|
197
197
|
|
|
198
|
-
export const modules: Module[] = [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
export
|
|
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
|
+
}));
|
|
203
206
|
`))
|
|
204
207
|
expect(readGenerated(tmpDir, 'modules.runtime.generated.ts')).toBe(dedent(`
|
|
205
208
|
// AUTO-GENERATED by mercato generate registry
|
|
206
|
-
import { createElement } from
|
|
207
|
-
import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from
|
|
209
|
+
import { createElement } from "react";
|
|
210
|
+
import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from "@open-mercato/shared/modules/registry";
|
|
208
211
|
|
|
209
|
-
export const modules: Module[] = [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
export
|
|
212
|
+
export const modules: Module[] = [];
|
|
213
|
+
|
|
214
|
+
export default modules;
|
|
215
|
+
|
|
216
|
+
export const modulesInfo = modules.map((m) => ({
|
|
217
|
+
id: m.id,
|
|
218
|
+
...m.info || {}
|
|
219
|
+
}));
|
|
214
220
|
`))
|
|
215
221
|
expect(readGenerated(tmpDir, 'frontend-routes.generated.ts')).toBe(dedent(`
|
|
216
222
|
// AUTO-GENERATED by mercato generate registry
|
|
217
|
-
import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from
|
|
223
|
+
import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
218
224
|
|
|
219
|
-
export const frontendRoutes: FrontendRouteManifestEntry[] = [
|
|
220
|
-
|
|
221
|
-
]
|
|
225
|
+
export const frontendRoutes: FrontendRouteManifestEntry[] = [];
|
|
222
226
|
|
|
223
|
-
export default frontendRoutes
|
|
227
|
+
export default frontendRoutes;
|
|
224
228
|
`))
|
|
225
229
|
expect(readGenerated(tmpDir, 'backend-routes.generated.ts')).toBe(dedent(`
|
|
226
230
|
// AUTO-GENERATED by mercato generate registry
|
|
227
|
-
import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from
|
|
231
|
+
import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
228
232
|
|
|
229
|
-
export const backendRoutes: BackendRouteManifestEntry[] = [
|
|
230
|
-
|
|
231
|
-
]
|
|
233
|
+
export const backendRoutes: BackendRouteManifestEntry[] = [];
|
|
232
234
|
|
|
233
|
-
export default backendRoutes
|
|
235
|
+
export default backendRoutes;
|
|
234
236
|
`))
|
|
235
237
|
expect(readGenerated(tmpDir, 'api-routes.generated.ts')).toBe(dedent(`
|
|
236
238
|
// AUTO-GENERATED by mercato generate registry
|
|
237
|
-
import type { ApiRouteManifestEntry } from
|
|
239
|
+
import type { ApiRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
238
240
|
|
|
239
|
-
export const apiRoutes: ApiRouteManifestEntry[] = [
|
|
240
|
-
|
|
241
|
-
]
|
|
241
|
+
export const apiRoutes: ApiRouteManifestEntry[] = [];
|
|
242
242
|
|
|
243
|
-
export default apiRoutes
|
|
243
|
+
export default apiRoutes;
|
|
244
244
|
`))
|
|
245
245
|
})
|
|
246
246
|
|
|
247
|
-
it('
|
|
247
|
+
it('pins the exact emitted 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,75 +267,99 @@ 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
|
|
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).
|
|
275
|
-
expect(modulesGenerated).
|
|
274
|
+
expect(modulesGenerated).toMatch(/frontendRoutes:\s*\[\s*\{ pattern: "\/"/)
|
|
275
|
+
expect(modulesGenerated).toMatch(/backendRoutes:\s*\[\s*\{ 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).
|
|
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 }`)
|
|
279
280
|
expect(readGenerated(tmpDir, 'modules.runtime.generated.ts')).toBe(dedent(`
|
|
280
281
|
// AUTO-GENERATED by mercato generate registry
|
|
281
|
-
import { createElement } from
|
|
282
|
-
import { createLazyModuleSubscriber, createLazyModuleWorker, type Module } from
|
|
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"
|
|
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";
|
|
286
287
|
|
|
287
288
|
export const modules: Module[] = [
|
|
288
|
-
|
|
289
|
+
{
|
|
289
290
|
id: "orders",
|
|
290
291
|
info: I0_orders.metadata,
|
|
291
|
-
frontendRoutes: [
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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: []
|
|
305
302
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
export default modules
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
export default modules;
|
|
306
|
+
|
|
307
|
+
export const modulesInfo = modules.map((m) => ({
|
|
308
|
+
id: m.id,
|
|
309
|
+
...m.info || {}
|
|
310
|
+
}));
|
|
309
311
|
`))
|
|
310
312
|
expect(readGenerated(tmpDir, 'frontend-routes.generated.ts')).toBe(dedent(`
|
|
311
313
|
// AUTO-GENERATED by mercato generate registry
|
|
312
|
-
import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from
|
|
314
|
+
import { resolvePageRouteMetadata, type FrontendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
313
315
|
|
|
314
316
|
export const frontendRoutes: FrontendRouteManifestEntry[] = [
|
|
315
|
-
|
|
316
|
-
|
|
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
|
+
];
|
|
317
326
|
|
|
318
|
-
export default frontendRoutes
|
|
327
|
+
export default frontendRoutes;
|
|
319
328
|
`))
|
|
320
329
|
expect(readGenerated(tmpDir, 'backend-routes.generated.ts')).toBe(dedent(`
|
|
321
330
|
// AUTO-GENERATED by mercato generate registry
|
|
322
|
-
import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from
|
|
331
|
+
import { resolvePageRouteMetadata, type BackendRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
323
332
|
|
|
324
333
|
export const backendRoutes: BackendRouteManifestEntry[] = [
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
];
|
|
327
343
|
|
|
328
|
-
export default backendRoutes
|
|
344
|
+
export default backendRoutes;
|
|
329
345
|
`))
|
|
330
346
|
expect(readGenerated(tmpDir, 'api-routes.generated.ts')).toBe(dedent(`
|
|
331
347
|
// AUTO-GENERATED by mercato generate registry
|
|
332
|
-
import type { ApiRouteManifestEntry } from
|
|
348
|
+
import type { ApiRouteManifestEntry } from "@open-mercato/shared/modules/registry";
|
|
333
349
|
|
|
334
350
|
export const apiRoutes: ApiRouteManifestEntry[] = [
|
|
335
|
-
|
|
336
|
-
|
|
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
|
+
];
|
|
337
361
|
|
|
338
|
-
export default apiRoutes
|
|
362
|
+
export default apiRoutes;
|
|
339
363
|
`))
|
|
340
364
|
})
|
|
341
365
|
|
|
@@ -575,7 +599,7 @@ export { POST, PUT, DELETE }
|
|
|
575
599
|
expect(result.errors).toEqual([])
|
|
576
600
|
const apiRoutes = readGenerated(tmpDir, 'api-routes.generated.ts')!
|
|
577
601
|
expect(apiRoutes).toContain('path: "/customers/people"')
|
|
578
|
-
expect(apiRoutes).
|
|
602
|
+
expect(apiRoutes).toMatch(/methods:\s*\[[\s\S]*?"GET",[\s\S]*?"POST",[\s\S]*?"PUT",[\s\S]*?"DELETE"[\s\S]*?\]/)
|
|
579
603
|
})
|
|
580
604
|
|
|
581
605
|
it('partitions API and backend loader graphs while preserving legacy manifests', async () => {
|
|
@@ -660,7 +684,7 @@ export const { metadata, GET, POST, PUT, DELETE } = crud
|
|
|
660
684
|
expect(result.errors).toEqual([])
|
|
661
685
|
const apiRoutes = readGenerated(tmpDir, 'api-routes.generated.ts')!
|
|
662
686
|
expect(apiRoutes).toContain('path: "/example/todos"')
|
|
663
|
-
expect(apiRoutes).
|
|
687
|
+
expect(apiRoutes).toMatch(/methods:\s*\[[\s\S]*?"GET",[\s\S]*?"POST",[\s\S]*?"PUT",[\s\S]*?"DELETE"[\s\S]*?\]/)
|
|
664
688
|
})
|
|
665
689
|
|
|
666
690
|
it('uses metadata.path in api route manifests when source import fails during generation', async () => {
|
|
@@ -1047,7 +1071,7 @@ export function GET() {
|
|
|
1047
1071
|
)
|
|
1048
1072
|
|
|
1049
1073
|
expect(output).toContain('@open-mercato/core/modules/customers/i18n/en.json')
|
|
1050
|
-
expect(output).
|
|
1074
|
+
expect(output).toMatch(/['"]en['"]:/)
|
|
1051
1075
|
})
|
|
1052
1076
|
})
|
|
1053
1077
|
|
|
@@ -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
|
|
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]*\}/)
|