sounding 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +334 -1
- package/bin/sounding.js +156 -0
- package/index.js +23 -0
- package/lib/create-app-manager.js +380 -26
- package/lib/create-auth-helpers.js +168 -21
- package/lib/create-browser-manager.js +578 -31
- package/lib/create-error.js +35 -0
- package/lib/create-expect.js +1070 -27
- package/lib/create-helper-runner.js +38 -2
- package/lib/create-mail-capture.js +125 -16
- package/lib/create-mailbox.js +20 -0
- package/lib/create-request-client.js +635 -57
- package/lib/create-runtime.js +222 -21
- package/lib/create-socket-manager.js +706 -0
- package/lib/create-test-api.js +491 -102
- package/lib/create-visit-client.js +40 -2
- package/lib/create-world-engine.js +106 -7
- package/lib/create-world-loader.js +150 -8
- package/lib/default-config.js +25 -0
- package/lib/define-world.js +27 -2
- package/lib/init-project.js +403 -0
- package/lib/merge-config.js +11 -0
- package/lib/normalize-config.js +16 -19
- package/lib/resolve-auth-config.js +36 -0
- package/lib/resolve-datastore.js +50 -7
- package/lib/resolve-dependency.js +145 -0
- package/lib/test-runner.js +427 -0
- package/lib/trial-context.js +29 -0
- package/lib/types.js +675 -0
- package/lib/validate-config.js +633 -0
- package/lib/validate-test-args.js +480 -0
- package/package.json +16 -2
|
@@ -5,28 +5,93 @@ const { getDefaultConfig } = require('./default-config')
|
|
|
5
5
|
const { mergeConfig } = require('./merge-config')
|
|
6
6
|
const { normalizeUserConfig } = require('./normalize-config')
|
|
7
7
|
const { buildManagedSqlitePath, resolveManagedRoot } = require('./resolve-datastore')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const { createSoundingError } = require('./create-error')
|
|
9
|
+
const { loadDependencyFromApp, resolveDependencyFromApp } = require('./resolve-dependency')
|
|
10
|
+
const { validateConfig } = require('./validate-config')
|
|
11
|
+
|
|
12
|
+
/** @typedef {import('./types').AnyRecord} AnyRecord */
|
|
13
|
+
/** @typedef {import('./types').SoundingAppManager} SoundingAppManager */
|
|
14
|
+
/** @typedef {import('./types').SoundingAppManagerOptions} SoundingAppManagerOptions */
|
|
15
|
+
/** @typedef {import('./types').SoundingConfig} SoundingConfig */
|
|
16
|
+
/** @typedef {import('./types').SoundingRuntime} SoundingRuntime */
|
|
17
|
+
/** @typedef {import('./types').SoundingSailsApp} SoundingSailsApp */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} appPath
|
|
21
|
+
* @returns {SoundingConfig}
|
|
22
|
+
*/
|
|
13
23
|
function loadAppSoundingConfig(appPath) {
|
|
14
24
|
const configPath = path.join(appPath, 'config', 'sounding.js')
|
|
15
25
|
|
|
16
26
|
if (!fs.existsSync(configPath)) {
|
|
17
|
-
return getDefaultConfig()
|
|
27
|
+
return validateConfig(getDefaultConfig())
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
delete require.cache[require.resolve(configPath)]
|
|
21
31
|
const loaded = require(configPath)
|
|
22
|
-
return
|
|
32
|
+
return validateConfig(
|
|
33
|
+
/** @type {SoundingConfig} */ (
|
|
34
|
+
mergeConfig(getDefaultConfig(), normalizeUserConfig(loaded?.sounding || {}))
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} appPath
|
|
41
|
+
* @param {{ resolveImplementation?: (moduleId: string, options?: { paths?: string[] }) => string }} [options]
|
|
42
|
+
* @returns {any}
|
|
43
|
+
*/
|
|
44
|
+
function defaultLoadSails(appPath, options = {}) {
|
|
45
|
+
return loadDependencyFromApp({
|
|
46
|
+
appPath,
|
|
47
|
+
moduleId: 'sails',
|
|
48
|
+
purpose: 'load your Sails app',
|
|
49
|
+
install: 'npm install sails',
|
|
50
|
+
resolveImplementation: options.resolveImplementation,
|
|
51
|
+
})
|
|
23
52
|
}
|
|
24
53
|
|
|
25
|
-
|
|
54
|
+
/**
|
|
55
|
+
* @param {SoundingConfig} config
|
|
56
|
+
* @param {string} appPath
|
|
57
|
+
* @param {{ resolveImplementation?: (moduleId: string, options?: { paths?: string[] }) => string }} [options]
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
function assertManagedDatastoreDependency(config, appPath, options = {}) {
|
|
61
|
+
if (config.datastore?.mode !== 'managed') {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const adapter = config.datastore.adapter || 'sails-sqlite'
|
|
66
|
+
|
|
67
|
+
if (adapter !== 'sails-sqlite') {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
resolveDependencyFromApp({
|
|
72
|
+
appPath,
|
|
73
|
+
moduleId: adapter,
|
|
74
|
+
purpose: 'run managed datastore trials',
|
|
75
|
+
install: 'npm install -D sails-sqlite',
|
|
76
|
+
suggestion:
|
|
77
|
+
'Or set `sounding.datastore` to `inherit` or configure an external datastore if this app should reuse its own test database.',
|
|
78
|
+
resolveImplementation: options.resolveImplementation,
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {SoundingConfig} config
|
|
84
|
+
* @param {string} appPath
|
|
85
|
+
* @param {{ resolveImplementation?: (moduleId: string, options?: { paths?: string[] }) => string }} [options]
|
|
86
|
+
* @returns {AnyRecord}
|
|
87
|
+
*/
|
|
88
|
+
function buildManagedDatastoreOverrides(config, appPath, options = {}) {
|
|
26
89
|
if (config.datastore?.mode !== 'managed') {
|
|
27
90
|
return {}
|
|
28
91
|
}
|
|
29
92
|
|
|
93
|
+
assertManagedDatastoreDependency(config, appPath, options)
|
|
94
|
+
|
|
30
95
|
const identity = config.datastore.identity || 'default'
|
|
31
96
|
|
|
32
97
|
return {
|
|
@@ -49,6 +114,10 @@ function buildManagedDatastoreOverrides(config, appPath) {
|
|
|
49
114
|
}
|
|
50
115
|
}
|
|
51
116
|
|
|
117
|
+
/**
|
|
118
|
+
* @param {Partial<SoundingConfig>} [config]
|
|
119
|
+
* @returns {{ install(): void, uninstall(): void }}
|
|
120
|
+
*/
|
|
52
121
|
function createOutputFilter(config = {}) {
|
|
53
122
|
if (config.app?.quiet === false) {
|
|
54
123
|
return {
|
|
@@ -121,6 +190,76 @@ function createOutputFilter(config = {}) {
|
|
|
121
190
|
}
|
|
122
191
|
}
|
|
123
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @param {'load' | 'lift'} mode
|
|
195
|
+
* @returns {import('./types').SoundingAppLifecycleState}
|
|
196
|
+
*/
|
|
197
|
+
function createLifecycleState(mode) {
|
|
198
|
+
return {
|
|
199
|
+
mode,
|
|
200
|
+
status: 'idle',
|
|
201
|
+
runs: 0,
|
|
202
|
+
reuses: 0,
|
|
203
|
+
reloads: 0,
|
|
204
|
+
durationMs: null,
|
|
205
|
+
startedAt: null,
|
|
206
|
+
readyAt: null,
|
|
207
|
+
error: null,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @returns {boolean}
|
|
213
|
+
*/
|
|
214
|
+
function shouldReportLifecycle() {
|
|
215
|
+
return (
|
|
216
|
+
process.env.SOUNDING_LIFECYCLE === 'verbose' ||
|
|
217
|
+
process.env.SOUNDING_DIAGNOSTICS === 'verbose'
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param {string} message
|
|
223
|
+
* @returns {void}
|
|
224
|
+
*/
|
|
225
|
+
function reportLifecycle(message) {
|
|
226
|
+
if (!shouldReportLifecycle()) {
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
process.stderr.write(`[sounding] ${message}\n`)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @param {string} method
|
|
235
|
+
* @param {Record<string, any>} options
|
|
236
|
+
* @param {string[]} allowed
|
|
237
|
+
* @returns {void}
|
|
238
|
+
*/
|
|
239
|
+
function assertKnownAppManagerOptions(method, options, allowed) {
|
|
240
|
+
const unknown = Object.keys(options || {}).filter((key) => !allowed.includes(key))
|
|
241
|
+
|
|
242
|
+
if (unknown.length === 0) {
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
throw createSoundingError({
|
|
247
|
+
code: 'E_SOUNDING_APP_MANAGER_OPTION_UNKNOWN',
|
|
248
|
+
name: 'SoundingAppLifecycleError',
|
|
249
|
+
message: `Sounding app manager option \`${unknown[0]}\` is not supported for ${method}().`,
|
|
250
|
+
details: {
|
|
251
|
+
option: unknown[0],
|
|
252
|
+
allowed,
|
|
253
|
+
method,
|
|
254
|
+
},
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @param {SoundingConfig} config
|
|
260
|
+
* @param {string} appPath
|
|
261
|
+
* @returns {string | null}
|
|
262
|
+
*/
|
|
124
263
|
function resolveManagedDatastoreFile(config, appPath) {
|
|
125
264
|
if (config.datastore?.mode !== 'managed') {
|
|
126
265
|
return null
|
|
@@ -138,11 +277,16 @@ function resolveManagedDatastoreFile(config, appPath) {
|
|
|
138
277
|
})
|
|
139
278
|
}
|
|
140
279
|
|
|
280
|
+
/**
|
|
281
|
+
* @param {SoundingAppManagerOptions} [options]
|
|
282
|
+
* @returns {SoundingAppManager}
|
|
283
|
+
*/
|
|
141
284
|
function createAppManager({
|
|
142
285
|
appPath = process.cwd(),
|
|
143
286
|
environment = 'test',
|
|
144
287
|
liftOptions = {},
|
|
145
288
|
SailsConstructor,
|
|
289
|
+
loadSails = defaultLoadSails,
|
|
146
290
|
} = {}) {
|
|
147
291
|
let loadedApp = null
|
|
148
292
|
let liftedApp = null
|
|
@@ -150,6 +294,10 @@ function createAppManager({
|
|
|
150
294
|
let liftPromise = null
|
|
151
295
|
const managedArtifacts = new Set()
|
|
152
296
|
let outputFilter = null
|
|
297
|
+
const lifecycle = {
|
|
298
|
+
load: createLifecycleState('load'),
|
|
299
|
+
lift: createLifecycleState('lift'),
|
|
300
|
+
}
|
|
153
301
|
|
|
154
302
|
function resolveAppPath() {
|
|
155
303
|
return path.resolve(appPath)
|
|
@@ -164,7 +312,7 @@ function createAppManager({
|
|
|
164
312
|
return SailsConstructor
|
|
165
313
|
}
|
|
166
314
|
|
|
167
|
-
return
|
|
315
|
+
return loadSails(resolveAppPath()).constructor
|
|
168
316
|
}
|
|
169
317
|
|
|
170
318
|
function buildOptions(mode) {
|
|
@@ -176,7 +324,9 @@ function createAppManager({
|
|
|
176
324
|
managedArtifacts.add(managedFile)
|
|
177
325
|
}
|
|
178
326
|
|
|
327
|
+
/** @type {AnyRecord} */
|
|
179
328
|
const appConfig = config.app || {}
|
|
329
|
+
/** @type {AnyRecord} */
|
|
180
330
|
const baseOptions = {
|
|
181
331
|
appPath: resolveAppPath(),
|
|
182
332
|
environment: appConfig.environment || environment,
|
|
@@ -194,6 +344,7 @@ function createAppManager({
|
|
|
194
344
|
appConfig.loadOptions || {}
|
|
195
345
|
)
|
|
196
346
|
: mergeConfig(appConfig.liftOptions || {}, liftOptions)
|
|
347
|
+
/** @type {AnyRecord} */
|
|
197
348
|
const nextOptions = mergeConfig(baseOptions, modeOptions)
|
|
198
349
|
|
|
199
350
|
if (mode === 'load' && nextOptions.datastores?.content) {
|
|
@@ -218,33 +369,199 @@ function createAppManager({
|
|
|
218
369
|
}
|
|
219
370
|
}
|
|
220
371
|
|
|
221
|
-
|
|
372
|
+
/**
|
|
373
|
+
* @param {SoundingSailsApp} app
|
|
374
|
+
* @returns {void}
|
|
375
|
+
*/
|
|
376
|
+
function activateGlobalApp(app) {
|
|
377
|
+
globalThis.sails = app
|
|
378
|
+
globalThis.sounding = app.sounding || app.hooks?.sounding
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @returns {void}
|
|
383
|
+
*/
|
|
384
|
+
function syncGlobalApp() {
|
|
385
|
+
const activeApp = liftedApp || loadedApp
|
|
386
|
+
|
|
387
|
+
if (activeApp) {
|
|
388
|
+
activateGlobalApp(activeApp)
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
delete globalThis.sails
|
|
393
|
+
delete globalThis.sounding
|
|
394
|
+
outputFilter?.uninstall()
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* @param {'load' | 'lift'} mode
|
|
399
|
+
* @returns {void}
|
|
400
|
+
*/
|
|
401
|
+
function recordLifecycleStart(mode) {
|
|
402
|
+
const entry = lifecycle[mode]
|
|
403
|
+
entry.status = 'loading'
|
|
404
|
+
entry.runs += 1
|
|
405
|
+
entry.error = null
|
|
406
|
+
entry.startedAt = new Date().toISOString()
|
|
407
|
+
entry.readyAt = null
|
|
408
|
+
entry.durationMs = null
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* @param {'load' | 'lift'} mode
|
|
413
|
+
* @param {number} startedAt
|
|
414
|
+
* @returns {void}
|
|
415
|
+
*/
|
|
416
|
+
function recordLifecycleReady(mode, startedAt) {
|
|
417
|
+
const entry = lifecycle[mode]
|
|
418
|
+
entry.status = 'ready'
|
|
419
|
+
entry.durationMs = Date.now() - startedAt
|
|
420
|
+
entry.readyAt = new Date().toISOString()
|
|
421
|
+
reportLifecycle(`app ${mode} ready in ${entry.durationMs}ms`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @param {'load' | 'lift'} mode
|
|
426
|
+
* @param {unknown} error
|
|
427
|
+
* @returns {void}
|
|
428
|
+
*/
|
|
429
|
+
function recordLifecycleError(mode, error) {
|
|
430
|
+
const entry = lifecycle[mode]
|
|
431
|
+
entry.status = 'error'
|
|
432
|
+
entry.error = error instanceof Error ? error.message : String(error)
|
|
433
|
+
reportLifecycle(`app ${mode} failed: ${entry.error}`)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @param {'load' | 'lift'} mode
|
|
438
|
+
* @returns {void}
|
|
439
|
+
*/
|
|
440
|
+
function recordLifecycleReuse(mode) {
|
|
441
|
+
const entry = lifecycle[mode]
|
|
442
|
+
entry.reuses += 1
|
|
443
|
+
reportLifecycle(`app ${mode} reused warm instance`)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @param {'load' | 'lift'} mode
|
|
448
|
+
* @returns {void}
|
|
449
|
+
*/
|
|
450
|
+
function recordLifecycleReload(mode) {
|
|
451
|
+
lifecycle[mode].reloads += 1
|
|
452
|
+
reportLifecycle(`app ${mode} reload requested`)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* @param {'load' | 'lift'} mode
|
|
457
|
+
* @returns {void}
|
|
458
|
+
*/
|
|
459
|
+
function recordLifecycleIdle(mode) {
|
|
460
|
+
lifecycle[mode].status = 'idle'
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* @param {SoundingSailsApp} app
|
|
465
|
+
* @returns {Promise<void>}
|
|
466
|
+
*/
|
|
467
|
+
async function lowerApp(app) {
|
|
468
|
+
await new Promise((resolve) => {
|
|
469
|
+
app.lower(() => resolve())
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* @param {'load' | 'lift'} mode
|
|
475
|
+
* @returns {Promise<void>}
|
|
476
|
+
*/
|
|
477
|
+
async function lowerMode(mode) {
|
|
478
|
+
const app = mode === 'load' ? loadedApp : liftedApp
|
|
479
|
+
|
|
480
|
+
if (mode === 'load') {
|
|
481
|
+
loadedApp = null
|
|
482
|
+
loadPromise = null
|
|
483
|
+
} else {
|
|
484
|
+
liftedApp = null
|
|
485
|
+
liftPromise = null
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (app) {
|
|
489
|
+
await lowerApp(app)
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
recordLifecycleIdle(mode)
|
|
493
|
+
syncGlobalApp()
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @param {'load' | 'lift'} mode
|
|
498
|
+
* @param {{ reload?: boolean }} [options]
|
|
499
|
+
* @returns {Promise<void>}
|
|
500
|
+
*/
|
|
501
|
+
async function prepareReload(mode, options = {}) {
|
|
502
|
+
if (!options.reload) {
|
|
503
|
+
return
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
recordLifecycleReload(mode)
|
|
507
|
+
|
|
508
|
+
if (mode === 'load' && loadPromise) {
|
|
509
|
+
await loadPromise.catch(() => {})
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (mode === 'lift' && liftPromise) {
|
|
513
|
+
await liftPromise.catch(() => {})
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
await lowerMode(mode)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @returns {SoundingAppManager['lifecycle']}
|
|
521
|
+
*/
|
|
522
|
+
function getLifecycleSnapshot() {
|
|
523
|
+
return {
|
|
524
|
+
load: { ...lifecycle.load },
|
|
525
|
+
lift: { ...lifecycle.lift },
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async function load(options = {}) {
|
|
530
|
+
assertKnownAppManagerOptions('load', options, ['reload'])
|
|
531
|
+
await prepareReload('load', options)
|
|
532
|
+
|
|
222
533
|
if (loadedApp) {
|
|
534
|
+
activateGlobalApp(loadedApp)
|
|
535
|
+
recordLifecycleReuse('load')
|
|
223
536
|
return loadedApp
|
|
224
537
|
}
|
|
225
538
|
|
|
226
539
|
if (loadPromise) {
|
|
540
|
+
recordLifecycleReuse('load')
|
|
227
541
|
return loadPromise
|
|
228
542
|
}
|
|
229
543
|
|
|
230
544
|
const Sails = resolveSailsConstructor()
|
|
231
545
|
const sailsApp = new Sails()
|
|
232
546
|
const nextLoadOptions = buildOptions('load')
|
|
547
|
+
const startedAt = Date.now()
|
|
548
|
+
recordLifecycleStart('load')
|
|
233
549
|
outputFilter?.install()
|
|
234
550
|
|
|
235
551
|
loadPromise = new Promise((resolve, reject) => {
|
|
236
552
|
sailsApp.load(nextLoadOptions, (error, loadedSails) => {
|
|
237
553
|
if (error) {
|
|
238
554
|
loadPromise = null
|
|
555
|
+
recordLifecycleError('load', error)
|
|
239
556
|
cleanupManagedArtifacts().catch(() => {})
|
|
240
|
-
|
|
557
|
+
syncGlobalApp()
|
|
241
558
|
reject(error)
|
|
242
559
|
return
|
|
243
560
|
}
|
|
244
561
|
|
|
245
562
|
loadedApp = loadedSails
|
|
246
|
-
|
|
247
|
-
|
|
563
|
+
activateGlobalApp(loadedSails)
|
|
564
|
+
recordLifecycleReady('load', startedAt)
|
|
248
565
|
resolve(loadedSails)
|
|
249
566
|
})
|
|
250
567
|
})
|
|
@@ -252,33 +569,42 @@ function createAppManager({
|
|
|
252
569
|
return loadPromise
|
|
253
570
|
}
|
|
254
571
|
|
|
255
|
-
async function lift() {
|
|
572
|
+
async function lift(options = {}) {
|
|
573
|
+
assertKnownAppManagerOptions('lift', options, ['reload'])
|
|
574
|
+
await prepareReload('lift', options)
|
|
575
|
+
|
|
256
576
|
if (liftedApp) {
|
|
577
|
+
activateGlobalApp(liftedApp)
|
|
578
|
+
recordLifecycleReuse('lift')
|
|
257
579
|
return liftedApp
|
|
258
580
|
}
|
|
259
581
|
|
|
260
582
|
if (liftPromise) {
|
|
583
|
+
recordLifecycleReuse('lift')
|
|
261
584
|
return liftPromise
|
|
262
585
|
}
|
|
263
586
|
|
|
264
587
|
const Sails = resolveSailsConstructor()
|
|
265
588
|
const sailsApp = new Sails()
|
|
266
589
|
const nextLiftOptions = buildOptions('lift')
|
|
590
|
+
const startedAt = Date.now()
|
|
591
|
+
recordLifecycleStart('lift')
|
|
267
592
|
outputFilter?.install()
|
|
268
593
|
|
|
269
594
|
liftPromise = new Promise((resolve, reject) => {
|
|
270
595
|
sailsApp.lift(nextLiftOptions, (error, liftedSails) => {
|
|
271
596
|
if (error) {
|
|
272
597
|
liftPromise = null
|
|
598
|
+
recordLifecycleError('lift', error)
|
|
273
599
|
cleanupManagedArtifacts().catch(() => {})
|
|
274
|
-
|
|
600
|
+
syncGlobalApp()
|
|
275
601
|
reject(error)
|
|
276
602
|
return
|
|
277
603
|
}
|
|
278
604
|
|
|
279
605
|
liftedApp = liftedSails
|
|
280
|
-
|
|
281
|
-
|
|
606
|
+
activateGlobalApp(liftedSails)
|
|
607
|
+
recordLifecycleReady('lift', startedAt)
|
|
282
608
|
resolve(liftedSails)
|
|
283
609
|
})
|
|
284
610
|
})
|
|
@@ -286,8 +612,35 @@ function createAppManager({
|
|
|
286
612
|
return liftPromise
|
|
287
613
|
}
|
|
288
614
|
|
|
615
|
+
function resolveRuntimeMode(options = {}) {
|
|
616
|
+
if (options.app !== undefined) {
|
|
617
|
+
if (options.app === 'load' || options.app === 'lift') {
|
|
618
|
+
return options.app
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
throw createSoundingError({
|
|
622
|
+
code: 'E_SOUNDING_APP_MODE_UNKNOWN',
|
|
623
|
+
name: 'SoundingAppLifecycleError',
|
|
624
|
+
message: `Sounding app lifecycle mode must be \`load\` or \`lift\`. Received \`${options.app}\`.`,
|
|
625
|
+
details: {
|
|
626
|
+
app: options.app,
|
|
627
|
+
allowed: ['load', 'lift'],
|
|
628
|
+
},
|
|
629
|
+
})
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (options.transport === 'http') {
|
|
633
|
+
return 'lift'
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return 'load'
|
|
637
|
+
}
|
|
638
|
+
|
|
289
639
|
async function runtime(options = {}) {
|
|
290
|
-
|
|
640
|
+
assertKnownAppManagerOptions('runtime', options, ['app', 'transport', 'reload'])
|
|
641
|
+
const mode = resolveRuntimeMode(options)
|
|
642
|
+
const lifecycleOptions = { reload: options.reload }
|
|
643
|
+
const app = mode === 'lift' ? await lift(lifecycleOptions) : await load(lifecycleOptions)
|
|
291
644
|
return app.sounding || app.hooks?.sounding
|
|
292
645
|
}
|
|
293
646
|
|
|
@@ -299,18 +652,13 @@ function createAppManager({
|
|
|
299
652
|
loadPromise = null
|
|
300
653
|
liftPromise = null
|
|
301
654
|
|
|
302
|
-
await Promise.all(
|
|
303
|
-
apps.map(
|
|
304
|
-
(app) =>
|
|
305
|
-
new Promise((resolve) => {
|
|
306
|
-
app.lower(() => resolve())
|
|
307
|
-
})
|
|
308
|
-
)
|
|
309
|
-
)
|
|
655
|
+
await Promise.all(apps.map((app) => lowerApp(app)))
|
|
310
656
|
|
|
311
657
|
delete globalThis.sails
|
|
312
658
|
delete globalThis.sounding
|
|
313
659
|
outputFilter?.uninstall()
|
|
660
|
+
recordLifecycleIdle('load')
|
|
661
|
+
recordLifecycleIdle('lift')
|
|
314
662
|
await cleanupManagedArtifacts()
|
|
315
663
|
}
|
|
316
664
|
|
|
@@ -320,10 +668,16 @@ function createAppManager({
|
|
|
320
668
|
runtime,
|
|
321
669
|
lower,
|
|
322
670
|
resolveConfig,
|
|
671
|
+
get lifecycle() {
|
|
672
|
+
return getLifecycleSnapshot()
|
|
673
|
+
},
|
|
323
674
|
}
|
|
324
675
|
}
|
|
325
676
|
|
|
326
677
|
module.exports = {
|
|
678
|
+
assertManagedDatastoreDependency,
|
|
679
|
+
buildManagedDatastoreOverrides,
|
|
327
680
|
createAppManager,
|
|
681
|
+
defaultLoadSails,
|
|
328
682
|
loadAppSoundingConfig,
|
|
329
683
|
}
|