@open-mercato/cli 0.8.1-develop.7297.1.67605e74f9 → 0.8.1-develop.7442.1.4c1dbf1f0e
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 +10 -2
- package/AGENTS.md +2 -0
- package/dist/agentic/guides/module-facts.json +7370 -224
- package/dist/agentic/guides/module-facts.v2.json +7370 -224
- package/dist/agentic/guides/modules/agent_orchestrator/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
- package/dist/agentic/guides/modules/ai_assistant/encryption.md +13 -0
- package/dist/agentic/guides/modules/ai_assistant/exact-override-targets.md +3 -0
- package/dist/agentic/guides/modules/ai_assistant/index.md +4 -3
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/domain-commands.md +12 -0
- package/dist/agentic/guides/modules/api_keys/index.md +3 -2
- package/dist/agentic/guides/modules/attachments/index.md +1 -1
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/availability/acl-features.md +13 -0
- package/dist/agentic/guides/modules/availability/backend-pages.md +14 -0
- package/dist/agentic/guides/modules/availability/di-registrations-rich.md +11 -0
- package/dist/agentic/guides/modules/availability/domain-commands.md +13 -0
- package/dist/agentic/guides/modules/availability/entities.md +11 -0
- package/dist/agentic/guides/modules/availability/events.md +13 -0
- package/dist/agentic/guides/modules/availability/exact-override-targets.md +19 -0
- package/dist/agentic/guides/modules/availability/host-extension-points.md +10 -0
- package/dist/agentic/guides/modules/availability/index.md +22 -0
- package/dist/agentic/guides/modules/availability/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/availability/setup.md +11 -0
- package/dist/agentic/guides/modules/availability/umes-hosts.md +14 -0
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/catalog/di-registrations-rich.md +1 -0
- package/dist/agentic/guides/modules/catalog/exact-override-targets.md +3 -0
- package/dist/agentic/guides/modules/catalog/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/workers.md +2 -0
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
- 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/channel_resend/index.md +1 -1
- package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/acl-features.md +2 -1
- package/dist/agentic/guides/modules/communication_channels/contribution-resolutions.md +1 -0
- package/dist/agentic/guides/modules/communication_channels/di-registrations-rich.md +11 -10
- package/dist/agentic/guides/modules/communication_channels/domain-commands.md +1 -0
- package/dist/agentic/guides/modules/communication_channels/events.md +2 -1
- package/dist/agentic/guides/modules/communication_channels/exact-override-targets.md +12 -10
- package/dist/agentic/guides/modules/communication_channels/incoming-installed-contributions.md +1 -0
- package/dist/agentic/guides/modules/communication_channels/index.md +2 -2
- package/dist/agentic/guides/modules/communication_channels/umes-contributions.md +1 -0
- package/dist/agentic/guides/modules/communication_channels/umes-hosts.md +1 -0
- 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/customer_groups/acl-features.md +16 -0
- package/dist/agentic/guides/modules/customer_groups/active-extension-bindings.md +13 -0
- package/dist/agentic/guides/modules/customer_groups/backend-pages.md +14 -0
- package/dist/agentic/guides/modules/customer_groups/cli-commands.md +11 -0
- package/dist/agentic/guides/modules/customer_groups/contribution-resolutions.md +13 -0
- package/dist/agentic/guides/modules/customer_groups/di-registrations-rich.md +13 -0
- package/dist/agentic/guides/modules/customer_groups/di-service-tokens.md +11 -0
- package/dist/agentic/guides/modules/customer_groups/domain-commands.md +11 -0
- package/dist/agentic/guides/modules/customer_groups/entities.md +13 -0
- package/dist/agentic/guides/modules/customer_groups/events.md +17 -0
- package/dist/agentic/guides/modules/customer_groups/exact-override-targets.md +27 -0
- package/dist/agentic/guides/modules/customer_groups/index.md +26 -0
- package/dist/agentic/guides/modules/customer_groups/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/customer_groups/setup.md +11 -0
- package/dist/agentic/guides/modules/customer_groups/umes-contributions.md +13 -0
- package/dist/agentic/guides/modules/customer_groups/umes-hosts.md +21 -0
- package/dist/agentic/guides/modules/customers/acl-features.md +2 -1
- package/dist/agentic/guides/modules/customers/active-extension-bindings.md +8 -7
- package/dist/agentic/guides/modules/customers/contribution-resolutions.md +1 -0
- package/dist/agentic/guides/modules/customers/domain-commands.md +1 -0
- package/dist/agentic/guides/modules/customers/entities.md +1 -0
- package/dist/agentic/guides/modules/customers/events.md +2 -1
- package/dist/agentic/guides/modules/customers/exact-override-targets.md +2 -0
- package/dist/agentic/guides/modules/customers/index.md +3 -3
- package/dist/agentic/guides/modules/customers/umes-contributions.md +1 -0
- package/dist/agentic/guides/modules/customers/umes-hosts.md +3 -0
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- 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/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/directory/index.md +1 -1
- package/dist/agentic/guides/modules/documents/index.md +1 -1
- package/dist/agentic/guides/modules/entities/active-extension-bindings.md +1 -1
- 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/forms/acl-features.md +16 -0
- package/dist/agentic/guides/modules/forms/active-extension-bindings.md +14 -0
- package/dist/agentic/guides/modules/forms/backend-pages.md +17 -0
- package/dist/agentic/guides/modules/forms/contribution-resolutions.md +21 -0
- package/dist/agentic/guides/modules/forms/di-registrations-rich.md +27 -0
- package/dist/agentic/guides/modules/forms/di-service-tokens.md +19 -0
- package/dist/agentic/guides/modules/forms/domain-commands.md +30 -0
- package/dist/agentic/guides/modules/forms/encryption.md +11 -0
- package/dist/agentic/guides/modules/forms/entities.md +21 -0
- package/dist/agentic/guides/modules/forms/events.md +28 -0
- package/dist/agentic/guides/modules/forms/exact-override-targets.md +59 -0
- package/dist/agentic/guides/modules/forms/frontend-pages.md +16 -0
- package/dist/agentic/guides/modules/forms/index.md +28 -0
- package/dist/agentic/guides/modules/forms/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/forms/setup.md +11 -0
- package/dist/agentic/guides/modules/forms/umes-contributions.md +21 -0
- package/dist/agentic/guides/modules/forms/umes-hosts.md +43 -0
- package/dist/agentic/guides/modules/forms/workers.md +12 -0
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_tpay/acl-features.md +12 -0
- package/dist/agentic/guides/modules/gateway_tpay/cli-commands.md +12 -0
- package/dist/agentic/guides/modules/gateway_tpay/contribution-resolutions.md +12 -0
- package/dist/agentic/guides/modules/gateway_tpay/di-registrations-rich.md +11 -0
- package/dist/agentic/guides/modules/gateway_tpay/exact-override-targets.md +17 -0
- package/dist/agentic/guides/modules/gateway_tpay/index.md +19 -0
- package/dist/agentic/guides/modules/gateway_tpay/owned-contract-module-metadata.md +11 -0
- package/dist/agentic/guides/modules/gateway_tpay/setup.md +11 -0
- package/dist/agentic/guides/modules/gateway_tpay/umes-contributions.md +12 -0
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/di-registrations-rich.md +8 -8
- package/dist/agentic/guides/modules/integrations/di-service-tokens.md +4 -4
- package/dist/agentic/guides/modules/integrations/exact-override-targets.md +8 -8
- 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/phone_calls/index.md +1 -1
- package/dist/agentic/guides/modules/planner/active-extension-bindings.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/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/sales/exact-override-targets.md +4 -4
- package/dist/agentic/guides/modules/sales/index.md +1 -1
- package/dist/agentic/guides/modules/sales/setup.md +1 -1
- package/dist/agentic/guides/modules/scheduler/exact-override-targets.md +1 -1
- package/dist/agentic/guides/modules/scheduler/index.md +1 -1
- package/dist/agentic/guides/modules/scheduler/workers.md +1 -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/seeds/index.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/active-extension-bindings.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/active-extension-bindings.md +11 -0
- package/dist/agentic/guides/modules/sync_excel/index.md +3 -2
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/telemetry/index.md +1 -1
- package/dist/agentic/guides/modules/tillio/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/active-extension-bindings.md +1 -1
- package/dist/agentic/guides/modules/wms/contribution-resolutions.md +3 -0
- package/dist/agentic/guides/modules/wms/di-registrations-rich.md +8 -8
- package/dist/agentic/guides/modules/wms/exact-override-targets.md +11 -8
- package/dist/agentic/guides/modules/wms/index.md +3 -3
- package/dist/agentic/guides/modules/wms/umes-contributions.md +3 -0
- package/dist/agentic/guides/modules/workflows/active-extension-bindings.md +3 -3
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +1 -1
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +73 -1
- package/dist/agentic/guides/upstream/manifest.json +2 -2
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +1 -1
- package/dist/bin.js +2 -2
- package/dist/bin.js.map +2 -2
- package/dist/lib/db/commands.js +84 -5
- package/dist/lib/db/commands.js.map +2 -2
- package/dist/lib/db/encryption-backfill-check.js +112 -0
- package/dist/lib/db/encryption-backfill-check.js.map +7 -0
- package/dist/lib/db/migration-reindex.js +2 -1
- package/dist/lib/db/migration-reindex.js.map +2 -2
- package/dist/lib/events-single-delivery.js.map +2 -2
- package/dist/lib/flush-before-exit.js +19 -0
- package/dist/lib/flush-before-exit.js.map +7 -0
- package/dist/lib/generate-watch-structure.js +113 -19
- package/dist/lib/generate-watch-structure.js.map +3 -3
- package/dist/lib/generators/module-registry.js +4 -2
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/web-research-adapters.js +32 -11
- package/dist/lib/generators/web-research-adapters.js.map +2 -2
- package/dist/lib/telemetry-init.js +69 -11
- package/dist/lib/telemetry-init.js.map +3 -3
- package/dist/lib/testing/integration.js +29 -2
- package/dist/lib/testing/integration.js.map +2 -2
- package/package.json +7 -6
- package/src/bin.ts +4 -4
- package/src/lib/__tests__/flush-before-exit.test.ts +32 -0
- package/src/lib/__tests__/generate-watch-structure.test.ts +261 -3
- package/src/lib/__tests__/telemetry-init.test.ts +89 -0
- package/src/lib/db/__tests__/commands.test.ts +43 -0
- package/src/lib/db/__tests__/dynamic-import-specifier.test.ts +36 -0
- package/src/lib/db/__tests__/encryption-backfill-check.test.ts +146 -0
- package/src/lib/db/__tests__/migration-reindex.test.ts +48 -3
- package/src/lib/db/commands.ts +113 -10
- package/src/lib/db/encryption-backfill-check.ts +163 -0
- package/src/lib/db/migration-reindex.ts +2 -1
- package/src/lib/events-single-delivery.ts +5 -2
- package/src/lib/flush-before-exit.ts +39 -0
- package/src/lib/generate-watch-structure.ts +134 -19
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +14 -3
- package/src/lib/generators/__tests__/module-package-sources.test.ts +2 -2
- package/src/lib/generators/__tests__/registry-variant-parity.test.ts +16 -0
- package/src/lib/generators/__tests__/web-research-adapters.test.ts +141 -0
- package/src/lib/generators/module-registry.ts +2 -0
- package/src/lib/generators/web-research-adapters.ts +41 -20
- package/src/lib/telemetry-init.ts +68 -11
- package/src/lib/testing/__tests__/integration.test.ts +26 -0
- package/src/lib/testing/integration.ts +32 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.8.1-develop.
|
|
3
|
+
"version": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,9 +60,10 @@
|
|
|
60
60
|
"@mikro-orm/decorators": "^7.1.14",
|
|
61
61
|
"@mikro-orm/migrations": "^7.1.14",
|
|
62
62
|
"@mikro-orm/postgresql": "^7.1.14",
|
|
63
|
-
"@open-mercato/
|
|
64
|
-
"@open-mercato/
|
|
65
|
-
"@open-mercato/
|
|
63
|
+
"@open-mercato/events": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
64
|
+
"@open-mercato/queue": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
65
|
+
"@open-mercato/shared": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
66
|
+
"@open-mercato/telemetry": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
66
67
|
"cross-spawn": "^7.0.6",
|
|
67
68
|
"pg": "8.23.0",
|
|
68
69
|
"semver": "^7.8.5",
|
|
@@ -73,10 +74,10 @@
|
|
|
73
74
|
"typescript-js": "npm:typescript@6.0.3"
|
|
74
75
|
},
|
|
75
76
|
"peerDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
77
|
+
"@open-mercato/shared": "0.8.1-develop.7442.1.4c1dbf1f0e"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
80
|
+
"@open-mercato/shared": "0.8.1-develop.7442.1.4c1dbf1f0e",
|
|
80
81
|
"@types/jest": "^30.0.0",
|
|
81
82
|
"jest": "^30.4.2",
|
|
82
83
|
"ts-jest": "^29.4.12"
|
package/src/bin.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
8
8
|
import { resolveCliBootstrapMode, type CliBootstrapMode } from './lib/cli-bootstrap-mode.js'
|
|
9
|
-
import {
|
|
9
|
+
import { flushBeforeExit } from './lib/flush-before-exit.js'
|
|
10
10
|
// `run` is imported dynamically inside `main()` so telemetry can initialize
|
|
11
11
|
// before the mercato entry (and its Postgres driver) loads — see main().
|
|
12
12
|
|
|
@@ -114,9 +114,9 @@ async function main(): Promise<void> {
|
|
|
114
114
|
// Postgres driver it pulls in — loads only after initTelemetry() above.
|
|
115
115
|
const { run } = await import('./mercato.js')
|
|
116
116
|
const code = await run(process.argv)
|
|
117
|
-
// Flush spans/logs for commands that
|
|
118
|
-
// their own shutdown handler instead).
|
|
119
|
-
await
|
|
117
|
+
// Flush the coalesced browser broadcasts, then spans/logs, for commands that
|
|
118
|
+
// return (workers block forever and flush via their own shutdown handler instead).
|
|
119
|
+
await flushBeforeExit()
|
|
120
120
|
process.exit(code ?? 0)
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { flushBeforeExit } from '../flush-before-exit'
|
|
2
|
+
|
|
3
|
+
describe('flushBeforeExit', () => {
|
|
4
|
+
let warn: jest.SpyInstance
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
warn = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
warn.mockRestore()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('flushes coalesced broadcasts before telemetry so the final pg_notify is still exported', async () => {
|
|
15
|
+
const order: string[] = []
|
|
16
|
+
await flushBeforeExit({
|
|
17
|
+
flushBroadcasts: async () => { order.push('broadcasts') },
|
|
18
|
+
flushTelemetry: async () => { order.push('telemetry') },
|
|
19
|
+
})
|
|
20
|
+
expect(order).toEqual(['broadcasts', 'telemetry'])
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('still flushes telemetry, with a warning, when the broadcast flush fails', async () => {
|
|
24
|
+
const flushTelemetry = jest.fn().mockResolvedValue(undefined)
|
|
25
|
+
await expect(flushBeforeExit({
|
|
26
|
+
flushBroadcasts: async () => { throw new Error('connection terminated') },
|
|
27
|
+
flushTelemetry,
|
|
28
|
+
})).resolves.toBeUndefined()
|
|
29
|
+
expect(flushTelemetry).toHaveBeenCalledTimes(1)
|
|
30
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining('connection terminated'))
|
|
31
|
+
})
|
|
32
|
+
})
|
|
@@ -29,13 +29,35 @@ describe('calculateGenerateWatchStructureChecksum', () => {
|
|
|
29
29
|
fs.rmSync(root, { recursive: true, force: true })
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
function
|
|
32
|
+
function checksumModule(modulesFile: string, appBase: string, packageBase: string): string {
|
|
33
33
|
return calculateGenerateWatchStructureChecksum({
|
|
34
|
-
modulesFile
|
|
35
|
-
moduleRoots: [{ appBase
|
|
34
|
+
modulesFile,
|
|
35
|
+
moduleRoots: [{ appBase, pkgBase: packageBase }],
|
|
36
36
|
})
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function currentChecksum(): string {
|
|
40
|
+
return checksumModule(path.join(appDir, 'src', 'modules.ts'), appModule, pkgModule)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createStandaloneModule() {
|
|
44
|
+
const standaloneRoot = path.join(root, 'standalone')
|
|
45
|
+
const packageRoot = path.join(standaloneRoot, 'node_modules', '@open-mercato', 'core')
|
|
46
|
+
const sourceModule = path.join(packageRoot, 'src', 'modules', 'customers')
|
|
47
|
+
const distModule = path.join(packageRoot, 'dist', 'modules', 'customers')
|
|
48
|
+
const standaloneAppModule = path.join(standaloneRoot, 'src', 'modules', 'customers')
|
|
49
|
+
const modulesFile = path.join(standaloneRoot, 'src', 'modules.ts')
|
|
50
|
+
write(modulesFile, 'export const enabledModules = ["customers"]\n')
|
|
51
|
+
write(path.join(sourceModule, 'index.ts'), 'export const metadata = { id: "customers" }\n')
|
|
52
|
+
write(path.join(distModule, 'index.js'), 'export const metadata = { id: "customers" }\n')
|
|
53
|
+
return {
|
|
54
|
+
sourceModule,
|
|
55
|
+
distModule,
|
|
56
|
+
appModule: standaloneAppModule,
|
|
57
|
+
modulesFile,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
it('ignores ordinary component edits outside generator discovery paths', () => {
|
|
40
62
|
const before = currentChecksum()
|
|
41
63
|
|
|
@@ -78,6 +100,32 @@ describe('calculateGenerateWatchStructureChecksum', () => {
|
|
|
78
100
|
expect(currentChecksum()).not.toBe(before)
|
|
79
101
|
})
|
|
80
102
|
|
|
103
|
+
it('changes when an identical convention file moves between module roots', () => {
|
|
104
|
+
const ordersPkgModule = path.join(root, 'packages', 'core', 'src', 'modules', 'orders')
|
|
105
|
+
const ordersAppModule = path.join(appDir, 'src', 'modules', 'orders')
|
|
106
|
+
const customersCli = path.join(pkgModule, 'cli.ts')
|
|
107
|
+
const ordersCli = path.join(ordersPkgModule, 'cli.ts')
|
|
108
|
+
const cliSource = 'export default function registerCli() {}\n'
|
|
109
|
+
const moduleRoots = [
|
|
110
|
+
{ appBase: appModule, pkgBase: pkgModule },
|
|
111
|
+
{ appBase: ordersAppModule, pkgBase: ordersPkgModule },
|
|
112
|
+
]
|
|
113
|
+
write(path.join(ordersPkgModule, 'index.ts'), 'export const metadata = { id: "orders" }\n')
|
|
114
|
+
write(customersCli, cliSource)
|
|
115
|
+
const before = calculateGenerateWatchStructureChecksum({
|
|
116
|
+
modulesFile: path.join(appDir, 'src', 'modules.ts'),
|
|
117
|
+
moduleRoots,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
fs.rmSync(customersCli)
|
|
121
|
+
write(ordersCli, cliSource)
|
|
122
|
+
|
|
123
|
+
expect(calculateGenerateWatchStructureChecksum({
|
|
124
|
+
modulesFile: path.join(appDir, 'src', 'modules.ts'),
|
|
125
|
+
moduleRoots,
|
|
126
|
+
})).not.toBe(before)
|
|
127
|
+
})
|
|
128
|
+
|
|
81
129
|
// A runtime.ts the watcher cannot see is the failure SPEC-072 exists to remove, reappearing in
|
|
82
130
|
// the dev loop: the registry is not regenerated, `Module.runtime` stays undefined, and the
|
|
83
131
|
// runtime never starts — with no error and no warning.
|
|
@@ -115,4 +163,214 @@ describe('calculateGenerateWatchStructureChecksum', () => {
|
|
|
115
163
|
|
|
116
164
|
expect(currentChecksum()).not.toBe(before)
|
|
117
165
|
})
|
|
166
|
+
|
|
167
|
+
it('tracks generator-relevant API route changes from a standalone source mirror', () => {
|
|
168
|
+
const standalone = createStandaloneModule()
|
|
169
|
+
const sourceRoute = path.join(standalone.sourceModule, 'api', 'records', 'route.ts')
|
|
170
|
+
const distRoute = path.join(standalone.distModule, 'api', 'records', 'route.js')
|
|
171
|
+
write(
|
|
172
|
+
sourceRoute,
|
|
173
|
+
'export const metadata = { path: "/records" }\nexport async function GET() { return null }\n',
|
|
174
|
+
)
|
|
175
|
+
write(
|
|
176
|
+
distRoute,
|
|
177
|
+
'export const metadata = { path: "/records" };\nexport async function GET() { return null; }\n',
|
|
178
|
+
)
|
|
179
|
+
const before = checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)
|
|
180
|
+
|
|
181
|
+
write(
|
|
182
|
+
sourceRoute,
|
|
183
|
+
'export const metadata = { path: "/contacts" }\nexport async function GET() { return null }\n',
|
|
184
|
+
)
|
|
185
|
+
const afterSourceMetadata = checksumModule(
|
|
186
|
+
standalone.modulesFile,
|
|
187
|
+
standalone.appModule,
|
|
188
|
+
standalone.distModule,
|
|
189
|
+
)
|
|
190
|
+
expect(afterSourceMetadata).not.toBe(before)
|
|
191
|
+
|
|
192
|
+
write(
|
|
193
|
+
distRoute,
|
|
194
|
+
'export const metadata = { path: "/contacts" };\nexport async function GET() { return null; }\n',
|
|
195
|
+
)
|
|
196
|
+
const afterDistMetadata = checksumModule(
|
|
197
|
+
standalone.modulesFile,
|
|
198
|
+
standalone.appModule,
|
|
199
|
+
standalone.distModule,
|
|
200
|
+
)
|
|
201
|
+
expect(afterDistMetadata).not.toBe(afterSourceMetadata)
|
|
202
|
+
|
|
203
|
+
write(
|
|
204
|
+
sourceRoute,
|
|
205
|
+
'export const metadata = { path: "/contacts" }\nexport async function POST() { return null }\n',
|
|
206
|
+
)
|
|
207
|
+
const afterSourceMethod = checksumModule(
|
|
208
|
+
standalone.modulesFile,
|
|
209
|
+
standalone.appModule,
|
|
210
|
+
standalone.distModule,
|
|
211
|
+
)
|
|
212
|
+
expect(afterSourceMethod).not.toBe(afterDistMetadata)
|
|
213
|
+
|
|
214
|
+
write(
|
|
215
|
+
distRoute,
|
|
216
|
+
'export const metadata = { path: "/contacts" };\nexport async function POST() { return null; }\n',
|
|
217
|
+
)
|
|
218
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule))
|
|
219
|
+
.not.toBe(afterSourceMethod)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('tracks standalone source-mirror page metadata but ignores ordinary page implementation edits', () => {
|
|
223
|
+
const standalone = createStandaloneModule()
|
|
224
|
+
const sourcePage = path.join(standalone.sourceModule, 'backend', 'customers', 'people', 'page.tsx')
|
|
225
|
+
const sourceMeta = path.join(standalone.sourceModule, 'backend', 'customers', 'people', 'page.meta.ts')
|
|
226
|
+
write(sourcePage, 'export default function Page() { return null }\n')
|
|
227
|
+
write(sourceMeta, 'export const metadata = { nav: { label: "People" } }\n')
|
|
228
|
+
write(
|
|
229
|
+
path.join(standalone.distModule, 'backend', 'customers', 'people', 'page.js'),
|
|
230
|
+
'export default function Page() { return null; }\n',
|
|
231
|
+
)
|
|
232
|
+
write(
|
|
233
|
+
path.join(standalone.distModule, 'backend', 'customers', 'people', 'page.meta.js'),
|
|
234
|
+
'export const metadata = { nav: { label: "People" } };\n',
|
|
235
|
+
)
|
|
236
|
+
const before = checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)
|
|
237
|
+
|
|
238
|
+
write(sourcePage, 'export default function Page() { return "implementation changed" }\n')
|
|
239
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)).toBe(before)
|
|
240
|
+
|
|
241
|
+
write(sourceMeta, 'export const metadata = { nav: { label: "Contacts" } }\n')
|
|
242
|
+
const afterSourceMetadata = checksumModule(
|
|
243
|
+
standalone.modulesFile,
|
|
244
|
+
standalone.appModule,
|
|
245
|
+
standalone.distModule,
|
|
246
|
+
)
|
|
247
|
+
expect(afterSourceMetadata).not.toBe(before)
|
|
248
|
+
|
|
249
|
+
write(
|
|
250
|
+
path.join(standalone.distModule, 'backend', 'customers', 'people', 'page.meta.js'),
|
|
251
|
+
'export const metadata = { nav: { label: "Contacts" } };\n',
|
|
252
|
+
)
|
|
253
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule))
|
|
254
|
+
.not.toBe(afterSourceMetadata)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('tracks additions and deletions enumerated from a standalone source mirror', () => {
|
|
258
|
+
const standalone = createStandaloneModule()
|
|
259
|
+
const before = checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)
|
|
260
|
+
const sourceWorker = path.join(standalone.sourceModule, 'workers', 'sync-customers.ts')
|
|
261
|
+
write(sourceWorker, 'export default async function syncCustomers() {}\n')
|
|
262
|
+
write(
|
|
263
|
+
path.join(standalone.distModule, 'workers', 'sync-customers.js'),
|
|
264
|
+
'export default async function syncCustomers() {}\n',
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)).not.toBe(before)
|
|
268
|
+
|
|
269
|
+
fs.rmSync(sourceWorker)
|
|
270
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)).toBe(before)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('tracks stale compiled entities after the source-mirror convention is deleted', () => {
|
|
274
|
+
const standalone = createStandaloneModule()
|
|
275
|
+
const sourceEntities = path.join(standalone.sourceModule, 'data', 'entities.ts')
|
|
276
|
+
const distEntities = path.join(standalone.distModule, 'data', 'entities.js')
|
|
277
|
+
const before = checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)
|
|
278
|
+
|
|
279
|
+
write(sourceEntities, 'export class Customer {}\n')
|
|
280
|
+
const afterSourceAdd = checksumModule(
|
|
281
|
+
standalone.modulesFile,
|
|
282
|
+
standalone.appModule,
|
|
283
|
+
standalone.distModule,
|
|
284
|
+
)
|
|
285
|
+
expect(afterSourceAdd).not.toBe(before)
|
|
286
|
+
|
|
287
|
+
write(distEntities, 'export class Customer {}\n')
|
|
288
|
+
const afterDistAdd = checksumModule(
|
|
289
|
+
standalone.modulesFile,
|
|
290
|
+
standalone.appModule,
|
|
291
|
+
standalone.distModule,
|
|
292
|
+
)
|
|
293
|
+
expect(afterDistAdd).not.toBe(afterSourceAdd)
|
|
294
|
+
|
|
295
|
+
write(sourceEntities, 'export class CustomerAccount {}\n')
|
|
296
|
+
const afterSourceEdit = checksumModule(
|
|
297
|
+
standalone.modulesFile,
|
|
298
|
+
standalone.appModule,
|
|
299
|
+
standalone.distModule,
|
|
300
|
+
)
|
|
301
|
+
expect(afterSourceEdit).not.toBe(afterDistAdd)
|
|
302
|
+
|
|
303
|
+
write(distEntities, 'export class CustomerAccount {}\n')
|
|
304
|
+
const afterDistEdit = checksumModule(
|
|
305
|
+
standalone.modulesFile,
|
|
306
|
+
standalone.appModule,
|
|
307
|
+
standalone.distModule,
|
|
308
|
+
)
|
|
309
|
+
expect(afterDistEdit).not.toBe(afterSourceEdit)
|
|
310
|
+
|
|
311
|
+
fs.rmSync(sourceEntities)
|
|
312
|
+
const afterSourceDelete = checksumModule(
|
|
313
|
+
standalone.modulesFile,
|
|
314
|
+
standalone.appModule,
|
|
315
|
+
standalone.distModule,
|
|
316
|
+
)
|
|
317
|
+
expect(afterSourceDelete).not.toBe(afterDistEdit)
|
|
318
|
+
expect(afterSourceDelete).not.toBe(before)
|
|
319
|
+
|
|
320
|
+
fs.rmSync(distEntities)
|
|
321
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule))
|
|
322
|
+
.toBe(before)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('fingerprints the selected app override instead of the shadowed package route', () => {
|
|
326
|
+
const standalone = createStandaloneModule()
|
|
327
|
+
const routeSource = 'export const metadata = { path: "/records" }\nexport async function GET() { return null }\n'
|
|
328
|
+
const packageRoute = path.join(standalone.sourceModule, 'api', 'records', 'route.js')
|
|
329
|
+
const appRoute = path.join(standalone.appModule, 'api', 'records', 'route.js')
|
|
330
|
+
write(packageRoute, routeSource)
|
|
331
|
+
write(path.join(standalone.distModule, 'api', 'records', 'route.js'), routeSource)
|
|
332
|
+
const beforeOverride = checksumModule(
|
|
333
|
+
standalone.modulesFile,
|
|
334
|
+
standalone.appModule,
|
|
335
|
+
standalone.distModule,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
write(appRoute, routeSource)
|
|
339
|
+
const withOverride = checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule)
|
|
340
|
+
expect(withOverride).not.toBe(beforeOverride)
|
|
341
|
+
|
|
342
|
+
write(
|
|
343
|
+
packageRoute,
|
|
344
|
+
'export const metadata = { path: "/shadowed" }\nexport async function POST() { return null }\n',
|
|
345
|
+
)
|
|
346
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule))
|
|
347
|
+
.toBe(withOverride)
|
|
348
|
+
|
|
349
|
+
fs.rmSync(appRoute)
|
|
350
|
+
expect(checksumModule(standalone.modulesFile, standalone.appModule, standalone.distModule))
|
|
351
|
+
.not.toBe(withOverride)
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('keeps content-sensitive fingerprinting for dist-only installed packages', () => {
|
|
355
|
+
const standaloneRoot = path.join(root, 'dist-only')
|
|
356
|
+
const distModule = path.join(
|
|
357
|
+
standaloneRoot,
|
|
358
|
+
'node_modules',
|
|
359
|
+
'@open-mercato',
|
|
360
|
+
'core',
|
|
361
|
+
'dist',
|
|
362
|
+
'modules',
|
|
363
|
+
'customers',
|
|
364
|
+
)
|
|
365
|
+
const modulesFile = path.join(standaloneRoot, 'src', 'modules.ts')
|
|
366
|
+
const routePath = path.join(distModule, 'api', 'records', 'route.js')
|
|
367
|
+
write(modulesFile, 'export const enabledModules = ["customers"]\n')
|
|
368
|
+
write(path.join(distModule, 'index.js'), 'export const metadata = { id: "customers" }\n')
|
|
369
|
+
write(routePath, 'export const metadata = { path: "/records" };\nexport async function GET() {}\n')
|
|
370
|
+
const appModule = path.join(standaloneRoot, 'src', 'modules', 'customers')
|
|
371
|
+
const before = checksumModule(modulesFile, appModule, distModule)
|
|
372
|
+
|
|
373
|
+
write(routePath, 'export const metadata = { path: "/contacts" };\nexport async function GET() {}\n')
|
|
374
|
+
expect(checksumModule(modulesFile, appModule, distModule)).not.toBe(before)
|
|
375
|
+
})
|
|
118
376
|
})
|
|
@@ -99,6 +99,33 @@ async function handleRequest(method: string, req: NextRequest): Promise<Response
|
|
|
99
99
|
}
|
|
100
100
|
`
|
|
101
101
|
|
|
102
|
+
const LEGACY_INSTRUMENTATION = `import { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
103
|
+
|
|
104
|
+
export async function register(): Promise<void> {
|
|
105
|
+
if (
|
|
106
|
+
process.env.NEXT_RUNTIME === 'nodejs'
|
|
107
|
+
&& process.env.NEXT_PHASE !== 'phase-production-build'
|
|
108
|
+
) {
|
|
109
|
+
const { assertJwtSecretPolicy } = await import('@open-mercato/shared/lib/auth/jwt')
|
|
110
|
+
try {
|
|
111
|
+
assertJwtSecretPolicy()
|
|
112
|
+
} catch (err) {
|
|
113
|
+
const nodeProcess = process
|
|
114
|
+
nodeProcess.stderr.write(\`\${err instanceof Error ? err.message : String(err)}\\n\`)
|
|
115
|
+
nodeProcess.exit(1)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (
|
|
120
|
+
process.env.NEXT_RUNTIME === 'nodejs'
|
|
121
|
+
&& isTelemetryBackendEnabled()
|
|
122
|
+
) {
|
|
123
|
+
const { registerTelemetryForNextjs } = await import('@open-mercato/telemetry/nextjs')
|
|
124
|
+
await registerTelemetryForNextjs()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
`
|
|
128
|
+
|
|
102
129
|
describe('mercato telemetry init', () => {
|
|
103
130
|
let tmpDir: string
|
|
104
131
|
let cwd: string
|
|
@@ -142,6 +169,8 @@ describe('mercato telemetry init', () => {
|
|
|
142
169
|
expect(read('.env.example')).toContain('TELEMETRY_BACKEND')
|
|
143
170
|
expect(read('.env.example')).toContain('OTEL_EXPORTER_OTLP_ENDPOINT')
|
|
144
171
|
expect(read('src/instrumentation.ts')).toContain('registerTelemetryForNextjs')
|
|
172
|
+
expect(read('src/instrumentation.ts')).toContain('nodeProcess.stderr.write')
|
|
173
|
+
expect(read('src/instrumentation.ts')).toContain('nodeProcess.exit(1)')
|
|
145
174
|
|
|
146
175
|
const nextConfig = read('next.config.ts')
|
|
147
176
|
expect(nextConfig).toContain('@open-mercato/telemetry/nextjs-config')
|
|
@@ -277,9 +306,69 @@ describe('mercato telemetry init', () => {
|
|
|
277
306
|
const instrumentation = read('src/instrumentation.ts')
|
|
278
307
|
assertParses(instrumentation, 'custom-instrumentation')
|
|
279
308
|
expect(instrumentation).toContain('registerTelemetryForNextjs')
|
|
309
|
+
expect(instrumentation).toContain('nodeProcess.stderr.write')
|
|
310
|
+
expect(instrumentation).toContain('nodeProcess.exit(1)')
|
|
280
311
|
expect(instrumentation).toContain("console.log('custom warmup')") // preserved
|
|
281
312
|
})
|
|
282
313
|
|
|
314
|
+
it('upgrades the legacy generated instrumentation and stays idempotent', async () => {
|
|
315
|
+
baseFixture(tmpDir)
|
|
316
|
+
fs.writeFileSync(path.join(tmpDir, dispatcherPath), SIMPLE_DISPATCHER)
|
|
317
|
+
fs.writeFileSync(path.join(tmpDir, 'src', 'instrumentation.ts'), LEGACY_INSTRUMENTATION)
|
|
318
|
+
|
|
319
|
+
await runTelemetryInit([])
|
|
320
|
+
const migrated = read('src/instrumentation.ts')
|
|
321
|
+
assertParses(migrated, 'legacy-instrumentation-migration')
|
|
322
|
+
expect(migrated).toContain('nodeProcess.stderr.write')
|
|
323
|
+
expect(migrated).toContain('nodeProcess.exit(1)')
|
|
324
|
+
expect((migrated.match(/registerTelemetryForNextjs\(\)/g) ?? []).length).toBe(1)
|
|
325
|
+
expect((migrated.match(/nodeProcess\.exit\(1\)/g) ?? []).length).toBe(2)
|
|
326
|
+
|
|
327
|
+
await runTelemetryInit([])
|
|
328
|
+
expect(read('src/instrumentation.ts')).toBe(migrated)
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
it('upgrades the older Node-only generated bootstrap', async () => {
|
|
332
|
+
baseFixture(tmpDir)
|
|
333
|
+
fs.writeFileSync(path.join(tmpDir, dispatcherPath), SIMPLE_DISPATCHER)
|
|
334
|
+
fs.writeFileSync(
|
|
335
|
+
path.join(tmpDir, 'src', 'instrumentation.ts'),
|
|
336
|
+
`export async function register(): Promise<void> {
|
|
337
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
338
|
+
const { registerTelemetryForNextjs } = await import('@open-mercato/telemetry/nextjs')
|
|
339
|
+
await registerTelemetryForNextjs()
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
`,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
await runTelemetryInit([])
|
|
346
|
+
const migrated = read('src/instrumentation.ts')
|
|
347
|
+
|
|
348
|
+
assertParses(migrated, 'node-only-instrumentation-migration')
|
|
349
|
+
expect(migrated).toContain("import { isTelemetryBackendEnabled }")
|
|
350
|
+
expect(migrated).toContain("process.env.NEXT_RUNTIME === 'nodejs' && isTelemetryBackendEnabled()")
|
|
351
|
+
expect(migrated).toContain('nodeProcess.exit(1)')
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('leaves an unrecognized custom telemetry bootstrap for a manual update', async () => {
|
|
355
|
+
baseFixture(tmpDir)
|
|
356
|
+
fs.writeFileSync(path.join(tmpDir, dispatcherPath), SIMPLE_DISPATCHER)
|
|
357
|
+
const customInstrumentation = `export async function register(): Promise<void> {
|
|
358
|
+
const { registerTelemetryForNextjs } = await import('@open-mercato/telemetry/nextjs')
|
|
359
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') await registerTelemetryForNextjs()
|
|
360
|
+
const nodeProcess = process
|
|
361
|
+
nodeProcess.exit(1)
|
|
362
|
+
}
|
|
363
|
+
`
|
|
364
|
+
fs.writeFileSync(path.join(tmpDir, 'src', 'instrumentation.ts'), customInstrumentation)
|
|
365
|
+
|
|
366
|
+
await runTelemetryInit([])
|
|
367
|
+
|
|
368
|
+
expect(read('src/instrumentation.ts')).toBe(customInstrumentation)
|
|
369
|
+
expect(logSpy.mock.calls.flat().join('\n')).toContain('manual step for src/instrumentation.ts')
|
|
370
|
+
})
|
|
371
|
+
|
|
283
372
|
it('is idempotent — a second run changes nothing and does not double-insert', async () => {
|
|
284
373
|
baseFixture(tmpDir)
|
|
285
374
|
fs.writeFileSync(path.join(tmpDir, dispatcherPath), SIMPLE_DISPATCHER)
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
resolveGeneratedMigrationPath,
|
|
8
8
|
dbGenerate,
|
|
9
9
|
dbGreenfield,
|
|
10
|
+
warnAboutMissingEncryptionMapBackfills,
|
|
10
11
|
} from '../commands'
|
|
11
12
|
import { MetadataStorage } from '@mikro-orm/core'
|
|
12
13
|
import fs from 'node:fs'
|
|
@@ -399,3 +400,45 @@ describe('dbGenerate metadata isolation (issue #1911)', () => {
|
|
|
399
400
|
expect(Object.keys(MetadataStorage.getMetadata())).toHaveLength(0)
|
|
400
401
|
})
|
|
401
402
|
})
|
|
403
|
+
|
|
404
|
+
describe('warnAboutMissingEncryptionMapBackfills', () => {
|
|
405
|
+
const tempDirs: string[] = []
|
|
406
|
+
|
|
407
|
+
afterEach(() => {
|
|
408
|
+
for (const dir of tempDirs.splice(0)) {
|
|
409
|
+
try { fs.rmSync(dir, { recursive: true, force: true }) } catch {}
|
|
410
|
+
}
|
|
411
|
+
jest.restoreAllMocks()
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
function createResolver(dir: string): PackageResolver {
|
|
415
|
+
return {
|
|
416
|
+
isMonorepo: () => true,
|
|
417
|
+
getRootDir: () => dir,
|
|
418
|
+
getAppDir: () => dir,
|
|
419
|
+
getOutputDir: () => dir,
|
|
420
|
+
getModulesConfigPath: () => path.join(dir, 'modules.ts'),
|
|
421
|
+
discoverPackages: () => [],
|
|
422
|
+
loadEnabledModules: () => [{ id: 'demo', from: '@app' }],
|
|
423
|
+
getModulePaths: () => ({ appBase: dir, pkgBase: dir }),
|
|
424
|
+
getModuleImportBase: () => ({ appBase: '@/modules/demo', pkgBase: '@open-mercato/core/modules/demo' }),
|
|
425
|
+
getPackageOutputDir: () => dir,
|
|
426
|
+
getPackageRoot: () => dir,
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function createModule(): string {
|
|
431
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mercato-enc-'))
|
|
432
|
+
tempDirs.push(dir)
|
|
433
|
+
return dir
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
it('stays silent without declared encryption maps', async () => {
|
|
437
|
+
const warn = jest.spyOn(console, 'warn').mockImplementation()
|
|
438
|
+
const resolver = createResolver(createModule())
|
|
439
|
+
|
|
440
|
+
await warnAboutMissingEncryptionMapBackfills(resolver.loadEnabledModules(), resolver)
|
|
441
|
+
|
|
442
|
+
expect(warn).not.toHaveBeenCalled()
|
|
443
|
+
})
|
|
444
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import { toImportableModuleSpecifier } from '../commands'
|
|
4
|
+
|
|
5
|
+
describe('toImportableModuleSpecifier (#6238)', () => {
|
|
6
|
+
it('converts cwd-relative node_modules migration paths to file: URLs', () => {
|
|
7
|
+
const relative = path.join('node_modules', '@open-mercato', 'core', 'dist', 'modules', 'customers', 'migrations', 'Migration20250101000000.js')
|
|
8
|
+
const result = toImportableModuleSpecifier(relative)
|
|
9
|
+
|
|
10
|
+
expect(result.startsWith('file:')).toBe(true)
|
|
11
|
+
expect(result).toBe(pathToFileURL(path.resolve(relative)).href)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('converts absolute filesystem paths to file: URLs on every platform', () => {
|
|
15
|
+
const absolute = path.resolve('migrations', 'Migration20250101000000.js')
|
|
16
|
+
expect(toImportableModuleSpecifier(absolute)).toBe(pathToFileURL(absolute).href)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('converts ./ and ../ relative paths to file: URLs', () => {
|
|
20
|
+
expect(toImportableModuleSpecifier('./Migration.js')).toBe(pathToFileURL(path.resolve('./Migration.js')).href)
|
|
21
|
+
expect(toImportableModuleSpecifier('../migrations/Migration.js')).toBe(
|
|
22
|
+
pathToFileURL(path.resolve('../migrations/Migration.js')).href,
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('leaves bare package names and package subpaths alone', () => {
|
|
27
|
+
expect(toImportableModuleSpecifier('zod')).toBe('zod')
|
|
28
|
+
expect(toImportableModuleSpecifier('@mikro-orm/core')).toBe('@mikro-orm/core')
|
|
29
|
+
expect(toImportableModuleSpecifier('next/server')).toBe('next/server')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('leaves existing file: and node: URLs alone', () => {
|
|
33
|
+
expect(toImportableModuleSpecifier('file:///tmp/Migration.js')).toBe('file:///tmp/Migration.js')
|
|
34
|
+
expect(toImportableModuleSpecifier('node:fs')).toBe('node:fs')
|
|
35
|
+
})
|
|
36
|
+
})
|