diff --git a/.changeset/fresh-start-versions.md b/.changeset/fresh-start-versions.md new file mode 100644 index 00000000..9adafede --- /dev/null +++ b/.changeset/fresh-start-versions.md @@ -0,0 +1,5 @@ +--- +'@tanstack/create': patch +--- + +Use the supported npm response format and resolve current versions for each generated project so long-running builders pick up new releases. diff --git a/packages/create/src/npm-resolver.ts b/packages/create/src/npm-resolver.ts index 976948ce..d3a76bed 100644 --- a/packages/create/src/npm-resolver.ts +++ b/packages/create/src/npm-resolver.ts @@ -6,21 +6,14 @@ * projects don't silently drift over time. */ -const cache = new Map() - export async function resolveNpmVersion(pkg: string): Promise { - if (cache.has(pkg)) { - return cache.get(pkg)! - } - try { const res = await fetch(`https://registry.npmjs.org/${pkg}/latest`, { - headers: { Accept: 'application/vnd.npm.install-v1+json' }, + headers: { Accept: 'application/json' }, }) if (!res.ok) return null const data = (await res.json()) as { version?: string } const version = data.version ?? null - if (version) cache.set(pkg, version) return version } catch { return null diff --git a/packages/create/tests/npm-resolver.test.ts b/packages/create/tests/npm-resolver.test.ts new file mode 100644 index 00000000..40627954 --- /dev/null +++ b/packages/create/tests/npm-resolver.test.ts @@ -0,0 +1,43 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { resolvePackageJSONLatest } from '../src/npm-resolver.js' + +afterEach(() => vi.unstubAllGlobals()) + +describe('npm version resolution', () => { + it('resolves the latest endpoint using its supported response format', async () => { + vi.stubGlobal( + 'fetch', + vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => + new Headers(init?.headers).get('Accept') === 'application/json' + ? Response.json({ version: '1.168.60' }) + : new Response(null, { status: 406 }), + ), + ) + + const project = await resolvePackageJSONLatest({ + dependencies: { '@tanstack/react-start': 'latest' }, + }) + + expect(project.dependencies['@tanstack/react-start']).toBe('1.168.60') + }) + + it('uses a newly published version for the next generated project', async () => { + let version = '1.168.59' + vi.stubGlobal( + 'fetch', + vi.fn(async () => Response.json({ version })), + ) + const template = { + dependencies: { '@tanstack/react-start': 'latest', react: '^19.2.0' }, + } + + const beforeRelease = await resolvePackageJSONLatest(template) + version = '1.168.60' + const afterRelease = await resolvePackageJSONLatest(template) + + expect(beforeRelease.dependencies['@tanstack/react-start']).toBe('1.168.59') + expect(afterRelease.dependencies['@tanstack/react-start']).toBe('1.168.60') + expect(afterRelease.dependencies.react).toBe('^19.2.0') + expect(template.dependencies['@tanstack/react-start']).toBe('latest') + }) +})