diff --git a/packages/frontend-2/.cursor/rules/nuxt-patterns.mdc b/packages/frontend-2/.cursor/rules/nuxt-patterns.mdc index e21d610a5..e17733f50 100644 --- a/packages/frontend-2/.cursor/rules/nuxt-patterns.mdc +++ b/packages/frontend-2/.cursor/rules/nuxt-patterns.mdc @@ -88,12 +88,12 @@ export default defineNuxtPlugin(() => { ```typescript // middleware/auth.ts (route middleware) -export default defineNuxtRouteMiddleware((to, from) => { +export default defineParallelizedNuxtRouteMiddleware((to, from) => { // Route protection logic }) // middleware/global.global.ts (global middleware) -export default defineNuxtRouteMiddleware((to, from) => { +export default defineParallelizedNuxtRouteMiddleware((to, from) => { // Runs on every route change }) ``` diff --git a/packages/frontend-2/components/error/page/GenericErrorBlock.vue b/packages/frontend-2/components/error/page/GenericErrorBlock.vue index cfd0c11b2..161410b02 100644 --- a/packages/frontend-2/components/error/page/GenericErrorBlock.vue +++ b/packages/frontend-2/components/error/page/GenericErrorBlock.vue @@ -14,9 +14,10 @@
+ class="whitespace-pre-line font-mono max-w-xl text-body-xs text-foreground-2" + > + {{ error.stack.trim() }} +
Go home diff --git a/packages/frontend-2/components/project/model-page/versions/CardActions.vue b/packages/frontend-2/components/project/model-page/versions/CardActions.vue index aa17b835e..b5dbd2ffd 100644 --- a/packages/frontend-2/components/project/model-page/versions/CardActions.vue +++ b/packages/frontend-2/components/project/model-page/versions/CardActions.vue @@ -4,6 +4,7 @@ diff --git a/packages/frontend-2/lib/core/helpers/middleware.ts b/packages/frontend-2/lib/core/helpers/middleware.ts new file mode 100644 index 000000000..95528032c --- /dev/null +++ b/packages/frontend-2/lib/core/helpers/middleware.ts @@ -0,0 +1,68 @@ +import type { RouteMiddleware } from '#app' +import type { NavigationGuardReturn } from '#vue-router' +import { isUndefinedOrVoid } from '@speckle/shared' +import { useScopedState } from '~/lib/common/composables/scopedState' + +const useMiddlewareParallelizationState = () => + useScopedState('middleware_parallelization', () => ({ + middlewares: [] as Array<() => Promise> + })) + +/** + * Make the middleware process in parallel with other middlewares and only get fully awaited at the end + */ +const withParallelization = (middleware: RouteMiddleware): RouteMiddleware => { + return (...args) => { + const app = useNuxtApp() + const { + public: { parallelMiddlewares } + } = useRuntimeConfig() + if (!parallelMiddlewares) { + return middleware(...args) + } + + const { middlewares } = useMiddlewareParallelizationState() + middlewares.push(async () => app.runWithContext(() => middleware(...args))) + } +} + +/** + * defineParallelizedNuxtRouteMiddleware() w/ parallelization support + */ +export const defineParallelizedNuxtRouteMiddleware = ( + middleware: RouteMiddleware +): RouteMiddleware => { + return withParallelization(middleware) +} + +export const useFinalizeParallelMiddlewares = () => { + const state = useMiddlewareParallelizationState() + const logger = useLogger() + + return { + finalize: async () => { + const middlewares = state.middlewares + if (!middlewares.length) { + return + } + + logger.debug('Finalizing {count} parallel middlewares', { + count: middlewares.length, + middlewares + }) + + try { + const results = await Promise.all(middlewares.map((m) => m())) + + // Report results + for (const resultItem of results) { + if (!isUndefinedOrVoid(resultItem) && resultItem !== true) { + return resultItem + } + } + } finally { + state.middlewares.length = 0 + } + } + } +} diff --git a/packages/frontend-2/middleware/001-fe2-header.global.ts b/packages/frontend-2/middleware/001-fe2-header.global.ts index d6bacc647..85b9d0d68 100644 --- a/packages/frontend-2/middleware/001-fe2-header.global.ts +++ b/packages/frontend-2/middleware/001-fe2-header.global.ts @@ -1,4 +1,4 @@ -export default defineNuxtRouteMiddleware(() => { +export default defineParallelizedNuxtRouteMiddleware(() => { // Add response header that shows this is a FE2 request const { ssrContext } = useNuxtApp() if (ssrContext) { diff --git a/packages/frontend-2/middleware/002-redirects.global.ts b/packages/frontend-2/middleware/002-redirects.global.ts index 7d256f29f..834047e73 100644 --- a/packages/frontend-2/middleware/002-redirects.global.ts +++ b/packages/frontend-2/middleware/002-redirects.global.ts @@ -67,7 +67,7 @@ const adminPageRgx = /^\/admin\/?/ * Setting up all kinds of redirects (e.g. for FE1 backwards compatibility) */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const logger = useLogger() const path = to.path const apollo = useApolloClientFromNuxt() diff --git a/packages/frontend-2/middleware/003-acceptInvites.global.ts b/packages/frontend-2/middleware/003-acceptInvites.global.ts index 4baa0ef1a..79c0c9ea0 100644 --- a/packages/frontend-2/middleware/003-acceptInvites.global.ts +++ b/packages/frontend-2/middleware/003-acceptInvites.global.ts @@ -23,7 +23,7 @@ const autoAcceptableWorkspaceInviteQuery = graphql(` /** * Handles all of the invite auto-accepting logic (when clicking on email accept links) */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const isWorkspacesEnabled = useIsWorkspacesEnabled() const shouldTryProjectAccept = to.path.startsWith('/projects/') diff --git a/packages/frontend-2/middleware/004-onboarding.global.ts b/packages/frontend-2/middleware/004-onboarding.global.ts index d14b5c066..5a01ea020 100644 --- a/packages/frontend-2/middleware/004-onboarding.global.ts +++ b/packages/frontend-2/middleware/004-onboarding.global.ts @@ -19,16 +19,21 @@ import { convertThrowIntoFetchResult } from '~~/lib/common/helpers/graphql' import { buildActiveUserWorkspaceExistenceCheckQuery } from '~/lib/workspaces/helpers/middleware' import { useMiddlewareQueryFetchPolicy } from '~/lib/core/composables/navigation' -export default defineNuxtRouteMiddleware(async (to, from) => { +export default defineParallelizedNuxtRouteMiddleware(async (to, from) => { const isAuthPage = to.path.startsWith('/authn/') const isSSOPath = to.path.includes('/sso/') if (isAuthPage || isSSOPath) return const client = useApolloClientFromNuxt() const fetchPolicy = useMiddlewareQueryFetchPolicy() + const isWorkspacesEnabled = useIsWorkspacesEnabled() // Fetch required data - const [{ data: serverInfoData }, { data: userData }] = await Promise.all([ + const [ + { data: serverInfoData }, + { data: userData }, + { data: workspaceExistenceData } + ] = await Promise.all([ client .query({ query: mainServerInfoDataQuery @@ -39,7 +44,17 @@ export default defineNuxtRouteMiddleware(async (to, from) => { query: activeUserQuery, fetchPolicy: fetchPolicy(to, from) }) - .catch(convertThrowIntoFetchResult) + .catch(convertThrowIntoFetchResult), + ...(isWorkspacesEnabled.value + ? [ + client + .query({ + ...buildActiveUserWorkspaceExistenceCheckQuery(), + fetchPolicy: fetchPolicy(to, from) + }) + .catch(convertThrowIntoFetchResult) + ] + : [{ data: undefined }]) ]) // If user is not logged in, skip all checks @@ -81,17 +96,9 @@ export default defineNuxtRouteMiddleware(async (to, from) => { // 3. Workspace join/create redirect // Everything past this point is only relevant for workspace enabled instances - const isWorkspacesEnabled = useIsWorkspacesEnabled() if (!isWorkspacesEnabled.value) return - const { data: workspaceExistenceData } = await client - .query({ - ...buildActiveUserWorkspaceExistenceCheckQuery(), - fetchPolicy: fetchPolicy(to, from) - }) - .catch(convertThrowIntoFetchResult) - const workspaces = workspaceExistenceData?.activeUser?.workspaces?.items ?? [] const hasWorkspaces = workspaces.length > 0 const hasDiscoverableWorkspaces = diff --git a/packages/frontend-2/middleware/999-parallelFinalize.ts b/packages/frontend-2/middleware/999-parallelFinalize.ts new file mode 100644 index 000000000..f7b1ae013 --- /dev/null +++ b/packages/frontend-2/middleware/999-parallelFinalize.ts @@ -0,0 +1,9 @@ +import { useFinalizeParallelMiddlewares } from '~/lib/core/helpers/middleware' + +/** + * Should be the very last middleware that's run on ALL pages and navigations + */ +export default defineNuxtRouteMiddleware(async () => { + const { finalize } = useFinalizeParallelMiddlewares() + return await finalize() +}) diff --git a/packages/frontend-2/middleware/admin.ts b/packages/frontend-2/middleware/admin.ts index 20b0cfb0f..55dc822d9 100644 --- a/packages/frontend-2/middleware/admin.ts +++ b/packages/frontend-2/middleware/admin.ts @@ -6,7 +6,7 @@ import { Roles } from '@speckle/shared' /** * Apply this to a page to prevent access by non-admin users */ -export default defineNuxtRouteMiddleware(async () => { +export default defineParallelizedNuxtRouteMiddleware(async () => { const client = useApolloClientFromNuxt() const { data } = await client diff --git a/packages/frontend-2/middleware/auth.ts b/packages/frontend-2/middleware/auth.ts index a0fc2488d..c239d0626 100644 --- a/packages/frontend-2/middleware/auth.ts +++ b/packages/frontend-2/middleware/auth.ts @@ -7,7 +7,7 @@ import { loginRoute } from '~~/lib/common/helpers/route' /** * Apply this to a page to prevent unauthenticated access */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const nuxt = useNuxtApp() const client = useApolloClientFromNuxt() const postAuthRedirect = usePostAuthRedirect({ route: to }) diff --git a/packages/frontend-2/middleware/canViewProjectTokens.ts b/packages/frontend-2/middleware/canViewProjectTokens.ts index 98b084f37..c045b8077 100644 --- a/packages/frontend-2/middleware/canViewProjectTokens.ts +++ b/packages/frontend-2/middleware/canViewProjectTokens.ts @@ -19,7 +19,7 @@ const canViewProjectTokensQuery = graphql(` /** * Apply this to a page to prevent unauthenticated access to tokens and ensure the user is the owner */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const client = useApolloClientFromNuxt() const projectId = to.params.id as string diff --git a/packages/frontend-2/middleware/canViewSettings.ts b/packages/frontend-2/middleware/canViewSettings.ts index 5707a92d4..596897d12 100644 --- a/packages/frontend-2/middleware/canViewSettings.ts +++ b/packages/frontend-2/middleware/canViewSettings.ts @@ -19,7 +19,7 @@ const canViewProjectSettingsQuery = graphql(` /** * Apply this to a page to prevent unauthenticated access to settings ensuring the user is a collaborator */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const client = useApolloClientFromNuxt() // Fetch project role data to check if the user is a collaborator diff --git a/packages/frontend-2/middleware/canViewWebhooks.ts b/packages/frontend-2/middleware/canViewWebhooks.ts index 130bffa33..3cca1e7d1 100644 --- a/packages/frontend-2/middleware/canViewWebhooks.ts +++ b/packages/frontend-2/middleware/canViewWebhooks.ts @@ -19,7 +19,7 @@ const canViewProjectWebhooksQuery = graphql(` /** * Apply this to a page to prevent unauthenticated access to webhooks and ensure the user is the owner */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const client = useApolloClientFromNuxt() // Fetch project role data to check if the user is the owner diff --git a/packages/frontend-2/middleware/dashboardRedirect.ts b/packages/frontend-2/middleware/dashboardRedirect.ts index 970a069fd..d20972129 100644 --- a/packages/frontend-2/middleware/dashboardRedirect.ts +++ b/packages/frontend-2/middleware/dashboardRedirect.ts @@ -2,7 +2,7 @@ import { projectsRoute, workspaceRoute } from '~/lib/common/helpers/route' import { useApolloClientFromNuxt } from '~~/lib/common/composables/graphql' import { activeUserActiveWorkspaceCheckQuery } from '~/lib/auth/graphql/queries' -export default defineNuxtRouteMiddleware(async () => { +export default defineParallelizedNuxtRouteMiddleware(async () => { const isWorkspacesEnabled = useIsWorkspacesEnabled() const client = useApolloClientFromNuxt() diff --git a/packages/frontend-2/middleware/guest.ts b/packages/frontend-2/middleware/guest.ts index b4018bb30..7cdbc44f0 100644 --- a/packages/frontend-2/middleware/guest.ts +++ b/packages/frontend-2/middleware/guest.ts @@ -8,7 +8,7 @@ const exclusionList = ['authorize-app', 'reset-password'] /** * Apply this to a page to prevent authenticated access */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const nuxt = useNuxtApp() const client = useApolloClientFromNuxt() diff --git a/packages/frontend-2/middleware/headers.global.ts b/packages/frontend-2/middleware/headers.global.ts index 19d6a4327..d9ba822c9 100644 --- a/packages/frontend-2/middleware/headers.global.ts +++ b/packages/frontend-2/middleware/headers.global.ts @@ -1,4 +1,4 @@ -export default defineNuxtRouteMiddleware((to) => { +export default defineParallelizedNuxtRouteMiddleware((to) => { const { ssrContext } = useNuxtApp() if (ssrContext) { diff --git a/packages/frontend-2/middleware/projectsActiveCheck.ts b/packages/frontend-2/middleware/projectsActiveCheck.ts index 1375b27c2..30c0aedf7 100644 --- a/packages/frontend-2/middleware/projectsActiveCheck.ts +++ b/packages/frontend-2/middleware/projectsActiveCheck.ts @@ -3,7 +3,7 @@ import { useSetActiveWorkspace } from '~/lib/user/composables/activeWorkspace' /** * Clear active workspace when navigating to the projects page */ -export default defineNuxtRouteMiddleware(async () => { +export default defineParallelizedNuxtRouteMiddleware(async () => { const { setActiveWorkspace } = useSetActiveWorkspace() const { isLoggedIn } = useActiveUser() const isWorkspacesEnabled = useIsWorkspacesEnabled() diff --git a/packages/frontend-2/middleware/requireDiscoverableWorkspaces.ts b/packages/frontend-2/middleware/requireDiscoverableWorkspaces.ts index b95265460..f2c815ef2 100644 --- a/packages/frontend-2/middleware/requireDiscoverableWorkspaces.ts +++ b/packages/frontend-2/middleware/requireDiscoverableWorkspaces.ts @@ -6,7 +6,7 @@ import { homeRoute, workspaceCreateRoute } from '~~/lib/common/helpers/route' /** * Redirect user to /workspaces/actions/create, if they have no discoverable workspaces */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const isWorkspacesEnabled = useIsWorkspacesEnabled() if (!isWorkspacesEnabled.value) return diff --git a/packages/frontend-2/middleware/requireSsoEnabled.ts b/packages/frontend-2/middleware/requireSsoEnabled.ts index fc73c79f4..9ee47a240 100644 --- a/packages/frontend-2/middleware/requireSsoEnabled.ts +++ b/packages/frontend-2/middleware/requireSsoEnabled.ts @@ -5,7 +5,7 @@ import { useWorkspacePublicSsoCheck } from '~/lib/workspaces/composables/sso' /** * Used to validate that the workspace has SSO enabled, redirects to workspace page if not */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { // Skip middleware when handling SSO callback with access code. // This page serves as both the SSO login page and OAuth callback URL. // We need to let the callback through to process the access code before any redirects. diff --git a/packages/frontend-2/middleware/requireValidAutomation.ts b/packages/frontend-2/middleware/requireValidAutomation.ts index ec3beb931..82235b7dd 100644 --- a/packages/frontend-2/middleware/requireValidAutomation.ts +++ b/packages/frontend-2/middleware/requireValidAutomation.ts @@ -7,7 +7,7 @@ import { } from '~/lib/common/helpers/graphql' import { projectAutomationAccessCheckQuery } from '~/lib/projects/graphql/queries' -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const projectId = to.params.id as string // const automationId = to.params.aid as string diff --git a/packages/frontend-2/middleware/requireValidFunction.ts b/packages/frontend-2/middleware/requireValidFunction.ts index 3675694ec..d2bea23f5 100644 --- a/packages/frontend-2/middleware/requireValidFunction.ts +++ b/packages/frontend-2/middleware/requireValidFunction.ts @@ -5,7 +5,7 @@ import { getFirstErrorMessage } from '~/lib/common/helpers/graphql' -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const functionId = to.params.fid as string const isAutomateEnabled = useIsAutomateModuleEnabled() diff --git a/packages/frontend-2/middleware/requireValidModel.ts b/packages/frontend-2/middleware/requireValidModel.ts index 47b57c12d..65697a119 100644 --- a/packages/frontend-2/middleware/requireValidModel.ts +++ b/packages/frontend-2/middleware/requireValidModel.ts @@ -1,3 +1,4 @@ +import { useMiddlewareQueryFetchPolicy } from '~/lib/core/composables/navigation' import { castToSupportedVisibility, SupportedProjectVisibility @@ -13,16 +14,18 @@ import { projectModelCheckQuery } from '~~/lib/projects/graphql/queries' /** * Used in project page to validate that project ID refers to a valid project and redirects to 404 if not */ -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to, from) => { const projectId = to.params.id as string const modelId = to.params.modelId as string const client = useApolloClientFromNuxt() + const fetchPolicy = useMiddlewareQueryFetchPolicy() const { data, errors } = await client .query({ query: projectModelCheckQuery, - variables: { projectId, modelId } + variables: { projectId, modelId }, + fetchPolicy: fetchPolicy(to, from) }) .catch(convertThrowIntoFetchResult) diff --git a/packages/frontend-2/middleware/requireValidProject.ts b/packages/frontend-2/middleware/requireValidProject.ts index b2f4db147..29b11ba1e 100644 --- a/packages/frontend-2/middleware/requireValidProject.ts +++ b/packages/frontend-2/middleware/requireValidProject.ts @@ -13,7 +13,7 @@ import { useMiddlewareQueryFetchPolicy } from '~/lib/core/composables/navigation /** * Used in project page to validate that project ID refers to a valid project and redirects to 404 if not */ -export default defineNuxtRouteMiddleware(async (to, from) => { +export default defineParallelizedNuxtRouteMiddleware(async (to, from) => { const projectId = to.params.id as string // Check if embed token is present in URL diff --git a/packages/frontend-2/middleware/requireValidWorkspace.ts b/packages/frontend-2/middleware/requireValidWorkspace.ts index c021b73ac..8239dc3cf 100644 --- a/packages/frontend-2/middleware/requireValidWorkspace.ts +++ b/packages/frontend-2/middleware/requireValidWorkspace.ts @@ -10,7 +10,7 @@ import { useMiddlewareQueryFetchPolicy } from '~/lib/core/composables/navigation /** * Used to validate that the workspace ID refers to a valid workspace and redirects to 404 if not */ -export default defineNuxtRouteMiddleware(async (to, from) => { +export default defineParallelizedNuxtRouteMiddleware(async (to, from) => { const workspaceSlug = to.params.slug as string const client = useApolloClientFromNuxt() diff --git a/packages/frontend-2/middleware/requiresAutomateEnabled.ts b/packages/frontend-2/middleware/requiresAutomateEnabled.ts index 415ad63e8..36499160a 100644 --- a/packages/frontend-2/middleware/requiresAutomateEnabled.ts +++ b/packages/frontend-2/middleware/requiresAutomateEnabled.ts @@ -1,4 +1,4 @@ -export default defineNuxtRouteMiddleware(() => { +export default defineParallelizedNuxtRouteMiddleware(() => { const isAutomateEnabled = useIsAutomateModuleEnabled() if (!isAutomateEnabled.value) { return abortNavigation( diff --git a/packages/frontend-2/middleware/requiresWorkspacesEnabled.ts b/packages/frontend-2/middleware/requiresWorkspacesEnabled.ts index 5d7098ca7..5c944b0fb 100644 --- a/packages/frontend-2/middleware/requiresWorkspacesEnabled.ts +++ b/packages/frontend-2/middleware/requiresWorkspacesEnabled.ts @@ -1,4 +1,4 @@ -export default defineNuxtRouteMiddleware(() => { +export default defineParallelizedNuxtRouteMiddleware(() => { const isWorkspacesEnabled = useIsWorkspacesEnabled() // If workspaces are enabled, continue as normal diff --git a/packages/frontend-2/middleware/settings.ts b/packages/frontend-2/middleware/settings.ts index d4ed6be9d..e0a8f4e5c 100644 --- a/packages/frontend-2/middleware/settings.ts +++ b/packages/frontend-2/middleware/settings.ts @@ -1,6 +1,6 @@ import { useSettingsMenuState } from '~/lib/settings/composables/menu' -export default defineNuxtRouteMiddleware((to, from) => { +export default defineParallelizedNuxtRouteMiddleware((to, from) => { const settingsMenuState = useSettingsMenuState() if (to.path.startsWith('/settings') && !from.path.startsWith('/settings')) { diff --git a/packages/frontend-2/middleware/thread.ts b/packages/frontend-2/middleware/thread.ts index 3b37eacf4..e84d8695b 100644 --- a/packages/frontend-2/middleware/thread.ts +++ b/packages/frontend-2/middleware/thread.ts @@ -14,7 +14,7 @@ const resolveLinkQuery = graphql(` } `) -export default defineNuxtRouteMiddleware(async (to) => { +export default defineParallelizedNuxtRouteMiddleware(async (to) => { const client = useApolloClientFromNuxt() const threadId = to.params.threadId as string const projectId = to.params.id as string diff --git a/packages/frontend-2/nuxt.config.ts b/packages/frontend-2/nuxt.config.ts index 71d06fffd..df1d7d1bc 100644 --- a/packages/frontend-2/nuxt.config.ts +++ b/packages/frontend-2/nuxt.config.ts @@ -83,12 +83,14 @@ export default defineNuxtConfig({ datadogSite: '', datadogService: '', datadogEnv: '', - intercomAppId: '' + intercomAppId: '', + parallelMiddlewares: true } }, experimental: { - emitRouteChunkError: 'automatic-immediate' + emitRouteChunkError: 'automatic-immediate', + asyncContext: true // necessary for parallel middlewares }, alias: { @@ -171,7 +173,11 @@ export default defineNuxtConfig({ headers: { // No search engine indexing on any of the pages anywhere! TODO: Come up with a more appropriate policy 'X-Robots-Tag': 'noindex, nofollow, noarchive' - } + }, + appMiddleware: [ + // Has to be applied to all pages and as the very last app middleware (hence the 999 prefix) + '999-parallel-finalize' + ] }, '/functions': { redirect: { diff --git a/packages/frontend-2/utils/globals.ts b/packages/frontend-2/utils/globals.ts index 6b71b1c15..5365c80b5 100644 --- a/packages/frontend-2/utils/globals.ts +++ b/packages/frontend-2/utils/globals.ts @@ -14,6 +14,7 @@ import { } from '~/lib/common/helpers/graphql' import { checkIfIsInPlaceNavigation } from '~/lib/common/helpers/navigation' import { ViewerEventBusKeys } from '~/lib/viewer/helpers/eventBus' +import { defineParallelizedNuxtRouteMiddleware } from '~/lib/core/helpers/middleware' /** * Debugging helper to ensure variables are available in debugging scope @@ -40,5 +41,6 @@ export { ROOT_QUERY, ROOT_MUTATION, ROOT_SUBSCRIPTION, - ViewerEventBusKeys + ViewerEventBusKeys, + defineParallelizedNuxtRouteMiddleware }