diff --git a/src/data/AtlasFileSource.ts b/src/data/AtlasFileSource.ts index b81f428..809546d 100644 --- a/src/data/AtlasFileSource.ts +++ b/src/data/AtlasFileSource.ts @@ -15,21 +15,21 @@ export class AtlasFileSource implements AtlasSource { // } - listEntries() { + listBundles() { return listAtlasEntries(this.filePath); } - getEntry(id: string) { + getBundle(id: string) { const numeric = parseInt(id, 10); assert(!Number.isNaN(numeric) && numeric > 1, `Invalid entry ID: ${id}`); return readAtlasEntry(this.filePath, Number(id)); } - entryDeltaEnabled() { + bundleDeltaEnabled() { return false; // File source does not implement the delta mechanism } - getEntryDelta() { + getBundleDelta() { return null; // File source does not implement the delta mechanism } } diff --git a/src/data/MetroGraphSource.ts b/src/data/MetroGraphSource.ts index 74d4ca1..9ee17a3 100644 --- a/src/data/MetroGraphSource.ts +++ b/src/data/MetroGraphSource.ts @@ -35,7 +35,7 @@ export class MetroGraphSource implements AtlasSource { this.serializeGraph = this.serializeGraph.bind(this); } - listEntries() { + listBundles() { return Array.from(this.entries.values()).map((item) => ({ id: item.entry.id, platform: item.entry.platform, @@ -45,17 +45,17 @@ export class MetroGraphSource implements AtlasSource { })); } - getEntry(id: string) { + getBundle(id: string) { const item = this.entries.get(id); if (!item) throw new Error(`Entry "${id}" not found.`); return item.entry; } - getEntryDelta(id: string) { + getBundleDelta(id: string) { return this.entries.get(id)?.delta || null; } - entryDeltaEnabled() { + bundleDeltaEnabled() { return !!this.deltaListener; } diff --git a/src/data/types.ts b/src/data/types.ts index 5ecc9b1..9ef917b 100644 --- a/src/data/types.ts +++ b/src/data/types.ts @@ -1,14 +1,14 @@ import type { MixedOutput } from 'metro'; export interface AtlasSource { - /** List all available entries */ - listEntries(): PartialAtlasBundle[] | Promise; + /** List the partial data of all available bundles */ + listBundles(): PartialAtlasBundle[] | Promise; /** Load the full entry, by reference */ - getEntry(ref: string): AtlasBundle | Promise; + getBundle(ref: string): AtlasBundle | Promise; /** Load the entry changes since last bundle collection, if any */ - getEntryDelta(ref: string): null | AtlasBundleDelta | Promise; + getBundleDelta(ref: string): null | AtlasBundleDelta | Promise; /** Determine if the source is watching for (live) changes. */ - entryDeltaEnabled(): boolean; + bundleDeltaEnabled(): boolean; } export type PartialAtlasBundle = Pick< diff --git a/webui/src/app/(atlas)/[entry]/index.tsx b/webui/src/app/(atlas)/[bundle].tsx similarity index 85% rename from webui/src/app/(atlas)/[entry]/index.tsx rename to webui/src/app/(atlas)/[bundle].tsx index 865fbed..d9d89ff 100644 --- a/webui/src/app/(atlas)/[entry]/index.tsx +++ b/webui/src/app/(atlas)/[bundle].tsx @@ -1,6 +1,6 @@ import { keepPreviousData, useQuery } from '@tanstack/react-query'; -import type { ModuleGraphResponse } from '~/app/--/entries/[entry]/modules/graph+api'; +import type { ModuleGraphResponse } from '~/app/--/bundles/[bundle]/modules/graph+api'; import { BundleGraph } from '~/components/BundleGraph'; import { BundleSelectForm } from '~/components/BundleSelectForm'; import { ModuleFiltersForm } from '~/components/ModuleFilterForm'; @@ -32,10 +32,10 @@ export default function BundlePage() {

Bundle

- {!!modules.data && {modules.data.entry.moduleFiles} modules} - {!!modules.data && {formatFileSize(modules.data.entry.moduleSize)}} + {!!modules.data && {modules.data.bundle.moduleFiles} modules} + {!!modules.data && {formatFileSize(modules.data.bundle.moduleSize)}} {modules.data && - modules.data.filtered.moduleFiles !== modules.data.entry.moduleFiles && ( + modules.data.filtered.moduleFiles !== modules.data.bundle.moduleFiles && ( visible:} @@ -58,7 +58,7 @@ export default function BundlePage() {

Try restarting Expo Atlas. If this error keeps happening, open a bug report.

) : treeHasData ? ( - + ) : (

@@ -71,11 +71,11 @@ export default function BundlePage() { } /** Load the bundle graph data from API, with default or custom filters */ -function useModuleGraphData(entryId: string, filters: ModuleFilters) { +function useModuleGraphData(bundleId: string, filters: ModuleFilters) { return useQuery({ refetchOnWindowFocus: false, placeholderData: keepPreviousData, - queryKey: [`entries`, entryId, 'bundle-graph', filters], + queryKey: [`bundles`, bundleId, 'bundle-graph', filters], queryFn: ({ queryKey }) => { const [_key, entry, _graph, filters] = queryKey as [ string, @@ -85,8 +85,8 @@ function useModuleGraphData(entryId: string, filters: ModuleFilters) { ]; const url = filters - ? `/entries/${entry}/modules/graph?${moduleFiltersToParams(filters)}` - : `/entries/${entry}/modules/graph`; + ? `/bundles/${entry}/modules/graph?${moduleFiltersToParams(filters)}` + : `/bundles/${entry}/modules/graph`; return fetchApi(url) .then((res) => (res.ok ? res : Promise.reject(res))) diff --git a/webui/src/app/(atlas)/[entry]/folders/[path].tsx b/webui/src/app/(atlas)/[bundle]/folders/[path].tsx similarity index 85% rename from webui/src/app/(atlas)/[entry]/folders/[path].tsx rename to webui/src/app/(atlas)/[bundle]/folders/[path].tsx index 33bc363..10a3c14 100644 --- a/webui/src/app/(atlas)/[entry]/folders/[path].tsx +++ b/webui/src/app/(atlas)/[bundle]/folders/[path].tsx @@ -1,7 +1,7 @@ import { keepPreviousData, useQuery } from '@tanstack/react-query'; import { useLocalSearchParams } from 'expo-router'; -import type { ModuleGraphResponse } from '~/app/--/entries/[entry]/modules/graph+api'; +import type { ModuleGraphResponse } from '~/app/--/bundles/[bundle]/modules/graph+api'; import { BreadcrumbLinks } from '~/components/BreadcrumbLinks'; import { BundleGraph } from '~/components/BundleGraph'; import { BundleSelectForm } from '~/components/BundleSelectForm'; @@ -60,7 +60,7 @@ export default function FolderPage() { Try restarting Expo Atlas. If this error keeps happening, open a bug report. ) : treeHasData ? ( - + ) : ( !modules.isPending && ( @@ -73,13 +73,13 @@ export default function FolderPage() { } /** Load the folder data from API, by path reference only */ -function useModuleGraphDataInFolder(entryId: string, path: string, filters: ModuleFilters) { +function useModuleGraphDataInFolder(bundleId: string, path: string, filters: ModuleFilters) { return useQuery({ refetchOnWindowFocus: false, placeholderData: keepPreviousData, - queryKey: [`entries`, entryId, `module`, path, filters], + queryKey: [`bundles`, bundleId, `module`, path, filters], queryFn: async ({ queryKey }) => { - const [_key, entry, _module, path, filters] = queryKey as [ + const [_key, bundle, _module, path, filters] = queryKey as [ string, string, string, @@ -88,8 +88,8 @@ function useModuleGraphDataInFolder(entryId: string, path: string, filters: Modu ]; const url = filters - ? `/entries/${entry}/modules/graph?path=${encodeURIComponent(path)}&${moduleFiltersToParams(filters)}` - : `/entries/${entry}/modules/graph?path=${encodeURIComponent(path)}`; + ? `/bundles/${bundle}/modules/graph?path=${encodeURIComponent(path)}&${moduleFiltersToParams(filters)}` + : `/bundles/${bundle}/modules/graph?path=${encodeURIComponent(path)}`; return fetchApi(url) .then((res) => (res.ok ? res : Promise.reject(res))) diff --git a/webui/src/app/(atlas)/[entry]/modules/[path].tsx b/webui/src/app/(atlas)/[bundle]/modules/[path].tsx similarity index 90% rename from webui/src/app/(atlas)/[entry]/modules/[path].tsx rename to webui/src/app/(atlas)/[bundle]/modules/[path].tsx index 502c469..f8bfde2 100644 --- a/webui/src/app/(atlas)/[entry]/modules/[path].tsx +++ b/webui/src/app/(atlas)/[bundle]/modules/[path].tsx @@ -58,8 +58,8 @@ export default function ModulePage() { {relativeBundlePath(bundle, path)} @@ -82,13 +82,13 @@ function getModuleType(module: AtlasModule) { } /** Load the module data from API, by path reference only */ -function useModuleData(entryId: string, path: string) { +function useModuleData(bundleId: string, path: string) { return useQuery({ refetchOnWindowFocus: false, - queryKey: [`entries`, entryId, `module`, path], + queryKey: [`bundles`, bundleId, `module`, path], queryFn: async ({ queryKey }) => { - const [_key, entry, _module, path] = queryKey as [string, string, string, string]; - return fetchApi(`/entries/${entry}/modules`, { + const [_key, bundle, _module, path] = queryKey as [string, string, string, string]; + return fetchApi(`/bundles/${bundle}/modules`, { method: 'POST', body: JSON.stringify({ path }), }) diff --git a/webui/src/app/--/bundles/[bundle]/delta+api.ts b/webui/src/app/--/bundles/[bundle]/delta+api.ts new file mode 100644 index 0000000..c6e4267 --- /dev/null +++ b/webui/src/app/--/bundles/[bundle]/delta+api.ts @@ -0,0 +1,21 @@ +import { getSource } from '~/utils/atlas'; +import type { AtlasBundleDelta } from '~core/data/types'; + +export type BundleDeltaResponse = { + isEnabled: boolean; + delta: null | AtlasBundleDelta; +}; + +export async function GET(_request: Request, params: Record<'bundle', string>) { + try { + const isEnabled = getSource().bundleDeltaEnabled(); + const response: BundleDeltaResponse = { + isEnabled, + delta: !isEnabled ? null : await getSource().getBundleDelta(params.bundle), + }; + + return Response.json(response, { status: 200 }); + } catch (error: any) { + return Response.json({ error: error.message }, { status: 406 }); + } +} diff --git a/webui/src/app/--/entries/[entry]/index+api.ts b/webui/src/app/--/bundles/[bundle]/index+api.ts similarity index 50% rename from webui/src/app/--/entries/[entry]/index+api.ts rename to webui/src/app/--/bundles/[bundle]/index+api.ts index e8c1134..4edb4c5 100644 --- a/webui/src/app/--/entries/[entry]/index+api.ts +++ b/webui/src/app/--/bundles/[bundle]/index+api.ts @@ -1,8 +1,8 @@ import { getSource } from '~/utils/atlas'; -export async function GET(_request: Request, params: Record<'entry', string>) { +export async function GET(_request: Request, params: Record<'bundle', string>) { try { - return Response.json(await getSource().getEntry(params.entry)); + return Response.json(await getSource().getBundle(params.bundle)); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } diff --git a/webui/src/app/--/entries/[entry]/modules/graph+api.ts b/webui/src/app/--/bundles/[bundle]/modules/graph+api.ts similarity index 76% rename from webui/src/app/--/entries/[entry]/modules/graph+api.ts rename to webui/src/app/--/bundles/[bundle]/modules/graph+api.ts index 1623093..e3e94a6 100644 --- a/webui/src/app/--/entries/[entry]/modules/graph+api.ts +++ b/webui/src/app/--/bundles/[bundle]/modules/graph+api.ts @@ -5,7 +5,7 @@ import type { AtlasBundle } from '~core/data/types'; export type ModuleGraphResponse = { data: TreemapNode; - entry: { + bundle: { platform: 'android' | 'ios' | 'web'; moduleSize: number; moduleFiles: number; @@ -16,29 +16,29 @@ export type ModuleGraphResponse = { }; }; -export async function GET(request: Request, params: Record<'entry', string>) { - let entry: AtlasBundle; +export async function GET(request: Request, params: Record<'bundle', string>) { + let bundle: AtlasBundle; try { - entry = await getSource().getEntry(params.entry); + bundle = await getSource().getBundle(params.bundle); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } const query = new URL(request.url).searchParams; - const allModules = Array.from(entry.modules.values()); + const allModules = Array.from(bundle.modules.values()); const filteredModules = filterModules(allModules, { - projectRoot: entry.projectRoot, + projectRoot: bundle.projectRoot, filters: moduleFiltersFromParams(query), rootPath: query.get('path') || undefined, }); const response: ModuleGraphResponse = { data: finalizeModuleTree(createModuleTree(filteredModules)), - entry: { - platform: entry.platform as any, + bundle: { + platform: bundle.platform as any, moduleSize: allModules.reduce((size, module) => size + module.size, 0), - moduleFiles: entry.modules.size, + moduleFiles: bundle.modules.size, }, filtered: { moduleSize: filteredModules.reduce((size, module) => size + module.size, 0), diff --git a/webui/src/app/--/entries/[entry]/modules/index+api.ts b/webui/src/app/--/bundles/[bundle]/modules/index+api.ts similarity index 74% rename from webui/src/app/--/entries/[entry]/modules/index+api.ts rename to webui/src/app/--/bundles/[bundle]/modules/index+api.ts index 1255650..e5728c7 100644 --- a/webui/src/app/--/entries/[entry]/modules/index+api.ts +++ b/webui/src/app/--/bundles/[bundle]/modules/index+api.ts @@ -1,13 +1,13 @@ import { getSource } from '~/utils/atlas'; import { filterModules, moduleFiltersFromParams } from '~/utils/filters'; -import { type AtlasBundle, type AtlasModule } from '~core/data/types'; +import type { AtlasBundle, AtlasModule } from '~core/data/types'; /** The partial module data, when listing all available modules from an entry */ export type PartialModule = Omit; export type ModuleListResponse = { data: PartialModule[]; - entry: { + bundle: { platform: 'android' | 'ios' | 'web'; moduleSize: number; moduleFiles: number; @@ -19,19 +19,19 @@ export type ModuleListResponse = { }; /** Get all modules as simple list */ -export async function GET(request: Request, params: Record<'entry', string>) { - let entry: AtlasBundle; +export async function GET(request: Request, params: Record<'bundle', string>) { + let bundle: AtlasBundle; try { - entry = await getSource().getEntry(params.entry); + bundle = await getSource().getBundle(params.bundle); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } const query = new URL(request.url).searchParams; - const allModules = Array.from(entry.modules.values()); + const allModules = Array.from(bundle.modules.values()); const filteredModules = filterModules(allModules, { - projectRoot: entry.projectRoot, + projectRoot: bundle.projectRoot, filters: moduleFiltersFromParams(query), rootPath: query.get('path') || undefined, }); @@ -42,10 +42,10 @@ export async function GET(request: Request, params: Record<'entry', string>) { source: undefined, output: undefined, })), - entry: { - platform: entry.platform as any, + bundle: { + platform: bundle.platform as any, moduleSize: allModules.reduce((size, module) => size + module.size, 0), - moduleFiles: entry.modules.size, + moduleFiles: bundle.modules.size, }, filtered: { moduleSize: filteredModules.reduce((size, module) => size + module.size, 0), @@ -60,7 +60,7 @@ export async function GET(request: Request, params: Record<'entry', string>) { * Get the full module information through a post request. * This requires a `path` property in the request body. */ -export async function POST(request: Request, params: Record<'entry', string>) { +export async function POST(request: Request, params: Record<'bundle', string>) { const moduleRef: string | undefined = (await request.json()).path; if (!moduleRef) { return Response.json( @@ -69,15 +69,15 @@ export async function POST(request: Request, params: Record<'entry', string>) { ); } - let entry: AtlasBundle; + let bundle: AtlasBundle; try { - entry = await getSource().getEntry(params.entry); + bundle = await getSource().getBundle(params.bundle); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } - const module = entry.modules.get(moduleRef); + const module = bundle.modules.get(moduleRef); return module ? Response.json(module) : Response.json({ error: `Module "${moduleRef}" not found.` }, { status: 404 }); diff --git a/webui/src/app/--/entries/[entry]/reload+api.ts b/webui/src/app/--/bundles/[bundle]/reload+api.ts similarity index 54% rename from webui/src/app/--/entries/[entry]/reload+api.ts rename to webui/src/app/--/bundles/[bundle]/reload+api.ts index dba8d92..3f98a19 100644 --- a/webui/src/app/--/entries/[entry]/reload+api.ts +++ b/webui/src/app/--/bundles/[bundle]/reload+api.ts @@ -1,17 +1,17 @@ import { getSource } from '~/utils/atlas'; -export async function GET(_request: Request, params: Record<'entry', string>) { +export async function GET(_request: Request, params: Record<'bundle', string>) { try { - const entry = await getSource().getEntry(params.entry); - if (!entry) { + const bundle = await getSource().getBundle(params.bundle); + if (!bundle) { return Response.json({ error: 'Entry not found' }, { status: 404 }); } - if (!entry.serializeOptions?.sourceUrl) { + if (!bundle.serializeOptions?.sourceUrl) { return Response.json({ error: 'Entry has no `serializeOptions.sourceUrl`' }, { status: 406 }); } - return Response.redirect(entry.serializeOptions.sourceUrl, 302); + return Response.redirect(bundle.serializeOptions.sourceUrl, 302); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } diff --git a/webui/src/app/--/entries/index+api.ts b/webui/src/app/--/bundles/index+api.ts similarity index 55% rename from webui/src/app/--/entries/index+api.ts rename to webui/src/app/--/bundles/index+api.ts index f822f62..61fd775 100644 --- a/webui/src/app/--/entries/index+api.ts +++ b/webui/src/app/--/bundles/index+api.ts @@ -1,16 +1,16 @@ import { getSource } from '~/utils/atlas'; -import { PartialAtlasBundle } from '~core/data/types'; +import type { PartialAtlasBundle } from '~core/data/types'; export async function GET() { try { - const entries = await getSource().listEntries(); - return Response.json(entries.sort(sortEntriesByPlatform)); + const bundles = await getSource().listBundles(); + return Response.json(bundles.sort(sortBundlesByPlatform)); } catch (error: any) { return Response.json({ error: error.message }, { status: 406 }); } } -function sortEntriesByPlatform(a: PartialAtlasBundle, b: PartialAtlasBundle) { +function sortBundlesByPlatform(a: PartialAtlasBundle, b: PartialAtlasBundle) { if (a.platform === 'server') return 1; if (b.platform === 'server') return -1; return 0; diff --git a/webui/src/app/--/entries/[entry]/delta+api.ts b/webui/src/app/--/entries/[entry]/delta+api.ts deleted file mode 100644 index d9d0904..0000000 --- a/webui/src/app/--/entries/[entry]/delta+api.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { getSource } from '~/utils/atlas'; -import { AtlasBundleDelta } from '~core/data/types'; - -export type EntryDeltaResponse = { - isEnabled: boolean; - delta: null | AtlasBundleDelta; -}; - -export async function GET(_request: Request, params: Record<'entry', string>) { - try { - const isEnabled = getSource().entryDeltaEnabled(); - const response: EntryDeltaResponse = { - isEnabled, - delta: !isEnabled ? null : await getSource().getEntryDelta(params.entry), - }; - - return Response.json(response, { status: 200 }); - } catch (error: any) { - return Response.json({ error: error.message }, { status: 406 }); - } -} diff --git a/webui/src/app/index.tsx b/webui/src/app/index.tsx index e23ecd1..07f02bf 100644 --- a/webui/src/app/index.tsx +++ b/webui/src/app/index.tsx @@ -5,5 +5,5 @@ import { useBundle } from '~/providers/bundle'; export default function HomeScreen() { const { bundle } = useBundle(); - return ; + return ; } diff --git a/webui/src/components/BreadcrumbLinks.tsx b/webui/src/components/BreadcrumbLinks.tsx index 5c7c572..457b082 100644 --- a/webui/src/components/BreadcrumbLinks.tsx +++ b/webui/src/components/BreadcrumbLinks.tsx @@ -26,7 +26,7 @@ export function BreadcrumbLinks(props: BreadcrumbLinksProps) { Bundle @@ -74,8 +74,8 @@ function getBreadcrumbLinks(props: BreadcrumbLinksProps): BreadcrumbLinkItem[] { const path = `${rootPath}/${breadcrumbs.slice(0, index + 1).join('/')}`; breadcrumb.key = path; breadcrumb.href = { - pathname: '/(atlas)/[entry]/folders/[path]', - params: { entry: props.bundle.id, path }, + pathname: '/(atlas)/[bundle]/folders/[path]', + params: { bundle: props.bundle.id, path }, }; } diff --git a/webui/src/components/BundleGraph.tsx b/webui/src/components/BundleGraph.tsx index 5052fdb..f9fb61c 100644 --- a/webui/src/components/BundleGraph.tsx +++ b/webui/src/components/BundleGraph.tsx @@ -16,7 +16,7 @@ import type { PartialAtlasBundle } from '~core/data/types'; echarts.use([TooltipComponent, TitleComponent, TreemapChart, CanvasRenderer]); type BundleGraphProps = { - entry: PartialAtlasBundle; + bundle: PartialAtlasBundle; graph: TreemapNode; }; @@ -51,10 +51,10 @@ export function BundleGraph(props: BundleGraphProps) { if (event.event.altKey || event.event.ctrlKey || event.event.metaKey) { router.push({ pathname: data.children?.length - ? '/(atlas)/[entry]/folders/[path]' - : '/(atlas)/[entry]/modules/[path]', + ? '/(atlas)/[bundle]/folders/[path]' + : '/(atlas)/[bundle]/modules/[path]', params: { - entry: props.entry.id, + bundle: props.bundle.id, path: data.value === 100 ? data.name : data.modulePath, }, }); diff --git a/webui/src/providers/bundle.tsx b/webui/src/providers/bundle.tsx index 5fe411c..8e9b8bd 100644 --- a/webui/src/providers/bundle.tsx +++ b/webui/src/providers/bundle.tsx @@ -9,7 +9,7 @@ import { useCallback, } from 'react'; -import { type EntryDeltaResponse } from '~/app/--/entries/[entry]/delta+api'; +import { type BundleDeltaResponse } from '~/app/--/bundles/[bundle]/delta+api'; import { StateInfo } from '~/components/StateInfo'; import { Button } from '~/ui/Button'; import { Spinner } from '~/ui/Spinner'; @@ -73,13 +73,13 @@ export function BundleProvider({ children }: PropsWithChildren) { ); } -/** Load all available entries from API, this is refetched every 2s when no data is present */ +/** Load all available bundles from API, this is refetched every 2s when no data is present */ function useBundleData() { return useQuery({ refetchOnWindowFocus: false, refetchInterval: (query) => (!query.state.data?.length ? 2000 : false), - queryKey: ['entries'], - queryFn: () => fetchApi('/entries').then((res) => res.json()), + queryKey: ['bundles'], + queryFn: () => fetchApi('/bundles').then((res) => res.json()), }); } @@ -99,9 +99,9 @@ export function BundleDeltaToast({ const refetchEntryData = useCallback( () => - fetchApi(`/entries/${bundle.id}/reload`) + fetchApi(`/bundles/${bundle.id}/reload`) .then((res) => (!res.ok ? Promise.reject(res) : res.text())) - .then(() => client.refetchQueries({ queryKey: ['entries', bundle.id], type: 'active' })), + .then(() => client.refetchQueries({ queryKey: ['bundles', bundle.id], type: 'active' })), [bundle.id] ); @@ -154,14 +154,14 @@ function toastBundleUpdate(entryId: string, refetchEntryData: () => any): Toaste }; } -/** Poll the server to check for possible changes in entries */ -function useBundleDeltaData(entryId: string) { - return useQuery({ +/** Poll the server to check for possible changes in bundles */ +function useBundleDeltaData(bundleId: string) { + return useQuery({ refetchInterval: (query) => (query.state.data?.isEnabled === false ? false : 2000), - queryKey: ['entries', entryId, 'delta'], + queryKey: ['bundles', bundleId, 'delta'], queryFn: ({ queryKey }) => { - const [_key, entry] = queryKey as [string, string]; - return fetchApi(`/entries/${entry}/delta`).then((res) => res.json()); + const [_key, bundle] = queryKey as [string, string]; + return fetchApi(`/bundles/${bundle}/delta`).then((res) => res.json()); }, }); }