repluggable-core 0.0.0-pr351.71 → 0.0.0-pr351.73
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/es/src/repluggableAppDebug/index.d.ts +1 -1
- package/dist/es/src/repluggableAppDebug/index.d.ts.map +1 -1
- package/dist/es/src/repluggableAppDebug/index.js.map +1 -1
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts +0 -20
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -1
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js +13 -47
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -1
- package/dist/es/test/repluggableAppDebug.spec.js +7 -108
- package/dist/es/test/repluggableAppDebug.spec.js.map +1 -1
- package/dist/es/test/testKit.spec.js +5 -16
- package/dist/es/test/testKit.spec.js.map +1 -1
- package/dist/es/testKit/index.d.ts +1 -10
- package/dist/es/testKit/index.d.ts.map +1 -1
- package/dist/es/testKit/index.js +11 -54
- package/dist/es/testKit/index.js.map +1 -1
- package/dist/src/repluggableAppDebug/index.d.ts +1 -1
- package/dist/src/repluggableAppDebug/index.d.ts.map +1 -1
- package/dist/src/repluggableAppDebug/index.js.map +1 -1
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts +0 -20
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -1
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js +13 -47
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -1
- package/dist/test/repluggableAppDebug.spec.js +7 -108
- package/dist/test/repluggableAppDebug.spec.js.map +1 -1
- package/dist/test/testKit.spec.js +4 -15
- package/dist/test/testKit.spec.js.map +1 -1
- package/dist/testKit/index.d.ts +1 -10
- package/dist/testKit/index.d.ts.map +1 -1
- package/dist/testKit/index.js +12 -56
- package/dist/testKit/index.js.map +1 -1
- package/package.json +1 -1
- package/src/repluggableAppDebug/debug.d.ts +2 -16
- package/src/repluggableAppDebug/index.ts +1 -1
- package/src/repluggableAppDebug/repluggableAppDebug.ts +16 -74
- package/test/repluggableAppDebug.spec.ts +7 -134
- package/test/testKit.spec.tsx +6 -19
- package/testKit/index.ts +19 -66
|
@@ -1 +1 @@
|
|
|
1
|
-
export { setupDebugInfo
|
|
1
|
+
export { setupDebugInfo } from './repluggableAppDebug'
|
|
@@ -36,77 +36,6 @@ function mapApiToEntryPoint(allPackages: EntryPoint[]) {
|
|
|
36
36
|
return apiToEntryPoint
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export interface RootUnreadyAPIInfo {
|
|
40
|
-
key: AnySlotKey
|
|
41
|
-
/**
|
|
42
|
-
* 'nobody' -> not declared by any entry point in the host (missing package / pact)
|
|
43
|
-
* otherwise -> declared by an INSTALLED shell whose contributeAPI never completed (hung async contribution)
|
|
44
|
-
*/
|
|
45
|
-
declaredBy: 'nobody' | { entryPointName: string }
|
|
46
|
-
/** names of unready entry points directly blocked on this API */
|
|
47
|
-
requiredBy: string[]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface UnreadyEntryPointsReport {
|
|
51
|
-
unreadyEntryPoints: EntryPoint[]
|
|
52
|
-
rootUnreadyAPIs: RootUnreadyAPIInfo[]
|
|
53
|
-
/** unready entry points directly blocked on a root unready API */
|
|
54
|
-
rootUnreadyEntryPoints: EntryPoint[]
|
|
55
|
-
/** true when entry points are unready but no root unready API exists - their dependencies form a cycle */
|
|
56
|
-
probableDependencyCycle: boolean
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
type UnreadyReportParams = Pick<SetupDebugInfoParams, 'readyAPIs' | 'getOwnSlotKey' | 'getUnreadyEntryPoints' | 'addedShells'>
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Computes all root unready APIs at once: dependencies of unready entry points that are neither ready
|
|
63
|
-
* nor declared by another unready entry point (i.e. the APIs actually blocking the host from loading).
|
|
64
|
-
*/
|
|
65
|
-
const createGetUnreadyEntryPointsReport = ({ readyAPIs, getOwnSlotKey, getUnreadyEntryPoints, addedShells }: UnreadyReportParams) => {
|
|
66
|
-
return (): UnreadyEntryPointsReport => {
|
|
67
|
-
const unreadyEntryPoints = getUnreadyEntryPoints()
|
|
68
|
-
const isReady = (key: AnySlotKey) => readyAPIs.has(getOwnSlotKey(key as SlotKey<any>))
|
|
69
|
-
|
|
70
|
-
const declaredByUnready = new Set<string>()
|
|
71
|
-
unreadyEntryPoints.forEach(entryPoint => entryPoint.declareAPIs?.().forEach(key => declaredByUnready.add(key.name)))
|
|
72
|
-
|
|
73
|
-
const declaredByInstalled = new Map<string, string>()
|
|
74
|
-
for (const shell of addedShells.values()) {
|
|
75
|
-
shell.entryPoint.declareAPIs?.().forEach(key => declaredByInstalled.set(key.name, shell.entryPoint.name))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const rootByName = new Map<string, RootUnreadyAPIInfo>()
|
|
79
|
-
unreadyEntryPoints.forEach(entryPoint => {
|
|
80
|
-
entryPoint.getDependencyAPIs?.().forEach(key => {
|
|
81
|
-
if (isReady(key) || declaredByUnready.has(key.name)) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
const declarerName = declaredByInstalled.get(key.name)
|
|
85
|
-
const info = rootByName.get(key.name) ?? {
|
|
86
|
-
key,
|
|
87
|
-
declaredBy: declarerName ? { entryPointName: declarerName } : ('nobody' as const),
|
|
88
|
-
requiredBy: []
|
|
89
|
-
}
|
|
90
|
-
info.requiredBy.push(entryPoint.name)
|
|
91
|
-
rootByName.set(key.name, info)
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
const rootUnreadyAPIs = [...rootByName.values()]
|
|
96
|
-
const rootAPINames = new Set(rootByName.keys())
|
|
97
|
-
const rootUnreadyEntryPoints = unreadyEntryPoints.filter(entryPoint =>
|
|
98
|
-
entryPoint.getDependencyAPIs?.().some(key => rootAPINames.has(key.name))
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
unreadyEntryPoints,
|
|
103
|
-
rootUnreadyAPIs,
|
|
104
|
-
rootUnreadyEntryPoints,
|
|
105
|
-
probableDependencyCycle: unreadyEntryPoints.length > 0 && rootUnreadyAPIs.length === 0
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
39
|
export type DependencyTree = {
|
|
111
40
|
entryPoint: string
|
|
112
41
|
deps: Array<{ api: string; subtree: DependencyTree | null }>
|
|
@@ -227,9 +156,22 @@ export function setupDebugInfo({
|
|
|
227
156
|
}
|
|
228
157
|
})
|
|
229
158
|
},
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
159
|
+
/**
|
|
160
|
+
* dependencies of unready entry points that are neither ready nor declared by another
|
|
161
|
+
* unready entry point - the APIs actually blocking the host from loading
|
|
162
|
+
* (missing entry point / pact, or a contribution that never completed)
|
|
163
|
+
*/
|
|
164
|
+
getRootUnreadyAPIs: (): AnySlotKey[] => {
|
|
165
|
+
const unreadyEntryPoints = getUnreadyEntryPoints()
|
|
166
|
+
const declaredByUnready = new Set(unreadyEntryPoints.flatMap(ep => (ep.declareAPIs?.() || []).map(key => key.name)))
|
|
167
|
+
return _.uniqBy(
|
|
168
|
+
unreadyEntryPoints
|
|
169
|
+
.flatMap(ep => ep.getDependencyAPIs?.() || [])
|
|
170
|
+
.filter(key => !readyAPIs.has(getOwnSlotKey(key)) && !declaredByUnready.has(key.name)),
|
|
171
|
+
'name'
|
|
172
|
+
)
|
|
173
|
+
},
|
|
174
|
+
getRootUnreadyAPI: () => utils.getRootUnreadyAPIs()[0],
|
|
233
175
|
unReadyEntryPoints: (): EntryPoint[] => getUnreadyEntryPoints(),
|
|
234
176
|
whyEntryPointUnready: (name: string) => {
|
|
235
177
|
const unreadyEntryPoint = _.find(
|
|
@@ -246,53 +246,8 @@ describe('RepluggableAppDebug', () => {
|
|
|
246
246
|
})
|
|
247
247
|
})
|
|
248
248
|
|
|
249
|
-
describe('
|
|
250
|
-
|
|
251
|
-
await new Promise(resolve => setTimeout(resolve, 0))
|
|
252
|
-
return globalThis.repluggableAppDebug.utils.getUnreadyEntryPointsReport()
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
it('should report no unready entry points when all are loaded', async () => {
|
|
256
|
-
createAppHost([
|
|
257
|
-
{
|
|
258
|
-
name: 'entryPoint',
|
|
259
|
-
declareAPIs: () => []
|
|
260
|
-
}
|
|
261
|
-
])
|
|
262
|
-
|
|
263
|
-
const report = await getReport()
|
|
264
|
-
|
|
265
|
-
expect(report).toEqual({
|
|
266
|
-
unreadyEntryPoints: [],
|
|
267
|
-
rootUnreadyAPIs: [],
|
|
268
|
-
rootUnreadyEntryPoints: [],
|
|
269
|
-
probableDependencyCycle: false
|
|
270
|
-
})
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
it('should report all root unready APIs of independent unready clusters', async () => {
|
|
274
|
-
createAppHost([
|
|
275
|
-
{
|
|
276
|
-
name: 'entryPoint A',
|
|
277
|
-
getDependencyAPIs: () => [{ name: 'missing A' }]
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
name: 'entryPoint B',
|
|
281
|
-
getDependencyAPIs: () => [{ name: 'missing B' }]
|
|
282
|
-
}
|
|
283
|
-
])
|
|
284
|
-
|
|
285
|
-
const report = await getReport()
|
|
286
|
-
|
|
287
|
-
expect(report.rootUnreadyAPIs).toEqual([
|
|
288
|
-
{ key: { name: 'missing A' }, declaredBy: 'nobody', requiredBy: ['entryPoint A'] },
|
|
289
|
-
{ key: { name: 'missing B' }, declaredBy: 'nobody', requiredBy: ['entryPoint B'] }
|
|
290
|
-
])
|
|
291
|
-
expect(report.rootUnreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
292
|
-
expect(report.probableDependencyCycle).toBe(false)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
it('should report only the root API of a transitively blocked chain', async () => {
|
|
249
|
+
describe('getRootUnreadyAPIs', () => {
|
|
250
|
+
it('should return all root unready APIs, excluding transitively blocked ones', async () => {
|
|
296
251
|
createAppHost([
|
|
297
252
|
{
|
|
298
253
|
name: 'entryPoint A',
|
|
@@ -301,98 +256,16 @@ describe('RepluggableAppDebug', () => {
|
|
|
301
256
|
{
|
|
302
257
|
name: 'entryPoint B',
|
|
303
258
|
declareAPIs: () => [{ name: 'API B' }],
|
|
304
|
-
getDependencyAPIs: () => [
|
|
305
|
-
}
|
|
306
|
-
])
|
|
307
|
-
|
|
308
|
-
const report = await getReport()
|
|
309
|
-
|
|
310
|
-
expect(report.rootUnreadyAPIs).toEqual([{ key: unreadAPI, declaredBy: 'nobody', requiredBy: ['entryPoint B'] }])
|
|
311
|
-
expect(report.rootUnreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint B'])
|
|
312
|
-
expect(report.unreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
it('should report roots of sibling branches, including APIs declared by an installed shell that never contributed them', async () => {
|
|
316
|
-
createAppHost([
|
|
317
|
-
{
|
|
318
|
-
name: 'entryPoint 0',
|
|
319
|
-
getDependencyAPIs: () => [{ name: 'missing API' }, { name: 'API B' }]
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
name: 'entryPoint 1',
|
|
323
|
-
declareAPIs: () => [{ name: 'API B' }]
|
|
324
|
-
}
|
|
325
|
-
])
|
|
326
|
-
|
|
327
|
-
const report = await getReport()
|
|
328
|
-
|
|
329
|
-
expect(report.rootUnreadyAPIs).toEqual([
|
|
330
|
-
{ key: { name: 'missing API' }, declaredBy: 'nobody', requiredBy: ['entryPoint 0'] },
|
|
331
|
-
{ key: { name: 'API B' }, declaredBy: { entryPointName: 'entryPoint 1' }, requiredBy: ['entryPoint 0'] }
|
|
332
|
-
])
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
it('should aggregate all entry points blocked on the same root API', async () => {
|
|
336
|
-
createAppHost([
|
|
337
|
-
{
|
|
338
|
-
name: 'entryPoint A',
|
|
339
|
-
getDependencyAPIs: () => [unreadAPI]
|
|
259
|
+
getDependencyAPIs: () => [{ name: 'missing B' }]
|
|
340
260
|
},
|
|
341
261
|
{
|
|
342
|
-
name: 'entryPoint
|
|
343
|
-
getDependencyAPIs: () => [
|
|
262
|
+
name: 'entryPoint C',
|
|
263
|
+
getDependencyAPIs: () => [{ name: 'missing C' }]
|
|
344
264
|
}
|
|
345
265
|
])
|
|
266
|
+
await new Promise(resolve => setTimeout(resolve, 0))
|
|
346
267
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
expect(report.rootUnreadyAPIs).toEqual([{ key: unreadAPI, declaredBy: 'nobody', requiredBy: ['entryPoint A', 'entryPoint B'] }])
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
it('should flag a probable dependency cycle when unready entry points have no root unready API', async () => {
|
|
353
|
-
createAppHost(
|
|
354
|
-
[
|
|
355
|
-
{
|
|
356
|
-
name: 'entryPoint A',
|
|
357
|
-
declareAPIs: () => [{ name: 'API X' }],
|
|
358
|
-
getDependencyAPIs: () => [{ name: 'API Y' }]
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
name: 'entryPoint B',
|
|
362
|
-
declareAPIs: () => [{ name: 'API Y' }],
|
|
363
|
-
getDependencyAPIs: () => [{ name: 'API X' }]
|
|
364
|
-
}
|
|
365
|
-
],
|
|
366
|
-
{ monitoring: {}, disableCheckCircularDependencies: true }
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
const report = await getReport()
|
|
370
|
-
|
|
371
|
-
expect(report.rootUnreadyAPIs).toEqual([])
|
|
372
|
-
expect(report.unreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
373
|
-
expect(report.probableDependencyCycle).toBe(true)
|
|
268
|
+
expect(globalThis.repluggableAppDebug.utils.getRootUnreadyAPIs()).toEqual([{ name: 'missing B' }, { name: 'missing C' }])
|
|
374
269
|
})
|
|
375
|
-
|
|
376
|
-
it('should not hang getRootUnreadyAPI on a dependency cycle', async () => {
|
|
377
|
-
createAppHost(
|
|
378
|
-
[
|
|
379
|
-
{
|
|
380
|
-
name: 'entryPoint A',
|
|
381
|
-
declareAPIs: () => [{ name: 'API X' }],
|
|
382
|
-
getDependencyAPIs: () => [{ name: 'API Y' }]
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
name: 'entryPoint B',
|
|
386
|
-
declareAPIs: () => [{ name: 'API Y' }],
|
|
387
|
-
getDependencyAPIs: () => [{ name: 'API X' }]
|
|
388
|
-
}
|
|
389
|
-
],
|
|
390
|
-
{ monitoring: {}, disableCheckCircularDependencies: true }
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
const unreadyAPIs = await getUnreadyAPIs()
|
|
394
|
-
|
|
395
|
-
expect(unreadyAPIs).toBeUndefined()
|
|
396
|
-
}, 3000)
|
|
397
270
|
})
|
|
398
271
|
})
|
package/test/testKit.spec.tsx
CHANGED
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
asyncLoadMockPackage,
|
|
13
13
|
dependsOnMockPackageEntryPoint,
|
|
14
14
|
MockPublicAPI,
|
|
15
|
-
createAppHostAndWaitForLoading
|
|
16
|
-
AppHostLoadingTimeoutError
|
|
15
|
+
createAppHostAndWaitForLoading
|
|
17
16
|
} from '../testKit'
|
|
18
17
|
|
|
19
18
|
interface APIKeys {
|
|
@@ -148,10 +147,10 @@ describe('App Host TestKit', () => {
|
|
|
148
147
|
it('should throw if failed to load all packages', async () => {
|
|
149
148
|
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint], [])
|
|
150
149
|
jest.runAllTimers()
|
|
151
|
-
await expect(hostPromise).rejects.toThrow(new RegExp(
|
|
150
|
+
await expect(hostPromise).rejects.toThrow(new RegExp(MockPublicAPI.name))
|
|
152
151
|
})
|
|
153
152
|
|
|
154
|
-
it('should
|
|
153
|
+
it('should report all root unready APIs of independent unready entry points', async () => {
|
|
155
154
|
const hostPromise = createAppHostAndWaitForLoading(
|
|
156
155
|
[
|
|
157
156
|
{
|
|
@@ -168,24 +167,20 @@ describe('App Host TestKit', () => {
|
|
|
168
167
|
[]
|
|
169
168
|
)
|
|
170
169
|
jest.runAllTimers()
|
|
171
|
-
const error:
|
|
170
|
+
const error: Error = await hostPromise.then(
|
|
172
171
|
() => {
|
|
173
172
|
throw new Error('expected hostPromise to reject')
|
|
174
173
|
},
|
|
175
174
|
e => e
|
|
176
175
|
)
|
|
177
176
|
|
|
178
|
-
expect(error).toBeInstanceOf(AppHostLoadingTimeoutError)
|
|
179
|
-
expect(error.report.rootUnreadyAPIs.map(info => info.key.name)).toEqual(['missing A', 'missing B'])
|
|
180
177
|
expect(error.message).toContain('"missing A"')
|
|
181
178
|
expect(error.message).toContain('"missing B"')
|
|
182
|
-
expect(error.message).toContain('required by: entryPoint A')
|
|
183
|
-
expect(error.message).toContain('required by: entryPoint B')
|
|
184
179
|
})
|
|
185
180
|
|
|
186
181
|
it('should respect a custom loading timeout', async () => {
|
|
187
182
|
let settled = false
|
|
188
|
-
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint], [],
|
|
183
|
+
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint], [], 10000)
|
|
189
184
|
hostPromise.catch(() => (settled = true))
|
|
190
185
|
|
|
191
186
|
jest.advanceTimersByTime(9999)
|
|
@@ -194,15 +189,7 @@ describe('App Host TestKit', () => {
|
|
|
194
189
|
expect(settled).toBe(false)
|
|
195
190
|
|
|
196
191
|
jest.advanceTimersByTime(1)
|
|
197
|
-
await expect(hostPromise).rejects.
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
it('should not leave a pending timeout after successful loading', async () => {
|
|
201
|
-
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint, asyncLoadMockPackage], [])
|
|
202
|
-
jest.advanceTimersByTime(500)
|
|
203
|
-
const host = await hostPromise
|
|
204
|
-
expect(host.getAPI(MockPublicAPI)).toBeDefined()
|
|
205
|
-
expect(jest.getTimerCount()).toBe(0)
|
|
192
|
+
await expect(hostPromise).rejects.toThrow('timed out after 10000ms')
|
|
206
193
|
})
|
|
207
194
|
})
|
|
208
195
|
})
|
package/testKit/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash'
|
|
2
2
|
import { EntryPoint, ObservableState } from '../src/API'
|
|
3
3
|
import { AnySlotKey, AppHost, createAppHost as _createAppHost, EntryPointOrPackage, Shell, SlotKey } from '../src/index'
|
|
4
|
-
import { UnreadyEntryPointsReport } from '../src/repluggableAppDebug'
|
|
5
4
|
import { createShellLogger } from '../src/loggers'
|
|
6
5
|
import { emptyLoggerOptions } from './emptyLoggerOptions'
|
|
7
6
|
|
|
@@ -82,60 +81,10 @@ export function createAppHostWithPacts(packages: EntryPointOrPackage[], pacts: P
|
|
|
82
81
|
})
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
export interface WaitForLoadingOptions {
|
|
86
|
-
/** milliseconds to wait for host loading before rejecting with an unready entry points report (default: 3000) */
|
|
87
|
-
timeout?: number
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export class AppHostLoadingTimeoutError extends Error {
|
|
91
|
-
constructor(message: string, public readonly report: UnreadyEntryPointsReport) {
|
|
92
|
-
super(message)
|
|
93
|
-
this.name = 'AppHostLoadingTimeoutError'
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const WAIT_FOR_LOADING_PROBE_SHELL = 'Depends on all declared APIs'
|
|
98
|
-
|
|
99
|
-
const formatUnreadyReport = (timeout: number, report: UnreadyEntryPointsReport): string => {
|
|
100
|
-
const { utils } = globalThis.repluggableAppDebug
|
|
101
|
-
const isProbeShell = (name: string) => name === WAIT_FOR_LOADING_PROBE_SHELL
|
|
102
|
-
const header = `createAppHostAndWaitForLoading - host not ready within ${timeout}ms.`
|
|
103
|
-
const unreadyEntryPoints = report.unreadyEntryPoints.filter(entryPoint => !isProbeShell(entryPoint.name))
|
|
104
|
-
const rootUnreadyEntryPoints = report.rootUnreadyEntryPoints.filter(entryPoint => !isProbeShell(entryPoint.name))
|
|
105
|
-
|
|
106
|
-
if (report.probableDependencyCycle) {
|
|
107
|
-
const names = unreadyEntryPoints.map(entryPoint => `"${entryPoint.name}"`).join(', ')
|
|
108
|
-
return `${header}
|
|
109
|
-
No root unready API found while ${unreadyEntryPoints.length} entry points are unready - probable dependency cycle between: ${names}`
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const roots = report.rootUnreadyAPIs.map((info, index) => {
|
|
113
|
-
const declaredBy =
|
|
114
|
-
info.declaredBy === 'nobody'
|
|
115
|
-
? 'declared by NO entry point (missing package or pact?)'
|
|
116
|
-
: `declared by "${info.declaredBy.entryPointName}" (installed, but its contribution never completed - hung async contributeAPI?)`
|
|
117
|
-
const requiredBy = info.requiredBy.filter(name => !isProbeShell(name))
|
|
118
|
-
const lines = [`${index + 1}. "${info.key.name}" - ${declaredBy}`]
|
|
119
|
-
if (requiredBy.length) {
|
|
120
|
-
lines.push(` required by: ${requiredBy.join(', ')}`)
|
|
121
|
-
const tree = utils.visualizeDependencyTree(utils.traceAPIDependency(requiredBy[0], info.key.name))
|
|
122
|
-
lines.push(...tree.split('\n').map(line => ` ${line}`))
|
|
123
|
-
}
|
|
124
|
-
return lines.join('\n')
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
return `${header}
|
|
128
|
-
|
|
129
|
-
Root unready APIs (${report.rootUnreadyAPIs.length}):
|
|
130
|
-
${roots.join('\n')}
|
|
131
|
-
|
|
132
|
-
Unready entry points: ${rootUnreadyEntryPoints.length} blocked directly on root APIs, ${unreadyEntryPoints.length} total.`
|
|
133
|
-
}
|
|
134
|
-
|
|
135
84
|
export async function createAppHostAndWaitForLoading(
|
|
136
85
|
packages: EntryPointOrPackage[],
|
|
137
86
|
pacts: PactAPIBase[],
|
|
138
|
-
|
|
87
|
+
timeout: number = 3000
|
|
139
88
|
): Promise<AppHost> {
|
|
140
89
|
const appHost = createAppHostWithPacts(packages, pacts)
|
|
141
90
|
const declaredAPIs = _(packages)
|
|
@@ -143,18 +92,29 @@ export async function createAppHostAndWaitForLoading(
|
|
|
143
92
|
.value()
|
|
144
93
|
.flatMap((entryPoint: EntryPoint) => (entryPoint.declareAPIs ? entryPoint.declareAPIs() : []))
|
|
145
94
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
95
|
+
const timeoutPromise = new Promise((resolve, reject) => {
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
const readyAPIs = Array.from(globalThis.repluggableAppDebug.readyAPIs)
|
|
98
|
+
const unreadyAPIs = declaredAPIs.filter(api => !readyAPIs.some(readyAPI => readyAPI.name === api.name))
|
|
99
|
+
const rootUnreadyAPIs = globalThis.repluggableAppDebug.utils.getRootUnreadyAPIs()
|
|
100
|
+
|
|
101
|
+
reject(
|
|
102
|
+
new Error(
|
|
103
|
+
`createAppHostAndWaitForLoading - waiting for loading timed out after ${timeout}ms.
|
|
104
|
+
these root unready APIs are most likely the reason - unready entry points require them but nothing declares them (missing entry point or pact?): ${JSON.stringify(
|
|
105
|
+
rootUnreadyAPIs
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
in addition here's the full list of declared APIs that have not been contributed: ${JSON.stringify(unreadyAPIs)}`
|
|
109
|
+
)
|
|
110
|
+
)
|
|
151
111
|
}, timeout)
|
|
152
112
|
})
|
|
153
113
|
|
|
154
114
|
const loadingPromise = new Promise<void>(async resolve => {
|
|
155
115
|
await appHost.addShells([
|
|
156
116
|
{
|
|
157
|
-
name:
|
|
117
|
+
name: 'Depends on all declared APIs',
|
|
158
118
|
getDependencyAPIs() {
|
|
159
119
|
return declaredAPIs
|
|
160
120
|
},
|
|
@@ -165,14 +125,7 @@ export async function createAppHostAndWaitForLoading(
|
|
|
165
125
|
])
|
|
166
126
|
})
|
|
167
127
|
|
|
168
|
-
|
|
169
|
-
await Promise.race([timeoutPromise, loadingPromise])
|
|
170
|
-
return appHost
|
|
171
|
-
} finally {
|
|
172
|
-
if (timer) {
|
|
173
|
-
clearTimeout(timer)
|
|
174
|
-
}
|
|
175
|
-
}
|
|
128
|
+
return Promise.race([timeoutPromise, loadingPromise]).then(() => appHost)
|
|
176
129
|
}
|
|
177
130
|
|
|
178
131
|
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
|