fix(fe2): viewer SSR query optimization (#2129)

* fix(fe2): viewer SSR query optimization

* fix apollo upload link
This commit is contained in:
Kristaps Fabians Geikins
2024-03-14 11:13:59 +01:00
committed by GitHub
parent fab231a05e
commit baabae627c
12 changed files with 248 additions and 91 deletions
@@ -10,11 +10,15 @@
:separator="true"
class="hidden md:inline-block"
/>
<PortalTarget name="navigation"></PortalTarget>
<ClientOnly>
<PortalTarget name="navigation"></PortalTarget>
</ClientOnly>
</div>
<div class="flex items-center gap-2.5 sm:gap-2">
<PortalTarget name="secondary-actions"></PortalTarget>
<PortalTarget name="primary-actions"></PortalTarget>
<ClientOnly>
<PortalTarget name="secondary-actions"></PortalTarget>
<PortalTarget name="primary-actions"></PortalTarget>
</ClientOnly>
<!-- Notifications dropdown -->
<HeaderNavNotifications />
<FormButton
@@ -106,23 +106,25 @@ const startResizing = (event: MouseEvent) => {
startWidth = width.value
}
useEventListener(resizeHandle, 'mousedown', startResizing)
if (process.client) {
useEventListener(resizeHandle, 'mousedown', startResizing)
useEventListener(document, 'mousemove', (event) => {
if (isResizing.value) {
const diffX = startX - event.clientX
width.value = Math.max(
300,
Math.min(startWidth + diffX, (parseInt('75vw') * window.innerWidth) / 100)
)
}
})
useEventListener(document, 'mousemove', (event) => {
if (isResizing.value) {
const diffX = startX - event.clientX
width.value = Math.max(
300,
Math.min(startWidth + diffX, (parseInt('75vw') * window.innerWidth) / 100)
)
}
})
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
})
useEventListener(document, 'mouseup', () => {
if (isResizing.value) {
isResizing.value = false
}
})
}
const minimize = () => {
width.value = 300
@@ -1,5 +1,5 @@
<template>
<button
<div
:class="`bg-foundation group relative block w-full space-y-2 rounded-md pb-2 text-left transition ${
clickable
? 'hover:bg-gray-100 dark:hover:bg-gray-700'
@@ -8,6 +8,7 @@
${isLoaded ? '' : ''}
`"
@click="handleClick"
@keypress="keyboardClick(handleClick)"
>
<!-- Timeline left border -->
<div
@@ -66,10 +67,11 @@
</div>
</div>
</div>
</button>
</div>
</template>
<script setup lang="ts">
import { ChevronDownIcon } from '@heroicons/vue/24/solid'
import { keyboardClick } from '@speckle/ui-components'
import dayjs from 'dayjs'
import localizedFormat from 'dayjs/plugin/localizedFormat'
import type { ViewerModelVersionCardItemFragment } from '~~/lib/common/generated/gql/graphql'
@@ -4,7 +4,7 @@ import { ApolloLink, InMemoryCache, split, from } from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
import { SubscriptionClient } from 'subscriptions-transport-ws'
import type { ApolloConfigResolver } from '~~/lib/core/nuxt-modules/apollo/module'
import { createUploadLink } from 'apollo-upload-client'
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs'
import { WebSocketLink } from '@apollo/client/link/ws'
import { getMainDefinition } from '@apollo/client/utilities'
import { Kind } from 'graphql'
@@ -92,6 +92,7 @@ export function buildAbstractCollectionMergeFunction<T extends string>(
}
return {
...(incoming || {}),
__typename: incoming?.__typename || existing?.__typename || typeName,
totalCount: incoming.totalCount || 0,
cursor: incoming.cursor || null,
@@ -23,7 +23,7 @@ import type { ComputedRef, WritableComputedRef, Raw, Ref, ShallowRef } from 'vue
import { useScopedState } from '~~/lib/common/composables/scopedState'
import type { MaybeNullOrUndefined, Nullable, Optional } from '@speckle/shared'
import { SpeckleViewer, isNonNullable } from '@speckle/shared'
import { useApolloClient, useQuery } from '@vue/apollo-composable'
import { useApolloClient, useLazyQuery, useQuery } from '@vue/apollo-composable'
import {
projectViewerResourcesQuery,
viewerLoadedResourcesQuery,
@@ -66,6 +66,7 @@ import {
useSetupViewerScope
} from '~/lib/viewer/composables/setup/core'
import { useSynchronizedCookie } from '~~/lib/common/composables/reactiveCookie'
import { buildManualPromise } from '@speckle/ui-components'
export type LoadedModel = NonNullable<
Get<ViewerLoadedResourcesQuery, 'project.models.items[0]'>
@@ -164,6 +165,14 @@ export type InjectableViewerState = Readonly<{
resourceItemsQueryVariables: ComputedRef<
Optional<ProjectViewerResourcesQueryVariables>
>
/**
* Whether or not the initial resource items load has happened (useful in SSR)
*/
resourceItemsLoaded: ComputedRef<boolean>
/**
* Whether or not the initial resources (models, objects etc.) have been loaded (useful in SSR)
*/
resourcesLoaded: ComputedRef<boolean>
/**
* Model GQL objects paired with their loaded version IDs
*/
@@ -391,7 +400,20 @@ function setupInitialState(params: UseSetupViewerParams): InitialSetupState {
projectId,
sessionId,
viewer: process.server
? (undefined as unknown as InitialSetupState['viewer'])
? ({
instance: undefined,
container: undefined,
init: {
promise: new Promise(() => {}),
ref: computed(() => false)
},
metadata: {
worldTree: computed(() => undefined),
availableFilters: computed(() => undefined),
views: computed(() => []),
filteringState: computed(() => undefined)
}
} as unknown as InitialSetupState['viewer'])
: {
instance,
container,
@@ -504,7 +526,7 @@ function setupResponseResourceItems(
state: InitialStateWithRequest
): Pick<
InjectableViewerState['resources']['response'],
'resourceItems' | 'resourceItemsQueryVariables'
'resourceItems' | 'resourceItemsQueryVariables' | 'resourceItemsLoaded'
> {
const globalError = useError()
const {
@@ -514,10 +536,12 @@ function setupResponseResourceItems(
}
} = state
const initLoadDone = ref(process.server ? false : true)
const {
result: resolvedResourcesResult,
variables: resourceItemsQueryVariables,
onError
onError,
onResult
} = useQuery(
projectViewerResourcesQuery,
() => ({
@@ -532,6 +556,11 @@ function setupResponseResourceItems(
statusCode: 500,
message: `Viewer resource resolution failed: ${err}`
})
initLoadDone.value = true
})
onResult(() => {
initLoadDone.value = true
})
const resolvedResourceGroups = computed(
@@ -599,9 +628,12 @@ function setupResponseResourceItems(
return finalItems
})
const resourceItemsLoaded = computed(() => initLoadDone.value)
return {
resourceItems,
resourceItemsQueryVariables: computed(() => resourceItemsQueryVariables.value)
resourceItemsQueryVariables: computed(() => resourceItemsQueryVariables.value),
resourceItemsLoaded
}
}
@@ -610,7 +642,7 @@ function setupResponseResourceData(
resourceItemsData: ReturnType<typeof setupResponseResourceItems>
): Omit<
InjectableViewerState['resources']['response'],
'resourceItems' | 'resourceItemsQueryVariables'
'resourceItems' | 'resourceItemsQueryVariables' | 'resourceItemsLoaded'
> {
const apollo = useApolloClient().client
const globalError = useError()
@@ -624,8 +656,9 @@ function setupResponseResourceData(
},
urlHashState: { diff }
} = state
const { resourceItems } = resourceItemsData
const { resourceItems, resourceItemsLoaded } = resourceItemsData
const initLoadDone = ref(process.server ? false : true)
const objects = computed(() =>
resourceItems.value.filter((i) => !i.modelId && !i.versionId)
)
@@ -667,11 +700,30 @@ function setupResponseResourceData(
result: viewerLoadedResourcesResult,
variables: viewerLoadedResourcesVariables,
onError: onViewerLoadedResourcesError,
onResult: onViewerLoadedResourcesResult
} = useQuery(viewerLoadedResourcesQuery, viewerLoadedResourcesVariablesFunc, {
onResult: onViewerLoadedResourcesResult,
load: loadViewerLoadedResources
} = useLazyQuery(viewerLoadedResourcesQuery, viewerLoadedResourcesVariablesFunc, {
keepPreviousResult: true
})
const serverResourcesLoadedPromise = buildManualPromise<void>()
if (process.server) {
watch(
() => resourceItemsLoaded.value,
async (newVal, oldVal) => {
if (!newVal || oldVal) return
// Load only now - once the previous query is done
await loadViewerLoadedResources()
serverResourcesLoadedPromise.resolve()
},
{ flush: 'sync' }
)
} else {
loadViewerLoadedResources()
serverResourcesLoadedPromise.resolve()
}
const project = computed(() => viewerLoadedResourcesResult.value?.project)
const models = computed(() => project.value?.models?.items || [])
@@ -707,10 +759,12 @@ function setupResponseResourceData(
statusCode: 500,
message: `Viewer loaded resource resolution failed: ${err}`
})
initLoadDone.value = true
})
// Load initial batch of cursors for each model
onViewerLoadedResourcesResult((res) => {
initLoadDone.value = true
if (!res.data?.project?.models) return
for (const model of res.data.project.models.items) {
@@ -784,6 +838,10 @@ function setupResponseResourceData(
logger.error(err)
})
onServerPrefetch(async () => {
await Promise.all([serverResourcesLoadedPromise.promise])
})
return {
objects,
commentThreads,
@@ -793,7 +851,8 @@ function setupResponseResourceData(
project,
resourceQueryVariables: computed(() => viewerLoadedResourcesVariables.value),
threadsQueryVariables: computed(() => threadsQueryVariables.value),
loadMoreVersions
loadMoreVersions,
resourcesLoaded: computed(() => initLoadDone.value)
}
}
@@ -1,4 +1,4 @@
import { SpeckleViewer, timeoutAt } from '@speckle/shared'
import { SpeckleViewer, timeoutAt, type Optional } from '@speckle/shared'
import type { TreeNode } from '@speckle/viewer'
import { CameraController, MeasurementsExtension } from '@speckle/viewer'
import type { MeasurementOptions, PropertyInfo } from '@speckle/viewer'
@@ -63,9 +63,16 @@ export function useCameraUtilities() {
const setView = (...args: Parameters<typeof instance.setView>) => {
instance.setView(...args)
}
const cameraController = instance.getExtension(CameraController)
const truck = (...args: Parameters<typeof cameraController.controls.truck>) =>
let cameraController: Optional<CameraController> = undefined
const truck = (
...args: Parameters<NonNullable<typeof cameraController>['controls']['truck']>
) => {
if (!cameraController) {
cameraController = instance.getExtension(CameraController)
}
cameraController.controls.truck(...args)
}
const zoomExtentsOrSelection = () => {
const ids = selectedObjects.value.map((o) => o.id).filter(isNonNullable)
@@ -106,11 +113,7 @@ export function useCameraUtilities() {
export function useFilterUtilities() {
// const { instance } = useInjectedViewer()
const { filters, explodeFactor } = useInjectedViewerInterfaceState()
const {
viewer: {
metadata: { availableFilters }
}
} = useInjectedViewerState()
const { viewer } = useInjectedViewerState()
const isolateObjects = (
objectIds: string[],
@@ -196,7 +199,7 @@ export function useFilterUtilities() {
const timeout = options?.timeout || 10000
const res = await Promise.race([
until(availableFilters).toMatch(
until(viewer.metadata.availableFilters).toMatch(
(filters) => !!filters?.find((p) => p.key === key)
),
timeoutAt(timeout, 'Waiting for available filter timed out')
@@ -225,15 +228,15 @@ export function useSelectionUtilities() {
const {
filters: { selectedObjects, selectedObjectIds }
} = useInjectedViewerInterfaceState()
const {
metadata: { worldTree }
} = useInjectedViewer()
const { metadata } = useInjectedViewer()
const setSelectionFromObjectIds = (objectIds: string[]) => {
const objs: Array<SpeckleObject> = []
objectIds.forEach((value: string) => {
objs.push(
...((worldTree.value?.findId(value) || []) as unknown as TreeNode[]).map(
...(
(metadata?.worldTree.value?.findId(value) || []) as unknown as TreeNode[]
).map(
(node: TreeNode) =>
(node.model as Record<string, unknown>).raw as SpeckleObject
)
@@ -347,7 +350,7 @@ export function useThreadUtilities() {
if (id === focusedThreadId.value) return
await focusedThreadId.update(id)
await Promise.all([
until(focusedThreadId).toBe(id),
until(focusedThreadId).toMatch((tid) => tid === id),
until(openThread).toMatch((t) => t?.id === id)
])
}
+5 -5
View File
@@ -20,7 +20,7 @@
"gqlgen:watch": "graphql-codegen --watch"
},
"dependencies": {
"@apollo/client": "^3.8.4",
"@apollo/client": "^3.9.6",
"@artmizu/nuxt-prometheus": "^2.2.1",
"@headlessui/vue": "^1.7.13",
"@heroicons/vue": "^2.0.12",
@@ -44,10 +44,10 @@
"@tiptap/pm": "2.0.0-beta.220",
"@tiptap/suggestion": "2.0.0-beta.220",
"@tiptap/vue-3": "2.0.0-beta.220",
"@vue/apollo-composable": "4.0.0-beta.11",
"@vue/apollo-ssr": "4.0.0-beta.9",
"@vue/apollo-composable": "4.0.2",
"@vue/apollo-ssr": "4.0.0",
"@vueuse/core": "^9.13.0",
"apollo-upload-client": "^17.0.0",
"apollo-upload-client": "^18.0.1",
"dayjs": "^1.11.7",
"graphql": "^16.6.0",
"ioredis": "^5.3.2",
@@ -80,7 +80,7 @@
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@testing-library/vue": "^6.6.1",
"@types/apollo-upload-client": "^17.0.2",
"@types/apollo-upload-client": "^18.0.0",
"@types/eslint": "^8.4.5",
"@types/js-cookie": "^3.0.2",
"@types/lodash-es": "^4.17.6",
@@ -1,5 +1,6 @@
import type { Optional } from '@speckle/shared'
import { activeUserQuery } from '~/lib/auth/composables/activeUser'
import { loginServerInfoQuery } from '~/lib/auth/graphql/queries'
import { usePreloadApolloQueries } from '~/lib/common/composables/graphql'
import { mainServerInfoDataQuery } from '~/lib/core/composables/server'
import { projectAccessCheckQuery } from '~/lib/projects/graphql/queries'
@@ -44,5 +45,15 @@ export default defineNuxtPlugin(async (ctx) => {
)
}
// Preload viewer data
if (route.meta.key === '/projects/:id/models/resources') {
// Unable to preload this from vue components due to SSR being essentially turned off for the viewer
promises.push(
preload({
queries: [{ query: loginServerInfoQuery }]
})
)
}
await Promise.all(promises)
})
@@ -65,3 +65,20 @@ export function writableAsyncComputed<T>(
return getter
}
/**
* Build promise that can be resolved/rejected manually outside of the promise's execution scope
*/
export const buildManualPromise = <T>() => {
let resolve: (value: T) => void
let reject: (reason?: any) => void
const promise = new Promise<T>((res, rej) => {
resolve = res
reject = rej
})
const resolveWrapper: typeof resolve = (...args) => resolve(...args)
const rejectWrapper: typeof reject = (...args) => reject(...args)
return { promise, resolve: resolveWrapper, reject: rejectWrapper }
}
+6 -2
View File
@@ -59,7 +59,10 @@ import InfiniteLoading from '~~/src/components/InfiniteLoading.vue'
import type { InfiniteLoaderState } from '~~/src/helpers/global/components'
import LayoutPanel from '~~/src/components/layout/Panel.vue'
import CommonAlert from '~~/src/components/common/Alert.vue'
import { writableAsyncComputed } from '~~/src/composables/common/async'
import {
writableAsyncComputed,
buildManualPromise
} from '~~/src/composables/common/async'
import type {
AsyncWritableComputedOptions,
AsyncWritableComputedRef
@@ -138,7 +141,8 @@ export {
writableAsyncComputed,
useFormCheckboxModel,
FormTags,
keyboardClick
keyboardClick,
buildManualPromise
}
export type {
ToastNotification,
+93 -39
View File
@@ -53,25 +53,26 @@ __metadata:
languageName: node
linkType: hard
"@apollo/client@npm:^3.6.6, @apollo/client@npm:^3.7.0, @apollo/client@npm:^3.7.14, @apollo/client@npm:^3.8.4":
version: 3.8.4
resolution: "@apollo/client@npm:3.8.4"
"@apollo/client@npm:^3.6.6, @apollo/client@npm:^3.7.0, @apollo/client@npm:^3.7.14, @apollo/client@npm:^3.8.0, @apollo/client@npm:^3.9.6":
version: 3.9.7
resolution: "@apollo/client@npm:3.9.7"
dependencies:
"@graphql-typed-document-node/core": ^3.1.1
"@wry/context": ^0.7.3
"@wry/caches": ^1.0.0
"@wry/equality": ^0.5.6
"@wry/trie": ^0.4.3
"@wry/trie": ^0.5.0
graphql-tag: ^2.12.6
hoist-non-react-statics: ^3.3.2
optimism: ^0.17.5
optimism: ^0.18.0
prop-types: ^15.7.2
rehackt: 0.0.6
response-iterator: ^0.2.6
symbol-observable: ^4.0.0
ts-invariant: ^0.10.3
tslib: ^2.3.0
zen-observable-ts: ^1.2.5
peerDependencies:
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
graphql: ^15.0.0 || ^16.0.0
graphql-ws: ^5.5.5
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -85,7 +86,7 @@ __metadata:
optional: true
subscriptions-transport-ws:
optional: true
checksum: 509e37cdce7462cacda0a86c413ce471cd8f618625fb8ac3a60d6347d12f37a4fc60e12fc3fc1a375799caa21e56ff58d709e13ef5e13ab15e4dfc828a527848
checksum: dcf5cfa9f4f95237b770e279e6e1b2433d1101fe4c11496a29807daf7df12ae511b812e56d4d4a47b04d9fb08aa3716b2ac64b9208a5af024db962e1bdc211a2
languageName: node
linkType: hard
@@ -13805,7 +13806,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@speckle/frontend-2@workspace:packages/frontend-2"
dependencies:
"@apollo/client": ^3.8.4
"@apollo/client": ^3.9.6
"@artmizu/nuxt-prometheus": ^2.2.1
"@babel/core": ^7.19.6
"@babel/preset-env": ^7.19.4
@@ -13841,7 +13842,7 @@ __metadata:
"@tiptap/pm": 2.0.0-beta.220
"@tiptap/suggestion": 2.0.0-beta.220
"@tiptap/vue-3": 2.0.0-beta.220
"@types/apollo-upload-client": ^17.0.2
"@types/apollo-upload-client": ^18.0.0
"@types/eslint": ^8.4.5
"@types/js-cookie": ^3.0.2
"@types/lodash-es": ^4.17.6
@@ -13852,10 +13853,10 @@ __metadata:
"@typescript-eslint/eslint-plugin": ^5.38.1
"@typescript-eslint/parser": ^5.38.1
"@vitejs/plugin-legacy": ^4.0.3
"@vue/apollo-composable": 4.0.0-beta.11
"@vue/apollo-ssr": 4.0.0-beta.9
"@vue/apollo-composable": 4.0.2
"@vue/apollo-ssr": 4.0.0
"@vueuse/core": ^9.13.0
apollo-upload-client: ^17.0.0
apollo-upload-client: ^18.0.1
autoprefixer: ^10.4.14
browserify-zlib: ^0.2.0
chromatic: ^6.11.4
@@ -16477,14 +16478,14 @@ __metadata:
languageName: node
linkType: hard
"@types/apollo-upload-client@npm:^17.0.2":
version: 17.0.2
resolution: "@types/apollo-upload-client@npm:17.0.2"
"@types/apollo-upload-client@npm:^18.0.0":
version: 18.0.0
resolution: "@types/apollo-upload-client@npm:18.0.0"
dependencies:
"@apollo/client": ^3.7.0
"@apollo/client": ^3.8.0
"@types/extract-files": "*"
graphql: 14 - 16
checksum: 77860397bc5e1749e6f69d70a3c6c9bd6eed4c5a6fd80cceb109c1badf03a100f4c7204c276e0cbbe170cea58a2a1a07701c3806813cb7a071009a1d1eeae80e
checksum: b26ba3ce2a391550fe4b6789647dcd6ed3ea4d3fb91313eb248e59dad549594b832fe963c6bdc7ad934a00778d145a63bdcea08cba746a38206503dbd6a8cc3f
languageName: node
linkType: hard
@@ -18689,9 +18690,9 @@ __metadata:
languageName: node
linkType: hard
"@vue/apollo-composable@npm:4.0.0-beta.11":
version: 4.0.0-beta.11
resolution: "@vue/apollo-composable@npm:4.0.0-beta.11"
"@vue/apollo-composable@npm:4.0.2":
version: 4.0.2
resolution: "@vue/apollo-composable@npm:4.0.2"
dependencies:
throttle-debounce: ^5.0.0
ts-essentials: ^9.4.0
@@ -18704,7 +18705,7 @@ __metadata:
peerDependenciesMeta:
"@vue/composition-api":
optional: true
checksum: c68771158d1362804c14ad872943b4f549b3f3842de7b9ba2ef21a11e012c7dd71ce7bbc8bed5fbd79ee26a402efee2263e9985b1cac9da0a0a1a8ec3ef66a6c
checksum: cb66ba92f179dd81b820c319d22897a1e039922c708ddf66517c67e7c2ed5257bcc5b602ab43b916c5615f50c8e06398851a244eb554ad4c3fb4fb07e81f61ae
languageName: node
linkType: hard
@@ -18758,12 +18759,12 @@ __metadata:
languageName: node
linkType: hard
"@vue/apollo-ssr@npm:4.0.0-beta.9":
version: 4.0.0-beta.9
resolution: "@vue/apollo-ssr@npm:4.0.0-beta.9"
"@vue/apollo-ssr@npm:4.0.0":
version: 4.0.0
resolution: "@vue/apollo-ssr@npm:4.0.0"
dependencies:
serialize-javascript: ^6.0.1
checksum: 493a1cae1e900754d3f3117f7a82d17ea0a8c2708923f9264f78f5821ce4380f8893f19a00a257de3f2e50f02ac25a425d57ba8a902767c59c81d975559c4303
checksum: e9a82bc27ad5ea464f0b9fb30edc7bae03b399bd3c7c8192652a00df5a0f77bf306a911ccf00e060aa72b7bd395eb5cc5abb35c60132f64387ff5ed5526e47e2
languageName: node
linkType: hard
@@ -19688,6 +19689,15 @@ __metadata:
languageName: node
linkType: hard
"@wry/caches@npm:^1.0.0":
version: 1.0.1
resolution: "@wry/caches@npm:1.0.1"
dependencies:
tslib: ^2.3.0
checksum: 9e89aa8e9e08577b2e4acbe805f406b141ae49c2ac4a2e22acf21fbee68339fa0550e0dee28cf2158799f35bb812326e80212e49e2afd169f39f02ad56ae4ef4
languageName: node
linkType: hard
"@wry/context@npm:^0.7.0":
version: 0.7.0
resolution: "@wry/context@npm:0.7.0"
@@ -19697,15 +19707,6 @@ __metadata:
languageName: node
linkType: hard
"@wry/context@npm:^0.7.3":
version: 0.7.3
resolution: "@wry/context@npm:0.7.3"
dependencies:
tslib: ^2.3.0
checksum: 91c1e9eee9046c48ff857d60dcbb59f22246ce0f9bb2d9b190e0555227e7ba3f86024032cc057f3f5141d3bee93fc6b2a15ce2c79fa512569d3432eb8e1af02b
languageName: node
linkType: hard
"@wry/equality@npm:^0.5.6":
version: 0.5.6
resolution: "@wry/equality@npm:0.5.6"
@@ -19724,6 +19725,15 @@ __metadata:
languageName: node
linkType: hard
"@wry/trie@npm:^0.5.0":
version: 0.5.0
resolution: "@wry/trie@npm:0.5.0"
dependencies:
tslib: ^2.3.0
checksum: 92aeea34152bd8485184236fe328d3d05fc98ee3b431d82ee60cf3584dbf68155419c3d65d0ff3731b204ee79c149440a9b7672784a545afddc8d4342fbf21c9
languageName: node
linkType: hard
"@xtuc/ieee754@npm:^1.2.0":
version: 1.2.0
resolution: "@xtuc/ieee754@npm:1.2.0"
@@ -20445,6 +20455,18 @@ __metadata:
languageName: node
linkType: hard
"apollo-upload-client@npm:^18.0.1":
version: 18.0.1
resolution: "apollo-upload-client@npm:18.0.1"
dependencies:
extract-files: ^13.0.0
peerDependencies:
"@apollo/client": ^3.8.0
graphql: 14 - 16
checksum: fa32478ef70eac0609e189dd06fe73469c992c6bb0f041f77c448e30ce48e8a484089f9f59bb9541b581a6fd64998ab3041acf2ee071e32432668ce636e0c561
languageName: node
linkType: hard
"app-root-dir@npm:^1.0.2":
version: 1.0.2
resolution: "app-root-dir@npm:1.0.2"
@@ -26919,6 +26941,15 @@ __metadata:
languageName: node
linkType: hard
"extract-files@npm:^13.0.0":
version: 13.0.0
resolution: "extract-files@npm:13.0.0"
dependencies:
is-plain-obj: ^4.1.0
checksum: b6fa0eb69115416808b4e92bfdaf69895a50daf3b28320a1dd99bc8a3c9163ac0fa1c1f5494bff00c16bdc029f2b8a89b1b0b879e9a06d6148f6f6ec50305b7a
languageName: node
linkType: hard
"extract-files@npm:^9.0.0":
version: 9.0.0
resolution: "extract-files@npm:9.0.0"
@@ -30341,6 +30372,13 @@ __metadata:
languageName: node
linkType: hard
"is-plain-obj@npm:^4.1.0":
version: 4.1.0
resolution: "is-plain-obj@npm:4.1.0"
checksum: 6dc45da70d04a81f35c9310971e78a6a3c7a63547ef782e3a07ee3674695081b6ca4e977fbb8efc48dae3375e0b34558d2bcd722aec9bddfa2d7db5b041be8ce
languageName: node
linkType: hard
"is-plain-object@npm:^2.0.4":
version: 2.0.4
resolution: "is-plain-object@npm:2.0.4"
@@ -37045,14 +37083,15 @@ __metadata:
languageName: node
linkType: hard
"optimism@npm:^0.17.5":
version: 0.17.5
resolution: "optimism@npm:0.17.5"
"optimism@npm:^0.18.0":
version: 0.18.0
resolution: "optimism@npm:0.18.0"
dependencies:
"@wry/caches": ^1.0.0
"@wry/context": ^0.7.0
"@wry/trie": ^0.4.3
tslib: ^2.3.0
checksum: 5990217d989e9857dc523a64cb6e5a9205eae68c7acac78f7dde8fbe50045d0f11ca8068cdbb51b1eae15510d96ad593a99cf98c6f86c41d1b6f90e54956ff11
checksum: d6ed6a90b05ee886dadfe556c7a30227c66843f51278e51eb843977a6a9368b6c50297fcc63fa514f53d8a5a58f8ddc8049c2356bd4ffac32f8961bcb806254d
languageName: node
linkType: hard
@@ -40696,6 +40735,21 @@ __metadata:
languageName: node
linkType: hard
"rehackt@npm:0.0.6":
version: 0.0.6
resolution: "rehackt@npm:0.0.6"
peerDependencies:
"@types/react": "*"
react: "*"
peerDependenciesMeta:
"@types/react":
optional: true
react:
optional: true
checksum: 25df31d4fc1198b5beba68ec3c960119f120aeba4f7a6f686b087ddbfdd45753ea74b6daf66523c8b6db844429eaed516e0f6f37f657fdcc96334e5ae9efee98
languageName: node
linkType: hard
"relateurl@npm:^0.2.7":
version: 0.2.7
resolution: "relateurl@npm:0.2.7"