@kennofizet/apphub-frontend 0.1.5 → 0.1.7
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 +1 -1
- package/src/index.js +94 -17
- package/src/modules/app-store/components/AppHubAppStoreApp.vue +41 -7
- package/src/modules/app-store/components/AppHubDraftStoreApp.vue +10 -1
- package/src/modules/app-store/composables/useAppStore.js +29 -1
- package/src/utils/apphubDebug.js +47 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
loadBootstrapCache,
|
|
25
25
|
saveBootstrapCache,
|
|
26
26
|
} from './utils/bootstrapCache.js'
|
|
27
|
+
import {
|
|
28
|
+
apphubDebug,
|
|
29
|
+
describeHostApi,
|
|
30
|
+
describeStore,
|
|
31
|
+
} from './utils/apphubDebug.js'
|
|
27
32
|
|
|
28
33
|
const bootstrapInflight = new WeakMap()
|
|
29
34
|
|
|
@@ -136,6 +141,7 @@ function applyBootstrapOrigins(store, bootstrapResponse, { fromCache = false } =
|
|
|
136
141
|
reconcileOriginSafety(store)
|
|
137
142
|
store.options.originBootstrapLoading = false
|
|
138
143
|
applyOriginSafety(store.options)
|
|
144
|
+
apphubDebug('bootstrap', 'applyBootstrapOrigins done', describeStore(store))
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
function applyCachedBootstrapIfAny(store) {
|
|
@@ -150,12 +156,24 @@ async function fetchBootstrapSession(store) {
|
|
|
150
156
|
if (promise) return promise
|
|
151
157
|
|
|
152
158
|
promise = (async () => {
|
|
159
|
+
apphubDebug('bootstrap', 'fetchBootstrapSession start', describeStore(store))
|
|
153
160
|
syncApi(store)
|
|
154
|
-
if (!store.facade?.bootstrap)
|
|
161
|
+
if (!store.facade?.bootstrap) {
|
|
162
|
+
apphubDebug('bootstrap', 'fetchBootstrapSession abort — no bootstrap fn', describeStore(store))
|
|
163
|
+
return
|
|
164
|
+
}
|
|
155
165
|
|
|
156
166
|
const res = await store.facade.bootstrap()
|
|
167
|
+
apphubDebug('bootstrap', 'fetchBootstrapSession bootstrap response', {
|
|
168
|
+
...describeStore(store),
|
|
169
|
+
hasResponse: !!res,
|
|
170
|
+
})
|
|
157
171
|
if (res) applyBootstrapOrigins(store, res)
|
|
158
|
-
})().catch(() => {
|
|
172
|
+
})().catch((err) => {
|
|
173
|
+
apphubDebug('bootstrap', 'fetchBootstrapSession failed', {
|
|
174
|
+
...describeStore(store),
|
|
175
|
+
error: err?.message ?? String(err),
|
|
176
|
+
})
|
|
159
177
|
store.options.originBootstrapLoading = false
|
|
160
178
|
if (!store.options.serverOriginsResolved) {
|
|
161
179
|
reconcileOriginSafety(store)
|
|
@@ -170,6 +188,11 @@ async function fetchBootstrapSession(store) {
|
|
|
170
188
|
|
|
171
189
|
function startBootstrapSession(store) {
|
|
172
190
|
const { backendUrl, token } = store.credentials
|
|
191
|
+
apphubDebug('bootstrap', 'startBootstrapSession', {
|
|
192
|
+
...describeStore(store),
|
|
193
|
+
hasBackendUrl: !!backendUrl,
|
|
194
|
+
hasToken: !!token,
|
|
195
|
+
})
|
|
173
196
|
if (!backendUrl || !token) {
|
|
174
197
|
store.options.originBootstrapLoading = false
|
|
175
198
|
reconcileOriginSafety(store)
|
|
@@ -180,11 +203,15 @@ function startBootstrapSession(store) {
|
|
|
180
203
|
applyOriginSafety(store.options)
|
|
181
204
|
|
|
182
205
|
const hadCache = applyCachedBootstrapIfAny(store)
|
|
206
|
+
apphubDebug('bootstrap', 'startBootstrapSession after cache', {
|
|
207
|
+
hadCache,
|
|
208
|
+
...describeStore(store),
|
|
209
|
+
})
|
|
183
210
|
if (!hadCache && !store.options.originBlocked) {
|
|
184
211
|
store.options.originBootstrapLoading = true
|
|
185
212
|
store.options.originBlocked = false
|
|
186
213
|
applyOriginSafety(store.options)
|
|
187
|
-
disableModuleServices(store)
|
|
214
|
+
disableModuleServices(store, 'startBootstrapSession:no-cache')
|
|
188
215
|
}
|
|
189
216
|
|
|
190
217
|
return fetchBootstrapSession(store)
|
|
@@ -195,21 +222,30 @@ function reconcileOriginSafety(store) {
|
|
|
195
222
|
const wasLoading = store.options.originBootstrapLoading === true
|
|
196
223
|
applyOriginSafety(store.options)
|
|
197
224
|
|
|
225
|
+
let action = 'noop'
|
|
198
226
|
if (store.options.originBootstrapLoading) {
|
|
199
|
-
disableModuleServices(store)
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
disableModuleServices(store)
|
|
227
|
+
disableModuleServices(store, 'reconcileOriginSafety:loading')
|
|
228
|
+
action = 'disable:loading'
|
|
229
|
+
} else if (store.options.originBlocked && !wasBlocked) {
|
|
230
|
+
disableModuleServices(store, 'reconcileOriginSafety:blocked')
|
|
231
|
+
action = 'disable:blocked'
|
|
205
232
|
} else if (!store.options.originBlocked && (wasBlocked || wasLoading)) {
|
|
206
233
|
enableModuleApi(store)
|
|
234
|
+
action = 'enable'
|
|
207
235
|
}
|
|
236
|
+
|
|
237
|
+
apphubDebug('origin', 'reconcileOriginSafety', {
|
|
238
|
+
wasLoading,
|
|
239
|
+
wasBlocked,
|
|
240
|
+
action,
|
|
241
|
+
...describeStore(store),
|
|
242
|
+
})
|
|
208
243
|
}
|
|
209
244
|
|
|
210
|
-
function disableModuleServices(store) {
|
|
245
|
+
function disableModuleServices(store, reason = 'unknown') {
|
|
211
246
|
store.facade.setImpl(null)
|
|
212
247
|
store.coreApi = null
|
|
248
|
+
apphubDebug('api', 'disableModuleServices', { reason, ...describeStore(store) })
|
|
213
249
|
}
|
|
214
250
|
|
|
215
251
|
/** Window manager + app store — required even when origin is blocked (AppHubDesktop setup). */
|
|
@@ -221,6 +257,7 @@ function ensureModuleInfrastructure(vueApp, store) {
|
|
|
221
257
|
function enableModuleApi(store) {
|
|
222
258
|
syncApi(store)
|
|
223
259
|
syncZoneContext(store)
|
|
260
|
+
apphubDebug('api', 'enableModuleApi', describeStore(store))
|
|
224
261
|
}
|
|
225
262
|
|
|
226
263
|
function enableModuleServices(vueApp, store) {
|
|
@@ -243,6 +280,9 @@ function createApiFacade() {
|
|
|
243
280
|
setImpl(next) {
|
|
244
281
|
impl = next
|
|
245
282
|
},
|
|
283
|
+
hasImpl() {
|
|
284
|
+
return impl != null
|
|
285
|
+
},
|
|
246
286
|
bootstrap: (...args) => impl?.bootstrap?.(...args),
|
|
247
287
|
apps: (...args) => impl?.apps?.(...args),
|
|
248
288
|
launch: (...args) => impl?.launch?.(...args),
|
|
@@ -263,7 +303,19 @@ function createApiFacade() {
|
|
|
263
303
|
}
|
|
264
304
|
}
|
|
265
305
|
|
|
306
|
+
function credentialsUnchanged(prev, next) {
|
|
307
|
+
return prev.backendUrl === next.backendUrl
|
|
308
|
+
&& prev.token === next.token
|
|
309
|
+
&& prev.coreUrl === next.coreUrl
|
|
310
|
+
&& prev.hostAccessSecret === next.hostAccessSecret
|
|
311
|
+
}
|
|
312
|
+
|
|
266
313
|
function applyModuleOptions(store, options = {}) {
|
|
314
|
+
const prevCredentials = { ...store.credentials }
|
|
315
|
+
const nextCredentials = buildCredentials(options)
|
|
316
|
+
Object.assign(store.credentials, nextCredentials)
|
|
317
|
+
const credsUnchanged = credentialsUnchanged(prevCredentials, nextCredentials)
|
|
318
|
+
|
|
267
319
|
const nextPublic = buildPublicOptions({ ...options, token: options.token ?? store.credentials.token })
|
|
268
320
|
Object.assign(store.options, {
|
|
269
321
|
language: nextPublic.language,
|
|
@@ -285,12 +337,23 @@ function applyModuleOptions(store, options = {}) {
|
|
|
285
337
|
enforceDevFriendlyOrigins: nextPublic.enforceDevFriendlyOrigins,
|
|
286
338
|
})
|
|
287
339
|
applyOriginSafety(store.options, options)
|
|
340
|
+
const branch = !store.credentials.backendUrl || !store.credentials.token
|
|
341
|
+
? 'no-credentials'
|
|
342
|
+
: (credsUnchanged ? 'creds-unchanged' : 'start-bootstrap')
|
|
343
|
+
apphubDebug('install', 'applyModuleOptions', {
|
|
344
|
+
branch,
|
|
345
|
+
credsUnchanged,
|
|
346
|
+
...describeStore(store),
|
|
347
|
+
})
|
|
288
348
|
if (store.credentials.backendUrl && store.credentials.token) {
|
|
289
|
-
|
|
349
|
+
if (credsUnchanged) {
|
|
350
|
+
reconcileOriginSafety(store)
|
|
351
|
+
} else {
|
|
352
|
+
void startBootstrapSession(store)
|
|
353
|
+
}
|
|
290
354
|
} else {
|
|
291
355
|
reconcileOriginSafety(store)
|
|
292
356
|
}
|
|
293
|
-
Object.assign(store.credentials, buildCredentials(options))
|
|
294
357
|
}
|
|
295
358
|
|
|
296
359
|
function syncApi(store) {
|
|
@@ -302,6 +365,10 @@ function syncApi(store) {
|
|
|
302
365
|
})
|
|
303
366
|
: null
|
|
304
367
|
facade.setImpl(api)
|
|
368
|
+
apphubDebug('api', 'syncApi', {
|
|
369
|
+
implSet: api != null,
|
|
370
|
+
...describeStore(store),
|
|
371
|
+
})
|
|
305
372
|
}
|
|
306
373
|
|
|
307
374
|
function syncCoreApi(store) {
|
|
@@ -349,16 +416,25 @@ export function installAppHubModule(vueApp, options = {}) {
|
|
|
349
416
|
let store = getAppHubStore(vueApp)
|
|
350
417
|
|
|
351
418
|
if (store) {
|
|
419
|
+
vueApp.provide('apphubHostApp', vueApp)
|
|
420
|
+
apphubDebug('install', 'installAppHubModule re-install', {
|
|
421
|
+
appUid: vueApp._uid ?? null,
|
|
422
|
+
hasToken: !!(options.token),
|
|
423
|
+
theme: options.theme,
|
|
424
|
+
language: options.language,
|
|
425
|
+
})
|
|
352
426
|
applyModuleOptions(store, options)
|
|
353
427
|
ensureModuleInfrastructure(vueApp, store)
|
|
354
|
-
|
|
355
|
-
disableModuleServices(store)
|
|
356
|
-
} else {
|
|
357
|
-
enableModuleApi(store)
|
|
358
|
-
}
|
|
428
|
+
reconcileOriginSafety(store)
|
|
359
429
|
return store.facade
|
|
360
430
|
}
|
|
361
431
|
|
|
432
|
+
apphubDebug('install', 'installAppHubModule first install', {
|
|
433
|
+
appUid: vueApp._uid ?? null,
|
|
434
|
+
hasToken: !!(options.token),
|
|
435
|
+
backendUrl: options.backendUrl ? '(set)' : '(empty)',
|
|
436
|
+
})
|
|
437
|
+
|
|
362
438
|
const facade = createApiFacade()
|
|
363
439
|
const moduleOptions = reactive(buildPublicOptions(options))
|
|
364
440
|
applyOriginSafety(moduleOptions, options)
|
|
@@ -377,6 +453,7 @@ export function installAppHubModule(vueApp, options = {}) {
|
|
|
377
453
|
registerAppHubStore(vueApp, store)
|
|
378
454
|
|
|
379
455
|
vueApp.provide('apphubOptions', moduleOptions)
|
|
456
|
+
vueApp.provide('apphubHostApp', vueApp)
|
|
380
457
|
vueApp.component('AppHubDesktop', AppHubDesktop)
|
|
381
458
|
vueApp.component('AppHubRunner', AppHubRunner)
|
|
382
459
|
|
|
@@ -109,6 +109,7 @@ 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, describeApp, describeHostApi } from '../../../utils/apphubDebug.js'
|
|
112
113
|
import AppHubAppStoreCard from './AppHubAppStoreCard.vue'
|
|
113
114
|
import AppHubAppStoreSettingsPanel from './AppHubAppStoreSettingsPanel.vue'
|
|
114
115
|
|
|
@@ -122,7 +123,8 @@ const props = defineProps({
|
|
|
122
123
|
const settingsOpen = ref(false)
|
|
123
124
|
const appStore = useAppStore()
|
|
124
125
|
const catalog = appStore.catalogs.store
|
|
125
|
-
const rootApp = resolveRootApp(getCurrentInstance())
|
|
126
|
+
const rootApp = inject('apphubHostApp', null) ?? resolveRootApp(getCurrentInstance())
|
|
127
|
+
const rootAppSource = inject('apphubHostApp', null) ? 'inject' : 'resolveRootApp'
|
|
126
128
|
const zone = useAppHubZoneContext()
|
|
127
129
|
const moduleOptions = inject('apphubOptions', {})
|
|
128
130
|
const lang = computed(() => resolveLang(moduleOptions?.language, 'vi'))
|
|
@@ -157,9 +159,25 @@ function hostApiOptions() {
|
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
async function reloadCatalog() {
|
|
161
|
-
if (!rootApp)
|
|
162
|
-
|
|
162
|
+
async function reloadCatalog(source = 'manual') {
|
|
163
|
+
if (!rootApp) {
|
|
164
|
+
apphubDebug('app-store', 'reloadCatalog skipped — no rootApp', { source, rootAppSource })
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
const hostApi = getHostApiForApp(rootApp)
|
|
168
|
+
const opts = hostApiOptions()
|
|
169
|
+
apphubDebug('app-store', 'reloadCatalog', {
|
|
170
|
+
source,
|
|
171
|
+
rootAppSource,
|
|
172
|
+
...describeApp(rootApp),
|
|
173
|
+
...describeHostApi(hostApi),
|
|
174
|
+
backendReady: opts.backendReady,
|
|
175
|
+
originBootstrapLoading: moduleOptions?.originBootstrapLoading,
|
|
176
|
+
originBlocked: moduleOptions?.originBlocked,
|
|
177
|
+
catalogLoaded: catalog.loaded,
|
|
178
|
+
catalogError: catalog.error,
|
|
179
|
+
})
|
|
180
|
+
await appStore.loadCatalog(hostApi, opts)
|
|
163
181
|
}
|
|
164
182
|
|
|
165
183
|
async function loadMore() {
|
|
@@ -191,20 +209,36 @@ async function onUninstall(app) {
|
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
onMounted(() => {
|
|
194
|
-
if (!catalog.loaded) reloadCatalog()
|
|
212
|
+
if (!catalog.loaded) reloadCatalog('onMounted')
|
|
195
213
|
})
|
|
196
214
|
|
|
197
215
|
watch(
|
|
198
216
|
() => moduleOptions?.hasToken,
|
|
199
217
|
(hasToken) => {
|
|
200
|
-
if (hasToken && !catalog.loaded) reloadCatalog()
|
|
218
|
+
if (hasToken && !catalog.loaded) reloadCatalog('watch:hasToken')
|
|
219
|
+
},
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
watch(
|
|
223
|
+
() => moduleOptions?.originBootstrapLoading,
|
|
224
|
+
(loading, wasLoading) => {
|
|
225
|
+
apphubDebug('app-store', 'watch originBootstrapLoading', {
|
|
226
|
+
loading,
|
|
227
|
+
wasLoading,
|
|
228
|
+
originBlocked: moduleOptions?.originBlocked,
|
|
229
|
+
catalogLoaded: catalog.loaded,
|
|
230
|
+
catalogError: catalog.error,
|
|
231
|
+
})
|
|
232
|
+
if (wasLoading && !loading && !moduleOptions?.originBlocked) {
|
|
233
|
+
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog('watch:bootstrap-done')
|
|
234
|
+
}
|
|
201
235
|
},
|
|
202
236
|
)
|
|
203
237
|
|
|
204
238
|
watch(
|
|
205
239
|
() => [zone?.state?.selectedZoneId, zone?.state?.viewAllZones],
|
|
206
240
|
() => {
|
|
207
|
-
if (moduleOptions?.hasToken) reloadCatalog()
|
|
241
|
+
if (moduleOptions?.hasToken) reloadCatalog('watch:zone')
|
|
208
242
|
},
|
|
209
243
|
)
|
|
210
244
|
</script>
|
|
@@ -83,7 +83,7 @@ const props = defineProps({
|
|
|
83
83
|
|
|
84
84
|
const appStore = useAppStore()
|
|
85
85
|
const catalog = appStore.catalogs.draft
|
|
86
|
-
const rootApp = resolveRootApp(getCurrentInstance())
|
|
86
|
+
const rootApp = inject('apphubHostApp', null) ?? resolveRootApp(getCurrentInstance())
|
|
87
87
|
const zone = useAppHubZoneContext()
|
|
88
88
|
const moduleOptions = inject('apphubOptions', {})
|
|
89
89
|
const lang = computed(() => resolveLang(moduleOptions?.language, 'vi'))
|
|
@@ -175,6 +175,15 @@ watch(
|
|
|
175
175
|
},
|
|
176
176
|
)
|
|
177
177
|
|
|
178
|
+
watch(
|
|
179
|
+
() => moduleOptions?.originBootstrapLoading,
|
|
180
|
+
(loading, wasLoading) => {
|
|
181
|
+
if (wasLoading && !loading && !moduleOptions?.originBlocked) {
|
|
182
|
+
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog()
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
178
187
|
watch(
|
|
179
188
|
() => [zone?.state?.selectedZoneId, zone?.state?.viewAllZones],
|
|
180
189
|
() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
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'
|
|
4
5
|
|
|
5
6
|
const APP_STORE_KEY = 'apphubAppStore'
|
|
6
7
|
|
|
@@ -28,6 +29,12 @@ function filterItems(items, search) {
|
|
|
28
29
|
)
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
function hostApiReady(hostApi) {
|
|
33
|
+
if (!hostApi?.apps) return false
|
|
34
|
+
if (typeof hostApi.hasImpl === 'function') return hostApi.hasImpl()
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
/**
|
|
32
39
|
* Independent App Store module — separate catalog buckets per mode (store / draft).
|
|
33
40
|
*/
|
|
@@ -102,7 +109,20 @@ export function createAppStoreState(options = {}) {
|
|
|
102
109
|
const append = options.append === true
|
|
103
110
|
const backendReady = options.backendReady !== false
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
apphubDebug('catalog', 'loadCatalog called', {
|
|
113
|
+
mode,
|
|
114
|
+
append,
|
|
115
|
+
backendReady,
|
|
116
|
+
...describeHostApi(hostApi),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
if (!backendReady || !hostApiReady(hostApi)) {
|
|
120
|
+
apphubDebug('catalog', 'loadCatalog → no_api (not ready)', {
|
|
121
|
+
mode,
|
|
122
|
+
append,
|
|
123
|
+
backendReady,
|
|
124
|
+
...describeHostApi(hostApi),
|
|
125
|
+
})
|
|
106
126
|
if (!append) {
|
|
107
127
|
bucket.items = []
|
|
108
128
|
bucket.error = 'no_api'
|
|
@@ -131,8 +151,16 @@ export function createAppStoreState(options = {}) {
|
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
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
|
+
})
|
|
134
161
|
if (res === undefined || res === null) {
|
|
135
162
|
if (!append) {
|
|
163
|
+
apphubDebug('catalog', 'loadCatalog → no_api (undefined response)', { mode })
|
|
136
164
|
bucket.items = []
|
|
137
165
|
bucket.error = 'no_api'
|
|
138
166
|
bucket.loaded = false
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
}
|