@kennofizet/apphub-frontend 0.1.8 → 0.1.9
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
package/src/index.js
CHANGED
|
@@ -1,509 +1,449 @@
|
|
|
1
|
-
import './modules/desktop/styles/desktop.css'
|
|
2
|
-
import './modules/desktop/styles/theme.css'
|
|
3
|
-
import { reactive } from 'vue'
|
|
4
|
-
import { createAppHubApi } from './api/index.js'
|
|
5
|
-
import { createCoreApi } from './api/coreApi.js'
|
|
6
|
-
import { createZoneContextState } from './composables/createZoneContext.js'
|
|
7
|
-
import { APPHUB_ZONE_CONTEXT_KEY } from './composables/useAppHubZoneContext.js'
|
|
8
|
-
import { createAppStoreState, provideAppStore } from './modules/app-store/index.js'
|
|
9
|
-
import { AppHubDesktop } from './modules/desktop/index.js'
|
|
10
|
-
import { AppHubRunner } from './modules/runner/index.js'
|
|
11
|
-
import { getAppHubStore, registerAppHubStore, APPHUB_MODULE_STORE_KEY } from './moduleStore.js'
|
|
12
|
-
import {
|
|
13
|
-
createWindowManagerState,
|
|
14
|
-
provideWindowManager,
|
|
15
|
-
} from './modules/window-manager/index.js'
|
|
16
|
-
import {
|
|
17
|
-
evaluateOriginSafety,
|
|
18
|
-
parseDevUserFromBootstrap,
|
|
19
|
-
parseOriginsFromBootstrap,
|
|
20
|
-
} from './utils/originSafety.js'
|
|
21
|
-
import { loadDevFriendlyOriginsPreference } from './utils/devOriginSettings.js'
|
|
22
|
-
import {
|
|
23
|
-
bootstrapResponseFromCache,
|
|
24
|
-
loadBootstrapCache,
|
|
25
|
-
saveBootstrapCache,
|
|
26
|
-
} from './utils/bootstrapCache.js'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
target.
|
|
80
|
-
target.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
store.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
store
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
export
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
store
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
zoneContext: null,
|
|
451
|
-
windowManager: null,
|
|
452
|
-
appStore: null,
|
|
453
|
-
}
|
|
454
|
-
registerAppHubStore(vueApp, store)
|
|
455
|
-
|
|
456
|
-
vueApp.provide('apphubOptions', moduleOptions)
|
|
457
|
-
vueApp.provide('apphubHostApp', vueApp)
|
|
458
|
-
vueApp.provide(APPHUB_MODULE_STORE_KEY, store)
|
|
459
|
-
vueApp.component('AppHubDesktop', AppHubDesktop)
|
|
460
|
-
vueApp.component('AppHubRunner', AppHubRunner)
|
|
461
|
-
|
|
462
|
-
ensureModuleInfrastructure(vueApp, store)
|
|
463
|
-
void startBootstrapSession(store)
|
|
464
|
-
|
|
465
|
-
return facade
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/** Whether installAppHubModule has been called for this Vue app instance. */
|
|
469
|
-
export function isAppHubModuleInstalled(vueApp) {
|
|
470
|
-
return vueApp != null && getAppHubStore(vueApp) != null
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
export { useAppHubHostApi, useAppHubModuleStore } from './composables/useAppHubHostApi.js'
|
|
474
|
-
export { useAppHubZoneContext } from './composables/useAppHubZoneContext.js'
|
|
475
|
-
export { createAppHubApi } from './api/index.js'
|
|
476
|
-
export { createCoreApi } from './api/coreApi.js'
|
|
477
|
-
export { AppHubDesktop } from './modules/desktop/index.js'
|
|
478
|
-
export {
|
|
479
|
-
createDesktopNotificationsState,
|
|
480
|
-
useDesktopNotifications,
|
|
481
|
-
AppHubDesktopNotifications,
|
|
482
|
-
parseApiError,
|
|
483
|
-
} from './modules/notifications/index.js'
|
|
484
|
-
export { AppHubRunner } from './modules/runner/index.js'
|
|
485
|
-
export { resolveLang } from './i18n/resolveLang.js'
|
|
486
|
-
export { resolveTheme, normalizeTheme, isThemeLocked } from './i18n/resolveTheme.js'
|
|
487
|
-
export { t } from './i18n/index.js'
|
|
488
|
-
export {
|
|
489
|
-
evaluateOriginSafety,
|
|
490
|
-
isEmbeddedFrame,
|
|
491
|
-
isLocalDevOrigin,
|
|
492
|
-
parseOriginsFromBootstrap,
|
|
493
|
-
resolveEffectiveOrigins,
|
|
494
|
-
ORIGIN_UNSAFE_SAME_ORIGIN_EMBED,
|
|
495
|
-
ORIGIN_UNSAFE_NOT_CONFIGURED,
|
|
496
|
-
ORIGIN_UNSAFE_WRONG_ORIGIN,
|
|
497
|
-
ORIGIN_UNSAFE_RUNTIME_NOT_CONFIGURED,
|
|
498
|
-
ORIGIN_UNSAFE_RUNTIME_SAME_ORIGIN,
|
|
499
|
-
resolveRuntimeApiBase,
|
|
500
|
-
} from './utils/originSafety.js'
|
|
501
|
-
|
|
502
|
-
/** True when installAppHubModule blocked due to unsafe same-origin embed. */
|
|
503
|
-
export function isAppHubOriginBlocked(vueApp) {
|
|
504
|
-
const store = getAppHubStore(vueApp)
|
|
505
|
-
return store?.options?.originBlocked === true
|
|
506
|
-
}
|
|
507
|
-
export * from './modules/app-store/index.js'
|
|
508
|
-
export * from './modules/window-manager/index.js'
|
|
509
|
-
export * from './modules/runner/index.js'
|
|
1
|
+
import './modules/desktop/styles/desktop.css'
|
|
2
|
+
import './modules/desktop/styles/theme.css'
|
|
3
|
+
import { reactive } from 'vue'
|
|
4
|
+
import { createAppHubApi } from './api/index.js'
|
|
5
|
+
import { createCoreApi } from './api/coreApi.js'
|
|
6
|
+
import { createZoneContextState } from './composables/createZoneContext.js'
|
|
7
|
+
import { APPHUB_ZONE_CONTEXT_KEY } from './composables/useAppHubZoneContext.js'
|
|
8
|
+
import { createAppStoreState, provideAppStore } from './modules/app-store/index.js'
|
|
9
|
+
import { AppHubDesktop } from './modules/desktop/index.js'
|
|
10
|
+
import { AppHubRunner } from './modules/runner/index.js'
|
|
11
|
+
import { getAppHubStore, registerAppHubStore, APPHUB_MODULE_STORE_KEY } from './moduleStore.js'
|
|
12
|
+
import {
|
|
13
|
+
createWindowManagerState,
|
|
14
|
+
provideWindowManager,
|
|
15
|
+
} from './modules/window-manager/index.js'
|
|
16
|
+
import {
|
|
17
|
+
evaluateOriginSafety,
|
|
18
|
+
parseDevUserFromBootstrap,
|
|
19
|
+
parseOriginsFromBootstrap,
|
|
20
|
+
} from './utils/originSafety.js'
|
|
21
|
+
import { loadDevFriendlyOriginsPreference } from './utils/devOriginSettings.js'
|
|
22
|
+
import {
|
|
23
|
+
bootstrapResponseFromCache,
|
|
24
|
+
loadBootstrapCache,
|
|
25
|
+
saveBootstrapCache,
|
|
26
|
+
} from './utils/bootstrapCache.js'
|
|
27
|
+
|
|
28
|
+
const bootstrapInflight = new WeakMap()
|
|
29
|
+
|
|
30
|
+
function buildPublicOptions(options = {}) {
|
|
31
|
+
const origins = Array.isArray(options.allowedRuntimeOrigins)
|
|
32
|
+
? options.allowedRuntimeOrigins.filter((o) => typeof o === 'string')
|
|
33
|
+
: []
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
language: options.language || 'vi',
|
|
37
|
+
theme: options.theme ?? 'auto',
|
|
38
|
+
themeToggle: options.themeToggle,
|
|
39
|
+
openAppStoreOnMount: options.openAppStoreOnMount !== false,
|
|
40
|
+
allowedRuntimeOrigins: origins,
|
|
41
|
+
coreUrl: options.coreUrl || '',
|
|
42
|
+
backendUrl: (options.backendUrl || '').replace(/\/$/, ''),
|
|
43
|
+
hasToken: !!(options.token),
|
|
44
|
+
allowSameOriginEmbed: options.allowSameOriginEmbed === true,
|
|
45
|
+
allowUnsafeOrigin: options.allowUnsafeOrigin === true,
|
|
46
|
+
hubOrigin: typeof options.hubOrigin === 'string' ? options.hubOrigin.trim() : '',
|
|
47
|
+
runtimePublicUrl: typeof options.runtimePublicUrl === 'string' ? options.runtimePublicUrl.trim() : '',
|
|
48
|
+
enforceDedicatedHubOrigin: options.enforceDedicatedHubOrigin !== false,
|
|
49
|
+
enforceIsolatedHostedRuntime: options.enforceIsolatedHostedRuntime !== false,
|
|
50
|
+
allowSameOriginHostedRuntime: options.allowSameOriginHostedRuntime === true,
|
|
51
|
+
hostedSandboxSameOrigin: options.hostedSandboxSameOrigin === true,
|
|
52
|
+
enforceDevFriendlyOrigins: typeof options.enforceDevFriendlyOrigins === 'boolean'
|
|
53
|
+
? options.enforceDevFriendlyOrigins
|
|
54
|
+
: true,
|
|
55
|
+
isDevUser: options.isDevUser === true,
|
|
56
|
+
serverHubPublicUrl: typeof options.serverHubPublicUrl === 'string' ? options.serverHubPublicUrl.trim() : '',
|
|
57
|
+
serverFrontendOrigin: typeof options.serverFrontendOrigin === 'string' ? options.serverFrontendOrigin.trim() : '',
|
|
58
|
+
serverRuntimePublicUrl: typeof options.serverRuntimePublicUrl === 'string' ? options.serverRuntimePublicUrl.trim() : '',
|
|
59
|
+
serverOriginsAuto: options.serverOriginsAuto === true,
|
|
60
|
+
serverOriginsResolved: options.serverOriginsResolved === true,
|
|
61
|
+
originBootstrapLoading: options.originBootstrapLoading === true,
|
|
62
|
+
originBlocked: false,
|
|
63
|
+
originCheckPending: false,
|
|
64
|
+
originBlockReason: null,
|
|
65
|
+
originBlockParentOrigin: null,
|
|
66
|
+
originBlockExpectedHubOrigin: null,
|
|
67
|
+
originBlockExpectedRuntimeOrigin: null,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @param {Record<string, unknown>} target */
|
|
72
|
+
function applyOriginSafety(target, sourceOptions = {}) {
|
|
73
|
+
const check = evaluateOriginSafety({ ...target, ...sourceOptions })
|
|
74
|
+
target.originBootstrapLoading = check.loading === true
|
|
75
|
+
target.originCheckPending = check.pending === true
|
|
76
|
+
target.originBlocked = !check.safe && check.loading !== true
|
|
77
|
+
target.originBlockReason = check.reason
|
|
78
|
+
target.originBlockParentOrigin = check.parentOrigin
|
|
79
|
+
target.originBlockExpectedHubOrigin = check.expectedHubOrigin
|
|
80
|
+
target.originBlockExpectedRuntimeOrigin = check.expectedRuntimeOrigin
|
|
81
|
+
return check
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseUserFromBootstrap(resp) {
|
|
85
|
+
const data = resp?.data?.data ?? resp?.data ?? {}
|
|
86
|
+
const user = data.user
|
|
87
|
+
if (!user || user.id == null) return null
|
|
88
|
+
return {
|
|
89
|
+
id: user.id,
|
|
90
|
+
name: user.name ?? String(user.id),
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function applyBootstrapOrigins(store, bootstrapResponse, { fromCache = false } = {}) {
|
|
95
|
+
const {
|
|
96
|
+
hubPublicUrl,
|
|
97
|
+
frontendOrigin,
|
|
98
|
+
runtimePublicUrl,
|
|
99
|
+
originsAuto,
|
|
100
|
+
} = parseOriginsFromBootstrap(bootstrapResponse)
|
|
101
|
+
|
|
102
|
+
store.options.isDevUser = parseDevUserFromBootstrap(bootstrapResponse)
|
|
103
|
+
store.options.serverOriginsAuto = originsAuto
|
|
104
|
+
|
|
105
|
+
if (!store.options.isDevUser) {
|
|
106
|
+
store.options.enforceDevFriendlyOrigins = true
|
|
107
|
+
} else {
|
|
108
|
+
store.options.enforceDevFriendlyOrigins = loadDevFriendlyOriginsPreference()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (hubPublicUrl) {
|
|
112
|
+
store.options.serverHubPublicUrl = hubPublicUrl
|
|
113
|
+
}
|
|
114
|
+
if (frontendOrigin) {
|
|
115
|
+
store.options.serverFrontendOrigin = frontendOrigin
|
|
116
|
+
}
|
|
117
|
+
if (runtimePublicUrl) {
|
|
118
|
+
store.options.serverRuntimePublicUrl = runtimePublicUrl
|
|
119
|
+
if (!store.options.runtimePublicUrl) store.options.runtimePublicUrl = runtimePublicUrl
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
store.options.serverOriginsResolved = true
|
|
123
|
+
|
|
124
|
+
if (!fromCache) {
|
|
125
|
+
saveBootstrapCache(store.credentials.backendUrl, bootstrapResponse)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const user = parseUserFromBootstrap(bootstrapResponse)
|
|
129
|
+
if (user && store.zoneContext?.state) {
|
|
130
|
+
store.zoneContext.state.user.id = user.id
|
|
131
|
+
store.zoneContext.state.user.name = user.name
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Reconcile while originBootstrapLoading may still be true so enableModuleApi runs
|
|
135
|
+
// after disableModuleServices (wasLoading must be captured before clearing the flag).
|
|
136
|
+
reconcileOriginSafety(store)
|
|
137
|
+
store.options.originBootstrapLoading = false
|
|
138
|
+
applyOriginSafety(store.options)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function applyCachedBootstrapIfAny(store) {
|
|
142
|
+
const cached = loadBootstrapCache(store.credentials.backendUrl)
|
|
143
|
+
if (!cached) return false
|
|
144
|
+
applyBootstrapOrigins(store, bootstrapResponseFromCache(cached), { fromCache: true })
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function fetchBootstrapSession(store) {
|
|
149
|
+
let promise = bootstrapInflight.get(store)
|
|
150
|
+
if (promise) return promise
|
|
151
|
+
|
|
152
|
+
promise = (async () => {
|
|
153
|
+
syncApi(store)
|
|
154
|
+
if (!store.facade?.bootstrap) return
|
|
155
|
+
|
|
156
|
+
const res = await store.facade.bootstrap()
|
|
157
|
+
if (res) applyBootstrapOrigins(store, res)
|
|
158
|
+
})().catch(() => {
|
|
159
|
+
store.options.originBootstrapLoading = false
|
|
160
|
+
if (!store.options.serverOriginsResolved) {
|
|
161
|
+
reconcileOriginSafety(store)
|
|
162
|
+
}
|
|
163
|
+
}).finally(() => {
|
|
164
|
+
bootstrapInflight.delete(store)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
bootstrapInflight.set(store, promise)
|
|
168
|
+
return promise
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function startBootstrapSession(store) {
|
|
172
|
+
const { backendUrl, token } = store.credentials
|
|
173
|
+
if (!backendUrl || !token) {
|
|
174
|
+
store.options.originBootstrapLoading = false
|
|
175
|
+
reconcileOriginSafety(store)
|
|
176
|
+
return Promise.resolve()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
syncApi(store)
|
|
180
|
+
applyOriginSafety(store.options)
|
|
181
|
+
|
|
182
|
+
const hadCache = applyCachedBootstrapIfAny(store)
|
|
183
|
+
if (!hadCache && !store.options.originBlocked) {
|
|
184
|
+
store.options.originBootstrapLoading = true
|
|
185
|
+
store.options.originBlocked = false
|
|
186
|
+
applyOriginSafety(store.options)
|
|
187
|
+
disableModuleServices(store)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return fetchBootstrapSession(store)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function reconcileOriginSafety(store) {
|
|
194
|
+
const wasBlocked = store.options.originBlocked === true
|
|
195
|
+
const wasLoading = store.options.originBootstrapLoading === true
|
|
196
|
+
applyOriginSafety(store.options)
|
|
197
|
+
|
|
198
|
+
if (store.options.originBootstrapLoading) {
|
|
199
|
+
disableModuleServices(store)
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (store.options.originBlocked && !wasBlocked) {
|
|
204
|
+
disableModuleServices(store)
|
|
205
|
+
} else if (!store.options.originBlocked && (wasBlocked || wasLoading)) {
|
|
206
|
+
enableModuleApi(store)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function disableModuleServices(store) {
|
|
211
|
+
store.facade.setImpl(null)
|
|
212
|
+
store.coreApi = null
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Window manager + app store — required even when origin is blocked (AppHubDesktop setup). */
|
|
216
|
+
function ensureModuleInfrastructure(vueApp, store) {
|
|
217
|
+
ensureZoneContext(vueApp, store)
|
|
218
|
+
ensureModuleState(vueApp, store)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function enableModuleApi(store) {
|
|
222
|
+
syncApi(store)
|
|
223
|
+
syncZoneContext(store)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function enableModuleServices(vueApp, store) {
|
|
227
|
+
ensureModuleInfrastructure(vueApp, store)
|
|
228
|
+
enableModuleApi(store)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function buildCredentials(options = {}) {
|
|
232
|
+
return {
|
|
233
|
+
coreUrl: options.coreUrl || '',
|
|
234
|
+
backendUrl: options.backendUrl || '',
|
|
235
|
+
token: options.token || '',
|
|
236
|
+
hostAccessSecret: options.hostAccessSecret || '',
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function createApiFacade() {
|
|
241
|
+
let impl = null
|
|
242
|
+
return {
|
|
243
|
+
setImpl(next) {
|
|
244
|
+
impl = next
|
|
245
|
+
},
|
|
246
|
+
hasImpl() {
|
|
247
|
+
return impl != null
|
|
248
|
+
},
|
|
249
|
+
bootstrap: (...args) => impl?.bootstrap?.(...args),
|
|
250
|
+
apps: (...args) => impl?.apps?.(...args),
|
|
251
|
+
launch: (...args) => impl?.launch?.(...args),
|
|
252
|
+
ping: (...args) => impl?.ping?.(...args),
|
|
253
|
+
verifyLaunchToken: (...args) => impl?.verifyLaunchToken?.(...args),
|
|
254
|
+
usage: (...args) => impl?.usage?.(...args),
|
|
255
|
+
devApps: (...args) => impl?.devApps?.(...args),
|
|
256
|
+
devInspectBundle: (...args) => impl?.devInspectBundle?.(...args),
|
|
257
|
+
devDisableApp: (...args) => impl?.devDisableApp?.(...args),
|
|
258
|
+
devSetAppStatus: (...args) => impl?.devSetAppStatus?.(...args),
|
|
259
|
+
registerApp: (...args) => impl?.registerApp?.(...args),
|
|
260
|
+
appVersions: (...args) => impl?.appVersions?.(...args),
|
|
261
|
+
integrationDocs: (...args) => impl?.integrationDocs?.(...args),
|
|
262
|
+
integrationDocsInternal: (...args) => impl?.integrationDocsInternal?.(...args),
|
|
263
|
+
grantBridgeScope: (...args) => impl?.grantBridgeScope?.(...args),
|
|
264
|
+
bridgeUser: (...args) => impl?.bridgeUser?.(...args),
|
|
265
|
+
bridgeDesktopMessage: (...args) => impl?.bridgeDesktopMessage?.(...args),
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function credentialsUnchanged(prev, next) {
|
|
270
|
+
return prev.backendUrl === next.backendUrl
|
|
271
|
+
&& prev.token === next.token
|
|
272
|
+
&& prev.coreUrl === next.coreUrl
|
|
273
|
+
&& prev.hostAccessSecret === next.hostAccessSecret
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function applyModuleOptions(store, options = {}) {
|
|
277
|
+
const prevCredentials = { ...store.credentials }
|
|
278
|
+
const nextCredentials = buildCredentials(options)
|
|
279
|
+
Object.assign(store.credentials, nextCredentials)
|
|
280
|
+
const credsUnchanged = credentialsUnchanged(prevCredentials, nextCredentials)
|
|
281
|
+
|
|
282
|
+
const nextPublic = buildPublicOptions({ ...options, token: options.token ?? store.credentials.token })
|
|
283
|
+
Object.assign(store.options, {
|
|
284
|
+
language: nextPublic.language,
|
|
285
|
+
theme: nextPublic.theme,
|
|
286
|
+
themeToggle: nextPublic.themeToggle,
|
|
287
|
+
openAppStoreOnMount: nextPublic.openAppStoreOnMount,
|
|
288
|
+
allowedRuntimeOrigins: nextPublic.allowedRuntimeOrigins,
|
|
289
|
+
coreUrl: nextPublic.coreUrl,
|
|
290
|
+
backendUrl: nextPublic.backendUrl,
|
|
291
|
+
hasToken: nextPublic.hasToken,
|
|
292
|
+
allowSameOriginEmbed: nextPublic.allowSameOriginEmbed,
|
|
293
|
+
allowUnsafeOrigin: nextPublic.allowUnsafeOrigin,
|
|
294
|
+
hubOrigin: nextPublic.hubOrigin,
|
|
295
|
+
runtimePublicUrl: nextPublic.runtimePublicUrl,
|
|
296
|
+
enforceDedicatedHubOrigin: nextPublic.enforceDedicatedHubOrigin,
|
|
297
|
+
enforceIsolatedHostedRuntime: nextPublic.enforceIsolatedHostedRuntime,
|
|
298
|
+
allowSameOriginHostedRuntime: nextPublic.allowSameOriginHostedRuntime,
|
|
299
|
+
hostedSandboxSameOrigin: nextPublic.hostedSandboxSameOrigin,
|
|
300
|
+
enforceDevFriendlyOrigins: nextPublic.enforceDevFriendlyOrigins,
|
|
301
|
+
})
|
|
302
|
+
applyOriginSafety(store.options, options)
|
|
303
|
+
if (store.credentials.backendUrl && store.credentials.token) {
|
|
304
|
+
if (credsUnchanged) {
|
|
305
|
+
reconcileOriginSafety(store)
|
|
306
|
+
} else {
|
|
307
|
+
void startBootstrapSession(store)
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
reconcileOriginSafety(store)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function syncApi(store) {
|
|
315
|
+
const { credentials, facade, zoneContext } = store
|
|
316
|
+
const api = credentials.backendUrl && credentials.token
|
|
317
|
+
? createAppHubApi(credentials.backendUrl, credentials.token, {
|
|
318
|
+
hostAccessSecret: credentials.hostAccessSecret,
|
|
319
|
+
getZoneHeaderId: () => zoneContext?.getZoneHeaderId?.() ?? null,
|
|
320
|
+
})
|
|
321
|
+
: null
|
|
322
|
+
facade.setImpl(api)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function syncCoreApi(store) {
|
|
326
|
+
const { credentials } = store
|
|
327
|
+
store.coreApi = credentials.coreUrl && credentials.token
|
|
328
|
+
? createCoreApi(credentials.coreUrl, credentials.token)
|
|
329
|
+
: null
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function ensureZoneContext(app, store) {
|
|
333
|
+
if (store.zoneContext) return
|
|
334
|
+
store.zoneContext = createZoneContextState(
|
|
335
|
+
() => store.coreApi,
|
|
336
|
+
() => store.facade,
|
|
337
|
+
{
|
|
338
|
+
ensureBootstrapSession: () => fetchBootstrapSession(store),
|
|
339
|
+
},
|
|
340
|
+
)
|
|
341
|
+
app.provide(APPHUB_ZONE_CONTEXT_KEY, store.zoneContext)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function syncZoneContext(store) {
|
|
345
|
+
syncCoreApi(store)
|
|
346
|
+
if (store.zoneContext) {
|
|
347
|
+
store.zoneContext.refresh({ skipBootstrap: true })
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function ensureModuleState(app, store) {
|
|
352
|
+
if (store.windowManager && store.appStore) {
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
store.windowManager = createWindowManagerState()
|
|
357
|
+
store.appStore = createAppStoreState()
|
|
358
|
+
provideWindowManager(app, store.windowManager)
|
|
359
|
+
provideAppStore(app, store.appStore)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Install App Hub — Windows desktop shell + modular apps (App Store default).
|
|
364
|
+
* Returns host API facade — keep in host app code, not publisher apps.
|
|
365
|
+
*/
|
|
366
|
+
export function installAppHubModule(vueApp, options = {}) {
|
|
367
|
+
let store = getAppHubStore(vueApp)
|
|
368
|
+
|
|
369
|
+
if (store) {
|
|
370
|
+
vueApp.provide('apphubHostApp', vueApp)
|
|
371
|
+
vueApp.provide(APPHUB_MODULE_STORE_KEY, store)
|
|
372
|
+
applyModuleOptions(store, options)
|
|
373
|
+
ensureModuleInfrastructure(vueApp, store)
|
|
374
|
+
reconcileOriginSafety(store)
|
|
375
|
+
return store.facade
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const facade = createApiFacade()
|
|
379
|
+
const moduleOptions = reactive(buildPublicOptions(options))
|
|
380
|
+
applyOriginSafety(moduleOptions, options)
|
|
381
|
+
const credentials = buildCredentials(options)
|
|
382
|
+
|
|
383
|
+
store = {
|
|
384
|
+
app: vueApp,
|
|
385
|
+
facade,
|
|
386
|
+
options: moduleOptions,
|
|
387
|
+
credentials,
|
|
388
|
+
coreApi: null,
|
|
389
|
+
zoneContext: null,
|
|
390
|
+
windowManager: null,
|
|
391
|
+
appStore: null,
|
|
392
|
+
}
|
|
393
|
+
registerAppHubStore(vueApp, store)
|
|
394
|
+
|
|
395
|
+
vueApp.provide('apphubOptions', moduleOptions)
|
|
396
|
+
vueApp.provide('apphubHostApp', vueApp)
|
|
397
|
+
vueApp.provide(APPHUB_MODULE_STORE_KEY, store)
|
|
398
|
+
vueApp.component('AppHubDesktop', AppHubDesktop)
|
|
399
|
+
vueApp.component('AppHubRunner', AppHubRunner)
|
|
400
|
+
|
|
401
|
+
ensureModuleInfrastructure(vueApp, store)
|
|
402
|
+
void startBootstrapSession(store)
|
|
403
|
+
|
|
404
|
+
return facade
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** Whether installAppHubModule has been called for this Vue app instance. */
|
|
408
|
+
export function isAppHubModuleInstalled(vueApp) {
|
|
409
|
+
return vueApp != null && getAppHubStore(vueApp) != null
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export { useAppHubHostApi, useAppHubModuleStore } from './composables/useAppHubHostApi.js'
|
|
413
|
+
export { useAppHubZoneContext } from './composables/useAppHubZoneContext.js'
|
|
414
|
+
export { createAppHubApi } from './api/index.js'
|
|
415
|
+
export { createCoreApi } from './api/coreApi.js'
|
|
416
|
+
export { AppHubDesktop } from './modules/desktop/index.js'
|
|
417
|
+
export {
|
|
418
|
+
createDesktopNotificationsState,
|
|
419
|
+
useDesktopNotifications,
|
|
420
|
+
AppHubDesktopNotifications,
|
|
421
|
+
parseApiError,
|
|
422
|
+
} from './modules/notifications/index.js'
|
|
423
|
+
export { AppHubRunner } from './modules/runner/index.js'
|
|
424
|
+
export { resolveLang } from './i18n/resolveLang.js'
|
|
425
|
+
export { resolveTheme, normalizeTheme, isThemeLocked } from './i18n/resolveTheme.js'
|
|
426
|
+
export { t } from './i18n/index.js'
|
|
427
|
+
export {
|
|
428
|
+
evaluateOriginSafety,
|
|
429
|
+
isEmbeddedFrame,
|
|
430
|
+
isLocalDevOrigin,
|
|
431
|
+
parseOriginsFromBootstrap,
|
|
432
|
+
resolveEffectiveOrigins,
|
|
433
|
+
ORIGIN_UNSAFE_SAME_ORIGIN_EMBED,
|
|
434
|
+
ORIGIN_UNSAFE_NOT_CONFIGURED,
|
|
435
|
+
ORIGIN_UNSAFE_WRONG_ORIGIN,
|
|
436
|
+
ORIGIN_UNSAFE_RUNTIME_NOT_CONFIGURED,
|
|
437
|
+
ORIGIN_UNSAFE_RUNTIME_SAME_ORIGIN,
|
|
438
|
+
resolveRuntimeApiBase,
|
|
439
|
+
} from './utils/originSafety.js'
|
|
440
|
+
|
|
441
|
+
/** True when installAppHubModule blocked due to unsafe same-origin embed. */
|
|
442
|
+
export function isAppHubOriginBlocked(vueApp) {
|
|
443
|
+
const store = getAppHubStore(vueApp)
|
|
444
|
+
return store?.options?.originBlocked === true
|
|
445
|
+
}
|
|
446
|
+
export * from './modules/app-store/index.js'
|
|
447
|
+
export * from './modules/window-manager/index.js'
|
|
448
|
+
export * from './modules/runner/index.js'
|
|
449
|
+
|
|
@@ -109,7 +109,6 @@ import { resolveLang } from '../../../i18n/resolveLang.js'
|
|
|
109
109
|
import { CATALOG_MODE_STORE } from '../constants/catalogModes.js'
|
|
110
110
|
import { useCatalogInfiniteScroll } from '../composables/useCatalogInfiniteScroll.js'
|
|
111
111
|
import { useAppStore } from '../composables/useAppStore.js'
|
|
112
|
-
import { apphubDebug, describeHostApi } from '../../../utils/apphubDebug.js'
|
|
113
112
|
import AppHubAppStoreCard from './AppHubAppStoreCard.vue'
|
|
114
113
|
import AppHubAppStoreSettingsPanel from './AppHubAppStoreSettingsPanel.vue'
|
|
115
114
|
|
|
@@ -160,20 +159,8 @@ function hostApiOptions() {
|
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
|
|
163
|
-
async function reloadCatalog(
|
|
164
|
-
|
|
165
|
-
const opts = hostApiOptions()
|
|
166
|
-
apphubDebug('app-store', 'reloadCatalog', {
|
|
167
|
-
source,
|
|
168
|
-
storeFromInject: !!hubStore,
|
|
169
|
-
...describeHostApi(api),
|
|
170
|
-
backendReady: opts.backendReady,
|
|
171
|
-
originBootstrapLoading: moduleOptions?.originBootstrapLoading,
|
|
172
|
-
originBlocked: moduleOptions?.originBlocked,
|
|
173
|
-
catalogLoaded: catalog.loaded,
|
|
174
|
-
catalogError: catalog.error,
|
|
175
|
-
})
|
|
176
|
-
await appStore.loadCatalog(api, opts)
|
|
162
|
+
async function reloadCatalog() {
|
|
163
|
+
await appStore.loadCatalog(hostApi, hostApiOptions())
|
|
177
164
|
}
|
|
178
165
|
|
|
179
166
|
async function loadMore() {
|
|
@@ -204,28 +191,21 @@ async function onUninstall(app) {
|
|
|
204
191
|
}
|
|
205
192
|
|
|
206
193
|
onMounted(() => {
|
|
207
|
-
if (!catalog.loaded) reloadCatalog(
|
|
194
|
+
if (!catalog.loaded) reloadCatalog()
|
|
208
195
|
})
|
|
209
196
|
|
|
210
197
|
watch(
|
|
211
198
|
() => moduleOptions?.hasToken,
|
|
212
199
|
(hasToken) => {
|
|
213
|
-
if (hasToken && !catalog.loaded) reloadCatalog(
|
|
200
|
+
if (hasToken && !catalog.loaded) reloadCatalog()
|
|
214
201
|
},
|
|
215
202
|
)
|
|
216
203
|
|
|
217
204
|
watch(
|
|
218
205
|
() => moduleOptions?.originBootstrapLoading,
|
|
219
206
|
(loading, wasLoading) => {
|
|
220
|
-
apphubDebug('app-store', 'watch originBootstrapLoading', {
|
|
221
|
-
loading,
|
|
222
|
-
wasLoading,
|
|
223
|
-
originBlocked: moduleOptions?.originBlocked,
|
|
224
|
-
catalogLoaded: catalog.loaded,
|
|
225
|
-
catalogError: catalog.error,
|
|
226
|
-
})
|
|
227
207
|
if (wasLoading && !loading && !moduleOptions?.originBlocked) {
|
|
228
|
-
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog(
|
|
208
|
+
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog()
|
|
229
209
|
}
|
|
230
210
|
},
|
|
231
211
|
)
|
|
@@ -233,7 +213,7 @@ watch(
|
|
|
233
213
|
watch(
|
|
234
214
|
() => [zone?.state?.selectedZoneId, zone?.state?.viewAllZones],
|
|
235
215
|
() => {
|
|
236
|
-
if (moduleOptions?.hasToken) reloadCatalog(
|
|
216
|
+
if (moduleOptions?.hasToken) reloadCatalog()
|
|
237
217
|
},
|
|
238
218
|
)
|
|
239
219
|
</script>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { computed, inject, reactive } from 'vue'
|
|
2
2
|
import { CATALOG_MODE_DRAFT, CATALOG_MODE_STORE } from '../constants/catalogModes.js'
|
|
3
3
|
import { normalizeCatalogList } from '../utils/normalizeCatalogApp.js'
|
|
4
|
-
import { apphubDebug, describeHostApi } from '../../../utils/apphubDebug.js'
|
|
5
4
|
|
|
6
5
|
const APP_STORE_KEY = 'apphubAppStore'
|
|
7
6
|
|
|
@@ -109,20 +108,7 @@ export function createAppStoreState(options = {}) {
|
|
|
109
108
|
const append = options.append === true
|
|
110
109
|
const backendReady = options.backendReady !== false
|
|
111
110
|
|
|
112
|
-
apphubDebug('catalog', 'loadCatalog called', {
|
|
113
|
-
mode,
|
|
114
|
-
append,
|
|
115
|
-
backendReady,
|
|
116
|
-
...describeHostApi(hostApi),
|
|
117
|
-
})
|
|
118
|
-
|
|
119
111
|
if (!backendReady || !hostApiReady(hostApi)) {
|
|
120
|
-
apphubDebug('catalog', 'loadCatalog → no_api (not ready)', {
|
|
121
|
-
mode,
|
|
122
|
-
append,
|
|
123
|
-
backendReady,
|
|
124
|
-
...describeHostApi(hostApi),
|
|
125
|
-
})
|
|
126
112
|
if (!append) {
|
|
127
113
|
bucket.items = []
|
|
128
114
|
bucket.error = 'no_api'
|
|
@@ -151,16 +137,8 @@ export function createAppStoreState(options = {}) {
|
|
|
151
137
|
}
|
|
152
138
|
|
|
153
139
|
const res = await hostApi.apps(params)
|
|
154
|
-
apphubDebug('catalog', 'loadCatalog apps() response', {
|
|
155
|
-
mode,
|
|
156
|
-
append,
|
|
157
|
-
...describeHostApi(hostApi),
|
|
158
|
-
resUndefined: res === undefined,
|
|
159
|
-
resNull: res === null,
|
|
160
|
-
})
|
|
161
140
|
if (res === undefined || res === null) {
|
|
162
141
|
if (!append) {
|
|
163
|
-
apphubDebug('catalog', 'loadCatalog → no_api (undefined response)', { mode })
|
|
164
142
|
bucket.items = []
|
|
165
143
|
bucket.error = 'no_api'
|
|
166
144
|
bucket.loaded = false
|
package/src/utils/apphubDebug.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/** Temporary diagnostics — filter console with `[apphub:debug]`. Disable: localStorage.setItem('apphub:debug','0') */
|
|
2
|
-
export function isAppHubDebugEnabled() {
|
|
3
|
-
try {
|
|
4
|
-
if (typeof localStorage !== 'undefined' && localStorage.getItem('apphub:debug') === '0') {
|
|
5
|
-
return false
|
|
6
|
-
}
|
|
7
|
-
if (typeof window !== 'undefined' && window.__APPHUB_DEBUG__ === false) {
|
|
8
|
-
return false
|
|
9
|
-
}
|
|
10
|
-
} catch {
|
|
11
|
-
/* ignore */
|
|
12
|
-
}
|
|
13
|
-
return true
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function apphubDebug(scope, message, data) {
|
|
17
|
-
if (!isAppHubDebugEnabled()) return
|
|
18
|
-
const payload = data !== undefined ? { ts: Date.now(), ...data } : { ts: Date.now() }
|
|
19
|
-
console.info(`[apphub:debug] ${scope}: ${message}`, payload)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function describeHostApi(hostApi) {
|
|
23
|
-
if (!hostApi) return { hostApi: null }
|
|
24
|
-
return {
|
|
25
|
-
hasImpl: typeof hostApi.hasImpl === 'function' ? hostApi.hasImpl() : null,
|
|
26
|
-
hasAppsFn: typeof hostApi.apps === 'function',
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function describeStore(store) {
|
|
31
|
-
if (!store) return { store: null }
|
|
32
|
-
return {
|
|
33
|
-
hasImpl: store.facade?.hasImpl?.() ?? null,
|
|
34
|
-
originBootstrapLoading: store.options?.originBootstrapLoading ?? null,
|
|
35
|
-
originBlocked: store.options?.originBlocked ?? null,
|
|
36
|
-
originBlockReason: store.options?.originBlockReason ?? null,
|
|
37
|
-
hasToken: store.options?.hasToken ?? null,
|
|
38
|
-
backendUrl: store.credentials?.backendUrl ? '(set)' : '(empty)',
|
|
39
|
-
token: store.credentials?.token ? `(len ${store.credentials.token.length})` : '(empty)',
|
|
40
|
-
serverOriginsResolved: store.options?.serverOriginsResolved ?? null,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function describeApp(app) {
|
|
45
|
-
if (!app) return { app: null }
|
|
46
|
-
return { appUid: app._uid ?? null }
|
|
47
|
-
}
|