@kennofizet/apphub-frontend 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/composables/useAppHubHostApi.js +6 -0
- package/src/index.js +19 -3
- package/src/modules/app-store/components/AppHubAppStoreApp.vue +24 -4
- package/src/modules/app-store/components/AppHubDraftStoreApp.vue +24 -4
- package/src/modules/app-store/composables/useAppStore.js +1 -1
package/package.json
CHANGED
|
@@ -15,6 +15,12 @@ export function isBackendReadyForApp(app) {
|
|
|
15
15
|
return !!(store?.credentials?.backendUrl && store?.credentials?.token)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export function isHostApiReadyForApp(app) {
|
|
19
|
+
const store = getAppHubStore(app)
|
|
20
|
+
if (!store?.credentials?.backendUrl || !store?.credentials?.token) return false
|
|
21
|
+
return store.facade?.hasImpl?.() === true
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* Host-only API — use in Hub shell components. Not provided via inject
|
|
20
26
|
* so publisher app code cannot access grantBridgeScope or internal docs.
|
package/src/index.js
CHANGED
|
@@ -120,7 +120,6 @@ function applyBootstrapOrigins(store, bootstrapResponse, { fromCache = false } =
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
store.options.serverOriginsResolved = true
|
|
123
|
-
store.options.originBootstrapLoading = false
|
|
124
123
|
|
|
125
124
|
if (!fromCache) {
|
|
126
125
|
saveBootstrapCache(store.credentials.backendUrl, bootstrapResponse)
|
|
@@ -132,7 +131,14 @@ function applyBootstrapOrigins(store, bootstrapResponse, { fromCache = false } =
|
|
|
132
131
|
store.zoneContext.state.user.name = user.name
|
|
133
132
|
}
|
|
134
133
|
|
|
134
|
+
// Reconcile while originBootstrapLoading may still be true so enableModuleApi runs
|
|
135
|
+
// after disableModuleServices (wasLoading must be captured before clearing the flag).
|
|
135
136
|
reconcileOriginSafety(store)
|
|
137
|
+
store.options.originBootstrapLoading = false
|
|
138
|
+
applyOriginSafety(store.options)
|
|
139
|
+
if (!store.options.originBlocked) {
|
|
140
|
+
enableModuleApi(store)
|
|
141
|
+
}
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
function applyCachedBootstrapIfAny(store) {
|
|
@@ -153,9 +159,12 @@ async function fetchBootstrapSession(store) {
|
|
|
153
159
|
const res = await store.facade.bootstrap()
|
|
154
160
|
if (res) applyBootstrapOrigins(store, res)
|
|
155
161
|
})().catch(() => {
|
|
162
|
+
const wasLoading = store.options.originBootstrapLoading === true
|
|
156
163
|
store.options.originBootstrapLoading = false
|
|
157
164
|
if (!store.options.serverOriginsResolved) {
|
|
158
165
|
reconcileOriginSafety(store)
|
|
166
|
+
} else if (!store.options.originBlocked && (wasLoading || !store.facade?.hasImpl?.())) {
|
|
167
|
+
enableModuleApi(store)
|
|
159
168
|
}
|
|
160
169
|
}).finally(() => {
|
|
161
170
|
bootstrapInflight.delete(store)
|
|
@@ -240,6 +249,9 @@ function createApiFacade() {
|
|
|
240
249
|
setImpl(next) {
|
|
241
250
|
impl = next
|
|
242
251
|
},
|
|
252
|
+
hasImpl() {
|
|
253
|
+
return impl != null
|
|
254
|
+
},
|
|
243
255
|
bootstrap: (...args) => impl?.bootstrap?.(...args),
|
|
244
256
|
apps: (...args) => impl?.apps?.(...args),
|
|
245
257
|
launch: (...args) => impl?.launch?.(...args),
|
|
@@ -281,13 +293,13 @@ function applyModuleOptions(store, options = {}) {
|
|
|
281
293
|
hostedSandboxSameOrigin: nextPublic.hostedSandboxSameOrigin,
|
|
282
294
|
enforceDevFriendlyOrigins: nextPublic.enforceDevFriendlyOrigins,
|
|
283
295
|
})
|
|
296
|
+
Object.assign(store.credentials, buildCredentials(options))
|
|
284
297
|
applyOriginSafety(store.options, options)
|
|
285
298
|
if (store.credentials.backendUrl && store.credentials.token) {
|
|
286
299
|
void startBootstrapSession(store)
|
|
287
300
|
} else {
|
|
288
301
|
reconcileOriginSafety(store)
|
|
289
302
|
}
|
|
290
|
-
Object.assign(store.credentials, buildCredentials(options))
|
|
291
303
|
}
|
|
292
304
|
|
|
293
305
|
function syncApi(store) {
|
|
@@ -378,7 +390,11 @@ export function installAppHubModule(vueApp, options = {}) {
|
|
|
378
390
|
vueApp.component('AppHubRunner', AppHubRunner)
|
|
379
391
|
|
|
380
392
|
ensureModuleInfrastructure(vueApp, store)
|
|
381
|
-
void startBootstrapSession(store)
|
|
393
|
+
void startBootstrapSession(store).then(() => {
|
|
394
|
+
if (!store.options.originBlocked) {
|
|
395
|
+
enableModuleApi(store)
|
|
396
|
+
}
|
|
397
|
+
})
|
|
382
398
|
|
|
383
399
|
return facade
|
|
384
400
|
}
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
import { computed, getCurrentInstance, inject, onMounted, ref, watch } from 'vue'
|
|
101
101
|
import {
|
|
102
102
|
getHostApiForApp,
|
|
103
|
-
|
|
103
|
+
isHostApiReadyForApp,
|
|
104
104
|
resolveRootApp,
|
|
105
105
|
} from '../../../composables/useAppHubHostApi.js'
|
|
106
106
|
import { useAppHubZoneContext } from '../../../composables/useAppHubZoneContext.js'
|
|
@@ -152,11 +152,19 @@ const labels = computed(() => ({
|
|
|
152
152
|
|
|
153
153
|
function hostApiOptions() {
|
|
154
154
|
return {
|
|
155
|
-
backendReady:
|
|
155
|
+
backendReady: isHostApiReadyForApp(rootApp),
|
|
156
156
|
mode: CATALOG_MODE_STORE,
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
function canLoadCatalog() {
|
|
161
|
+
return (
|
|
162
|
+
!moduleOptions?.originBootstrapLoading
|
|
163
|
+
&& !moduleOptions?.originBlocked
|
|
164
|
+
&& isHostApiReadyForApp(rootApp)
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
160
168
|
async function reloadCatalog() {
|
|
161
169
|
if (!rootApp) return
|
|
162
170
|
await appStore.loadCatalog(getHostApiForApp(rootApp), hostApiOptions())
|
|
@@ -197,14 +205,26 @@ onMounted(() => {
|
|
|
197
205
|
watch(
|
|
198
206
|
() => moduleOptions?.hasToken,
|
|
199
207
|
(hasToken) => {
|
|
200
|
-
if (hasToken && !catalog.loaded) reloadCatalog()
|
|
208
|
+
if (hasToken && canLoadCatalog() && !catalog.loaded) reloadCatalog()
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
watch(
|
|
213
|
+
() => [
|
|
214
|
+
moduleOptions?.originBootstrapLoading,
|
|
215
|
+
moduleOptions?.originBlocked,
|
|
216
|
+
isHostApiReadyForApp(rootApp),
|
|
217
|
+
],
|
|
218
|
+
() => {
|
|
219
|
+
if (!canLoadCatalog()) return
|
|
220
|
+
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog()
|
|
201
221
|
},
|
|
202
222
|
)
|
|
203
223
|
|
|
204
224
|
watch(
|
|
205
225
|
() => [zone?.state?.selectedZoneId, zone?.state?.viewAllZones],
|
|
206
226
|
() => {
|
|
207
|
-
if (
|
|
227
|
+
if (canLoadCatalog()) reloadCatalog()
|
|
208
228
|
},
|
|
209
229
|
)
|
|
210
230
|
</script>
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
import { computed, getCurrentInstance, inject, onMounted, reactive, ref, watch } from 'vue'
|
|
66
66
|
import {
|
|
67
67
|
getHostApiForApp,
|
|
68
|
-
|
|
68
|
+
isHostApiReadyForApp,
|
|
69
69
|
resolveRootApp,
|
|
70
70
|
} from '../../../composables/useAppHubHostApi.js'
|
|
71
71
|
import { useAppHubZoneContext } from '../../../composables/useAppHubZoneContext.js'
|
|
@@ -119,11 +119,19 @@ const labels = computed(() => ({
|
|
|
119
119
|
|
|
120
120
|
function hostApiOptions() {
|
|
121
121
|
return {
|
|
122
|
-
backendReady:
|
|
122
|
+
backendReady: isHostApiReadyForApp(rootApp),
|
|
123
123
|
mode: CATALOG_MODE_DRAFT,
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
function canLoadCatalog() {
|
|
128
|
+
return (
|
|
129
|
+
!moduleOptions?.originBootstrapLoading
|
|
130
|
+
&& !moduleOptions?.originBlocked
|
|
131
|
+
&& isHostApiReadyForApp(rootApp)
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
async function reloadCatalog() {
|
|
128
136
|
if (!rootApp) return
|
|
129
137
|
await appStore.loadCatalog(getHostApiForApp(rootApp), hostApiOptions())
|
|
@@ -171,14 +179,26 @@ onMounted(() => {
|
|
|
171
179
|
watch(
|
|
172
180
|
() => moduleOptions?.hasToken,
|
|
173
181
|
(hasToken) => {
|
|
174
|
-
if (hasToken && !catalog.loaded) reloadCatalog()
|
|
182
|
+
if (hasToken && canLoadCatalog() && !catalog.loaded) reloadCatalog()
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
watch(
|
|
187
|
+
() => [
|
|
188
|
+
moduleOptions?.originBootstrapLoading,
|
|
189
|
+
moduleOptions?.originBlocked,
|
|
190
|
+
isHostApiReadyForApp(rootApp),
|
|
191
|
+
],
|
|
192
|
+
() => {
|
|
193
|
+
if (!canLoadCatalog()) return
|
|
194
|
+
if (!catalog.loaded || catalog.error === 'no_api') reloadCatalog()
|
|
175
195
|
},
|
|
176
196
|
)
|
|
177
197
|
|
|
178
198
|
watch(
|
|
179
199
|
() => [zone?.state?.selectedZoneId, zone?.state?.viewAllZones],
|
|
180
200
|
() => {
|
|
181
|
-
if (
|
|
201
|
+
if (canLoadCatalog()) reloadCatalog()
|
|
182
202
|
},
|
|
183
203
|
)
|
|
184
204
|
</script>
|
|
@@ -102,7 +102,7 @@ export function createAppStoreState(options = {}) {
|
|
|
102
102
|
const append = options.append === true
|
|
103
103
|
const backendReady = options.backendReady !== false
|
|
104
104
|
|
|
105
|
-
if (!backendReady || !hostApi?.
|
|
105
|
+
if (!backendReady || !hostApi?.hasImpl?.()) {
|
|
106
106
|
if (!append) {
|
|
107
107
|
bucket.items = []
|
|
108
108
|
bucket.error = 'no_api'
|