@open-mercato/cli 0.6.3-develop.3525.3.cc18b8a43f → 0.6.3-develop.3574.1.f3c5dcf345

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.6.3-develop.3525.3.cc18b8a43f",
3
+ "version": "0.6.3-develop.3574.1.f3c5dcf345",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -59,8 +59,8 @@
59
59
  "@mikro-orm/decorators": "^7.0.17",
60
60
  "@mikro-orm/migrations": "^7.0.17",
61
61
  "@mikro-orm/postgresql": "^7.0.17",
62
- "@open-mercato/queue": "0.6.3-develop.3525.3.cc18b8a43f",
63
- "@open-mercato/shared": "0.6.3-develop.3525.3.cc18b8a43f",
62
+ "@open-mercato/queue": "0.6.3-develop.3574.1.f3c5dcf345",
63
+ "@open-mercato/shared": "0.6.3-develop.3574.1.f3c5dcf345",
64
64
  "cross-spawn": "^7.0.6",
65
65
  "pg": "8.21.0",
66
66
  "semver": "^7.8.0",
@@ -70,10 +70,10 @@
70
70
  "typescript": "^6.0.3"
71
71
  },
72
72
  "peerDependencies": {
73
- "@open-mercato/shared": "0.6.3-develop.3525.3.cc18b8a43f"
73
+ "@open-mercato/shared": "0.6.3-develop.3574.1.f3c5dcf345"
74
74
  },
75
75
  "devDependencies": {
76
- "@open-mercato/shared": "0.6.3-develop.3525.3.cc18b8a43f",
76
+ "@open-mercato/shared": "0.6.3-develop.3574.1.f3c5dcf345",
77
77
  "@types/jest": "^30.0.0",
78
78
  "jest": "^30.4.2",
79
79
  "ts-jest": "^29.4.9"
@@ -6,6 +6,7 @@ import {
6
6
  padByCodePointWidth,
7
7
  run,
8
8
  } from '../mercato'
9
+ import { pathIncludes } from '../lib/__tests__/path-helpers'
9
10
 
10
11
  type MockChildAutoExit = { code: number | null; signal?: NodeJS.Signals | null } | undefined
11
12
  type MockChildSpawnRouter = (args: string[]) => MockChildAutoExit
@@ -674,7 +675,7 @@ describe('server dev managed process exits', () => {
674
675
  return {
675
676
  ...actual,
676
677
  existsSync: jest.fn((candidate: string) =>
677
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
678
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
678
679
  ),
679
680
  unlinkSync: jest.fn(),
680
681
  }
@@ -691,7 +692,7 @@ describe('server dev managed process exits', () => {
691
692
  }))
692
693
  jest.doMock('child_process', () =>
693
694
  buildMockChildProcessModule((args) =>
694
- args[0]?.includes('next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
695
+ pathIncludes(args[0] ?? '', 'next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
695
696
  ),
696
697
  )
697
698
 
@@ -715,7 +716,7 @@ describe('server dev managed process exits', () => {
715
716
  return {
716
717
  ...actual,
717
718
  existsSync: jest.fn((candidate: string) =>
718
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
719
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
719
720
  ),
720
721
  unlinkSync: jest.fn(),
721
722
  }
@@ -763,7 +764,7 @@ describe('server dev managed process exits', () => {
763
764
  return {
764
765
  ...actual,
765
766
  existsSync: jest.fn((candidate: string) =>
766
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
767
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
767
768
  ),
768
769
  unlinkSync: jest.fn(),
769
770
  }
@@ -792,7 +793,7 @@ describe('server dev managed process exits', () => {
792
793
 
793
794
  jest.doMock('child_process', () =>
794
795
  buildMockChildProcessModule((args) =>
795
- args[0]?.includes('next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
796
+ pathIncludes(args[0] ?? '', 'next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
796
797
  ),
797
798
  )
798
799
 
@@ -830,7 +831,7 @@ describe('server dev managed process exits', () => {
830
831
  return {
831
832
  ...actual,
832
833
  existsSync: jest.fn((candidate: string) =>
833
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
834
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
834
835
  ),
835
836
  unlinkSync: jest.fn(),
836
837
  }
@@ -859,7 +860,7 @@ describe('server dev managed process exits', () => {
859
860
 
860
861
  jest.doMock('child_process', () =>
861
862
  buildMockChildProcessModule((args) =>
862
- args[0]?.includes('next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
863
+ pathIncludes(args[0] ?? '', 'next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
863
864
  ),
864
865
  )
865
866
 
@@ -932,7 +933,7 @@ describe('server start managed process exits', () => {
932
933
  return {
933
934
  ...actual,
934
935
  existsSync: jest.fn((candidate: string) =>
935
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
936
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
936
937
  ),
937
938
  }
938
939
  })
@@ -949,7 +950,7 @@ describe('server start managed process exits', () => {
949
950
  }))
950
951
  jest.doMock('child_process', () =>
951
952
  buildMockChildProcessModule((args) =>
952
- args[0]?.includes('next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
953
+ pathIncludes(args[0] ?? '', 'next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
953
954
  ),
954
955
  )
955
956
 
@@ -973,7 +974,7 @@ describe('server start managed process exits', () => {
973
974
  return {
974
975
  ...actual,
975
976
  existsSync: jest.fn((candidate: string) =>
976
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
977
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
977
978
  ),
978
979
  }
979
980
  })
@@ -1022,7 +1023,7 @@ describe('server start managed process exits', () => {
1022
1023
  return {
1023
1024
  ...actual,
1024
1025
  existsSync: jest.fn((candidate: string) =>
1025
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
1026
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
1026
1027
  ),
1027
1028
  unlinkSync: jest.fn(),
1028
1029
  }
@@ -1089,7 +1090,7 @@ describe('server start managed process exits', () => {
1089
1090
 
1090
1091
  return {
1091
1092
  spawn: jest.fn((_command: string, args: string[]) => {
1092
- if (args[0]?.includes('next/dist/bin/next')) {
1093
+ if (pathIncludes(args[0] ?? '', 'next/dist/bin/next')) {
1093
1094
  nextSpawnCount += 1
1094
1095
  if (nextSpawnCount === 1) {
1095
1096
  queueMicrotask(() => envChangeCallback?.('/tmp/test-app/.env'))
@@ -1106,7 +1107,7 @@ describe('server start managed process exits', () => {
1106
1107
  const exitCode = await mercado.run(['node', 'mercato', 'server', 'dev'])
1107
1108
  const { spawn } = await import('child_process')
1108
1109
  const nextSpawns = (spawn as jest.Mock).mock.calls.filter((call) =>
1109
- call[1]?.[0]?.includes('next/dist/bin/next'),
1110
+ pathIncludes(call[1]?.[0] ?? '', 'next/dist/bin/next'),
1110
1111
  )
1111
1112
 
1112
1113
  expect(exitCode).toBe(0)
@@ -1132,7 +1133,7 @@ describe('server start managed process exits', () => {
1132
1133
  return {
1133
1134
  ...actual,
1134
1135
  existsSync: jest.fn((candidate: string) =>
1135
- candidate.includes('next/dist/bin/next') || candidate.includes('@open-mercato/cli/bin/mercato'),
1136
+ pathIncludes(candidate, 'next/dist/bin/next') || pathIncludes(candidate, '@open-mercato/cli/bin/mercato'),
1136
1137
  ),
1137
1138
  }
1138
1139
  })
@@ -1159,7 +1160,7 @@ describe('server start managed process exits', () => {
1159
1160
 
1160
1161
  jest.doMock('child_process', () =>
1161
1162
  buildMockChildProcessModule((args) =>
1162
- args[0]?.includes('next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
1163
+ pathIncludes(args[0] ?? '', 'next/dist/bin/next') ? { code: null, signal: 'SIGTERM' } : undefined,
1163
1164
  ),
1164
1165
  )
1165
1166
 
@@ -2,6 +2,7 @@ import fs from 'node:fs'
2
2
  import os from 'node:os'
3
3
  import path from 'node:path'
4
4
  import { createDevEnvReloader, resolveDevEnvFilePaths } from '../dev-env-reload'
5
+ import { normalizeTestPath } from './path-helpers'
5
6
 
6
7
  describe('dev env reload helpers', () => {
7
8
  let appDir: string
@@ -15,7 +16,7 @@ describe('dev env reload helpers', () => {
15
16
  })
16
17
 
17
18
  it('resolves app env files in low-to-high dev precedence order', () => {
18
- expect(resolveDevEnvFilePaths('/tmp/app')).toEqual([
19
+ expect(resolveDevEnvFilePaths('/tmp/app').map(normalizeTestPath)).toEqual([
19
20
  '/tmp/app/.env',
20
21
  '/tmp/app/.env.development',
21
22
  '/tmp/app/.env.local',
@@ -0,0 +1,7 @@
1
+ export function normalizeTestPath(value: string): string {
2
+ return value.replace(/\\/g, '/')
3
+ }
4
+
5
+ export function pathIncludes(value: string, needle: string): boolean {
6
+ return normalizeTestPath(value).includes(normalizeTestPath(needle))
7
+ }
@@ -13,6 +13,7 @@ import fs from 'node:fs'
13
13
  import os from 'node:os'
14
14
  import path from 'node:path'
15
15
  import type { ModuleEntry, PackageResolver } from '../../resolver'
16
+ import { normalizeTestPath } from '../../__tests__/path-helpers'
16
17
 
17
18
  describe('db commands security', () => {
18
19
  describe('sanitizeModuleId', () => {
@@ -189,7 +190,7 @@ describe('resolveGeneratedMigrationPath', () => {
189
190
  '/repo/src/modules/example/migrations',
190
191
  )
191
192
 
192
- expect(result).toBe('/repo/src/modules/example/migrations/Migration20260506101927.ts')
193
+ expect(normalizeTestPath(result)).toBe('/repo/src/modules/example/migrations/Migration20260506101927.ts')
193
194
  })
194
195
 
195
196
  it('keeps absolute MikroORM results unchanged', () => {
@@ -78,6 +78,7 @@ const resolveBuildCacheFingerprint = async (
78
78
  }
79
79
 
80
80
  describe('integration cache and options', () => {
81
+ const REUSE_ENV_TEST_TIMEOUT_MS = 60000
81
82
  const ephemeralEnvFilePath = path.join(projectRootDirectory, '.ai', 'qa', 'ephemeral-env.json')
82
83
  const ephemeralLegacyEnvFilePath = path.join(projectRootDirectory, '.ai', 'qa', 'ephemeral-env.md')
83
84
  const originalCacheTtl = process.env[CACHE_TTL_ENV_VAR]
@@ -130,12 +131,20 @@ describe('integration cache and options', () => {
130
131
  await writeEphemeralEnvironmentState({
131
132
  baseUrl,
132
133
  port: 5001,
134
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
135
+ queueBaseDir: '/tmp/open-mercato-queue',
133
136
  logPrefix: 'integration',
134
137
  captureScreenshots: true,
135
138
  })
136
139
 
137
140
  const state = await readEphemeralEnvironmentState()
138
- expect(state).toMatchObject({ baseUrl, port: 5001, captureScreenshots: true })
141
+ expect(state).toMatchObject({
142
+ baseUrl,
143
+ port: 5001,
144
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
145
+ queueBaseDir: '/tmp/open-mercato-queue',
146
+ captureScreenshots: true,
147
+ })
139
148
 
140
149
  const environment = await tryReuseExistingEnvironment({
141
150
  verbose: false,
@@ -151,12 +160,16 @@ describe('integration cache and options', () => {
151
160
  ownedByCurrentProcess: false,
152
161
  })
153
162
  expect(environment?.commandEnvironment.OM_INTEGRATION_TEST).toBe('true')
163
+ expect(environment?.commandEnvironment.DATABASE_URL).toBe(
164
+ 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
165
+ )
166
+ expect(environment?.commandEnvironment.QUEUE_BASE_DIR).toBe('/tmp/open-mercato-queue')
154
167
  expect(environment?.commandEnvironment.PW_CAPTURE_SCREENSHOTS).toBe('1')
155
168
  expect(environment?.commandEnvironment.NEXT_PUBLIC_OM_EXAMPLE_CHECKOUT_TEST_INJECTIONS_ENABLED).toBeUndefined()
156
169
  } finally {
157
170
  fetchSpy.mockRestore()
158
171
  }
159
- }, 20000)
172
+ }, REUSE_ENV_TEST_TIMEOUT_MS)
160
173
 
161
174
  it('reuses an existing environment with checkout wrapper injections only when explicitly enabled', async () => {
162
175
  const baseUrl = 'http://127.0.0.1:5001'
@@ -167,6 +180,8 @@ describe('integration cache and options', () => {
167
180
  await writeEphemeralEnvironmentState({
168
181
  baseUrl,
169
182
  port: 5001,
183
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
184
+ queueBaseDir: '/tmp/open-mercato-queue',
170
185
  logPrefix: 'integration',
171
186
  captureScreenshots: true,
172
187
  })
@@ -184,7 +199,7 @@ describe('integration cache and options', () => {
184
199
  } finally {
185
200
  fetchSpy.mockRestore()
186
201
  }
187
- }, 20000)
202
+ }, REUSE_ENV_TEST_TIMEOUT_MS)
188
203
 
189
204
  it('reuses an existing environment when /login returns a redirect status other than 302', async () => {
190
205
  const baseUrl = 'http://127.0.0.1:5001'
@@ -196,6 +211,8 @@ describe('integration cache and options', () => {
196
211
  await writeEphemeralEnvironmentState({
197
212
  baseUrl,
198
213
  port: 5001,
214
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
215
+ queueBaseDir: '/tmp/open-mercato-queue',
199
216
  logPrefix: 'integration',
200
217
  captureScreenshots: true,
201
218
  })
@@ -216,7 +233,7 @@ describe('integration cache and options', () => {
216
233
  } finally {
217
234
  fetchSpy.mockRestore()
218
235
  }
219
- }, 20000)
236
+ }, REUSE_ENV_TEST_TIMEOUT_MS)
220
237
 
221
238
  it('reuses an existing environment when /login returns healthy HTML without static asset references', async () => {
222
239
  const baseUrl = 'http://127.0.0.1:5001'
@@ -231,6 +248,8 @@ describe('integration cache and options', () => {
231
248
  await writeEphemeralEnvironmentState({
232
249
  baseUrl,
233
250
  port: 5001,
251
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
252
+ queueBaseDir: '/tmp/open-mercato-queue',
234
253
  logPrefix: 'integration',
235
254
  captureScreenshots: false,
236
255
  })
@@ -251,7 +270,7 @@ describe('integration cache and options', () => {
251
270
  } finally {
252
271
  fetchSpy.mockRestore()
253
272
  }
254
- }, 20000)
273
+ }, REUSE_ENV_TEST_TIMEOUT_MS)
255
274
 
256
275
  it('falls back to rebuilding when the ephemeral environment state is unreachable', async () => {
257
276
  const baseUrl = 'http://127.0.0.1:5001'
@@ -261,6 +280,8 @@ describe('integration cache and options', () => {
261
280
  await writeEphemeralEnvironmentState({
262
281
  baseUrl,
263
282
  port: 5001,
283
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
284
+ queueBaseDir: '/tmp/open-mercato-queue',
264
285
  logPrefix: 'integration',
265
286
  captureScreenshots: false,
266
287
  })
@@ -289,6 +310,8 @@ describe('integration cache and options', () => {
289
310
  await writeEphemeralEnvironmentState({
290
311
  baseUrl,
291
312
  port: 5001,
313
+ databaseUrl: 'postgres://integration:integration@127.0.0.1:5432/open_mercato',
314
+ queueBaseDir: '/tmp/open-mercato-queue',
292
315
  logPrefix: 'integration',
293
316
  captureScreenshots: true,
294
317
  })
@@ -138,6 +138,8 @@ type EphemeralEnvironmentState = {
138
138
  status: 'running'
139
139
  baseUrl: string
140
140
  port: number
141
+ databaseUrl: string
142
+ queueBaseDir: string
141
143
  source: string
142
144
  captureScreenshots: boolean
143
145
  startedAt: string
@@ -1168,6 +1170,8 @@ async function getPreferredPort(preferredPort: number): Promise<number> {
1168
1170
  export async function writeEphemeralEnvironmentState(input: {
1169
1171
  baseUrl: string
1170
1172
  port: number
1173
+ databaseUrl: string
1174
+ queueBaseDir: string
1171
1175
  logPrefix: string
1172
1176
  captureScreenshots: boolean
1173
1177
  }): Promise<void> {
@@ -1175,6 +1179,8 @@ export async function writeEphemeralEnvironmentState(input: {
1175
1179
  status: 'running',
1176
1180
  baseUrl: input.baseUrl,
1177
1181
  port: input.port,
1182
+ databaseUrl: input.databaseUrl,
1183
+ queueBaseDir: input.queueBaseDir,
1178
1184
  source: input.logPrefix,
1179
1185
  captureScreenshots: input.captureScreenshots,
1180
1186
  startedAt: new Date().toISOString(),
@@ -1219,6 +1225,12 @@ export async function readEphemeralEnvironmentState(): Promise<EphemeralEnvironm
1219
1225
  if (typeof record.port !== 'number' || !Number.isFinite(record.port) || record.port < 1) {
1220
1226
  return null
1221
1227
  }
1228
+ if (typeof record.databaseUrl !== 'string' || record.databaseUrl.length === 0) {
1229
+ return null
1230
+ }
1231
+ if (typeof record.queueBaseDir !== 'string' || record.queueBaseDir.length === 0) {
1232
+ return null
1233
+ }
1222
1234
  if (typeof record.source !== 'string' || record.source.length === 0) {
1223
1235
  return null
1224
1236
  }
@@ -1233,6 +1245,8 @@ export async function readEphemeralEnvironmentState(): Promise<EphemeralEnvironm
1233
1245
  status: 'running',
1234
1246
  baseUrl: record.baseUrl,
1235
1247
  port: record.port,
1248
+ databaseUrl: record.databaseUrl,
1249
+ queueBaseDir: record.queueBaseDir,
1236
1250
  source: record.source,
1237
1251
  captureScreenshots: record.captureScreenshots,
1238
1252
  startedAt: record.startedAt,
@@ -1614,9 +1628,15 @@ export async function acquireEphemeralRuntimeLock(
1614
1628
  }
1615
1629
  }
1616
1630
 
1617
- function buildReusableEnvironment(baseUrl: string, captureScreenshots: boolean): NodeJS.ProcessEnv {
1631
+ function buildReusableEnvironment(
1632
+ baseUrl: string,
1633
+ databaseUrl: string,
1634
+ queueBaseDir: string,
1635
+ captureScreenshots: boolean,
1636
+ ): NodeJS.ProcessEnv {
1618
1637
  const enterpriseModulesFlag = process.env.OM_ENABLE_ENTERPRISE_MODULES ?? 'false'
1619
1638
  return buildEnvironment({
1639
+ DATABASE_URL: databaseUrl,
1620
1640
  BASE_URL: baseUrl,
1621
1641
  APP_URL: baseUrl,
1622
1642
  NEXT_PUBLIC_APP_URL: baseUrl,
@@ -1639,6 +1659,7 @@ function buildReusableEnvironment(baseUrl: string, captureScreenshots: boolean):
1639
1659
  TENANT_DATA_ENCRYPTION_FALLBACK_KEY: process.env.TENANT_DATA_ENCRYPTION_FALLBACK_KEY ?? 'om-ephemeral-integration-fallback-key',
1640
1660
  OM_CLI_QUIET: '1',
1641
1661
  MERCATO_QUIET: '1',
1662
+ QUEUE_BASE_DIR: queueBaseDir,
1642
1663
  NODE_NO_WARNINGS: '1',
1643
1664
  PW_CAPTURE_SCREENSHOTS: captureScreenshots ? '1' : '0',
1644
1665
  })
@@ -1695,8 +1716,13 @@ export async function tryReuseExistingEnvironment(options: EphemeralRuntimeOptio
1695
1716
  return {
1696
1717
  baseUrl: state.baseUrl,
1697
1718
  port: state.port,
1698
- databaseUrl: '',
1699
- commandEnvironment: buildReusableEnvironment(state.baseUrl, state.captureScreenshots),
1719
+ databaseUrl: state.databaseUrl,
1720
+ commandEnvironment: buildReusableEnvironment(
1721
+ state.baseUrl,
1722
+ state.databaseUrl,
1723
+ state.queueBaseDir,
1724
+ state.captureScreenshots,
1725
+ ),
1700
1726
  ownedByCurrentProcess: false,
1701
1727
  stop: async () => {},
1702
1728
  }
@@ -3030,6 +3056,8 @@ export async function startEphemeralEnvironment(options: EphemeralRuntimeOptions
3030
3056
  await writeEphemeralEnvironmentState({
3031
3057
  baseUrl: applicationBaseUrl,
3032
3058
  port: applicationPort,
3059
+ databaseUrl,
3060
+ queueBaseDir: EPHEMERAL_QUEUE_BASE_DIR,
3033
3061
  logPrefix: options.logPrefix,
3034
3062
  captureScreenshots: options.captureScreenshots,
3035
3063
  })