UNPKG

@vue/apollo-composable

Version:

Apollo GraphQL for Vue Composition API

4 lines 71.9 kB
{ "version": 3, "sources": ["../src/useApolloClient.ts", "../src/useLazyQuery.ts", "../src/useQuery.ts", "../src/util/env.ts", "../src/util/loadingTracking.ts", "../src/util/paramToReactive.ts", "../src/util/paramToRef.ts", "../src/util/toApolloError.ts", "../src/util/useEventHook.ts", "../src/useLoading.ts", "../src/useMutation.ts", "../src/useResult.ts", "../src/useSubscription.ts"], "sourcesContent": ["import type { ApolloClient } from '@apollo/client/core/index.js'\nimport { hasInjectionContext, inject } from 'vue-demi'\n\nexport const DefaultApolloClient = Symbol('default-apollo-client')\nexport const ApolloClients = Symbol('apollo-clients')\n\ntype ClientId = string\ntype ClientDict<T> = Record<ClientId, ApolloClient<T>>\n\ntype ResolveClient<TCacheShape, TReturn = ApolloClient<TCacheShape>> = (clientId?: ClientId) => TReturn\ntype NullableApolloClient<TCacheShape> = ApolloClient<TCacheShape> | undefined\n\nexport interface UseApolloClientReturn<TCacheShape> {\n resolveClient: ResolveClient<TCacheShape>\n readonly client: ApolloClient<TCacheShape>\n}\n\nfunction resolveDefaultClient<T>(providedApolloClients: ClientDict<T> | null, providedApolloClient: ApolloClient<T> | null): NullableApolloClient<T> {\n const resolvedClient = providedApolloClients\n ? providedApolloClients.default\n : (providedApolloClient ?? undefined)\n return resolvedClient\n}\n\nfunction resolveClientWithId<T>(providedApolloClients: ClientDict<T> | null, clientId: ClientId): NullableApolloClient<T> {\n return providedApolloClients?.[clientId]\n}\n\nexport function useApolloClient<TCacheShape = any>(clientId?: ClientId): UseApolloClientReturn<TCacheShape> {\n let resolveImpl: ResolveClient<TCacheShape, NullableApolloClient<TCacheShape>>\n\n // Save current client in current closure scope\n const savedCurrentClients = currentApolloClients\n\n if (!hasInjectionContext()) {\n resolveImpl = (id?: ClientId) => {\n if (id) {\n return resolveClientWithId(savedCurrentClients, id)\n }\n return resolveDefaultClient(savedCurrentClients, savedCurrentClients.default)\n }\n }\n else {\n const providedApolloClients: ClientDict<TCacheShape> | null = inject(ApolloClients, null)\n const providedApolloClient: ApolloClient<TCacheShape> | null = inject(DefaultApolloClient, null)\n\n resolveImpl = (id?: ClientId) => {\n if (id) {\n const client = resolveClientWithId(providedApolloClients, id)\n if (client) {\n return client\n }\n return resolveClientWithId(savedCurrentClients, id)\n }\n const client = resolveDefaultClient(providedApolloClients, providedApolloClient)\n if (client) {\n return client\n }\n return resolveDefaultClient(savedCurrentClients, savedCurrentClients.default)\n }\n }\n\n function resolveClient(id: ClientId | undefined = clientId) {\n const client = resolveImpl(id)\n if (!client) {\n throw new Error(\n `Apollo client with id ${\n id ?? 'default'\n } not found. Use an app.runWithContext() or provideApolloClient() if you are outside of a component setup.`,\n )\n }\n return client\n }\n\n return {\n resolveClient,\n get client() {\n return resolveClient()\n },\n }\n}\n\nlet currentApolloClients: ClientDict<any> = {}\n\nexport function provideApolloClient<TCacheShape = any>(client: ApolloClient<TCacheShape>) {\n currentApolloClients = {\n default: client,\n }\n return function <TFnResult = any> (fn: () => TFnResult) {\n const result = fn()\n currentApolloClients = {}\n return result\n }\n}\n\nexport function provideApolloClients<TCacheShape = any>(clients: ClientDict<TCacheShape>) {\n currentApolloClients = clients\n return function <TFnResult = any> (fn: () => TFnResult) {\n const result = fn()\n currentApolloClients = {}\n return result\n }\n}\n", "import type { OperationVariables } from '@apollo/client/core'\nimport type { DocumentNode } from 'graphql'\nimport type { DocumentParameter, OptionsParameter, UseQueryOptions, UseQueryReturn, VariablesParameter } from './useQuery'\nimport { isRef } from 'vue-demi'\nimport { useQueryImpl } from './useQuery'\nimport { isServer } from './util/env.js'\n\nexport interface UseLazyQueryReturn<TResult, TVariables extends OperationVariables> extends UseQueryReturn<TResult, TVariables> {\n /**\n * Activate the query and starts loading.\n * @param document Override document\n * @param variables Override variables\n * @param options Override options\n * @returns Returns false if the query is already active, otherwise the next result of the query.\n */\n load: (document?: DocumentNode | null, variables?: TVariables | null, options?: UseQueryOptions | null) => false | Promise<TResult>\n}\n\nexport function useLazyQuery<\n TResult = any,\n TVariables extends Record<string, unknown> = any,\n>(\n document: DocumentParameter<TResult, TVariables>,\n variables?: VariablesParameter<TVariables>,\n options?: OptionsParameter<TResult, TVariables>,\n): UseLazyQueryReturn<TResult, TVariables> {\n const query = useQueryImpl<TResult, TVariables>(document, variables, options, true)\n\n function load(\n document?: DocumentNode | null,\n variables?: TVariables | null,\n options?: UseQueryOptions | null,\n ) {\n if (document) {\n query.document.value = document\n }\n if (variables) {\n query.variables.value = variables\n }\n if (options) {\n Object.assign(isRef(query.options) ? query.options.value : query.options, options)\n }\n const isFirstRun = query.forceDisabled.value\n if (isFirstRun) {\n query.forceDisabled.value = false\n\n // If SSR, we need to start the query manually since `watch` on `isEnabled` in `useQueryImpl` won't be called.\n if (isServer) {\n query.start()\n }\n\n return new Promise<TResult>((resolve, reject) => {\n const { off: offResult } = query.onResult((result) => {\n if (!result.loading) {\n resolve(result.data)\n offResult()\n offError()\n }\n })\n const { off: offError } = query.onError((error) => {\n reject(error)\n offResult()\n offError()\n })\n })\n }\n else {\n return false\n }\n }\n\n return {\n ...query,\n load,\n }\n}\n", "import type {\n ApolloClient,\n ApolloError,\n ApolloQueryResult,\n FetchMoreQueryOptions,\n MaybeMasked,\n ObservableQuery,\n ObservableSubscription,\n OperationVariables,\n SubscribeToMoreOptions,\n TypedDocumentNode,\n Unmasked,\n UpdateQueryMapFn,\n WatchQueryOptions,\n} from '@apollo/client/core/index.js'\nimport type { DocumentNode } from 'graphql'\nimport type {\n Ref,\n} from 'vue-demi'\nimport type { ReactiveFunction } from './util/ReactiveFunction'\nimport { debounce, throttle } from 'throttle-debounce'\nimport {\n computed,\n getCurrentInstance,\n getCurrentScope,\n nextTick,\n onScopeDispose,\n onServerPrefetch,\n ref,\n shallowRef,\n unref,\n watch,\n} from 'vue-demi'\nimport { useApolloClient } from './useApolloClient'\nimport { isServer } from './util/env'\nimport { trackQuery } from './util/loadingTracking'\nimport { paramToReactive } from './util/paramToReactive'\nimport { paramToRef } from './util/paramToRef'\nimport { resultErrorsToApolloError, toApolloError } from './util/toApolloError'\nimport { useEventHook } from './util/useEventHook'\n\nexport interface UseQueryOptions<\n TResult = any,\n TVariables extends OperationVariables = OperationVariables,\n> extends Omit<WatchQueryOptions<TVariables>, 'query' | 'variables'> {\n clientId?: string\n enabled?: boolean | Ref<boolean>\n throttle?: number\n debounce?: number\n prefetch?: boolean\n keepPreviousResult?: boolean\n}\n\ninterface SubscribeToMoreItem {\n options: any\n unsubscribeFns: (() => void)[]\n}\n\n// Parameters\nexport type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode | null | undefined> | ReactiveFunction<DocumentNode | null | undefined> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables> | null | undefined> | ReactiveFunction<TypedDocumentNode<TResult, TVariables> | null | undefined>\nexport type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>\nexport type OptionsParameter<TResult, TVariables extends OperationVariables> = UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>> | ReactiveFunction<UseQueryOptions<TResult, TVariables>>\n\nexport interface OnResultContext {\n client: ApolloClient<any>\n}\n\nexport interface OnErrorContext {\n client: ApolloClient<any>\n}\n\n// Return\nexport interface UseQueryReturn<TResult, TVariables extends OperationVariables> {\n result: Ref<TResult | undefined>\n loading: Ref<boolean>\n networkStatus: Ref<number | undefined>\n error: Ref<ApolloError | null>\n start: () => void\n stop: () => void\n restart: () => void\n forceDisabled: Ref<boolean>\n document: Ref<DocumentNode | null | undefined>\n variables: Ref<TVariables | undefined>\n options: UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>>\n query: Ref<ObservableQuery<TResult, TVariables> | null | undefined>\n refetch: (variables?: TVariables) => Promise<ApolloQueryResult<TResult>> | undefined\n fetchMore: <TFetchData = TResult, TFetchVars extends OperationVariables = TVariables> (options: FetchMoreQueryOptions<TFetchVars, TFetchData> & {\n updateQuery?: (previousQueryResult: Unmasked<TResult>, options: {\n fetchMoreResult: Unmasked<TFetchData>\n variables: TFetchVars\n }) => Unmasked<TResult>\n }) => Promise<ApolloQueryResult<MaybeMasked<TFetchData>>> | undefined\n updateQuery: (mapFn: UpdateQueryMapFn<TResult, TVariables>) => void\n subscribeToMore: <TSubscriptionVariables extends OperationVariables = OperationVariables, TSubscriptionData = TResult>(options: SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData> | Ref<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>> | ReactiveFunction<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>>) => void\n onResult: (fn: (param: ApolloQueryResult<TResult>, context: OnResultContext) => void) => {\n off: () => void\n }\n onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {\n off: () => void\n }\n}\n\n/**\n * Use a query that does not require variables or options.\n */\nexport function useQuery<TResult = any>(\n document: DocumentParameter<TResult, undefined>\n): UseQueryReturn<TResult, Record<string, never>>\n\n/**\n * Use a query that has optional variables but not options\n */\nexport function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>\n): UseQueryReturn<TResult, TVariables>\n\n/**\n * Use a query that has required variables but not options\n */\nexport function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>,\n variables: VariablesParameter<TVariables>\n): UseQueryReturn<TResult, TVariables>\n\n/**\n * Use a query that requires options but not variables.\n */\nexport function useQuery<TResult = any>(\n document: DocumentParameter<TResult, undefined>,\n variables: undefined | null,\n options: OptionsParameter<TResult, Record<string, never>>,\n): UseQueryReturn<TResult, Record<string, never>>\n\n/**\n * Use a query that requires variables and options.\n */\nexport function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>,\n variables: VariablesParameter<TVariables>,\n options: OptionsParameter<TResult, TVariables>,\n): UseQueryReturn<TResult, TVariables>\n\nexport function useQuery<\n TResult,\n TVariables extends OperationVariables,\n>(\n document: DocumentParameter<TResult, TVariables>,\n variables?: VariablesParameter<TVariables>,\n options?: OptionsParameter<TResult, TVariables>,\n): UseQueryReturn<TResult, TVariables> {\n return useQueryImpl<TResult, TVariables>(document, variables, options)\n}\n\nexport function useQueryImpl<\n TResult,\n TVariables extends OperationVariables,\n>(\n document: DocumentParameter<TResult, TVariables>,\n variables?: VariablesParameter<TVariables>,\n options: OptionsParameter<TResult, TVariables> = {},\n lazy = false,\n): UseQueryReturn<TResult, TVariables> {\n const currentScope = getCurrentScope()\n const currentInstance = getCurrentInstance()\n\n const currentOptions = ref<UseQueryOptions<TResult, TVariables>>()\n\n const documentRef = paramToRef(document)\n const variablesRef = paramToRef(variables)\n const optionsRef = paramToReactive(options)\n\n // Result\n /**\n * Result from the query\n */\n const result = shallowRef<TResult | undefined>()\n const resultEvent = useEventHook<[ApolloQueryResult<TResult>, OnResultContext]>()\n const error = shallowRef<ApolloError | null>(null)\n const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()\n\n // Loading\n\n /**\n * Indicates if a network request is pending\n */\n const loading = ref(false)\n currentScope && trackQuery(loading)\n const networkStatus = ref<number>()\n\n // SSR\n let firstResolve: (() => void) | undefined\n let firstResolveTriggered = false\n let firstReject: ((apolloError: ApolloError) => void) | undefined\n let firstRejectError: undefined | ApolloError\n\n const tryFirstResolve = () => {\n firstResolveTriggered = true\n if (firstResolve)\n firstResolve()\n }\n\n const tryFirstReject = (apolloError: ApolloError) => {\n firstRejectError = apolloError\n if (firstReject)\n firstReject(apolloError)\n }\n\n const resetFirstResolveReject = () => {\n firstResolve = undefined\n firstReject = undefined\n firstResolveTriggered = false\n firstRejectError = undefined\n }\n\n currentInstance && onServerPrefetch?.(() => {\n if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false))\n return\n\n return new Promise<void>((resolve, reject) => {\n firstResolve = () => {\n resetFirstResolveReject()\n resolve()\n }\n firstReject = (apolloError: ApolloError) => {\n resetFirstResolveReject()\n reject(apolloError)\n }\n\n if (firstResolveTriggered) {\n firstResolve()\n }\n else if (firstRejectError) {\n firstReject(firstRejectError)\n }\n }).finally(stop)\n })\n\n // Apollo Client\n const { resolveClient } = useApolloClient()\n\n function getClient() {\n return resolveClient(currentOptions.value?.clientId)\n }\n\n // Query\n\n const query: Ref<ObservableQuery<TResult, TVariables> | null | undefined> = shallowRef()\n let observer: ObservableSubscription | undefined\n let started = false\n let ignoreNextResult = false\n let firstStart = true\n\n /**\n * Starts watching the query\n */\n function start() {\n if (\n started || !isEnabled.value\n || (isServer && currentOptions.value?.prefetch === false)\n || !currentDocument\n ) {\n tryFirstResolve()\n return\n }\n\n // On server the watchers on document, variables and options are not triggered\n if (isServer) {\n applyDocument(documentRef.value)\n applyVariables(variablesRef.value)\n applyOptions(unref(optionsRef))\n }\n\n started = true\n error.value = null\n loading.value = true\n\n const client = getClient()\n\n query.value = client.watchQuery<TResult, TVariables>({\n query: currentDocument,\n variables: currentVariables ?? {} as TVariables,\n ...currentOptions.value,\n ...(isServer && currentOptions.value?.fetchPolicy !== 'no-cache')\n ? {\n fetchPolicy: 'network-only',\n }\n : {},\n })\n\n startQuerySubscription()\n\n // Make the cache data available to the component immediately\n // This prevents SSR hydration mismatches\n if (!isServer && (firstStart || !currentOptions.value?.keepPreviousResult) && (currentOptions.value?.fetchPolicy !== 'no-cache' || currentOptions.value.notifyOnNetworkStatusChange)) {\n const currentResult = query.value.getCurrentResult(false)\n\n if (!currentResult.loading || currentResult.partial || currentOptions.value?.notifyOnNetworkStatusChange) {\n onNextResult(currentResult)\n ignoreNextResult = !currentResult.loading\n }\n else if (currentResult.error) {\n onError(currentResult.error)\n ignoreNextResult = true\n }\n }\n\n if (!isServer) {\n for (const item of subscribeToMoreItems) {\n addSubscribeToMore(item)\n }\n }\n\n firstStart = false\n }\n\n function startQuerySubscription() {\n if (observer && !observer.closed)\n return\n if (!query.value)\n return\n\n // Create subscription\n ignoreNextResult = false\n observer = query.value.subscribe({\n next: onNextResult,\n error: onError,\n })\n }\n\n function getErrorPolicy() {\n const client = resolveClient(currentOptions.value?.clientId)\n return currentOptions.value?.errorPolicy || client.defaultOptions?.watchQuery?.errorPolicy\n }\n\n function onNextResult(queryResult: ApolloQueryResult<TResult>) {\n if (ignoreNextResult) {\n ignoreNextResult = false\n return\n }\n\n // Remove any previous error that may still be present from the last fetch (so result handlers\n // don't receive old errors that may not even be applicable anymore).\n error.value = null\n\n processNextResult(queryResult)\n\n // When `errorPolicy` is `all`, `onError` will not get called and\n // ApolloQueryResult.errors may be set at the same time as we get a result.\n // The code is only relevant when `errorPolicy` is `all`, because for other situations it\n // could hapen that next and error are called at the same time and then it will lead to multiple\n // onError calls.\n const errorPolicy = getErrorPolicy()\n if (errorPolicy && errorPolicy === 'all' && !queryResult.error && queryResult.errors?.length) {\n processError(resultErrorsToApolloError(queryResult.errors))\n }\n\n tryFirstResolve()\n }\n\n function processNextResult(queryResult: ApolloQueryResult<TResult>) {\n result.value = queryResult.data && Object.keys(queryResult.data).length === 0\n ? queryResult.error\n && !currentOptions.value?.returnPartialData\n && currentOptions.value?.errorPolicy === 'none'\n ? undefined\n : result.value\n : queryResult.data\n loading.value = queryResult.loading\n networkStatus.value = queryResult.networkStatus\n // Wait for handlers to be registered\n nextTick(() => {\n resultEvent.trigger(queryResult, {\n client: getClient(),\n })\n })\n }\n\n function onError(queryError: unknown) {\n if (ignoreNextResult) {\n ignoreNextResult = false\n return\n }\n\n // any error should already be an ApolloError, but we make sure\n const apolloError = toApolloError(queryError)\n const errorPolicy = getErrorPolicy()\n\n if (errorPolicy && errorPolicy !== 'none') {\n processNextResult((query.value as ObservableQuery<TResult, TVariables>).getCurrentResult())\n }\n processError(apolloError)\n tryFirstReject(apolloError)\n // The observable closes the sub if an error occurs\n resubscribeToQuery()\n }\n\n function processError(apolloError: ApolloError) {\n error.value = apolloError\n loading.value = false\n networkStatus.value = 8\n // Wait for handlers to be registered\n nextTick(() => {\n errorEvent.trigger(apolloError, {\n client: getClient(),\n })\n })\n }\n\n function resubscribeToQuery() {\n if (!query.value)\n return\n const lastError = query.value.getLastError()\n const lastResult = query.value.getLastResult()\n query.value.resetLastResults()\n startQuerySubscription()\n Object.assign(query.value, { lastError, lastResult })\n }\n\n let onStopHandlers: Array<() => void> = []\n\n /**\n * Stop watching the query\n */\n function stop() {\n tryFirstResolve()\n if (!started)\n return\n started = false\n loading.value = false\n\n onStopHandlers.forEach(handler => handler())\n onStopHandlers = []\n\n if (query.value) {\n query.value.stopPolling()\n query.value = null\n }\n\n if (observer) {\n observer.unsubscribe()\n observer = undefined\n }\n }\n\n // Restart\n let restarting = false\n /**\n * Queue a restart of the query (on next tick) if it is already active\n */\n function baseRestart() {\n if (!started || restarting)\n return\n restarting = true\n nextTick(() => {\n if (started) {\n stop()\n start()\n }\n restarting = false\n })\n }\n\n let debouncedRestart: typeof baseRestart\n let isRestartDebounceSetup = false\n function updateRestartFn() {\n // On server, will be called before currentOptions is initialized\n // @TODO investigate\n if (!currentOptions.value) {\n debouncedRestart = baseRestart\n }\n else {\n if (currentOptions.value?.throttle) {\n debouncedRestart = throttle(currentOptions.value.throttle, baseRestart)\n }\n else if (currentOptions.value?.debounce) {\n debouncedRestart = debounce(currentOptions.value.debounce, baseRestart)\n }\n else {\n debouncedRestart = baseRestart\n }\n isRestartDebounceSetup = true\n }\n }\n\n function restart() {\n if (!started || restarting)\n return\n if (!isRestartDebounceSetup)\n updateRestartFn()\n debouncedRestart()\n }\n\n // Applying document\n let currentDocument: DocumentNode | null | undefined = documentRef.value\n\n // Enabled state\n\n const forceDisabled = ref(lazy)\n const enabledOption = computed(() => !currentOptions.value || currentOptions.value.enabled == null || currentOptions.value.enabled)\n const isEnabled = computed(() => enabledOption.value && !forceDisabled.value && !!documentRef.value)\n\n // Applying options first (in case it disables the query)\n watch(() => unref(optionsRef), applyOptions, {\n deep: true,\n immediate: true,\n })\n\n function applyOptions(value: UseQueryOptions<TResult, TVariables>) {\n if (currentOptions.value && (\n currentOptions.value.throttle !== value.throttle\n || currentOptions.value.debounce !== value.debounce\n )) {\n updateRestartFn()\n }\n currentOptions.value = value\n restart()\n }\n\n // Applying document\n watch(documentRef, applyDocument)\n\n function applyDocument(value: DocumentNode | null | undefined) {\n currentDocument = value\n restart()\n }\n\n // Applying variables\n let currentVariables: TVariables | undefined\n let currentVariablesSerialized: string\n watch(() => {\n if (isEnabled.value) {\n return variablesRef.value\n }\n else {\n return undefined\n }\n }, applyVariables, {\n deep: true,\n immediate: true,\n })\n\n function applyVariables(value?: TVariables) {\n const serialized = JSON.stringify([value, isEnabled.value])\n if (serialized !== currentVariablesSerialized) {\n currentVariables = value\n restart()\n }\n currentVariablesSerialized = serialized\n }\n\n // Refetch\n\n function refetch(variables: TVariables | undefined = undefined) {\n if (query.value) {\n if (variables) {\n currentVariables = variables\n }\n error.value = null\n loading.value = true\n return query.value.refetch(variables)\n .then((refetchResult) => {\n const currentResult = query.value?.getCurrentResult()\n currentResult && processNextResult(currentResult)\n return refetchResult\n })\n }\n }\n\n // Update Query\n\n function updateQuery(mapFn: UpdateQueryMapFn<TResult, TVariables>) {\n if (query.value) {\n query.value.updateQuery(mapFn)\n }\n }\n\n // Fetch more\n\n function fetchMore<TFetchData = TResult, TFetchVars extends OperationVariables = TVariables>(options: FetchMoreQueryOptions<TFetchVars, TFetchData> & {\n updateQuery?: (previousQueryResult: Unmasked<TResult>, options: {\n fetchMoreResult: Unmasked<TFetchData>\n variables: TFetchVars\n }) => Unmasked<TResult>\n }): Promise<ApolloQueryResult<MaybeMasked<TFetchData>>> | undefined {\n if (query.value) {\n error.value = null\n loading.value = true\n return query.value.fetchMore(options)\n .then((fetchMoreResult) => {\n const currentResult = query.value?.getCurrentResult()\n currentResult && processNextResult(currentResult)\n return fetchMoreResult\n })\n }\n }\n\n // Subscribe to more\n\n const subscribeToMoreItems: SubscribeToMoreItem[] = []\n\n function subscribeToMore<\n TSubscriptionVariables extends OperationVariables = OperationVariables,\n TSubscriptionData = TResult,\n >(\n options: SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData> |\n Ref<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>> |\n ReactiveFunction<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>>,\n ) {\n if (isServer)\n return\n const optionsRef = paramToRef(options)\n watch(optionsRef, (value, oldValue, onCleanup) => {\n const index = subscribeToMoreItems.findIndex(item => item.options === oldValue)\n if (index !== -1) {\n subscribeToMoreItems.splice(index, 1)\n }\n const item: SubscribeToMoreItem = {\n options: value,\n unsubscribeFns: [],\n }\n subscribeToMoreItems.push(item)\n\n addSubscribeToMore(item)\n\n onCleanup(() => {\n item.unsubscribeFns.forEach(fn => fn())\n item.unsubscribeFns = []\n })\n }, {\n immediate: true,\n })\n }\n\n function addSubscribeToMore(item: SubscribeToMoreItem) {\n if (!started)\n return\n if (!query.value) {\n throw new Error('Query is not defined')\n }\n const unsubscribe = query.value.subscribeToMore(item.options)\n onStopHandlers.push(unsubscribe)\n item.unsubscribeFns.push(unsubscribe)\n }\n\n // Auto start & stop\n\n watch(isEnabled, (value) => {\n if (value) {\n nextTick(() => {\n start()\n })\n }\n else {\n stop()\n }\n })\n\n if (isEnabled.value) {\n start()\n }\n\n // Teardown\n if (currentScope) {\n onScopeDispose(() => {\n stop()\n subscribeToMoreItems.length = 0\n })\n }\n else {\n console.warn('[Vue apollo] useQuery() is called outside of an active effect scope and the query will not be automatically stopped.')\n }\n\n return {\n result,\n loading,\n networkStatus,\n error,\n start,\n stop,\n restart,\n forceDisabled,\n document: documentRef,\n variables: variablesRef,\n options: optionsRef,\n query,\n refetch,\n fetchMore,\n subscribeToMore,\n updateQuery,\n onResult: resultEvent.on,\n onError: errorEvent.on,\n }\n}\n", "export const isServer = typeof window === 'undefined'\n", "import type { EffectScope, Ref } from 'vue-demi'\nimport { getCurrentScope, onScopeDispose, ref, watch } from 'vue-demi'\n\nimport { isServer } from './env.js'\n\nexport interface LoadingTracking {\n queries: Ref<number>\n mutations: Ref<number>\n subscriptions: Ref<number>\n}\n\nexport interface AppLoadingTracking extends LoadingTracking {\n components: Map<EffectScope, LoadingTracking>\n}\n\nexport const globalTracking: AppLoadingTracking = {\n queries: ref(0),\n mutations: ref(0),\n subscriptions: ref(0),\n components: new Map(),\n}\n\nexport function getCurrentTracking() {\n const currentScope = getCurrentScope()\n if (!currentScope) {\n return {}\n }\n\n let tracking: LoadingTracking\n if (isServer) {\n // SSR does not support onScopeDispose, so if we don't skip this, it will leak memory\n tracking = {\n queries: ref(0),\n mutations: ref(0),\n subscriptions: ref(0),\n }\n return { tracking }\n }\n\n if (!globalTracking.components.has(currentScope)) {\n // Add per-component tracking\n globalTracking.components.set(currentScope, tracking = {\n queries: ref(0),\n mutations: ref(0),\n subscriptions: ref(0),\n })\n // Cleanup\n onScopeDispose(() => {\n globalTracking.components.delete(currentScope)\n })\n }\n else {\n tracking = globalTracking.components.get(currentScope) as LoadingTracking\n }\n\n return {\n tracking,\n }\n}\n\nfunction track(loading: Ref<boolean>, type: keyof LoadingTracking) {\n if (isServer)\n return\n\n const { tracking } = getCurrentTracking()\n\n watch(loading, (value, oldValue) => {\n if (oldValue != null && value !== oldValue) {\n const mod = value ? 1 : -1\n if (tracking)\n tracking[type].value += mod\n globalTracking[type].value += mod\n }\n }, {\n immediate: true,\n })\n\n onScopeDispose(() => {\n if (loading.value) {\n if (tracking)\n tracking[type].value--\n globalTracking[type].value--\n }\n })\n}\n\nexport function trackQuery(loading: Ref<boolean>) {\n track(loading, 'queries')\n}\n\nexport function trackMutation(loading: Ref<boolean>) {\n track(loading, 'mutations')\n}\n\nexport function trackSubscription(loading: Ref<boolean>) {\n track(loading, 'subscriptions')\n}\n", "import type { Ref } from 'vue-demi'\nimport type { ReactiveFunction } from './ReactiveFunction'\nimport { computed, isRef, reactive } from 'vue-demi'\n\ntype TObject = object\n\nexport function paramToReactive<T extends TObject>(param: T | Ref<T> | ReactiveFunction<T>): T | Ref<T> {\n if (isRef(param)) {\n return param\n }\n else if (typeof param === 'function') {\n return computed(param as ReactiveFunction<T>)\n }\n else if (param) {\n return reactive(param) as T\n }\n else {\n return param\n }\n}\n", "import type { Ref } from 'vue-demi'\nimport type { ReactiveFunction } from './ReactiveFunction'\nimport { computed, isRef, ref } from 'vue-demi'\n\nexport function paramToRef<T>(param: T | Ref<T> | ReactiveFunction<T>): Ref<T> {\n if (isRef(param)) {\n return param\n }\n else if (typeof param === 'function') {\n return computed(param as ReactiveFunction<T>)\n }\n else {\n return ref(param) as Ref<T>\n }\n}\n", "import type { GraphQLFormattedError } from 'graphql'\nimport { ApolloError, isApolloError } from '@apollo/client/core/index.js'\n\nexport function toApolloError(error: unknown): ApolloError {\n if (!(error instanceof Error)) {\n return new ApolloError({\n networkError: Object.assign(new Error((error as any)?.message), { originalError: error }),\n errorMessage: String(error),\n })\n }\n\n if (isApolloError(error)) {\n return error\n }\n\n return new ApolloError({ networkError: error, errorMessage: error.message })\n}\n\nexport function resultErrorsToApolloError(errors: ReadonlyArray<GraphQLFormattedError>): ApolloError {\n return new ApolloError({\n graphQLErrors: errors,\n errorMessage: `GraphQL response contains errors: ${errors.map((e: any) => e.message).join(' | ')}`,\n })\n}\n", "export function useEventHook<TParams extends any[] = any[]>() {\n const fns: Array<(...params: TParams) => void> = []\n\n function on(fn: (...params: TParams) => void) {\n fns.push(fn)\n return {\n off: () => off(fn),\n }\n }\n\n function off(fn: (...params: TParams) => void) {\n const index = fns.indexOf(fn)\n if (index !== -1) {\n fns.splice(index, 1)\n }\n }\n\n function trigger(...params: TParams) {\n for (const fn of fns) {\n fn(...params)\n }\n }\n\n function getCount() {\n return fns.length\n }\n\n return {\n on,\n off,\n trigger,\n getCount,\n }\n}\n", "import { computed } from 'vue-demi'\nimport { getCurrentTracking, globalTracking } from './util/loadingTracking'\n\nexport function useQueryLoading() {\n const { tracking } = getCurrentTracking()\n if (!tracking)\n throw new Error('useQueryLoading must be called inside a setup function.')\n return computed(() => tracking.queries.value > 0)\n}\n\nexport function useMutationLoading() {\n const { tracking } = getCurrentTracking()\n if (!tracking)\n throw new Error('useMutationLoading must be called inside a setup function.')\n return computed(() => tracking.mutations.value > 0)\n}\n\nexport function useSubscriptionLoading() {\n const { tracking } = getCurrentTracking()\n if (!tracking)\n throw new Error('useSubscriptionLoading must be called inside a setup function.')\n return computed(() => tracking.subscriptions.value > 0)\n}\n\nexport function useGlobalQueryLoading() {\n return computed(() => globalTracking.queries.value > 0)\n}\n\nexport function useGlobalMutationLoading() {\n return computed(() => globalTracking.mutations.value > 0)\n}\n\nexport function useGlobalSubscriptionLoading() {\n return computed(() => globalTracking.subscriptions.value > 0)\n}\n", "import type { ApolloClient, ApolloError, FetchResult, MutationOptions, OperationVariables, TypedDocumentNode } from '@apollo/client/core/index.js'\nimport type { DocumentNode } from 'graphql'\nimport type { Ref } from 'vue-demi'\nimport type { ReactiveFunction } from './util/ReactiveFunction'\nimport { getCurrentScope, isRef, nextTick, onScopeDispose, ref, shallowRef } from 'vue-demi'\nimport { useApolloClient } from './useApolloClient'\nimport { trackMutation } from './util/loadingTracking'\nimport { toApolloError } from './util/toApolloError'\nimport { useEventHook } from './util/useEventHook'\n\n/**\n * `useMutation` options for mutations that don't require `variables`.\n */\nexport interface UseMutationOptions<\n TResult = any,\n TVariables = OperationVariables,\n> extends Omit<MutationOptions<TResult, TVariables>, 'mutation'> {\n clientId?: string\n throws?: 'auto' | 'always' | 'never'\n}\n\ntype DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>\ntype OptionsParameter<TResult, TVariables> = UseMutationOptions<TResult, TVariables> | Ref<UseMutationOptions<TResult, TVariables>> | ReactiveFunction<UseMutationOptions<TResult, TVariables>>\n\nexport type MutateOverrideOptions<TResult> = Pick<UseMutationOptions<TResult, OperationVariables>, 'update' | 'optimisticResponse' | 'context' | 'updateQueries' | 'refetchQueries' | 'awaitRefetchQueries' | 'errorPolicy' | 'fetchPolicy' | 'clientId'>\nexport type MutateResult<TResult> = Promise<FetchResult<TResult, Record<string, any>, Record<string, any>> | null>\nexport type MutateFunction<TResult, TVariables> = (variables?: TVariables | null, overrideOptions?: MutateOverrideOptions<TResult>) => MutateResult<TResult>\n\nexport interface OnDoneContext {\n client: ApolloClient<any>\n}\n\nexport interface OnErrorContext {\n client: ApolloClient<any>\n}\n\nexport interface UseMutationReturn<TResult, TVariables> {\n mutate: MutateFunction<TResult, TVariables>\n loading: Ref<boolean>\n error: Ref<ApolloError | null>\n called: Ref<boolean>\n onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>, context: OnDoneContext) => void) => {\n off: () => void\n }\n onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {\n off: () => void\n }\n}\n\nexport function useMutation<\n TResult = any,\n TVariables extends OperationVariables = OperationVariables,\n>(\n document: DocumentParameter<TResult, TVariables>,\n options: OptionsParameter<TResult, TVariables> = {},\n): UseMutationReturn<TResult, TVariables> {\n const currentScope = getCurrentScope()\n const loading = ref<boolean>(false)\n currentScope && trackMutation(loading)\n const error = shallowRef<ApolloError | null>(null)\n const called = ref<boolean>(false)\n\n const doneEvent = useEventHook<[FetchResult<TResult, Record<string, any>, Record<string, any>>, OnDoneContext]>()\n const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()\n\n // Apollo Client\n const { resolveClient } = useApolloClient()\n\n async function mutate(variables?: TVariables | null, overrideOptions: Omit<UseMutationOptions<TResult, TVariables>, 'variables'> = {}) {\n let currentDocument: DocumentNode\n if (typeof document === 'function') {\n currentDocument = document()\n }\n else if (isRef(document)) {\n currentDocument = document.value\n }\n else {\n currentDocument = document\n }\n\n let currentOptions: UseMutationOptions<TResult, TVariables>\n if (typeof options === 'function') {\n currentOptions = options()\n }\n else if (isRef(options)) {\n currentOptions = options.value\n }\n else {\n currentOptions = options\n }\n const client = resolveClient(currentOptions.clientId)\n error.value = null\n loading.value = true\n called.value = true\n try {\n const result = await client.mutate<TResult, TVariables>({\n mutation: currentDocument,\n ...currentOptions,\n ...overrideOptions,\n variables: (variables ?? currentOptions.variables)\n ? {\n ...(currentOptions.variables as TVariables),\n ...(variables as TVariables),\n }\n : undefined,\n })\n loading.value = false\n await nextTick()\n doneEvent.trigger(result, {\n client,\n })\n return result\n }\n catch (e) {\n const apolloError = toApolloError(e)\n error.value = apolloError\n loading.value = false\n await nextTick()\n errorEvent.trigger(apolloError, {\n client,\n })\n if (currentOptions.throws === 'always' || (currentOptions.throws !== 'never' && !errorEvent.getCount())) {\n throw apolloError\n }\n }\n return null\n }\n\n currentScope && onScopeDispose(() => {\n loading.value = false\n })\n\n return {\n mutate,\n loading,\n error,\n called,\n onDone: doneEvent.on,\n onError: errorEvent.on,\n }\n}\n", "import type { DeepNonNullable, DeepRequired } from 'ts-essentials'\nimport type { Ref } from 'vue-demi'\nimport type { ExtractSingleKey } from './util/ExtractSingleKey'\nimport { computed } from 'vue-demi'\n\nexport type UseResultReturn<T> = Readonly<Ref<Readonly<T>>>\n\n/**\n * Resolve a `result`, returning either the first key of the `result` if there\n * is only one, or the `result` itself. The `value` of the ref will be\n * `undefined` until it is resolved.\n *\n * @example\n * const { result } = useQuery({})\n * const user = useResult(result)\n * // user is `undefined` until the query resolves\n *\n * @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.\n * @returns Readonly ref with `undefined` or the resolved `result`.\n * @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`\n */\nexport function useResult<TResult, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>>(\n result: Ref<TResult>\n): UseResultReturn<undefined | ExtractSingleKey<NonNullable<TResult>, TResultKey>>\n\n/**\n * Resolve a `result`, returning either the first key of the `result` if there\n * is only one, or the `result` itself. The `value` of the ref will be\n * `defaultValue` until it is resolved.\n *\n * @example\n * const { result } = useQuery({})\n * const profile = useResult(result, {})\n * // profile is `{}` until the query resolves\n *\n * @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.\n * @param {TDefaultValue} defaultValue The default return value before `result` is resolved.\n * @returns Readonly ref with the `defaultValue` or the resolved `result`.\n * @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`\n */\nexport function useResult<TResult, TDefaultValue, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>>(\n result: Ref<TResult>,\n defaultValue: TDefaultValue\n): UseResultReturn<TDefaultValue | ExtractSingleKey<NonNullable<TResult>, TResultKey>>\n\n/**\n * Resolve a `result`, returning the `result` mapped with the `pick` function.\n * The `value` of the ref will be `defaultValue` until it is resolved.\n *\n * @example\n * const { result } = useQuery({})\n * const comments = useResult(result, undefined, (data) => data.comments)\n * // user is `undefined`, then resolves to the result's `comments`\n *\n * @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.\n * @param {TDefaultValue} defaultValue The default return value before `result` is resolved.\n * @param {(data:TResult)=>TReturnValue} pick The function that receives `result` and maps a return value from it.\n * @returns Readonly ref with the `defaultValue` or the resolved and `pick`-mapped `result`\n * @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`\n */\nexport function useResult<\n TResult,\n TDefaultValue,\n TReturnValue,\n>(\n result: Ref<TResult>,\n defaultValue: TDefaultValue | undefined,\n pick: (data: DeepRequired<DeepNonNullable<TResult>>) => TReturnValue\n): UseResultReturn<TDefaultValue | TReturnValue>\n\n/**\n * @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`\n */\nexport function useResult<\n TResult,\n TDefaultValue,\n TReturnValue,\n>(\n result: Ref<TResult>,\n defaultValue?: TDefaultValue,\n pick?: (data: DeepRequired<DeepNonNullable<TResult>>) => TReturnValue,\n): UseResultReturn<TResult | TResult[keyof TResult] | TDefaultValue | TReturnValue | undefined> {\n console.warn(`'useResult' is deprecated and will be removed soon. Please use 'computed' instead.\nBefore:\nconst items = useResult(result, [], data => data.someField.myItems)\nAfter:\nconst items = computed(() => result.value?.someField.myItems ?? [])`)\n return computed(() => {\n const value = result.value\n if (value) {\n if (pick) {\n try {\n return pick(value as DeepRequired<DeepNonNullable<TResult>>)\n }\n catch (e) {\n // Silent error\n }\n }\n else {\n const keys = Object.keys(value)\n if (keys.length === 1) {\n // Automatically take the only key in result data\n return value[keys[0] as keyof TResult]\n }\n else {\n // Return entire result data\n return value\n }\n }\n }\n return defaultValue\n })\n}\n", "import type {\n ApolloClient,\n ApolloError,\n FetchResult,\n Observable,\n ObservableSubscription,\n OperationVariables,\n SubscriptionOptions,\n TypedDocumentNode,\n} from '@apollo/client/core/index.js'\nimport type { DocumentNode } from 'graphql'\nimport type {\n Ref,\n} from 'vue-demi'\nimport type { ReactiveFunction } from './util/ReactiveFunction'\nimport { debounce, throttle } from 'throttle-debounce'\nimport {\n computed,\n getCurrentScope,\n isRef,\n nextTick,\n onScopeDispose,\n ref,\n shallowRef,\n watch,\n} from 'vue-demi'\nimport { useApolloClient } from './useApolloClient'\nimport { isServer } from './util/env'\nimport { trackSubscription } from './util/loadingTracking'\nimport { paramToReactive } from './util/paramToReactive'\nimport { paramToRef } from './util/paramToRef'\nimport { toApolloError } from './util/toApolloError'\nimport { useEventHook } from './util/useEventHook'\n\nexport interface UseSubscriptionOptions<\n TResult = any,\n TVariables = OperationVariables,\n> extends Omit<SubscriptionOptions<TVariables>, 'query' | 'variables'> {\n clientId?: string\n enabled?: boolean | Ref<boolean>\n throttle?: number\n debounce?: number\n}\n\ntype DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>\ntype VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>\ntype OptionsParameter<TResult, TVariables> = UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>> | ReactiveFunction<UseSubscriptionOptions<TResult, TVariables>>\n\nexport interface OnResultContext {\n client: ApolloClient<any>\n}\n\nexport interface OnErrorContext {\n client: ApolloClient<any>\n}\n\nexport interface UseSubscriptionReturn<TResult, TVariables> {\n result: Ref<TResult | null | undefined>\n loading: Ref<boolean>\n error: Ref<ApolloError | null>\n start: () => void\n stop: () => void\n restart: () => void\n document: Ref<DocumentNode>\n variables: Ref<TVariables | undefined>\n options: UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>>\n subscription: Ref<Observable<FetchResult<TResult, Record<string, any>, Record<string, any>>> | null>\n onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>, context: OnResultContext) => void) => {\n off: () => void\n }\n onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {\n off: () => void\n }\n}\n\n/**\n * Use a subscription that does not require variables or options.\n */\nexport function useSubscription<TResult = any>(\n document: DocumentParameter<TResult, undefined>\n): UseSubscriptionReturn<TResult, undefined>\n\n/**\n * Use a subscription that requires options but not variables.\n */\nexport function useSubscription<TResult = any>(\n document: DocumentParameter<TResult, undefined>,\n variables: undefined | null,\n options: OptionsParameter<TResult, null>\n): UseSubscriptionReturn<TResult, null>\n\n/**\n * Use a subscription that requires variables.\n */\nexport function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>,\n variables: VariablesParameter<TVariables>\n): UseSubscriptionReturn<TResult, TVariables>\n\n/**\n * Use a subscription that has optional variables.\n */\nexport function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>,\n): UseSubscriptionReturn<TResult, TVariables>\n\n/**\n * Use a subscription that requires variables and options.\n */\nexport function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables>(\n document: DocumentParameter<TResult, TVariables>,\n variables: VariablesParameter<TVariables>,\n options: OptionsParameter<TResult, TVariables>\n): UseSubscriptionReturn<TResult, TVariables>\n\nexport function useSubscription<\n TResult,\n TVariables extends Record<string, unknown>,\n>(\n document: DocumentParameter<TResult, TVariables>,\n variables: VariablesParameter<TVariables> | undefined = undefined,\n options: OptionsParameter<TResult, TVariables> = {},\n): UseSubscriptionReturn<TResult, TVariables> {\n const currentScope = getCurrentScope()\n\n const documentRef = paramToRef(document)\n const variablesRef = paramToRef(variables)\n const optionsRef = paramToReactive(options)\n\n const result = shallowRef<TResult | null | undefined>()\n const resultEvent = useEventHook<[FetchResult<TResult>, OnResultContext]>()\n const error = shallowRef<ApolloError | null>(null)\n const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()\n\n const loading = ref(false)\n currentScope && trackSubscription(loading)\n\n // Apollo Client\n const { resolveClient } = useApolloClient()\n\n const subscription: Ref<Observable<FetchResult<TResult>> | null> = ref(null)\n let observer: ObservableSubscription | null = null\n let started = false\n\n function getClient() {\n return resolveClient(currentOptions.value?.clientId)\n }\n\n function start() {\n if (started || !isEnabled.value || isServer)\n return\n started = true\n loading.value = true\n\n const client = getClient()\n\n subscription.value = client.subscribe<TResult, TVariables>({\n query: currentDocument,\n variables: currentVariables,\n ...currentOptions.value,\n })\n\n observer = subscription.value.subscribe({\n next: onNextResult,\n error: onError,\n })\n }\n\n function onNextResult(fetchResult: FetchResult<TResult>) {\n result.value = fetchResult.data\n loading.value = false\n resultEvent.trigger(fetchResult, {\n client: getClient(),\n })\n }\n\n function onError(fetchError: unknown) {\n const apolloError = toApolloError(fetchError)\n\n error.value = apolloError\n loading.value = false\n errorEvent.trigger(apolloError, {\n client: getClient(),\n })\n }\n\n function stop() {\n if (!started)\n return\n started = false\n loading.value = false\n\n if (subscription.value) {\n subscription.value = null\n }\n\n if (observer) {\n observer.unsubscribe()\n observer = null\n }\n }\n\n // Restart\n let restart