@open-mercato/cli 0.6.2-develop.3461.1.605f31c2c9 → 0.6.2
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/dist/lib/generators/extensions/notifications.js +14 -4
- package/dist/lib/generators/extensions/notifications.js.map +2 -2
- package/dist/lib/generators/module-registry.js +66 -9
- package/dist/lib/generators/module-registry.js.map +3 -3
- package/dist/lib/testing/integration.js +35 -7
- package/dist/lib/testing/integration.js.map +2 -2
- package/jest.config.cjs +3 -1
- package/package.json +13 -14
- package/src/__tests__/mercato.test.ts +16 -15
- package/src/lib/__tests__/dev-env-reload.test.ts +2 -1
- package/src/lib/__tests__/path-helpers.ts +7 -0
- package/src/lib/db/__tests__/commands.test.ts +2 -1
- package/src/lib/generators/__tests__/module-subset.test.ts +142 -0
- package/src/lib/generators/extensions/notifications.ts +14 -4
- package/src/lib/generators/module-registry.ts +84 -10
- package/src/lib/testing/__tests__/integration.test.ts +28 -5
- package/src/lib/testing/integration.ts +44 -7
|
@@ -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({
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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(
|
|
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(
|
|
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
|
}
|
|
@@ -2880,10 +2906,19 @@ export async function startEphemeralEnvironment(options: EphemeralRuntimeOptions
|
|
|
2880
2906
|
JWT_SECRET: process.env.JWT_SECRET ?? 'om-ephemeral-integration-jwt-secret',
|
|
2881
2907
|
OM_SECURITY_MFA_SETUP_SECRET: process.env.OM_SECURITY_MFA_SETUP_SECRET ?? 'om-ephemeral-integration-mfa-setup-secret',
|
|
2882
2908
|
NODE_ENV: 'production',
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2909
|
+
// Pool sizing for the ephemeral integration runtime. Defaults were once
|
|
2910
|
+
// very aggressive (max=5, idle=1000) which exposed flaky 'timeout exceeded
|
|
2911
|
+
// when trying to connect' errors on `progressService.createJob`-backed
|
|
2912
|
+
// endpoints (sync_excel.import, data_sync.run, progress.jobs) — each
|
|
2913
|
+
// request acquires a transaction connection plus a separate connection
|
|
2914
|
+
// for the encryption subscriber's fetchMap probe, and with 1s idle close
|
|
2915
|
+
// the pool thrashes faster than pg-pool can repopulate. These values
|
|
2916
|
+
// still keep the pool tighter than production but give enough headroom
|
|
2917
|
+
// for the legitimate query bursts.
|
|
2918
|
+
DB_POOL_MIN: '2',
|
|
2919
|
+
DB_POOL_MAX: '20',
|
|
2920
|
+
DB_POOL_IDLE_TIMEOUT: '10000',
|
|
2921
|
+
DB_POOL_ACQUIRE_TIMEOUT: '15000',
|
|
2887
2922
|
DB_IDLE_SESSION_TIMEOUT_MS: '30000',
|
|
2888
2923
|
DB_IDLE_IN_TRANSACTION_TIMEOUT_MS: '30000',
|
|
2889
2924
|
OM_INTEGRATION_TEST: 'true',
|
|
@@ -3030,6 +3065,8 @@ export async function startEphemeralEnvironment(options: EphemeralRuntimeOptions
|
|
|
3030
3065
|
await writeEphemeralEnvironmentState({
|
|
3031
3066
|
baseUrl: applicationBaseUrl,
|
|
3032
3067
|
port: applicationPort,
|
|
3068
|
+
databaseUrl,
|
|
3069
|
+
queueBaseDir: EPHEMERAL_QUEUE_BASE_DIR,
|
|
3033
3070
|
logPrefix: options.logPrefix,
|
|
3034
3071
|
captureScreenshots: options.captureScreenshots,
|
|
3035
3072
|
})
|