From 8921f3204c8c2729dcb652e2caafd98d27e0ee1a Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 00:52:10 +0200 Subject: [PATCH 01/31] feat(router-plugin): add native Bun bundler integration --- .changeset/fruity-pears-see.md | 5 + .github/workflows/bun.yml | 52 ++++ packages/router-plugin/e2e/bun/build.mjs | 247 ++++++++++++++++++ packages/router-plugin/e2e/bun/bun.spec.ts | 175 +++++++++++++ .../router-plugin/e2e/bun/fixture/main.tsx | 9 + .../e2e/bun/fixture/routes/__root.tsx | 14 + .../e2e/bun/fixture/routes/about.tsx | 25 ++ .../e2e/bun/fixture/routes/details.lazy.tsx | 5 + .../e2e/bun/fixture/routes/details.tsx | 3 + .../e2e/bun/fixture/routes/index.tsx | 5 + .../e2e/bun/playwright.config.ts | 24 ++ .../router-plugin/e2e/bun/source-maps.mjs | 126 +++++++++ packages/router-plugin/package.json | 46 ++++ packages/router-plugin/src/bun.ts | 20 ++ .../src/core/router-code-splitter-plugin.ts | 127 +++++++-- .../src/core/router-composed-plugin.ts | 17 +- .../src/core/router-generator-plugin.ts | 15 +- packages/router-plugin/tests/bun.test-d.ts | 17 ++ packages/router-plugin/tsconfig.json | 2 +- packages/router-plugin/vite.config.ts | 1 + pnpm-lock.yaml | 13 +- 21 files changed, 915 insertions(+), 33 deletions(-) create mode 100644 .changeset/fruity-pears-see.md create mode 100644 .github/workflows/bun.yml create mode 100644 packages/router-plugin/e2e/bun/build.mjs create mode 100644 packages/router-plugin/e2e/bun/bun.spec.ts create mode 100644 packages/router-plugin/e2e/bun/fixture/main.tsx create mode 100644 packages/router-plugin/e2e/bun/fixture/routes/__root.tsx create mode 100644 packages/router-plugin/e2e/bun/fixture/routes/about.tsx create mode 100644 packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx create mode 100644 packages/router-plugin/e2e/bun/fixture/routes/details.tsx create mode 100644 packages/router-plugin/e2e/bun/fixture/routes/index.tsx create mode 100644 packages/router-plugin/e2e/bun/playwright.config.ts create mode 100644 packages/router-plugin/e2e/bun/source-maps.mjs create mode 100644 packages/router-plugin/src/bun.ts create mode 100644 packages/router-plugin/tests/bun.test-d.ts diff --git a/.changeset/fruity-pears-see.md b/.changeset/fruity-pears-see.md new file mode 100644 index 00000000000..9fe3adc9d6b --- /dev/null +++ b/.changeset/fruity-pears-see.md @@ -0,0 +1,5 @@ +--- +'@tanstack/router-plugin': minor +--- + +Add a native Bun production-build plugin with file-based route generation and automatic code splitting, including shared route modules. diff --git a/.github/workflows/bun.yml b/.github/workflows/bun.yml new file mode 100644 index 00000000000..aa5bae23d27 --- /dev/null +++ b/.github/workflows/bun.yml @@ -0,0 +1,52 @@ +name: Bun Router + +on: + pull_request: + paths: + - 'packages/router-plugin/**' + - 'packages/router-generator/**' + - 'packages/router-utils/**' + - 'packages/virtual-file-routes/**' + - 'packages/router-core/**' + - 'packages/react-router/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - 'nx.json' + - 'tsconfig.json' + - 'scripts/nx/**' + - '.npmrc' + - '.nvmrc' + - '.github/workflows/bun.yml' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + CI: '1' + NX_DAEMON: 'false' + NX_NO_CLOUD: 'true' + +jobs: + router: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Setup Tools + uses: TanStack/config/.github/setup@e4b48f16568324f76f467aa4c2aac2f05db632c3 # main + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: '1.4.3' + - name: Install Chromium + run: pnpm exec playwright install --with-deps chromium --only-shell + - name: Test production builds and navigation + run: pnpm nx run @tanstack/router-plugin:test:e2e:bun --outputStyle=stream --skipRemoteCache diff --git a/packages/router-plugin/e2e/bun/build.mjs b/packages/router-plugin/e2e/bun/build.mjs new file mode 100644 index 00000000000..292e30a387d --- /dev/null +++ b/packages/router-plugin/e2e/bun/build.mjs @@ -0,0 +1,247 @@ +import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import tanstackRouter, { + tanstackRouter as namedTanstackRouter, +} from '@tanstack/router-plugin/bun' +import { verifyBunRouteSourceMaps } from './source-maps.mjs' + +const here = path.dirname(fileURLToPath(import.meta.url)) +const workspace = path.resolve(here, '../../.cache/bun-e2e') +const fixture = path.join(workspace, 'fixture') +const generatedRouteTree = path.join(fixture, 'routeTree.gen.ts') + +await rm(workspace, { recursive: true, force: true }) +await mkdir(workspace, { recursive: true }) +await cp(path.join(here, 'fixture'), fixture, { recursive: true }) + +const options = { + target: 'react', + routesDirectory: path.join(fixture, 'routes'), + generatedRouteTree, + tmpDir: path.join(workspace, 'tmp'), + autoCodeSplitting: true, + disableLogging: true, +} + +const markers = [ + 'HOME_NATIVE_BUN', + 'ABOUT_NATIVE_BUN', + 'DETAILS_DYNAMIC_BUN', + 'SECOND_BUILD_NATIVE_BUN', + 'EDITED_NATIVE_BUN', +] + +const supportsInputSourceMaps = await verifyBunRouteSourceMaps() + +async function build(name, plugin, beforePlugins = []) { + const result = await Bun.build({ + entrypoints: [path.join(fixture, 'main.tsx')], + outdir: path.join(workspace, name), + target: 'browser', + format: 'esm', + splitting: true, + minify: true, + sourcemap: 'external', + loader: { '.js': 'jsx' }, + define: { 'process.env.NODE_ENV': '"production"' }, + plugins: [...beforePlugins, plugin], + }) + if (!result.success) { + throw new Error(result.logs.map(String).join('\n')) + } + const outputs = await Promise.all( + result.outputs.map(async (output) => ({ + path: path + .relative(path.join(workspace, name), output.path) + .replaceAll('\\', '/'), + kind: output.kind, + source: await output.text(), + })), + ) + const routeSource = await readFile( + path.join(fixture, 'routes/about.tsx'), + 'utf8', + ) + return { + name, + routeTree: await readFile(generatedRouteTree, 'utf8'), + routeSourceMaps: outputs + .filter( + ({ path, source }) => + path.endsWith('.js') && source.includes('ABOUT_NATIVE_BUN'), + ) + .map((output) => { + const prefix = output.source + .slice(0, output.source.indexOf('ABOUT_NATIVE_BUN')) + .split('\n') + return { + payload: JSON.parse( + outputs.find(({ path }) => path === `${output.path}.map`).source, + ), + generatedLine: prefix.length - 1, + generatedColumn: prefix.at(-1).length, + originalSource: routeSource, + } + }), + outputs: outputs.map(({ source, ...output }) => ({ + ...output, + markers: output.path.endsWith('.js') + ? markers.filter((marker) => source.includes(marker)) + : [], + })), + } +} + +const reusedPlugin = tanstackRouter({ + ...options, + codeSplittingOptions: { defaultBehavior: [['loader'], ['component']] }, +}) +const builds = [await build('initial', reusedPlugin)] + +await writeFile( + path.join(fixture, 'routes/second build.js'), + `import { createFileRoute } from '@tanstack/react-router' +const shared = { value: 42 } +export const Route = createFileRoute('/second build')({ + loader: () => shared, + component: () =>

SECOND_BUILD_NATIVE_BUN

, +}) +`, +) +builds.push(await build('reused', reusedPlugin)) + +// Hold A after reference compilation, then start B while A still needs its +// shared bindings. Only public Bun hooks are used to control the overlap. +const aAtResolve = Promise.withResolvers() +const bStarted = Promise.withResolvers() +const releaseB = Promise.withResolvers() +const concurrentA = build('concurrent-a', reusedPlugin, [ + { + name: 'pause-before-split-resolution', + setup(build) { + build.onEnd(() => { + releaseB.resolve() + }) + build.onResolve( + { filter: /about\.tsx\?tsr-(split|shared)=/ }, + async () => { + aAtResolve.resolve() + await bStarted.promise + }, + ) + }, + }, +]) +try { + await Promise.race([ + aAtResolve.promise, + concurrentA.then(() => { + throw new Error( + 'Concurrent build completed without resolving route chunks', + ) + }), + ]) + const concurrentB = build('concurrent-b', reusedPlugin, [ + { + name: 'pause-concurrent-build', + setup(build) { + build.onStart(() => { + bStarted.resolve() + return releaseB.promise + }) + }, + }, + ]) + builds.push(...(await Promise.all([concurrentA, concurrentB]))) +} finally { + bStarted.resolve() + releaseB.resolve() +} + +await rm(generatedRouteTree) +builds.push(await build('independent', namedTanstackRouter(options))) + +// Both files are valid TSX. A stale tree would still bundle successfully, so +// this conflict specifically verifies that generation errors reject the build. +await mkdir(path.join(fixture, 'routes/(duplicate)'), { recursive: true }) +await writeFile( + path.join(fixture, 'routes/(duplicate)/about.tsx'), + `import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/(duplicate)/about')({}) +`, +) +let generationFailure +try { + await build('invalid', reusedPlugin) +} catch (error) { + generationFailure = + error instanceof AggregateError + ? [String(error), ...Array.from(error.errors, String)].join('\n') + : String(error) +} +await rm(path.join(fixture, 'routes/(duplicate)/about.tsx')) +builds.push(await build('recovered', reusedPlugin)) + +await writeFile( + path.join(fixture, 'routes/about.tsx'), + `import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/about')({ + component: () =>

EDITED_NATIVE_BUN

, +}) +`, +) +await rm(path.join(fixture, 'routes/details.tsx')) +await rm(path.join(fixture, 'routes/details.lazy.tsx')) +builds.push(await build('edited', reusedPlugin)) + +const manifest = { builds, generationFailure, supportsInputSourceMaps } +if (!process.argv.includes('--serve')) { + console.log(JSON.stringify(manifest, null, 2)) +} else { + const servedBuilds = builds.filter((build) => + ['concurrent-a', 'concurrent-b', 'independent', 'recovered'].includes( + build.name, + ), + ) + const entrypoints = new Map( + servedBuilds.map((build) => [ + build.name, + build.outputs.find((output) => output.kind === 'entry-point').path, + ]), + ) + const assets = new Map( + servedBuilds.flatMap((build) => + build.outputs.map((output) => [ + `/${build.name}/${output.path}`, + Bun.file(path.join(workspace, build.name, output.path)), + ]), + ), + ) + Bun.serve({ + hostname: '127.0.0.1', + port: Number(process.env.E2E_APP_PORT ?? 43187), + fetch(request) { + const url = new URL(request.url) + const pathname = url.pathname + if (pathname === '/__builds') { + return Response.json(manifest) + } + const asset = assets.get(pathname) + if (asset) { + return new Response(asset, { + headers: { 'Content-Type': 'text/javascript' }, + }) + } + const buildName = url.searchParams.get('build') ?? 'recovered' + const entrypoint = entrypoints.get(buildName) + if (!entrypoint) { + return new Response('Unknown build', { status: 404 }) + } + return new Response( + `
`, + { headers: { 'Content-Type': 'text/html' } }, + ) + }, + }) +} diff --git a/packages/router-plugin/e2e/bun/bun.spec.ts b/packages/router-plugin/e2e/bun/bun.spec.ts new file mode 100644 index 00000000000..6a5351c288e --- /dev/null +++ b/packages/router-plugin/e2e/bun/bun.spec.ts @@ -0,0 +1,175 @@ +import { expect, test } from '@playwright/test' +import { SourceMap } from 'node:module' +import type { SourceMapPayload } from 'node:module' + +const markers = { + Home: 'HOME_NATIVE_BUN', + About: 'ABOUT_NATIVE_BUN', + Details: 'DETAILS_DYNAMIC_BUN', + 'Second build': 'SECOND_BUILD_NATIVE_BUN', +} + +type Build = { + name: string + routeTree: string + routeSourceMaps: Array<{ + payload: SourceMapPayload + generatedLine: number + generatedColumn: number + originalSource: string + }> + outputs: Array<{ path: string; kind: string; markers: Array }> +} + +test('generates routes before production bundling and refreshes reused plugins', async ({ + request, +}) => { + const response = await request.get('/__builds') + expect(response.ok()).toBe(true) + const manifest = (await response.json()) as { + builds: Array + generationFailure?: string + } + expect(manifest.builds.map((build) => build.name)).toEqual([ + 'initial', + 'reused', + 'concurrent-a', + 'concurrent-b', + 'independent', + 'recovered', + 'edited', + ]) + for (const build of manifest.builds) { + expect(build.routeTree).toContain('/about') + if (build.name === 'edited') { + expect(build.routeTree).not.toContain('/details') + } else { + expect(build.routeTree).toContain('/details') + } + const entrypoint = build.outputs.find( + (output) => output.kind === 'entry-point', + ) + expect(entrypoint).toBeDefined() + expect(entrypoint!.markers).toEqual([]) + const expectedMarkers = + build.name === 'initial' + ? [markers.Home, markers.About, markers.Details] + : build.name === 'edited' + ? [markers.Home, markers['Second build'], 'EDITED_NATIVE_BUN'] + : Object.values(markers) + expect(build.outputs.flatMap((output) => output.markers).sort()).toEqual( + [...expectedMarkers].sort(), + ) + for (const marker of expectedMarkers) { + expect( + build.outputs.filter((output) => output.markers.includes(marker)), + ).toEqual([expect.objectContaining({ kind: 'chunk', markers: [marker] })]) + } + if (build.name !== 'initial') { + expect(build.routeTree).toContain('/second build') + } + } + expect(manifest.generationFailure).toBeTruthy() + expect(manifest.generationFailure).toMatch(/conflicting configuration paths/i) +}) + +test('maps split route chunks to their authored source', async ({ + request, +}) => { + const manifest = (await (await request.get('/__builds')).json()) as { + builds: Array + supportsInputSourceMaps: boolean + } + const maps = manifest.builds + .filter(({ name }) => name !== 'edited') + .flatMap(({ routeSourceMaps }) => routeSourceMaps) + expect(maps).toHaveLength(6) + test.skip( + !manifest.supportsInputSourceMaps, + 'Bun does not compose input source maps: https://github.com/oven-sh/bun/issues/6173', + ) + for (const sourceMap of maps) { + const entry = new SourceMap(sourceMap.payload).findEntry( + sourceMap.generatedLine, + sourceMap.generatedColumn, + ) + expect(entry.originalSource).toMatch(/\/routes\/about\.tsx$/) + const sourceIndex = sourceMap.payload.sources.indexOf(entry.originalSource!) + expect(sourceMap.payload.sourcesContent?.[sourceIndex]).toBe( + sourceMap.originalSource, + ) + // Bun maps JSX text to its enclosing element, at line 21, column 4. + expect(entry.originalLine).toBe(20) + expect(entry.originalColumn).toBe(4) + } +}) + +for (const buildName of [ + 'concurrent-a', + 'concurrent-b', + 'independent', + 'recovered', +]) { + test(`${buildName}: loads route chunks on navigation and preserves shared module identity`, async ({ + page, + request, + }) => { + const manifest = (await (await request.get('/__builds')).json()) as { + builds: Array + } + const build = manifest.builds.find((build) => build.name === buildName)! + const requested = new Set() + const errors: Array = [] + page.on('request', (request) => { + requested.add(new URL(request.url()).pathname.slice(1)) + }) + page.on('pageerror', (error) => { + errors.push(error.message) + }) + page.on('console', (message) => { + if (message.type() === 'error') { + errors.push(message.text()) + } + }) + const chunkFor = (marker: string) => + `${buildName}/${build.outputs.find((output) => output.markers.includes(marker))!.path}` + + await page.goto(`/?build=${buildName}`) + await expect(page.getByRole('heading')).toHaveText(markers.Home) + expect(requested.has(chunkFor(markers.Home))).toBe(true) + expect(requested.has(chunkFor(markers.About))).toBe(false) + expect(requested.has(chunkFor(markers.Details))).toBe(false) + expect(requested.has(chunkFor(markers['Second build']))).toBe(false) + + for (const name of ['About', 'Details', 'Home', 'About'] as const) { + await page.getByRole('link', { name, exact: true }).click() + await expect(page.getByRole('heading')).toContainText(markers[name]) + expect(requested.has(chunkFor(markers[name]))).toBe(true) + if (name === 'About') { + await expect(page.getByRole('heading')).toHaveAttribute( + 'data-shared-identity', + 'true', + ) + await expect(page.getByRole('heading')).toHaveText('ABOUT_NATIVE_BUN 1') + } + } + await page.getByRole('link', { name: 'Second build', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText(markers['Second build']) + await expect(page.getByRole('heading')).toHaveAttribute( + 'data-shared-identity', + 'true', + ) + expect(requested.has(chunkFor(markers['Second build']))).toBe(true) + expect( + await page.evaluate( + () => + ( + globalThis as typeof globalThis & { + __bunSharedInitializations?: number + } + ).__bunSharedInitializations, + ), + ).toBe(1) + expect(errors).toEqual([]) + }) +} diff --git a/packages/router-plugin/e2e/bun/fixture/main.tsx b/packages/router-plugin/e2e/bun/fixture/main.tsx new file mode 100644 index 00000000000..94cd7e9c789 --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/main.tsx @@ -0,0 +1,9 @@ +import { createRoot } from 'react-dom/client' +import { createRouter, RouterProvider } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' + +const router = createRouter({ routeTree, defaultPreload: false }) + +createRoot(document.getElementById('app')!).render( + , +) diff --git a/packages/router-plugin/e2e/bun/fixture/routes/__root.tsx b/packages/router-plugin/e2e/bun/fixture/routes/__root.tsx new file mode 100644 index 00000000000..18b45b14bb5 --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/routes/__root.tsx @@ -0,0 +1,14 @@ +import { createRootRoute, Link, Outlet } from '@tanstack/react-router' + +export const Route = createRootRoute({ + component: () => ( + <> + + + + ), +}) diff --git a/packages/router-plugin/e2e/bun/fixture/routes/about.tsx b/packages/router-plugin/e2e/bun/fixture/routes/about.tsx new file mode 100644 index 00000000000..1729aeb4c5c --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/routes/about.tsx @@ -0,0 +1,25 @@ +import { createFileRoute } from '@tanstack/react-router' + +const state = globalThis as typeof globalThis & { + __bunSharedInitializations?: number +} + +const shared = { + initialization: (state.__bunSharedInitializations = + (state.__bunSharedInitializations ?? 0) + 1), +} + +export const Route = createFileRoute('/about')({ + beforeLoad: () => shared, + loader: () => shared, + component: About, +}) + +function About() { + const data = Route.useLoaderData() + return ( +

+ ABOUT_NATIVE_BUN {shared.initialization} +

+ ) +} diff --git a/packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx b/packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx new file mode 100644 index 00000000000..92d513e7258 --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx @@ -0,0 +1,5 @@ +import { createLazyFileRoute } from '@tanstack/react-router' + +export const Route = createLazyFileRoute('/details')({ + component: () =>

DETAILS_DYNAMIC_BUN

, +}) diff --git a/packages/router-plugin/e2e/bun/fixture/routes/details.tsx b/packages/router-plugin/e2e/bun/fixture/routes/details.tsx new file mode 100644 index 00000000000..8c29d2f4f6a --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/routes/details.tsx @@ -0,0 +1,3 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/details')({}) diff --git a/packages/router-plugin/e2e/bun/fixture/routes/index.tsx b/packages/router-plugin/e2e/bun/fixture/routes/index.tsx new file mode 100644 index 00000000000..8a31d996402 --- /dev/null +++ b/packages/router-plugin/e2e/bun/fixture/routes/index.tsx @@ -0,0 +1,5 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/')({ + component: () =>

HOME_NATIVE_BUN

, +}) diff --git a/packages/router-plugin/e2e/bun/playwright.config.ts b/packages/router-plugin/e2e/bun/playwright.config.ts new file mode 100644 index 00000000000..fe88f232025 --- /dev/null +++ b/packages/router-plugin/e2e/bun/playwright.config.ts @@ -0,0 +1,24 @@ +import { defineConfig, devices } from '@playwright/test' + +const port = Number(process.env.E2E_APP_PORT ?? 43187) + +export default defineConfig({ + testDir: '.', + testMatch: '**/*.spec.ts', + workers: 1, + reporter: [['line']], + use: { + baseURL: `http://127.0.0.1:${port}`, + ...devices['Desktop Chrome'], + launchOptions: { + executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, + }, + }, + webServer: { + command: 'bun build.mjs --serve', + env: { E2E_APP_PORT: String(port) }, + url: `http://127.0.0.1:${port}/__builds`, + reuseExistingServer: false, + stdout: 'pipe', + }, +}) diff --git a/packages/router-plugin/e2e/bun/source-maps.mjs b/packages/router-plugin/e2e/bun/source-maps.mjs new file mode 100644 index 00000000000..d0bc969a9e9 --- /dev/null +++ b/packages/router-plugin/e2e/bun/source-maps.mjs @@ -0,0 +1,126 @@ +import assert from 'node:assert/strict' +import { cp, mkdir, readFile, rm } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath, pathToFileURL } from 'node:url' +import tanstackRouter from '@tanstack/router-plugin/bun' + +export async function verifyBunRouteSourceMaps() { + const here = path.dirname(fileURLToPath(import.meta.url)) + const workspace = path.resolve(here, '../../.cache/bun-source-maps') + const fixture = path.join(workspace, 'fixture # %') + await rm(workspace, { recursive: true, force: true }) + await mkdir(workspace, { recursive: true }) + await cp(path.join(here, 'fixture'), fixture, { recursive: true }) + + const authoredSource = + '\n\nexport const inputMapProbe = "authored input map"\n' + const inputMap = Buffer.from( + JSON.stringify({ + version: 3, + sources: [pathToFileURL(path.join(workspace, 'authored-probe.js')).href], + sourcesContent: [authoredSource], + names: [], + mappings: 'AAEA', + }), + ).toString('base64') + const probe = await Bun.build({ + entrypoints: ['router-input-map-probe'], + outdir: path.join(workspace, 'probe'), + sourcemap: 'external', + plugins: [ + { + name: 'input-source-map-capability', + setup(build) { + build.onResolve({ filter: /^router-input-map-probe$/ }, () => ({ + path: 'probe.js', + namespace: 'input-map-probe', + })) + build.onLoad({ filter: /.*/, namespace: 'input-map-probe' }, () => ({ + contents: `export const inputMapProbe = "generated input map"\n//# sourceMappingURL=data:application/json;base64,${inputMap}`, + loader: 'js', + })) + }, + }, + ], + }) + assert.equal(probe.success, true, probe.logs.map(String).join('\n')) + const probeMaps = await Promise.all( + probe.outputs + .filter((output) => output.path.endsWith('.map')) + .map(async (output) => JSON.parse(await output.text())), + ) + assert.ok(probeMaps.length > 0) + const supportsInputSourceMaps = probeMaps.some((map) => + map.sourcesContent.includes(authoredSource), + ) + + for (const sourcemap of [ + 'external', + 'inline', + 'linked', + undefined, + false, + 'none', + ]) { + const loaded = [] + const router = tanstackRouter({ + target: 'react', + routesDirectory: path.join(fixture, 'routes'), + generatedRouteTree: path.join(fixture, 'routeTree.gen.ts'), + tmpDir: path.join(workspace, 'tmp'), + autoCodeSplitting: true, + disableLogging: true, + codeSplittingOptions: { defaultBehavior: [['loader'], ['component']] }, + }) + const result = await Bun.build({ + entrypoints: [path.join(fixture, 'main.tsx')], + outdir: path.join(workspace, String(sourcemap)), + target: 'browser', + format: 'esm', + splitting: true, + sourcemap, + define: { 'process.env.NODE_ENV': '"production"' }, + plugins: [ + { + name: 'observe-router-source-maps', + setup(build) { + return router.setup({ + ...build, + onLoad(options, callback) { + build.onLoad(options, async (args) => { + const result = await callback(args) + if ( + /^tanstack-router-tsr-(split|shared)$/.test(args.namespace) + ) { + loaded.push({ id: args.path, contents: result.contents }) + } + return result + }) + }, + }) + }, + }, + ], + }) + assert.equal(result.success, true, result.logs.map(String).join('\n')) + for (const parameter of ['tsr-split=', 'tsr-shared=']) { + assert.ok(loaded.some(({ id }) => id.includes(parameter))) + } + for (const { id, contents } of loaded) { + const inlineMap = contents.match( + /\/\/# sourceMappingURL=data:application\/json[^,]*;base64,([^\s]+)/, + ) + if (!sourcemap || sourcemap === 'none') { + assert.equal(inlineMap, null, `${id}: maps are disabled`) + continue + } + assert.ok(inlineMap, `${id}: forwards the compiler source map`) + const map = JSON.parse(Buffer.from(inlineMap[1], 'base64').toString()) + const filename = id.split('?')[0] + assert.deepEqual(map.sources, [pathToFileURL(filename).href]) + assert.deepEqual(map.sourcesContent, [await readFile(filename, 'utf8')]) + assert.ok(map.mappings.length > 0, `${id}: preserves compiler mappings`) + } + } + return supportsInputSourceMaps +} diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json index 9c9c831ec67..2dcc86135fc 100644 --- a/packages/router-plugin/package.json +++ b/packages/router-plugin/package.json @@ -29,6 +29,7 @@ "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", "test:unit": "vitest", "test:unit:dev": "vitest --watch", + "test:e2e:bun": "playwright test --config e2e/bun/playwright.config.ts", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", @@ -103,6 +104,16 @@ "default": "./dist/cjs/esbuild.cjs" } }, + "./bun": { + "import": { + "types": "./dist/esm/bun.d.ts", + "default": "./dist/esm/bun.js" + }, + "require": { + "types": "./dist/cjs/bun.d.cts", + "default": "./dist/cjs/bun.cjs" + } + }, "./package.json": "./package.json" }, "sideEffects": false, @@ -132,6 +143,7 @@ "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/node": ">=20", + "bun-types-no-globals": "^1.4.3", "@tanstack/vite-config": "catalog:", "vitest": "catalog:", "jsdom": "catalog:", @@ -145,6 +157,40 @@ "rimraf": "catalog:", "webpack": "^5.104.1" }, + "nx": { + "targets": { + "test:unit": { + "dependsOn": [ + "build" + ] + }, + "test:e2e:bun": { + "dependsOn": [ + "build", + { + "target": "build", + "projects": [ + "@tanstack/react-router" + ] + } + ], + "cache": true, + "inputs": [ + "default", + "^production", + "dependentTaskOutputs", + { + "runtime": "bun --version" + } + ], + "outputs": [ + "{projectRoot}/.cache/bun-e2e", + "{projectRoot}/test-results" + ], + "parallelism": false + } + } + }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "workspace:^", diff --git a/packages/router-plugin/src/bun.ts b/packages/router-plugin/src/bun.ts new file mode 100644 index 00000000000..0501770c301 --- /dev/null +++ b/packages/router-plugin/src/bun.ts @@ -0,0 +1,20 @@ +import { createBunPlugin } from 'unplugin' +import { configSchema } from './core/config' +import { unpluginRouterComposedFactory } from './core/router-composed-plugin' +import type { BunPlugin } from 'unplugin' +import type { Config } from './core/config' + +type RouterPluginOptions = Partial Config)> | undefined + +const TanStackRouterBun = (options?: RouterPluginOptions): BunPlugin => ({ + name: 'tanstack-router', + setup(build) { + // A plugin can be reused by overlapping builds; compiler state is build-local. + return createBunPlugin(unpluginRouterComposedFactory)(options).setup(build) + }, +}) +const tanstackRouter = TanStackRouterBun + +export default TanStackRouterBun +export { configSchema, TanStackRouterBun, tanstackRouter } +export type { CodeSplittingOptions, Config } from './core/config' diff --git a/packages/router-plugin/src/core/router-code-splitter-plugin.ts b/packages/router-plugin/src/core/router-code-splitter-plugin.ts index 596bd6e0120..3aec495596c 100644 --- a/packages/router-plugin/src/core/router-code-splitter-plugin.ts +++ b/packages/router-plugin/src/core/router-code-splitter-plugin.ts @@ -3,6 +3,8 @@ * https://github.com/TanStack/router/pull/3355 */ +import { readFile } from 'node:fs/promises' +import { dirname, extname, resolve } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import { decodeIdentifier, logDiff } from '@tanstack/router-utils' import { getConfig, splitGroupingsSchema } from './config' @@ -17,6 +19,7 @@ import { getFrameworkHmrCompilerPlugins } from './code-splitter/plugins/framewor import { defaultCodeSplitGroupings, splitRouteIdentNodes, + tsrShared, tsrSplit, } from './constants' import { debug, normalizePath, routeFactoryCallCodeFilter } from './utils' @@ -28,12 +31,66 @@ import type { Config, HmrStyle } from './config' import type { RouterPluginContext } from './router-plugin-context' import type { UnpluginFactory, + UnpluginOptions, TransformResult as UnpluginTransformResult, } from 'unplugin' const CODE_SPLITTER_PLUGIN_NAME = 'tanstack-router:code-splitter:compile-reference-file' +// Query identities are separate Bun modules, backed by the original route source. +function bunRouteModule( + parameter: typeof tsrSplit | typeof tsrShared, + transform: (code: string, id: string) => UnpluginTransformResult, +): NonNullable { + const namespace = `tanstack-router-${parameter}` + return { + setup(build) { + build.onResolve({ filter: new RegExp(`[?&]${parameter}=`) }, (args) => { + const [filename, query] = args.path.split('?') + return { + path: `${normalizePath(resolve(args.resolveDir, filename!))}?${query}`, + namespace, + } + }) + build.onLoad({ filter: /.*/, namespace }, async (args) => { + const [filename] = args.path.split('?') + const code = await readFile(filename!, 'utf8') + const result = transform(code, args.path) + const extension = extname(filename!) + let contents = + typeof result === 'string' ? result : (result?.code ?? code) + if ( + build.config.sourcemap && + build.config.sourcemap !== 'none' && + result && + typeof result !== 'string' && + result.map + ) { + const map = + typeof result.map === 'string' ? JSON.parse(result.map) : result.map + // The query selects a module; mappings still refer to the physical file. + const sourceMap = { ...map, sources: [pathToFileURL(filename!).href] } + contents += `\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(sourceMap)).toString('base64')}` + } + return { + contents, + loader: + build.config.loader?.[extension] ?? + (extension === '.tsx' + ? 'tsx' + : extension === '.jsx' + ? 'jsx' + : /\.[cm]?ts$/.test(filename!) + ? 'ts' + : 'js'), + resolveDir: dirname(filename!), + } + }) + }, + } +} + type TransformationPluginInfo = { pluginNames: Array pkg: string @@ -252,11 +309,50 @@ export function createRouterCodeSplitterPlugin( return result } + const handleCompilingSharedFile = ( + code: string, + id: string, + ): UnpluginTransformResult => { + const url = pathToFileURL(id) + url.searchParams.delete('v') + const normalizedId = normalizePath(fileURLToPath(url)) + const [baseId] = normalizedId.split('?') + + if (!baseId) { + return null + } + const sharedBindings = sharedBindingsMap.get(baseId) + if (!sharedBindings || sharedBindings.size === 0) { + return null + } + if (debug) { + console.info('Compiling Shared Module: ', id) + } + const result = compileCodeSplitSharedRoute({ + code, + sharedBindings, + filename: normalizedId, + }) + if (debug) { + logDiff(code, result.code) + console.log('Output:\n', result.code + '\n\n') + } + return result + } + return [ { name: 'tanstack-router:code-splitter:compile-reference-file', enforce: 'pre', + bun: { + setup() { + isProduction = true + initUserConfig() + sharedBindingsMap.clear() + }, + }, + transform: { filter: { id: { @@ -345,6 +441,8 @@ export function createRouterCodeSplitterPlugin( name: 'tanstack-router:code-splitter:compile-virtual-file', enforce: 'pre', + bun: bunRouteModule(tsrSplit, handleCompilingVirtualFile), + transform: { filter: { id: /tsr-split/, @@ -370,36 +468,13 @@ export function createRouterCodeSplitterPlugin( name: 'tanstack-router:code-splitter:compile-shared-file', enforce: 'pre', + bun: bunRouteModule(tsrShared, handleCompilingSharedFile), + transform: { filter: { id: /tsr-shared/, }, - handler(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - const normalizedId = normalizePath(fileURLToPath(url)) - const [baseId] = normalizedId.split('?') - - if (!baseId) return null - - const sharedBindings = sharedBindingsMap.get(baseId) - if (!sharedBindings || sharedBindings.size === 0) return null - - if (debug) console.info('Compiling Shared Module: ', id) - - const result = compileCodeSplitSharedRoute({ - code, - sharedBindings, - filename: normalizedId, - }) - - if (debug) { - logDiff(code, result.code) - console.log('Output:\n', result.code + '\n\n') - } - - return result - }, + handler: handleCompilingSharedFile, }, vite: { diff --git a/packages/router-plugin/src/core/router-composed-plugin.ts b/packages/router-plugin/src/core/router-composed-plugin.ts index c778e4e8d47..e8f44575350 100644 --- a/packages/router-plugin/src/core/router-composed-plugin.ts +++ b/packages/router-plugin/src/core/router-composed-plugin.ts @@ -4,6 +4,7 @@ import { createRouterCodeSplitterPlugin } from './router-code-splitter-plugin' import { createRouterHmrPlugin } from './router-hmr-plugin' import { createRouterPluginContext } from './router-plugin-context' import type { Config } from './config' +import type { PluginBuilder as BunPluginBuilder } from 'bun' import type { RspackCompiler, UnpluginFactory, @@ -30,7 +31,7 @@ function applyRspackInlineCssDefaultDefinePlugin(compiler: RspackCompiler) { export const unpluginRouterComposedFactory: UnpluginFactory< Partial Config)> | undefined -> = (options = {}, _meta) => { +> = (options = {}, meta) => { const ROOT: string = process.cwd() const userConfig = getConfig( (typeof options === 'function' ? options() : options) as Partial, @@ -55,6 +56,14 @@ export const unpluginRouterComposedFactory: UnpluginFactory< const result = [ { name: 'tanstack:router-inline-css-defaults', + bun: { + setup(build: BunPluginBuilder) { + build.config.define = { + ...INLINE_CSS_DEFAULT_DEFINES, + ...build.config.define, + } + }, + }, vite: { config() { return { @@ -87,7 +96,11 @@ export const unpluginRouterComposedFactory: UnpluginFactory< const isProduction = process.env.NODE_ENV === 'production' - if (!isProduction && !userConfig.autoCodeSplitting) { + if ( + meta.framework !== 'bun' && + !isProduction && + !userConfig.autoCodeSplitting + ) { const routerHmr = getPlugin( createRouterHmrPlugin(options, routerPluginContext), ) diff --git a/packages/router-plugin/src/core/router-generator-plugin.ts b/packages/router-plugin/src/core/router-generator-plugin.ts index 50dde9f55cc..4589bf828e9 100644 --- a/packages/router-plugin/src/core/router-generator-plugin.ts +++ b/packages/router-plugin/src/core/router-generator-plugin.ts @@ -40,6 +40,11 @@ export function createRouterGeneratorPlugin( }) } + const runGenerator = async (event?: GeneratorEvent) => { + await generator.run(event) + routerPluginContext.routesByFile = generator.getRoutesByFileMap() + } + const generate = async (opts?: { file: string event: 'create' | 'update' | 'delete' @@ -55,8 +60,7 @@ export function createRouterGeneratorPlugin( } try { - await generator.run(generatorEvent) - routerPluginContext.routesByFile = generator.getRoutesByFileMap() + await runGenerator(generatorEvent) } catch (e) { console.error(e) } @@ -71,6 +75,13 @@ export function createRouterGeneratorPlugin( event, }) }, + bun: { + setup(build) { + initConfigAndGenerator() + // Reject generation errors instead of bundling a stale route tree. + build.onStart(() => runGenerator()) + }, + }, vite: { async configResolved(config) { initConfigAndGenerator({ root: config.root }) diff --git a/packages/router-plugin/tests/bun.test-d.ts b/packages/router-plugin/tests/bun.test-d.ts new file mode 100644 index 00000000000..9d3ff3214d2 --- /dev/null +++ b/packages/router-plugin/tests/bun.test-d.ts @@ -0,0 +1,17 @@ +import { expectTypeOf, test } from 'vitest' +import TanStackRouterBun, { tanstackRouter } from '@tanstack/router-plugin/bun' +import type { BuildConfig, BunPlugin } from 'bun' +import type { Config } from '@tanstack/router-plugin/bun' + +test('accepts the published plugin in a native Bun build', () => { + expectTypeOf>().toEqualTypeOf() + expectTypeOf().toEqualTypeOf< + typeof tanstackRouter + >() + expectTypeOf>>().toMatchTypeOf< + BuildConfig['plugins'] + >() + expectTypeOf>().toMatchTypeOf< + Parameters[0] + >() +}) diff --git a/packages/router-plugin/tsconfig.json b/packages/router-plugin/tsconfig.json index 0e74c8c099c..82c36ce2f47 100644 --- a/packages/router-plugin/tsconfig.json +++ b/packages/router-plugin/tsconfig.json @@ -4,6 +4,6 @@ "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { "jsx": "react-jsx", - "types": ["node"] + "types": ["node", "bun-types-no-globals"] } } diff --git a/packages/router-plugin/vite.config.ts b/packages/router-plugin/vite.config.ts index e80f073d218..007d1bd28d3 100644 --- a/packages/router-plugin/vite.config.ts +++ b/packages/router-plugin/vite.config.ts @@ -22,6 +22,7 @@ export default mergeConfig( './src/rspack.ts', './src/webpack.ts', './src/esbuild.ts', + './src/bun.ts', ], srcDir: './src', }), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 344bac44899..47c1ca960a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14749,7 +14749,7 @@ importers: version: 5.0.0 unplugin: specifier: ^3.3.0 - version: 3.3.0(@rspack/core@2.2.7(@swc/helpers@0.5.23))(esbuild@0.28.2)(rolldown@1.2.13)(rollup@4.63.1)(vite@8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0))(webpack@5.110.3) + version: 3.3.0(@rspack/core@2.2.7(@swc/helpers@0.5.23))(bun-types-no-globals@1.4.3)(esbuild@0.28.2)(rolldown@1.2.13)(rollup@4.63.1)(vite@8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0))(webpack@5.110.3) vite: specifier: ^8.3.4 version: 8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0) @@ -14784,6 +14784,9 @@ importers: '@types/react-dom': specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.9) + bun-types-no-globals: + specifier: ^1.4.3 + version: 1.4.3 jsdom: specifier: 'catalog:' version: 25.0.1(supports-color@10.2.2) @@ -23373,6 +23376,9 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + bun-types-no-globals@1.4.3: + resolution: {integrity: sha512-tQEllXIKGEN+0spgZesvqh2spJMWdeovxO9TbgcCve0CLaug+CoamPGMGGp5bD1vvlpnZI4tny8pi3/ytn1/ZA==} + bun-types@1.2.22: resolution: {integrity: sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA==} peerDependencies: @@ -37994,6 +38000,8 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bun-types-no-globals@1.4.3: {} + bun-types@1.2.22(@types/react@19.2.9): dependencies: '@types/node': 25.0.9 @@ -44001,13 +44009,14 @@ snapshots: picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - unplugin@3.3.0(@rspack/core@2.2.7(@swc/helpers@0.5.23))(esbuild@0.28.2)(rolldown@1.2.13)(rollup@4.63.1)(vite@8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0))(webpack@5.110.3): + unplugin@3.3.0(@rspack/core@2.2.7(@swc/helpers@0.5.23))(bun-types-no-globals@1.4.3)(esbuild@0.28.2)(rolldown@1.2.13)(rollup@4.63.1)(vite@8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0))(webpack@5.110.3): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 optionalDependencies: '@rspack/core': 2.2.7(@swc/helpers@0.5.23) + bun-types-no-globals: 1.4.3 esbuild: 0.28.2 rolldown: 1.2.13 rollup: 4.63.1 From 06b4a7cb1abb4d9f15dc95ec20092d3e95f517b1 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 02:32:40 +0200 Subject: [PATCH 02/31] feat(router-plugin): support native Bun development builds --- .changeset/fruity-pears-see.md | 5 +- .../src/filesystem/virtual/loadConfigFile.ts | 1 + packages/router-generator/src/generator.ts | 11 + .../router-generator/tests/generator.test.ts | 26 + .../tests/virtual-config.test.ts | 62 ++ packages/router-plugin/e2e/bun/dev-fixture.ts | 309 ++++++++++ .../e2e/bun/dev-playwright.config.ts | 23 + packages/router-plugin/e2e/bun/dev.test.ts | 572 ++++++++++++++++++ packages/router-plugin/e2e/bun/run-dev.mjs | 58 ++ packages/router-plugin/package.json | 14 + .../plugins/framework-plugins.ts | 4 +- ...react-stable-hmr-split-route-components.ts | 3 +- .../src/core/hmr/vite-adapter.ts | 5 +- .../src/core/router-code-splitter-plugin.ts | 18 +- .../src/core/router-composed-plugin.ts | 11 +- .../src/core/router-generator-plugin.ts | 63 +- .../src/core/router-hmr-plugin.ts | 28 +- .../snapshots/react/arrow-function@true.tsx | 8 +- .../react/arrow-function@webpack-hot.tsx | 5 +- ...ateFileRoute-lowercase-components@true.tsx | 11 +- .../createRootRoute-inline-component@true.tsx | 5 +- ...ateRootRoute-lowercase-components@true.tsx | 5 +- .../snapshots/react/createRootRoute@true.tsx | 5 +- ...ateRootRouteWithContext-type-args@true.tsx | 5 +- .../explicit-undefined-component@true.tsx | 5 +- .../react/function-declaration@true.tsx | 8 +- .../snapshots/react/multi-component@true.tsx | 11 +- .../react/string-literal-keys@true.tsx | 11 +- .../snapshots/solid/arrow-function@true.tsx | 5 +- 29 files changed, 1226 insertions(+), 71 deletions(-) create mode 100644 packages/router-generator/tests/virtual-config.test.ts create mode 100644 packages/router-plugin/e2e/bun/dev-fixture.ts create mode 100644 packages/router-plugin/e2e/bun/dev-playwright.config.ts create mode 100644 packages/router-plugin/e2e/bun/dev.test.ts create mode 100644 packages/router-plugin/e2e/bun/run-dev.mjs diff --git a/.changeset/fruity-pears-see.md b/.changeset/fruity-pears-see.md index 9fe3adc9d6b..3ca2c74552f 100644 --- a/.changeset/fruity-pears-see.md +++ b/.changeset/fruity-pears-see.md @@ -1,5 +1,8 @@ --- '@tanstack/router-plugin': minor +'@tanstack/router-generator': minor --- -Add a native Bun production-build plugin with file-based route generation and automatic code splitting, including shared route modules. +Add a native Bun plugin with file-based route generation and automatic code splitting, including shared route modules. Reuse Router HMR and expose resolved generator directory roots for native development-server watches. + +Reload edited virtual route configurations when regenerating the route tree. diff --git a/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts index a4606e4e193..9de740ed15a 100644 --- a/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts +++ b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts @@ -3,6 +3,7 @@ import { createJiti } from 'jiti' export async function loadConfigFile(filePath: string) { const jiti = createJiti(filePath, { interopDefault: false, + moduleCache: false, tsconfigPaths: true, }) const loaded = await jiti.import(filePath) diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index 91f87dadda2..9f16c139308 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -304,6 +304,17 @@ export class Generator { ) } + public getRoutesDirectoryPaths(): Array { + return [ + ...new Set( + [ + ...(this.config.virtualRouteConfig ? [] : [this.routesDirectoryPath]), + ...this.physicalDirectories, + ].map((directory) => path.resolve(this.root, directory)), + ), + ] + } + public async run(event?: GeneratorEvent): Promise { if ( event && diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts index 3e0831fe91c..4c06bb4ea27 100644 --- a/packages/router-generator/tests/generator.test.ts +++ b/packages/router-generator/tests/generator.test.ts @@ -408,6 +408,32 @@ describe('generator works', async () => { }) }) + it.each([ + { folder: 'only-root', directories: ['routes'] }, + { + folder: 'virtual-physical-no-prefix', + directories: ['routes/merged'], + }, + ])( + 'returns isolated resolved directory roots for $folder', + async ({ folder, directories }) => { + const root = makeFolderDir(folder) + const config = setupConfig(folder) + const generator = new Generator({ config, root }) + + await generator.run() + + const expected = directories.map((directory) => + path.resolve(root, directory), + ) + const snapshot = generator.getRoutesDirectoryPaths() + expect(snapshot).toEqual(expected) + snapshot[0] = path.resolve(root, 'changed') + snapshot.push(path.resolve(root, 'extra')) + expect(generator.getRoutesDirectoryPaths()).toEqual(expected) + }, + ) + it.each(folderNames)( 'should create directory for routeTree if it does not exist', async () => { diff --git a/packages/router-generator/tests/virtual-config.test.ts b/packages/router-generator/tests/virtual-config.test.ts new file mode 100644 index 00000000000..e41914a6ed3 --- /dev/null +++ b/packages/router-generator/tests/virtual-config.test.ts @@ -0,0 +1,62 @@ +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { expect, test } from 'vitest' +import { Generator } from '../src/generator' +import { getConfig } from '../src/config' + +test('reloads an edited virtual route configuration on the next generation', async () => { + const root = await mkdtemp(path.join(tmpdir(), 'router-virtual-config-')) + const routes = path.join(root, 'routes') + const configFile = path.join(root, 'virtual-routes.ts') + const generatedRouteTree = path.join(root, 'routeTree.gen.ts') + const virtualConfig = (name: string) => + `export default ${JSON.stringify({ + type: 'root', + file: '__root.tsx', + children: [{ type: 'route', path: `/${name}`, file: `${name}.tsx` }], + })}\n` + + try { + await mkdir(routes) + await Promise.all([ + writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router' +export const Route = createRootRoute({})\n`, + ), + ...['before', 'after'].map((name) => + writeFile( + path.join(routes, `${name}.tsx`), + `import { createFileRoute } from '@tanstack/react-router' +export const Route = createFileRoute('/${name}')({})\n`, + ), + ), + writeFile(configFile, virtualConfig('before')), + ]) + const generator = new Generator({ + root, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree, + virtualRouteConfig: 'virtual-routes.ts', + tmpDir: path.join(root, 'tmp'), + disableLogging: true, + }, + root, + ), + }) + + await generator.run() + expect(await readFile(generatedRouteTree, 'utf8')).toContain("'/before'") + + await writeFile(configFile, virtualConfig('after')) + await generator.run() + const updated = await readFile(generatedRouteTree, 'utf8') + expect(updated).toContain("'/after'") + expect(updated).not.toContain("'/before'") + } finally { + await rm(root, { recursive: true, force: true }) + } +}) diff --git a/packages/router-plugin/e2e/bun/dev-fixture.ts b/packages/router-plugin/e2e/bun/dev-fixture.ts new file mode 100644 index 00000000000..79968b18c66 --- /dev/null +++ b/packages/router-plugin/e2e/bun/dev-fixture.ts @@ -0,0 +1,309 @@ +import { spawn, execFileSync } from 'node:child_process' +import { createRequire } from 'node:module' +import { + mkdir, + mkdtemp, + readFile, + rename, + rm, + symlink, + writeFile, +} from 'node:fs/promises' +import path from 'node:path' +import { tmpdir } from 'node:os' +import { pathToFileURL } from 'node:url' +import { createHash } from 'node:crypto' + +export function aboutSource( + component = 'ABOUT_BEFORE', + loader = 'LOADER_BEFORE', + map = 'AUTHORED_BEFORE', +) { + return `import { useState } from 'react' +import { createFileRoute } from '@tanstack/react-router' +const state = globalThis as typeof globalThis & { __bunDevSharedInitializations?: number } +const shared = { initialization: (state.__bunDevSharedInitializations = (state.__bunDevSharedInitializations ?? 0) + 1) } +export const Route = createFileRoute('/about')({ + loader: () => ({ shared, label: '${loader}' }), + component: About, +}) +function About() { + const [count, setCount] = useState(0) + const data = Route.useLoaderData() + function authoredProbe() { + throw new Error('${map}') + } + return
+

${component}

+ + {data.label} + +
+} +` +} + +export const nestedSource = (id: string, marker: string) => + `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('${id}')({ component: () =>

${marker}

});\n` + +export const virtualConfigSource = (included: 'before' | 'after') => + `import { rootRoute, index, route } from '@tanstack/virtual-file-routes'; export const routes = rootRoute('__root.tsx', [index('index.tsx'), route('/about', 'about.tsx'), route('/virtual-${included}', '../virtual-pages/${included}.tsx')]);\n` + +export type InlineMapEvent = { id: string; contents: string } + +export async function startDevFixture({ + generatedExtension = 'ts', + virtualMount = false, + virtualConfigFile = false, + autoCodeSplitting = true, +}: { + generatedExtension?: string + virtualMount?: boolean + virtualConfigFile?: boolean + autoCodeSplitting?: boolean +} = {}) { + const executable = process.env.BUN_EXECUTABLE + const repo = process.env.ROUTER_REPOSITORY_ROOT + if (!executable || !repo) { + throw new Error('Use run-dev.mjs with BUN_EXECUTABLE set') + } + const requirePlugin = createRequire( + path.join(repo, 'packages/router-plugin/package.json'), + ) + const requireReact = createRequire( + path.join(repo, 'packages/react-router/package.json'), + ) + const directory = await mkdtemp(path.join(tmpdir(), 'router-bun-native-dev-')) + const inlineMaps: Array = [] + let logs = '' + let child: ReturnType | undefined + const file = (name: string) => path.join(directory, name) + const save = async (name: string, source: string) => { + await mkdir(path.dirname(file(name)), { recursive: true }) + await writeFile(file(name), source) + } + try { + for (const name of [ + '@tanstack/router-plugin', + '@tanstack/react-router', + '@tanstack/virtual-file-routes', + 'react', + 'react-dom', + ]) { + const target = name.startsWith('@tanstack/') + ? path.join(repo, 'packages', name.slice('@tanstack/'.length)) + : path.dirname(requireReact.resolve(`${name}/package.json`)) + const destination = file(`node_modules/${name}`) + await mkdir(path.dirname(destination), { recursive: true }) + await symlink( + target, + destination, + process.platform === 'win32' ? 'junction' : 'dir', + ) + } + await mkdir(file('routes/nested/empty/deep'), { recursive: true }) + await mkdir(file('routes/(conflict)'), { recursive: true }) + await mkdir(file('mounted/empty/deep'), { recursive: true }) + await save( + 'routes/__root.tsx', + `import { createRootRoute, Link, Outlet } from '@tanstack/react-router'; export const Route = createRootRoute({ notFoundComponent: () =>

NOT_FOUND

, component: () => <> });`, + ) + await save('routes/index.tsx', nestedSource('/', 'HOME_NATIVE_DEV')) + await save('routes/about.tsx', aboutSource()) + if (virtualConfigFile) { + await save('virtual-routes.ts', virtualConfigSource('before')) + await save( + 'virtual-pages/before.tsx', + nestedSource('/virtual-before', 'VIRTUAL_BEFORE'), + ) + await save( + 'virtual-pages/after.tsx', + nestedSource('/virtual-after', 'VIRTUAL_AFTER'), + ) + } + await save( + 'main.tsx', + `import { createRoot } from 'react-dom/client'; import { createRouter, RouterProvider } from '@tanstack/react-router'; import { routeTree } from './routeTree.gen.${generatedExtension}'; const router = createRouter({ routeTree, defaultPreload: false }); createRoot(document.getElementById('app')!).render();`, + ) + await save( + 'index.html', + '
', + ) + await save( + 'tsconfig.json', + JSON.stringify({ compilerOptions: { jsx: 'react-jsx' } }), + ) + await save( + 'bunfig.toml', + '[serve.static]\nplugins = ["./plugin.ts"]\nsourcemap = "linked"\n', + ) + const options = { + target: 'react', + routesDirectory: file('routes'), + generatedRouteTree: file(`routeTree.gen.${generatedExtension}`), + tmpDir: file('tmp'), + autoCodeSplitting, + disableLogging: true, + codeSplittingOptions: { defaultBehavior: [['loader'], ['component']] }, + } + await save( + 'plugin.ts', + `${virtualMount ? `import { rootRoute, index, route, physical } from '@tanstack/virtual-file-routes';` : ''} +const { default: router } = await import('@tanstack/router-plugin/bun'); +const options = ${JSON.stringify(options)}; +${virtualMount ? `options.virtualRouteConfig = rootRoute('__root.tsx', [index('index.tsx'), route('/about', 'about.tsx'), physical('../mounted')]);` : ''} +${virtualConfigFile ? `options.virtualRouteConfig = 'virtual-routes.ts';` : ''} +const plugin = router(options); +export default { name: 'observe-public-router-dev', setup(build) { + return plugin.setup(new Proxy(build, { get(target, key) { + if (key === 'onLoad') return (options, callback) => target.onLoad(options, async args => { + const result = await callback(args); + if (typeof result?.contents === 'string' && args.path.replaceAll('\\\\', '/').includes('/routes/')) { + console.log('ROUTER_INLINE_MAP ' + JSON.stringify({ id: args.path, contents: result.contents })); + } + return result; + }); + const value = Reflect.get(target, key); + return typeof value === 'function' ? value.bind(target) : value; + } })); +} }; +`, + ) + await save( + 'server.ts', + `import html from './index.html'; const server = Bun.serve({ hostname: '127.0.0.1', port: 0, development: { hmr: true }, routes: { '/__native-info': () => Response.json({ pid: process.pid }), '/*': html } }); console.log('ROUTER_READY ' + JSON.stringify({ url: server.url.href, pid: process.pid }));`, + ) + const preload = process.env.BUN_PLUGIN_PRELOAD + const preloadArg = preload + ? preload.startsWith('file:') + ? preload + : pathToFileURL(path.resolve(preload)).href + : undefined + let pending = '' + let settleReady: (value: { url: string; pid: number }) => void + let rejectReady: (error: Error) => void + const ready = new Promise<{ url: string; pid: number }>( + (resolve, reject) => { + settleReady = resolve + rejectReady = reject + }, + ) + child = spawn( + executable, + [...(preloadArg ? ['--preload', preloadArg] : []), 'server.ts'], + { + cwd: directory, + env: { ...process.env, NODE_ENV: 'development' }, + stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, + }, + ) + child.on('error', (error) => rejectReady(error)) + child.on('exit', (code, signal) => + rejectReady( + new Error(`Bun exited before readiness (${code}, ${signal})\n${logs}`), + ), + ) + child.stdout!.on('data', (chunk) => { + logs = (logs + chunk).slice(-2_000_000) + pending += chunk.toString() + let newline: number + while ((newline = pending.indexOf('\n')) !== -1) { + const line = pending.slice(0, newline) + pending = pending.slice(newline + 1) + try { + if (line.startsWith('ROUTER_READY ')) { + settleReady(JSON.parse(line.slice('ROUTER_READY '.length))) + } + if (line.startsWith('ROUTER_INLINE_MAP ')) { + inlineMaps.push(JSON.parse(line.slice('ROUTER_INLINE_MAP '.length))) + } + } catch (error) { + rejectReady(new Error(`Invalid fixture event: ${error}`)) + } + } + }) + child.stderr!.on('data', (chunk) => { + logs = (logs + chunk).slice(-2_000_000) + }) + let timeout: ReturnType + const info = await Promise.race([ + ready, + new Promise((_, reject) => { + timeout = setTimeout( + () => reject(new Error(`Bun readiness deadline\n${logs}`)), + 20_000, + ) + }), + ]).finally(() => clearTimeout(timeout!)) + const versionOf = async ( + name: string, + requireFrom: ReturnType, + ) => + JSON.parse( + await readFile(requireFrom.resolve(`${name}/package.json`), 'utf8'), + ).version as string + const versions = { + bun: execFileSync(executable, ['--version'], { encoding: 'utf8' }).trim(), + revision: execFileSync(executable, ['--revision'], { + encoding: 'utf8', + }).trim(), + node: process.version, + routerPlugin: await versionOf('@tanstack/router-plugin', requirePlugin), + reactRouter: await versionOf('@tanstack/react-router', requireReact), + react: await versionOf('react', requireReact), + unplugin: await versionOf('unplugin', requirePlugin), + playwright: await versionOf('@playwright/test', requirePlugin), + preload: preloadArg ?? null, + preloadSha256: preloadArg + ? createHash('sha256') + .update(await readFile(new URL(preloadArg))) + .digest('hex') + : null, + routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: repo, + encoding: 'utf8', + }).trim(), + } + return { + ...info, + directory, + versions, + inlineMaps, + logs: () => logs, + save, + tree: () => readFile(file(`routeTree.gen.${generatedExtension}`), 'utf8'), + rename: (from: string, to: string) => rename(file(from), file(to)), + remove: (name: string) => rm(file(name)), + assertAlive() { + if (child!.exitCode !== null || child!.signalCode !== null) { + throw new Error(`Bun exited\n${logs}`) + } + }, + async close() { + if (child!.exitCode === null && child!.signalCode === null) { + child!.kill() + let timer: ReturnType + await Promise.race([ + new Promise((resolve) => child!.once('exit', resolve)), + new Promise((resolve) => { + timer = setTimeout(resolve, 3_000) + }), + ]).finally(() => clearTimeout(timer!)) + if (child!.exitCode === null && child!.signalCode === null) { + child!.kill('SIGKILL') + await new Promise((resolve) => child!.once('exit', resolve)) + } + } + await rm(directory, { recursive: true, force: true }) + }, + } + } catch (error) { + child?.kill('SIGKILL') + if (child && child.exitCode === null && child.signalCode === null) { + await new Promise((resolve) => child!.once('exit', resolve)) + } + await rm(directory, { recursive: true, force: true }) + throw error + } +} diff --git a/packages/router-plugin/e2e/bun/dev-playwright.config.ts b/packages/router-plugin/e2e/bun/dev-playwright.config.ts new file mode 100644 index 00000000000..e814a7ed487 --- /dev/null +++ b/packages/router-plugin/e2e/bun/dev-playwright.config.ts @@ -0,0 +1,23 @@ +import { defineConfig, devices } from '@playwright/test' + +if (!process.env.BUN_EXECUTABLE) { + throw new Error('Set BUN_EXECUTABLE to the native development candidate') +} + +export default defineConfig({ + testDir: '.', + testMatch: 'dev.test.ts', + workers: 1, + retries: 0, + timeout: 90_000, + expect: { timeout: 15_000 }, + reporter: [['line']], + outputDir: process.env.BUN_DEV_TEST_OUTPUT ?? '../../.cache/bun-dev-results', + use: { + ...devices['Desktop Chrome'], + trace: 'retain-on-failure', + launchOptions: { + executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, + }, + }, +}) diff --git a/packages/router-plugin/e2e/bun/dev.test.ts b/packages/router-plugin/e2e/bun/dev.test.ts new file mode 100644 index 00000000000..416cf58b38e --- /dev/null +++ b/packages/router-plugin/e2e/bun/dev.test.ts @@ -0,0 +1,572 @@ +import { expect, test as base } from '@playwright/test' +import { SourceMap } from 'node:module' +import type { SourceMapPayload } from 'node:module' +import type { CDPSession, Page } from '@playwright/test' +import { + aboutSource, + nestedSource, + startDevFixture, + virtualConfigSource, +} from './dev-fixture' + +const test = base.extend<{ + native: Awaited> + generatedExtension: string + virtualMount: boolean + virtualConfigFile: boolean + autoCodeSplitting: boolean +}>({ + generatedExtension: ['ts', { option: true }], + virtualMount: [false, { option: true }], + virtualConfigFile: [false, { option: true }], + autoCodeSplitting: [true, { option: true }], + native: async ( + { generatedExtension, virtualMount, virtualConfigFile, autoCodeSplitting }, + use, + testInfo, + ) => { + const native = await startDevFixture({ + generatedExtension, + virtualMount, + virtualConfigFile, + autoCodeSplitting, + }) + try { + await testInfo.attach('versions.json', { + body: JSON.stringify(native.versions, null, 2), + contentType: 'application/json', + }) + await use(native) + } finally { + await testInfo.attach('native.log', { + body: native.logs(), + contentType: 'text/plain', + }) + await native.close() + } + }, +}) + +test.describe('virtual physical directory outside routesDirectory', () => { + test.use({ virtualMount: true }) + test('discovers a route added inside an existing empty mounted directory', async ({ + page, + request, + native, + }, testInfo) => { + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const token = await documentToken(page) + await native.save( + 'mounted/empty/deep/created.tsx', + nestedSource('/empty/deep/created', 'MOUNTED_ADDED'), + ) + await expect.poll(() => native.tree()).toContain('/empty/deep/created') + await page + .getByRole('link', { name: 'Mounted created', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('MOUNTED_ADDED') + const sameDocumentAtCheckpoint = (await documentToken(page)) === token + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('mounted.json', { + body: JSON.stringify({ sameDocumentAtCheckpoint, sameProcess: true }), + contentType: 'application/json', + }) + }) +}) + +for (const extension of ['mts', 'cts', 'tsx']) { + test.describe(`generated route tree .${extension}`, () => { + test.use({ generatedExtension: extension }) + test('bundles the actual generated TypeScript through the public plugin', async ({ + page, + native, + }) => { + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + expect(await native.tree()).toContain( + 'export interface FileRoutesByFullPath', + ) + await page.getByRole('link', { name: 'About', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') + native.assertAlive() + }) + }) +} + +const documentToken = (page: Page) => + page.evaluate(() => { + const state = globalThis as typeof globalThis & { + __bunDevDocumentToken?: string + } + return (state.__bunDevDocumentToken ??= crypto.randomUUID()) + }) + +function inlinePosition(contents: string, marker: string) { + const match = contents.match( + /\/\/# sourceMappingURL=data:application\/json[^,]*;base64,([^\s]+)/, + ) + expect( + match, + 'Router must forward an inline compiler source map', + ).toBeTruthy() + const payload = JSON.parse( + Buffer.from(match![1]!, 'base64').toString(), + ) as SourceMapPayload + return mappedPosition(contents, marker, payload) +} + +function mappedPosition( + source: string, + marker: string, + payload: SourceMapPayload, +) { + const markerIndex = source.indexOf(marker) + expect(markerIndex).toBeGreaterThanOrEqual(0) + const errorIndex = source.lastIndexOf('new Error', markerIndex) + expect(errorIndex).toBeGreaterThanOrEqual(0) + const generated = source.slice(0, errorIndex).split('\n') + const entry = new SourceMap(payload).findEntry( + generated.length - 1, + generated.at(-1)!.length, + ) + if (!('originalSource' in entry)) { + throw new Error( + `No authored mapping for ${marker} at generated ${generated.length}:${generated.at(-1)!.length}`, + ) + } + return { entry, payload } +} + +function expectAuthoredPosition( + result: ReturnType, + authored: string, + marker: string, +) { + const { entry, payload } = result + expect(entry.originalSource?.replaceAll('\\', '/')).toMatch( + /\/routes\/about\.tsx$/, + ) + const authoredLines = authored.split('\n') + const line = authoredLines.findIndex((value) => value.includes(marker)) + expect(entry.originalLine).toBe(line) + expect(entry.originalColumn).toBe(authoredLines[line]!.indexOf('new Error')) + const index = payload.sources.indexOf(entry.originalSource!) + expect(payload.sourcesContent?.[index]).toBe(authored) +} + +for (const autoCodeSplitting of [true, false]) { + test.describe(`autoCodeSplitting: ${autoCodeSplitting}`, () => { + test.use({ autoCodeSplitting }) + test('native lazy navigation and component/loader edits preserve the document and state', async ({ + page, + request, + native, + }, testInfo) => { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + await expect(page.getByText('ABOUT_BEFORE', { exact: true })).toHaveCount( + 0, + ) + await page.getByRole('link', { name: 'About', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') + await expect(page.getByRole('heading')).toHaveAttribute( + 'data-shared-identity', + 'true', + ) + expect( + await page.evaluate( + () => + ( + globalThis as typeof globalThis & { + __bunDevSharedInitializations?: number + } + ).__bunDevSharedInitializations, + ), + ).toBe(1) + expect( + native.inlineMaps.some((event) => + event.id.includes('?tsr-split=component'), + ), + ).toBe(autoCodeSplitting) + await page.getByRole('button', { name: 'Count 0', exact: true }).click() + await expect( + page.getByRole('button', { name: 'Count 1', exact: true }), + ).toBeVisible() + const token = await documentToken(page) + + await native.save('routes/about.tsx', aboutSource('ABOUT_AFTER')) + await expect(page.getByRole('heading')).toHaveText('ABOUT_AFTER') + await expect( + page.getByRole('button', { name: 'Count 1', exact: true }), + ).toBeVisible() + expect(await documentToken(page)).toBe(token) + await expect(page.getByRole('heading')).toHaveAttribute( + 'data-shared-identity', + 'true', + ) + + await native.save( + 'routes/about.tsx', + aboutSource('ABOUT_AFTER', 'LOADER_AFTER'), + ) + await expect(page.getByTestId('loader')).toHaveText('LOADER_AFTER') + await expect( + page.getByRole('button', { name: 'Count 1', exact: true }), + ).toBeVisible() + await expect(page.getByRole('heading')).toHaveAttribute( + 'data-shared-identity', + 'true', + ) + expect(await documentToken(page)).toBe(token) + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('lifecycle.json', { + body: JSON.stringify({ sameDocument: true, sameProcess: true, errors }), + contentType: 'application/json', + }) + expect(errors).toEqual([]) + }) + }) +} + +test('inline compiler maps and browser mappings retain authored positions before and after HMR', async ({ + page, + request, + native, +}, testInfo) => { + const session: CDPSession = await page.context().newCDPSession(page) + const scripts: Array<{ + scriptId: string + url: string + sourceMapURL: string + }> = [] + session.on('Debugger.scriptParsed', (event) => { + scripts.push({ + scriptId: event.scriptId, + url: event.url, + sourceMapURL: event.sourceMapURL ?? '', + }) + }) + await session.send('Debugger.enable') + try { + await page.goto(new URL('/about', native.url).href) + await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') + const token = await documentToken(page) + for (const [heading, marker, authored] of [ + ['ABOUT_BEFORE', 'AUTHORED_BEFORE', aboutSource()], + [ + 'ABOUT_MAPPED_AFTER', + 'AUTHORED_AFTER', + aboutSource('ABOUT_MAPPED_AFTER', 'LOADER_BEFORE', 'AUTHORED_AFTER'), + ], + ]) { + const start = heading === 'ABOUT_BEFORE' ? 0 : native.inlineMaps.length + if (heading !== 'ABOUT_BEFORE') { + await native.save('routes/about.tsx', authored!) + } + await expect(page.getByRole('heading')).toHaveText(heading!) + await expect + .poll(() => + native.inlineMaps + .slice(start) + .some( + (event) => + event.id.includes('?tsr-split=component') && + event.contents.includes(marker!), + ), + ) + .toBe(true) + const event = native.inlineMaps + .slice(start) + .findLast( + (value) => + value.id.includes('?tsr-split=component') && + value.contents.includes(marker!), + )! + expectAuthoredPosition( + inlinePosition(event.contents, marker!), + authored!, + marker!, + ) + + let browserResult: ReturnType | undefined + let browserMapKind = '' + await expect + .poll(async () => { + for (const script of [...scripts].reverse()) { + if (!script.sourceMapURL) { + continue + } + const { scriptSource } = await session.send( + 'Debugger.getScriptSource', + { scriptId: script.scriptId }, + ) + if (!scriptSource.includes(marker!)) { + continue + } + let payload: SourceMapPayload + if (script.sourceMapURL.startsWith('data:')) { + const [header, data] = script.sourceMapURL.split(',', 2) + payload = JSON.parse( + header!.includes(';base64') + ? Buffer.from(data!, 'base64').toString() + : decodeURIComponent(data!), + ) + browserMapKind = 'inline' + } else { + const scriptUrl = new URL(script.url || native.url, native.url) + // Chromium resolves a blob script's map against its inner URL. + const mapBase = + scriptUrl.protocol === 'blob:' + ? scriptUrl.pathname + : scriptUrl.href + const response = await request.get( + new URL(script.sourceMapURL, mapBase).href, + ) + if (!response.ok()) { + continue + } + payload = await response.json() + browserMapKind = 'external' + } + browserResult = mappedPosition(scriptSource, marker!, payload) + return true + } + return false + }) + .toBe(true) + expectAuthoredPosition(browserResult!, authored!, marker!) + expect(await documentToken(page)).toBe(token) + await testInfo.attach(`${marker}-mapping.json`, { + body: JSON.stringify({ + input: inlinePosition(event.contents, marker!).entry, + browser: browserResult!.entry, + browserMapKind, + }), + contentType: 'application/json', + }) + } + native.assertAlive() + } finally { + await session.detach() + } +}) + +test('discovers nested empty directories and handles add, rename and delete without a process restart', async ({ + page, + request, + native, +}, testInfo) => { + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const topology: Array<{ stage: string; automaticDocumentReload: boolean }> = + [] + let token = await documentToken(page) + await native.save( + 'routes/nested/empty/deep/added.tsx', + nestedSource('/nested/empty/deep/added', 'NESTED_ADDED'), + ) + await expect.poll(() => native.tree()).toContain('/nested/empty/deep/added') + await page.getByRole('link', { name: 'Nested added', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('NESTED_ADDED') + topology.push({ + stage: 'add-in-existing-empty-nested-directory', + automaticDocumentReload: (await documentToken(page)) !== token, + }) + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + token = await documentToken(page) + + await native.rename( + 'routes/nested/empty/deep/added.tsx', + 'routes/nested/empty/deep/renamed.tsx', + ) + await expect + .poll(async () => { + const tree = await native.tree() + return ( + tree.includes('/nested/empty/deep/renamed') && + !tree.includes('/nested/empty/deep/added') + ) + }) + .toBe(true) + await page.getByRole('link', { name: 'Nested renamed', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('NESTED_ADDED') + await page.getByRole('link', { name: 'Nested added', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + topology.push({ + stage: 'rename', + automaticDocumentReload: (await documentToken(page)) !== token, + }) + await page.getByRole('link', { name: 'Home', exact: true }).click() + token = await documentToken(page) + + await native.remove('routes/nested/empty/deep/renamed.tsx') + await expect + .poll( + async () => !(await native.tree()).includes('/nested/empty/deep/renamed'), + ) + .toBe(true) + await page.getByRole('link', { name: 'Nested renamed', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + topology.push({ + stage: 'delete', + automaticDocumentReload: (await documentToken(page)) !== token, + }) + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('topology.json', { + body: JSON.stringify({ pid: native.pid, topology }, null, 2), + contentType: 'application/json', + }) +}) + +test('repairs a route generation conflict without restarting the server', async ({ + page, + request, + native, +}, testInfo) => { + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const token = await documentToken(page) + const errorStart = native.logs().length + await native.save( + 'routes/(conflict)/about.tsx', + nestedSource('/(conflict)/about', 'CONFLICTING_ABOUT'), + ) + await expect + .poll(() => native.logs().slice(errorStart)) + .toMatch(/conflicting configuration paths/i) + native.assertAlive() + + await native.remove('routes/(conflict)/about.tsx') + await native.save( + 'routes/repaired.tsx', + nestedSource('/repaired', 'GENERATION_REPAIRED'), + ) + await expect.poll(() => native.tree()).toContain('/repaired') + await page.getByRole('link', { name: 'Repaired', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('GENERATION_REPAIRED') + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('generation-recovery.json', { + body: JSON.stringify({ + sameProcess: true, + automaticDocumentReload: (await documentToken(page)) !== token, + }), + contentType: 'application/json', + }) +}) + +test('repairs a syntax error in an active route without restarting the server', async ({ + page, + request, + native, +}, testInfo) => { + await page.goto(native.url) + await page.getByRole('link', { name: 'About', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') + const token = await documentToken(page) + const errorStart = native.logs().length + await native.save( + 'routes/about.tsx', + 'export const Route = ; // SYNTAX_BROKEN\n', + ) + await expect + .poll(() => { + const output = native.logs().slice(errorStart) + return ( + output.includes('about.tsx') && + /Unexpected|Expected (?:expression|identifier)|SyntaxError/.test(output) + ) + }) + .toBe(true) + native.assertAlive() + + await native.save( + 'routes/about.tsx', + aboutSource('SYNTAX_REPAIRED', 'LOADER_REPAIRED'), + ) + await expect(page.getByRole('heading')).toHaveText('SYNTAX_REPAIRED') + await expect(page.getByTestId('loader')).toHaveText('LOADER_REPAIRED') + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('syntax-recovery.json', { + body: JSON.stringify({ + sameProcess: true, + automaticDocumentReload: (await documentToken(page)) !== token, + }), + contentType: 'application/json', + }) +}) + +test.describe('string virtual configuration outside routesDirectory', () => { + test.use({ virtualConfigFile: true }) + test('updates existing browser navigation after an in-place config edit', async ({ + page, + request, + native, + }, testInfo) => { + await page.goto(native.url) + await page + .getByRole('link', { name: 'Virtual before', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('VIRTUAL_BEFORE') + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const token = await documentToken(page) + + await native.save('virtual-routes.ts', virtualConfigSource('after')) + await expect + .poll(async () => { + const tree = await native.tree() + return ( + tree.includes('/virtual-after') && !tree.includes('/virtual-before') + ) + }) + .toBe(true) + await page.getByRole('link', { name: 'Virtual after', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('VIRTUAL_AFTER') + await page + .getByRole('link', { name: 'Virtual before', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('virtual-config.json', { + body: JSON.stringify({ + sameProcess: true, + automaticDocumentReload: (await documentToken(page)) !== token, + }), + contentType: 'application/json', + }) + }) +}) diff --git a/packages/router-plugin/e2e/bun/run-dev.mjs b/packages/router-plugin/e2e/bun/run-dev.mjs new file mode 100644 index 00000000000..70486fad3bb --- /dev/null +++ b/packages/router-plugin/e2e/bun/run-dev.mjs @@ -0,0 +1,58 @@ +import { createRequire } from 'node:module' +import { spawn } from 'node:child_process' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { existsSync } from 'node:fs' + +if (!process.env.BUN_EXECUTABLE) { + throw new Error('Set BUN_EXECUTABLE to the native development candidate') +} +let repo = path.dirname(fileURLToPath(import.meta.url)) +while (!existsSync(path.join(repo, 'packages/router-plugin/package.json'))) { + const parent = path.dirname(repo) + if (parent === repo) { + throw new Error('Run this harness inside the Router repository') + } + repo = parent +} +const requirePlugin = createRequire( + path.join(repo, 'packages/router-plugin/package.json'), +) +const config = fileURLToPath( + new URL('./dev-playwright.config.ts', import.meta.url), +) +const executable = process.env.BUN_EXECUTABLE +const preload = process.env.BUN_PLUGIN_PRELOAD +const child = spawn( + process.execPath, + [ + requirePlugin.resolve('@playwright/test/cli'), + 'test', + '--config', + config, + ...process.argv.slice(2), + ], + { + cwd: path.join(repo, 'packages/router-plugin'), + env: { + ...process.env, + ROUTER_REPOSITORY_ROOT: repo, + BUN_EXECUTABLE: /[\\/]/.test(executable) + ? path.resolve(executable) + : executable, + BUN_PLUGIN_PRELOAD: + preload && !preload.startsWith('file:') + ? path.resolve(preload) + : preload, + }, + stdio: 'inherit', + windowsHide: true, + }, +) +child.on('error', (error) => { + console.error(error) + process.exitCode = 1 +}) +child.on('exit', (code, signal) => { + process.exitCode = signal ? 1 : (code ?? 1) +}) diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json index 2dcc86135fc..3ffd7003160 100644 --- a/packages/router-plugin/package.json +++ b/packages/router-plugin/package.json @@ -30,6 +30,7 @@ "test:unit": "vitest", "test:unit:dev": "vitest --watch", "test:e2e:bun": "playwright test --config e2e/bun/playwright.config.ts", + "test:e2e:bun:dev": "node e2e/bun/run-dev.mjs", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", @@ -164,6 +165,19 @@ "build" ] }, + "test:e2e:bun:dev": { + "dependsOn": [ + "build", + { + "target": "build", + "projects": [ + "@tanstack/react-router" + ] + } + ], + "cache": false, + "parallelism": false + }, "test:e2e:bun": { "dependsOn": [ "build", diff --git a/packages/router-plugin/src/core/code-splitter/plugins/framework-plugins.ts b/packages/router-plugin/src/core/code-splitter/plugins/framework-plugins.ts index a0351ad2103..8c06ef9f211 100644 --- a/packages/router-plugin/src/core/code-splitter/plugins/framework-plugins.ts +++ b/packages/router-plugin/src/core/code-splitter/plugins/framework-plugins.ts @@ -3,16 +3,18 @@ import { createReactRefreshRouteComponentsPlugin } from './react-refresh-route-c import { createReactStableHmrSplitRouteComponentsPlugin } from './react-stable-hmr-split-route-components' import type { CodeSplitCompilerPlugin } from '../plugins' import type { Config, HmrStyle } from '../../config' +import type { UnpluginContextMeta } from 'unplugin' export function getFrameworkHmrCompilerPlugins(opts: { targetFramework: Config['target'] hmrStyle?: HmrStyle + framework?: UnpluginContextMeta['framework'] }): Array | undefined { switch (opts.targetFramework) { case 'react': { const hmrStyle = opts.hmrStyle ?? 'vite' return [ - ...(hmrStyle === 'vite' + ...(hmrStyle === 'vite' && opts.framework !== 'bun' ? [createReactRefreshIgnoredRouteExportsPlugin()] : []), createReactRefreshRouteComponentsPlugin(), diff --git a/packages/router-plugin/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts b/packages/router-plugin/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts index 99448f452ad..2bb691294cf 100644 --- a/packages/router-plugin/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts +++ b/packages/router-plugin/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts @@ -15,8 +15,7 @@ function createHotDataKey(exportName: string) { const buildStableSplitComponentStatements = template.statements( ` const %%stableComponentIdent%% = (() => { - const hot = %%hotExpression%% - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = %%hotExpression%% ? ((%%hotExpression%%).data ??= {}) : undefined return hotData?.[%%hotDataKey%%] ?? %%lazyRouteComponentIdent%%(%%localImporterIdent%%, %%exporterIdent%%) })() if (%%hotExpression%%) { diff --git a/packages/router-plugin/src/core/hmr/vite-adapter.ts b/packages/router-plugin/src/core/hmr/vite-adapter.ts index ba8d42a80ad..8419b9e01f3 100644 --- a/packages/router-plugin/src/core/hmr/vite-adapter.ts +++ b/packages/router-plugin/src/core/hmr/vite-adapter.ts @@ -26,8 +26,7 @@ export function createViteHmrStatement( template.statement( ` if (import.meta.hot) { - const hot = import.meta.hot - const hotData = hot.data ??= {} + const hotData = import.meta.hot.data ??= {} const handleRouteUpdate = ${handleRouteUpdateCode} const initialRouteId = ${routeIdFallback} ?? hotData['tsr-route-id'] if (initialRouteId) { @@ -41,7 +40,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? ${routeIdFallback} if (routeId) { diff --git a/packages/router-plugin/src/core/router-code-splitter-plugin.ts b/packages/router-plugin/src/core/router-code-splitter-plugin.ts index 3aec495596c..8be2f093e5b 100644 --- a/packages/router-plugin/src/core/router-code-splitter-plugin.ts +++ b/packages/router-plugin/src/core/router-code-splitter-plugin.ts @@ -30,6 +30,7 @@ import type { CodeSplitCompilerPlugin } from './code-splitter/plugins' import type { Config, HmrStyle } from './config' import type { RouterPluginContext } from './router-plugin-context' import type { + UnpluginContextMeta, UnpluginFactory, UnpluginOptions, TransformResult as UnpluginTransformResult, @@ -85,6 +86,7 @@ function bunRouteModule( ? 'ts' : 'js'), resolveDir: dirname(filename!), + watchFiles: [filename!], } }) }, @@ -137,6 +139,7 @@ const TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record< export function createRouterCodeSplitterPlugin( options: Partial Config)> | undefined = {}, routerPluginContext: RouterPluginContext, + framework?: UnpluginContextMeta['framework'], ): ReturnType Config)> | undefined>> { let ROOT: string = process.cwd() let userConfig: Config @@ -161,6 +164,7 @@ export function createRouterCodeSplitterPlugin( ? (getFrameworkHmrCompilerPlugins({ targetFramework: userConfig.target, hmrStyle, + framework, }) ?? []) : []), ...(userConfig.codeSplittingOptions?.compilerPlugins ?? []), @@ -346,8 +350,10 @@ export function createRouterCodeSplitterPlugin( enforce: 'pre', bun: { - setup() { - isProduction = true + setup(build) { + isProduction = !( + 'reactFastRefresh' in build.config && build.config.reactFastRefresh + ) initUserConfig() sharedBindingsMap.clear() }, @@ -491,6 +497,10 @@ export function createRouterCodeSplitterPlugin( export const unpluginRouterCodeSplitterFactory: UnpluginFactory< Partial Config)> | undefined -> = (options = {}) => { - return createRouterCodeSplitterPlugin(options, createRouterPluginContext()) +> = (options = {}, meta) => { + return createRouterCodeSplitterPlugin( + options, + createRouterPluginContext(), + meta.framework, + ) } diff --git a/packages/router-plugin/src/core/router-composed-plugin.ts b/packages/router-plugin/src/core/router-composed-plugin.ts index e8f44575350..9846940ee4f 100644 --- a/packages/router-plugin/src/core/router-composed-plugin.ts +++ b/packages/router-plugin/src/core/router-composed-plugin.ts @@ -50,7 +50,11 @@ export const unpluginRouterComposedFactory: UnpluginFactory< createRouterGeneratorPlugin(options, routerPluginContext), ) const routerCodeSplitter = getPlugin( - createRouterCodeSplitterPlugin(options, routerPluginContext), + createRouterCodeSplitterPlugin( + options, + routerPluginContext, + meta.framework, + ), ) const result = [ @@ -97,12 +101,11 @@ export const unpluginRouterComposedFactory: UnpluginFactory< const isProduction = process.env.NODE_ENV === 'production' if ( - meta.framework !== 'bun' && - !isProduction && + (meta.framework === 'bun' || !isProduction) && !userConfig.autoCodeSplitting ) { const routerHmr = getPlugin( - createRouterHmrPlugin(options, routerPluginContext), + createRouterHmrPlugin(options, routerPluginContext, meta.framework), ) result.push(...routerHmr) } diff --git a/packages/router-plugin/src/core/router-generator-plugin.ts b/packages/router-plugin/src/core/router-generator-plugin.ts index 4589bf828e9..87a5acca9b7 100644 --- a/packages/router-plugin/src/core/router-generator-plugin.ts +++ b/packages/router-plugin/src/core/router-generator-plugin.ts @@ -1,4 +1,12 @@ -import { isAbsolute, join, normalize } from 'node:path' +import { readFile, readdir } from 'node:fs/promises' +import { + dirname, + extname, + isAbsolute, + join, + normalize, + resolve, +} from 'node:path' import { Generator, resolveConfigPath } from '@tanstack/router-generator' import { getConfig } from './config' import { createRouterPluginContext } from './router-plugin-context' @@ -80,6 +88,59 @@ export function createRouterGeneratorPlugin( initConfigAndGenerator() // Reject generation errors instead of bundling a stale route tree. build.onStart(() => runGenerator()) + if ( + 'reactFastRefresh' in build.config && + build.config.reactFastRefresh + ) { + const generatedRouteTree = resolve( + ROOT, + userConfig.generatedRouteTree, + ) + const extension = extname(generatedRouteTree) + build.onLoad( + { + filter: new RegExp( + `^${generatedRouteTree.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, + ), + }, + async () => { + // Bun watches immediate directory entries. Include empty directories + // so a route added there also triggers generation before bundling. + const watchDirs = await Promise.all( + generator.getRoutesDirectoryPaths().map(async (directory) => { + const entries = await readdir(directory, { + recursive: true, + withFileTypes: true, + }) + return [ + directory, + ...entries + .filter((entry) => entry.isDirectory()) + .map((entry) => join(entry.parentPath, entry.name)), + ] + }), + ) + return { + contents: await readFile(generatedRouteTree, 'utf8'), + loader: + build.config.loader?.[extension] ?? + (extension === '.tsx' + ? 'tsx' + : extension === '.jsx' + ? 'jsx' + : /\.[cm]?ts$/.test(extension) + ? 'ts' + : 'js'), + resolveDir: dirname(generatedRouteTree), + watchDirs: watchDirs.flat(), + watchFiles: + typeof userConfig.virtualRouteConfig === 'string' + ? [resolve(ROOT, userConfig.virtualRouteConfig)] + : undefined, + } + }, + ) + } }, }, vite: { diff --git a/packages/router-plugin/src/core/router-hmr-plugin.ts b/packages/router-plugin/src/core/router-hmr-plugin.ts index e1dc01a43b1..24b98c80cc0 100644 --- a/packages/router-plugin/src/core/router-hmr-plugin.ts +++ b/packages/router-plugin/src/core/router-hmr-plugin.ts @@ -5,7 +5,11 @@ import { createRouteHmrStatement } from './hmr' import { debug, normalizePath, routeFactoryCallCodeFilter } from './utils' import { getConfig } from './config' import { createRouterPluginContext } from './router-plugin-context' -import type { UnpluginFactory } from 'unplugin' +import type { + UnpluginContextMeta, + UnpluginFactory, + UnpluginOptions, +} from 'unplugin' import type { Config } from './config' import type { RouterPluginContext } from './router-plugin-context' @@ -18,6 +22,7 @@ import type { RouterPluginContext } from './router-plugin-context' export function createRouterHmrPlugin( options: Partial Config)> | undefined = {}, routerPluginContext: RouterPluginContext, + framework?: UnpluginContextMeta['framework'], ): ReturnType | undefined>> { let ROOT: string = process.cwd() @@ -27,9 +32,18 @@ export function createRouterHmrPlugin( let userConfig = resolveUserConfig() - return { + const plugin: UnpluginOptions = { name: 'tanstack-router:hmr', enforce: 'pre', + bun: { + setup(build) { + if ( + !('reactFastRefresh' in build.config && build.config.reactFastRefresh) + ) { + plugin.transform = undefined + } + }, + }, transform: { filter: { // this is necessary for webpack / rspack to avoid matching .html files @@ -53,6 +67,7 @@ export function createRouterHmrPlugin( const compilerPlugins = getFrameworkHmrCompilerPlugins({ targetFramework: 'react', hmrStyle, + framework, }) const compiled = compileCodeSplitReferenceRoute({ code, @@ -109,10 +124,15 @@ export function createRouterHmrPlugin( }, }, } + return plugin } export const unpluginRouterHmrFactory: UnpluginFactory< Partial | undefined -> = (options = {}) => { - return createRouterHmrPlugin(options, createRouterPluginContext()) +> = (options = {}, meta) => { + return createRouterHmrPlugin( + options, + createRouterPluginContext(), + meta.framework, + ) } diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx index c771483895a..3f529238f11 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx @@ -5,8 +5,7 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' const TSRSplitComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') @@ -39,8 +38,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -101,7 +99,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@webpack-hot.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@webpack-hot.tsx index eb655d02877..2dd93d236df 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@webpack-hot.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@webpack-hot.tsx @@ -5,8 +5,9 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' const TSRSplitComponent = (() => { - const hot = import.meta.webpackHot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.webpackHot + ? (import.meta.webpackHot.data ??= {}) + : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/createFileRoute-lowercase-components@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/createFileRoute-lowercase-components@true.tsx index bf94d5d3fd2..cd8539367c4 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/createFileRoute-lowercase-components@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/createFileRoute-lowercase-components@true.tsx @@ -5,8 +5,7 @@ const $$splitErrorComponentImporter = () => import { lazyRouteComponent } from '@tanstack/react-router' import { createFileRoute } from '@tanstack/react-router' const TSRSplitErrorComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:errorComponent'] ?? lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') @@ -17,8 +16,7 @@ if (import.meta.hot) { TSRSplitErrorComponent } const TSRSplitComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') @@ -58,8 +56,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -120,7 +117,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-inline-component@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-inline-component@true.tsx index f12187ccd1a..0f165963312 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-inline-component@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-inline-component@true.tsx @@ -24,8 +24,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -86,7 +85,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-lowercase-components@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-lowercase-components@true.tsx index 9f8df0d43f5..5a2cbcdc051 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-lowercase-components@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-lowercase-components@true.tsx @@ -40,8 +40,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -102,7 +101,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute@true.tsx index 859380ef535..e91bcc84f3e 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute@true.tsx @@ -23,8 +23,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -85,7 +84,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRouteWithContext-type-args@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRouteWithContext-type-args@true.tsx index 9d942f65a2b..358972aaa0a 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRouteWithContext-type-args@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/createRootRouteWithContext-type-args@true.tsx @@ -31,8 +31,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -93,7 +92,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/explicit-undefined-component@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/explicit-undefined-component@true.tsx index 555c8fdd6cd..4ec3589a754 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/explicit-undefined-component@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/explicit-undefined-component@true.tsx @@ -22,8 +22,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -84,7 +83,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx index 9e27af7d699..a98bdb7498d 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx @@ -5,8 +5,7 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' const TSRSplitComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') @@ -39,8 +38,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -101,7 +99,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/multi-component@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/multi-component@true.tsx index 1a134b88da2..609cfe7987e 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/multi-component@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/multi-component@true.tsx @@ -7,8 +7,7 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' const TSRSplitComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') @@ -19,8 +18,7 @@ if (import.meta.hot) { TSRSplitComponent } const TSRSplitErrorComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:errorComponent'] ?? lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') @@ -54,8 +52,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -116,7 +113,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/react/string-literal-keys@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/react/string-literal-keys@true.tsx index b3bc82d69ed..a2a7e0bf3f6 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/react/string-literal-keys@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/react/string-literal-keys@true.tsx @@ -7,8 +7,7 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' const TSRSplitComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:component'] ?? lazyRouteComponent($$splitComponentImporter, 'component') @@ -19,8 +18,7 @@ if (import.meta.hot) { TSRSplitComponent } const TSRSplitErrorComponent = (() => { - const hot = import.meta.hot - const hotData = hot ? (hot.data ??= {}) : undefined + const hotData = import.meta.hot ? (import.meta.hot.data ??= {}) : undefined return ( hotData?.['tsr-split-component:errorComponent'] ?? lazyRouteComponent($$splitErrorComponentImporter, 'errorComponent') @@ -54,8 +52,7 @@ export function TSRFastRefreshAnchor() { return null } if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -116,7 +113,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { diff --git a/packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx b/packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx index 05fa745c4b5..bc531f9000e 100644 --- a/packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx +++ b/packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx @@ -8,8 +8,7 @@ export const Route = createFileRoute('/posts')({ component: lazyRouteComponent($$splitComponentImporter, 'component'), }) if (import.meta.hot) { - const hot = import.meta.hot - const hotData = (hot.data ??= {}) + const hotData = (import.meta.hot.data ??= {}) const handleRouteUpdate = function handleRouteUpdate(routeId, newRoute) { const router = window.__TSR_ROUTER__ const oldRoute = router.routesById[routeId] @@ -64,7 +63,7 @@ if (import.meta.hot) { handleRouteUpdate(initialRouteId, Route) hotData['tsr-route-update-handled'] = Route } - hot.accept((newModule) => { + import.meta.hot.accept((newModule) => { if (Route && newModule && newModule.Route) { const routeId = hotData['tsr-route-id'] ?? Route.id if (routeId) { From 818db82b261e88bb4e984451359d50a5df191a76 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 08:55:08 +0200 Subject: [PATCH 03/31] ci(router-plugin): test Bun builds across platforms --- .github/workflows/bun.yml | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bun.yml b/.github/workflows/bun.yml index aa5bae23d27..171cf46e56d 100644 --- a/.github/workflows/bun.yml +++ b/.github/workflows/bun.yml @@ -34,19 +34,42 @@ env: jobs: router: - runs-on: ubuntu-latest + name: Bun Router (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + defaults: + run: + shell: bash steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - name: Setup Tools - uses: TanStack/config/.github/setup@e4b48f16568324f76f467aa4c2aac2f05db632c3 # main + - name: Setup pnpm + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version-file: .nvmrc + package-manager-cache: false + - name: Install dependencies + run: >- + pnpm install --frozen-lockfile + --filter . + --filter "@tanstack/router-plugin..." + --filter "@tanstack/react-router..." - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: '1.4.3' - - name: Install Chromium + - name: Install Chromium (Linux) + if: runner.os == 'Linux' run: pnpm exec playwright install --with-deps chromium --only-shell + - name: Install Chromium (Windows and macOS) + if: runner.os != 'Linux' + run: pnpm exec playwright install chromium --only-shell - name: Test production builds and navigation run: pnpm nx run @tanstack/router-plugin:test:e2e:bun --outputStyle=stream --skipRemoteCache From d70b9ddaf4007b546c1e151dd0397554f3ec46fe Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 10:53:57 +0200 Subject: [PATCH 04/31] ci: validate patched Bun on native macOS --- .../native-bun-validation/browser-setup.mjs | 64 +++++++ .github/native-bun-validation/build-macos.sh | 54 ++++++ .../native-v9-additional-files.tar.gz | Bin 0 -> 10816 bytes .../native-v9-manifest.json | 27 +++ .../native-v9-tracked.patch.gz | Bin 0 -> 85792 bytes .github/native-bun-validation/prepare.py | 103 +++++++++++ .../require-tests-reporter.mjs | 29 +++ .github/workflows/bun-native-validation.yml | 175 ++++++++++++++++++ 8 files changed, 452 insertions(+) create mode 100644 .github/native-bun-validation/browser-setup.mjs create mode 100644 .github/native-bun-validation/build-macos.sh create mode 100644 .github/native-bun-validation/native-v9-additional-files.tar.gz create mode 100644 .github/native-bun-validation/native-v9-manifest.json create mode 100644 .github/native-bun-validation/native-v9-tracked.patch.gz create mode 100644 .github/native-bun-validation/prepare.py create mode 100644 .github/native-bun-validation/require-tests-reporter.mjs create mode 100644 .github/workflows/bun-native-validation.yml diff --git a/.github/native-bun-validation/browser-setup.mjs b/.github/native-bun-validation/browser-setup.mjs new file mode 100644 index 00000000000..c68480e2d0d --- /dev/null +++ b/.github/native-bun-validation/browser-setup.mjs @@ -0,0 +1,64 @@ +import { mkdir, readFile, writeFile, chmod } from 'node:fs/promises' +import { createHash } from 'node:crypto' +import { execFileSync } from 'node:child_process' +import path from 'node:path' +import { pathToFileURL } from 'node:url' + +const repo = process.env.GITHUB_WORKSPACE +const binary = path.join(repo, '.native-artifact/binary/bun') +const proof = path.join(repo, '.native-browser-proof') +const cache = path.join(repo, 'packages/router-plugin/.cache/native-validation') +const preload = path.join(cache, 'preload.ts') +const upstream = path.join(repo, '.native-unplugin/dist/index.mjs') +const wrapper = path.join(cache, 'bin/bun') +await mkdir(path.dirname(wrapper), { recursive: true }) +await mkdir(proof, { recursive: true }) +await chmod(binary, 0o755) +const hash = createHash('sha256') + .update(await readFile(binary)) + .digest('hex') +const expected = JSON.parse( + await readFile(path.join(repo, '.native-artifact/binary-proof.json'), 'utf8'), +) +if (hash !== expected.sha256) { + throw new Error('Downloaded native Bun binary hash mismatch') +} +// Bun resolves this mock beside router-plugin's installed unplugin dependency. +await writeFile( + preload, + `import { mock } from 'bun:test'\nimport * as upstream from ${JSON.stringify(pathToFileURL(upstream).href)}\nmock.module('unplugin', () => upstream)\n`, +) +const quote = (value) => `'${value.replaceAll("'", "'\\''")}'` +await writeFile( + wrapper, + `#!/bin/sh\nexec ${quote(binary)} --preload ${quote(preload)} "$@"\n`, +) +await chmod(wrapper, 0o755) +const versions = { + routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: repo, + encoding: 'utf8', + }).trim(), + unpluginHead: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: path.dirname(path.dirname(upstream)), + encoding: 'utf8', + }).trim(), + node: process.version, + bun: execFileSync(binary, ['--version'], { encoding: 'utf8' }).trim(), + binarySha256: hash, + nativeSource: expected, +} +await writeFile( + path.join(proof, 'versions.json'), + JSON.stringify(versions, null, 2) + '\n', +) +await writeFile(path.join(proof, 'preload.ts'), await readFile(preload)) +await writeFile( + process.env.GITHUB_ENV, + `BUN_EXECUTABLE=${binary}\nBUN_PLUGIN_PRELOAD=${preload}\nBUN_DEV_TEST_OUTPUT=${proof}/dev-results\n`, + { flag: 'a' }, +) +await writeFile(process.env.GITHUB_PATH, path.dirname(wrapper) + '\n', { + flag: 'a', +}) +console.log(JSON.stringify(versions, null, 2)) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh new file mode 100644 index 00000000000..a8e3a560c80 --- /dev/null +++ b/.github/native-bun-validation/build-macos.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo="$GITHUB_WORKSPACE" +proof="$repo/.native-proof" +mkdir -p "$proof" +{ + date -u + sw_vers + uname -a + sysctl hw.memsize hw.ncpu + df -h + xcodebuild -version + xcrun --show-sdk-path + node --version + bun --version + python3 --version + brew --version +} | tee "$proof/preflight.log" + +python3 "$repo/.github/native-bun-validation/prepare.py" \ + --bun "$repo/.native-bun" --out "$proof" | tee "$proof/source-verification.json" + +# CONTRIBUTING.md's macOS prerequisites, plus its required LLVM major. +brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm@23 +export PATH="$(brew --prefix llvm@23)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" +export RUSTUP_TOOLCHAIN=nightly-2026-09-15 +if ! command -v rustup >/dev/null; then + rustup-init -y --no-modify-path --profile minimal --default-toolchain none +fi +rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component rust-src +llvm_version="$(llvm-config --version)" +[[ "$llvm_version" =~ ^23\.1\.[0-9]+$ ]] || { echo "Expected LLVM 23.1.x, got $llvm_version"; exit 1; } +{ + brew list --versions + clang --version + llvm-config --version + rustc -vV + cargo --version + rustup show + cmake --version + ninja --version + ccache --version + df -h +} | tee "$proof/toolchain.log" + +cd "$repo/.native-bun" +bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" +bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" + +# Use the official build-and-execute path. No timeout wraps compilation. +read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v9-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" +[[ "${#native_tests[@]}" -eq 9 ]] +bun run build:assert -j2 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" diff --git a/.github/native-bun-validation/native-v9-additional-files.tar.gz b/.github/native-bun-validation/native-v9-additional-files.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..f022742ed0d756f6e48367fcae9a29594cd9213e GIT binary patch literal 10816 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 ITL_5%10YgB3;+NC literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/native-v9-manifest.json b/.github/native-bun-validation/native-v9-manifest.json new file mode 100644 index 00000000000..76c3a3d5185 --- /dev/null +++ b/.github/native-bun-validation/native-v9-manifest.json @@ -0,0 +1,27 @@ +{ + "head": "dca7d25e95cca39316c659a377dba6803805549f", + "trackedPatchSha256": "fb44303ad3c22ae5652bfe32fe3e6e32c1aeb24dc5594b3a1a631ab0e945406a", + "additionalFiles": { + "src/bundler/input_source_map.rs": "acc9b44a3a7c619801e3c9738b00f335b9cb48eaaff7cc9437b7ec5233dbf0da", + "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", + "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", + "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", + "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", + "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" + }, + "platform": "Debian Linux x64 in Docker", + "testCommand": "bun run build:assert -j6 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts", + "nativeTests": { + "passed": 110, + "failed": 0 + }, + "routerDevelopmentBrowser": { + "passed": 11, + "failed": 0 + }, + "routerProductionBrowser": { + "passed": 6, + "failed": 0, + "skipped": 0 + } +} diff --git a/.github/native-bun-validation/native-v9-tracked.patch.gz b/.github/native-bun-validation/native-v9-tracked.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..d08a5c99e16e2d408b84af7b6335b602e4cc03d7 GIT binary patch literal 85792 zcmV(_K-9ka@;u5DEMDbfmTn*RW6FEi>{RA9$A*V-JflFCHGuD zkC(+FQ4%c{SwpZSt8GPW#767`Y@GMl7ubL2P0o{SWF|m@*J4TTnR8jkOiLnx1PCM& zc~8%uPTA(>rJpco>%@sKBQuEHYc|pTSo1@Ve_{Q>WUxORI;Pp5xO;n({)i3w{oU>D zwav}VT<^7Bua}4L=RdQ}!QN=!*kwKZxySzeXXf!a4?P~bJ{RnWeOzN~eXJPzZH(dYwPOKYiJ^Eu22icq7MdHz4V&(+F4R`6UEG)`uGpF^LNDO) z7XQNCMdC~XF3g$tg-se?%QbQOJA1qR>C`kQyzdSMLnpr`jUZ^18k@knjrzOB9_!JM zKmVD%xJ$Sjd7Qb?Z0-k6;zuEyMK@fqxf2UNykyZ0kFU7nv1t^uz=C%#B{!2H=fj&3*;i4!LbzrkUFpCkb{*Vx*o{1y={VwcaHx%N4H zHsPLN4ohF+BF0<@?y*}xxnh7s1``oWuAGD++6cA*gSpp9?7(8oBR@=70!_Fdvncj2 z{m=faCZQn^eXC^;2T|t^3et@YR#)&-V`c8&O8rYMNbQ{Ij1zHm^ zqI5V*gWX>F?iCYPQJnBl(1~8mVG-)-G!ot_3Z1@?wAphf+}jy>ra2n$eRqFnuYopa zohztv_7dpv-tI13WAI}i=<&szyZ+RdyPDk1kxFKWoJ8!Bhdg$YYPx z^RqDV#AbbbIIh25oV}B19fgVGhp?!Cmj7J%H%;(c&~149Wf6aj%_APMa^T{5ed1OrL~fhx`jt4j3D-rE4G^kf%pzM@k(dIdHll z1`GUa&bXk#y@(5w&IvUUV?}jjPh5Cd1tMEcl0R~E4;BcPA0|AWaS!$dTNumkQfg! z_W-Sk18~@_69Wd)qU49ArJgx+A-9EB1qVH>I8z1%{Xokmf6OI}FW_o5K*re&Lqz5|(jIIkOurY=o5?U22RY`EbC_;Wqbgcwsg#{kVQIOiqS=VNdZq>6eu})HIN4wI%oI z07>}ncEA6)eL9*9}cgqn8{NIjo`OO%P ze&zF&32;Y~gJIt^`DC|$FxuVDANuOPblj`o0Rru81N!W269X_`Oke>PZo-a5^6ZK8 zoG^#6tu6Sv8Lml8tRP$mfj{NI0B!Qv0U`_6d+fLgtj72viDG`vr(=^~0Q4(ITuq$t z(qj1bB8iRcC2g>O!!33;2SWNxHF|DHeAwE8D}*I*4+Hg9{J1(KfU8dg3mlQC8#QAJ zQl7vhX!yC<#-33l5W~~KU0`%9>tgPN&keN$h6I6EaC4--GRQ`|l2Hik&}2g5y*(f!#xKtw1Yg!)Hwv19H= zu_r9{8vj1WKi~Kwv8<5a+J4w^VjenOBj3A>4wiNL_Wg&y7uso<@ebq>+CTNLY7ePd z4hZd=Etko50^bpKG_~myEOySPmi6xJ-D#oU+=&xmvG-1#EdL^LH=9I(u-FCuQrV$I z3qa@NMls)-awl2D+@1!`rO0SP?R!ZZM!Y}q_Pvp54u+H6>C~N;X+u4Xj7HSALDT>- zp*MgFN74#63Pr+RzP>nq@#fS%IeYv5{Pg1D_1Qc7^*j5Q4y9g2=1aJ4s54@O%m0OGw*s(}n0O!x+-1e5=$*tXX4u-n}XK0$7 z@9&JJ-frdAR`kzpYsGui$n72&gKgHspF{1u8|=wsF`MJDmwoi71tL)Q54mS~B0k1^ zYMXu-^4P{t>vZ9kSb#F_lc{718;I56a_C!IlG0oN!w(;X6z3F=IQL#i%KP8`um79r zZ`RsPnY!3SFglWqgZ|fGxrv%0@Lk^N8Vo+J`_tjt<}&z_2!W6*%=toGb$+(2_fq6# zUzY=bf7krZVi(bjcTT^|W6SbGKk2mV3jajK#v*|YMSx<-3|`UF?$&1lzN z!-bYRoLjY(M`_-Kmf&)z(_4-9VgZ z=E))s32)i`7+X-Yw>}xM#u|!@fgK%x7B(t3*jF=P^~UB}ZyGWk z#b8nv+js$JMCTB;*HGt%{sHQsHJcPE>?h`hVHX6jT33v5cZ0}>;N!?1=VJpygc zmb&ST)gP_JcIH=Q*-1T? zV$)>L@!W$QZkmJ1&YtV+jq1gwv};*nN?)P;I~byBWH2mg%U**40rZ*boWr|C=>K!U z?Q4E#Povm&JkJMYasnHTA?!u;<=Mx@{wD)S#xWd@=bADMRB3QGgNmfO|6+GrYmcJ3 zmCfW8{H>|YUV(8(Q;{`j$Joz7G;soU#htmuyx0LHC{i4cBmD9~obiR4%yU=+)KmjqO${kv-PRYmPE}RgA&1M$c1G=o zW!-SM(>1}GXHTLp+_RO$mj}3fv-*V|mD{DAkHYCHFK9u*b+6qoxH#K{tlK-ZIHcMM z0*(YtSQhFmY$uMLJ9x2}h2jT&ogR+8?G_}%-rD8R*5Hu{rCq(XgyjvYSWjT$Uy?F` zDZZA3hCBO%z5cvL)uLEnb*qZ+86b+a6bdD|Ct>z z;{Se){E){QnjMl&C~GgR(Cmo#Oyn=@OCW=I4qz9^?CU3dCgierbY2&r6t}B2ykf_W z&I$tLe=ec~j$zuumZ+8vfxt~2XugkXU-uE94h zcD6I>}t`&nRQqA_4EM&Sd@TKSIX-v3|p2;YZ;=)-5(N=#e}&@aW^ZE-?F3 z_CtOGrY~$hnEz%3>Ch3~x zb%Tu|^rZuL#J+vD7%G4C%fMjH1mwu%3RV>KgBIJMi`^IUt_DlVw<@_A#))}A-9-|` z&Lyuy%9tm~orKMfV27ZWDF-PZ2KBE9A1*TH6D=yWiH zY>c&A-DYN}Bv!K)9Dt}N%xhP8&c|w|vR0!3GY*`M*6Q%1;a@W>1 zze5E{gB+U!&>++nCk<0( zC@#qNy&m+X|Dnc|-Eam9gVvk4m!kV}l$U7VYuUTpu*!bV_Mld^?P6bcW6`7*jT&if7txD?&Y*>C8S(m_v6Mlqx07@UQ z)2H+SJ0lsigQm;WWcAWX9DNVr?hPUb{B~U@w6B~So->gY_nUl44%e#CbZd)ZSF+$j z6;GK3!p)p{W*}Bv#aIOyYO9aTXKK)CWzPAS+n$U_`k;uPRq(IsV|tYwQO4I;Y~w;H zIyahUrHocJb2-eJP0+N7ag@q{4$;6oej?cM#RujDX$T4(r4B3;1pj+%a)Xc?%HO7|Kq5czMV? zo;dCm%q5EB=(YqrS|p@_j>6zhTWb!bc^cNN8uo7XmnTfGDX*J%#v*hSK5x|lsDigC%B%;r-dy= zQ!j|s$cY&eMfP?HMfP`BvGCFX`RBrqIcS+=FwTr84)U4G;^_pz#Br~!3VoY4-*WV?zed$v90SMHo;Ya2mQ-82WLpAU%Cegzs_JiS`Y&Zy^QbqViO74ErPWblTtU6LA0+t6Ahp!bkT} zjqlDp=2QPm(cNa5a}Vk_V8`Ad+W`i4t@o89Y$v?4T_J4b=Y+*Jj+1ESyT6Tw+9|IJ z%tO#}H8OWcEyfbPO(6=+vdB;mlnH)5`}G2Y5Q%GkZm{F^%ji)4#@k zg2A~q&~9AJU0B85{_d`1zLu?K(KK>`H|lt6d>lZIfx8!YT)i=dg2@CSo5Zix0zqCu z=8K@H%$Pgwl{By5@qa=tzsDCJ#u%YVLX}w!l4Q{sE$FpU9V~b1GpttCvW`X4aYTZ$ z*4cFjS6LGLr|`VV+q4D9ug(78Ps>Qcj)0<=k=slNhQkM`8@Chqgid`$5`*ujj=a?*zVqNZ#Zg+?i$OP zz}@2}Ul{NJF`qIFt4AW3Au5|YLasDO8nG0dAIFa+Ah z3^Ye@6A4p$RNx{Pg4Z_uhrj&9rq zzT1QRB6A2d$GZ#DvmD~O0KdiIbUW8P2QqeU+4w0Czz-^=R7|N?VonS?8+V?j>89eY z;$z0h;ZK4)v#j51h+xmtS9Zh-UkM)zyjZQAzX#ILPzOxDd`I@6tXm<`j)- zr{UX`J|xkl>3E(ULsYtrX|Xy8j6SSuu-^oKnFfGc*sg;KA5!&K*I;VsLy7kzbeSCP zZI9aBnR(We(ACWDNu$OM19qVKHm&QK4nnd0X8BgFp}QN^yIwI)cdg2V0~01h!XEvvy_?24WbY|*=fu6NwnDS?~{&V`Ho4V z2Fziqr$bjZWaw22zFQ71v_5Pdzyi`3n5%lvH=i(52at*%^{(S3T`>xujh!+^zHC9H zH@Yu=H}yELmnttXCC&+C4hwmhGzgguEmcC(A>Z3|y*<+$?F}Xedplme%-IC3EP^(* zMqTCsWkNmJC#Cc>l*Cgi4m#~+jza8HRVt9x!YuMKYCZVgvLK7za;(szF<|!_cb#yYA4*P@2Xt=X)n#1i8-}9!E`n}C{FK=eQaw5O0<2eMdY0VB_i>c(^@S&T%^in|XQq2NvGJqzNRa{_fk56_P)Iy8v` zxzNjBFNgt*O_-he7x1PUv(9)C`cc^7;bPV;xwHNF(c`gy!#gr0sr!jCF7Rj8I`<9hXg{}#l3b3zl@fxfbD>6-ak%7x|C0D*MmnzO-ugoSbYQ48g z$}4*O2KYoA(Bn5Y;+nZt&uNRc19F^4-F zEIkyOvLuKZzklLf^Oo&@(1%T3b(VD6`1t8jEgD2$lYg0WH|eaOoxNSJH*VIZUYRmK zc><{vDJ!N*FlE4PFRr3R;9=5MKS^^@C8&Y~shARAhMF=ZYbf?CLx4?EVo7r{xaTj09AhT?FuG+E?mD1$f5~r1UQjkk*l0=~ zoJ3$`SqhUr+>@dtD8>MBvs~>l7jvmeqBHJ*?_u*Q0d7n^a`XlvKrXIjouB@1zr8*` zy`Xe*FHbK{&R@U(aCUytX1A2~jr^t277iIwEepN3DMG@YN06%r30k|HW@jP0{^x=( zIGYDf0#-{QGp~Ye!66MV;oR9)4W*)I*s4DKj0)Au;*jHMci=(!^j zN@mF>esb#z&Mul8y=d z0kg>BO|8Jmoa-h40Rb00ltdi{cm4z-u$X&0$csDj^ zWi*a|UQKPl^(=%Lgw z?M){8eLkF;=Fs&H_68HDUc)3imUT<=1*IM#rPB6p-ts~h3~|VZkZx5bXO-Dxn8VyS z5@Hk8;_NDlu1$8%H)XnIs&67g&3hr>z~$&-{sOvdlq@QuF4e&J5fqObO(gYf@x|N&lhtzG?oR> z>@-JvE+xw}WLFN(pOo^bX`MQLu!wnw$FZd>3TUV^7_PL%P%gnF|CWUbjj}M~G}JqY zE-m(y_9NAlz5%nwWwX-b3y1xvcJ+YsozlO9GLg1f1hv$d6*~0=yu?XIGp_$0h5rj1BrPI?Dzv#=d!l00l{MyDG+Y8u~B~G8j zAWO#ZpkgJJ)>2zEc(7!CJ#Bu=C0Me3r}L@bR$tgRew-|vfMWIyCN-rSA5*pGCxekP zRDZU@a!P5{cG2sgQ^F*m$Q6^r5tLb4dx_2qka*>;Fb<*yZg_DF9n@lXyU}2aCEPPz;2uv>uaFXE6O+yxl1Pz8_OaSF^42VH=I&9 zHh@Ea`&^*_krt$Z;y{TXW|~z&-#02j6N_p3d0`Z8mOfEi)DP*1Bu~a1s4()o(vz8~ z;#N~Xkt$pFntP-pVB|$hu+X*(Eq-}>o>s+z>OY>Wsr3Oij)!hUB@hG)qFd16{(2z` zXW-WoFhKt>QLd(G=F8&{a3C!!B4~~<9S}@qfJGE%=%H-Rg?SM)m>i&|v_)fytJ{dp zuR!Kh^&?JC-X6;`V{%yNA}f+XdZbINlz;$Lp#}~$=_Y&%^~ap>PCbvNC|1Y~aqrxK zGY)b1h`*N++RBqi<^sj2fiQt$CY0lGoRudcZil`evnZ&+*ce^F#yT<)yc;L>(HYxd zV@LwJm_s!ba_k1IIFLF@;6PYEs@WRK|8JQ7HUcppkX4eeLp2a}hc{998{#;YU+pzd zLm}r=IiatTR%^3qn#`espN+1cFDd}5w_r^2aQN*V1sj}~=&{kJ{cy$hquTbLD!xD` z1CW?F^*vH#0X>iOUPyc7vyptZ+9o2Y-_-kq3=jpNtiSB6&lD|PPhku|5zx_~o3lmG z85(Sa8DaG4$@^IQuKatZKG8}iXo7MDseHQTrsv;4{HxwmEyVVBnKV2ZdWD2EiRPOD)GJ}mt>Y)MFwq#hW%xgqjnjHg&Rw*C z6v_Zl-KId3fud5?+l2t)1oUf+kjIij<9$Nck(rBX0G^x}OS;%70vBxydyZ3ns?_X+d-PnI)fO6Pf!OM`M@)drf)FNtiOwz*asb zrOR2i1Ah{L46Ye|u20{h5}<{4|E6$zUqnsf77!C91SNk?qMtLLosluz0Xe8|jE049tOsI!rE#`aStu3Ta9?Fy%Mp<4hLR09oh6kH zDn*thePoWGFbXs6#a%u>|I*qjT8{p9g>Wzp{AZz5FRl~FjQxLcVq{Wc4nbvLhxC4L z2UFtz&zAL)yRv{6#LLOl&l?}*o3?XgS(Ouu$y3vQMe@2~pjE4Nv8>lA#aLy=sT%u7 zjH?uhnPM0coYf%Ruh<@&x_eUPnUdtoed*JcxwK|%;2OZ1aV-~JW;hTno2n7dIZf*%yNR3TNiwIHxmc^dj zA-^t_HA{gh8A@tq&_TlozD%fU+)^Wjy0Im|P)0CG_atYCjv64DT*XlsEu`mqdLV9>kRH4vfLx!5_o;(hACoWjQ;6Wu1|V|F5*J?{QfTrmD6rTcZ2?b%>Ez zO{2XIwZSe>-L3{RDuTMcR^|uJj_$?=NMaznl|>p{X+xJ0Yco}qJHrhPbWp8BZ#C3? z;1VoPPJCZgq-0GkOe%58T%wdNd9xth7oyBY}ONya4P7Ch0O&bWg6?3=|EmFO;=mRcTKBP6m zyk07a&*o#8^-Oou(6H%ymew;<8YOu*0_ll!dZlvhvzJj)MJiNQo=iVg!OzHuyLCC- zI&Na6f4jPStlT2>R_Dfw+*c(yomy>eRVwaL*ZnEq?!=ixHEb5}P%%2Q=muo5LlFr+?`YO({SthT%a}VEK7&4WfLe|IOOJ#{0C5o(1E3THG4i zekn$ADG`;7BEWtZd7M~YV3Td+d%>lvlRIr~D07iB%OBroM{M|S(fd4VBkF)R0`2~> z98@m&?SI=Vx)HL3P-5a zZwKO_Zm(1dz|`Zc1P_CzG}V!3vSV_DkzO!zzM#2EzXT^5aOZ}X0Xpm|BF`ikIOlj( z6>cWk!R0nuDKb8<3Q=fbuWcHfNNttj7MuyP>K+Brz6cdVtr9+iZ`Z`V+Wg!y-Fm`j zrWAHfj}j&KYUI`zmh~c2rFVR9Sw1>_b<=A0ZHxt}^sP^C30;tPbRoq^i2yX}gmW80 zGp_a(@I4bv14e!UvF!b7u`{UTY91Ks&A;`9zzEsE11`}MEE9q% z#DvWi&|vd>p+Hew*nG(DSBVUpe+(Y1)}skqmSRZR!$Tvb)m9cTHrH08RpMb`or!M;jXy@MJ zlf@-QUdPD~om79LbICQVweDb%+VIb=vA`?MXqBivREmIeKi2QcLh)qC*&FBgI~DtX zeDQ(AJ^sZF7LXcO#!1~U@+El!v2yPSxyQyA zFyQGI(hFe_xDznf5!}pW3ZMw+k|VvvHqxL0j0Ax2Yqjd&<*)Vxt{$jEl9E;$QqcW# zDrVU(Y;3R}98vIpGN*xaS-?8Xf9v?6=*TEsitqJkfLGALvVJ+fu-_d2=ilwqzr8;@ z|Il6Qr8|bHBW37ZT}WUWP>Q-V8MJspjy|UsZ{=6KisD~pv1MV^EdO^tW`yJ_g_FVx z4A5Ka(PB3E!az}{qDzc+EuDjdOkuI{G$gYGifBpUr-PLU*arGBq0Xqt@=#u~Tw%d` zEdW8^te60wlFg(u@xw0pQXy4a89XGV@?e zS5XXkp+omIBw-JPAj<8GU#>y8cvJA9{gnEtW>mWJpr13)>Mu~6WF zkp}0d>;LtIp?FM#of;@n8SH0+or7xdf+F%E5Wga&O2EJH7>M|1kdD4UrX@xV#bOQ( zYTW*6UmUJ&F7I7%8f@F{aINwG*mYtrSHTsFu#T$%27XyXHQ~-JrS|{yd(2<8N&hV?e~rC9hG2b zWk7|HqBgNLNarbn=qek+ePy)?EVr%42x4d;JHn?XaXV7^SrJ4f*{#z!hJ-s^c2vz)x5J>0 zYY-D@Xj3vMFP$uK4l#P=A*y{$^Al@3hiX>1&P$!9Sp81>hUy0NVGTtsux3I1>k_6_ zvFUX#L-KBW4@{vd%Oh7yTKil14i_?R;vsPSP_8oiiIn%N$sL^Dk-?!?-I8*Al)S{0 z&Ga_fBn#~6#ao#PB3-DoE+tYOnX*LLPcNeqFii4bV%aw2up?L1vtUtJ&b`XVET7BlX}S)J*8M`KW%3xt1v@Vn3dFrRlF-N z*>Z%_jD|8kdYAG59t@4aBlwhM|KvsPharz!=;F{%t72)5rS6oCIxQ5-t(Bs*BrXG= zl|*wJvo+Y5Qvr&k+(xmd(U!KF+n+7#RVYRN*WzcTZIM@8i|Dvk@l8ucW8VsIjv=_K z#o$Xkty<6R0X|&c(fzg#+P%?Qj0LhW;}>_cNfZbv;Vl(kYdT4>b(;?dp119qrn5I4 z4EF|u)?#ZN;HBbfT}LDj2INjKfHJJu_t5!JFoy{%lEQaze;bki2*6P+kCO#Gk{w^us z_BPZ#>*3G6LV%o@(K261X5R}9?`DRm@FDuR{JO|_+A^TSc;X~YGl_RZ(_+Hdh zU@uq{az)T-vBp$yG1V(V`YtwhWl~?&=n$h_H_>SiijtXmxT)m0@l^IGSvoe#>#nuv zW=g!8B?hgYM4YttWK9X`j6!|;rh%LJp+CLTe7U6ZSEGXMwy&3$hFWi7iEys4ja6PX z-)k#Nu&cMTS1C#sw=~zPo3pp%%^g$$1*=*rvlVhlQ346C@%*L=5b*sx=hNqydkW~n zsE-`cXwU}*&cnz8O6R8BKRb?Yg;t+lyLdKS6VoY6rb>P%ecw;Z@%E@S-s-5ewZ%@M zjIqaWHf1%LvK@$+NK7jg-Ga8+O``bDWbd4rA718wQPl^khN*mH@q3;KCa%ygIF2F^ zp{~*Ok1ayV>+Z>MpNJeh`bI5coO0F+e}d&asE=S*Xte-@oIr*^j8fMS4rgG79Af9? z39ysMrafUtg`-!n)sS+k@NnkLJKu6g_*)g5QzL2U{p$25Pv0|G0a|c$UbMilGV?;!H5hX|$lkjx%#j*Q%XR`f1Dh)wyv5rU&hO7HCr< zT#)&xRXvzptfjfLzn@i8(CmltBD5v)$fFL4ygTU!ymdUjxtLSh26h<{;$!+Zpn*>W zlhrt-qEOadz~al0k21hC3<{bo(hLQQqfqHl6-PnSfZSR5OS(CruZ4qUu#JVR$f2Pa z+n@=UIDzgTNKAeUC%7e`x0-{5=gC!>@F0R*tg=vuq#;z-0|<*e(ZbAu`wtSUNDoHj zD3*0W$i7UuIo0K$D2_&HD(Ww%tsy*9<1;Pm*&03z*_01P8GV{8nRHjQ#T4%b@8>nMm4dxgoaA{ zBbn9>)u})rvbxuB3)5W-3teSvK+dRR8;rgQE4d)et0{Pn>xWpqsZ=~3^w@ zZilkV2vVY{CzKk6(jTfGthTci)q{;q4 z8>?PkK(6-OYrSvmUxHV`31WQB%Qt>ln#m21W8WiQ469N>gJqiq!t8rY$Zsa1dhK#e z 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 b5M_IsuT&pt)rXm(d${)>U^>#6tbGLlF3m;V literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py new file mode 100644 index 00000000000..448cc39d739 --- /dev/null +++ b/.github/native-bun-validation/prepare.py @@ -0,0 +1,103 @@ +import argparse +import gzip +import hashlib +import io +import json +from pathlib import Path, PurePosixPath +import re +import subprocess +import tarfile + + +BASE = "dca7d25e95cca39316c659a377dba6803805549f" +PATCH_HASH = "fb44303ad3c22ae5652bfe32fe3e6e32c1aeb24dc5594b3a1a631ab0e945406a" +ADDITIONAL = { + "src/bundler/input_source_map.rs", + "src/runtime/bake/dev_server/plugin_watch_store.rs", + "src/sourcemap/InputSourceMap.rs", + "test/bake/dev/barrel-hmr-renaming.test.ts", + "test/bake/dev/barrel-hmr.test.ts", + "test/bake/dev/client-plugin-cache.test.ts", +} + + +def digest(data): + return hashlib.sha256(data).hexdigest() + + +def allowed(name): + path = PurePosixPath(name) + return ( + not path.is_absolute() + and ".." not in path.parts + and "\\" not in name + and ( + name.startswith(("src/", "test/", "docs/")) + or name in {"Cargo.lock", "packages/bun-types/bun.d.ts"} + ) + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--bun", type=Path) + parser.add_argument("--out", type=Path) + parser.add_argument("--check-assets-only", action="store_true") + args = parser.parse_args() + data = Path(__file__).resolve().parent + manifest = json.loads((data / "native-v9-manifest.json").read_text()) + assert manifest["head"] == BASE + assert manifest["trackedPatchSha256"] == PATCH_HASH + assert set(manifest["additionalFiles"]) == ADDITIONAL + patch = gzip.decompress((data / "native-v9-tracked.patch.gz").read_bytes()) + assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" + paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) + assert paths, "No tracked patch paths" + tracked = [] + for old, new in paths: + assert old == new and allowed(old.decode()), "Unexpected tracked path" + tracked.append(old.decode()) + extra = {} + archive = gzip.decompress( + (data / "native-v9-additional-files.tar.gz").read_bytes() + ) + with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: + for member in bundle.getmembers(): + assert member.isfile(), "Non-regular archive entry" + assert member.name in ADDITIONAL and allowed(member.name) + assert member.name not in extra, "Duplicate archive entry" + content = bundle.extractfile(member).read() + assert digest(content) == manifest["additionalFiles"][member.name] + extra[member.name] = content + assert set(extra) == ADDITIONAL + print(json.dumps({"base": BASE, "patchSha256": PATCH_HASH, + "trackedPaths": tracked, "additionalFiles": manifest["additionalFiles"]}, indent=2)) + if args.check_assets_only: + return + assert args.bun and args.out, "--bun and --out are required" + bun = args.bun.resolve() + out = args.out.resolve() + actual = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=bun, text=True).strip() + assert actual == BASE, "Unexpected Bun checkout" + assert not subprocess.check_output(["git", "status", "--porcelain"], cwd=bun), "Bun checkout is dirty" + for name in extra: + assert not (bun / name).exists(), "Additional file already exists" + subprocess.run(["git", "apply", "--check", "-"], input=patch, cwd=bun, check=True) + subprocess.run(["git", "apply", "-"], input=patch, cwd=bun, check=True) + for name, content in extra.items(): + target = bun / name + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(content) + subprocess.run(["git", "diff", "--check"], cwd=bun, check=True) + out.mkdir(parents=True, exist_ok=True) + with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: + for name in sorted(set(tracked) | ADDITIONAL): + bundle.add(bun / name, arcname=name) + (out / "native-v9-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") + (out / "tracked.patch").write_bytes(patch) + for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: + (out / name).write_bytes((bun / name).read_bytes()) + + +if __name__ == "__main__": + main() diff --git a/.github/native-bun-validation/require-tests-reporter.mjs b/.github/native-bun-validation/require-tests-reporter.mjs new file mode 100644 index 00000000000..bb1972b99d2 --- /dev/null +++ b/.github/native-bun-validation/require-tests-reporter.mjs @@ -0,0 +1,29 @@ +import { writeFileSync } from 'node:fs' + +export default class RequireTestsReporter { + tests = [] + + onTestEnd(test, result) { + this.tests.push({ + title: test.titlePath().join(' > '), + status: result.status, + errors: result.errors, + }) + } + + onEnd(result) { + const passed = + this.tests.length > 0 && + this.tests.every((test) => test.status === 'passed') + writeFileSync( + process.env.NATIVE_REPORT, + JSON.stringify({ result, tests: this.tests }, null, 2) + '\n', + ) + if (!passed) { + console.error( + 'Native validation requires every selected test to execute and pass; skips fail validation.', + ) + return { status: 'failed' } + } + } +} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml new file mode 100644 index 00000000000..9683380d056 --- /dev/null +++ b/.github/workflows/bun-native-validation.yml @@ -0,0 +1,175 @@ +name: Temporary native Bun validation + +on: + workflow_dispatch: + inputs: + router_ref: + description: 'Exact Router commit; empty uses this workflow commit' + type: string + default: '' + binary_run: + description: 'Existing successful native build run ID; empty builds Bun' + type: string + default: '' + +permissions: + contents: read + actions: read + +env: + CI: '1' + NX_DAEMON: 'false' + NX_NO_CLOUD: 'true' + +jobs: + native: + if: github.repository == 'RentnerKev/router' && inputs.binary_run == '' + runs-on: macos-15-intel + defaults: + run: + shell: bash + steps: + - name: Checkout validation harness + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Checkout immutable Bun base + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/bun + ref: dca7d25e95cca39316c659a377dba6803805549f + path: .native-bun + persist-credentials: false + - name: Setup bootstrap Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: '1.4.4' + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '26.10.0' + package-manager-cache: false + - name: Build native assertion binary and execute all nine suites + id: native_tests + run: bash .github/native-bun-validation/build-macos.sh + - name: Collect binary and final machine state + if: always() + run: | + mkdir -p .native-proof/binary + df -h > .native-proof/final-disk.log + if [[ -f .native-bun/build/release-assert/bun-assertions ]]; then + cp .native-bun/build/release-assert/bun-assertions .native-proof/binary/bun + python3 - <<'PY' + import hashlib, json, os, subprocess + from pathlib import Path + binary = Path('.native-proof/binary/bun') + manifest = json.loads(Path('.github/native-bun-validation/native-v9-manifest.json').read_text()) + proof = { + 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), + 'base': manifest['head'], + 'patchSha256': manifest['trackedPatchSha256'], + 'additionalFiles': manifest['additionalFiles'], + 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), + 'workflowRun': os.environ['GITHUB_RUN_ID'], + 'workflowCommit': os.environ['GITHUB_SHA'], + } + Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') + PY + fi + - name: Upload native binary, source, toolchain and test proof + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: native-macos-intel-bun + path: .native-proof/ + include-hidden-files: true + if-no-files-found: error + retention-days: 14 + + browser: + if: always() && !cancelled() && github.repository == 'RentnerKev/router' && (inputs.binary_run != '' || needs.native.result != 'skipped') + needs: native + runs-on: macos-15-intel + defaults: + run: + shell: bash + steps: + - name: Checkout exact Router commit + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ inputs.router_ref || github.sha }} + persist-credentials: false + - name: Require immutable Router ref + env: + ROUTER_REF: ${{ inputs.router_ref || github.sha }} + run: | + [[ "$ROUTER_REF" =~ ^[0-9a-f]{40}$ ]] + [[ "$(git rev-parse HEAD)" == "$ROUTER_REF" ]] + - name: Download native binary and proof + env: + GH_TOKEN: ${{ github.token }} + BINARY_RUN: ${{ inputs.binary_run || github.run_id }} + run: | + [[ "$BINARY_RUN" =~ ^[0-9]+$ ]] + gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-intel-bun --dir .native-artifact + - name: Setup pnpm + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '26.10.0' + package-manager-cache: false + - name: Install Router dependencies + run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' + - name: Checkout actual unplugin PR source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/unplugin + ref: 4d01143e6f60a6a93ed40411629ea4da14f540a7 + path: .native-unplugin + persist-credentials: false + - name: Build actual unplugin PR distribution + run: | + pnpm dlx pnpm@12.14.0 --dir .native-unplugin install --frozen-lockfile + pnpm dlx pnpm@12.14.0 --dir .native-unplugin build + test -f .native-unplugin/dist/index.mjs + - name: Prepare isolated native Bun wrapper and unplugin preload + run: node .github/native-bun-validation/browser-setup.mjs + - name: Install Chromium + run: pnpm exec playwright install chromium --only-shell + - name: Production builds, navigation and source maps + id: production + continue-on-error: true + env: + NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/production-results.json + run: | + set -o pipefail + pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/production.log + - name: Native development navigation, HMR, recovery and source maps + id: development + if: ${{ !cancelled() && steps.production.outcome != 'skipped' }} + continue-on-error: true + env: + NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/development-results.json + run: | + set -o pipefail + pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun:dev --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/development.log + - name: Upload all browser results + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: native-macos-intel-router-browser + path: | + .native-browser-proof/ + e2e/react-router/bun-basic-file-based/test-results/ + e2e/react-router/bun-basic-file-based/.cache/ + include-hidden-files: true + if-no-files-found: warn + retention-days: 14 + - name: Require both browser suites to pass + if: always() + env: + PRODUCTION: ${{ steps.production.outcome }} + DEVELOPMENT: ${{ steps.development.outcome }} + run: | + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success ]] From 21ed31bbb26dc804305fc899e0c30fdc713260d5 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 11:07:17 +0200 Subject: [PATCH 05/31] ci: use native arm64 macOS toolchain for Bun validation --- .github/native-bun-validation/build-macos.sh | 9 ++++++--- .github/workflows/bun-native-validation.yml | 14 +++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh index a8e3a560c80..74c0a431632 100644 --- a/.github/native-bun-validation/build-macos.sh +++ b/.github/native-bun-validation/build-macos.sh @@ -22,9 +22,12 @@ python3 "$repo/.github/native-bun-validation/prepare.py" \ --bun "$repo/.native-bun" --out "$proof" | tee "$proof/source-verification.json" # CONTRIBUTING.md's macOS prerequisites, plus its required LLVM major. -brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm@23 -export PATH="$(brew --prefix llvm@23)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" +brew update +brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm +export PATH="$(brew --prefix llvm)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" export RUSTUP_TOOLCHAIN=nightly-2026-09-15 +export CARGO_BUILD_JOBS=1 +export CARGO_INCREMENTAL=0 if ! command -v rustup >/dev/null; then rustup-init -y --no-modify-path --profile minimal --default-toolchain none fi @@ -51,4 +54,4 @@ bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" # Use the official build-and-execute path. No timeout wraps compilation. read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v9-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" [[ "${#native_tests[@]}" -eq 9 ]] -bun run build:assert -j2 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" +bun run build:assert -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 9683380d056..fa751320cc3 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: router_ref: - description: 'Exact Router commit; empty uses this workflow commit' + description: 'Exact Router commit for browser tests; empty builds Bun only' type: string default: '' binary_run: @@ -24,7 +24,7 @@ env: jobs: native: if: github.repository == 'RentnerKev/router' && inputs.binary_run == '' - runs-on: macos-15-intel + runs-on: macos-15 defaults: run: shell: bash @@ -80,16 +80,16 @@ jobs: if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: native-macos-intel-bun + name: native-macos-arm64-bun path: .native-proof/ include-hidden-files: true if-no-files-found: error retention-days: 14 browser: - if: always() && !cancelled() && github.repository == 'RentnerKev/router' && (inputs.binary_run != '' || needs.native.result != 'skipped') + if: always() && !cancelled() && github.repository == 'RentnerKev/router' && inputs.router_ref != '' && (inputs.binary_run != '' || needs.native.result == 'success') needs: native - runs-on: macos-15-intel + runs-on: macos-15 defaults: run: shell: bash @@ -111,7 +111,7 @@ jobs: BINARY_RUN: ${{ inputs.binary_run || github.run_id }} run: | [[ "$BINARY_RUN" =~ ^[0-9]+$ ]] - gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-intel-bun --dir .native-artifact + gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact - name: Setup pnpm uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - name: Setup Node @@ -158,7 +158,7 @@ jobs: if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: native-macos-intel-router-browser + name: native-macos-arm64-router-browser path: | .native-browser-proof/ e2e/react-router/bun-basic-file-based/test-results/ From 1a8a9bf98dea92e3ff3da7ae75deefde86cd08fa Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 11:12:07 +0200 Subject: [PATCH 06/31] ci: use supported native macOS release profile --- .github/native-bun-validation/build-macos.sh | 2 +- .github/workflows/bun-native-validation.yml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh index 74c0a431632..82f6d9a23cb 100644 --- a/.github/native-bun-validation/build-macos.sh +++ b/.github/native-bun-validation/build-macos.sh @@ -54,4 +54,4 @@ bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" # Use the official build-and-execute path. No timeout wraps compilation. read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v9-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" [[ "${#native_tests[@]}" -eq 9 ]] -bun run build:assert -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" +bun run build:release --lto=off --build-dir=build/native-release -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index fa751320cc3..67b898d4c79 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -49,7 +49,7 @@ jobs: with: node-version: '26.10.0' package-manager-cache: false - - name: Build native assertion binary and execute all nine suites + - name: Build native release binary and execute all nine suites id: native_tests run: bash .github/native-bun-validation/build-macos.sh - name: Collect binary and final machine state @@ -57,8 +57,8 @@ jobs: run: | mkdir -p .native-proof/binary df -h > .native-proof/final-disk.log - if [[ -f .native-bun/build/release-assert/bun-assertions ]]; then - cp .native-bun/build/release-assert/bun-assertions .native-proof/binary/bun + if [[ -f .native-bun/build/native-release/bun-profile ]]; then + cp .native-bun/build/native-release/bun-profile .native-proof/binary/bun python3 - <<'PY' import hashlib, json, os, subprocess from pathlib import Path @@ -72,6 +72,7 @@ jobs: 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), 'workflowRun': os.environ['GITHUB_RUN_ID'], 'workflowCommit': os.environ['GITHUB_SHA'], + 'buildProfile': 'release --lto=off', } Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') PY From efb0b763278c485d1a3b5d107cf628d9045742a3 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 11:21:17 +0200 Subject: [PATCH 07/31] fix(router-plugin): watch imported virtual route configuration modules --- .changeset/fruity-pears-see.md | 4 +- .github/workflows/bun.yml | 6 +- .../bun-basic-file-based}/build.mjs | 2 +- .../bun-basic-file-based}/bun.spec.ts | 3 +- .../bun-basic-file-based}/dev-fixture.ts | 25 ++- .../dev-playwright.config.ts | 2 +- .../bun-basic-file-based}/dev.test.ts | 108 ++++++---- .../bun-basic-file-based}/fixture/main.tsx | 0 .../fixture/routes/__root.tsx | 0 .../fixture/routes/about.tsx | 0 .../fixture/routes/details.lazy.tsx | 0 .../fixture/routes/details.tsx | 0 .../fixture/routes/index.tsx | 0 .../bun-basic-file-based/package.json | 50 +++++ .../playwright.config.ts | 0 .../bun-basic-file-based}/run-dev.mjs | 9 +- .../bun-basic-file-based}/source-maps.mjs | 2 +- .../src/filesystem/physical/getRouteNodes.ts | 29 ++- .../src/filesystem/virtual/getRouteNodes.ts | 66 ++++-- .../src/filesystem/virtual/loadConfigFile.ts | 17 +- packages/router-generator/src/generator.ts | 38 ++-- packages/router-generator/src/types.ts | 1 + .../router-generator/tests/generator.test.ts | 16 +- .../tests/virtual-config.test.ts | 196 +++++++++++++++++- packages/router-plugin/package.json | 40 ---- .../src/core/router-generator-plugin.ts | 8 +- pnpm-lock.yaml | 25 +++ 27 files changed, 481 insertions(+), 166 deletions(-) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/build.mjs (99%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/bun.spec.ts (98%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/dev-fixture.ts (93%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/dev-playwright.config.ts (86%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/dev.test.ts (87%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/main.tsx (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/routes/__root.tsx (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/routes/about.tsx (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/routes/details.lazy.tsx (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/routes/details.tsx (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/fixture/routes/index.tsx (100%) create mode 100644 e2e/react-router/bun-basic-file-based/package.json rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/playwright.config.ts (100%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/run-dev.mjs (87%) rename {packages/router-plugin/e2e/bun => e2e/react-router/bun-basic-file-based}/source-maps.mjs (98%) diff --git a/.changeset/fruity-pears-see.md b/.changeset/fruity-pears-see.md index 3ca2c74552f..c4a30b0a177 100644 --- a/.changeset/fruity-pears-see.md +++ b/.changeset/fruity-pears-see.md @@ -3,6 +3,6 @@ '@tanstack/router-generator': minor --- -Add a native Bun plugin with file-based route generation and automatic code splitting, including shared route modules. Reuse Router HMR and expose resolved generator directory roots for native development-server watches. +Add a native Bun plugin with file-based route generation and automatic code splitting, including shared route modules. Reuse Router HMR and expose resolved generator watch dependencies for native development-server watches. -Reload edited virtual route configurations when regenerating the route tree. +Reload edited virtual route configurations and their TypeScript imports when regenerating the route tree. diff --git a/.github/workflows/bun.yml b/.github/workflows/bun.yml index 171cf46e56d..661c00382d0 100644 --- a/.github/workflows/bun.yml +++ b/.github/workflows/bun.yml @@ -4,6 +4,8 @@ on: pull_request: paths: - 'packages/router-plugin/**' + - 'e2e/react-router/bun-basic-file-based/**' + - 'e2e/e2e-utils/**' - 'packages/router-generator/**' - 'packages/router-utils/**' - 'packages/virtual-file-routes/**' @@ -60,7 +62,7 @@ jobs: pnpm install --frozen-lockfile --filter . --filter "@tanstack/router-plugin..." - --filter "@tanstack/react-router..." + --filter "tanstack-router-e2e-react-bun-basic-file-based..." - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: @@ -72,4 +74,4 @@ jobs: if: runner.os != 'Linux' run: pnpm exec playwright install chromium --only-shell - name: Test production builds and navigation - run: pnpm nx run @tanstack/router-plugin:test:e2e:bun --outputStyle=stream --skipRemoteCache + run: pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun --outputStyle=stream --skipRemoteCache diff --git a/packages/router-plugin/e2e/bun/build.mjs b/e2e/react-router/bun-basic-file-based/build.mjs similarity index 99% rename from packages/router-plugin/e2e/bun/build.mjs rename to e2e/react-router/bun-basic-file-based/build.mjs index 292e30a387d..d13d87ef461 100644 --- a/packages/router-plugin/e2e/bun/build.mjs +++ b/e2e/react-router/bun-basic-file-based/build.mjs @@ -7,7 +7,7 @@ import tanstackRouter, { import { verifyBunRouteSourceMaps } from './source-maps.mjs' const here = path.dirname(fileURLToPath(import.meta.url)) -const workspace = path.resolve(here, '../../.cache/bun-e2e') +const workspace = path.resolve(here, './.cache/bun-e2e') const fixture = path.join(workspace, 'fixture') const generatedRouteTree = path.join(fixture, 'routeTree.gen.ts') diff --git a/packages/router-plugin/e2e/bun/bun.spec.ts b/e2e/react-router/bun-basic-file-based/bun.spec.ts similarity index 98% rename from packages/router-plugin/e2e/bun/bun.spec.ts rename to e2e/react-router/bun-basic-file-based/bun.spec.ts index 6a5351c288e..717bb9c0e65 100644 --- a/packages/router-plugin/e2e/bun/bun.spec.ts +++ b/e2e/react-router/bun-basic-file-based/bun.spec.ts @@ -1,4 +1,5 @@ -import { expect, test } from '@playwright/test' +import { expect } from '@playwright/test' +import { test } from '@tanstack/router-e2e-utils' import { SourceMap } from 'node:module' import type { SourceMapPayload } from 'node:module' diff --git a/packages/router-plugin/e2e/bun/dev-fixture.ts b/e2e/react-router/bun-basic-file-based/dev-fixture.ts similarity index 93% rename from packages/router-plugin/e2e/bun/dev-fixture.ts rename to e2e/react-router/bun-basic-file-based/dev-fixture.ts index 79968b18c66..deac5ae4558 100644 --- a/packages/router-plugin/e2e/bun/dev-fixture.ts +++ b/e2e/react-router/bun-basic-file-based/dev-fixture.ts @@ -11,7 +11,7 @@ import { } from 'node:fs/promises' import path from 'node:path' import { tmpdir } from 'node:os' -import { pathToFileURL } from 'node:url' +import { fileURLToPath, pathToFileURL } from 'node:url' import { createHash } from 'node:crypto' export function aboutSource( @@ -55,11 +55,13 @@ export async function startDevFixture({ generatedExtension = 'ts', virtualMount = false, virtualConfigFile = false, + virtualConfigHelperDepth = 0, autoCodeSplitting = true, }: { generatedExtension?: string virtualMount?: boolean virtualConfigFile?: boolean + virtualConfigHelperDepth?: 0 | 1 | 2 autoCodeSplitting?: boolean } = {}) { const executable = process.env.BUN_EXECUTABLE @@ -73,6 +75,9 @@ export async function startDevFixture({ const requireReact = createRequire( path.join(repo, 'packages/react-router/package.json'), ) + const requireProject = createRequire( + fileURLToPath(new URL('./package.json', import.meta.url)), + ) const directory = await mkdtemp(path.join(tmpdir(), 'router-bun-native-dev-')) const inlineMaps: Array = [] let logs = '' @@ -111,7 +116,18 @@ export async function startDevFixture({ await save('routes/index.tsx', nestedSource('/', 'HOME_NATIVE_DEV')) await save('routes/about.tsx', aboutSource()) if (virtualConfigFile) { - await save('virtual-routes.ts', virtualConfigSource('before')) + for (let index = 0; index < virtualConfigHelperDepth; index++) { + await save( + index ? `config/helper${index}.ts` : 'virtual-routes.ts', + `export { routes } from '${index ? './' : './config/'}helper${index + 1}.ts'\n`, + ) + } + await save( + virtualConfigHelperDepth + ? `config/helper${virtualConfigHelperDepth}.ts` + : 'virtual-routes.ts', + virtualConfigSource('before'), + ) await save( 'virtual-pages/before.tsx', nestedSource('/virtual-before', 'VIRTUAL_BEFORE'), @@ -253,7 +269,7 @@ export default { name: 'observe-public-router-dev', setup(build) { reactRouter: await versionOf('@tanstack/react-router', requireReact), react: await versionOf('react', requireReact), unplugin: await versionOf('unplugin', requirePlugin), - playwright: await versionOf('@playwright/test', requirePlugin), + playwright: await versionOf('@playwright/test', requireProject), preload: preloadArg ?? null, preloadSha256: preloadArg ? createHash('sha256') @@ -270,6 +286,9 @@ export default { name: 'observe-public-router-dev', setup(build) { directory, versions, inlineMaps, + virtualConfigPath: virtualConfigHelperDepth + ? `config/helper${virtualConfigHelperDepth}.ts` + : 'virtual-routes.ts', logs: () => logs, save, tree: () => readFile(file(`routeTree.gen.${generatedExtension}`), 'utf8'), diff --git a/packages/router-plugin/e2e/bun/dev-playwright.config.ts b/e2e/react-router/bun-basic-file-based/dev-playwright.config.ts similarity index 86% rename from packages/router-plugin/e2e/bun/dev-playwright.config.ts rename to e2e/react-router/bun-basic-file-based/dev-playwright.config.ts index e814a7ed487..8680b8bf65d 100644 --- a/packages/router-plugin/e2e/bun/dev-playwright.config.ts +++ b/e2e/react-router/bun-basic-file-based/dev-playwright.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ timeout: 90_000, expect: { timeout: 15_000 }, reporter: [['line']], - outputDir: process.env.BUN_DEV_TEST_OUTPUT ?? '../../.cache/bun-dev-results', + outputDir: process.env.BUN_DEV_TEST_OUTPUT ?? './.cache/bun-dev-results', use: { ...devices['Desktop Chrome'], trace: 'retain-on-failure', diff --git a/packages/router-plugin/e2e/bun/dev.test.ts b/e2e/react-router/bun-basic-file-based/dev.test.ts similarity index 87% rename from packages/router-plugin/e2e/bun/dev.test.ts rename to e2e/react-router/bun-basic-file-based/dev.test.ts index 416cf58b38e..2f2114a328e 100644 --- a/packages/router-plugin/e2e/bun/dev.test.ts +++ b/e2e/react-router/bun-basic-file-based/dev.test.ts @@ -1,4 +1,5 @@ -import { expect, test as base } from '@playwright/test' +import { expect } from '@playwright/test' +import { test as base } from '@tanstack/router-e2e-utils' import { SourceMap } from 'node:module' import type { SourceMapPayload } from 'node:module' import type { CDPSession, Page } from '@playwright/test' @@ -14,14 +15,22 @@ const test = base.extend<{ generatedExtension: string virtualMount: boolean virtualConfigFile: boolean + virtualConfigHelperDepth: 0 | 1 | 2 autoCodeSplitting: boolean }>({ generatedExtension: ['ts', { option: true }], virtualMount: [false, { option: true }], virtualConfigFile: [false, { option: true }], + virtualConfigHelperDepth: [0, { option: true }], autoCodeSplitting: [true, { option: true }], native: async ( - { generatedExtension, virtualMount, virtualConfigFile, autoCodeSplitting }, + { + generatedExtension, + virtualMount, + virtualConfigFile, + virtualConfigHelperDepth, + autoCodeSplitting, + }, use, testInfo, ) => { @@ -29,6 +38,7 @@ const test = base.extend<{ generatedExtension, virtualMount, virtualConfigFile, + virtualConfigHelperDepth, autoCodeSplitting, }) try { @@ -441,7 +451,9 @@ test('repairs a route generation conflict without restarting the server', async page, request, native, + whitelistErrors, }, testInfo) => { + whitelistErrors.push(/conflicting configuration paths/i) await page.goto(native.url) await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') const token = await documentToken(page) @@ -482,7 +494,11 @@ test('repairs a syntax error in an active route without restarting the server', page, request, native, + whitelistErrors, }, testInfo) => { + whitelistErrors.push( + /Unexpected.*;|Expected (?:expression|identifier)|SyntaxError|SYNTAX_BROKEN/, + ) await page.goto(native.url) await page.getByRole('link', { name: 'About', exact: true }).click() await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') @@ -524,49 +540,53 @@ test('repairs a syntax error in an active route without restarting the server', }) }) -test.describe('string virtual configuration outside routesDirectory', () => { - test.use({ virtualConfigFile: true }) - test('updates existing browser navigation after an in-place config edit', async ({ - page, - request, - native, - }, testInfo) => { - await page.goto(native.url) - await page - .getByRole('link', { name: 'Virtual before', exact: true }) - .click() - await expect(page.getByRole('heading')).toHaveText('VIRTUAL_BEFORE') - await page.getByRole('link', { name: 'Home', exact: true }).click() - await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') - const token = await documentToken(page) +for (const virtualConfigHelperDepth of [0, 1, 2] as const) { + test.describe(`string virtual configuration with ${virtualConfigHelperDepth} helper imports`, () => { + test.use({ virtualConfigFile: true, virtualConfigHelperDepth }) + test('updates existing browser navigation after an in-place config edit', async ({ + page, + request, + native, + }, testInfo) => { + await page.goto(native.url) + await page + .getByRole('link', { name: 'Virtual before', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('VIRTUAL_BEFORE') + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const token = await documentToken(page) - await native.save('virtual-routes.ts', virtualConfigSource('after')) - await expect - .poll(async () => { - const tree = await native.tree() - return ( - tree.includes('/virtual-after') && !tree.includes('/virtual-before') - ) + await native.save(native.virtualConfigPath, virtualConfigSource('after')) + await expect + .poll(async () => { + const tree = await native.tree() + return ( + tree.includes('/virtual-after') && !tree.includes('/virtual-before') + ) + }) + .toBe(true) + await page + .getByRole('link', { name: 'Virtual after', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('VIRTUAL_AFTER') + await page + .getByRole('link', { name: 'Virtual before', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('virtual-config.json', { + body: JSON.stringify({ + sameProcess: true, + automaticDocumentReload: (await documentToken(page)) !== token, + }), + contentType: 'application/json', }) - .toBe(true) - await page.getByRole('link', { name: 'Virtual after', exact: true }).click() - await expect(page.getByRole('heading')).toHaveText('VIRTUAL_AFTER') - await page - .getByRole('link', { name: 'Virtual before', exact: true }) - .click() - await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') - native.assertAlive() - expect( - await ( - await request.get(new URL('/__native-info', native.url).href) - ).json(), - ).toEqual({ pid: native.pid }) - await testInfo.attach('virtual-config.json', { - body: JSON.stringify({ - sameProcess: true, - automaticDocumentReload: (await documentToken(page)) !== token, - }), - contentType: 'application/json', }) }) -}) +} diff --git a/packages/router-plugin/e2e/bun/fixture/main.tsx b/e2e/react-router/bun-basic-file-based/fixture/main.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/main.tsx rename to e2e/react-router/bun-basic-file-based/fixture/main.tsx diff --git a/packages/router-plugin/e2e/bun/fixture/routes/__root.tsx b/e2e/react-router/bun-basic-file-based/fixture/routes/__root.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/routes/__root.tsx rename to e2e/react-router/bun-basic-file-based/fixture/routes/__root.tsx diff --git a/packages/router-plugin/e2e/bun/fixture/routes/about.tsx b/e2e/react-router/bun-basic-file-based/fixture/routes/about.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/routes/about.tsx rename to e2e/react-router/bun-basic-file-based/fixture/routes/about.tsx diff --git a/packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx b/e2e/react-router/bun-basic-file-based/fixture/routes/details.lazy.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/routes/details.lazy.tsx rename to e2e/react-router/bun-basic-file-based/fixture/routes/details.lazy.tsx diff --git a/packages/router-plugin/e2e/bun/fixture/routes/details.tsx b/e2e/react-router/bun-basic-file-based/fixture/routes/details.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/routes/details.tsx rename to e2e/react-router/bun-basic-file-based/fixture/routes/details.tsx diff --git a/packages/router-plugin/e2e/bun/fixture/routes/index.tsx b/e2e/react-router/bun-basic-file-based/fixture/routes/index.tsx similarity index 100% rename from packages/router-plugin/e2e/bun/fixture/routes/index.tsx rename to e2e/react-router/bun-basic-file-based/fixture/routes/index.tsx diff --git a/e2e/react-router/bun-basic-file-based/package.json b/e2e/react-router/bun-basic-file-based/package.json new file mode 100644 index 00000000000..c2e82634643 --- /dev/null +++ b/e2e/react-router/bun-basic-file-based/package.json @@ -0,0 +1,50 @@ +{ + "name": "tanstack-router-e2e-react-bun-basic-file-based", + "private": true, + "type": "module", + "scripts": { + "test:e2e:bun": "playwright test --config playwright.config.ts", + "test:e2e:bun:dev": "node run-dev.mjs" + }, + "dependencies": { + "@tanstack/react-router": "workspace:^", + "@tanstack/router-plugin": "workspace:^", + "@tanstack/virtual-file-routes": "workspace:^", + "react": "catalog:", + "react-dom": "catalog:" + }, + "devDependencies": { + "@playwright/test": "catalog:", + "@tanstack/router-e2e-utils": "workspace:^" + }, + "nx": { + "targets": { + "test:e2e:bun": { + "dependsOn": [ + "^build" + ], + "cache": true, + "inputs": [ + "default", + "^production", + "dependentTaskOutputs", + { + "runtime": "bun --version" + } + ], + "outputs": [ + "{projectRoot}/.cache/bun-e2e", + "{projectRoot}/test-results" + ], + "parallelism": false + }, + "test:e2e:bun:dev": { + "dependsOn": [ + "^build" + ], + "cache": false, + "parallelism": false + } + } + } +} diff --git a/packages/router-plugin/e2e/bun/playwright.config.ts b/e2e/react-router/bun-basic-file-based/playwright.config.ts similarity index 100% rename from packages/router-plugin/e2e/bun/playwright.config.ts rename to e2e/react-router/bun-basic-file-based/playwright.config.ts diff --git a/packages/router-plugin/e2e/bun/run-dev.mjs b/e2e/react-router/bun-basic-file-based/run-dev.mjs similarity index 87% rename from packages/router-plugin/e2e/bun/run-dev.mjs rename to e2e/react-router/bun-basic-file-based/run-dev.mjs index 70486fad3bb..027098721dd 100644 --- a/packages/router-plugin/e2e/bun/run-dev.mjs +++ b/e2e/react-router/bun-basic-file-based/run-dev.mjs @@ -15,9 +15,8 @@ while (!existsSync(path.join(repo, 'packages/router-plugin/package.json'))) { } repo = parent } -const requirePlugin = createRequire( - path.join(repo, 'packages/router-plugin/package.json'), -) +const project = path.dirname(fileURLToPath(import.meta.url)) +const requireProject = createRequire(path.join(project, 'package.json')) const config = fileURLToPath( new URL('./dev-playwright.config.ts', import.meta.url), ) @@ -26,14 +25,14 @@ const preload = process.env.BUN_PLUGIN_PRELOAD const child = spawn( process.execPath, [ - requirePlugin.resolve('@playwright/test/cli'), + requireProject.resolve('@playwright/test/cli'), 'test', '--config', config, ...process.argv.slice(2), ], { - cwd: path.join(repo, 'packages/router-plugin'), + cwd: project, env: { ...process.env, ROUTER_REPOSITORY_ROOT: repo, diff --git a/packages/router-plugin/e2e/bun/source-maps.mjs b/e2e/react-router/bun-basic-file-based/source-maps.mjs similarity index 98% rename from packages/router-plugin/e2e/bun/source-maps.mjs rename to e2e/react-router/bun-basic-file-based/source-maps.mjs index d0bc969a9e9..601438a78d8 100644 --- a/packages/router-plugin/e2e/bun/source-maps.mjs +++ b/e2e/react-router/bun-basic-file-based/source-maps.mjs @@ -6,7 +6,7 @@ import tanstackRouter from '@tanstack/router-plugin/bun' export async function verifyBunRouteSourceMaps() { const here = path.dirname(fileURLToPath(import.meta.url)) - const workspace = path.resolve(here, '../../.cache/bun-source-maps') + const workspace = path.resolve(here, './.cache/bun-source-maps') const fixture = path.join(workspace, 'fixture # %') await rm(workspace, { recursive: true, force: true }) await mkdir(workspace, { recursive: true }) diff --git a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts index 09e7fc6c25e..52280810abc 100644 --- a/packages/router-generator/src/filesystem/physical/getRouteNodes.ts +++ b/packages/router-generator/src/filesystem/physical/getRouteNodes.ts @@ -62,6 +62,7 @@ export async function getRouteNodes( const routeNodes: Array = [] const allPhysicalDirectories: Array = [] + const allConfigFilePaths: Array = [] async function recurse(dir: string) { const fullDir = path.resolve(config.routesDirectory, dir) @@ -98,7 +99,7 @@ export async function getRouteNodes( }) if (virtualConfigFile !== undefined) { - const virtualRouteConfigExport = await loadConfigFile( + const { exports: virtualRouteConfigExport, cache } = await loadConfigFile( path.resolve(fullDir, virtualConfigFile.name), ) let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig @@ -107,22 +108,27 @@ export async function getRouteNodes( } else { virtualRouteSubtreeConfig = virtualRouteConfigExport.default } + allConfigFilePaths.push(...Object.keys(cache)) const dummyRoot: VirtualRootRoute = { type: 'root', file: '', children: virtualRouteSubtreeConfig, } - const { routeNodes: virtualRouteNodes, physicalDirectories } = - await getRouteNodesVirtual( - { - ...config, - routesDirectory: fullDir, - virtualRouteConfig: dummyRoot, - }, - root, - tokenRegexes, - ) + const { + routeNodes: virtualRouteNodes, + physicalDirectories, + configFilePaths, + } = await getRouteNodesVirtual( + { + ...config, + routesDirectory: fullDir, + virtualRouteConfig: dummyRoot, + }, + root, + tokenRegexes, + ) allPhysicalDirectories.push(...physicalDirectories) + allConfigFilePaths.push(...(configFilePaths ?? [])) virtualRouteNodes.forEach((node) => { const normalizedDir = dir === './' ? '' : dir const filePath = replaceBackslash( @@ -379,6 +385,7 @@ export async function getRouteNodes( rootRouteNode, routeNodes, physicalDirectories: allPhysicalDirectories, + configFilePaths: allConfigFilePaths, } } diff --git a/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts index 5d3cd610be8..2d0735a1637 100644 --- a/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts +++ b/packages/router-generator/src/filesystem/virtual/getRouteNodes.ts @@ -61,15 +61,19 @@ export async function getRouteNodes( throw new Error(`virtualRouteConfig is undefined`) } let virtualRouteConfig: VirtualRootRoute + const configFilePaths: Array = [] if (typeof tsrConfig.virtualRouteConfig === 'string') { - virtualRouteConfig = await getVirtualRouteConfigFromFileExport( - tsrConfig, - root, - ) + const loaded = await getVirtualRouteConfigFromFileExport(tsrConfig, root) + virtualRouteConfig = loaded.config + configFilePaths.push(...loaded.configFilePaths) } else { virtualRouteConfig = tsrConfig.virtualRouteConfig } - const { children, physicalDirectories } = await getRouteNodesRecursive( + const { + children, + physicalDirectories, + configFilePaths: nestedConfigFilePaths, + } = await getRouteNodesRecursive( tsrConfig, root, fullDir, @@ -88,7 +92,12 @@ export async function getRouteNodes( const rootRouteNode = allNodes[0] const routeNodes = allNodes.slice(1) - return { rootRouteNode, routeNodes, physicalDirectories } + return { + rootRouteNode, + routeNodes, + physicalDirectories, + configFilePaths: [...configFilePaths, ...nestedConfigFilePaths], + } } /** @@ -108,7 +117,7 @@ export async function getRouteNodes( async function getVirtualRouteConfigFromFileExport( tsrConfig: Pick, root: string, -): Promise { +): Promise<{ config: VirtualRootRoute; configFilePaths: Array }> { if ( tsrConfig.virtualRouteConfig === undefined || typeof tsrConfig.virtualRouteConfig !== 'string' || @@ -116,7 +125,9 @@ async function getVirtualRouteConfigFromFileExport( ) { throw new Error(`virtualRouteConfig is undefined or empty`) } - const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig)) + const { exports, cache } = await loadConfigFile( + resolve(root, tsrConfig.virtualRouteConfig), + ) if (!('routes' in exports) && !('default' in exports)) { throw new Error( @@ -127,7 +138,10 @@ async function getVirtualRouteConfigFromFileExport( const virtualRouteConfig = 'routes' in exports ? exports.routes : exports.default - return virtualRootRouteSchema.parse(virtualRouteConfig) + return { + config: virtualRootRouteSchema.parse(virtualRouteConfig), + configFilePaths: Object.keys(cache), + } } export async function getRouteNodesRecursive( @@ -144,11 +158,16 @@ export async function getRouteNodesRecursive( nodes: Array | undefined, tokenRegexes: TokenRegexBundle, parent?: RouteNode, -): Promise<{ children: Array; physicalDirectories: Array }> { +): Promise<{ + children: Array + physicalDirectories: Array + configFilePaths: Array +}> { if (nodes === undefined) { - return { children: [], physicalDirectories: [] } + return { children: [], physicalDirectories: [], configFilePaths: [] } } const allPhysicalDirectories: Array = [] + const allConfigFilePaths: Array = [] const children = await Promise.all( nodes.map(async (node) => { if (node.type === 'physical') { @@ -160,18 +179,20 @@ export async function getRouteNodesRecursive( removeLeadingSlash(node.pathPrefix), ) : { routePath: '', originalRoutePath: '' } - const { routeNodes, physicalDirectories } = await getRouteNodesPhysical( - { - ...tsrConfig, - routesDirectory: resolve(fullDir, node.directory), - }, - root, - tokenRegexes, - ) + const { routeNodes, physicalDirectories, configFilePaths } = + await getRouteNodesPhysical( + { + ...tsrConfig, + routesDirectory: resolve(fullDir, node.directory), + }, + root, + tokenRegexes, + ) allPhysicalDirectories.push( resolve(fullDir, node.directory), ...physicalDirectories, ) + allConfigFilePaths.push(...(configFilePaths ?? [])) routeNodes.forEach((subtreeNode) => { const pathPrefix = cleanPath( `${parent?.routePath ?? ''}${routePathPrefix}`, @@ -277,7 +298,7 @@ export async function getRouteNodesRecursive( } if (node.children !== undefined) { - const { children, physicalDirectories } = + const { children, physicalDirectories, configFilePaths } = await getRouteNodesRecursive( tsrConfig, root, @@ -288,6 +309,7 @@ export async function getRouteNodesRecursive( ) routeNode.children = children allPhysicalDirectories.push(...physicalDirectories) + allConfigFilePaths.push(...configFilePaths) // If the route has children, it should be a layout routeNode._fsRouteType = 'layout' @@ -334,7 +356,7 @@ export async function getRouteNodesRecursive( } if (node.children !== undefined) { - const { children, physicalDirectories } = + const { children, physicalDirectories, configFilePaths } = await getRouteNodesRecursive( tsrConfig, root, @@ -345,6 +367,7 @@ export async function getRouteNodesRecursive( ) routeNode.children = children allPhysicalDirectories.push(...physicalDirectories) + allConfigFilePaths.push(...configFilePaths) } return routeNode } @@ -354,5 +377,6 @@ export async function getRouteNodesRecursive( return { children: children.flat(), physicalDirectories: allPhysicalDirectories, + configFilePaths: allConfigFilePaths, } } diff --git a/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts index 9de740ed15a..c0a8946e0e1 100644 --- a/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts +++ b/packages/router-generator/src/filesystem/virtual/loadConfigFile.ts @@ -1,11 +1,24 @@ +import { readFile } from 'node:fs/promises' import { createJiti } from 'jiti' +import { replaceBackslash } from '../../utils' +import type { ModuleCache } from 'jiti' export async function loadConfigFile(filePath: string) { + // Match Jiti's resolved import paths so cycles share the entry module cache. + filePath = replaceBackslash(filePath) const jiti = createJiti(filePath, { interopDefault: false, moduleCache: false, + tryNative: false, tsconfigPaths: true, }) - const loaded = await jiti.import(filePath) - return loaded + // Keep the evaluated import graph local to this generation for file watching. + const cache: ModuleCache = {} + const source = await readFile(filePath, 'utf8') + const loaded = await jiti.evalModule(source, { + filename: filePath, + async: true, + cache, + }) + return { exports: loaded as any, cache } } diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index 9f16c139308..3b68f73ec99 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -205,6 +205,7 @@ export class Generator { private routeTreeFileCache: GeneratorCacheEntry | undefined private crawlingResult: CrawlingResult | undefined + private configFilePaths = new Set() public config: Config public targetTemplate: TargetTemplate @@ -304,15 +305,23 @@ export class Generator { ) } - public getRoutesDirectoryPaths(): Array { - return [ - ...new Set( - [ - ...(this.config.virtualRouteConfig ? [] : [this.routesDirectoryPath]), - ...this.physicalDirectories, - ].map((directory) => path.resolve(this.root, directory)), - ), - ] + public getWatchDependencies(): { + files: Array + directories: Array + } { + return { + files: [...this.configFilePaths], + directories: [ + ...new Set( + [ + ...(this.config.virtualRouteConfig + ? [] + : [this.routesDirectoryPath]), + ...this.physicalDirectories, + ].map((directory) => path.resolve(this.root, directory)), + ), + ], + } } public async run(event?: GeneratorEvent): Promise { @@ -418,6 +427,7 @@ export class Generator { rootRouteNode, routeNodes: beforeRouteNodes, physicalDirectories, + configFilePaths, } = getRouteNodesResult if (rootRouteNode === undefined) { let errorMessage = `rootRouteNode must not be undefined. Make sure you've added your root route into the route-tree.` @@ -427,6 +437,9 @@ export class Generator { throw new Error(errorMessage) } this.physicalDirectories = physicalDirectories + this.configFilePaths = new Set( + configFilePaths?.map((filePath) => path.resolve(filePath)), + ) await this.handleRootNode(rootRouteNode) @@ -1646,11 +1659,8 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved return true } - // the virtual route config file passed into `virtualRouteConfig` - if ( - typeof this.config.virtualRouteConfig === 'string' && - filePath === this.config.virtualRouteConfig - ) { + // Virtual configuration modules and the helpers loaded while evaluating them. + if (this.configFilePaths.has(path.resolve(filePath))) { return true } diff --git a/packages/router-generator/src/types.ts b/packages/router-generator/src/types.ts index ec0aa226ceb..d003a6a5bf3 100644 --- a/packages/router-generator/src/types.ts +++ b/packages/router-generator/src/types.ts @@ -33,6 +33,7 @@ export interface GetRouteNodesResult { rootRouteNode?: RouteNode routeNodes: Array physicalDirectories: Array + configFilePaths?: Array } export type FsRouteType = diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts index 4c06bb4ea27..7d93fd246e2 100644 --- a/packages/router-generator/tests/generator.test.ts +++ b/packages/router-generator/tests/generator.test.ts @@ -426,11 +426,17 @@ describe('generator works', async () => { const expected = directories.map((directory) => path.resolve(root, directory), ) - const snapshot = generator.getRoutesDirectoryPaths() - expect(snapshot).toEqual(expected) - snapshot[0] = path.resolve(root, 'changed') - snapshot.push(path.resolve(root, 'extra')) - expect(generator.getRoutesDirectoryPaths()).toEqual(expected) + const snapshot = generator.getWatchDependencies() + expect(snapshot.directories).toEqual(expected) + const files = [...snapshot.files] + if (typeof config.virtualRouteConfig === 'string') { + expect(files).toContain(path.resolve(root, config.virtualRouteConfig)) + } + snapshot.directories[0] = path.resolve(root, 'changed') + snapshot.directories.push(path.resolve(root, 'extra')) + snapshot.files.push(path.resolve(root, 'extra.ts')) + expect(generator.getWatchDependencies().directories).toEqual(expected) + expect(generator.getWatchDependencies().files).toEqual(files) }, ) diff --git a/packages/router-generator/tests/virtual-config.test.ts b/packages/router-generator/tests/virtual-config.test.ts index e41914a6ed3..1c0804050b3 100644 --- a/packages/router-generator/tests/virtual-config.test.ts +++ b/packages/router-generator/tests/virtual-config.test.ts @@ -1,14 +1,25 @@ -import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { + mkdtemp, + mkdir, + readFile, + rename, + rm, + writeFile, +} from 'node:fs/promises' import { tmpdir } from 'node:os' import path from 'node:path' import { expect, test } from 'vitest' -import { Generator } from '../src/generator' -import { getConfig } from '../src/config' +import { Generator, getConfig } from '../src' -test('reloads an edited virtual route configuration on the next generation', async () => { +test.each([ + { source: 'configuration', depth: 0 }, + { source: 'helper', depth: 1 }, + { source: 'transitive helper', depth: 2 }, +])('reloads an edited $source from its file event', async ({ depth }) => { const root = await mkdtemp(path.join(tmpdir(), 'router-virtual-config-')) const routes = path.join(root, 'routes') const configFile = path.join(root, 'virtual-routes.ts') + const editedFile = depth ? path.join(root, `helper${depth}.ts`) : configFile const generatedRouteTree = path.join(root, 'routeTree.gen.ts') const virtualConfig = (name: string) => `export default ${JSON.stringify({ @@ -25,14 +36,20 @@ test('reloads an edited virtual route configuration on the next generation', asy `import { createRootRoute } from '@tanstack/react-router' export const Route = createRootRoute({})\n`, ), - ...['before', 'after'].map((name) => + ...['before', 'after', 'replacement'].map((name) => writeFile( path.join(routes, `${name}.tsx`), `import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/${name}')({})\n`, ), ), - writeFile(configFile, virtualConfig('before')), + writeFile(editedFile, virtualConfig('before')), + ...Array.from({ length: depth }, (_, index) => + writeFile( + index ? path.join(root, `helper${index}.ts`) : configFile, + `export { default } from './helper${index + 1}'\n`, + ), + ), ]) const generator = new Generator({ root, @@ -50,12 +67,175 @@ export const Route = createFileRoute('/${name}')({})\n`, await generator.run() expect(await readFile(generatedRouteTree, 'utf8')).toContain("'/before'") + const dependencies = [ + configFile, + ...Array.from({ length: depth }, (_, index) => + path.join(root, `helper${index + 1}.ts`), + ), + ] + expect(generator.getWatchDependencies()).toEqual({ + files: expect.arrayContaining(dependencies), + directories: [], + }) + expect(generator.getWatchDependencies().files).toHaveLength( + dependencies.length, + ) - await writeFile(configFile, virtualConfig('after')) - await generator.run() + const isolatedConfig = path.join(root, 'isolated-routes.ts') + await writeFile(isolatedConfig, virtualConfig('replacement')) + const isolated = new Generator({ + root, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree: path.join(root, 'isolated-routeTree.gen.ts'), + virtualRouteConfig: isolatedConfig, + tmpDir: path.join(root, 'tmp'), + disableLogging: true, + }, + root, + ), + }) + await isolated.run() + expect(isolated.getWatchDependencies().files).toEqual([isolatedConfig]) + expect(generator.getWatchDependencies().files).toEqual( + expect.arrayContaining(dependencies), + ) + expect(generator.getWatchDependencies().files).toHaveLength( + dependencies.length, + ) + + await writeFile(editedFile, virtualConfig('after')) + await generator.run({ path: editedFile, type: 'update' }) const updated = await readFile(generatedRouteTree, 'utf8') expect(updated).toContain("'/after'") expect(updated).not.toContain("'/before'") + + await generator.run({ path: editedFile, type: 'update' }) + expect(await readFile(generatedRouteTree, 'utf8')).toBe(updated) + + await writeFile(`${editedFile}.next`, virtualConfig('replacement')) + await rename(`${editedFile}.next`, editedFile) + await generator.run({ path: editedFile, type: 'update' }) + const replaced = await readFile(generatedRouteTree, 'utf8') + expect(replaced).toContain("'/replacement'") + expect(replaced).not.toContain("'/after'") + expect(replaced).not.toContain("'/before'") + + await writeFile(configFile, virtualConfig('before')) + await generator.run({ path: configFile, type: 'update' }) + expect(await readFile(generatedRouteTree, 'utf8')).toContain("'/before'") + expect(generator.getWatchDependencies().files).toEqual([configFile]) + } finally { + await rm(root, { recursive: true, force: true }) + } +}) + +test('watches imports awaited by a nested __virtual factory', async () => { + const root = await mkdtemp(path.join(tmpdir(), 'router-virtual-factory-')) + const routes = path.join(root, 'routes') + const nested = path.join(routes, 'nested') + const configFile = path.join(nested, '__virtual.ts') + const helperFile = path.join(root, 'helper.ts') + const leafFile = path.join(root, 'leaf.ts') + const generatedRouteTree = path.join(root, 'routeTree.gen.ts') + const subtree = (name: string) => + `export default [{ type: 'route', path: '/${name}', file: '${name}.tsx' }]\n` + try { + await mkdir(nested, { recursive: true }) + await Promise.all([ + writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, + ), + ...['before', 'after'].map((name) => + writeFile( + path.join(nested, `${name}.tsx`), + `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/nested/${name}')({})\n`, + ), + ), + writeFile( + configFile, + `export default async () => (await import('../../helper')).default\n`, + ), + writeFile(helperFile, `export { default } from './leaf'\n`), + writeFile(leafFile, subtree('before')), + ]) + const generator = new Generator({ + root, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree, + tmpDir: path.join(root, 'tmp'), + disableLogging: true, + }, + root, + ), + }) + await generator.run() + expect(await readFile(generatedRouteTree, 'utf8')).toContain( + "'/nested/before'", + ) + expect(generator.getWatchDependencies()).toEqual({ + files: expect.arrayContaining([configFile, helperFile, leafFile]), + directories: [routes], + }) + expect(generator.getWatchDependencies().files).toHaveLength(3) + await writeFile(leafFile, subtree('after')) + await generator.run({ path: leafFile, type: 'update' }) + const updated = await readFile(generatedRouteTree, 'utf8') + expect(updated).toContain("'/nested/after'") + expect(updated).not.toContain("'/nested/before'") + + await writeFile(configFile, subtree('before')) + await generator.run({ path: configFile, type: 'update' }) + expect(await readFile(generatedRouteTree, 'utf8')).toContain( + "'/nested/before'", + ) + expect(generator.getWatchDependencies().files).toEqual([configFile]) + } finally { + await rm(root, { recursive: true, force: true }) + } +}) + +test('evaluates a cyclic virtual configuration once per generation', async () => { + const root = await mkdtemp(path.join(tmpdir(), 'router-virtual-cycle-')) + const routes = path.join(root, 'routes') + const configFile = path.join(root, 'virtual-routes.ts') + const evaluationLog = path.join(root, 'evaluations.log') + try { + await mkdir(routes) + await writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, + ) + await writeFile( + configFile, + `import { appendFileSync } from 'node:fs' +import './virtual-routes' +appendFileSync(${JSON.stringify(evaluationLog)}, 'run\\n') +export default { type: 'root', file: '__root.tsx', children: [] } +`, + ) + const generator = new Generator({ + root, + config: getConfig( + { + routesDirectory: routes, + virtualRouteConfig: configFile, + generatedRouteTree: path.join(root, 'routeTree.gen.ts'), + tmpDir: path.join(root, 'tmp'), + disableLogging: true, + }, + root, + ), + }) + await generator.run() + expect(await readFile(evaluationLog, 'utf8')).toBe('run\n') + await generator.run({ path: configFile, type: 'update' }) + expect(await readFile(evaluationLog, 'utf8')).toBe('run\nrun\n') + expect(generator.getWatchDependencies().files).toEqual([configFile]) } finally { await rm(root, { recursive: true, force: true }) } diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json index 3ffd7003160..fda796f3bc9 100644 --- a/packages/router-plugin/package.json +++ b/packages/router-plugin/package.json @@ -29,8 +29,6 @@ "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", "test:unit": "vitest", "test:unit:dev": "vitest --watch", - "test:e2e:bun": "playwright test --config e2e/bun/playwright.config.ts", - "test:e2e:bun:dev": "node e2e/bun/run-dev.mjs", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", @@ -164,44 +162,6 @@ "dependsOn": [ "build" ] - }, - "test:e2e:bun:dev": { - "dependsOn": [ - "build", - { - "target": "build", - "projects": [ - "@tanstack/react-router" - ] - } - ], - "cache": false, - "parallelism": false - }, - "test:e2e:bun": { - "dependsOn": [ - "build", - { - "target": "build", - "projects": [ - "@tanstack/react-router" - ] - } - ], - "cache": true, - "inputs": [ - "default", - "^production", - "dependentTaskOutputs", - { - "runtime": "bun --version" - } - ], - "outputs": [ - "{projectRoot}/.cache/bun-e2e", - "{projectRoot}/test-results" - ], - "parallelism": false } } }, diff --git a/packages/router-plugin/src/core/router-generator-plugin.ts b/packages/router-plugin/src/core/router-generator-plugin.ts index 87a5acca9b7..99c0b0d8907 100644 --- a/packages/router-plugin/src/core/router-generator-plugin.ts +++ b/packages/router-plugin/src/core/router-generator-plugin.ts @@ -104,10 +104,11 @@ export function createRouterGeneratorPlugin( ), }, async () => { + const dependencies = generator.getWatchDependencies() // Bun watches immediate directory entries. Include empty directories // so a route added there also triggers generation before bundling. const watchDirs = await Promise.all( - generator.getRoutesDirectoryPaths().map(async (directory) => { + dependencies.directories.map(async (directory) => { const entries = await readdir(directory, { recursive: true, withFileTypes: true, @@ -133,10 +134,7 @@ export function createRouterGeneratorPlugin( : 'js'), resolveDir: dirname(generatedRouteTree), watchDirs: watchDirs.flat(), - watchFiles: - typeof userConfig.virtualRouteConfig === 'string' - ? [resolve(ROOT, userConfig.virtualRouteConfig)] - : undefined, + watchFiles: dependencies.files, } }, ) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47c1ca960a9..c468a2228ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1102,6 +1102,31 @@ importers: specifier: ^8.3.4 version: 8.3.4(@types/node@25.0.9)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.105.1)(sass@1.97.2)(terser@5.51.2)(tsx@4.20.3)(yaml@2.9.0) + e2e/react-router/bun-basic-file-based: + dependencies: + '@tanstack/react-router': + specifier: workspace:* + version: link:../../../packages/react-router + '@tanstack/router-plugin': + specifier: workspace:* + version: link:../../../packages/router-plugin + '@tanstack/virtual-file-routes': + specifier: workspace:* + version: link:../../../packages/virtual-file-routes + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + devDependencies: + '@playwright/test': + specifier: ^1.63.0 + version: 1.63.0 + '@tanstack/router-e2e-utils': + specifier: workspace:^ + version: link:../../e2e-utils + e2e/react-router/escaped-special-strings: dependencies: '@tanstack/react-router': From 15c5aa70d123f67f804808ea5362a0071a379385 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 11:37:59 +0200 Subject: [PATCH 08/31] test: validate native config helpers and portable preload paths --- .../combined-generator.mjs | 225 ++++++++++++++++++ .../helper-import-preload.mjs | 13 + .github/workflows/bun-native-validation.yml | 49 +++- .../bun-basic-file-based/dev-fixture.ts | 8 +- 4 files changed, 287 insertions(+), 8 deletions(-) create mode 100644 .github/native-bun-validation/combined-generator.mjs create mode 100644 .github/native-bun-validation/helper-import-preload.mjs diff --git a/.github/native-bun-validation/combined-generator.mjs b/.github/native-bun-validation/combined-generator.mjs new file mode 100644 index 00000000000..d4dafbf2076 --- /dev/null +++ b/.github/native-bun-validation/combined-generator.mjs @@ -0,0 +1,225 @@ +import { + mkdtemp, + mkdir, + readFile, + rename, + rm, + writeFile, +} from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { + Generator, + getConfig, +} from '../../packages/router-generator/dist/esm/index.js' + +const normalize = (filename) => path.resolve(filename).replaceAll('\\', '/') +const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => + [1, 2].map((depth) => ({ ext, depth, dynamic: false })), +) +cases.push({ ext: 'mjs', depth: 2, dynamic: true }) +const results = [] +const routeNames = ['before', 'after', 'replacement'] +const configSource = (file, dynamic) => + file.endsWith('.cjs') + ? `const routes = require(${JSON.stringify(file)}); export default routes\n` + : dynamic + ? `export default (await import(${JSON.stringify(file)})).default\n` + : `import routes from ${JSON.stringify(file)}; export default routes\n` +const routeConfig = (name) => ({ + type: 'root', + file: '__root.tsx', + children: [{ type: 'route', path: `/${name}`, file: `${name}.tsx` }], +}) +const helperSource = (ext, name) => + ext === 'json' + ? JSON.stringify(routeConfig(name)) + : ext === 'cjs' + ? `module.exports = ${JSON.stringify(routeConfig(name))}\n` + : `export default ${JSON.stringify(routeConfig(name))}\n` + +for (const scenario of cases) { + const root = await mkdtemp(path.join(tmpdir(), 'router-built-helper-')) + const checks = [] + const record = (name, passed, details = undefined) => + checks.push({ name, passed, details }) + try { + const projects = [] + for (const id of ['a', 'b']) { + const project = path.join(root, id) + const routes = path.join(project, 'routes') + await mkdir(routes, { recursive: true }) + await writeFile(path.join(project, 'package.json'), '{"type":"module"}\n') + await writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, + ) + for (const suffix of routeNames) { + const name = `${id}-${suffix}` + await writeFile( + path.join(routes, `${name}.tsx`), + `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/${name}')({})\n`, + ) + } + const filename = path.join(project, `helper.${scenario.ext}`) + const configFile = path.join(project, 'virtual-routes.ts') + const bridge = path.join(project, 'bridge.ts') + await writeFile(filename, helperSource(scenario.ext, `${id}-before`)) + await writeFile( + configFile, + configSource( + scenario.depth === 2 ? './bridge.ts' : `./helper.${scenario.ext}`, + false, + ), + ) + if (scenario.depth === 2) { + await writeFile( + bridge, + configSource(`./helper.${scenario.ext}`, scenario.dynamic), + ) + } + const generatedRouteTree = path.join(project, 'routeTree.gen.ts') + const generator = new Generator({ + root: project, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree, + virtualRouteConfig: 'virtual-routes.ts', + tmpDir: path.join(project, 'tmp'), + disableLogging: true, + }, + project, + ), + }) + projects.push({ + id, + project, + filename, + configFile, + bridge, + generatedRouteTree, + generator, + }) + } + const [a, b] = projects + await Promise.all(projects.map((project) => project.generator.run())) + const expectedFiles = (project) => + [ + project.configFile, + ...(scenario.depth === 2 ? [project.bridge] : []), + project.filename, + ] + .map(normalize) + .sort() + for (const project of projects) { + const deps = project.generator + .getWatchDependencies() + .files.map(normalize) + .sort() + record( + `${project.id}:watch-dependencies`, + JSON.stringify(deps) === JSON.stringify(expectedFiles(project)), + { + expected: expectedFiles(project).map((filename) => + path.relative(root, filename), + ), + actual: deps.map((filename) => path.relative(root, filename)), + }, + ) + record( + `${project.id}:initial-tree`, + (await readFile(project.generatedRouteTree, 'utf8')).includes( + `'/${project.id}-before'`, + ), + ) + } + const initialB = await readFile(b.generatedRouteTree, 'utf8') + const stableA = await readFile(a.generatedRouteTree, 'utf8') + await a.generator.run() + record( + 'a:unchanged-generation', + (await readFile(a.generatedRouteTree, 'utf8')) === stableA, + ) + await writeFile(a.filename, helperSource(scenario.ext, 'a-after')) + await a.generator.run({ path: a.filename, type: 'update' }) + const eventTree = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:in-place-update-event', + eventTree.includes("'/a-after'") && !eventTree.includes("'/a-before'"), + ) + await a.generator.run() + const rerunTree = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:in-place-unconditional-rerun', + rerunTree.includes("'/a-after'") && !rerunTree.includes("'/a-before'"), + ) + record( + 'b:unchanged-after-a-edit', + (await readFile(b.generatedRouteTree, 'utf8')) === initialB, + ) + await writeFile( + `${a.filename}.next`, + helperSource(scenario.ext, 'a-replacement'), + ) + await rename(`${a.filename}.next`, a.filename) + await a.generator.run({ path: a.filename, type: 'update' }) + const replaced = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:atomic-replacement-event', + replaced.includes("'/a-replacement'") && !replaced.includes("'/a-after'"), + ) + await writeFile(b.filename, helperSource(scenario.ext, 'b-after')) + await b.generator.run({ path: b.filename, type: 'update' }) + record( + 'b:independent-update-event', + (await readFile(b.generatedRouteTree, 'utf8')).includes("'/b-after'"), + ) + await a.generator.run() + record( + 'a:no-cross-generator-leakage', + (await readFile(a.generatedRouteTree, 'utf8')) === replaced, + ) + record( + 'watch-dependencies-remain-isolated', + projects.every((project) => { + const deps = project.generator + .getWatchDependencies() + .files.map(normalize) + return ( + JSON.stringify(deps.sort()) === JSON.stringify(expectedFiles(project)) + ) + }), + ) + } catch (error) { + record( + 'execution', + false, + error instanceof Error ? error.stack : String(error), + ) + } finally { + await rm(root, { recursive: true, force: true }) + } + results.push({ + ...scenario, + passed: checks.every((check) => check.passed), + checks, + }) +} +const report = { + runtime: { + bun: process.versions.bun ?? null, + node: process.versions.node, + platform: process.platform, + arch: process.arch, + }, + mode: process.env.JITI_COMBINED_MODE ?? 'installed', + generator: 'packages/router-generator/dist/esm/index.js', + cases: results.length, + passed: results.filter((result) => result.passed).length, + results, +} +console.log(JSON.stringify(report, null, 2)) +if (report.passed !== report.cases) { + process.exitCode = 1 +} diff --git a/.github/native-bun-validation/helper-import-preload.mjs b/.github/native-bun-validation/helper-import-preload.mjs new file mode 100644 index 00000000000..d871bbce50c --- /dev/null +++ b/.github/native-bun-validation/helper-import-preload.mjs @@ -0,0 +1,13 @@ +import { mock } from 'bun:test' +import { fileURLToPath, pathToFileURL } from 'node:url' +import path from 'node:path' +const repository = fileURLToPath(new URL('../../../', import.meta.url)) +const candidateEntry = process.env.JITI_CANDIDATE_ENTRY + ? path.resolve(process.env.JITI_CANDIDATE_ENTRY) + : path.join( + repository, + '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', + ) +const candidate = await import(pathToFileURL(candidateEntry).href) +mock.module('jiti', () => candidate) +process.env.JITI_COMBINED_MODE = 'candidate' diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 67b898d4c79..d9f89f28245 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -130,10 +130,20 @@ jobs: path: .native-unplugin persist-credentials: false - name: Build actual unplugin PR distribution + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + version: '12.14.0' + package_json_file: .native-unplugin/package.json + dest: ~/native-pnpm12 + - name: Install and build actual unplugin PR run: | - pnpm dlx pnpm@12.14.0 --dir .native-unplugin install --frozen-lockfile - pnpm dlx pnpm@12.14.0 --dir .native-unplugin build + pnpm --dir .native-unplugin install --frozen-lockfile + pnpm --dir .native-unplugin build test -f .native-unplugin/dist/index.mjs + - name: Restore Router pnpm version + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + dest: ~/native-pnpm11 - name: Prepare isolated native Bun wrapper and unplugin preload run: node .github/native-bun-validation/browser-setup.mjs - name: Install Chromium @@ -155,6 +165,36 @@ jobs: run: | set -o pipefail pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun:dev --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/development.log + - name: Checkout actual Jiti PR source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/jiti + ref: 2669fd42050027531c7bbeb0e61b61f7ae35517a + path: .native-jiti + persist-credentials: false + - name: Build actual Jiti PR distribution + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + version: '10.30.3' + package_json_file: .native-jiti/package.json + dest: ~/native-pnpm10 + - name: Install and build actual Jiti PR + run: | + pnpm --dir .native-jiti install --frozen-lockfile + pnpm --dir .native-jiti build + test -f .native-jiti/dist/jiti.cjs + - name: Imported virtual configuration helpers with actual Jiti PR + id: configuration + continue-on-error: true + env: + JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs + run: | + mkdir -p packages/router-generator/.cache + cp .github/native-bun-validation/helper-import-preload.mjs packages/router-generator/.cache/helper-import-preload.mjs + if "$BUN_EXECUTABLE" .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-installed.json; then + echo 'Installed Jiti also passed the helper cases.' + fi + "$BUN_EXECUTABLE" --preload ./packages/router-generator/.cache/helper-import-preload.mjs .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-candidate.json - name: Upload all browser results if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 @@ -167,10 +207,11 @@ jobs: include-hidden-files: true if-no-files-found: warn retention-days: 14 - - name: Require both browser suites to pass + - name: Require browser and configuration suites to pass if: always() env: PRODUCTION: ${{ steps.production.outcome }} DEVELOPMENT: ${{ steps.development.outcome }} + CONFIGURATION: ${{ steps.configuration.outcome }} run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success ]] + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success ]] diff --git a/e2e/react-router/bun-basic-file-based/dev-fixture.ts b/e2e/react-router/bun-basic-file-based/dev-fixture.ts index deac5ae4558..dec0e2a301a 100644 --- a/e2e/react-router/bun-basic-file-based/dev-fixture.ts +++ b/e2e/react-router/bun-basic-file-based/dev-fixture.ts @@ -11,7 +11,7 @@ import { } from 'node:fs/promises' import path from 'node:path' import { tmpdir } from 'node:os' -import { fileURLToPath, pathToFileURL } from 'node:url' +import { fileURLToPath } from 'node:url' import { createHash } from 'node:crypto' export function aboutSource( @@ -192,8 +192,8 @@ export default { name: 'observe-public-router-dev', setup(build) { const preload = process.env.BUN_PLUGIN_PRELOAD const preloadArg = preload ? preload.startsWith('file:') - ? preload - : pathToFileURL(path.resolve(preload)).href + ? fileURLToPath(preload) + : path.resolve(preload) : undefined let pending = '' let settleReady: (value: { url: string; pid: number }) => void @@ -273,7 +273,7 @@ export default { name: 'observe-public-router-dev', setup(build) { preload: preloadArg ?? null, preloadSha256: preloadArg ? createHash('sha256') - .update(await readFile(new URL(preloadArg))) + .update(await readFile(preloadArg)) .digest('hex') : null, routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { From fa67bb091603bb85a9d1867fbf80808e66699c9b Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 11:46:39 +0200 Subject: [PATCH 09/31] ci: validate final native Bun fixes with stable release profile --- .github/native-bun-validation/build-macos.sh | 4 +-- .../native-v10-additional-files.tar.gz | Bin 0 -> 10601 bytes .../native-v10-manifest.json | 18 ++++++++++++ .../native-v10-tracked.patch.gz | Bin 0 -> 85991 bytes .../native-v9-additional-files.tar.gz | Bin 10816 -> 0 bytes .../native-v9-manifest.json | 27 ------------------ .../native-v9-tracked.patch.gz | Bin 85792 -> 0 bytes .github/native-bun-validation/prepare.py | 10 +++---- .github/workflows/bun-native-validation.yml | 4 +-- 9 files changed, 27 insertions(+), 36 deletions(-) create mode 100644 .github/native-bun-validation/native-v10-additional-files.tar.gz create mode 100644 .github/native-bun-validation/native-v10-manifest.json create mode 100644 .github/native-bun-validation/native-v10-tracked.patch.gz delete mode 100644 .github/native-bun-validation/native-v9-additional-files.tar.gz delete mode 100644 .github/native-bun-validation/native-v9-manifest.json delete mode 100644 .github/native-bun-validation/native-v9-tracked.patch.gz diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh index 82f6d9a23cb..53259742028 100644 --- a/.github/native-bun-validation/build-macos.sh +++ b/.github/native-bun-validation/build-macos.sh @@ -52,6 +52,6 @@ bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" # Use the official build-and-execute path. No timeout wraps compilation. -read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v9-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" +read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v10-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" [[ "${#native_tests[@]}" -eq 9 ]] -bun run build:release --lto=off --build-dir=build/native-release -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" +bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" diff --git a/.github/native-bun-validation/native-v10-additional-files.tar.gz b/.github/native-bun-validation/native-v10-additional-files.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e1f2d7a78af9308a8b8164c3b28c59ff10571685 GIT binary patch literal 10601 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 DD=fZe literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/native-v10-manifest.json b/.github/native-bun-validation/native-v10-manifest.json new file mode 100644 index 00000000000..64e9cbd7bcf --- /dev/null +++ b/.github/native-bun-validation/native-v10-manifest.json @@ -0,0 +1,18 @@ +{ + "candidate": "native-v10", + "head": "dca7d25e95cca39316c659a377dba6803805549f", + "trackedPatchSha256": "04da37bc9b4bea9c446a96c88b6288f3faec626d846be808af6291d0ceb669d5", + "additionalFiles": { + "src/bundler/input_source_map.rs": "6afe1551ae56d44dfa6abccc89668cd582db68c79f65acf692abba457f678cbf", + "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", + "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", + "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", + "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", + "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" + }, + "changesSinceV9": [ + "Windows synchronous handles for external input-map reads", + "Watched leaf-directory rename regression and explicit Windows ancestor-rename restriction" + ], + "testCommand": "bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts" +} diff --git a/.github/native-bun-validation/native-v10-tracked.patch.gz b/.github/native-bun-validation/native-v10-tracked.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..18f7009b26d0cf4aaa2866a02155d9aa14f5e239 GIT binary patch literal 85991 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 ITL_5%10YgB3;+NC diff --git a/.github/native-bun-validation/native-v9-manifest.json b/.github/native-bun-validation/native-v9-manifest.json deleted file mode 100644 index 76c3a3d5185..00000000000 --- a/.github/native-bun-validation/native-v9-manifest.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "head": "dca7d25e95cca39316c659a377dba6803805549f", - "trackedPatchSha256": "fb44303ad3c22ae5652bfe32fe3e6e32c1aeb24dc5594b3a1a631ab0e945406a", - "additionalFiles": { - "src/bundler/input_source_map.rs": "acc9b44a3a7c619801e3c9738b00f335b9cb48eaaff7cc9437b7ec5233dbf0da", - "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", - "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", - "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", - "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", - "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" - }, - "platform": "Debian Linux x64 in Docker", - "testCommand": "bun run build:assert -j6 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts", - "nativeTests": { - "passed": 110, - "failed": 0 - }, - "routerDevelopmentBrowser": { - "passed": 11, - "failed": 0 - }, - "routerProductionBrowser": { - "passed": 6, - "failed": 0, - "skipped": 0 - } -} diff --git a/.github/native-bun-validation/native-v9-tracked.patch.gz b/.github/native-bun-validation/native-v9-tracked.patch.gz deleted file mode 100644 index d08a5c99e16e2d408b84af7b6335b602e4cc03d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85792 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 z 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 b5M_IsuT&pt)rXm(d${)>U^>#6tbGLlF3m;V diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py index 448cc39d739..f7d8a27519d 100644 --- a/.github/native-bun-validation/prepare.py +++ b/.github/native-bun-validation/prepare.py @@ -10,7 +10,7 @@ BASE = "dca7d25e95cca39316c659a377dba6803805549f" -PATCH_HASH = "fb44303ad3c22ae5652bfe32fe3e6e32c1aeb24dc5594b3a1a631ab0e945406a" +PATCH_HASH = "04da37bc9b4bea9c446a96c88b6288f3faec626d846be808af6291d0ceb669d5" ADDITIONAL = { "src/bundler/input_source_map.rs", "src/runtime/bake/dev_server/plugin_watch_store.rs", @@ -45,11 +45,11 @@ def main(): parser.add_argument("--check-assets-only", action="store_true") args = parser.parse_args() data = Path(__file__).resolve().parent - manifest = json.loads((data / "native-v9-manifest.json").read_text()) + manifest = json.loads((data / "native-v10-manifest.json").read_text()) assert manifest["head"] == BASE assert manifest["trackedPatchSha256"] == PATCH_HASH assert set(manifest["additionalFiles"]) == ADDITIONAL - patch = gzip.decompress((data / "native-v9-tracked.patch.gz").read_bytes()) + patch = gzip.decompress((data / "native-v10-tracked.patch.gz").read_bytes()) assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) assert paths, "No tracked patch paths" @@ -59,7 +59,7 @@ def main(): tracked.append(old.decode()) extra = {} archive = gzip.decompress( - (data / "native-v9-additional-files.tar.gz").read_bytes() + (data / "native-v10-additional-files.tar.gz").read_bytes() ) with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: for member in bundle.getmembers(): @@ -93,7 +93,7 @@ def main(): with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: for name in sorted(set(tracked) | ADDITIONAL): bundle.add(bun / name, arcname=name) - (out / "native-v9-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") + (out / "native-v10-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") (out / "tracked.patch").write_bytes(patch) for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: (out / name).write_bytes((bun / name).read_bytes()) diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index d9f89f28245..3fea556f5b0 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -63,7 +63,7 @@ jobs: import hashlib, json, os, subprocess from pathlib import Path binary = Path('.native-proof/binary/bun') - manifest = json.loads(Path('.github/native-bun-validation/native-v9-manifest.json').read_text()) + manifest = json.loads(Path('.github/native-bun-validation/native-v10-manifest.json').read_text()) proof = { 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), 'base': manifest['head'], @@ -72,7 +72,7 @@ jobs: 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), 'workflowRun': os.environ['GITHUB_RUN_ID'], 'workflowCommit': os.environ['GITHUB_SHA'], - 'buildProfile': 'release --lto=off', + 'buildProfile': 'release --lto=off --canary=off', } Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') PY From dba3b4e68756764c0266be2dee8e74dc2c24d5db Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:05:47 +0200 Subject: [PATCH 10/31] test: execute native artifacts and exercise helper reload cycles --- .../native-bun-validation/artifact-tests.py | 58 ++++ .../helper-browser-preload.mjs | 21 ++ .../native-bun-validation/helper-browser.mjs | 279 ++++++++++++++++++ .github/workflows/bun-native-validation.yml | 25 +- 4 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 .github/native-bun-validation/artifact-tests.py create mode 100644 .github/native-bun-validation/helper-browser-preload.mjs create mode 100644 .github/native-bun-validation/helper-browser.mjs diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py new file mode 100644 index 00000000000..b39323cbbb9 --- /dev/null +++ b/.github/native-bun-validation/artifact-tests.py @@ -0,0 +1,58 @@ +import hashlib +import json +import os +from pathlib import Path +import subprocess +import xml.etree.ElementTree as ET + + +root = Path(os.environ["GITHUB_WORKSPACE"]) +binary = root / ".native-artifact/binary/bun" +proof = root / ".native-browser-proof" +proof.mkdir(exist_ok=True) +expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) +manifest = json.loads((root / ".github/native-bun-validation/native-v10-manifest.json").read_text()) +assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] +assert expected["base"] == manifest["head"] +assert expected["patchSha256"] == manifest["trackedPatchSha256"] +assert expected["additionalFiles"] == manifest["additionalFiles"] +binary.chmod(0o755) +source = root / ".native-test-source" +subprocess.run([ + "python3", str(root / ".github/native-bun-validation/prepare.py"), + "--bun", str(source), "--out", str(proof / "native-source"), +], check=True) +for cwd in [source, source / "test"]: + subprocess.run([str(binary), "install", "--frozen-lockfile"], cwd=cwd, check=True) +tests = manifest["testCommand"].split(" test ", 1)[1].split() +assert len(tests) == 9 +report = proof / "native-results.xml" +# Execute the verified, source-built artifact. The Bun CI build path ignores +# trailing execution arguments, so a successful build alone is not a test run. +result = subprocess.run([ + str(binary), "test", *tests, "--reporter=junit", f"--reporter-outfile={report}", +], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +(proof / "native-regressions.log").write_text(result.stdout) +print(result.stdout, end="") +result.check_returncode() +cases = ET.parse(report).findall(".//testcase") +assert cases, "Native test runner executed no cases" +assert not any(case.find("failure") is not None or case.find("error") is not None for case in cases) +by_file = {filename: [] for filename in tests} +for case in cases: + filename = Path(case.attrib["file"]) + if not filename.is_absolute(): + filename = source / filename + relative = filename.resolve().relative_to(source.resolve()).as_posix() + assert relative in by_file, f"Unexpected test source: {relative}" + by_file[relative].append(case) +assert all(any(case.find("skipped") is None for case in group) for group in by_file.values()), \ + "Every selected native test file must execute a non-skipped case" +summary = { + "binarySha256": expected["sha256"], "selectedFiles": tests, + "cases": len(cases), + "skipped": sum(case.find("skipped") is not None for case in cases), + "perFile": {filename: len(group) for filename, group in by_file.items()}, +} +(proof / "native-results.json").write_text(json.dumps(summary, indent=2) + "\n") +print(json.dumps(summary, indent=2)) diff --git a/.github/native-bun-validation/helper-browser-preload.mjs b/.github/native-bun-validation/helper-browser-preload.mjs new file mode 100644 index 00000000000..42abdf9a47e --- /dev/null +++ b/.github/native-bun-validation/helper-browser-preload.mjs @@ -0,0 +1,21 @@ +import { fileURLToPath, pathToFileURL } from 'node:url' +import path from 'node:path' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +await import( + pathToFileURL( + path.join( + root, + 'packages/router-plugin/.cache/helper-browser-override.mjs', + ), + ).href +) +await import( + pathToFileURL( + path.join( + root, + 'packages/router-generator/.cache/helper-browser-override.mjs', + ), + ).href +) diff --git a/.github/native-bun-validation/helper-browser.mjs b/.github/native-bun-validation/helper-browser.mjs new file mode 100644 index 00000000000..e5070f698e5 --- /dev/null +++ b/.github/native-bun-validation/helper-browser.mjs @@ -0,0 +1,279 @@ +import assert from 'node:assert/strict' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath, pathToFileURL } from 'node:url' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +process.env.ROUTER_REPOSITORY_ROOT = root +if (!process.env.BUN_EXECUTABLE) { + throw new Error('Set BUN_EXECUTABLE to the native Bun candidate') +} +process.env.BUN_PLUGIN_PRELOAD ??= fileURLToPath( + new URL('./helper-browser-preload.mjs', import.meta.url), +) +for (const [pkg, name, env, fallback] of [ + [ + 'router-plugin', + 'unplugin', + 'UNPLUGIN_CANDIDATE_ENTRY', + '.cache/upstream-drafts/unplugin/dist/index.mjs', + ], + [ + 'router-generator', + 'jiti', + 'JITI_CANDIDATE_ENTRY', + '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', + ], +]) { + const directory = path.join(root, 'packages', pkg, '.cache') + await mkdir(directory, { recursive: true }) + await writeFile( + path.join(directory, 'helper-browser-override.mjs'), + `import { mock } from 'bun:test'\nimport { pathToFileURL } from 'node:url'\nimport path from 'node:path'\nconst entry = process.env[${JSON.stringify(env)}] ?? path.join(process.env.ROUTER_REPOSITORY_ROOT, ${JSON.stringify(fallback)})\nconst actual = await import(pathToFileURL(path.resolve(entry)).href)\nmock.module(${JSON.stringify(name)}, () => actual)\n`, + ) +} +const projectRequire = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +) +const { chromium, expect } = projectRequire('@playwright/test') +const { startDevFixture } = await import( + pathToFileURL( + path.join(root, 'e2e/react-router/bun-basic-file-based/dev-fixture.ts'), + ).href +) +const output = + process.env.HELPER_BROWSER_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/helper-browser-${process.platform}.json`, + ) +const logFile = output.replace(/\.json$/, '.log') +await mkdir(path.dirname(output), { recursive: true }) +const log = [] +const say = (message) => { + log.push(message) + console.log(message) +} +const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => + [1, 2].map((depth) => ({ ext, depth, dynamic: false })), +) +cases.push({ ext: 'mjs', depth: 2, dynamic: true }) +const results = [] +const configSource = (file, dynamic = false) => + file.endsWith('.cjs') + ? `const config = require(${JSON.stringify(file)}); export default config\n` + : dynamic + ? `export default (await import(${JSON.stringify(file)})).default\n` + : `import config from ${JSON.stringify(file)}; export default config\n` +const configValue = (included) => ({ + type: 'root', + file: '__root.tsx', + children: [ + { type: 'index', file: 'index.tsx' }, + { type: 'route', path: '/about', file: 'about.tsx' }, + { + type: 'route', + path: `/virtual-${included}`, + file: `../virtual-pages/${included}.tsx`, + }, + ], +}) +const helperSource = (ext, included) => + ext === 'json' + ? JSON.stringify(configValue(included)) + : ext === 'cjs' + ? `module.exports = ${JSON.stringify(configValue(included))}\n` + : `export default ${JSON.stringify(configValue(included))}\n` +const sha256 = async (filename) => + createHash('sha256') + .update(await readFile(filename)) + .digest('hex') +const browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), +}) +try { + for (const scenario of cases) { + const name = `${scenario.ext}-depth${scenario.depth}${scenario.dynamic ? '-dynamic' : ''}` + say(`START ${name}`) + const result = { + ...scenario, + passed: false, + steps: [], + browserErrors: [], + documentLoads: 0, + } + let native, context + try { + native = await startDevFixture({ + virtualConfigFile: true, + virtualConfigHelperDepth: 1, + }) + result.pid = native.pid + result.versions = native.versions + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.__helperBrowserDocumentToken = crypto.randomUUID() + }) + const page = await context.newPage() + page.on('load', () => { + result.documentLoads++ + }) + page.on('pageerror', (error) => + result.browserErrors.push({ + type: 'pageerror', + message: error.message, + }), + ) + page.on('console', (message) => { + if ( + message.type() === 'error' && + !message.location().url.endsWith('/favicon.ico') + ) { + result.browserErrors.push({ + type: 'console', + message: message.text(), + location: message.location(), + }) + } + }) + const heading = page.getByRole('heading') + const goHome = async () => { + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) + } + const checkpoint = async (phase, included) => { + await expect + .poll( + async () => { + native.assertAlive() + const tree = await native.tree() + return ( + tree.includes(`/virtual-${included}`) && + !tree.includes( + `/virtual-${included === 'after' ? 'before' : 'after'}`, + ) + ) + }, + { + timeout: 15000, + message: `${name} ${phase}: automatic route-tree update`, + }, + ) + .toBe(true) + await page + .getByRole('link', { name: `Virtual ${included}`, exact: true }) + .click() + await expect(heading).toHaveText(`VIRTUAL_${included.toUpperCase()}`, { + timeout: 15000, + }) + native.assertAlive() + assert.deepEqual( + await (await fetch(new URL('/__native-info', native.url))).json(), + { pid: native.pid }, + ) + result.steps.push({ + phase, + route: `/virtual-${included}`, + samePid: true, + documentToken: await page.evaluate( + () => globalThis.__helperBrowserDocumentToken, + ), + documentLoads: result.documentLoads, + browserErrorCount: result.browserErrors.length, + }) + await goHome() + } + await page.goto(native.url) + await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) + await checkpoint('ts-bootstrap', 'before') + const helper = `config/browser-helper.${scenario.ext}` + await native.save(helper, helperSource(scenario.ext, 'after')) + if (scenario.depth === 2) { + await native.save( + 'config/browser-bridge.ts', + configSource(`./browser-helper.${scenario.ext}`, scenario.dynamic), + ) + } + await native.save( + 'virtual-routes.ts.next', + configSource( + scenario.depth === 2 + ? './config/browser-bridge.ts' + : `./config/browser-helper.${scenario.ext}`, + ), + ) + await native.rename('virtual-routes.ts.next', 'virtual-routes.ts') + await checkpoint('helper-graph-loaded', 'after') + await native.save(helper, helperSource(scenario.ext, 'before')) + await checkpoint('helper-in-place-edit', 'before') + await native.save(`${helper}.next`, helperSource(scenario.ext, 'after')) + await native.rename(`${helper}.next`, helper) + await checkpoint('helper-atomic-replacement', 'after') + assert.deepEqual( + result.browserErrors, + [], + `${name}: unexpected browser errors`, + ) + const serverErrors = native + .logs() + .split(/\r?\n/) + .filter((line) => /^(?:error:|panic:|thread .* panicked)/i.test(line)) + assert.deepEqual(serverErrors, [], `${name}: unexpected server errors`) + result.passed = true + say( + `PASS ${name}: browser navigation + automatic tree updates, in-place/atomic, same PID ${native.pid}, no browser errors`, + ) + } catch (error) { + result.error = error instanceof Error ? error.stack : String(error) + result.serverLog = native?.logs().slice(-12000) + say(`FAIL ${name}: ${String(error).split('\n')[0]}`) + } finally { + try { + await context?.close() + } finally { + await native?.close() + } + } + results.push(result) + await writeFile( + output, + JSON.stringify( + { + platform: process.platform, + node: process.version, + passed: results.filter((result) => result.passed).length, + cases: cases.length, + results, + }, + null, + 2, + ) + '\n', + ) + await writeFile(logFile, log.join('\n') + '\n') + } +} finally { + await browser.close() +} +const report = { + platform: process.platform, + arch: process.arch, + node: process.version, + binary: process.env.BUN_EXECUTABLE, + binarySha256: await sha256(process.env.BUN_EXECUTABLE), + preload: process.env.BUN_PLUGIN_PRELOAD, + passed: results.filter((result) => result.passed).length, + cases: cases.length, + results, +} +await writeFile(output, JSON.stringify(report, null, 2) + '\n') +say(`RESULT ${report.passed}/${report.cases} PASS; evidence ${output}`) +await writeFile(logFile, log.join('\n') + '\n') +if (report.passed !== report.cases) { + process.exitCode = 1 +} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 3fea556f5b0..6533923192d 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -120,6 +120,17 @@ jobs: with: node-version: '26.10.0' package-manager-cache: false + - name: Checkout matching native regression sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/bun + ref: dca7d25e95cca39316c659a377dba6803805549f + path: .native-test-source + persist-credentials: false + - name: Execute verified native artifact regressions + id: native_regressions + continue-on-error: true + run: python3 .github/native-bun-validation/artifact-tests.py - name: Install Router dependencies run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' - name: Checkout actual unplugin PR source @@ -195,6 +206,16 @@ jobs: echo 'Installed Jiti also passed the helper cases.' fi "$BUN_EXECUTABLE" --preload ./packages/router-generator/.cache/helper-import-preload.mjs .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-candidate.json + - name: Imported helper edits in the running native browser + id: configuration_browser + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + UNPLUGIN_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-unplugin/dist/index.mjs + JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs + BUN_PLUGIN_PRELOAD: ${{ github.workspace }}/.github/native-bun-validation/helper-browser-preload.mjs + HELPER_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/configuration-browser.json + run: node .github/native-bun-validation/helper-browser.mjs - name: Upload all browser results if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 @@ -213,5 +234,7 @@ jobs: PRODUCTION: ${{ steps.production.outcome }} DEVELOPMENT: ${{ steps.development.outcome }} CONFIGURATION: ${{ steps.configuration.outcome }} + CONFIGURATION_BROWSER: ${{ steps.configuration_browser.outcome }} + NATIVE_REGRESSIONS: ${{ steps.native_regressions.outcome }} run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success ]] + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success ]] From fb30c95cbb3b10b007d1bb5a55ce7041f9660c6b Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:13:23 +0200 Subject: [PATCH 11/31] test(router-plugin): cover restored virtual routes and atomic config saves --- .../bun-basic-file-based/dev.test.ts | 60 +++++++++++++------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/e2e/react-router/bun-basic-file-based/dev.test.ts b/e2e/react-router/bun-basic-file-based/dev.test.ts index 2f2114a328e..1c603efd326 100644 --- a/e2e/react-router/bun-basic-file-based/dev.test.ts +++ b/e2e/react-router/bun-basic-file-based/dev.test.ts @@ -543,7 +543,7 @@ test('repairs a syntax error in an active route without restarting the server', for (const virtualConfigHelperDepth of [0, 1, 2] as const) { test.describe(`string virtual configuration with ${virtualConfigHelperDepth} helper imports`, () => { test.use({ virtualConfigFile: true, virtualConfigHelperDepth }) - test('updates existing browser navigation after an in-place config edit', async ({ + test('updates existing browser navigation after config edits and atomic replacement', async ({ page, request, native, @@ -557,23 +557,49 @@ for (const virtualConfigHelperDepth of [0, 1, 2] as const) { await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') const token = await documentToken(page) - await native.save(native.virtualConfigPath, virtualConfigSource('after')) - await expect - .poll(async () => { - const tree = await native.tree() - return ( - tree.includes('/virtual-after') && !tree.includes('/virtual-before') + for (const [included, atomic] of [ + ['after', false], + ['before', false], + ['after', true], + ] as const) { + if (atomic) { + await native.save( + `${native.virtualConfigPath}.next`, + virtualConfigSource(included), ) - }) - .toBe(true) - await page - .getByRole('link', { name: 'Virtual after', exact: true }) - .click() - await expect(page.getByRole('heading')).toHaveText('VIRTUAL_AFTER') - await page - .getByRole('link', { name: 'Virtual before', exact: true }) - .click() - await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + await native.rename( + `${native.virtualConfigPath}.next`, + native.virtualConfigPath, + ) + } else { + await native.save( + native.virtualConfigPath, + virtualConfigSource(included), + ) + } + const excluded = included === 'after' ? 'before' : 'after' + await expect + .poll(async () => { + const tree = await native.tree() + return ( + tree.includes(`/virtual-${included}`) && + !tree.includes(`/virtual-${excluded}`) + ) + }) + .toBe(true) + await page + .getByRole('link', { name: `Virtual ${included}`, exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText( + `VIRTUAL_${included.toUpperCase()}`, + ) + await page + .getByRole('link', { name: `Virtual ${excluded}`, exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('NOT_FOUND') + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + } native.assertAlive() expect( await ( From c7911fb3e45247c9d506ee61b3b5bd21e703ba3a Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:34:59 +0200 Subject: [PATCH 12/31] test: isolate native Jiti validation from the Router workspace --- .github/native-bun-validation/build-macos.sh | 7 +++---- .github/workflows/bun-native-validation.yml | 10 ++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh index 53259742028..d4cbcee1e20 100644 --- a/.github/native-bun-validation/build-macos.sh +++ b/.github/native-bun-validation/build-macos.sh @@ -51,7 +51,6 @@ cd "$repo/.native-bun" bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" -# Use the official build-and-execute path. No timeout wraps compilation. -read -r -a native_tests <<< "$(python3 -c 'import json; from pathlib import Path; m=json.loads(Path("../.github/native-bun-validation/native-v10-manifest.json").read_text()); print(m["testCommand"].split(" test ", 1)[1])')" -[[ "${#native_tests[@]}" -eq 9 ]] -bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test "${native_tests[@]}" 2>&1 | tee "$proof/native-tests.log" +# The CI build wrapper does not execute trailing arguments. Regressions run +# against the verified binary in the artifact validation job. +bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 6533923192d..8082a31e8ab 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -49,7 +49,7 @@ jobs: with: node-version: '26.10.0' package-manager-cache: false - - name: Build native release binary and execute all nine suites + - name: Build native release binary id: native_tests run: bash .github/native-bun-validation/build-macos.sh - name: Collect binary and final machine state @@ -190,10 +190,12 @@ jobs: package_json_file: .native-jiti/package.json dest: ~/native-pnpm10 - name: Install and build actual Jiti PR + working-directory: .native-jiti run: | - pnpm --dir .native-jiti install --frozen-lockfile - pnpm --dir .native-jiti build - test -f .native-jiti/dist/jiti.cjs + [[ "$(pnpm --ignore-workspace --version)" == '10.30.3' ]] + pnpm --ignore-workspace install --frozen-lockfile + pnpm --ignore-workspace build + test -f dist/jiti.cjs - name: Imported virtual configuration helpers with actual Jiti PR id: configuration continue-on-error: true From d22bc91a7a50812641036bdbce076b97264054e1 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:36:13 +0200 Subject: [PATCH 13/31] test: record canonical module paths in native macOS validation --- .../path-identity-probe.ts | 63 +++++++++++++++++++ .github/workflows/bun-native-validation.yml | 2 + 2 files changed, 65 insertions(+) create mode 100644 .github/native-bun-validation/path-identity-probe.ts diff --git a/.github/native-bun-validation/path-identity-probe.ts b/.github/native-bun-validation/path-identity-probe.ts new file mode 100644 index 00000000000..0627529087c --- /dev/null +++ b/.github/native-bun-validation/path-identity-probe.ts @@ -0,0 +1,63 @@ +import { mkdtemp, mkdir, realpath, symlink, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { dirname, join, resolve } from 'node:path' + +// Public API diagnostic only. Preserve the tiny fixture for artifact inspection. +const base = process.env.BUN_PATH_PROBE_ROOT ?? tmpdir() +const directory = await mkdtemp(join(base, 'bun-path-identity-')) +const source = join(directory, 'source') +await mkdir(source) +await writeFile(join(source, 'entry.ts'), 'export const value = 42;\n') +const alias = join(directory, 'alias') +await symlink(source, alias, process.platform === 'win32' ? 'junction' : 'dir') + +const results = [] +for (const entrypoint of [join(source, 'entry.ts'), join(alias, 'entry.ts')]) { + const loads: Array<{ path: string; resolveDir: string }> = [] + let exactPathHookCalls = 0 + const exactFilter = new RegExp( + `^${entrypoint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, + ) + const result = await Bun.build({ + entrypoints: [entrypoint], + write: false, + plugins: [ + { + name: 'public-path-identity', + setup(build) { + build.onLoad({ filter: exactFilter }, () => { + exactPathHookCalls++ + }) + build.onLoad({ filter: /entry\.ts$/ }, (args) => { + loads.push({ path: args.path, resolveDir: dirname(args.path) }) + }) + }, + }, + ], + }) + results.push({ + entrypoint, + resolved: resolve(entrypoint), + realpath: await realpath(entrypoint), + exactPathHookCalls, + loads, + success: result.success, + logs: result.logs.map((log) => log.message), + }) +} +console.log( + JSON.stringify( + { + platform: process.platform, + arch: process.arch, + version: Bun.version, + revision: Bun.revision, + tmpdir: tmpdir(), + tmpdirRealpath: await realpath(tmpdir()), + directory, + results, + }, + null, + 2, + ), +) diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 8082a31e8ab..3a7e5133ac3 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -131,6 +131,8 @@ jobs: id: native_regressions continue-on-error: true run: python3 .github/native-bun-validation/artifact-tests.py + - name: Record native module path identity + run: .native-artifact/binary/bun .github/native-bun-validation/path-identity-probe.ts > .native-browser-proof/path-identity.json - name: Install Router dependencies run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' - name: Checkout actual unplugin PR source From ad9f1bb0f029485f6339da141d53b174b237f1db Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:45:53 +0200 Subject: [PATCH 14/31] test: validate ordered HMR updates with the native Bun candidate --- .../native-bun-validation/artifact-tests.py | 2 +- .../native-v10-tracked.patch.gz | Bin 85991 -> 0 bytes ....gz => native-v12-additional-files.tar.gz} | Bin ...manifest.json => native-v12-manifest.json} | 21 +- .../native-v12-tracked.patch.gz | Bin 0 -> 88090 bytes .github/native-bun-validation/prepare.py | 13 +- .../pure-bun-graph-browser.mjs | 529 ++++++++++++++++++ .github/workflows/bun-native-validation.yml | 22 +- 8 files changed, 576 insertions(+), 11 deletions(-) delete mode 100644 .github/native-bun-validation/native-v10-tracked.patch.gz rename .github/native-bun-validation/{native-v10-additional-files.tar.gz => native-v12-additional-files.tar.gz} (100%) rename .github/native-bun-validation/{native-v10-manifest.json => native-v12-manifest.json} (51%) create mode 100644 .github/native-bun-validation/native-v12-tracked.patch.gz create mode 100644 .github/native-bun-validation/pure-bun-graph-browser.mjs diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index b39323cbbb9..a26ae1ecec5 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -11,7 +11,7 @@ proof = root / ".native-browser-proof" proof.mkdir(exist_ok=True) expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -manifest = json.loads((root / ".github/native-bun-validation/native-v10-manifest.json").read_text()) +manifest = json.loads((root / ".github/native-bun-validation/native-v12-manifest.json").read_text()) assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] assert expected["base"] == manifest["head"] assert expected["patchSha256"] == manifest["trackedPatchSha256"] diff --git a/.github/native-bun-validation/native-v10-tracked.patch.gz b/.github/native-bun-validation/native-v10-tracked.patch.gz deleted file mode 100644 index 18f7009b26d0cf4aaa2866a02155d9aa14f5e239..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85991 zcmV(yK;r6k@3Aki|9x*VPqM#rP9~555+Eqa-7`I(qq`&lc|+#O zbHDV5gMm}4T@2?==jl;rb}?~Blip{iYy7b`9QXaNPQB4>>@}Mm*R6MZySv@`rqig` zceb|HYPDLd_gbY=iI4Cv|KijdyPJE}9jC%ScO5+H`%@o7k9$KuaGpCK*BocPyBK@Z z`E0$a{|Nl6FTVNrO@Kct^2cH}ir)M!nD^zc;Honkeerwp*ZguA__NuB2I-sM+n@A; zr|8)q`Ln0~SHHKIce*1#aIgAbvHrZ*YEL@#?cJUFVBor4zus#!nw|Kb% zZL_|E?W)KRJa~CC_j{AR@AM{D)8VKyA5O;3)#MBIaN3y#!|{cKKW3MHr|%3VGiQWj z@SWj!x|lnIAx3rvv&oe+Ta4$!E8m%~Icv^`OW$eNYFESYaB$Oh&|`7skLS+J?=O1j zF~|F0_&48~4EXo?tTPTUx!-pti#d%`bSlVUL$rb?6M7UT5qCoiDy~ z6$Y3#Of(>dNQl&&;kt)xlX^4KFU|PB0&iM$YhRI>QIzug+}l@Hb$};e0;w zU3^PTeM>M|%zFM+XKH+of7SK-0h)&|c@t-T5a3I$hx1E^fT)W1SaAm(2y6o9F-_L{ zjIXB6m`;WmYfer4;mn!Lh8M$eXXF6VWy#p=U{2eg-Ywn6bzUyUxB%hwGzos0jK1jY z4wu+j%qLgq)x+l8IM<}%G02<#hp-sfr@W#kq_vu=UeYK&!Y@@^b=!`p8>QloVl=blkxW;Ads(Wsp74gw!>L?QtdmZlYCJ!h%zUTBOCMu7ep!u)Sun^< zFHZHwSL(Ul_!~N|hQHU_+uqH=%~59yR*qg0KHlBgAu>ik_6Q%JPyOC-FjS{H zznLCv{uyb2AFuhN{Ep9{Brn=fao64=#sO zT6|kRiRT{sUm0`I+ypJSMT7^`?Fo!4rLU2iINXpb5d3F=XdsjKC!mjVPozoE)>udN zb-U;<&Gp+CFw`*becqKeP%o3~ey&NcvpV7krk`B8^%gSt6wCnDo~ z-z{^?>h)$5VeAqaYxg_zPOI(UEUNS;wbg&By#}_P`E=#K_zD{v$Lu;U_|tjYd0T0# zobd#>$-AK@4zK({XE6d)4?3g3Z@Y0Upumi;WsR;G z|K|2xKvg&It-=S}`<>4AX1(XSyW4xcZf7&WtL2R#NFlEUVTPT}y=_7b{IgLP7Pkj( z2p@`V#P<@Py6$`fSL)o-jyM8z1ELJ4<2RE||I81t1?LRaM}&00f!D>qryCp2i!LbT zLIEd(LI4zsE9CSpJL3z6Xds4Rp8%LSE;TLCJ{?%!|Kg7(QwBM3#2^>0v+-2MzwXR? zm#+yle{2EdXE^DPpPb(vpg?~By3jwctfN1i`Mvps5sNHjc%?58CIL0dUzqE>n-G&p z)Ew}fSk0^9EPFAIT8#YSZ18wEKCJ3(cnmi0;uXuX8oY$obcag{O23c=~ip(UwgxG z2{>uoDOcmY)8No*9lw45;V+4H24uV=c|^`n|FfN;G>Z))=jN$x@_->afj1d=@(C>m zpxSD^JAHSY=m!R3jxT$UAIrZexVh?1MreM{zgRn@Z~^Ijuwnkwf!~=gX1+HVbuNMk zCuF`?xM9<;cl&$&P1kKSyE}tHZ;-|f*<(aFBD)QP28juk1`!;ED{$R$&t9FJzj*oP z*gHCX`~K|s{QTtfop(|F;-uu&2H2Ent4PT-&pRm_8YiELB;cH%zXiAKt4H@6y)-$aIJPk?k?p=bZ z$0=Knm?bb=qnE__gBqI0n|`N`cB`}B+-Y>0K>PmQ_U53!V?A0+|Jbow-m^w-XTRFm zf=Z5lHjVpUb)Iw=S5vel|vUKqTVU!daC;e~Li7nI( zpxpCIkOJxB%0B|?mW{8F5DB?~J6!~qrJq`@_e$i&zSfHD>u3K42xfBSm+)CYnUFo^ zrD9#_-!X_9vpK4#^_zgF3J+-RP_bTxhX*6K@KYb_3GITeVpgK9ubN9JJhtm9Ijz-F zM4?n(-t)G65GOyyj`_l$gJkoQ((?WxDAIka7He<7LctS`?b^z-m8(&H;qND**B5(2TBdpwMX$EC8X zHGG&%&05YuYxhEDRy39b-R`=&o9lpAI+#LNd^y^PwzTM&tD%crG;tsFP!uh!yr+f7 z%iqQ&!{~N7&2n#f;;x?KS3vd%BbM?n(s`@(2GZiF2=nq8SgA!l{*``d{p%5NkyTN- zH1?|Cn06Yw)#l#H_y9igO7(Y!+BO2;h~$*fBwj7S(bdza%h{dq~Gy)%QmJz@D}o z>{;2V9Xj!Q&1W~l`n!|j3X~1+T5InYLkX zRFjwZHLIDv6%ZOp0PB#%DB>{fp-7K}o1?AHyJOi`>o()L6|Ys6^-lgBpSNr-F?)jB zwaP7N*GYjEemmswgKPonr&(uunU+Ei3i%ntIw8Rv? zV)?hxWYq|MB(-HHWI!N&roQL&ZZRJI`@;7CdmfClUZ>w55-@=aV`GT(a`N@r$Hm^K zDxr)QbU6+UWf-Z_h&Gdo#NL0gvt_hrQN0zd-IfIt4NN4#D{aYTHXDuS=sOkE`%_$&MwH6{L~>eKDESH4IyL3e>_WcyQMoG~P$I zPkcO3{$RzCuR~@lSn(1EvQ5?QScs8FTM^ZMbb+z8unCt966`CqE=R=Mz zWO{?g8lJe(G0TWA#5%~XSD~AR8kV=K^O=0(#;_NSu!~^T^jkLAh_{5B23d7h!@gYh z7lfvM1}?#cezw?b!j*2bd59A?UofYX3DTr=913KsvyFkU)=9>C|Hd)~crNnZg4Fcw zuVcsg>pF}m0ruvv>n&%qDv#8)p+_IrO@SGD;z#iXxWmAM&@^YhKQ2F7A>EeT`QhDkJX|+Di6<4*-Gy%U1NJrY6ovT@p@ndx{&jDjH**7MMEWdTI3cJ znqSQQY|%MkDRrY0QRc@X7$*)V!6MTH7n7;+?XozCG9HKusYZCD*s9dFqn|sN0Iz!N zFhcNdVZaF+498>vh;z5`KR0MFmKw;V7t6`~Vm4SVrm`1}df^j-* z%N&tQ6Yg$zF~BXhj#TQC)_@#=SZzb@F!QpT-ZwfJ0bjXr&z;|YgUCmZO=18qm@dhY z^Gn)M(hs7M5Ox5n&}y=j{BDz*X&!u!bPpi2z^Nn)C?Vm_Z`9aW3{Hr8xoVR1WzheU z;}bCho^Q1b8ld--8A zFVs~Nu~5{5)=#5 zrbc3$^P0A-auVXOo$ z26wBEu8%C6GH1{<%Olp=Cy%6@v%iGSLpe8fn6BD#k_Bh0Z=O0aKA@_aMjyp$ADZ>& zZJs>(DK32;iDn}dLJcIFmV^05nYxo0*@D`S6(l)wY;1rWp*Fc_TC$VA_VH#J$i%An z`IxgV2+7esvZGAn`erm(jIW_n0vX5Z*OOM_atf*DG7$0AWpNY9J*#GHnq}is!ubG> z&2v3v=3Hzx#u5TiKJ z_t~xH$uCe|giGdD%S{e=duu$nU8a^WZ$olJ9+o_qTmLA-l$~=25|d_|xR-+aa*$VG zUn$r--Oy&gyc1%V4Y4Bj*j@#Cql)7B@F46!bXQcKhZ8k2SKK!1692lsuKbW1n{3Ic z;OB02ueef~xBJJKR+B$+=6~^sC8H$}C(Ep=8$L0A%q9G+-U6T9MKA%B#!9?Y21~{QtVT{KyYd!S$y!}{H^c}Ahwwq*&%+%V zu-jayXjiRL`$=qAd>K&}`0itepR*o7(g$qUC4Ip5rV83&(`9I~dWFzA^9+ghju5E> zH&=MO!lnlK!ZeX2&s%&+4%Td7ii7wN4=&X4lu;lYo<;^@%~iB@kfE{r%zTChokHfE zkFn#4kmQgQ@mCi9Rewyy$`M6;4FtM#t>}E5zbb9C%2>-m%xuD@O^&0~26T!B_Gj3k z7v~?G&L|8)k*idqZKB|RC~S6)sFJ2#i_)81tLDsD+L`z_7 zaUJ7$6S7W$&a)Y)zaW9lVc7}49KdBAF`t*TmI;LM>(t%Cx*G&H6w zdK#k}6fcujjhQz>g%DsWG9EK#d!>&B6CebfB1>%5Ogpp$H1<%oDfLkLZ{F;9wkis_uwZDXc z@|FJuo0{nu@SecyLnrv0b_y_GDTjbYuUYR6nh4k!Y$2GW-p}zoigiyr1H@i4nAGM@k;xM(c_Cz{g^nkM&=%Uat!uUG2ox`{pm#HT%sa2}vf+bm2x}XO>>`>Uj ztKr`ypgD9i(zB_)%3fr+tWiK;CGt8t2O4RIUL6ER@iT8%Rq&jO(-c(10rj|EJar{8 z_5EByD(0R9aAXDfGXu@T&|8k0BWJ`8C&8Ezo~`l*AwHfXM%&BR=BXKCYb3p6Y48$bnp}5GJS)pU|TW-yLuzgW=btyUjA^9@cNriM?UAgAD9O zZ#eaMoiW^og1}>b4p;v13nV!i_I`zJKDy<$z&svW?MCG8XvA2uw<$%TwOV4RC(J}Y zpZ#*qL5RXNAHwlyd?PC6*tb)FGWQ;k)9IgPpaO*5J;L3*nLD(Ll|5v=5aw&yZYE75 zM@&)MPunj>lw;uLC12Nmn?u1=f{>c)>Y?vfJ_lJQw`^4Z;f&)km~q?A0hF}XhIi!p-)QO-xDbp;dxqzYti zhW-fQz_O~R@i`!NGsW0#P;7Ulx!c?<2<`^UIValFo5P(J=pKl~;jnr}f)Su%Akdpq z$Vs-J%wncJVv}efj|O@k@sE1&5;KNza|DM#dz^vhIZ+~{m5ClDxJX=h&*pD7=YG*M z=MfJj-j5+o5KM%)U#MZ?jDMR4;0WsWW7$>3(Y4FOclRm3$dm%jnRan{mIK}w;X9odSUps)rVwq;er5pGm1+0I4xF* z2a^wjDG|X=ufhQE7Pl*L!iP}(g+_Yn0|ob+>@wNh-P$ZhGvlnMfU6tP$!dlh2Ax1Y zHO=Z7P9m}WZknoQ;N8deQ@6}hUbC5S=)gpq0HGVRr4lwhxVTc6Vj-_rR!b=I#EPK?jhBi5*q_DZ?J6L?D`-D>Ab7X&$;q#;8bw z@Gwj%7xyx4LI&cnQY@7VBE@^QXeVW7AUb5Q2G`gU({5~9~kl4o%I zG4~w`ShD!{wX~TEo_%BXWS1k`6VYO?z9%}00))owPo_gokH zLw~nF=w_d7tb6(}W3N>N&5i^XZ0|%dO?2zKUz#2(r4v}ihMZH>_~WO0wa5{DUD)u!PnXtDPv5R*8#lAG7sysSoIjydijoymCzz@dwMP=v1u|Pw z($?WT%tbY46(mW;k^pl|df1VhImHLXP>^j9qjkw1NMR_SGr9~1j&+Zf25q~($L7=R z`u=XUu~+ogu`nP2sz3y}5;_z~w-~b_+2S&JyYl5#ShU0$Mdb?DvXoDpqqY@Cz9ybk z8q1l@G=2XYXd;n@1n z*?@?@?Z)8n$Se4>h>yd#KT23n31 za5@|U?1~agnUl#qf9c3G&SXD^&Z-L@nAGmDqlvtrZIX1*k~|nk3VwO%nDXI$B}$TF zi~u*v)s7*jN|PjayhFZ+`MX50G3bk_3{OIiD{fE=D z^CG9EwQu4t&9-pLklJdo_qIexc+&~x>S2UdET`G&*!c`02`NB;)#hZi3{>V-vMqE( z!z(bi(-byxXDg}L%>p`%&(3~fP$n$?9GM9r2E43NLkT{Iq$J5Kk)UaQjj9u%7%x)8 zwXgiE-t>l3R=1;$Wy!4EJ_-VM`a$ZCfHbLXd=PI&o3nSPhU1KkWOQTQfq*0N4I()@ z6!+$)+=?RWqMI@<(g4J5@CRIQQiB>LHK;O_bJl{yfTY?^>6pkLFp4Z*?qMLAlx%dA zJ|X4g=F)kjz0VUk)dG_-*G(FP1YGh^3bG)$^am1wO$ScS1HZT1;6(6y``bCpQ6`R; zY@aFzzG6Rs(nE`KnEW({!OGfO8BTWeqiCjMo?M^8cwU9zGbj{!^2F@DItwa?E>k{t z$&)@A%!y#(zW@ZJ!uXRoc~Y9+iMyPoQZtmJRb}Z6)Tw6^-p7w+XAGPbc}Xqrrf8Ny zPT-WIR%h?MgzxhdtC-Jpn9G$@Thd<4noFC}chCuW-5V7kgKS697Zvx7Qn= zzYhgsCtJg$I;M3?>V>2p5v9`BPTcY$1V%XI14_55lC!F8GN3g;XF*V7wYYORnS6GE zT52lYveY+Gp>b?sqiQjdXh&raG7PVhxjPWYql2{wpJ^2s0LJjVpjXM0La!e_s>q!6 zWL}Q-Pix8V>d8wFk78Z5D-w5-l!ELINSOu0)GUx}r*vsxP{3$jn4>+Gk_F0DAT3(I zDCJqxI_L~XNYz_{;jE=C3T&vWI=s`+d=h2gB>zZ|MUSE|<1o}4P}XubNx3}xfdcC`uhlp36#D=t2 z9z-12t6NR-U$1VnsgPZ+1Y**-u+{n&L!MQK#;3gK(QlmL=9X!~Q^~_kHPnvJ-&PaZ zXtY`&AirzUE&7xiAHqdTx;0$#XeJQ!h^v@#xqx;hA|>p6Mfx3x8jCU3NcSCn z?KK*r>5`+nbp*J-%(%V=JH4`u(-C)R2&ipUWCAJJyDk{SeM5^5o1XEX@3_@?>^&ajU^_u2i~T& zreWsG7h{5fu&hWRYoz6nV5$Nv04O1NXq$6lT{0Rij=)pdqPfJ?H8f3^By;Ne5ywYw zU#K!;YFg@|Dw0upqzkT;zys<+4L;SR>-qz#KL!U5{d_WDu|ge4@1}=mKE>fP{9a7h zR*oD^k_(ih2C!PZlpK%ks63HyJM#6MML|#IwAlr$Z32^w2S^>VGj`Q!Qxed{l&YbK zV|P0om|v+}p%6J-T<0<}z*xD=KF_vrAJ#k8x6I@4<`}CPe zJsMS5k50TI;Nv@bVpT^a6vQM?X`t#nX;G{k?MDC*W1lHnii{U+EMFgF%2W^ttzuMD zV>mXdbI6I1MkU~~i(k}GQMnAYFr&Cud%PHpjFT||pDwX6Je3-Y!3jg=Fi^E0Cu5_a z9^g5cOvXAtS4jMCV*4y-p%9((AOG|JLLx67`YBSrQp_*a9ev7qx#*?iJW)<_jVD#7 zfk=DEP*g|M)})Ch$f~uDtbi1g-yeR-YPpG)^(t}iUBV%xF9}i3Oi(EO11Ip&3DXSo zpZI?X0H-Y+j2+eBgjhf7)mF9tUo-q|lf--iR)xL}^hDB~-b}{7GK_Qi)k^*{G;nUH z1$|Sv+E`8AVh;59(d_2^k^-=13n*TsFMoSUk4?@?^0->0eRIY3o0;uDS-!wT1C*FJ z^gYsOfjy7RUW|LxvrYAEwL@f7Uo-oY3@{myvi_p9ex-5gdN@Xd6agh;bQcg?!W^5N z5yo7eqQ}N}#os&n6I96((wPw+Q~*s&QD)se@9PltP&X z)YO!4GGSDydb7pvJa;U5y ziKb!ABkEzBMLUQouN?Y98cKI9nP0(uR7UfNH8F~W;RGV*=Cy>gsMwNVuI^=LA2k*z z0zGxeQbw0_NH!dKn%g7?)vKG$L^#$Rq26ko%~TdD#WvBah--OH=sKrl121Pur30(T zvZRm7@dF_w(q7!e^YbsQtzzWpFIEVL)4=~0Xw?h4s*L@AghwV@DSZkmBRgdOZ^gz` z@Q<|Zukf1`@S=D*mHPSdNA;%Y8jUI^aDr366yA}zZkTY@YF!Wm7h;T6RvfCaf8e-E z;HeP87~!lo((Q`vDf$QOB)e{sGdv}0BG#Kk8r<9{zl2eBqVNQ(v^6UQ5Xvgr_x96w zE<#jb^r+HCEx)GDj|cgdA69uhcVbt$Qt%pA9{37Z9`O2B?sau5t6kg5U9W8AL9T0M zg{xZmp4YTe@QPOMcs(nHu4d&<*Rpb-jVn_4Cg&nj!NHK5TLKkIW0TS%k`%yYvAZ|S zuPbHE(!sP0r8G0_pfM!AEYQ`sl}3tnV@n2O8Nn6ZlUgA=YLH|CXVLLwp*(+7z3-(1 z3b(-$i6LFK-TaOzo?hw+5&FnGhUIDSLLSS`MP=|wJZ~N%&Tz52&B^Osl<{rl z+pA*hkj7+}VoG;V8f|y~`!K$;gQ{X#%uayB8lvL=lkDqz-qxz4tF}2yGcwgukyv@N zos5mi&RN~AC#zb5y1rTS14maE{ux6q%;cp-8s6!uDI;cPs!Dez3Qc%W??YuZ(7odp zEKg2+Yb#Q+rZ*;(I8`oDNtawpNH=kb#v;KKky!2|p)8X~9zp_n2#Mov5=H@uqDw+O zS$_%$4=g1wsbW=(D~`ZIYVTm3s-zfu;}qb2i?pGT+h9r*u_dav0)5B@Ye;F0IIovZ z;#0d1vmWVgavJ7+&(eBkTBD?BBcYyIOs|x#efDZHx1kE1l_%0qS@;W$$eReGqDwJrcH6ry6#W$c1N8lRl~+Ejy0o$D^0e*c1)Fph%kxb z?|m*O0`=@EtYQLh(Fhw|#u`Ga|U4bGAp#R7p#QH2d6m)_#y5SrD~1e~b5Q>1$u;P0j- zSSH6g_eVNeSSMS*QB0pC{!KX zy!E;FX35R3<%dfoZ-1>om2$xVg&2lAVS(lMx$qF_JN*yV{^iosB6=2%?W5Ltug4qE=c98@g- zYo<<0Np4I0C@fm5&~=G@)Wm&=5}1Y>CT(UG2Rz0;xqPQX1l+CW%vP~GT2xkWu&CVCv7(Y=iOp0CWC{#& zeF|7O3-g9|;SpEi7327*yn+eSuFfmmeRXzmRXb}T_Hh-vX;KfkL{G3x2(pL?wH3gi z_D~>@6c=iDIenYRQ2Rb`uv(8iXjuv&X%7zrmD;UBihI8Y2F$>IMKRxpOZ85FZ*6U* zsMk)C8s(jGzUR(&XGeehyI?pA|N3LPV%e=$!^DzLP-D_lr+ovAd*AoFiwlmto}s=~ zsJ}6}UwQiPoQxqep^il;)(-gN$UqhtS(17E~F|7&lw zpwzf3PU?#zz9dg5mM%=%B@xmpUM`F`yNczaLrT-D$@rJ^T5#DxngyqQP7@w~6}=D# zfn%T^7Uae<1xN&R%8?!c0b$SpM*>jzwcd5|^4DiVq=)K|gs4@f421q12UpQ4z*FQA zn#3W;9gI2`38>@zw;dc>Nk!pGd~aVScugHzt)E|VV$zmatGl`<_k(h%9@s6mF?U*-$g zPM7yiI1LtU2dKTn*y<`2YhFze0&opn+8oJWh=0E>^+v<#^rqE9?kHrGL2iFsiUmjI zmsS24U_gDOoW7Ii;QSg$1tPQl7Cd``$({fz;4CTmx~k0vD%jMkTiZIp&dLKNLW+vS zre#kV6BpPhOR7p< zI#uADV)W8e*nLdn3oE(?J1d;!r7lafzcaqU-atMqr>F(jEXaPHf;1bOp5-#6Xxn>Y z3Uyf?wOh*CU&wbjk#UnR0a!1!%j_qTKCe7?aCs*Nhl;(WhbIx1y}wx3>1QiE}l2basXF^3IDaaGR(rq6Wl#bPklwisY?BU2wsXlkmH zv@o`MX;eg7lF>WeNNB_|oulLOQhLCs^102DR!>Z0Gp#1zC;6G_K`TWes&Lmhh@~(l z$XRTKi6!en?YVcNEl&lqDyMTjI`}_^m{M#$i~T0|%#(wHZz4I{RLrGLv3#(6oTL$t zI+MyG1BK$wO}#vn7dM#xh3=$T^2JOk7TQmX*~u(sD2rK1f7qHW=W}w)mIIt&G*t1? zJCX-*zgcbEgHLe^ggFLOmu2kF3h3h4Ps_5k)wO$>YgjCAtrVrDV43(VWNYv^TZ6|r z6{tuGD(>_R+)`9?3yt&Zu@d=Df}gauMUl7y(Q$?1o0iOmLU{2vFDSUHz~oCjtqQO0 z4nABD=zg0u+HJM47)xm5%0Iuk>LQ!3lJJ&_uNj?`*t+F68~y%P&viSyg9Zu%HVTWa zSpzQ>SF<`YdZ<$FgeqZ%H8X`A%0dugAw6HKwV{MWNsEd!SUpw1?;GTbW6CDSABQB4 zGm={?_O__@1BsUkRlTL;&(^L+;m{uPgS1X(RK5i@w6&C*saqqN7^*-1U17ehEvkD~ z;h(#S068VEaOOw$91Uc9LIkLA-fb+G1@XU%I`%nYFW?lz^cxGfSIAXCI26h9v48QF zrJlVWa_Ck~;?(0VyIW7^j%;_RZ?Hw=zybLYwWZ~MakUwxS{0uctiC_Svnr4_uXhwj+A&A zTTEI#1vp{t$&3=z5r+ExcVoCKoax}k@a0m8Y+B*Da5(LG1|Op9_lD7 z>4K@Yfn%vcj;FA&XK0g{xX>vlVkm@HF$4^b;yT$oCV9wL{K5MR;Me&K%KZ zqfQE(yP*Y^&RunW9^w`PqdvVsc#!Uf(NSH`YD>b<$ZF3JS1M>B~>j2g-VuMN52dRdsePsE2VDN$AhWvtOlL?7XpV{>f zyC`|x`)b}NL2NwvMk8Wea@GgKE|>F=J^@U~WVIlG>{5n6j#4)Oj#uC!y);3A+yD=D zZ8;MhcKqrkY&D{sN<2im>C*49EBw2S&B>57%zjz=6DmC`36}41dy^jH<&+(YscuY5 zq4X{=6EgKb(}?HY;;M_Cn1$lYt*%$EHPos+Hbb%OIes7$sZ^~HI$XOZP@*Bj-let} zk-QZ6x622PA0_gXVyN&E<&|)jQ9>GwN&*Wi zKeet0v%|GCxA*pzQKahH#T^j1@n@cL?3x<0CxUI@vc1i^wsq^<`c7ImWoH#XeAidZFjFhNH% zRTo6;%aWT@69+_=RRkqpwv z1VTHNnVVAT3q3{7TPm)bAej-lEIsC0>8^to$1fgqx~*F=Sd*3w4XYz@pAl{~;Ne-l@7VVsvy@SOLLp}MA3Jbmfml-Nj-L7S=g zV@kC9EqJQ(n*>jhF#o0e{*FG*y;O2jZW|@I?erRrdS|=gx;uWy-|XyI?2Y;3L~>ew zJCmld1>!jzS*XGyeh_$SP`1(M!GUpFVz)g!+@Qs==MvO}$U`{6qYhTaqvGS&2Rei@^F^ zg1i1H(+G~q`7%MC%im#~nOvb%(=+<>@DLC1DO|{-&nVyzNe~H#E;%?<#917Y4&$ z;*cQO^=q0OfbDV7`gHB1GHbohkb9>Qoco zZ$2#BB<8wPX4KCr#paupGBYs>DpRdcd4TG?_fmF=! zJCefyj8<>{8blHD8|ctw{OxbS*H@&iolGSWY4}c?ABm)pEYRb5iFm>}ts}yZ^Ye$d zZ)DqD($}o%Xmf50w@CULS#T&gs`^~JQlxqH9gX6n*SjP#`m=Qfam3WL;yWIL=%_S$ za!b@>>_rPqMBm(x`2Hw;sMcp8P7D0}$r%1p!+s3>I9skGwuiv^fb*3nvImWZ5T>Ro zn{$_4a2S}SCdgFq1YEA@Vj7b35d7+MRk4!oXctJ4TtfzRqs~aeuh@X2u+=BSRZ{WC zCHve^5I!aH$FI>`piwmIZV%hdw&&Rd&Jjk4sX1EQkfX8apJfX@6A1n1P8_q3V~B^8ga^ z(T!M_wfp_`gf)r;j%!`;3}_;ljME;=k?V3?vYPi6D7B-7}PrH28W}!1H#AcsO=RltXx&6EsOyQLbO8?DSy1=X!ZBxIwueK z0<CHsYZ5=ZT=iD!;Id0@?6cd>mm#XoOsC z-(7SgyVV9%*c))vz6n=GJ)&iBJp1^|gnY9}*{bVZ3}@j*RF1vID)pPTsulxxAdo<; zhUCr-Dh{ihwR0u~cy|Z~sj6OiE%!eZx&3? zBX(?$m>YUXdYU*hWaFVo2`VJgF$jh^AuzWw=<>*vw^@fNZ@=JPuQ{4-QQcTY26>%fFAWcZ z*ksX+xBMB~CiU9N>6h9RM_5`8B*e$jBaR+0j>hnd6Ld|x6S7#P^$pBe;5X|bDTCbT=ug0LK4kMWC`Vkdt**wepc*T6iwl}yea;|`SHh)El7}L zdk15`!%m9S%F%^EH`=|EX(**+i&%q$Xiu;u3Yy1$H1{BG+f+QuM^Zvnr5^StVqHFdT#rUtuNuQr zouBn^u7(z^B`>7OpuN{7gwE}JOa{`FgUzQhxmVq%kqk!X^m%8Ifrt*_F{vS$lXzS zI(sx&a+pkKFaFG&_eV0Q#P_`gavPG8I;X>XWG#F#24ZGD7lGRpN+M!Rv(XSaMt&AP zv=B9rcQ+zY*n0R}$9Xwd-Wa1fMG#A@8B^yi_#H>OvpeZ&jVusjPI~99_VT zJRpaQ3vxZ31k3X68}lu3?-L`g@?KriHg=xp95BA*Kza2zRDFiz6xN_alwWdBG4wm3 zc*}EaR-noTvWA&ZeMjw#@@=Aa>PijCWC#B3`qF1R<_z8tT%a%r7JgLt>zDICt05dJ ztx9~fvJ`TRr`XQ}5nojeGIDUxvrtt;v4K@XsSTE*F;yDqkpo0u`RjzAamFZ9RcgGM zbBfLjE?EY-_e*EoqsK&;24wrKI_z3=4PMEqt5F7I#xnpXZfvB3H=ML&oorEMtqa&~ zwq#Zl4juB1;mbI1=<>$KV}XN~2@u9>I`CHFE^7dQete(Ke`mAECB8MC=CLbs_AsGS zq66{3_BinxnYKN)ms4P>;3dRrLK({no0=tDNW#W(TGmLW_q@F?W*1b9zB4YxFlK67 z^;}hj5*?0#gQvqa8N)%SH;)22Wwf8NXifTZm{qg-(LtGQU_p( zYsv?RbcbjKmY0f>rk=+RH<@hWVIWDCbU$cTC_W`T@x&o`c|1@BACY5mi zv5=(~@t+I0!d2Z9zI3tSA|R&cya$vu>l%6OZ;B=N9}i`cxAmMYlmA#yi>>7E2ybbg zcR2vY*P20|D{=B%3?y}y8Xme3V8+&RALwjuRjCG1v%X&h1%6A#o*!NM&^{t-3BJ}jl1^A*>VoxzSdZEwO!cHY!_MR&dWBV`P6XbM^JuM>*k>CHEt2rJM0RC z(}0uvTs%-I<2p{i_Tv2LZzyO~l z<6#^7Bf5NYo;mfedv#lUirP3C+Y(XFaBz@Wj?b1HfpVlE#siiGRcKs7G+CDo?|FFU z^D5~ZGPZ*@I{kUkRtJ>iD1wJlPodcIJ-#q6Z#5kc`V##p%*H=SIJogE}W7-jNtvXYG%dB)aE1`l^~(c@?vI-}9CXy4ylUAdFWhRDmaw?sw*i&R*fPVo}bj)uKjX6~7&l9771QjurtSWz0Ha5^vAom5OyU;Qhv-Ze9 z$t|QA@di3Y<)lkKiA2&359@diBwrHhRLv4HatbmWC8H#F3OV_Xs&Y(@SqQckD}{2I z=i13+rs(yEl^_j^WU-Vkys;$?9|BA!tE^P%%UbFd82R?A>69caC>Td$=C-8OO5PUA z(MAKiJd4Vxj98_ck|Z_LS)|V?Q6}%@w^-_3{vB!3cmd^4nn+sab;6w4#!In){p6b| zyZ8%vaQtQ(Uzb*>RB7S06P1njlIu%L5{qOOeZl6aCNJq!b5eyU5YJ6<9qo0VAvwFI zcUIDvVyTLgy_0{(=Z)FAvnSAQx1qYE0JdfJV@@ftIm}vcBcaq7VJL64HeW;Bns6Y%&bUUHRmLH|62JztC!nqY1&oU8s?I194F(#7FguA+ zYYG|K-Xs;Jsr@PNIa#J|6}>&xfs7yJrz9oi^g@ERln~C*kgkqAo-`=GYX*4 z@g&4|QtT&Ua)G3ROYUEy|7bgOd0FvGN|H>pnlV!37#5~`t1=5XBQ)ldQI##Xx|Npo z#H)-dD7g9dcUB^q1SBkwWMGS>wGtu(5zl^gECf$I=&mcMT`x<9L@88MpcaE2&zO~v zj6+>}<1Z)ZVU2Ty|gV z!ZouNV~U`A{Rg7FW=0_8ttA-<*xRUMgycKZ`7CrX5|I^e2fnc3nG;C1FEGO# z<56NI{nU+3C3Q$#otO|lN1VKINT~;$C2olKB8lIV94;q?>LXVeb2So}OaAVS1d1Vm z2fzG9w{n?x;&Rl$-jszd4*4!qmTc!g{>T4x-k-kGMJ-rfr92=|$BC$z&jE|9{X9wy zBFfe&aRD?|$w(ulD;_|AbcJu3g)uW*q9sC(!3RPTNfM}vJA@%OMAn(|&@V3khgs>x zm{OJEY6}aLJAQE@t?=PLEnZlWH-2cOusT1yj2AAz06!4(TjW~jF};Nt-dkIqa=v)m zJJn_#7jG}=9=_teyR{)6b_b{6eU?>Kl>ndte&$AR;crsij?sSc; z*C!h!O-#zUe~^|=WtwtW7pVjCC;_c2l?x+OCW)y-#VTcEmT~R8ZQd^Ei7ccwu_IOaT5Bb^ zhnXQ`&rSSE|H<}4%wQ>GZ;nPCn6{*Dlodgm#mniOsa|4KyF8P@qA#JU1yqBZzcB+t zF54&B5xzJ)7SK}%I%;F!C5P}J6Idykm2|`fSVFk{3ESTMD>9xM)x{`QL@Z6sx&&Tt z?%$7=C5olT4N!fuTtV++d6~of6;B6#TQ0A9yxDkmnuCLd#i`}8H|9xZH;uzkcDqOX z1!>DB*H2}sU7O8R020J`%ALU}Ri`7kTJ$sM#rFl+wJaVWtSb+#xx(5;=@jjGfwU1k zwo}O*C`Nsq;F>fKeOLK;Nwy9s96JC$uI+~MB0wVo^xFvcMq2buga$S1_ah6Y^PTL5 z)WDOi$+{_6{uA}_8^m%zQ%VjiPn3Bz;M}Y9U45lGo!_`Q0KSZUt30@BAXE!De=l}# zMQ+o|A@Z5T*|yLQv_$+`!hPj(V8ysFjU>Y)kOi5s)r7-b!7xt@&fU903Yoiob~WF) zoFfL>OHF0EY^LsI{6>O&a=Bwv$(#&1pKnJpzoM#0fx8*`j;y4n$nXa^m!;?-B?C3qbasU8`EM7e2Jp0_}^Q^P*cFW zGI!lt8zm~7vLLaNyhR03e=y`ty|8--SUE$cxOw|mNp2I)LQ+IH;)Y52h|dbq?{rq% z&Faow&Wb**#dS-gXZqr@I)w>AD;1BSG<%0ex0L^tfnX>N7I;}tZIlW=iFxm_x0X1( zJ)^o^l(3=4X-;AbW^ZP~npG}Q--Vx_DtC;m-}6Z|&Nh}g_h(9glusi@F47w1`KKJH zg!BmIgI;iZcU5geiZ~UZo5G3{M6FrX+7w3w+XZk)gLMjm*2XAoM9c*}%Z6P*Nwzp!*>Z@30 zS457->BI&KSHPtaD1j3dG$2Ed`W)@oAT#1`q*9Q|)N!Y2?3EtNGr#6}RK_`uSr~HT zkL;)NvoIl{C*SWG?ZRqdr!!8=qdVAB!~++A5LGLI;Cd4xrKDHuv3+_ zf0|^%q$Ecqu!^J+Fd`#3ttmJSs;Ln>QL<4Y&z%cZbMq!31Q;L-KhigK*&r|>-R|Q#5#~F!4Q7G8eUw^MOE^}=aV%>>wtZ{q5xCMR5_WqXSxV)>r zgxS_)WT2C($n-%;vva?9IUdp`+)y;73QHI&2)*{7V6~iarY{08*(y_m;fgtO#gxku z&@opkp_qprrAdT+b1|1HGPDtMos>Q`6xARB?VFH0FKye{CtuypY^Y+}x`=UbxTq2q zJ)GmLz_oqhyH-xuc11`*gM9+SqJ?bfrD8kG!P=#cq|S%2Q|ParW&&J+W~wG5INj1j zxi9Fu^h))R+G<&hx)4eFhzy>YO0VkLgDvIyV^Np?xatQf5=_NIEN`ha$av!QPyX;<=E z!AhjXUCL_(ij^*Db^EZ!`Ha!Bp4-=FmC%j( zJbjAU%^i-1C!eD${|cl4s`FBm!oVD)>ZG1W3n~|mhECNAr4-Y;^znmCZG^X)1R}Yc zmYqone~=zP8cbYh!-JPHjPm(vniWtu z)nS8sds_|4dB#6Y)l5}+lYRKh`{VPYvy=B9lxVG`tHqN1c!OuxgpyQ$Cx8?buecG2i=)(X>AYJb&{d2HmM*lbx_D~5hD8da_GZ%ZmF)|A$kx3EK*9L6I~1Cr{*EhNQ? z21oNzH4o9S8dCntT#pU!SlTEw)baN__5GcF*X?cZ?{v4oIp?4u+c-9?WNRm}&08GZ z%0KtNKm1v61I5-0Cec|zs7jNv2T+dtXC!AHa#r07QnSpCMnecDXFABM^o&^C!z$P< zw|vlE%L{ZP{kGw5qtWGX4At@o^%KE-bITrON}{SC2Ue@V2O~f>p$qGZ$W6+Dgsp(s zV0(FBlG(dAWgg|7K@%y=hGDi+yGz|NXF69@jQP5(1M5k>R<;s{hn6ydRq+$x z(D8WW9r-emPqzLni=iZbAXJqTwCKQohSZFmu30-l(gk~9+wY=Oxhuz+8eRpfKZ@+W#zVUk&e_gEr5yH2 zXVs<@yQiEP;sg0+gHd}4O%tLY`GO)b|XUXZ3Uhj1D|-8wYn2(7yga;E73Pz zbtvUw?4p+H!6(XgqC8YWplRC-x`NB23NBRn@2-Py^hGJj=1%oLg(s(>aqJ zQ^{|1X!nHniGGArz(^Vw`VC52PwEGu*eX&$sg+T}NW0xTwA%2F@h3p}MjH@)37c8S zy3RQuU^=ney%&M57vAQgFZm2>-+d_ntnMJ02Ui2I-XCnqP87I$WDt5}w zdO?qaSXWJ*Hmtp)rrvk`3-+ zw?2CWm!pSoLn-?EmpPs!{azrU5ilKaZV2F;MDpCz}45b;ZoEt<>DIPHTs}GV07BoI; zVrsIchqkV0CNjb+gRO5cDsMV}Gb?ABdW9YpUiOHx2b|Rx<~uFz2CZa}Ig1fowVVqS z5S>>7v_q2CG{UFw_I~=w~`<5?t>-aL#PJ8%#!5DyV_lZ%!D3;c#F>eEreC|1$|bF3WW3ES*taK}>sE~t zSd^G8qE@SYxqYTrBt6Zz_*qzDcs1#H(49<(jc6tO1b7rg|mF?g~B2_8X1~#M@ zATk-pXKQy5smH6bOc)u&F;}N7Lwc{n80O~MR8q$4F<+cAr)A^v^PzWGDhK4Suia7< z0qqkp6fY?YSqQD0fU9BOqGez(%}!Hcs7QFa&%Qs6(({z_f)k{&l(e%XbV}rNvYET+ ziUy;JE#lSwEtu*Y?K2ref)cGnW(|eC9iK+VJMxd`vWbIM>)q+Qx6Iq5y8bUGZyz=ekhKGnlSLSz+arCz!yY>l*rrEq*K&w^BX zPyaZa%@>`~TZDiEA(=?U@=hU@y`BBRp5NVql5()Uw>KDAk&3OqiBxRw*{Zn5=EMsB z45fA_-Z+L#4ifcZ!XS{6B6Dm&L;%hWYn{2?HdRC8te@qwRP3Tkwtd@Odu^db~SZ^^O>?Ik-+muj`PXzJ=qV|jdsI04%4xIE#ESR}n*#^FHKjIStg30Y-_7NzJtS4J+Dwv+#6vkUcnRw22{uBvC` zFOb65p6G9TAOjch0qTq_ZsGO|s+CSpEtQRpyOh^V7uMU{>~HtG1L!#$jb5j}wQaw) zxkJToaBfqA&n*_hw)S<=Ub=YB`q8?SP(L-RMvFb(qm;Zj9LuW>m3CgFFqIZFV23AN zH90CY43bY_cZ+ePxS%+;Aei)q%vAq!?tm>0ls_vPuBDcj_$bcGej{Q9ph; zKSG4gm_Vuj%lRM4MpShcxJ7#&Ew;9FT(eYTfuSuAiTeB|48>FpYk&ZXb=kSID^h?%4bJ^!$VO`qy_yA5Ko+ z!Fw?_i+0&E&!Xy-Qgg+T!>{lDboSysiCeGU9G^kt`t_%icU*b+H4%)YP(nHt*DHt6Vm#E}L;X z>NMhG@WbDNUv;@$j_i?817=sYcT{C^8>k~G0jz|<FCJ72C8jip1w zaV_Skw@OyYFIQD3il@N>jFpXUOE8rXd{gVB~GLCZ$m_z#*iO#E)fR7zJiOAnVlGsD}-&yE$PL$ zuOLj7^o9=+7d$W7*DA=&itrt|rn)wGZX1jWWcYeA;)2IH4MlAOA)*|kuK#@BS7r69 zV^o}1PbfFo{52HTDvPgrjIvg*NO?V(5-tS>Q*3c(F`p1lBNII@w08LADwK=pt%&D% z|LXYY&5N^R@59e$r+@O!k51no;|eI8y0gQE+nwEpkk^Oae6=1$3j!T#5aN6|U=Yr? z>}N>s18D~_adGY{@^hum8kw6H!@(3#|%N;Q{L$d~1r?$h==iCfAkI?sUv$ zJKifY!U3ntdz}PtsOW@nXSwZOLiMe*b4%MPRw{`PzQY~g-=#agTi;4is{0&A(MxCB z^YW@USB~Hg-S|XSzwM!Yo<1B}3SF0De8ZPOI090Nbi%*sZhb|dS}=Y>d53-pQ%Jhe zfo;fu%8&ZFlZB_u?WS;`xxT>%=2&p|r06)4cVNYGG{cYPUrB7>v>ZE{P=?)YX18~@ z_o|J3n^GYKD8PIE-~87=7m)XJDX(J1_4G=18c0t#zx|EtAdw|caXpng0PSglC0(+j ziqer~Ub{;1YgdU5=^}nQSvzj@2%|oqYiu87SW`SBv9RU{hFJC|zk9@C4qfvz&(hm* zg#8NxWog;*A@!Qxa)9Lvb#q=W1_M$P>WgIVN?7bDO^#w~%^*VhvlWd4&>tysQ_`=> zHo~KpAY{@zdF>tl`RMpP>jV_d{1%4)gmPz`eunBUDPVCYSTjYeyK|lF>!(oV@`j?W z%WZe&|0V$_1?b9ZYSGIg>d8x`60HxKb!^SH>(=+TnmYrOuv<+fdRbH;L; z4X*|$$FsrQXBE_35ueOOgq$aJVIr+o-;WvYiZ3L4z`HDkCVJ4N$bid^#`Avu@ZtR# zGH1ZS1p*$`n2h%Hjz^R~=>3)iC8giFD%-t^a_-h;kqf8^>2|l@-`yL)BK_uv$; zv*M+{EPCaIkZ$g<@JK)Ql=mTQxGmWzf4sPo1jbJ4-nTRrG!H88s#cdaOK`fmfWEw) zKw*5=`~zO4tpG#O9%=*f;f6x4As*S`C48yFYbC2$fAkO3c2 z1JUv9isDeg#lM~WWvO;-0n8F_jY%{ zX%Du$`#XEP_JdFMj-Pt+tz?kp(i@xGitw`oj3mnX6DM|>nITqhCKHt876;olQZ0V& zT=*!5JQ=qskIv$1%pQAfigax&=M#=)laZbT(MWLOqWb0f@2FVnE0h=SvfC#T@UU0z zyVDO2p=_>9BIyYy_|hD#ef;vptJm$P?cPfQaAGdTyhAV=m?N= z4VaHbQ<(G65QW_-^2IN=qT#HkwDRFZj`Ca3n+h#`b`VleJZ1G-%1 zjWC??+56C-8gxA*?aQ@3AT~+fkhi6H2JdcFAx*u{4vl4xWCuPkkK%sksZ!eY02P@7&9=de)H(bt$MrI#f`XzMIb&027a4IdWQkhW< zb3?x4x$#j2GVEjw#$!Z)AAHmw@QIw*IGb~JfLy^j$XCwO<2sL?JK^v57+3gWP7;fv zL#QfF>00KOrTdM@plpSP>iq^TAKb6MPNOyN1fR8bUjQpQvHQ-UGtPjNcPH8Tlvnw8 zj`2wQk3{Vy%K6cmbL`ur2RJ7Bw|+(?JIITl;J5`%=z8^GM(zew!sumK$mn54%?7WB z8UF!>Dc={0ZtvIKNKL2WU++C0EH-|vgX+knXTSGoTrSSN-!QsL-2IQMw1F%-WmUSy z!}XHt9Ia;@Z+G}Wa2q4glHY+g^?~kMNDh#$AT|?I>JtRNpGZ}a2brz@K;u0A_^Ci0 z(>svFit~WvFq5^Zd}m5jc{nOmalQ)$syN?+`cxjA@>HDfM|J+u6zBHfexJ88lfERP z|L#;Oq%!v!l=J;43RAf^b*X$;%2N4mRHgDz6y;&=&N8x8c>t1B`Nxr?=qgw4agFbI z1D(5djMLAEd|HhBs?f*N&U6?V(<4n|)@yBq+~4f)`n^r)nfuM|U~k7_kH{P%(m7@} zVO?`WoKzco)&vs>n^wLq%M=C^aYgf#71HY%{(qU|HsJiIOIoSKAC&@avf=B;wM^g< zUC(ZPhoiueJS()uEZ+%lF-Ed%Xh1h89Jc3?1>9JM8MUVpBWqi_S;vBuXdWdnq?80< zgYbj-^0VSF$bL&7U~K7{{jiS;=xSqmdfG4R+T4GMGP4< zuK_=5*BU#VJr}?1SDTH(`)1GBL4l^S8@N^gSE}mK>FbyU4^^y7vCVSj$7WNdhTF5{ z{uDnP4A}kB^yH5cg&Vl|J1KASb6rkbLf2J#F46;2YG`6&PG{n(rIz&@C1dxv8kx#3 zlIBa47oPZPc@yn3Y{{~cgqTDdt3C`hdW?RO0|NV`9I?(9J<6qDqDSg?TZnMzVpc+7 zhHv(~NV5LWxheTQ2ligZ+MMSZaqM^4WtqI1-ZE=>9a@NSk-~2f(#ir$5DsZHTrwD4 zyCP#zJL^z5yZFI4_Ke+p56p5m#>K!@Q5PdKQB$->EhiZ!Z3V>JtU_tV-sHBRFSex| zNRay5atdxNw@?A+H|zf80X@H~+7m&JI>;`upd@Bzt5^aP*ibUz7)e6nw&bc4Cup3G{Fgu_BuCQVXD=sTpM6~HeL6gh!HKu#XT->FhJsXEr3`3MXoMu1fYW>*MLiY6DZ3|N4?FSz&GkT3lI*40AUm2mOl0 z{g{P{sXYM{nZb0XgN&KNBoL&6kQA>OXxP{+l}&>GM9e7iHF!AGU z0rpq0jQ&ffv_gV%_TC1GgIdc|6N)-58a{i4NW&YhvdA)xKkO@ZX`NFqz=;jNB7@x1 z^$bx>MHrNRr?vj>JkmMORW6FGUQ#U__j$?Z@jgi*3FFL!dL`T6rjpnwLcxQS6M1dO z0DU^`fW>v-E9r<=T9_;I2x3$_;n3QaB%2fIM9!~V&M6#?94|cBvOQIkt1acihgx4Kr?&WqEM3KFijHrRAfQvV1qRa7q5zPNT&pA!CCCI3~Y#Fvj2N< z?;&@By(WIyS?L54;&mYMwN0Ef1nZpFU2q&WVN$)0(zeEGCWa@y!lvejv1V+rb#vuy zko8qvj&McRS-N3}LX04j~7BT$R%W0>=KcVBWo z?`<^;-c-UB$cPJr1J_yQ(%A5li6fd4V-tt42~}AmR6_M-rEK9`=b?!P6r|GO6ucC; zGv-V)M57=sb~qUw($I}1`6J;Tza|>TQ6IBnP@4NVQx&>Yv9A@37CgDa7yg8 z6K5{frX3p4hyE&jE0bN#z+pLvD_Rt1jLbj^Q6e-syS=8QOy7fB@9y8@jwj$McEK%h zS>$%-?=&U5lUyuj7C3nl(}cwpOk8|$%tRK{6%?$0z$Eq(Wff~|e2`@OGv}!xGjSOM zu2=}NC>y-V=~}VFaFA`*SK8wL7AQn#eILcI8?iL<;NCaSCUu3nA-16AYla9bu|ASA z2y-OiBOOo}W)@3Lpfv)8I00UJGE*bX;7UM)HyjuOcS>XevnZ-0la>4q*d_^|`AXW9 zN;50(iPk-Z=}q|J?AJw?u)ovzr@>5j+dz`DdZBtiN|yogz*x^OO6!rG1T;`KcRk!j zN$uF!-`%~V&BVT)8LGQ5pq6W!sl6>1ZA_b;rOAu!w=J{!T2gbDNZi=i-=vZ|*b0;f z`QMmWhh!81$wW4?m3U^Mw^N-&C$?49Xj96`d}6CH=GMIJ7D&?TNWY0M%ran@xyO<< zHx8SXw7*gE+$@a}ryM1?_wB*_w>9`?^DXnkAp1WP& ztM@vcUba0qW1zHEH=`jZb)%X+75ulsHBwZyVo_N9I%b1GAEobr1wYdFLlVGsRN+Oh zI88bN-EX2qE>h6yU;P`ZC&uclk5Y`1u$cs_;LS;&p4P->(Q-;a11(j9rnK%pMHxO- z!)(3m{`~grE&t9sbQS0Jj9AA*KCGu38>kr)RWP}}B(E$~07b1BUBUx!Ii)&NDseoD zn@BPCfQp0D6DnvTQ4kv{f?yVix$7!c!#yx6T~#F<1Ws*;j_`>U;0C(ph^vNskt$6h zh2-0+iUOB3rc@iy0L2TNAhcoQDUGu7F3GQC>IgGT@FA!v1vMe<3Lbs}R}(vROJ65U z@IIOG&P!Oh{Pz%L;Ca-XCLph|IqU#Lc12}a`Q1Sn0>WC#A3r7gYN$Ly#hJ+%*-g=l zz75;4e0Qo#?yd+ZPrF%O81_aw@9b`ObI|GTx-Keh)%!a;{UvudJy6EoO*fRf@SKm) zsHo_iQ$bmU!&SK_lhhb;XaYB9b8A`bt6_-A$A*K3q8;)KA3wE~Z4QwB1s7AQ>4tnUTU5NVR(v*u zVQVys?`DdjdiU#_Hx?c#%kd;pDWeF>MM8*^oqSs{i{;4LEJjgRDVx>%k~K)$263FH z8}(W~=U)Z0nJ&n%i!@|=JII~Bv(?z_cee^&hS*T~*CE!F4zanzRUYX_bcnBYEA!|G zs8#}YlVKrn@FoHeO3`b9lsjCIaH+9-f&-Q!A%Sv`wU-daI~+T=gsqQc7S%ek_^~tB zCZ}fE+1y;VN7?D-O_WjAlTx&rY)Xere_Hqo<;-<;GuPQ(SxYd1=AOD-&C@eyiA@cHGV*R$E+TJkoZHGD;K*!AVK+8M;hpY1Do3eIP>}7{%doMjT2^7o>v!HX0!eyh4&z*8lt(#IW6(yiPpT>bj#S?2}83grz;N7Q{eNT5^d5 z25+O8EpRwva^jjyRhUY=q>^&wDQRV4m{}&{a>nnFvCdEhWgp)x92B1^dUHqOS4rRP z#JXZvmkZtF9=)KSp(BCCUm*tGM8nc($0!A@{TBB)Q!cVW!my-I+j5*1CDyH320^@R zBwj&oR(Kgas@DMu(^r>GA6|6B9$P*j=9sb4=<#c>bAHDjs)^$dZL7#r2N>^CI2Xtu z!Uk2Ys8eR<8!vKpmjzR_t!5O(;L)UL_P&%XHu<}Zfl~ndpM;>5UPl}BZ}9agr$9ga zWB7vbo{#?ovq-#=C7#<2mAlS5(hVJC}gV^2ze z0D1D5l~c%Lk;rNEfgwRnxHGO(cjHq9pQHTi@=q;J)ouIyPeH@e*R~ifS0A5G&!a|) zruVx29e-!9fy!j{Mzh}E-z`Sdje+v%y3vr)24nmEdP?uCta4MNJ;?Fc_)F8Mr6}lgsSg6Zc+ljPnlGHdHu<1nO`*|bu*53^;VwTy7q zQXbE-?iNgCz*H{HQ{etR#;&qNsdplIk&r}TKAYTV_jcV(7NM^TZbvB1q6h~U`gpbM zdPLVwX(%#oh^?KvBwPKx{m#xNN|Sf{jUKGG%Pxs^tc-hNZ7UgdB)Jy-Fc@K-FDOYN zWDN3>CAAfK;HjvG7`GO>%7%sCbVRDE_oP%0igOkqOd3m}a0Em+^75SjKteTAVv=^u z;_fK{MqDz}re+Vljo8ot=lKbo=R;vl`QIh_B@4gNh9=eQm+%&rJVhRJ^(o5!t5;0v)#pjnWKjp%TRe2E7i_$qZGA=a_?Xg1DBo={rT`QZ{!E zl!PK%;RcR$i7aJ+2GeX0_Z#mZRbniP0Ht!1oXdyAFEy9;Uc~KCkd5G-(Qx3?IlDQr zA3A(fJE{W_!@L5e#I2j*C1A7E+gt%s4GTE-iwU0gS~*rHG+j~Ax}3U@>ZG!+o4!6( z$8`~w^n969a{AKKvdGuItejc#3tw^jNI8+QY9&-mGUUp>==`%Q1QE+-;rz!rp4e6y zDvqWQ6FZ&j7!&$JcB;tf;*nE_NB%q!q|DMu1B-RjIRpzkcN^I%i4n9W8nEn`isG2e z%1eriaw7n>?3^WLV=~LFGD;YWYWGoD^}d1~)h&B(T&fq1MkR$SIAO9JiPg{lj+@}| zx8D}=qZSkr|;hUB{tyIknsoWNlBS16+qj`F-ny3fC`~skJ;vBI`GEEqxdw* zQ8*6^NcVlky<$V9t74Y1eGamsVu$AB7A&rGC^H`$v5WfBP8(ry7YJD(n{4}sj{w(M z2~JVtfG#i!>3l+%ZJQ@VWn(HT23El7VhyMWizT>;+P{p<`zSOZ0l2O_V2Z*!8S(F> z#}>l}OG0z;(^|IwA+MWo_~P7n5U;*)Mm+N}5v7d^STlH`0A6zwhS$bsb-S4lUj`S} zCO;Hh*a?Q_oQ!Rb<_KuQHeHzZK~(%(a%@m)zSvkOI70M}4jr!9Z9;EtGLlk1a9fie zTkD4bkDS%Hs2x1aS zI#19K{Wtk0u?el@t|Wq7mB^Fec{I2t8mDEU+JnhLwZgJc?LM+l&6I^|iSxECjVe7; zEm5M|>KWpW`JyGYDfg4AY&1!jmvn%tm5DOE(3zjg2ufX8wb?brhC>)Nc*T^C086)2@ItK~qH9OysDWS_bk%V5_z?YV@4mOMZ4;E7nwx<%> z2t35cBANw`!?97qORJ|V#(Jm5mMW`yQ1$HsLZG)i5CWi{GO^MZWnlBXoK+xxmnGCKpsBbZCjio?N&* z0$t9Ay^T1;{dvbn!_Q&Hhxa?)OI6uqYGP&k|&n;7B<{oa#l9Dg$wDm^> z@yL`JV+^X3H69579&ziAhKeubfRm>Vh-iPCY0G#2GY?;6eE(joLnL~Jdapk zX_Jnp>lNuTwFQgk zTyDk+%{(7H4t%3(6J*Bbtf96b7wIHHtDYJWh#F8^Vs`X9RQ@s zO!68kh{FPS32m?;FED}3Q1Cdn8s0OkNtHVvpy>N72PiMT*8wtl`6oTZ9F1dygbB$faPi&t6(kD~T(+Cjl@J`5{ekad!ADkkkB(ep3mZ*0NQ?C&+$5 zjMIE#hO$)6Qc}pw(hEH-R9+_Sm=8&@q@x{})Uuz&m*H%_Aj^Yfcyc&#l|?gNlA7)A zgUw<6tcuNp2P1IlfF2|pAcjs?5~N@shbj?N;xP1D^E=W4O27NR+m4c~b(w0wBN~o! zh-$jWPPk1~%H@s#q}FUX{)B=%-5^wQ*KD9u`n~tNQ+kYKdd!0N+(_vGxrmdCk)&)* z+2WF;9vhZu5JOt-*+t(aQmUbD2_;sR*Gh)o5cbav!y!T!U-h6LYK5D4GM+BxiRD)d zti=?^^$OmBiLoax%S&IQf=D@YGBQ)i3B>QEp}M&M3k}561yS)w9%)lO(X}9)K&OH_ zT@p5KYadPJ* zD)`adj<`zQgY)B_Q~TtFVhP5@&}*g@(Mc${ibUuVYIV6ZmssZJX z$f~ZN!s0B5L{g~2Lx3`oS=(HU+1!rJ?c9vn+|9*2!_1rXlgzgc`{>&}LLj=T$GZN% z6A0hFeIM3ddmX<;#^T{PC+w~nM@EZ%#ob5JtQA^<#7IZ-f{7>c%*pW`z-z_^n>4@h zZ-o)QCf&+{-+a044s$> zbtq6z;*}2D%kYLaYDo<)a!AReTEd25Em=I2y7#u|qm$#B)ci>>VAJxNXxdd2ZI4@7 zW_blTbs6Av8brDh+batkD1^xcKPF6xD3*nU2ZF23@=svTcIJ`Wq+|BY?0VR`=Iy@f zw7cs72S(hsIv+h98v%G1s6x&zDZ_fa#~|^}@lfzfgP>{#3`4SHivhj6padj9N5qtMP<`Bc81w^%XX4OU>Kk+xWva6_b7b1_dzw_fC4@{6*Kqz)as%|W<5 zsdUEPrdD?NiA5$>{wC*_u#Uq`2ola6TAXn+_s-dv&Ypa7BKO&~Pltl0A#%B?vj;~b zwAN`aV_TqBjto8VI8p4_CXhNsnDYwII3QdR7>o<00!kx!%j+Rt^)p zPhN5|!Esl`p#O-fgG-_CdOZMrh)9w`i8?H~X$TJe5R!lxGc}6m*}F6H$3`>hs!OYzxD zuC+U90@Yk-&8}ye|@p0?tSr!9>_9pmiEaxd`9xIh;;V(GUG+QQE9`fzgtxw7l4JNWxxc#Wf0 z((?jGuH;QlKi^nstfN9N|LFpQn32EYH?;P2DH1qT6E$fQ%y1}8RMj$}E7n}DQ$ou* zr}|oxd`uK%NS_-diswOfkazdtKh5sk$!c237}XMTxTvybwpz~~Xc%^jtz!bUdjca* zY4J^tIa2ExjP8W;jnUmH^zx?owYPiKu6k@xooC8jiJpvf;tv<+YA%gtP_GKvEshc0 zx40~CdY8oRuZwyyJ&|Z7DM+9}5dsozdM-O&#={NsPLF~^ItF}PF}ssED#N`D#rrKv%9JP^F#i@VA5K7|LO%;&RPnix%-Y;2vnhI|j6ob*< zPb9~xWzyGKpli`KYUX9VVb`IuE^eZmkUkDx{QUZ_C1bj(A~f4I_` zSKa0-S|-eW{5F~bnu7{kYc(2L%{jvrVVJLm$#KVy^`ZZ{R^Edy!H773Vei-0=B)u) zm$9~9hi2F{e-_P>ugl=q*XDi2r$efOMSA35)+yUpC~TXHlmsn%e}T%GC95gZS>XLU zjMXrwAq9L?HXuk-rVo2b7YL@JhpW;grm};NOP%;O%4qk_-BA&*PR_0c!1n)bX{lbt zXXl;B;s+{dTxaQUVW-|}}qc*{3@=$60kz%75nVOw70pehbPqw|@;Mo!{Gh1<7yCuDC6-hU33$yGA2=aJRRg{WO{V zat`P1=&^*w@Q=TH7SoJld^DB~!~_44lAghT8Iwb|<0OH0CMnGi?y$+%0>8G|^Lxbq ze$hK8*hn@nbMYa>m}8GR+72I)c5j0SAeLlQgo(dekWbaFhu(uA_+{T8MRJQy#=WR9 zw%!lFjn8YIh@)><{w?kO7ua`SGchCDuKpz}nPtrGMGunKSp|Y&f^U!_(20~3)~5RJ zs8w_uw9R-Do%$8OTDs>ojTGaMex<57;u(aefHl@`)W|q3gntx2{-4(xoSc!9i3PZj zlAa+R7AwqC;?ZzK5yl-;Xa~le5ixbm7X1aXA%oY9AUgA;{FP)B}piUF%(10{gQ**SmH+Z*zb zaN$dXZ4+NAO$^bHK8oI3ARmIF>|9hIWiqy5b_eU1tgUy1g(lgM(3QGkUQZ)4 z0z{K>P8vr7bnkHMI)idjL=Tp)Nu^9N8dM393P(Hv+m+2|qdx!qf|3`XP*CtYWF|H; z84iw?G-KDK0Peem~`^B^IpOEHqiom#zX z0^8YbDx_PTp5#wV$BMaWcMu1!0+JNoB9EY(^?LsUGYoa?E}H6tS})Bk#?V2x28JGgg7q^p@`1m_ zeO70+*fGn!G5l$Edh#E?0mH zPG33e9!@~6sMJUNkcgt&*KK!gq9bX356`8Jq24OIFV$1?=y(zhmyN1c0NROtX{KeP zG{H~qJ39PhbIU|b+O8ijnGIp_?+F(|RJbQNZ&^A0m-8=fDel}m59`%h{ZXmJH(J{6 zMBp!cB~_~w#%#{SeQ>d}Use*7rYdUm0_#hS%Xck}Y*3*xhF|_XqqH}^O{o)}4)~Wk2RUV6ea)+@6DS0}09m@GT)cd+Oyg(?ifGcwg*mWiQIp;Dvn94_oUsJ(%Dl zXG~iYY*&x+>09b1+EaXGhUVW`+g*IKQ}DYH2yo=-AX*441NI558ng(#vv;Gw`>U=O zWB7a<$z=u8M$y`_aMvUav&a-+ZHOGAJF#$AoJhf2P=r2DB*W5G?gdrI-hm=U6^@&FgPq$^;_QYsWiS9d==n)#fzgyYAzc>?6IPbZFD7x&Cd3 z1N_XhDtNBI&ekq5zr{pR7H4vmdT>=J{)Ax4l|_lsq6+U z#IzgRYdej#jq7ZO1>m*79JpM6rl{gIz&zy)A$3Bi4SZmQYvYP(P;&Rl1?M&rC`Hyo z1O%madO*?amlhL=$|NMHsD_OT+8VulH7buqwou1<0>#yXUiD!9iOH%6!Kp^6Xau7p z?Ug1TXb;Mf;$&#@&$(h2l6lq%+ESc}u*JZgKX(*~In#vf>P+R2{Eb&jLt+CLxGuzW zD8r;%yzcA3ki;qT?TrQ}{(=5gVC>$@U$d|@2)~Pmg6%Iww?%XrL#==CyHfYjnA}}@ zNnGs*V-NQW7eVVCghjInW39h|@p~^t^C|3z+2=C|?PKzFgqvEklqGYV}{>PKQr-2w3nJf1YTof9bM?>A(;42AdL88*;eg%tA?9Xjr zRfs?U>n0wihgnIC&fHE)XRA)9ZM5+h{fbT(3#*RTC=Po0uFDmDY(5!X_t8~(*uiL~o}AeX zrX5^aTG?!6XS1=nPL(iLu3>vv(3gr)iIjnz6lcA!nHf3|QhY3vF+=IYU~_Z=Q224gtLZ z-&Wk;HT+x6qLbp9KCV;`U*YF!R$$|Om9MK=C~$s#e^)axyX*VBLU77&^?RkpbRFMU zA;7ZQ|5e_6o)4@dW@fX8nAH@2puGTaQumf|=dg!L7_cEANK zi+~P5<31e^V9aH3BF!9sBtJF^t#Q*BxoOtRKL~IE52!=6GGVx~4PMjp=--V5z{3ey zk|pzqD{TJ+jRg^~6wKBrAUP1iR(b2?MOz2i@`n^{YcVWPAGt|LGq_oiv_$|jqf9ah z3uEV~^^VR!IYDuTjL+Q`>5Bf&K%i8sT|*7G0kE}+Eu=qpY(i#w-~4QU34Ihvp)-N< zD#bb2QwalnjpO!th>Z*frnLN1vM=Hb5$26&BCHA2rZo+E%UO?$f&%3OzO!M+B~u!( z5*exh)OgGxIiA#|<{()U0Ab!>iz8@c5frtLNOawS_#V6)9mxD0iePE&hav-Y@v~73 zba`E_I|)MYBPSLbW&}9=j~QlIP_h6WJ%E>-RHRhigqxUv$A0Qf&u-V2Al1ERFq27U z>ZyoleGQ2ttCVBC9w5dRkF?`DuQXtwXOQ|mk=_%eB=i7m&^W$ zGK=(QljJ~8_v`5z$6nWNtK3Jth@|LiKF&(TXT5f~nX-uI+XBd86?5~g5{r?OLjrc% zoX?o)E;85@#GcKEf+J+1{1vGD8@e(?-a4lE4_pLefnSacy7#0JOP4IUeW6n6zJDj_ z^eVg-zZKV#l{{PBs5)!B{??g~Bo~^`)FwM)*0y#Vs~Zd4lDtsf1ufv}EA`mp8=KQzb!p5xl6eY8kAjfB&EVR}TxDNVPdRK5p3#Tu-mriYYeI?maFGV?x%tYDNpJ zj#L|Eaq+$YxISOLPrYJt(RPowhpYWTtF~_9{pL|WO6OM0KTi+-M z`J=Oo(=5i7H(6>$W#E;>7d@u%BAaTK&V+%}39k9JD=G`#zS>t~*DTJfJ4~ zQOG6AH4^O9`^-lK2KgQnsFdblku@{tI!D0mn@Dsen8%4<ITvX6L|1%wY zgqfH^J1QPh$CsbqNFYHfAfh5GK`NBk@@RXeqSpwip$W{*k$CF8AlvT;r>W~8n9E-` z@dj^peXks8@hLWr=S8S;g0vxSlF4ZwkfLYuFh7|9x$dz9-4e25QwEo@%P8tlBUD~- zcu7VcFJto20}3e&t4mO-2$L8OnB8%8EG)P#F9$WPY!VG`p+Nl34Un+A5{K_bT=+t7 z!~^`BY9aZhrAt*sLCMR>7S53@QX7N*p?d;{9$b}Y?{J|%5Fm}@)`a_w2#rEV8pl%F zgFi$Z(x*Xo)8~30Do21NRB<7-crE1{X zYJ@U#XfR8EoaZkXG(vDG@lSRLmjx18I@D;jiU28EGr2S$&WWNbSo$H2(~Cc|m?NG7 zKh&>L;8JQ#*ismN#wfTseo`>w^M;;sk?Q=k#S&mku)Q=IWgmu-hjaUq41Fic9lfWT z9r%+AjC&7cAzsj5u@)3As`~a~aDYO9I?x3$ad=ZsTcNOOoJl4FHhj8NUl1g*tltG+ zPxH6aFdl0Wn8f;=Q1Gkj$5K04h;Ey6L$-FdJOkDZQQcJ~ zzkL876k{y$hVa+x_x5YfKtRO~?SsYp^b?PyGxtjgxZgbCf{wfCp9G9pzF7XME79~) zaV4gzI^Ifu>8oye%;jl?h(z1jPHb=qrxRLg`*}E9y9~I#y{Z{dH^`+d9*j4>5}?zh zU~G36mnTP?k^dimpI6~CYEDiv3dH@=K^VI|&!s`!K{-3V8aoseuDYJvsj~R;#QQYn z<%bwx3XDpWp6wkrv@GweY>?mMW;ddINM?-!-%dgGU@^ntxx3?Af$iuEMAf22rL;td zb_LNu*(ouj{qnvmxa&gZh&A}W^`82ER?UVF zi`{#>5*Y>2T=!ZO5^>dbopiDkMO{oFVPhTcHP3x1FaA(;R3}~Whs}WX5{kPz@EL3tc3;a98bRgvwT!D-sm%|#29siRgT%1N(qu4 zA}NP-Tr^N2E#|WUZ)OP88F+R4EnBG~F{Wq_`DMG2<5?9ZIkojan!j;xS0rTy*N>qT zl1}LDmZvEdOs#1^S(-S%dIoQ=^P5~QR3#>Nhpc z(O!RJW$Sni1w=NEkB7$_tBX5FgYM=#MT6$-+vCi8{C9OF@`b{E&o`l#q%aooJcP)j zTgn071-IL$+qI9U9SOETRcftl@$pon@k77JC#oGSSbt<&j~*4>e2r8&n$YL6>~#=9 zUY15S#ZSwwNAF8sSX6309aQ2)KNcO{)aY$wT#^{Ul#{b}va~2-+}0SGsH^z+aL2Y< zq@<&{o@HaV8O>sId)w)9*%OpMcY#R5aPy>1~ZR zuMrp#bvXa@M=vN;?-oP#ZWoWg*BlqYjO_&qni&FSzTk$BC&el!*CwS(GFpU$=914` z(pijbB9h_2k`*q)w6@{{XWYng(vdYK$4J7a@XX?3L`5q7y+CLsm6fHGS5oy&U!vUF z7%qd^k&Y*zL5O66}u_vbetNvu^sPEfnnsad0rEzEF}| z9e!=@^HcP9r&hckcVr2AbwmG|0@x8@fFy?Uz zB6Sw)Q>kRU(#TX>a{bn;RfU-ByqP3oRA?moF5;rnwID@VJ%IXTD^mbQwH~X6#8`rpu zq@x8cA!*2lPQHA$_42_3gk#L0R`FlqOc1-1{@aSKdqM0PJ@U>Owv2u$%5d5XHf1(} z?ymow5+7jl!PjzE{7B#7m{~fT5}ipEF-f18 zoSj^fFKwDp0F*)&jXsYC7p#^meoIcAoz|-%VNeYBqPg_aAq-L<#}rqF&?+)zWt>4v z`R4eDK|+H5n_t4L4WW{K6*P4TrOTx~7wVJ_MOQ^M>ha0=-Ft*&J;Em)Rpw}VB5Bht z2Zu*Nq}{u$W}o#0Y1>~9uZX%~QeG)_cbq~yR=EiaUb=CPsE>rKtj(_UPg_0SkIuWF z9scDd;&^M%pCL-`*^7gt)-3;6NAjM55pPLqZI|P2yOL@97r}ymDq)C^1PR`UUcGOl zQLq%4>v+JLV~>^?@w&DO@5ss7P11RphG~~ms%+ADXgyh+SUnt zaJPdd99Ec1scwW9o{_~e>=WbY+5vPM8cfNRq%uY^r zQB5nY`%|G2$XrN-<}Taq7vod@8`E$+r5_=H%bap*m31HGGuTtR#7$rz&4w3zYL&IX zM00T-QA1bi7Bb7x7&+n%kB(kTifet33vN>ZGmbc5Obx-u@O>t6Ll76K^nHx&hCJ&>q_Q4CZo;3k0dSLZw_? z#N$8~*ftCh50Gk&Mf|4OQuF3mQuBt{QS(MwQS*k`Q1fP4P;)`{6K920bD`#qbD-vp zai79W7GgrpZ(%^q8(}_$f!_cRYJNTciHGx5Y$$x6=HLlqUPAT}bxw<-kzHne2`>kj zG#5tgD5hN7JZr~lk2#Y=lu}MJa7RLk5Hh4f~^D-bIaAXwkfDIsNF%S)%?=D^6qH6NJ`e|Y=WOu@+jtNQr zp>)?D%|4O8TJYwxni@74(C*~o^o+%blTQRcwPF(t;cXiqkJWrZO71bCrBHY7buMa% zXJk}51)rk38G|6&!}BwKmoAY%yb*x4+T+PNoO+L`P#D}h;$Nx1y|t|Bw3`tPo?UqU z$oJf*xo+fr9lk`hmJb1l%fH9tuAaL+^3@E{y4$g)~>5cgX6!3S%^Lahm z*_f&zmbQ^GYpZ2*=Keb>ST?zWrB)*}tdhTWH9&u- zpycuS$w*I6-cUG2W*MiPNem=}++*|@9K$0_xg;xu&CxNIamH&I93Ty>Zbql7nL=cb zX<&h5*Ft`*;dyO)>K4n0O=iKeTePsfq2s13N>9^z6)q~3+uJNdrjOTQ!L?W}0gg}3 z&&6*I9vndl2%Pg2aUubZrn-n9^tk6^dJ;s3R7JU6yRAWy4$UDfb>rH0Mt{FuD~r`^ zWMxRhzT^9qB7o80W5=SL0v!z`AeM`4-S%4*WdY)cMRH2{#3L>)i)G(!1&s7xMI%-fMeRFQE66GJ}hwNj%6DmC?iu1I0O-B35Qht7a;Y z_AKInVMdbip;ylz-iUGFZ3-|#r$H%w5`8K0WK6~;#WVzmNI+o2G4#2%8iOym?!beJ0#L`DVg-71DX4 zfvs?n^raaepS=Dh^C7njL#UcpOtXFNtL5z+}-t}mV#wu z2ox5-&JbhyD9e%lMOWD+J6#z-N~FEDCTt6k_j{L|-9@NRS@#8rK^&KRaKf?KUFpn~ z0285bD4m?KSF6s#62+`gK`d6(vo1v*OGx>C*H>aZy(RvwT9aV^ne=GLg=0u@d)o!r zH&+{V&3(RIT;&#D=X`bBwo_Gmbsf&&t>a#+g~BXrz5aTCaaG&(HDAqkZQ1uKxk&Vf zL-9+7t&PP96HVKazB(uGWdzfd^T|aLH1SPf^y7Cs-)54MCU>0^TC-Xk-5pYWn*cy4{5p_#h_*&9^2?MRc{)Jsp+Q|ugDcotJ(6UNbio1qy%tkbz9p#AT#E2jjaP5vI1 z@6S+)2!?tqy|eEJS14APJU=`vZx{6bRV&+du3=}rFJ8xs+{8RTc5XrwAtE8CQL79J zmoDmJ9@xHwZ0@YG(6-vx++E-t`xZM8#EF=gI-c^N=f{QpaNs^S_KrgID&#uyX$5~WLSI+-Of;TkK zfxLDny-V81u1HaxU-JoEVFYFX!}yBvu6v7~TB^= z=hIB%VYNDJp@k5%p%AqHk0g%Nx;~J_S=N!2;6?!*l&lN>i%otpji`W8YvDmM4N!G} z@(N+4m92Dlc{O}esY=P_y{xF3X;>hIk5sfPa4t;9)Hz6$Co@^mG}-=ADO$}{eX&$H zDXx1a2G;Y_AHt=3gS|+l@m+Vh^ty1Cl9Ex|H492|l{7B0{G^qou>kT{v@k-Y4~0zA zr=5;K0ynj50XErr(&7uJCEV_XUS267;7ntDJLZNnY)#-Y*iip3_$#wCO>frRHie)s z*v*L-{fb=`ApAcOxcxLp>E(3s)m2!6mRC_!c+FXa0&zkV`N8qK8iZNIF68yMw^C&> z)Hf`0VVnNwh~XOnv=iivnHtt%Ha7WTK8_sxx6RCUS6(4OJAOx@c`<mt!=uDRZt`o zM$RNS6ML`?M^3y0yp!>nsmdqo%8Lj5p;|76R`=!H7VfJDpvLjd8tR9V}dhzbNJuXM{N%YJ4(EYnhcT=pJjMm7z)QU3hWg2)b%^wA5PPD=j z7Ft-85|}843n+{@(YnlN4+t+tv+Q8>6#b0#y{}GI+cO>=2crP(Yutp`N!Qd znRHUAvOTz>Cnq13EeR8ZSqj0Pvh$;bY*0wvxK4&FFmiFNetciRwtc zf0yluh@1pZ2j8~Zp_-q}CvO+KNvsn3crqSxDioWzqE1{nBo?**cE$!&quFCn#61wg zcsI9xM7l*_qEL$s9FbD7jiW3mz!&KvLy4bg$rd#iBwHs=U$+Wwax;^%;I%e%xq6#! zmuztA&2WVNiv?LNS(>2e#w%T^$`ZGWtyHn);#F27=5tl7QD>nfZ0em+p@lY?62acd z?kYy|cMxIT6*>~*y;}T`+>FYKClv2P>qHi~zJ%ei71@tSY885d%K+_nGD+_<_D~HA znvP5qlX1T5fh=@m!ra*g3Y_r|?1uj|qKqzBUVvyZ6~jw!CcRP^U~yVvIHc@E8_U9> zq32VAE$7-N3WKNFWRv4WCu+@R>(h9qeg=39##Ds7Sw__yFyfQvn-zFE^!~ZVTfxx~ zH+(Z&E$OQAaHI&!FewIsu|Z}MK*b>sypOyM9RIjt45TZ@%R=$9=EYlOr(^mDxOH&`*@rZz^dUYzBqg7S z3xzs{IGlf5x>~CLAg-T}qd{=TU;L^f{{4UYzyAH-{`Ywwj8>;3RZjQR zC%v|@!!^a$0gUL?6f1}fziKd;uNab<*9)?t?P#+A=|^aVdM6N~{F~Ygh+d6~fmwwp ztN}*Qq~fWIoq>lYLiof*Co2oY$vz%`CPj#9r*NL=o;Jk~SX1Qb2YoT4I1$&w-M^jP z^~y2`BpR%ZsHF1C%YW(o{OaK8vwwBkWPgc9`{wBKv_ClkP}Q{dw*X^ z%)GQ~GxbImESn%DCJXO;_2N{TmADi-#|4}V1cs#0X#8#McPg>1qAXue;w2?xA8uR- zn20i@`L-6Hse$XjOjrCEx&os$*s&cOt4Ee2XUmd!L*_Eut6b|~o$9P?m2;Um(10ps z<67qvy|%ltCbPb(*M28wnL*@`1?e4=CQf2Nt2j*RA@68Zy`i-t6~3KtL1)^?k?0FJmqf?6;m^2f27@W(m?%6~huT->-qMTP0 z*Jzh2Wi7A!B@@c+C8j!Y35f7~UihD3FRQU{mo1Sm6rf#22`k@gZ;K<0V%TZt*H@(S z=K3}S-}S}z{wj%Uy$~~W(7b}YTOvo4vX)X-=pP{ALFnFice9fEFwN{hq9ur(L--{f zq7Oy;gTR)A(OP^LmG|@*3Nf~eL4IDpc&-_<8ta0T9M(a;a@CBd;U-p!Py`NN1IYLp zTR&!#2?7gd9H^`rbg}jzXf-a{AJK%O;9iz~fvtgk+6sZ<)O`6ChqFPe0Etl=0pHJ@ z=RiY|6n}_oIU&gn%NP4EBfBZ=N~O>t(imBz!5|^`(Z<=puO8(Ql2p_mVPInl5uvC$ zb{bMpjixvGe#RfxB_1>PZvk1LCgGamlL40Y4m0kZake<3Jf?pTBRwpP};#8Uu$n(o{N z9N5f`W?8^Nj?3d*H!7DCbxwrz`Fu=P;7@o$@uNB66l&0?7oIn#H+!7scWH?f9x*Du zL!gGJrg%cE*A|w14@9pfkgvf@IO88dB7}H#AFknMm#NML{!jae>FF!(#>6AaRdWs0W}xv z%o0IGk2Z9clb5WpEUFFyE7I;G4z~pcY8QZ@7UvyG&*LQ%4kFuAN_@7>-+V}a?aT;Cf57RlT$x>SRakr9Uf)^hHsn$SEJr;w z*@JTHYLzNm$Dv^9l%$i+c!-oiasUpka{p{tvkz@CMt?`3Iw&gqA(U=x+Em;`%oc$* zMb+uBSciu%$hE4Gc6-^c^jLy6H659xXAzP@x=($;68krOC0GK=N;gh5Uc^E*>M#_s zuw+`YD=K+o4Gw?yjFZq8BUz+o~)UKj#{QkJyG{5km9`^NHh&)cxlW3N?6E7Dy@eRzKw!o{A%%h zKnA;-p9E-{8MLR}t-;EGQ1Xv=Mx*}P`ZZAUZCCTt{cKZ?6I)+ztWpFo{#;wDPC-os z&);U}eHcAdS?7x3)q9tH(ELT;M(lDgixi3VE_cH0>S9(bIx<$@9%nB%85eJ;Ac3v< z<-;PeM!JmSYRdlCBIg>6i@-~(dGUDR6m9q^JFS`FfMb-oAQl*#|JB9H#m)=SEFRVQ z6Iie-Mp0``&KGE2W~W@B5}FO``VXa_1@_0I3a$CFe6u|^>FF%r z4@r9A!3c!lA)9$FazTH1HxbjJ>y>hAxmM5Af=%dm)>^b0!54H9Ouh|g|Z{}`1ATz-e_H% zcCdtBbfRB)PPG*XRBSOVf3c+e{w5@_YQj|M+R!wzL zy}E9hK&%N_f28c!RBBI(S&wxis_10(A^mqt<3S#pYetfl#5qp=wMa|9n3@pSve%BN ztfZIe;uKf?1JZO+zw^9;kaX2J--V!f@!C z*$>%>#y;p*&eP%XGi`QwhM^BW*w-5V?lrPt#On6OZ?>*iW-5!XukRAb_WI_EST=5& zsLdE;(?|bH zH`gVyX;XoGzSn}pOX8VMnl51a_v{S@4sLaxE4}1z+jM<_le;H0Cj3l)_&<;HM+AkB zC;B(Ct8=Tv=|O%fv(UBH&l!>{{c5oR#o^Io{xk91A6%mQc#NimMrx$)Oi5esNXcRn zYv(6IE|M289=dvVyu|>NU!y(V+0v-m@3qJCPq{_bl=a7@_kn^q-Hnae6Z>iC=E@>x zN$NL!61SzjB3UdDU-Y?zqcn|QMjCQ*HKam(?};ZI$+v~x!d0Poa4xQ;k9AtFx-iPC-%0lU}nmPNL;i`4U9-pQ`Miou_HlA8@rn~$&MBk3!6rk z6S=D9^ZO!ut`i8XE|6!jy+PS>`MTrrUMUXDlSH#Xf@}oJ%Hjf~>;UiI{(lLQf|tD6 z*jhmWEnKVX5> zka^W=VQ@1w$);T8juI}k0xVg}ZI86BJxT@OI%|}EFaZ?d>G(H+bf6Ibo{i>5Vxb08 zoe@IAIL|K}25M&RWP(^&d?Ydg+sQYL#J^hfESQD=!JM=f45T&Mf_jU58#Ui)cf#u2 zetLQR1JCaVo@VoEiGVEU(__A2ppE97gud}Pgqyy`v`B>qb<{L;m!6fGL^~Mzt#BYg z>`QRRXiCtBU^=`Qz1-KJ8$xVu=kb`V^&HkHK2^WV;F^jY_X=>|v}dt&yF5`}cCHP# z$O%g^xEkNAzipV5-ay;u3~;ij^MaH6MrF{pE0kswZp722MBy>v zj@}an31_T0>+I+g@~k%+%|;JZK+)IqXWwfOKP!`@83C1M_zIzNQ>|>K!n$&7t)-3eI7x6g~FV7HBG^U~T1zLZy z76c0hX&lnNU%73C9o@ry)xYg}P&rLfg^jrV={-DF8n(sw+%yz^)tgcv2JqFd-=<_c z>MyG&zL*J=ddq3e+JJ%h8 zR8J7@&(+}@vNwFnxHk?c?^7TlN>iRrgEQW>X>R<;Mj(ivSnLOOllYRl$8Ufe*&R3Y z6)6qzBrQ{rbS(VqJ;##dPPQ9yKZUh!NTo~@NWd9_$}I+$gOd@1DdnMT$UVjWZApR< ziXxHX9=CerQ+iC}yd#CzIikIdYh_V ztK}wD=~m!|ekM)B*bwOL+sw})0#NC{^I7)gOBVe?1|$k0rHn`U>8b8P(EoWjq4I%x z#?*69;Za%gJQfveMQn+3b4fFZW&KKHt@}v9Wb3+4EoWU|Ta*YE}+0}QPg%a-&a854q~^nMiygl06H#;27$XqYxcDEG}F#A))j zyIAFt71`KyB-jT)e?c0?kUKEE2qAq$RrW5?E84zE;gAiQ*fPF3R1->q+y;4X|QPm;p|V@x#81q&dz* z5$Mt?%!ru$H0o3OwiV6(j8u8k9fXcE1Bo!Q)nK?YRDz~Ge>^!ootz=aF(MP>@)ra@ z8Ma3_LSLM>8*7#o=j=vAip*P$P{`5a=6h6_t1v^xb?)`ezuR8xdcH*`xbH8HuSQZC zCqK+o3K%hPtyIes>67=269GSraTbPc6I9CWv4)P?ab+kH!2oDl1XOS?#pP@3r@DfRBEwd`O-O2%u^)$P4$6HIiTW>!MMTuZ-0=bMYNKeYD zxxR$4(I>TS-HtF&D}HFb@iyhHZC%utNCl4crAC!LM$0Y;t{C&s*Osg}PVB5TN7^^a zET3*$yGXmEW#J-5DyTEa?kqYFk!>!t4vne&unNd&vykT{U?BN+!g#;;9XQ|9X`|v7B?!`d)Wtv6Lk_X{wEscF5$0pO*VS?YX$TmFcc#9JQsP*L=-jLp zvjT6UhMr=$UQ$;ZCkAWumELlIxNf1ZQxJW^nVaxGg^#QPjnhIKO`g%4W zS|w-sdg`4g7sBFko|4^5R4`w>qgO>F^L9qehThQ1m7;5^LyLI4zotuHx3ZJ*G;iwD z5@TJ2=jZzGK!A3QywP~Ud@AcdIr#CHKeiqn9UZ)ST?+*N+j{#ty}&q1yjHhG(G?O< z2Z=0tL$ts$>DlypWj2vIs6`^X^i(rprUeIMwN{zdC!HmCVd36#DpHfU=BK&eo)KD> zSc1Ch@Vm!)88A;R91N*4O(SXQVRM!~k%BMI2}tJE#hEPt=o_5ablmW?xH7vMcUEp& zgUFuSAvwD#He2##ncax>lr72J9bMVJwt#f%U~V&ZU%J`p_%GC2`u@g?U<(1{TA3adb30UderD~WafG*q2tyX%Z^eaXQPo!M7PPB^i^mw8@pCqgXI$~cD*4p=Y28_hsa_8qUur;~vl3C6 z<&>%|rVe~J5?fLlbs$W5rowt)>vlpoHz5pxcaW^;o?0=&q%)3Ki88kDxx35yqhMg!1}0$ugYL5ra+DvD-^>adwSKqxyIv!w(kbcS8f zl84$A;g&Z)(WXejBt4313eV5!niZRiUV#MnW~Yit0PiZ-aF!!P)E$b-%Y{ubJ!NYg zxy+HgH*u1Fw@rHIiCSU(tD})xp$7aO@`1^68nVPpEr%uG$b3g+A&Y zBeqN4A)I3EY{KyIbgFu^K~uw6Xv`nSLvM+^4HF&lsVoPH0StcgOoPm^YZMC!pWNm(VdDXP#T#BRBbWw;)75nVbx&{_krd+ktwb5hx997n3F z=%*YTxrOx7P_sO(zrplfxxFhpa>a7)7pe*3v&Z9i7sW?f|LRIlkP#Yt)0af3FHj0r z&n7|B(H0+>XZtE!Fv7HZ?-_fa#n>1+H|+iO(Ee3+?3J#>8+re&Ctf|0lHED~Su?NI zLo+e%)3$EcNDGwn0gWtSj;tp!SMWNs{DDq7ag$HIlMjN|tniASCoQl@T7kipP{x7d z8_R&J(zVwoBNa#D5a!u*jHsHCtuoy5HjFhV<`?L>_sIk{T`}$OWbIzmWaW@Q!*V_R zSK%Hyy7G4G4WA*UytlM#{ILLhKRE7&O8NA;F0TTMJ%WMgxbfVb@DN#$+Kv}SUS+Q@ z<3ME_MMI8clW$_#0^jUQlBzYf(`9Sdt1i+#E{^PnA0DFId|fJm$%wAu#$Gn8(U&T?mxbiCr4Lkw7lwu(I`&`R(%5+#lQyDP7uOrUwx zMOi#!^_AIv?TDzzf~=Ha&n(5m>0h9}-}p?-&kBkgN%+~)8O(EB3vH=uPgaQfCX{=o zI%`XNjm8yFIo&(hPG77z%ftGv*SMY%1-BNyq@qjVEN3nrgmIPf?@AsX)iJ#C^g#ZP z-XyxCam0<1YY=W@SY=z;DXorHSxT_Zdm+;d!*MK+l7--}wfQy?IiUf;Vc&+I6m891 zZfOMEvNDbl@(B}p;ut^}P;6$+T%GzJP*GA6;6$ObEQ@qK$Pg6mBZ3kpDn#Zcn;X=9E1l`l9G+%gzX2N#%0q-INcyG&KEjmHEiG2y7NF4eK`%8KWvmJ)}& z@ow?V4g3J7|3C`7R0x85!lrl!L~I_u8|heb#s#M0(=)(*OFuwE0MP={@qLfMXjtOT z-T`9oz3A3C6C55R8=PWhA2^y_F1^?O-?5-tOlrLG~ISWOslu!GboHv zNRi#erxTabuG*?RwHm7Yb1yVe0+i0{`k|3l+D2aFs;k~PWD|Nrs9v&ye9Pi|@o=o7 zAvZkBhzK;_=L7HU#n1=eV;*j}J#`9i~p(Wjoo%8PZ;Z}|eN1-gyX*z*j{~VA?s#LDk_l_=|nZiw=oSz-!#;BWzT|}WWAiQ zW3sll%@I2V;qQj^kKl7-V^_CP9qP$N*kCg9q6&RWrbz5k!$53~Bq*f}YzeD-=&|z+ zKy{y&m0HYvV;C)bVr1&|W=n=Ms9{0qvh_?tN)TeMAt%sTLt{|PJ$Ry_j8itMiE}(M zt!ZD8T}|w5HET*!Z*@FW-*ARId?CYGQajg$jP!GQ{-T)T8p_s8Z`!gT4tvshXt6La z6c68A@w`+x*A=J|&aWYwdxCj-=&`U~A*xph>Q|0acxe=*a%LQxJ|4JWbrf5CwNECt z5(o#qP7@&{JdIcQ(oJ{VNJXTWuU!{|$hAl%$~|~(Q@BzS03Or6>`B>!MQ(M81e5|bevP!e$gINf^FJg?DoX{=&&n6 zKe6l-b?UIuLn+XHvP2fdci&2;>kcK{BU5m7WyhqtdV3vvg`>P4&(da-T7xY6>KGsE zX7)Im4L%}^zjILk?wsPcZS)U?9f6hIPKE>d49(kFTP)AKqi+1$Ek(ksd6AkF{u&0b zk%PiuwGE|=^4QNiXn3G%ELHw0VTuYoE)G+dW+h6|nVU6Tef?1w@k)t@`gG@^1NQ% zIBtiZ&dk;QWF!dlz(sQX8f&yYUfcr*^W_8TAk3bAGC8|T8~t(e!FURDjcS!-D-IE5 zd*%p`qXX;F;q+Qk!PG6sW*$<_gi<*-iC$~UYfUN!W}V~exa+x-MC9&O>~z)d)Df=+ z@1AqPn~?WnPn-x?L$K00r{xZ*$!{cB79$qwHs4p`pRw&N7tJrU^k=G!V8S_EpiJgJ zrpv%?f$xqoK_$OOU>X6^ToEg%v{MIyFb2NO2VhQG(tC{yvF5#A_b?L5i8UNZHJ~mo ztKkJ7nfs(%q;cL0jTBgSYkPgL)9-D!T3dtu#yU`T=K$*#J1PO!EjAQzpS7TX+wmD& z-G@>L{o`qEFoVqYm#xVdLq3g+k0^!0lpu|ys3B0O=uUXQ_yuYz*A zyvx#w6lW$m^YENA?zE1~uXznI@{R1>$)w*qp&BaZ9Td2${hHGs^&dhE=4*9k5HX5< zrT~_IIgmFgQ?lO8NG}X4JH~C9 zV1GWj0O~?crT#c1LJ9Y$+3CrTd}3cwRnZzwFJbGq+hkPuc{Y9U9t}EjropMH&3@f0 zBS=*I)`zhB@mroA*Wfgeo z1+T_CS(%|rbdF)Yqr!%e)V+t^}Vwi3+Rc9=VDimn!&JhhNIYGz@dp&vesEeNkNZ+GTaMqpxNxoq9!?`9(SaDJ?KtE)q^|#*cbM z5Wt%L_0}BD>z5sMh27|CL5=SbDU)2Qiwcg)qx!tUTK8NxM&i~t#hSjmyF!W_1j$X5 zYnewVRxa@vkDO`P6aIAcNB-+!tk!vD8?#uv@}lzi{?xIGIkMqLN5|*1&?GvY=DD(0 zm^c2EtC(7=2fG-qyX7uU{%XvTwt`(CNujE_aLEqi+1VncBIYR~tLT24tFkd$y9;cL z`JZ+UD@BjuWD@rS&LQNL&M|_sNa9Bb-E5j@=7}3g-746v#PfytYJs1Yi5FJ^PgUa! zX$r7%)mvO>t3%Rs2lPold>*p^R#3%cR+!ZN$50z5u-BZPs791}q>9)2>ZpIbLdKQV z<)W_wcX0SFfS)}!aOu}7O1oc{t(n-=&+R80<&xOa`fp(GOWTg ze7D!gUVB{ZDFJ8B9?w4S2UX*tje=VrA0sZOGo!EoF0E*Op`+h*^~SSeYfeZeo{#Mu zjK}TlRqxXglAM9Gv%a?9Fm)K{TU>$&Z#HZZRt~G2L9ED6dVWeDRvmG3wjlZ>AG4u_ z{2LivFLjQBk!7afTdkX&chzA)Lmi);U(7l_Ll-{&;LhEiG1fk#Hg<(D+GRIde%7QK zO+4!Yo}huLClf~@KBS?{DnuXNdI1CJvnFl$a}C+pq-`863OwFY?M`WlTO zz`AAM4N+%r%9t<$k%CLWq+TM9i^ETsWTs7gWC;U?tTw%D+rHkcSNy{AYjFGWzip}01tm$W85Wy&1R z3O6~Suu701%~Ys(m)Qxy{#*0IgCxBooEyKeXmL-{8tl2_ zDkG=fzyP>@Bv**GO}L0NygDeKw*_DBnzQ^yyYuJg|IM8(4qeTH#V(M zO;T7qx^^`ub(+8;LwsIUYkv24%Lo?gjs7;LM~ICiMn>r)EaQGYA%KP*_;DyN_7QJ$3cc@>?h zke2Kz=WB?mD;R*^lZZx{tJRV^3w-joH#m-CYj=akWSx&7Lv)EAxp(1?IP{1(;=GgbY>!hv z{Em)|>0d`em|PSwLAPO!_*j@hdS(P(WnVffF=YV7W^~Bc!)uPZY$rxi3rz*y6%-ei zKbZ`oUwE_2L=a_~-Yfn_Cx#o+=t5%;M#}^A#^kQ7Sn(VW>EH#Qhd2ClZACbJj>@&( zP*XipG!#0q_d>9PKOek$+ICs#RE&T^z4-`bQnvEs(nqE4av-22n|!W!TS0H#7mzx} zoY2ALzuIWml^6yR(AKusnzRgAm+$#5gu*xXh-F{w>}Bg~Z@bwtADHb`(w>&L*S9=V z*P_S81nH(-qlq(L3vURYe{#^2UU%jmnD=sM9<`UXh$Ar-hR+*iFUyAL>+#P@4$;d# zi!OfGe=6e1ws;4(H+-wnqHBItkLik~a;84gaS4g9XH@~Ngv`-VLk;B;{CZ7s0sD&f zt4wH%6Ib{qxBC^{gV*fIma<{`snBy@=mnI}bloG>b$7Q`cSgJY-BxR7u(31T9aZYO z-s>rC*L%#G!WxH5%O7R~pHC(qF4!d*auo{G)Yu`mSUG`&qNu0DY4kS^=zL@7W%&7R z5FSKEZuc%sNE9tmC_%(i6x8UD+=zz>#m~2dqx7z_&Aivhj&cXy%t3)OXd+EJK3DTRTDHVR(uVx3LKyL ztEG!y5bD)#QBWD%c(Iei7z~o()n@V|0;&_WF;a@h9culh`}ddXl4&LL)k9|{Yy`fy z&h~>52Df#M?ZG_6@%kEGtl%ZEB&7I={A>clwuhtj<6ZEO(JKCgA+w5y=&LFIp^w-$ zEtct3u`$prsE{59zO~!GGk{nl6H_~f2V&lw9F5!sV{==2%TXd++G;?*fl^(o(1Ik* zmre6{oA&(vpPk7`ieAp#%i&3j-;ZQ7d0WcBF*$2646Nq8;VxIB}wA+t$AR+_Ixms5Th}Na6 zb!}s#zrMTHPaKPd`}EGs!tY4^<}D8J<3Fw0*)v^0(g7SUgmyS#VEOW#G9WnbCagu8 zrC_lF4h;58Wvd->8B?k+{hrtAemD(X19bP1?2o6d9^JAO#5(yvK1bz`2XerlogvktGo|)8p_-7HL@l5$d(_X5H^kFsxNpBKKbh4 z(d&cMlNX17KIj}BJb#*cc=+=9U!OdC6>gM!?@8zBtHT#%y*}x@K1@G*^6cqf_X2I^ z=+V=I*MEgMcPO3)-fSF2o*DgGvrt02C=w>1X7_1)7M+plS@DuY5dT~&m&0mA(qj3! zFLY5n_Jt;V=dH66wJthTii|%9{eCb649RoQZp%L%!E)bbktAuH7xeh}qz519olIVP zc?e4SYTAtZtQ9&1ZFs-Q_Iw?YE;5lvuR&BlR!ro@!Rtrp_EA_{bA|JS)@_>5O)PmO zT`n@0zr1?p_N19uDSEz_Ttj+-g`aca{IQgczfpdKN)J!r*sKl_t#dp=VE)d^U}gJw zd$;`9R34bg3&RT*Lq*(>@#7$8kRHn;dmgtt4ad#iM`iJU;y8B^>E&L5C=| zy0)`tOc#j25U?FFL@-RxjIowHa4~%Hj5AavpA{#A!@=t0fdL#D-Ty7^PG8nv8>U|o zr!BY`p=)tn7t>{%OJZ<*DS?hb)G(ZP8|5?@vCP)<5w$$Xtv|sv`H|p$4tqv4ZQr;9c;2b~a6>mx*_OuLxQni|Pel z(ixgAIy_u|WU1thtJs#BauVBxC#rH;Ji+n@yZ1J7-~m4N>>az0BrsI}-60mhwpqMx zek*j~^Fpvnf+5n6idoU^OG8K5Fdx)#;Pn-DIxnxU?lvmP-opb;grUMPdP>~8MQ9!< zeUyq)2C*@8U&pbqoCpZ-7LHPBBGd6u3ZNAz?wI}f$@l0i-67rVj9;%vE21xS)G*Gs z7!SC1JS^+_DouGZPdh{m4jbYRdVw6nFoqxu_9rh63)NeV)t#zcqltXFgn#XQyG{SC z8M0#c@K5-Ka_pmEAP9`^s8Hh?{l_<^i}A%fcEWxEZ8Zc^0XXV%$;6)` z=#9}=$u+=sETUJz0yW3O_I_0u?3Ig5ypI^)BN&xumtGtxB}H`Q&hL-3D8v|o1Ms9_ zU_PI)*;nrts&q@Jx^KFGy_|L5a_@wLEz7+roRI-NXoVwGWym1oefBv~&_`FBwJbAvu zVMPwbASut+)i!t7C`RFbV(6K>w8jCamkb{bwqgdj2Yco;+lJ4}0c(*x9;$*2oH^Z2*|9Gw8ubIL7g_ zazeaV#OgZ2x$Iv%Q5XbfCA+Z8&>CB~1=rT+?LvuM3$}IfIhHdaFHa|9m1~1oJi3mV zcr?l)h?Z!22m>Xn9_}u{K02@uOVk4MPT62NjGu;Y%wIGNv?=IfS^w_+yU9=p+jQRk zMjZpTEZol^p>~`T2yaKcZw1zBw@LfjPfZIFgKOt|W6eO4KJq*Eoj1ikTdlW|tXCQ; zX}c*8lVm+Je7y8vxc`VTARqMif4_P#-Nz5)yk_ba@HG4wI~DplWy}3|ME?Z}WX)eb zZ(saN3iRU6cLKYV#0Jb{!GQMLe($Ki^r>k_WGxdp~GPhu>I zvl3>mB+7mv@KCx^Sy(TMfVPcS&DiWwGZrwIlav14>DBChHQb{^n6I9Ya{wkK|3}RF z;9n0OH&D3e2k$#LjbRj<bw?hEhApXYLVyomT&JR)ihjAVr{W5kQ=0UiM}0*<-}7Y zI>6`>+pCS<2df)=$XTTI&xl1YKFdni%uU8ijdpvG^0|7?`^ri?Ld^PvRcgM3f^_BO zbh`5GQuXIeXk>fq-KX(Ex2Me7oeCYA7R7$U@Q+u5TQI%PxVzKLSK%m4V$8Rq*tc;( zji-7=MNu6_8t|4Vlm`-rt4!e!`m{GZ?$J&UG4CS;cGSGjG}K9T^!mxct5Xp#PmhcgMqdvUPG=v2HSvW=bXU<6-CBg;aWD zHwpg(_aObj2jt7~@C#arLSGBwWWQMtvc^-#;i$^QjfSkI)C%h6SpShQW_sL=ms5jy zNCKCC|IcM*8sE#F~~5EYu2{i$L>$`rg2&6HZ6Q z{}z6j^UID~vs&1yUeaB%FRakYUggHpt7t0}k&y!dA$M7?j~vg+?ZkVvJM=PC=SG(L zc)YQsMJ=aJL3pSwv=E(-_HV)d5ErkMehz z?k9L3wwao_bR)x!#iT2yq+Lt3YA&E!HDfDiv#3oq)7n(CRGVsEN1JNS)25m?p-nX_ zZLZBSn`>X6_O*-Ok?%)dwqf;nkN(lz=eVD^u)o3snIE*;Z2sN4L>f)#x*=ldl z@me>imO#`q;nsUWu!MMG>UO@Dh@Deh$wSVvwqc{3Hwhi6RUBpD)Z*1A1|-qK(^I9% z(3^xkNBl8jhN!BW8-9r@?=*s&xI8?&j*H=yzm#iwtfn*4)K{FgYK{9_4^ZX#!CoJ7 zaF`i%K;cwgV>p79KMMo0G6L{Dktznf@`+tnHR+h4-xkr7iVExv*##;!FAT#fU(4S^ z`C6`U-G05;c|4k?mP{G3O+~TCj?Dieai->pONJUq77G57KuhyYd8Igp6vD+~Coxw1 z?QB9tt{!G?u?`U^TZMu+FHEX5K&m1Drph2#7GITETN795F|%V{)`T^MVhCg_;1wj4 zIa&qn!2ANu*lPoZ7`35a%4t$Wv}*FY_F`T|>~o&A)?<~ie-Di1M?mX+A|>6h^(MWh zMIR-Re?_XsYy)b3wbIocN+Ah7JI120IV}$t_KlP|gfMyZVmd7Mprl$21k;u<^(Cfglc7XwU!)f`Gl;Cst}r$?j|c)7mfw9 zkzYl}mup%tB&HE3)aSA|bR}3sxbTXl`g4+z-dtc|o8M(&>tTpd^4ke(qw@)fovR=Q zXwKlC;sk83af-_h{#czGJTkAEz;%LzLtrYFYaSLiD8*I`{hd~Luj zC7kxD+7SZI4-a3os{v+4XE{;Q#ThaRhE`kdDo01uJKa#IBQzPXoKdHeXhDxXdd7v& z5V|!!L1(BxMNnu+X(2lqs<;VM$v7YMrd$fjM&+}~^1T4{ZEx%})`9P~vxypZ8&yOS z1s8WxTNmWMba0#b%^yzFmlLG?&1#V(ZKW$j{WT-O{pG|%{HXz;r$w1FTue-0Ehk(njH^0>Wd5Qmi$G(=orxce zlQ(j$y=(M0@J`bFXy=Mw!q0V0`J1I+VuHideDrlsbzX zHIv^9GUORSuM(ES&}h_20nQhOgZJOtQx^54-nT>;)*jlTL7?tK+F(&iufP+XJ2@kvFyi!4IvaP7$Pz~s2I(^!K7 zwY%-(v?nfd19QgF{6r@x$2y`@i5N>`G+@+b!eE(3-*nVftH+R9MVT+Xq|KCl$VP{< z*{yJ6>=n6YD2+dQefZ+pW03dUbJ z=bU`%D)w8R?CyBjBuHdrHqkXq_h+}+L@9U$BH?5SF6Z9Gk3j4ckdf})bZ?f1nvzF{ ze@z%`8SKGfI$)Z>JCVODo{1lm>Vs(Jnl`Cs;i2H_T3VuwAg{UF^#F%GkopLz&P>)N zWmmd_^N3{mz&7Dl+Ff3mEg{JH3GcAj|MO}kAngS&zNL=AWb;x=)U%X$?W!~@!^k4x zA@K0KQkfKS%33qcFkC=&I_#}P_KFbYf~}cGaFNl)Qxvzg)TPE?udb{z93u(_Zknv; z@k~#s`P*%O&Jx!xiS(3Zi71H&53=>WxCJ{GULV>P8-*4MpkZ5Vdh137q$!zrtJT`Z zbDZQMsYHIfm=tg`hCNAD7T-n>n7ESBL|yRB0w)VWO2ZyLVq}!%XgYD0su|PPUiisJ zR3jG|SyZhW36OxS6sT&FnHt8q(xA_QEB8(lpDKkNFrVDs3o!0vm)180IBj*yLZ=z9 zC+YU^=MEXOk0`kgiMOyeLnh{Sm*OZ6E$dGbb9-q$070l8mXK5Xt z+bSrE5wyCoVapJjvJ8bxAI8&j{_SGWy)7G4ls_2`j-i<4nAkcc#acQYQ( zQb)j0ka1j(=`vvSW=Y5=3m12uOEGmI_`^i-rdyg=g*-iP@EQhce^4(wf7|}(`PlW5 zEY&t!aIscf>x#KZt+@bW;C83w65N7`+&X+$9uK?d8P?q)$s}*O%5~dqa}{^rYL4J| zX6z-L)Q?M)yo8Slhpd4`KL?Z-pzu%%{^a2Ajg0>937L*fCO;3zW02yj$NT{V2}zbkk2>h`WAO3`5;zk|og9xIgg?>0j# z_Od#7&^vF6490i=1?9XFRbHB~V z5PqY8Rhi~r8%H8&rK=lMN@I0(cQejV^Vgg%0sfIp#l;;ctWlxf1~&|28*cex>Vm83 zi_@;(V%&tZy1K^Nmyg(c3*A$VAvbne!}VQW!?o4zd23k620JAqywoF;+AnP>Wn|yp z|F6}KR(o^3K{xpt>Vm~t;5WG3#gSbr8p;!JmjxKehVx}A@ddI`kMi#K9GKDA3Q2Uw z%#o1@$~l#0Z~q06*`8i&K=M-lQ=Y8|XS^~@$HsF;xBv-AhYDOiz3s}e#p34*F*aNU zEMI>OWzUXRw^x7$d0YW8R_G&vG*)QCKyh1ZP)wHTkF^9Et;2@saK*VAAw#s~ELqn9 zVQZVu3N1%_dRl@}b(ymH|6>~^$>{73mqzgPDcQK1-6=FngTU0;;IJo zGcSV78eFU>Bt5&|hcb5`!F>0%=mY(T@({T1svhgLx;5G!?W}JC27Z0Fzp_0*#f9Kn zt?WW>)ygJPIbe-T2jGuQ4hKTJ*LYrAf-9gmo=R!QQU2usHt{^+%qS91Ss%Hj?FP(@UZ$^Dai1;(I>gHx3W9dwaiixF* zO|4ygb$}9|J*k0;e#y$*pCG~>=yM#yBegX#E!6LxT}t`0-i*7`(HLN^9@S8V^@yB7 zFp~D%OJr5arEBZ~Z}p79IU2@^!~JP(Mq3RPD@lJlV+7GpFhjgDOD*xwFfW{uC8IYW z&Xe6e?M*)b<-?yUMOJd{0G=Vc&Ws60*Lq5>rc(+Ww-o6=<&j65aGcnD9j-+dmANos zE=z4wkU8!4(a|feegLU*mU|N&2L#4t6B=qbwcTk~{tmOv?j58Zw)fbx(l%_W)oKAk zeGEtRQ}ax(MfuWWdx+YOvn5_?#m#Tq+cln9n-Ti-@fH6m|7DA?{mc@VxzF$OsRWx? zYG+;3rJnzLBni?d#RGD;)w=Hv{e60H*IuBb&-}{JRB=_LwyZWC!S;%}vb{i=F$HEv zpD0%!T|$%bFWkEyM!1KvyNIokO71QCp+?`VqY~JZ3T*!hXKL+k<1PYlf>)7s{*g-~ z@at4s1SCUmwuC}k{IvMe#ds*M_-*lHBZX?D;z3s*E=3CyEvV1m;w2NOi+qkuN9e`0 z>3X}@%c;Z*@$?!_ie1b~jw_3(UE5W$d!tj9=N4Ab^~jzbyDh0H+NJ5bHA>F4bhaq^ z=vtZ8G(#c(fL=O=y9K<7*^+SJ@hsxJ!r6%PYEK|Ult4B`C-ZD`Wu^6f){r)g%gZqm z#XCsjIW?udYdiA%mPxqz$V#XomUA( zqx`f~BJ!S@x*r=W{oVf7ajP}l-R-ZU5^0q<ZEiJi`bFSDACfi9b{V4Ce=Fi|iD%&(Ef@7i1DWs1(r&oe&q7!@Q+caq0#<-|g8`(RkT}z-4zZZ{C3PH6&cRxQmI$EkEt4di@oXi7kj+2{2VyJ~8 zg+&h9%Pcr8tKB z&C8{|Zzagm&r45B*Pz?qGh{qnI<8hATB6L)Opd`PyKV{Y!cOvhaR6wf-{^DQ8@f{R5T`irC5S>Sb{EA4j3)I$C;i@bu9y&tET<)6nYP zKMSWMa#_-mFOeZe8YGFP?N%AVN}SO~ThOOFt0{w}(7qH!>ij-iZd*>$rs;oD%0&DV zR#7L+c76LdY+s#tDJyV!76=9ZKe_Qw$HT87;@RYU-fQUjTWKF(Sx7{5-u9$JPB?R-Y!3{fN0EVgX*t_(pN&BSd7cf86&mIc z6*qb(A6j^BIl5ToVRo^Vs6LKIpR_j^6F;!sviz!J6l} zIrFN!65ILRj@htEdih|*hhb4PnRft&B{GTYv|s3SuyCjLm3-bSMcK$b8x*>md#>}l z*OH+=cmkAnn*HPT;Xm-;=w>c*G0ZSNc6nuk@pNzj8jnuY_rC*r*WX*Au^!4D6PZ1_ zKH2t4y6kJ0KQ3LDtM^iU2W&qzA25&S6Rs=hVyfAQjU+s_>oQipzcYr>q4e^_dBX*9 zO9Gbgn+bF!@jW6I54IcRs%N7fW#1E%<4iG5)1vZ#fZz|*s+NDL^jfmU4|$a-T&36Q z+h2aKVXd=TN0sY|uA@I49lmUd-5Wq*wIB$D#?nDa@*XM&@xU6qr}iiM zMm__8S>w95? ze%PRYHx$SI>*W0No*YWR_%u~SLXQX#-G3*`qrav4IE*H{h;wJ^e9ZsQ~v zw25OzRP(3ds&|t4y3{svAt8lsxQm8##&>|SXC0-@Yk_lAJI>k5<`10WD?Tz}eTp}< zDa;BEOgnE)p-~YT#_W%{9sUV8!=OTxD=KOIZ|SagcR|^d)Y0EO6G>4O?O&XpvljYW zN(22q(gO}9e>LJfzlr`Q4CS|PQ3g{yBkOg3BYyB3jywI0KH<*xKhb4~L1rvNK|T9t zr}^`nrTOz~X+wi=>8`h^awXU1$CRD%`m0_e)c=u%s1aYbm}}6 z4M@+^7uKy$;|izblz?a3*+yP@){d_ zTDAfG?@_kE9)JL-#|R+J6kB-D(&WTdoKinji}#aVOrhyf9p5xf!+YY)SE*ORl4R7FI zn3^lwkI`+%fo#0%OncRpRhG64fzHuj+=^N+l zW#dQ4OZjlj_(xh7%6m@L$teYklg#FYv3wp;=8xtj$ZEL*{Qg~|3 zdWX!Al#EukSMnG2hl>+)Yr8;18`5#lsSO-GerkOddc4d&qJH~ZXgfFTb8XTq^zcge z7*{WwOj=r{-=!_YQ(#`Ne4}ZbJa5w0_EIYF9)dPbCgZ>EDAW8Z&J6u<4W;F#IkYHi zAP?oyJF2VFf0s7+aI9F=%H>^e(Bg8&O6|ZLpD$C2Wo_5f%M06D;rAkNi}!#fk(e8S zFiuL3Nz5F~4tx14sEX#3kf^UZYGCih$Y<$V_AgC@J)Z<)`m5zhRP}Sk6zbEM6#m-g z_5Ed}Hxn5O?IT@s2@v!HbRnqzd+=RtUx7!e%+*@4^XvN6d!<@k-RCb+a(}wdKCAR! zCHZ_`{ZGFSCZz^O5hB?y0L?tvdFJd$91zCwrVtG2^qzkH-AQVHGC5h4rV{mMfIz`P z!d3pfQd@)^1i*QkLRclB+p$aD2sqyJzyM2?uE0B!#9^R`SBDVw_+#qLuz4aA?%hHc ztU?+tsKX~GX$w>Y8j{bxA|avoi8r-*Y8rf|6O8U9y2;cQV#&%R;OQeg99QPAPFK`} z?75XA9xBs_6Oh2D#2E_fR8OM^RS6rs3`xrBNV6a+>D6T@bJ3dqCa0p+-O}} z6~aLWNSQP0zmn!(N$WeavwcoJPn~D=+*@_@YXzNc84!(kAez>Vgl=*-T84VG@g}K3 zfrIi2UurW{ca`(31cFkepruk%*=UTBJf-x(KOIl@d&fUdChu)+=NH-1(K)=I%ureZ z8r0BZ=8!$4T7Tc&Zv4-^7DqHzXH8bg{No=O*T%H=!m`roV6xwavgWNmM38m?!LMWNs{0>(`svM(kMK5D9;mQUig4 z8$f=cJZk`yA$}lGH3Vor)0+Cdvy}4`9GsCR^OW{vA{h@N{_li&QnCr^SI)|}PhmLy zRLIKdy(NbV4U7>S+RFvop$<=hcX`cN(eKq-^!Cedu9Aa730KZU z-PnBtj?A8;U9iBOBNC09@To*$mekk-a6>Hw9GW z>lIHK@60Z3osT>u{PqS>H+ClP>3T)t=SyZ`4o{?_RrBS$w5w{>*dkYJ-CA=tdFajT zddZE@D&_6el7F|=?gre3&BkYFCSW^pq3HYBZaKsto}`G9x$dt`sSV5)kw!J&SL{fBfrS@Rg4)5 z%=x}GsZ^jVq_SJrR*OtHY)*-i0=E>a906 zOTl7@mlZ&w8i<@JVaf^a5xxa=#i8cSv7t8EbZXa5THO|xH-qnHFQShOfM28^9|5nl zZBV5+<&ibA4tvw%&nEa#A@^7SBU{%5*D!0-7rB)ZJROZBSMl!~8d$;tiSs>*nOL`T z%KS%VS74CKW={LNT_hs)Jpt*_k``Vp$0Ogy+h4-M%OA(hyTN7Xq1(RN-q+nn+WzMH zGMmU*x*RQg@d*BY_}z6Ty|9`sz>{kSL-|#oUy<0Nos5n0Xh<2R zzn#dUJ^QNEFGG%sD-2QWhjJlx50b$tM6wlGI3EE0_ud~%M{W~| zcbm|YBwz)<_ZfmD>gFvc(i~15MGdV&s|(4jAuEoOERJ>A=W5DddSIa0=sf3v=Rp*6 z_02^zJ*rc9g|;3YosE5n0IydOUoQTHaDAt~ubK2YG=Qs`)Rk|Ncjat?$IX26z_?j4 zgtOx1TF4q9R&uM!!Y<-6D6!G|;UGZKU99!chd=kaT9fYe@keJgKA5c3^8NZaozQOf zfP5qM#Fb<#u(Ic!??UQ`9~MJWX&+2VRw6GMzpjSg#IW})v z_WH$h?qeG%7pBDEsZWvTw#0&DcR%0XZyxLP+VDc&&UIm95$puR0-8ye6^T!I35eBn z6T!$gi14FSlFxyY8i#UDzXoSlbY47vG=7(zW_d4_aoGWY%;5#~&6w;QLH&xj7<-!9 z!UW>|<=kQApIqQ~<^sNeSTfMaORx5CjsoxmvGZnLVC@Sp#o2RTFt2GdQnCq8e&ee0 zNgraWrVgWT_mB;|mw2lDE?M)tU>{sp*NchjI=B3~Fa=-D56_6P7vMtT->9b;R6VYX z#pvExm1pP(B`hCuSTw-9A>7O+(VP}yoUy{E^bEuAicZb*`8R?r6kC#20^ylLsxAUl zP10)UQ9YPM6nK6fz6e$j@<2}~F#kCG1*ICOor00xz9~X?pZ=6R7e0y3bSL>4Er=9o6MDo~ZnszWL zb%8cSnkIOXm?2{ab6VTtIgF{Tq8I#K73cHqHF>VNLrtVw%eTMh@@^D{ep*Vs4ABI~ z5cklNL$iR9tS@ML>tLR(Z_SB0#Xt+gW(ees4aX~(h!v}8H1W*GlRkqCt?1N(dU zz0}N~S4Wr$Lsyk56QYh6Gh5@nE^1D!q0yA7b9;4yXln+qze*)Wah<#k93+ZruUD(XYPhdFc3M3CWC+9Uvy6{tC zcF+|U1d|}k9-n10eSVB4E7C0Wbvf$S{kA z&+Ors^wB7V7Lt?QR&{kfcA6bTxMp@7k&b^WJ!N^S$r!5{ej@*o)R!#a2*VZP;%)(~ zL)OAb09Noae1km*709q>AUZ@9z>Rf*Lp!4sW6g{`={dQk6Vk?LJahbwi9MHEb8^7- zwVRvGHMC4y#0gm>kHN)L&qu54=!z}zi}_w?$@;d8FC)feH)+5JP&O}vEV#oK;jkfQ zn}WV9xycl7N+g5=pR@VgE0cAph7C5!mOz~SF^06WU)>bSO`Ge}UYJKl-<63k<9b#nYfc>~uboBs=U ztlx}3AH%N{OTEknE|yy6k#rE;j!J>H!D)AMDZrN6MfDI#B-bvk0$gw>e;=^V-KBsZ z#V!SY*+p*#0kaUG79&MuyR;CSD`9Gdcra!@3OctO8~h5~Mf%&(44_OP3$vQBXJr6A zbPYhG@!|54=ZH*ZgNxKxLd!eDhdwCqv3>1X07SXs)b}~i2r_0Xt0z z%EF~oESS+%EwaePC$C1KUYQ%z67}#`SExA=y?6Nx1q=e*)pfa49Af1wF}PLR@k>H* z1S;z|VpNg(#PUIzZp#Phz`>)IX|f4ivL?-4Q$hu+|Mc1@_u5F>U)^t`zy*wF zX?upWHZkX~>Q@wyga)14P!u;+Lqy%W)!j5{tf+o#u~A*TD8E^+*uA!7f7YYCOOCpc z%0CEV%6UeR$~MHvU}?nyH&Q;I$#kGMFO|dO^Nzxzewqb=AaJ&TD0NB^@xmxsaA&bg zY*t(qaXXgMXs$9HQgj1OHZ&YG7X|b9w%{ExjwqyP_gilU6VR-B+}r2;lb+iw?nOa9 zlsHm`U&QB-Tq9p{=p>Qp4oc_lRSQ(a0F8X(QWTD$!rcD-Frh`S%7_&s!4;R`nDMXh zT|ekxrhs61_$~moh*Xn@OUVg#nRyGujI%LdE{@bb-d>!Q=oQG|Wf3nVD1yTycGo9J z0z$l>3`G557K1VFk9(gHi%!vdY4geg3wSC!0z*8tE;8;|K%@9qg}t1tm2=){N)-}?Pp}e8A72w9H(c~ zq4NspW<-T9eAy@{AG-393+U_}U-NKMc_nOE4C%`{sGNdg8r~U=`|b{rQJv@wLZST5 zklA1}_|sOwV6+DuRuj0hP*OGd41c&vE?c>;zGafAhpf*<`ZRfN8;X{IPdzerf>sUkq2!jEP{Dn0 zGefmtLJ8A(l1=Lgf;A^ByIR6-I-B4KNqc0CfL}GN8|+q%I)?)Zvl}{gCDo*L4H4Lb5!i8HPtm4}Ke@I71k+Tn&aFMmWkw zGYxgNz~fpWX(ov52GDVG?^6dO|uBf1ZoF|APT zC^ml}JD&Gc5q=6YvjCauWbp(yllK&)d}jM#2W!-@-q*AQ^cOj*@<9Aau&czg=FNpx z*PAK5Cs6xrX}@j7)G)bo(&0t?pTnTX!y%0n7~y^9w(0xPDUNUw6*ktvDhaoSe%F)y zTU?Yxf-^C713!I+mZ+S*KdeNrM45~Li(YgFMfp5zW^ax2%0>s$0z9A0?6OyVw5Xc3 z0($GgN2}6f|9FBV*<;TU^ex?i)8X4$FMa#vNu%8XW57Io>JLGCS3&IuD`ZWMpsocYk!uOdqlGA@zbWgHr?( zrAbtz@#gG=vZd6Ml`H`XH>_;E8GCYXviKIc{te=ey*^}w~Jph7utxjk)0gc0~)ETrBVaTb-7A9BUi7tr}=HT%N zUZh=SPp#|c7(D$)b^tm%2up1=xM&>=x?BE7Xy!E&K&pP4Di&0^x?1yq+=-v{PU+7; z`p(=fjE}A_N>sbo&$*I|7Jj+t*7m%7kaBhKs^E)dI_bYB8xPIZ>F8AVI32OW*+*z4 zwR=j?(o!?uiM_0k??ndn$Qv|pjUG+LvmR)qNBCuLc||*VMBA+?vo+v!LwTYK3Y{`@ zaD|FlOL4cFL=3d_RoR=E`CV$Oo^-LQrx%XS$lsBw+(QM^`NXs$l+4V9vloAR^7!qKuUsfmOmt!-_XbnGe?F-8Y=2gxqekZcGwfpGN&jLD-v zzEa`fT`{L?r`>7a?Z}G`!Bd@hMxGv@ z5gJ!oc$Lh&k6stEWnx#xY#F&W-o&+Wb8XXH9A9!Ny*u_HQBMIU$DiWXKY$5ta*8xX zP(zWd61ih#uhb>itknfBnXA!D=Jdo}7EczuYx))klWnO7n=54(nu@!rI>)K$@>tW1 zn{)BQXv*1Om31zfLr5kNJ+lI-9TSMWI7v%J=-9P8PZRiP#~RwP6}#&>(|MI)333^c zXMX6{eeOZk7p!SwIk9dc_J|+{OW^Y0J>!;|I+I1(u_WUT@bGMmQ)O6n{h>30)U4G| z0|@h`ektZnC_ZE6O@CES5pArI0YEGzvy-e?tl@7l{KGiNkV1X5*)WF?kum)ta$&6U$ zC&<2|_r@>Hrz4#$$^_>P%&H_8OJ`PCHdZm`(q63IqN1^CWg9WPrx7&RZ}cLR9kF+y zLcAYsITRPQY!j*H&Qb;Fyt%fvXova}K7tn;Yqq$x2YGB>gg${YG0vAUI3z)d}8FIKEx;#AR-sW#CtD|71DWnARoF@>+_?CJEpq={F50?n(Q z=WyTDzrTFd_5FedL|ahxS818bqq!urj30#OB?R7w8IzP(oETM{B@N&<`D2QXe!62Z65M0be!9)_)>C9SFbxp&R=3l~EJKKPu@}JbF)OpK)?j;9NlY;sDDXzGpkd z6WByv(w?314PQ{OgUqwUMOb&6Dd~KD>e*ej=aJ`kbcpd3HJFPoe4DYlo~t`Jyl%wL z4DDgS@BO}C_RI+DxUyp-dm5N2`@$nZS-Y+7OIUe?FK5OD@pP-39l{pB5{jU zj?Ti$gL^G0`C!E?!OGmE+4p{U{NmB;|9JT%fxhX%J^2?-PxO16s>DD0XS3O4{NNFw z9FnzrE&ZFFhjjqd0ea4#wYZLzdU#zwVkcOv5jpY+xiv5%c+EiE;ICHf>SpfMSuejb z$3rG~WgY$&u$2ua{WA#WOr}ZeK#*xi^z!!To3m8U&%G% z1nR3-oYw)K`BTKq#BF&`j)y0&Au?8ukj|mf^UVgPD9-_*kn^lm=2fJ{s4^LRyI8P* zPZCgJ21d4s-L$W^g{XA&MNK#kRL^rDZEmZ3)eY_!GzcESTW5hb-ICY$-MW_xQpPC+ zF&fZsd*`kg1xfWrC@jZn3*$sVBOcfv?IO*?YuMqr3&1xNNTg4fy2pl}URpBARTBy) z!NCzz5l6f~okDmC`2?A(R;t{a+DcG=srRR-kxgjbK%qvSJb&@z`RkQjS>s~K<+s9j z7x5viR29}H+bjPMJuLqLr4lwN8zGWE4mYHDQlSXt-D;!oO;aeu{C{JKMLJ?JcR?!z&X|S z7FINHO6}BR{wyRaSe9%fbtDvR^K44mavE?WrHGRwL7^P}5%tcJOFVL3e$yMg_R937 zQKjI(;Xin;YjS*&*q#OlC>|iRY^9Q`v)0|`~PQu`8R0Pj+>X%@ZX%jrd)fhWbLM5A{$buV;wt)R}12PDufQ6^_@ zwjeugJ4=#ym5Un`ZV>-KCbc)D1gl_C>qM0e}0 z=Rf?lopZq&4BRD-|5&Uw`(52{H~Mt0e%f~73dUJ}iVQ|6n>EQ^DfzIlpEXqlOqA#r z{`v!+6PLeGscrJAj)w2d8kh@Ga|hyR2sI;{&i1zQ#YC96@B5dsVS=1htJ#y4VhFuj za~B@(8;-!>n8Wyy0)-QV8W5G*JXFyXxkjl2D(gjM0lj)8^9?4cww3*mZ)^O1ls-0} zP|&kKistEAdc;cC{P)A-RD4LiQq7d~S;H!(lMs5xhpdEc*NP0>wX%!f6-=HVgPP_XZF9;lG+_(s4QF;J%a^6=D#n_8XBV>N2sKB_SFaw63~#-pVs;8Aft0SLa0x;?H7>|@+#J=7IZ!? zF6@}1F@bH7!Q^Tv7Yn`O5eaLlmg>2>u4vh#fl<2j?g@uUHA0p8_ptiP(co1vclo`t zEvwrZEVcgmD&|PKi+r%qw9Oxq^~fA9>dKz|b~(Y?NYe}`w~R>r9Z9>Fl1S%?$e55N zq~bE+HmGVT2{-J-WyRcVEpx2z1tM%j=rkomffEZ+`{vg5??J$kTf#S0w}fl|Ep;yc zolm&Ar`jbYnMK5xWn~r-R2I?z?Js^7_9JIga!o-~h)JDr@&tqlp8|=T=!}8y4qON^ z071rFM#7UBLt<)vzLjz|NZAE$Tb|4(S4liI@L0%DcG@e9sLqv8h_3d{_RTwY?+lvF z-p0ZHowa_u45BMvODyU-UkY*8cNr>*{=K;lq$r!3tUucxlk?^Qxe*-g%+B_SMh);2 zCYrem^C8YbmA=9kTKplo4ieDM=dOn&FJ@0%sTp)im`0PchAGao6n5y;n#zK)t|yEv zViEI^q*uUKvx(Y0WPLgzC>Oc_N*jcXOqQ+;5Vc^-H8YvvsTxULk$!Zk-X)jVz7BND z<_yMj1Rf%AA56R%AY-|)7IfbtL$EiF_KfG$wk4oTi^@zP^KUkrk(I3n0DEHQB?ly0 zav3va{lfLG%Ni0{K1HJ!yev5i#bMe@OIAP3iAv2D&($N+`VPT}Q9SK*_@g%X z<7E1JO3TAZSQl$zfts=yS_@%=A$$oklJoV5z=eG(!3+Boh5UVe6s9@tMc|cx8w~(N zT3X zhQh>j=WQ$MTGz3o(ldvVa1FGV>q0#dh#*bG;IZobr0i!W#bSGwkV-bbMx1?7?ZLqsA)K!F_ItNC`(@%&VP!EXs<5z!eR}f_W7sT!C*#VD((Rq? z=eCT4rDNGrr7B$<(V3 z>J`~UKYz~Z5wFw%t9ZNz93%^cRPgk4lCm?>>&bg0X|iv0gJ@a<&Ql_IW1MF9faB9s z!c-!Peq)H;6-I6ceA5JU_)}0*6&}@m>e5e#BxXCM*FyDbW>;tSY5s|ix#?@V%DtEh z*4UcgTAy$qPR6FaUHrTELz4;k#X&U~UC@Gjw^$oUSnSCm6-rzz< z_p6J}^>dyFvJByO?Ir%|dKDAsBxUV|OYpC>hX$YL^7{>*s!_sy=zuF5bNP zcq4i9rkW{a<_868T@eV-pNl}vY4$us_R*O7M@QHxG?>7}OL}L7pvf{bZvaL3;9Tvh z8@imdUZRpYmrI7XJIPgV*238da3Kh=<&K$B0Vf6Uf>^V4I6qf+NbqOU#Vq7e#m$5u z+A0J~MQ60t`WKxeLQFg*LizR8FZaFn5Vd-3wXi#QOn5uy(a-t|+Py)4hq0Nml=b zm_*f1=o^~RR&6hY>yZzX`|8)s?96CX#|AcRA6cI9=2LtB&F=165!0Js@SV+0`%SHt(?>;_h;j<%BIyy431xeL zp+te}d5&_}eh@G=*6QoGlhr%x^>!QT8YRF?&I1xG3Hyw&B42_P@pd&BqR;3QXCn=V zm5YYsBkl^cp$-ofO_h6bEs3k(KurxUk*5=kxZx=ilmI>=f9OXZY3fpnA?T#9i2}{| z-Nb;(ZC$?&8Cn`z6}jA740)L_S2K;`NDK}g%wk85uWO#qhA$ELH0jYI30=17N3J~@ z#^Gd^ogwes58+Z-R+IigbKZG^I$!F*t zDz)TKe~K5l)oI`226Qml79J7bENkG|=a+QNDrsQ7JQnrjmW5WMD(CFdU{-CRCv|DK_}C{XEy4 znY2i2xw2-YVOft!`xg#37kpL`ap(fqljxK%lwEK@-ndo2bEy;I zYi!cwlADy5NLHtGqZaO#d7G5$p0iKeh7nw13oW<-7N$0DLM+Ac5yNOrC6w*{Sf)8Q zJ@ZiAZ$aFB-nUL!Vw2SMdl)8Q=-vZWeUIWkBgKW-5*ywEBiEe~&o=UetFx=9T zezz~VTQVy{PmV|Xtuu5%a7(Ukr+6zAYe!YQS^DPflBJ)*R;@w7weEQb*x&udbPr|s zil?CLT>Hw{d{gKLNHBIo;U3y@!5HOfbbsIF+sW$s`ki|FW{`fU@D7BO4n`{N^{10G z)m(N%z_&1hklcr^xpW9wj=t*e;Z>)JM|H|@4cIc6@lzpZE63@uk*Gx^(01QvKu+!R99Qj_@i=KcDPR zj$QZ*x7YPqR@c;KzA~CjJMr$Kol)vhuEpv2`Z*LKR)^QT!Nk1Vg0K1>mw1CK_$N|V z@^oI%RUGQPEaXINGex&kxS_}z<9DO$z0hsNufttMALTSak5Ejngj!jp7F6ePBJ;Ft z5P3etO@t@5*ST;YRXAj2#wHuu%kEVmpq5&3=9_Pd>^8%8uh(yHHk@{-X8`Na6 z$eKnA(YStY26I7t#W#=Xv{N~n%xF0~hZEY;w)~&*Ek@vi;pBitfIybTHwo19b zT8Xz9Z^qq{noM`18?3l4&2u|FmQ9$%NYtF@M5&N}b5<_%z9atH9WMt^>s>k-Z&AL_ z;jPVjh5GUE3@1nvEU?O_++>H1V^y}7>hBf#Kra`@dA-E$SH^oT$uq8>7i@BZ=`pz% zX`_{7;t6`Q^r`@`b@$JmRbG+i> zsWP3@TbL%(EkMMQ?Ast9jJTizZ{b1!tZWfZKo&2+=4?8IbPneg#W}PCvu?&Epw`b-E)op7ji998RaKJKc?ZCzhO z;6!;!N+J$AxOF|^(fI_!dybs0cq;N4Ma;=Y)wqw$!+_|)Mr(jomZU{@^N@JNhvO*Pk;SKzrf~A`xH;R^YhpS(m%rD?Ms$7LNz1|;TyuLPnEJ=oo0 zF9*W@NukHxtLFIEMFu2E4M8)w#O|nE{E+gS!Ri+X=SFC5Ap6;phBx!=3*|zxj8*c5 z8vxx!7ne$PpmF1F5qsa#??7PJ}GzSyj1%#>z8qP)yo!`fGFfLzx0&fB*xYH#Rj z^#*0Gw}PfdgBqponQ>FkNmi)(b?*!R^2Q>!9q8yy7s;Q3^iIKNDXqci6RhDxbCv7o zqrnfm?LGKD`7NVzm&HTAspULBm1elGZM-3+Rn1Y0nC*Di^A*;z8&AoaH{3bwUFvoL zqvM;ZrEj{avb{EVIMYB(YX`i3j>;~K!o(=LCA}|$;tk>U-(xN_IypJxO=0vXUv3M; zcYzg9o^)co87VG~Pmg+)g$;98s6r{fR%Fl2A}lPiMa9RqKka>(__}WCxAE{O6W$il zJABzdd{>trOQ|r+WRs3Kh{kIA6kztK$_~yM zsZq-0WLn!hdsQww)BTmZ%)6s_6TjMOP-SZvRAyz zZ-+ohYValEjAJb+uo5hH>8_V3RNP%JL+s01Gd%li_TJ|>))MxM_roFi-Aqn<6a}3# zVh}?V_y$FA%$(INY9~(AEy+B+v--BSC=S{_bd}-)}kHdX}eSP0) zwMrlq<{%YpFNIGad+g+@JbUs=`iK&q9jaR`IvepH3tX?n1>C6-%2Y4DOHW2YS2lxM zC*OOF(OwGYcRRml^G4sC+VP@rT|5?8+PHX&)v|Y#FIJWp4aPlD zUDN!TxyXTLXCiXL-U%vF5?&pG@fm&3uK@vl*wqj|9Qp{ zPkKW}+V*~R(@Z756=CWrs`}-L;ty^GsuC{d^dwHz!(7JoAW-2H^nmZ^u}1VgeMC3? z>aGk;I;c0ky40oH$Wz(KJ`uSWS1N2;?{e%Sy5uU%fn0UP;Z6Anc4BaF2hQ}#s4#TY z6^$UQXP;*e8!+ZvDX)3f$l4Mz@^<*=Vdza#@Xj5f`A&%@Hs23BdGcn@ztc|@-8q_u z_$@KhmN-?t9cp0Zd4h1T2{e8$U+lc5Cp?oEf%d`F+621RnGrJA*8&YkjBL!7*Ux*? zY45YVuZH+sLN;tx3Jpm=k`OV=sKGn+@YyoU(0$ojYb~~P^Qf=Y~17A517IPt+HKjuibUf-`qEd z*EHb-fee9`L6GnL@c6}}*Z=YI2|s#pExE@(?;R0OdTDkw3hWCyqpCeyf6d2p}A zFR3Uv{eyeD;@Fe-D+0S(Nl1RWPf-Vw5{u*~`bx^tFY;N78|rc_9rqt+?%8z8s>I27 z2i!rE@L^|QX;TlYnz;vUP~gb!16fHCs1c$GYpzB#S0XtqqyFBTu>qmK4{W-Yftsfqm5XSpxTkrn zSp(;Hp0)2+q$dsOmKk*F2PPL~9B~OicuuR4Y#vsu0{A6${*V!^0og5F8Xz;-JZmtz zarve$k|zgxzCK(+($tHqRpo%}Bn|ndlFvn!i>^MUlg0$U%U40}r)UN<*EdQZJsd37 zFHnulZ+Z2ZG=gene~#s-EuWE0EhYkUD^@C)m6Y=TG=>0Q$jyqD#ygTk z4VTWA5~gh0=aZvpS#+c%ZsVftHG)0uBq#9lMbWpUpFxhzWoaQ-#+e_h&G(PW)=F)` z5zBTP6pUHl7K}L{kPD~3%A%i75h*tfGtYY$NxZBoqF)_ScF#wZ4l=P|9)Jq)jJa=9 zCjl^^Wm)92Q)a@pa;fKycT6#7|Amp6Fb+9-F+}Q6BPp!+47JZp_Y#xy0sv3aD zn7;AkV->enZr@)i&c0BMPg8R5etcdDVe1Fi4g3`xFAj3c7d0{mI?jBrYY*<*KIcyU zoT#LxPV5{D1^cllsb|y$A$y_)VuBDBDpW2)6EJ&vLc~6z9tEeG`;|P%9!~+7tt2Q} zh5&Oy$SH7=ne1a4O$G+))fuBd>A5B|4cR^&?H`K~?u4UI4*878lKmpRQ(rP#x?@&> zaRL*wER>aPfmO+E>p(<6*BZ*5BV~=46B7^o&1=MnqRpFA#-WF~QmVPksLF(QWeOYn zQ`TbS%~d@S9bG5MDD6bCSGR|nKP^GR!H6^F5)&gkj+{tN16;TylR-nC`;I9ziG6d7 zo%TMC%`w(Lp;K{}?rl##QG<0~dN9ZGa7;=Tlo%UysQyR#NR?}JQFJQQ!34PvDyO4U zYe1rhqznxn2G}CI@>N|6(hPnY%^s0BvS(K==<;)>KYFAA{tJu z!Apt2xeu!H`T-a7b#RsQN9lB49}f>;|E*>e#)2=$G<6D9K~;hzGYViT)pTU0 zs#$@7iIj{hio-IXM-#gl758Hw3Bd-4&bfUb`@#j)2FyF_yI1s4c&P}QG2{@=wRr!D zk%@Wi@WYOXYN83DD?(6uS>G#QZo?J;IZCP1H}`e-*y`$&$OaJ4Vx(o1Rg&uc4_=QmgF` zjhGAYyuK)K++Yc(i$LlIF$JE>>(}5rc%yeZ$|>&33aP@bf4kpn-`Tv`Y~I?qd3*EL z=IxlmuCyXwQCC`!6?8XQL8l5}b8Wd6$q{2-!Z=;eq{FS?VSuHzH0D=e^R|UaTnnn@ zK|G%@4yeQAYWa^1Bo{P%`?MLsgZX{Mif5{tG|I{Ldi~ahAaIp^fWg0(-LVzK5dvOb6QW%81_z*V__oHnNkN} z6ZC1n_UV535gV7YDb92flQsCbB!8i5)B%I!iNmwhX4{bC1n$K52BQy2>%o@OnR0e6 z?LY1He z51&;5jUfQRMD zXeIe20#@l4(7`VKB&`{{Dk2^6q1{V=Zpv{VJ~LLkOi8xN?d5@EE&_KAG#>HD+3o&H z?CBIsK}7%8oqso3AxVN_il}rM*QHJ9U^kuOr0g@SFuvN5uQvBW_nQmj=tuOoopjj* z*~L{Ao3lr8kr}tEuHBmK{v;T!gl*gJP08>|yPbqry18qO;G)gsDeXWy21(-pG}!4x zMCoJ7_-JlD^on^9op!XnKDa8mg7{V+E1r}GPbgW~(G9hw@;K5&k*Egoo$m*_d{L$y zLO`CAWT%qLo&!7R7*?Bj2A!2>+pqq|il)n1!uRY&{qW)T_D=oj_V%yHmGkLg{ol5? zpW*MP^=J4E|HzxIN_KSXiS9pkFIQcyPh)PUz7G8hnp3!JGJwBEGT%*5$|lW z4ZY=)*X6BDI9f+m+ zn%mVRI}xdMf&tSrZ;Te}x8p;O#@!Cx!RMVlMG36DJF6QE7OR@+Ov`lKP<7N5RRPBH z-l!SwSx=%5?BoRJRuVZFkg_U8w&@uXTmwd&4ns(7#L^^@i%7=_+8Wr%t93qi&+5-!aB#JmL?8Og0D`+Pan+IrLd5qYglN7Mk?;Y%Y; zg{_TLk7rYbPSLbOG~-iGZe(!xmDH3(W|Ontbilo5;Tcl%B3D2K7%53Ly7(u0Jv`W0 z-(26=TyHivdYiWfo15zkT@Q<^Exjxje?v zj>D*oy_3DhUgKrrdDxne?$aKr{OsFy!l4CO=DI&2r$i^t=wN0hEdZv$WdI1^{bQLG zS5O`2ho;7xv?%aylO{~U#0#DOjGq`!D8}2aGVhG~;bLLhOY&)|t?tcQ5u4UxXu#vs zq!XjqsSbO|RHEElmb-{|bA8S9jN;v!?@NCf zciqn0+jA?lh?ygA=qMeczq9k^k3s`Tfe9pP1j$`5cHe$AONd7;Mx}1m{d^X7n3X5( zN@01IAe2jLcF^57Z(4hwI5X(2&Rv@sG;);suIKg`&2bVr@4q4|F#^U{U@3I5xHLo2 zZo-3vCPg$I5rU>B$m{$f#zs8flq?IOuL>B*^7{>S$+Agq@#+NYFloBzOde;02U@B9 zz>#ME+-p&!`O5TJ59dw>Hr9$omXiMq}q>1knFTJMR=F#Kl zZ(siU@Rz5L-oD&^{WEgH9L;6~Q`&0v2V-Ivy%Wlb(4wIuTFAs)4aTH(!sV@+W};kR zx-g@@L`6f)z@9B#&JiTR2wehDBxGi;iB4>Dybkoh{7AaAAzySo z6}}qmIBG$ycJPYa5$GLrALR-xjVQLNx!K~#?6TJ60QcpWM2Vl=mG;fpUUgqm2o$WN zThYAsRXQhMhT3^){C~++_;hQoB2liX@6t|86M0$-DqW^VEC<|0rer0d$_b2vP<`$R zLDUl>K~iatA7DN%vN&JAvw6}DDG1p0b3a5BZ(^8V7hRWbr=UI)*~EcORITvkUtc|a1eQ96fX=mFbY0Xp z3yFvs{EbcZRy~RQUT8^<1Fj$5gNhKG? zKZ1zEX6(p2Z%;7&He#|YZ27tfAYF6^7`}pptCs3D8$SN+uhh z2iC&wMVsrl*u7};)~)*H=B?1bDB6tgu0X?RdzTfHGK8E8I|-0w2&SWsxJJZ7B$H!K zcs8NGZppPFv6(e>dLgJ813uF}Yq81V4>Gk1@QC+8HKPhJjs`{{FiZO_l}=hIMPrcX zBknjgWQAsiBtu>C^#s;Gz^bf6%{m)nMzf4Fk%i+lDCmr~8CjaA!3prx;J+84+WB_v zPQmf1E=qsL;&smTUU=g)xkrY->G6S~_)bcH4z0Zpd z(|Qt4AoYE>0`V4uV6iq#F;0J|U`vU3MY!$4ouPVO@!h6kXjxKiCu1S*Yg zHCOIt=T0S_c{o?}R;H--I8v^??iXB<0jz%doj3kTmmuH&4_n&+w z!e`1@3MW4P{M!-fUr42id$y-5m6uN`h2spfJ53{RNn!-5w8i#NV)NyJ(UUA>ASl8$iGC0BE*eJb&U_f~6`lCtRYc z*T22+?S*tW{W3i4Q9@DLq<`r`>vBS3s@z-~a%CIn4UfG#>9Q~}VwE{Kx*e}N@$(jh z-cib0N!giQZvwi_kc;3cxQHkG7qF9(`AJs2Jn}S}ORyYwWj~K-FLd$t>N&Lq(TYUx z5d8$~iYDYC{HGhn=@kK{$io=3@XR2OQ_uSDntMZIo9IV(9JD{ zaJ0cVGbP1_2|Gp97-%=_1%>Lg#i*{|Qb7rv)BbV3Xl>{!!lm`eLZatLr_wsL@ zA_>#8SI=FP+zAr%4y6^&93)DaIsZ`VLZ+lnGJHcP&@a&6dH>Mm&!Trd@a+~>HEVL03<28g3+5J*sKQ5hl*C}?7nBfMteaXDm2wpg^xWw);XZNEIuMWJG~dWS3ffieN{Iha9ob_C!>R zF1}H#BEyg8m@S44RxMLu(`&V280BKyg&Sit47}Qm9gGe`_=zXTH!gkBv6>Daaj;}g zQuJiR-hM{x z*hwlR)^L{_WKwkMop~f3g6zt$ht@>lIU5?rya>Q~xLV{+A}- zu(AuklBm}}Op_aksdSg_8O?1#P+Ye1-{{)BFTx*w?YUo<5>6MnlgkKfm%HtL ziFv4tj`6LRI)k59{@{oE@=%GUJI^Y#g4$Gk#$0#WIaP9RJt(lAEnwT%Qu|U(=4!of zYuS(1q8(o81Z$lscUhtRS6amnfU|qV#?d0lJ%~l)*Z*jNIBxUWgrCZ0~{j z(ieMKRU`f`WS(VVRC#(nz7z!O07#+aGpKg*-;Blj2*g)^V&)@Jd*kQBFo&1 zmpeJj+?R3Y%K2n+npPIzAsB-!$(Ib_=hv@aE;0n;gRfrlv-h;@9HPWq|G6+F z-je0Y_A_PO)EGPyx@UfCla+Ya{U+#Jd3O_^BuNZ>dN`g;O?;o{k5^%O!bYq}p!g_N z-(0PL*|NQzUVL45uqSX|W~W6$Xgt2wY6cy|w~RGmMU~S=(C3|`^>@?l7Qp_A-K7ZL2y#@Af~Lc7IJRE%$Jyal zY%<9(r;@t9nsWY1Iihi0`(@G_`2A|$psbRydR$Hdzms~z>Se7PhMt*Qgg7@g>Bgs( z85A!$af8~th+REwX@9I(k386v>E`yHj!_8K2)3qUs~JQXaoXcfkbGbPz14E}qv$w` z^;pTG?j?SxW~jMYKz9SwR6v^1s=Z5N3xDz5aJMgum-wo_A2z^Y9-I6YAp_4Rvsbhp zzX>#*eOxLNYvH6D#D4pdFa%`{mj`+nArVhG)DX@X1_0UMG=F_*R@D&8iW9%D+Oljj zS$LMh%>z^>f%mW?W_Ermm!yz?14J*m$-fi_>n9qaTuLF`KX+T*e-T!zpua9Uiu%%2 zv|&P1=sJSndo^p|#(+5V>Kj2>KnX#B@Q`tEHzbE6N1-LMS~zOu5*oNyPkw2aXyBw$ zP}INBDRdN5Umai8IS`-bT?0|+es6Gzp*-AvTs9P53aL51d)&LFhk{SzLt*bM781Th z#kceFQQ6SY$iJ?ynP%d{3wm;?Q3lN{?9>@i0xGG_RRAg-SY|HhPEe7WLJyvvo0BjOa!HF{b!8DB)*#tnKk z2IIamC-T|$Vd2(Wj&K8U>gqla1&i^LFVk5HqA- ztukptia^r%&V-Dz9l3x2veY&#QFrSgi?-4wXzJDQ@a(uZ{c#a>ZkWWN=WdMT6aj|` zq$1$jL?F>fxGSTd=JM9^Z%7q$j5>B2b}Nr$BXZP_XV1YLRoZozF3fZEa_H14))=0mcXiK!qz0VDmbQ z)BuR%^ic{{X7Mi^$^SEAXReH=OGNfzRP?=u@5C$~#UVZ4g>A!rQ8vRcb(B?;x%GlM znCdD;7Lu>RfIQ_*DFyjj9-l?!{V$h37hk9l`eOW;?3Iggtk6yt>2<5$45d*aO9KWDNkiXEHMVf$gN< zR37-|tYjgh=R8h8Fn(ng(gG~4=aXN_eS-j6fwe}4Vw{q%cOt-ANzA%bf{z;@mPT-K zv+orTw>P-i@AnS+&F1>uI|rNVgLVlXZmy094sNat5W;TX20j@5yV(XfSQfCd2(h&) zK`t)If`d&*QpeT?^OMe8Bmpg^>ZD0Ao01gTXdsm9?6 zr_`MsaAhv1DaYY;M_on_+_ldiX^u8&i}CB~mS+gwtocid?(y!qfkeI}r*WoKo70T> z%6|^06G0vXX94D5cA}#GyF40(H2?}}J&FI^+ok`jnaT9w1|Qzq1W@eu!$*&w{P@$) zPyhNqetGu%#mj$twe$Mdzy0>_|M5S2`+Z_1hexA#?~hN$lhgl2UfyRPK7RWApKEQ( z&~o$E?K^i@0Vr#${BR6^&MJ@5z@z#&>Bw^aflA0E+@si~KPT0O{&g=QK)-(w%jqQU z$(H+Y!hqQ4TYY_#nT{g6C(KuNuC+6TZ8q=yNmKbKGbaX;Bu z-|{jmB&+u^IlKJYAnRS29Od$D2(L*WZJF#L(i`G2)R#5G4v+mm_>B+8$SWx?nWmgtj6PGyMZ3-^$Wh6v3)m=iIB!DgeIquamc#JlWi=>pNm8%{m4YUBQC;lW1 zUJS$hc}#y!j?G_v{M8S0n`4hKVjtl8fYk@6bH5KkY3=(gOtF1Y^9I2H^p(1^Fz8Et zu~o6?hL{}1`2W!Z+$3_c$036`yB!5#^2HPv(3hMYsX9s-Mo6>SgX`p(ZvS}HI-1Pz zUlxZv^2#JMy3@aP=g#c|Bs3bd*Ea6PSZ(ZckITkhgTZdr+c%Td&HDPC0APH7NQUhp zoC+Pp_^2FU{2Eil>1Trw&d7@WQ~8xi)nSR_)yaGRFC)bU#c`hdC61w3^BzF3a(|xK zU(d$DmjQ5j-R13N)bd6lK>8@%-r0VRpO1(8XNUNOxbxX3{PG*E%;aNgQPk;|lT(M3 zPKs7itD?!*lPB!;okv->kmMMxmry{P$FH;oSOPv1ShSWN$*tMugN_`wL$D* z2(2&W3x+rU(}SvAv>N+XROqsCMnD0`4ma`UN36Ai=K})?$U@LKpk^+rT9r6zkuo3z zy%{Bn=qG9KgF;wFQjpMaNMU)z8R>W^feNy`U8@1-FKG&Fl_r(4dLP@gW0<6rtf!O` zOh8vBGh{)N?+-}jgeeusN*3B}_!rgro)m$@V~mj|#4D8&y&!LYdS&W=e`bB}#* z08Ah7)+UkYxQYu(AY$gAxsjMqjtTira8&ra>*x64Ah~U~l}U4Yl=mYwnP9cF(6 z@$k&mGAemx_RLGfO-TY^tD<aFP#6w)t5_d;+@fsS8f~-<7DGJci~AK85U+8)su@8(cj-~? z(NWz0fq?vF^D=>ws=I zV?(mD4l4PIIlww4E!r%FtDN#PQb*PNi==;Q8V1K;^hjc~P zF6uchEj44^*o!V!&h^6%Kbva{r`(oZD%HJHf2t%+1T?|f$vm5Px!LD z%?B^f1l3o!d1b=GpOy%<;Y{ro_@=}uqboI-@4H@yMQ<8S|79+`EGJPGsPX3p&1hP5 z>nV(O7A@XAC09jFJ45-=a4oX{GwwNxkOWjZ)nvPPk)6N#y!^oZm=Vxb>N zT7E@&4yV0wddhosaK<{Ao*s-^ABfor%5=eDcN=UKXRVoWswUb)ICaSqvC1nzRin4!Ep`$ze~;)@rRMPy1sx(!Q5 z=DpTLN`DbUM>D>6lIe~c^y)q7eFhDDmSOf_QFT-#wPcssEdhHuVCoDiU)|akqqLwE zp5Qq4$zcv5m^AUK1Ngz5bXD1|6|?H8gjs5;Fyh6T!BUz2bOJ$;+l75LagwLG;aH`-T`=^lCqN+tiZu}G>y1Xt2xV?m7CRCDR;^(|Fwt} zq77T;3^*H`_1jmqCO8_CQ1X+$aDpI{KAWN|j{UnP4MFCr$&Xf7gBpj&loqeNCWNVZ zS9V(+JwRovOIPNqkaY^Wuf%@kj-=FiFte_V~#Zg*Uj*wsvf0UoyUXVtu;Wb!NH&b z)3CV|aIQm!RI=Q83p9@eLwwMA)e(i$4Qqxj0hGjkIUMj6+dtdv-T-xvSf4{b?%hw; z>F4Td&ELv_&fU-Wo}rRrX>oM1)phe2pXiY*a1pW^or(JaCM^3z#wN{TNqazwCG z)BQ7KYdY*1Co;$qJ}dRc4=jf>DfDWyH62EBTY2 z)~m}N z5!>D|ZqMJ;AFHJ-?;zJ$M?J*;V-rygJAV`YSpJK$q4c~A8a_f z_eGe<`WG7IGT3&@v%q^wYWix6=Lb`gy2bTs@|PLBfcZIA_Z0hw^>);CK66!2Wl4-n zNHS7CHVl#k`#wq_?9}&Rq~#{DMLWuUW(P=~6Iyx9FbN?kXCMrsis-98IkGfs;bE7d zX`$!U$fA3m`6Y**5{Ud6xikjv;}m4Mpk5b60s&{ZxfSIY8_F?E$yJYctd?*XEpN*v zSI%dWd3+{`@)?mWBW%Xo%rC}6-ZktDX7|2Zdvohg8RRE*ac87odA}9#1(GitswKor zc1uffxRBmwRVS&LVFVsmmL;uwOcmYt{$^@E;CCuwTgEl5U4$=*Neu zriUw;(2p46xF=c}d53WwTqALY(cvM$G<|>oPH(MqL)~Dru_(NQA(@I(xip($MMq@1 z7nsZ+_>Nr?+ZIXcEmVK0bj|WxNtWhHJ{xtI=sK$qUx6d{isqp9Ol5gA%OJh;wn^_y zshfY5gv|@2a#o%ohP?r+o~`kbXI|E!!PD-d&z%*r5_tMXQg7GdqYN@_FYE+d$$0?7 zpUVW$eQ5isWhzU1_BzYwg`Z8BbcoM-Sz|8E6-=CY*L3egrG*yaaDRjyqFCx)&U+Tq)D1=J@PV|d99n%ulqV?ud6B-XsnIvubcz0b-K*V zZUk|2QZRUHJhGGFoiezxnsR^o6OVO3>LEUCQuD@mYLT;wvFF$d+#IFH^kMbpS}i+5 zb_?;W*Xoy>HDBk9*G&Btwqo-Z2n^W#SbVuFLIv{3Zjk#nu4~V_hG#9^zMY%NNj<-f zg*&uZJB?KKan8K0)Eh{Ay0R_~S2jyLOv_Cxv+!z!@G~2+Ru6aLI`71V`mtWrkBg|N z@GgaGbqf%Z_@%)X?8edTN#y@X{iK6KOH#pP0Bt!V{qyp5ytgLx5ob^Z+{E*EfZ6r5i5+h5~zDQ%D zxm;EKEYiD(V`vj98xuc68RMqx3&Nmn-oJ*9Z2$GN1O>zDE$6iWEF5FN(d6#~A?7j#!w$ZZ{l+cio zG`zNa@16w8XT&U_EY7fdKRkZ%==FcRe3IbFgM0Gt{$%j^!97uEB=BIkUl9dH1s=!u zktN{t6kF`Uy_S@sU*w|}*WkkuRkUn2q0rHgJl87jtf_4UUlD~Lj1Gy|q@%mMFtEta zM*Y1vW3yuS0pQS*zc`jJ#6oH|o7HftedX$(^I1D8LDV6Cx@Zt37j|Kk(Fn@2X1plM z%mrM8ML6V(Cvi7Z--Z8Y2QD@KOuES-Xs;XZ(i1`VBf>ja3&AFC?2`4xgJM2Y1PQbNj_DPP~xFh88&rNl-KLM~? z&iCQmVS@3wXz|gKj6jHP8FA1vAQetdn2^N(AlS>YcMAzn1!?u*S3%n2Q$eG``nX1L zKbF(*2hGgUB%LX_w%2br*XaM+G+I=y>IIK1uAh5&KkSWsjS`n$dGQBL}D*j8lUeR2J@38EWOS2uWNt)elu>*cBlPc;r6k@3Aki|9x*VPqM#rP9~555+Eqa-7`I(qq`&lc|+#O zbHDV5gMm}4T@2?==jl;rb}?~Blip{iYy7b`9QXaNPQB4>>@}Mm*R6MZySv@`rqig` zceb|HYPDLd_gbY=iI4Cv|KijdyPJE}9jC%ScO5+H`%@o7k9$KuaGpCK*BocPyBK@Z z`E0$a{|Nl6FTVNrO@Kct^2cH}ir)M!nD^zc;Honkeerwp*ZguA__NuB2I-sM+n@A; zr|8)q`Ln0~SHHKIce*1#aIgAbvHrZ*YEL@#?cJUFVBor4zus#!nw|Kb% zZL_|E?W)KRJa~CC_j{AR@AM{D)8VKyA5O;3)#MBIaN3y#!|{cKKW3MHr|%3VGiQWj z@SWj!x|lnIAx3rvv&oe+Ta4$!E8m%~Icv^`OW$eNYFESYaB$Oh&|`7skLS+J?=O1j zF~|F0_&48~4EXo?tTPTUx!-pti#d%`bSlVUL$rb?6M7UT5qCoiDy~ z6$Y3#Of(>dNQl&&;kt)xlX^4KFU|PB0&iM$YhRI>QIzug+}l@Hb$};e0;w zU3^PTeM>M|%zFM+XKH+of7SK-0h)&|c@t-T5a3I$hx1E^fT)W1SaAm(2y6o9F-_L{ zjIXB6m`;WmYfer4;mn!Lh8M$eXXF6VWy#p=U{2eg-Ywn6bzUyUxB%hwGzos0jK1jY z4wu+j%qLgq)x+l8IM<}%G02<#hp-sfr@W#kq_vu=UeYK&!Y@@^b=!`p8>QloVl=blkxW;Ads(Wsp74gw!>L?QtdmZlYCJ!h%zUTBOCMu7ep!u)Sun^< zFHZHwSL(Ul_!~N|hQHU_+uqH=%~59yR*qg0KHlBgAu>ik_6Q%JPyOC-FjS{H zznLCv{uyb2AFuhN{Ep9{Brn=fao64=#sO zT6|kRiRT{sUm0`I+ypJSMT7^`?Fo!4rLU2iINXpb5d3F=XdsjKC!mjVPozoE)>udN zb-U;<&Gp+CFw`*becqKeP%o3~ey&NcvpV7krk`B8^%gSt6wCnDo~ z-z{^?>h)$5VeAqaYxg_zPOI(UEUNS;wbg&By#}_P`E=#K_zD{v$Lu;U_|tjYd0T0# zobd#>$-AK@4zK({XE6d)4?3g3Z@Y0Upumi;WsR;G z|K|2xKvg&It-=S}`<>4AX1(XSyW4xcZf7&WtL2R#NFlEUVTPT}y=_7b{IgLP7Pkj( z2p@`V#P<@Py6$`fSL)o-jyM8z1ELJ4<2RE||I81t1?LRaM}&00f!D>qryCp2i!LbT zLIEd(LI4zsE9CSpJL3z6Xds4Rp8%LSE;TLCJ{?%!|Kg7(QwBM3#2^>0v+-2MzwXR? zm#+yle{2EdXE^DPpPb(vpg?~By3jwctfN1i`Mvps5sNHjc%?58CIL0dUzqE>n-G&p z)Ew}fSk0^9EPFAIT8#YSZ18wEKCJ3(cnmi0;uXuX8oY$obcag{O23c=~ip(UwgxG z2{>uoDOcmY)8No*9lw45;V+4H24uV=c|^`n|FfN;G>Z))=jN$x@_->afj1d=@(C>m zpxSD^JAHSY=m!R3jxT$UAIrZexVh?1MreM{zgRn@Z~^Ijuwnkwf!~=gX1+HVbuNMk zCuF`?xM9<;cl&$&P1kKSyE}tHZ;-|f*<(aFBD)QP28juk1`!;ED{$R$&t9FJzj*oP z*gHCX`~K|s{QTtfop(|F;-uu&2H2Ent4PT-&pRm_8YiELB;cH%zXiAKt4H@6y)-$aIJPk?k?p=bZ z$0=Knm?bb=qnE__gBqI0n|`N`cB`}B+-Y>0K>PmQ_U53!V?A0+|Jbow-m^w-XTRFm zf=Z5lHjVpUb)Iw=S5vel|vUKqTVU!daC;e~Li7nI( zpxpCIkOJxB%0B|?mW{8F5DB?~J6!~qrJq`@_e$i&zSfHD>u3K42xfBSm+)CYnUFo^ zrD9#_-!X_9vpK4#^_zgF3J+-RP_bTxhX*6K@KYb_3GITeVpgK9ubN9JJhtm9Ijz-F zM4?n(-t)G65GOyyj`_l$gJkoQ((?WxDAIka7He<7LctS`?b^z-m8(&H;qND**B5(2TBdpwMX$EC8X zHGG&%&05YuYxhEDRy39b-R`=&o9lpAI+#LNd^y^PwzTM&tD%crG;tsFP!uh!yr+f7 z%iqQ&!{~N7&2n#f;;x?KS3vd%BbM?n(s`@(2GZiF2=nq8SgA!l{*``d{p%5NkyTN- zH1?|Cn06Yw)#l#H_y9igO7(Y!+BO2;h~$*fBwj7S(bdza%h{dq~Gy)%QmJz@D}o z>{;2V9Xj!Q&1W~l`n!|j3X~1+T5InYLkX zRFjwZHLIDv6%ZOp0PB#%DB>{fp-7K}o1?AHyJOi`>o()L6|Ys6^-lgBpSNr-F?)jB zwaP7N*GYjEemmswgKPonr&(uunU+Ei3i%ntIw8Rv? zV)?hxWYq|MB(-HHWI!N&roQL&ZZRJI`@;7CdmfClUZ>w55-@=aV`GT(a`N@r$Hm^K zDxr)QbU6+UWf-Z_h&Gdo#NL0gvt_hrQN0zd-IfIt4NN4#D{aYTHXDuS=sOkE`%_$&MwH6{L~>eKDESH4IyL3e>_WcyQMoG~P$I zPkcO3{$RzCuR~@lSn(1EvQ5?QScs8FTM^ZMbb+z8unCt966`CqE=R=Mz zWO{?g8lJe(G0TWA#5%~XSD~AR8kV=K^O=0(#;_NSu!~^T^jkLAh_{5B23d7h!@gYh z7lfvM1}?#cezw?b!j*2bd59A?UofYX3DTr=913KsvyFkU)=9>C|Hd)~crNnZg4Fcw zuVcsg>pF}m0ruvv>n&%qDv#8)p+_IrO@SGD;z#iXxWmAM&@^YhKQ2F7A>EeT`QhDkJX|+Di6<4*-Gy%U1NJrY6ovT@p@ndx{&jDjH**7MMEWdTI3cJ znqSQQY|%MkDRrY0QRc@X7$*)V!6MTH7n7;+?XozCG9HKusYZCD*s9dFqn|sN0Iz!N zFhcNdVZaF+498>vh;z5`KR0MFmKw;V7t6`~Vm4SVrm`1}df^j-* z%N&tQ6Yg$zF~BXhj#TQC)_@#=SZzb@F!QpT-ZwfJ0bjXr&z;|YgUCmZO=18qm@dhY z^Gn)M(hs7M5Ox5n&}y=j{BDz*X&!u!bPpi2z^Nn)C?Vm_Z`9aW3{Hr8xoVR1WzheU z;}bCho^Q1b8ld--8A zFVs~Nu~5{5)=#5 zrbc3$^P0A-auVXOo$ z26wBEu8%C6GH1{<%Olp=Cy%6@v%iGSLpe8fn6BD#k_Bh0Z=O0aKA@_aMjyp$ADZ>& zZJs>(DK32;iDn}dLJcIFmV^05nYxo0*@D`S6(l)wY;1rWp*Fc_TC$VA_VH#J$i%An z`IxgV2+7esvZGAn`erm(jIW_n0vX5Z*OOM_atf*DG7$0AWpNY9J*#GHnq}is!ubG> z&2v3v=3Hzx#u5TiKJ z_t~xH$uCe|giGdD%S{e=duu$nU8a^WZ$olJ9+o_qTmLA-l$~=25|d_|xR-+aa*$VG zUn$r--Oy&gyc1%V4Y4Bj*j@#Cql)7B@F46!bXQcKhZ8k2SKK!1692lsuKbW1n{3Ic z;OB02ueef~xBJJKR+B$+=6~^sC8H$}C(Ep=8$L0A%q9G+-U6T9MKA%B#!9?Y21~{QtVT{KyYd!S$y!}{H^c}Ahwwq*&%+%V zu-jayXjiRL`$=qAd>K&}`0itepR*o7(g$qUC4Ip5rV83&(`9I~dWFzA^9+ghju5E> zH&=MO!lnlK!ZeX2&s%&+4%Td7ii7wN4=&X4lu;lYo<;^@%~iB@kfE{r%zTChokHfE zkFn#4kmQgQ@mCi9Rewyy$`M6;4FtM#t>}E5zbb9C%2>-m%xuD@O^&0~26T!B_Gj3k z7v~?G&L|8)k*idqZKB|RC~S6)sFJ2#i_)81tLDsD+L`z_7 zaUJ7$6S7W$&a)Y)zaW9lVc7}49KdBAF`t*TmI;LM>(t%Cx*G&H6w zdK#k}6fcujjhQz>g%DsWG9EK#d!>&B6CebfB1>%5Ogpp$H1<%oDfLkLZ{F;9wkis_uwZDXc z@|FJuo0{nu@SecyLnrv0b_y_GDTjbYuUYR6nh4k!Y$2GW-p}zoigiyr1H@i4nAGM@k;xM(c_Cz{g^nkM&=%Uat!uUG2ox`{pm#HT%sa2}vf+bm2x}XO>>`>Uj ztKr`ypgD9i(zB_)%3fr+tWiK;CGt8t2O4RIUL6ER@iT8%Rq&jO(-c(10rj|EJar{8 z_5EByD(0R9aAXDfGXu@T&|8k0BWJ`8C&8Ezo~`l*AwHfXM%&BR=BXKCYb3p6Y48$bnp}5GJS)pU|TW-yLuzgW=btyUjA^9@cNriM?UAgAD9O zZ#eaMoiW^og1}>b4p;v13nV!i_I`zJKDy<$z&svW?MCG8XvA2uw<$%TwOV4RC(J}Y zpZ#*qL5RXNAHwlyd?PC6*tb)FGWQ;k)9IgPpaO*5J;L3*nLD(Ll|5v=5aw&yZYE75 zM@&)MPunj>lw;uLC12Nmn?u1=f{>c)>Y?vfJ_lJQw`^4Z;f&)km~q?A0hF}XhIi!p-)QO-xDbp;dxqzYti zhW-fQz_O~R@i`!NGsW0#P;7Ulx!c?<2<`^UIValFo5P(J=pKl~;jnr}f)Su%Akdpq z$Vs-J%wncJVv}efj|O@k@sE1&5;KNza|DM#dz^vhIZ+~{m5ClDxJX=h&*pD7=YG*M z=MfJj-j5+o5KM%)U#MZ?jDMR4;0WsWW7$>3(Y4FOclRm3$dm%jnRan{mIK}w;X9odSUps)rVwq;er5pGm1+0I4xF* z2a^wjDG|X=ufhQE7Pl*L!iP}(g+_Yn0|ob+>@wNh-P$ZhGvlnMfU6tP$!dlh2Ax1Y zHO=Z7P9m}WZknoQ;N8deQ@6}hUbC5S=)gpq0HGVRr4lwhxVTc6Vj-_rR!b=I#EPK?jhBi5*q_DZ?J6L?D`-D>Ab7X&$;q#;8bw z@Gwj%7xyx4LI&cnQY@7VBE@^QXeVW7AUb5Q2G`gU({5~9~kl4o%I zG4~w`ShD!{wX~TEo_%BXWS1k`6VYO?z9%}00))owPo_gokH zLw~nF=w_d7tb6(}W3N>N&5i^XZ0|%dO?2zKUz#2(r4v}ihMZH>_~WO0wa5{DUD)u!PnXtDPv5R*8#lAG7sysSoIjydijoymCzz@dwMP=v1u|Pw z($?WT%tbY46(mW;k^pl|df1VhImHLXP>^j9qjkw1NMR_SGr9~1j&+Zf25q~($L7=R z`u=XUu~+ogu`nP2sz3y}5;_z~w-~b_+2S&JyYl5#ShU0$Mdb?DvXoDpqqY@Cz9ybk z8q1l@G=2XYXd;n@1n z*?@?@?Z)8n$Se4>h>yd#KT23n31 za5@|U?1~agnUl#qf9c3G&SXD^&Z-L@nAGmDqlvtrZIX1*k~|nk3VwO%nDXI$B}$TF zi~u*v)s7*jN|PjayhFZ+`MX50G3bk_3{OIiD{fE=D z^CG9EwQu4t&9-pLklJdo_qIexc+&~x>S2UdET`G&*!c`02`NB;)#hZi3{>V-vMqE( z!z(bi(-byxXDg}L%>p`%&(3~fP$n$?9GM9r2E43NLkT{Iq$J5Kk)UaQjj9u%7%x)8 zwXgiE-t>l3R=1;$Wy!4EJ_-VM`a$ZCfHbLXd=PI&o3nSPhU1KkWOQTQfq*0N4I()@ z6!+$)+=?RWqMI@<(g4J5@CRIQQiB>LHK;O_bJl{yfTY?^>6pkLFp4Z*?qMLAlx%dA zJ|X4g=F)kjz0VUk)dG_-*G(FP1YGh^3bG)$^am1wO$ScS1HZT1;6(6y``bCpQ6`R; zY@aFzzG6Rs(nE`KnEW({!OGfO8BTWeqiCjMo?M^8cwU9zGbj{!^2F@DItwa?E>k{t z$&)@A%!y#(zW@ZJ!uXRoc~Y9+iMyPoQZtmJRb}Z6)Tw6^-p7w+XAGPbc}Xqrrf8Ny zPT-WIR%h?MgzxhdtC-Jpn9G$@Thd<4noFC}chCuW-5V7kgKS697Zvx7Qn= zzYhgsCtJg$I;M3?>V>2p5v9`BPTcY$1V%XI14_55lC!F8GN3g;XF*V7wYYORnS6GE zT52lYveY+Gp>b?sqiQjdXh&raG7PVhxjPWYql2{wpJ^2s0LJjVpjXM0La!e_s>q!6 zWL}Q-Pix8V>d8wFk78Z5D-w5-l!ELINSOu0)GUx}r*vsxP{3$jn4>+Gk_F0DAT3(I zDCJqxI_L~XNYz_{;jE=C3T&vWI=s`+d=h2gB>zZ|MUSE|<1o}4P}XubNx3}xfdcC`uhlp36#D=t2 z9z-12t6NR-U$1VnsgPZ+1Y**-u+{n&L!MQK#;3gK(QlmL=9X!~Q^~_kHPnvJ-&PaZ zXtY`&AirzUE&7xiAHqdTx;0$#XeJQ!h^v@#xqx;hA|>p6Mfx3x8jCU3NcSCn z?KK*r>5`+nbp*J-%(%V=JH4`u(-C)R2&ipUWCAJJyDk{SeM5^5o1XEX@3_@?>^&ajU^_u2i~T& zreWsG7h{5fu&hWRYoz6nV5$Nv04O1NXq$6lT{0Rij=)pdqPfJ?H8f3^By;Ne5ywYw zU#K!;YFg@|Dw0upqzkT;zys<+4L;SR>-qz#KL!U5{d_WDu|ge4@1}=mKE>fP{9a7h zR*oD^k_(ih2C!PZlpK%ks63HyJM#6MML|#IwAlr$Z32^w2S^>VGj`Q!Qxed{l&YbK zV|P0om|v+}p%6J-T<0<}z*xD=KF_vrAJ#k8x6I@4<`}CPe zJsMS5k50TI;Nv@bVpT^a6vQM?X`t#nX;G{k?MDC*W1lHnii{U+EMFgF%2W^ttzuMD zV>mXdbI6I1MkU~~i(k}GQMnAYFr&Cud%PHpjFT||pDwX6Je3-Y!3jg=Fi^E0Cu5_a z9^g5cOvXAtS4jMCV*4y-p%9((AOG|JLLx67`YBSrQp_*a9ev7qx#*?iJW)<_jVD#7 zfk=DEP*g|M)})Ch$f~uDtbi1g-yeR-YPpG)^(t}iUBV%xF9}i3Oi(EO11Ip&3DXSo zpZI?X0H-Y+j2+eBgjhf7)mF9tUo-q|lf--iR)xL}^hDB~-b}{7GK_Qi)k^*{G;nUH z1$|Sv+E`8AVh;59(d_2^k^-=13n*TsFMoSUk4?@?^0->0eRIY3o0;uDS-!wT1C*FJ z^gYsOfjy7RUW|LxvrYAEwL@f7Uo-oY3@{myvi_p9ex-5gdN@Xd6agh;bQcg?!W^5N z5yo7eqQ}N}#os&n6I96((wPw+Q~*s&QD)se@9PltP&X z)YO!4GGSDydb7pvJa;U5y ziKb!ABkEzBMLUQouN?Y98cKI9nP0(uR7UfNH8F~W;RGV*=Cy>gsMwNVuI^=LA2k*z z0zGxeQbw0_NH!dKn%g7?)vKG$L^#$Rq26ko%~TdD#WvBah--OH=sKrl121Pur30(T zvZRm7@dF_w(q7!e^YbsQtzzWpFIEVL)4=~0Xw?h4s*L@AghwV@DSZkmBRgdOZ^gz` z@Q<|Zukf1`@S=D*mHPSdNA;%Y8jUI^aDr366yA}zZkTY@YF!Wm7h;T6RvfCaf8e-E z;HeP87~!lo((Q`vDf$QOB)e{sGdv}0BG#Kk8r<9{zl2eBqVNQ(v^6UQ5Xvgr_x96w zE<#jb^r+HCEx)GDj|cgdA69uhcVbt$Qt%pA9{37Z9`O2B?sau5t6kg5U9W8AL9T0M zg{xZmp4YTe@QPOMcs(nHu4d&<*Rpb-jVn_4Cg&nj!NHK5TLKkIW0TS%k`%yYvAZ|S zuPbHE(!sP0r8G0_pfM!AEYQ`sl}3tnV@n2O8Nn6ZlUgA=YLH|CXVLLwp*(+7z3-(1 z3b(-$i6LFK-TaOzo?hw+5&FnGhUIDSLLSS`MP=|wJZ~N%&Tz52&B^Osl<{rl z+pA*hkj7+}VoG;V8f|y~`!K$;gQ{X#%uayB8lvL=lkDqz-qxz4tF}2yGcwgukyv@N zos5mi&RN~AC#zb5y1rTS14maE{ux6q%;cp-8s6!uDI;cPs!Dez3Qc%W??YuZ(7odp zEKg2+Yb#Q+rZ*;(I8`oDNtawpNH=kb#v;KKky!2|p)8X~9zp_n2#Mov5=H@uqDw+O zS$_%$4=g1wsbW=(D~`ZIYVTm3s-zfu;}qb2i?pGT+h9r*u_dav0)5B@Ye;F0IIovZ z;#0d1vmWVgavJ7+&(eBkTBD?BBcYyIOs|x#efDZHx1kE1l_%0qS@;W$$eReGqDwJrcH6ry6#W$c1N8lRl~+Ejy0o$D^0e*c1)Fph%kxb z?|m*O0`=@EtYQLh(Fhw|#u`Ga|U4bGAp#R7p#QH2d6m)_#y5SrD~1e~b5Q>1$u;P0j- zSSH6g_eVNeSSMS*QB0pC{!KX zy!E;FX35R3<%dfoZ-1>om2$xVg&2lAVS(lMx$qF_JN*yV{^iosB6=2%?W5Ltug4qE=c98@g- zYo<<0Np4I0C@fm5&~=G@)Wm&=5}1Y>CT(UG2Rz0;xqPQX1l+CW%vP~GT2xkWu&CVCv7(Y=iOp0CWC{#& zeF|7O3-g9|;SpEi7327*yn+eSuFfmmeRXzmRXb}T_Hh-vX;KfkL{G3x2(pL?wH3gi z_D~>@6c=iDIenYRQ2Rb`uv(8iXjuv&X%7zrmD;UBihI8Y2F$>IMKRxpOZ85FZ*6U* zsMk)C8s(jGzUR(&XGeehyI?pA|N3LPV%e=$!^DzLP-D_lr+ovAd*AoFiwlmto}s=~ zsJ}6}UwQiPoQxqep^il;)(-gN$UqhtS(17E~F|7&lw zpwzf3PU?#zz9dg5mM%=%B@xmpUM`F`yNczaLrT-D$@rJ^T5#DxngyqQP7@w~6}=D# zfn%T^7Uae<1xN&R%8?!c0b$SpM*>jzwcd5|^4DiVq=)K|gs4@f421q12UpQ4z*FQA zn#3W;9gI2`38>@zw;dc>Nk!pGd~aVScugHzt)E|VV$zmatGl`<_k(h%9@s6mF?U*-$g zPM7yiI1LtU2dKTn*y<`2YhFze0&opn+8oJWh=0E>^+v<#^rqE9?kHrGL2iFsiUmjI zmsS24U_gDOoW7Ii;QSg$1tPQl7Cd``$({fz;4CTmx~k0vD%jMkTiZIp&dLKNLW+vS zre#kV6BpPhOR7p< zI#uADV)W8e*nLdn3oE(?J1d;!r7lafzcaqU-atMqr>F(jEXaPHf;1bOp5-#6Xxn>Y z3Uyf?wOh*CU&wbjk#UnR0a!1!%j_qTKCe7?aCs*Nhl;(WhbIx1y}wx3>1QiE}l2basXF^3IDaaGR(rq6Wl#bPklwisY?BU2wsXlkmH zv@o`MX;eg7lF>WeNNB_|oulLOQhLCs^102DR!>Z0Gp#1zC;6G_K`TWes&Lmhh@~(l z$XRTKi6!en?YVcNEl&lqDyMTjI`}_^m{M#$i~T0|%#(wHZz4I{RLrGLv3#(6oTL$t zI+MyG1BK$wO}#vn7dM#xh3=$T^2JOk7TQmX*~u(sD2rK1f7qHW=W}w)mIIt&G*t1? zJCX-*zgcbEgHLe^ggFLOmu2kF3h3h4Ps_5k)wO$>YgjCAtrVrDV43(VWNYv^TZ6|r z6{tuGD(>_R+)`9?3yt&Zu@d=Df}gauMUl7y(Q$?1o0iOmLU{2vFDSUHz~oCjtqQO0 z4nABD=zg0u+HJM47)xm5%0Iuk>LQ!3lJJ&_uNj?`*t+F68~y%P&viSyg9Zu%HVTWa zSpzQ>SF<`YdZ<$FgeqZ%H8X`A%0dugAw6HKwV{MWNsEd!SUpw1?;GTbW6CDSABQB4 zGm={?_O__@1BsUkRlTL;&(^L+;m{uPgS1X(RK5i@w6&C*saqqN7^*-1U17ehEvkD~ z;h(#S068VEaOOw$91Uc9LIkLA-fb+G1@XU%I`%nYFW?lz^cxGfSIAXCI26h9v48QF zrJlVWa_Ck~;?(0VyIW7^j%;_RZ?Hw=zybLYwWZ~MakUwxS{0uctiC_Svnr4_uXhwj+A&A zTTEI#1vp{t$&3=z5r+ExcVoCKoax}k@a0m8Y+B*Da5(LG1|Op9_lD7 z>4K@Yfn%vcj;FA&XK0g{xX>vlVkm@HF$4^b;yT$oCV9wL{K5MR;Me&K%KZ zqfQE(yP*Y^&RunW9^w`PqdvVsc#!Uf(NSH`YD>b<$ZF3JS1M>B~>j2g-VuMN52dRdsePsE2VDN$AhWvtOlL?7XpV{>f zyC`|x`)b}NL2NwvMk8Wea@GgKE|>F=J^@U~WVIlG>{5n6j#4)Oj#uC!y);3A+yD=D zZ8;MhcKqrkY&D{sN<2im>C*49EBw2S&B>57%zjz=6DmC`36}41dy^jH<&+(YscuY5 zq4X{=6EgKb(}?HY;;M_Cn1$lYt*%$EHPos+Hbb%OIes7$sZ^~HI$XOZP@*Bj-let} zk-QZ6x622PA0_gXVyN&E<&|)jQ9>GwN&*Wi zKeet0v%|GCxA*pzQKahH#T^j1@n@cL?3x<0CxUI@vc1i^wsq^<`c7ImWoH#XeAidZFjFhNH% zRTo6;%aWT@69+_=RRkqpwv z1VTHNnVVAT3q3{7TPm)bAej-lEIsC0>8^to$1fgqx~*F=Sd*3w4XYz@pAl{~;Ne-l@7VVsvy@SOLLp}MA3Jbmfml-Nj-L7S=g zV@kC9EqJQ(n*>jhF#o0e{*FG*y;O2jZW|@I?erRrdS|=gx;uWy-|XyI?2Y;3L~>ew zJCmld1>!jzS*XGyeh_$SP`1(M!GUpFVz)g!+@Qs==MvO}$U`{6qYhTaqvGS&2Rei@^F^ zg1i1H(+G~q`7%MC%im#~nOvb%(=+<>@DLC1DO|{-&nVyzNe~H#E;%?<#917Y4&$ z;*cQO^=q0OfbDV7`gHB1GHbohkb9>Qoco zZ$2#BB<8wPX4KCr#paupGBYs>DpRdcd4TG?_fmF=! zJCefyj8<>{8blHD8|ctw{OxbS*H@&iolGSWY4}c?ABm)pEYRb5iFm>}ts}yZ^Ye$d zZ)DqD($}o%Xmf50w@CULS#T&gs`^~JQlxqH9gX6n*SjP#`m=Qfam3WL;yWIL=%_S$ za!b@>>_rPqMBm(x`2Hw;sMcp8P7D0}$r%1p!+s3>I9skGwuiv^fb*3nvImWZ5T>Ro zn{$_4a2S}SCdgFq1YEA@Vj7b35d7+MRk4!oXctJ4TtfzRqs~aeuh@X2u+=BSRZ{WC zCHve^5I!aH$FI>`piwmIZV%hdw&&Rd&Jjk4sX1EQkfX8apJfX@6A1n1P8_q3V~B^8ga^ z(T!M_wfp_`gf)r;j%!`;3}_;ljME;=k?V3?vYPi6D7B-7}PrH28W}!1H#AcsO=RltXx&6EsOyQLbO8?DSy1=X!ZBxIwueK z0<CHsYZ5=ZT=iD!;Id0@?6cd>mm#XoOsC z-(7SgyVV9%*c))vz6n=GJ)&iBJp1^|gnY9}*{bVZ3}@j*RF1vID)pPTsulxxAdo<; zhUCr-Dh{ihwR0u~cy|Z~sj6OiE%!eZx&3? zBX(?$m>YUXdYU*hWaFVo2`VJgF$jh^AuzWw=<>*vw^@fNZ@=JPuQ{4-QQcTY26>%fFAWcZ z*ksX+xBMB~CiU9N>6h9RM_5`8B*e$jBaR+0j>hnd6Ld|x6S7#P^$pBe;5X|bDTCbT=ug0LK4kMWC`Vkdt**wepc*T6iwl}yea;|`SHh)El7}L zdk15`!%m9S%F%^EH`=|EX(**+i&%q$Xiu;u3Yy1$H1{BG+f+QuM^Zvnr5^StVqHFdT#rUtuNuQr zouBn^u7(z^B`>7OpuN{7gwE}JOa{`FgUzQhxmVq%kqk!X^m%8Ifrt*_F{vS$lXzS zI(sx&a+pkKFaFG&_eV0Q#P_`gavPG8I;X>XWG#F#24ZGD7lGRpN+M!Rv(XSaMt&AP zv=B9rcQ+zY*n0R}$9Xwd-Wa1fMG#A@8B^yi_#H>OvpeZ&jVusjPI~99_VT zJRpaQ3vxZ31k3X68}lu3?-L`g@?KriHg=xp95BA*Kza2zRDFiz6xN_alwWdBG4wm3 zc*}EaR-noTvWA&ZeMjw#@@=Aa>PijCWC#B3`qF1R<_z8tT%a%r7JgLt>zDICt05dJ ztx9~fvJ`TRr`XQ}5nojeGIDUxvrtt;v4K@XsSTE*F;yDqkpo0u`RjzAamFZ9RcgGM zbBfLjE?EY-_e*EoqsK&;24wrKI_z3=4PMEqt5F7I#xnpXZfvB3H=ML&oorEMtqa&~ zwq#Zl4juB1;mbI1=<>$KV}XN~2@u9>I`CHFE^7dQete(Ke`mAECB8MC=CLbs_AsGS zq66{3_BinxnYKN)ms4P>;3dRrLK({no0=tDNW#W(TGmLW_q@F?W*1b9zB4YxFlK67 z^;}hj5*?0#gQvqa8N)%SH;)22Wwf8NXifTZm{qg-(LtGQU_p( zYsv?RbcbjKmY0f>rk=+RH<@hWVIWDCbU$cTC_W`T@x&o`c|1@BACY5mi zv5=(~@t+I0!d2Z9zI3tSA|R&cya$vu>l%6OZ;B=N9}i`cxAmMYlmA#yi>>7E2ybbg zcR2vY*P20|D{=B%3?y}y8Xme3V8+&RALwjuRjCG1v%X&h1%6A#o*!NM&^{t-3BJ}jl1^A*>VoxzSdZEwO!cHY!_MR&dWBV`P6XbM^JuM>*k>CHEt2rJM0RC z(}0uvTs%-I<2p{i_Tv2LZzyO~l z<6#^7Bf5NYo;mfedv#lUirP3C+Y(XFaBz@Wj?b1HfpVlE#siiGRcKs7G+CDo?|FFU z^D5~ZGPZ*@I{kUkRtJ>iD1wJlPodcIJ-#q6Z#5kc`V##p%*H=SIJogE}W7-jNtvXYG%dB)aE1`l^~(c@?vI-}9CXy4ylUAdFWhRDmaw?sw*i&R*fPVo}bj)uKjX6~7&l9771QjurtSWz0Ha5^vAom5OyU;Qhv-Ze9 z$t|QA@di3Y<)lkKiA2&359@diBwrHhRLv4HatbmWC8H#F3OV_Xs&Y(@SqQckD}{2I z=i13+rs(yEl^_j^WU-Vkys;$?9|BA!tE^P%%UbFd82R?A>69caC>Td$=C-8OO5PUA z(MAKiJd4Vxj98_ck|Z_LS)|V?Q6}%@w^-_3{vB!3cmd^4nn+sab;6w4#!In){p6b| zyZ8%vaQtQ(Uzb*>RB7S06P1njlIu%L5{qOOeZl6aCNJq!b5eyU5YJ6<9qo0VAvwFI zcUIDvVyTLgy_0{(=Z)FAvnSAQx1qYE0JdfJV@@ftIm}vcBcaq7VJL64HeW;Bns6Y%&bUUHRmLH|62JztC!nqY1&oU8s?I194F(#7FguA+ zYYG|K-Xs;Jsr@PNIa#J|6}>&xfs7yJrz9oi^g@ERln~C*kgkqAo-`=GYX*4 z@g&4|QtT&Ua)G3ROYUEy|7bgOd0FvGN|H>pnlV!37#5~`t1=5XBQ)ldQI##Xx|Npo z#H)-dD7g9dcUB^q1SBkwWMGS>wGtu(5zl^gECf$I=&mcMT`x<9L@88MpcaE2&zO~v zj6+>}<1Z)ZVU2Ty|gV z!ZouNV~U`A{Rg7FW=0_8ttA-<*xRUMgycKZ`7CrX5|I^e2fnc3nG;C1FEGO# z<56NI{nU+3C3Q$#otO|lN1VKINT~;$C2olKB8lIV94;q?>LXVeb2So}OaAVS1d1Vm z2fzG9w{n?x;&Rl$-jszd4*4!qmTc!g{>T4x-k-kGMJ-rfr92=|$BC$z&jE|9{X9wy zBFfe&aRD?|$w(ulD;_|AbcJu3g)uW*q9sC(!3RPTNfM}vJA@%OMAn(|&@V3khgs>x zm{OJEY6}aLJAQE@t?=PLEnZlWH-2cOusT1yj2AAz06!4(TjW~jF};Nt-dkIqa=v)m zJJn_#7jG}=9=_teyR{)6b_b{6eU?>Kl>ndte&$AR;crsij?sSc; z*C!h!O-#zUe~^|=WtwtW7pVjCC;_c2l?x+OCW)y-#VTcEmT~R8ZQd^Ei7ccwu_IOaT5Bb^ zhnXQ`&rSSE|H<}4%wQ>GZ;nPCn6{*Dlodgm#mniOsa|4KyF8P@qA#JU1yqBZzcB+t zF54&B5xzJ)7SK}%I%;F!C5P}J6Idykm2|`fSVFk{3ESTMD>9xM)x{`QL@Z6sx&&Tt z?%$7=C5olT4N!fuTtV++d6~of6;B6#TQ0A9yxDkmnuCLd#i`}8H|9xZH;uzkcDqOX z1!>DB*H2}sU7O8R020J`%ALU}Ri`7kTJ$sM#rFl+wJaVWtSb+#xx(5;=@jjGfwU1k zwo}O*C`Nsq;F>fKeOLK;Nwy9s96JC$uI+~MB0wVo^xFvcMq2buga$S1_ah6Y^PTL5 z)WDOi$+{_6{uA}_8^m%zQ%VjiPn3Bz;M}Y9U45lGo!_`Q0KSZUt30@BAXE!De=l}# zMQ+o|A@Z5T*|yLQv_$+`!hPj(V8ysFjU>Y)kOi5s)r7-b!7xt@&fU903Yoiob~WF) zoFfL>OHF0EY^LsI{6>O&a=Bwv$(#&1pKnJpzoM#0fx8*`j;y4n$nXa^m!;?-B?C3qbasU8`EM7e2Jp0_}^Q^P*cFW zGI!lt8zm~7vLLaNyhR03e=y`ty|8--SUE$cxOw|mNp2I)LQ+IH;)Y52h|dbq?{rq% z&Faow&Wb**#dS-gXZqr@I)w>AD;1BSG<%0ex0L^tfnX>N7I;}tZIlW=iFxm_x0X1( zJ)^o^l(3=4X-;AbW^ZP~npG}Q--Vx_DtC;m-}6Z|&Nh}g_h(9glusi@F47w1`KKJH zg!BmIgI;iZcU5geiZ~UZo5G3{M6FrX+7w3w+XZk)gLMjm*2XAoM9c*}%Z6P*Nwzp!*>Z@30 zS457->BI&KSHPtaD1j3dG$2Ed`W)@oAT#1`q*9Q|)N!Y2?3EtNGr#6}RK_`uSr~HT zkL;)NvoIl{C*SWG?ZRqdr!!8=qdVAB!~++A5LGLI;Cd4xrKDHuv3+_ zf0|^%q$Ecqu!^J+Fd`#3ttmJSs;Ln>QL<4Y&z%cZbMq!31Q;L-KhigK*&r|>-R|Q#5#~F!4Q7G8eUw^MOE^}=aV%>>wtZ{q5xCMR5_WqXSxV)>r zgxS_)WT2C($n-%;vva?9IUdp`+)y;73QHI&2)*{7V6~iarY{08*(y_m;fgtO#gxku z&@opkp_qprrAdT+b1|1HGPDtMos>Q`6xARB?VFH0FKye{CtuypY^Y+}x`=UbxTq2q zJ)GmLz_oqhyH-xuc11`*gM9+SqJ?bfrD8kG!P=#cq|S%2Q|ParW&&J+W~wG5INj1j zxi9Fu^h))R+G<&hx)4eFhzy>YO0VkLgDvIyV^Np?xatQf5=_NIEN`ha$av!QPyX;<=E z!AhjXUCL_(ij^*Db^EZ!`Ha!Bp4-=FmC%j( zJbjAU%^i-1C!eD${|cl4s`FBm!oVD)>ZG1W3n~|mhECNAr4-Y;^znmCZG^X)1R}Yc zmYqone~=zP8cbYh!-JPHjPm(vniWtu z)nS8sds_|4dB#6Y)l5}+lYRKh`{VPYvy=B9lxVG`tHqN1c!OuxgpyQ$Cx8?buecG2i=)(X>AYJb&{d2HmM*lbx_D~5hD8da_GZ%ZmF)|A$kx3EK*9L6I~1Cr{*EhNQ? z21oNzH4o9S8dCntT#pU!SlTEw)baN__5GcF*X?cZ?{v4oIp?4u+c-9?WNRm}&08GZ z%0KtNKm1v61I5-0Cec|zs7jNv2T+dtXC!AHa#r07QnSpCMnecDXFABM^o&^C!z$P< zw|vlE%L{ZP{kGw5qtWGX4At@o^%KE-bITrON}{SC2Ue@V2O~f>p$qGZ$W6+Dgsp(s zV0(FBlG(dAWgg|7K@%y=hGDi+yGz|NXF69@jQP5(1M5k>R<;s{hn6ydRq+$x z(D8WW9r-emPqzLni=iZbAXJqTwCKQohSZFmu30-l(gk~9+wY=Oxhuz+8eRpfKZ@+W#zVUk&e_gEr5yH2 zXVs<@yQiEP;sg0+gHd}4O%tLY`GO)b|XUXZ3Uhj1D|-8wYn2(7yga;E73Pz zbtvUw?4p+H!6(XgqC8YWplRC-x`NB23NBRn@2-Py^hGJj=1%oLg(s(>aqJ zQ^{|1X!nHniGGArz(^Vw`VC52PwEGu*eX&$sg+T}NW0xTwA%2F@h3p}MjH@)37c8S zy3RQuU^=ney%&M57vAQgFZm2>-+d_ntnMJ02Ui2I-XCnqP87I$WDt5}w zdO?qaSXWJ*Hmtp)rrvk`3-+ zw?2CWm!pSoLn-?EmpPs!{azrU5ilKaZV2F;MDpCz}45b;ZoEt<>DIPHTs}GV07BoI; zVrsIchqkV0CNjb+gRO5cDsMV}Gb?ABdW9YpUiOHx2b|Rx<~uFz2CZa}Ig1fowVVqS z5S>>7v_q2CG{UFw_I~=w~`<5?t>-aL#PJ8%#!5DyV_lZ%!D3;c#F>eEreC|1$|bF3WW3ES*taK}>sE~t zSd^G8qE@SYxqYTrBt6Zz_*qzDcs1#H(49<(jc6tO1b7rg|mF?g~B2_8X1~#M@ zATk-pXKQy5smH6bOc)u&F;}N7Lwc{n80O~MR8q$4F<+cAr)A^v^PzWGDhK4Suia7< z0qqkp6fY?YSqQD0fU9BOqGez(%}!Hcs7QFa&%Qs6(({z_f)k{&l(e%XbV}rNvYET+ ziUy;JE#lSwEtu*Y?K2ref)cGnW(|eC9iK+VJMxd`vWbIM>)q+Qx6Iq5y8bUGZyz=ekhKGnlSLSz+arCz!yY>l*rrEq*K&w^BX zPyaZa%@>`~TZDiEA(=?U@=hU@y`BBRp5NVql5()Uw>KDAk&3OqiBxRw*{Zn5=EMsB z45fA_-Z+L#4ifcZ!XS{6B6Dm&L;%hWYn{2?HdRC8te@qwRP3Tkwtd@Odu^db~SZ^^O>?Ik-+muj`PXzJ=qV|jdsI04%4xIE#ESR}n*#^FHKjIStg30Y-_7NzJtS4J+Dwv+#6vkUcnRw22{uBvC` zFOb65p6G9TAOjch0qTq_ZsGO|s+CSpEtQRpyOh^V7uMU{>~HtG1L!#$jb5j}wQaw) zxkJToaBfqA&n*_hw)S<=Ub=YB`q8?SP(L-RMvFb(qm;Zj9LuW>m3CgFFqIZFV23AN zH90CY43bY_cZ+ePxS%+;Aei)q%vAq!?tm>0ls_vPuBDcj_$bcGej{Q9ph; zKSG4gm_Vuj%lRM4MpShcxJ7#&Ew;9FT(eYTfuSuAiTeB|48>FpYk&ZXb=kSID^h?%4bJ^!$VO`qy_yA5Ko+ z!Fw?_i+0&E&!Xy-Qgg+T!>{lDboSysiCeGU9G^kt`t_%icU*b+H4%)YP(nHt*DHt6Vm#E}L;X z>NMhG@WbDNUv;@$j_i?817=sYcT{C^8>k~G0jz|<FCJ72C8jip1w zaV_Skw@OyYFIQD3il@N>jFpXUOE8rXd{gVB~GLCZ$m_z#*iO#E)fR7zJiOAnVlGsD}-&yE$PL$ zuOLj7^o9=+7d$W7*DA=&itrt|rn)wGZX1jWWcYeA;)2IH4MlAOA)*|kuK#@BS7r69 zV^o}1PbfFo{52HTDvPgrjIvg*NO?V(5-tS>Q*3c(F`p1lBNII@w08LADwK=pt%&D% z|LXYY&5N^R@59e$r+@O!k51no;|eI8y0gQE+nwEpkk^Oae6=1$3j!T#5aN6|U=Yr? z>}N>s18D~_adGY{@^hum8kw6H!@(3#|%N;Q{L$d~1r?$h==iCfAkI?sUv$ zJKifY!U3ntdz}PtsOW@nXSwZOLiMe*b4%MPRw{`PzQY~g-=#agTi;4is{0&A(MxCB z^YW@USB~Hg-S|XSzwM!Yo<1B}3SF0De8ZPOI090Nbi%*sZhb|dS}=Y>d53-pQ%Jhe zfo;fu%8&ZFlZB_u?WS;`xxT>%=2&p|r06)4cVNYGG{cYPUrB7>v>ZE{P=?)YX18~@ z_o|J3n^GYKD8PIE-~87=7m)XJDX(J1_4G=18c0t#zx|EtAdw|caXpng0PSglC0(+j ziqer~Ub{;1YgdU5=^}nQSvzj@2%|oqYiu87SW`SBv9RU{hFJC|zk9@C4qfvz&(hm* zg#8NxWog;*A@!Qxa)9Lvb#q=W1_M$P>WgIVN?7bDO^#w~%^*VhvlWd4&>tysQ_`=> zHo~KpAY{@zdF>tl`RMpP>jV_d{1%4)gmPz`eunBUDPVCYSTjYeyK|lF>!(oV@`j?W z%WZe&|0V$_1?b9ZYSGIg>d8x`60HxKb!^SH>(=+TnmYrOuv<+fdRbH;L; z4X*|$$FsrQXBE_35ueOOgq$aJVIr+o-;WvYiZ3L4z`HDkCVJ4N$bid^#`Avu@ZtR# zGH1ZS1p*$`n2h%Hjz^R~=>3)iC8giFD%-t^a_-h;kqf8^>2|l@-`yL)BK_uv$; zv*M+{EPCaIkZ$g<@JK)Ql=mTQxGmWzf4sPo1jbJ4-nTRrG!H88s#cdaOK`fmfWEw) zKw*5=`~zO4tpG#O9%=*f;f6x4As*S`C48yFYbC2$fAkO3c2 z1JUv9isDeg#lM~WWvO;-0n8F_jY%{ zX%Du$`#XEP_JdFMj-Pt+tz?kp(i@xGitw`oj3mnX6DM|>nITqhCKHt876;olQZ0V& zT=*!5JQ=qskIv$1%pQAfigax&=M#=)laZbT(MWLOqWb0f@2FVnE0h=SvfC#T@UU0z zyVDO2p=_>9BIyYy_|hD#ef;vptJm$P?cPfQaAGdTyhAV=m?N= z4VaHbQ<(G65QW_-^2IN=qT#HkwDRFZj`Ca3n+h#`b`VleJZ1G-%1 zjWC??+56C-8gxA*?aQ@3AT~+fkhi6H2JdcFAx*u{4vl4xWCuPkkK%sksZ!eY02P@7&9=de)H(bt$MrI#f`XzMIb&027a4IdWQkhW< zb3?x4x$#j2GVEjw#$!Z)AAHmw@QIw*IGb~JfLy^j$XCwO<2sL?JK^v57+3gWP7;fv zL#QfF>00KOrTdM@plpSP>iq^TAKb6MPNOyN1fR8bUjQpQvHQ-UGtPjNcPH8Tlvnw8 zj`2wQk3{Vy%K6cmbL`ur2RJ7Bw|+(?JIITl;J5`%=z8^GM(zew!sumK$mn54%?7WB z8UF!>Dc={0ZtvIKNKL2WU++C0EH-|vgX+knXTSGoTrSSN-!QsL-2IQMw1F%-WmUSy z!}XHt9Ia;@Z+G}Wa2q4glHY+g^?~kMNDh#$AT|?I>JtRNpGZ}a2brz@K;u0A_^Ci0 z(>svFit~WvFq5^Zd}m5jc{nOmalQ)$syN?+`cxjA@>HDfM|J+u6zBHfexJ88lfERP z|L#;Oq%!v!l=J;43RAf^b*X$;%2N4mRHgDz6y;&=&N8x8c>t1B`Nxr?=qgw4agFbI z1D(5djMLAEd|HhBs?f*N&U6?V(<4n|)@yBq+~4f)`n^r)nfuM|U~k7_kH{P%(m7@} zVO?`WoKzco)&vs>n^wLq%M=C^aYgf#71HY%{(qU|HsJiIOIoSKAC&@avf=B;wM^g< zUC(ZPhoiueJS()uEZ+%lF-Ed%Xh1h89Jc3?1>9JM8MUVpBWqi_S;vBuXdWdnq?80< zgYbj-^0VSF$bL&7U~K7{{jiS;=xSqmdfG4R+T4GMGP4< zuK_=5*BU#VJr}?1SDTH(`)1GBL4l^S8@N^gSE}mK>FbyU4^^y7vCVSj$7WNdhTF5{ z{uDnP4A}kB^yH5cg&Vl|J1KASb6rkbLf2J#F46;2YG`6&PG{n(rIz&@C1dxv8kx#3 zlIBa47oPZPc@yn3Y{{~cgqTDdt3C`hdW?RO0|NV`9I?(9J<6qDqDSg?TZnMzVpc+7 zhHv(~NV5LWxheTQ2ligZ+MMSZaqM^4WtqI1-ZE=>9a@NSk-~2f(#ir$5DsZHTrwD4 zyCP#zJL^z5yZFI4_Ke+p56p5m#>K!@Q5PdKQB$->EhiZ!Z3V>JtU_tV-sHBRFSex| zNRay5atdxNw@?A+H|zf80X@H~+7m&JI>;`upd@Bzt5^aP*ibUz7)e6nw&bc4Cup3G{Fgu_BuCQVXD=sTpM6~HeL6gh!HKu#XT->FhJsXEr3`3MXoMu1fYW>*MLiY6DZ3|N4?FSz&GkT3lI*40AUm2mOl0 z{g{P{sXYM{nZb0XgN&KNBoL&6kQA>OXxP{+l}&>GM9e7iHF!AGU z0rpq0jQ&ffv_gV%_TC1GgIdc|6N)-58a{i4NW&YhvdA)xKkO@ZX`NFqz=;jNB7@x1 z^$bx>MHrNRr?vj>JkmMORW6FGUQ#U__j$?Z@jgi*3FFL!dL`T6rjpnwLcxQS6M1dO z0DU^`fW>v-E9r<=T9_;I2x3$_;n3QaB%2fIM9!~V&M6#?94|cBvOQIkt1acihgx4Kr?&WqEM3KFijHrRAfQvV1qRa7q5zPNT&pA!CCCI3~Y#Fvj2N< z?;&@By(WIyS?L54;&mYMwN0Ef1nZpFU2q&WVN$)0(zeEGCWa@y!lvejv1V+rb#vuy zko8qvj&McRS-N3}LX04j~7BT$R%W0>=KcVBWo z?`<^;-c-UB$cPJr1J_yQ(%A5li6fd4V-tt42~}AmR6_M-rEK9`=b?!P6r|GO6ucC; zGv-V)M57=sb~qUw($I}1`6J;Tza|>TQ6IBnP@4NVQx&>Yv9A@37CgDa7yg8 z6K5{frX3p4hyE&jE0bN#z+pLvD_Rt1jLbj^Q6e-syS=8QOy7fB@9y8@jwj$McEK%h zS>$%-?=&U5lUyuj7C3nl(}cwpOk8|$%tRK{6%?$0z$Eq(Wff~|e2`@OGv}!xGjSOM zu2=}NC>y-V=~}VFaFA`*SK8wL7AQn#eILcI8?iL<;NCaSCUu3nA-16AYla9bu|ASA z2y-OiBOOo}W)@3Lpfv)8I00UJGE*bX;7UM)HyjuOcS>XevnZ-0la>4q*d_^|`AXW9 zN;50(iPk-Z=}q|J?AJw?u)ovzr@>5j+dz`DdZBtiN|yogz*x^OO6!rG1T;`KcRk!j zN$uF!-`%~V&BVT)8LGQ5pq6W!sl6>1ZA_b;rOAu!w=J{!T2gbDNZi=i-=vZ|*b0;f z`QMmWhh!81$wW4?m3U^Mw^N-&C$?49Xj96`d}6CH=GMIJ7D&?TNWY0M%ran@xyO<< zHx8SXw7*gE+$@a}ryM1?_wB*_w>9`?^DXnkAp1WP& ztM@vcUba0qW1zHEH=`jZb)%X+75ulsHBwZyVo_N9I%b1GAEobr1wYdFLlVGsRN+Oh zI88bN-EX2qE>h6yU;P`ZC&uclk5Y`1u$cs_;LS;&p4P->(Q-;a11(j9rnK%pMHxO- z!)(3m{`~grE&t9sbQS0Jj9AA*KCGu38>kr)RWP}}B(E$~07b1BUBUx!Ii)&NDseoD zn@BPCfQp0D6DnvTQ4kv{f?yVix$7!c!#yx6T~#F<1Ws*;j_`>U;0C(ph^vNskt$6h zh2-0+iUOB3rc@iy0L2TNAhcoQDUGu7F3GQC>IgGT@FA!v1vMe<3Lbs}R}(vROJ65U z@IIOG&P!Oh{Pz%L;Ca-XCLph|IqU#Lc12}a`Q1Sn0>WC#A3r7gYN$Ly#hJ+%*-g=l zz75;4e0Qo#?yd+ZPrF%O81_aw@9b`ObI|GTx-Keh)%!a;{UvudJy6EoO*fRf@SKm) zsHo_iQ$bmU!&SK_lhhb;XaYB9b8A`bt6_-A$A*K3q8;)KA3wE~Z4QwB1s7AQ>4tnUTU5NVR(v*u zVQVys?`DdjdiU#_Hx?c#%kd;pDWeF>MM8*^oqSs{i{;4LEJjgRDVx>%k~K)$263FH z8}(W~=U)Z0nJ&n%i!@|=JII~Bv(?z_cee^&hS*T~*CE!F4zanzRUYX_bcnBYEA!|G zs8#}YlVKrn@FoHeO3`b9lsjCIaH+9-f&-Q!A%Sv`wU-daI~+T=gsqQc7S%ek_^~tB zCZ}fE+1y;VN7?D-O_WjAlTx&rY)Xere_Hqo<;-<;GuPQ(SxYd1=AOD-&C@eyiA@cHGV*R$E+TJkoZHGD;K*!AVK+8M;hpY1Do3eIP>}7{%doMjT2^7o>v!HX0!eyh4&z*8lt(#IW6(yiPpT>bj#S?2}83grz;N7Q{eNT5^d5 z25+O8EpRwva^jjyRhUY=q>^&wDQRV4m{}&{a>nnFvCdEhWgp)x92B1^dUHqOS4rRP z#JXZvmkZtF9=)KSp(BCCUm*tGM8nc($0!A@{TBB)Q!cVW!my-I+j5*1CDyH320^@R zBwj&oR(Kgas@DMu(^r>GA6|6B9$P*j=9sb4=<#c>bAHDjs)^$dZL7#r2N>^CI2Xtu z!Uk2Ys8eR<8!vKpmjzR_t!5O(;L)UL_P&%XHu<}Zfl~ndpM;>5UPl}BZ}9agr$9ga zWB7vbo{#?ovq-#=C7#<2mAlS5(hVJC}gV^2ze z0D1D5l~c%Lk;rNEfgwRnxHGO(cjHq9pQHTi@=q;J)ouIyPeH@e*R~ifS0A5G&!a|) zruVx29e-!9fy!j{Mzh}E-z`Sdje+v%y3vr)24nmEdP?uCta4MNJ;?Fc_)F8Mr6}lgsSg6Zc+ljPnlGHdHu<1nO`*|bu*53^;VwTy7q zQXbE-?iNgCz*H{HQ{etR#;&qNsdplIk&r}TKAYTV_jcV(7NM^TZbvB1q6h~U`gpbM zdPLVwX(%#oh^?KvBwPKx{m#xNN|Sf{jUKGG%Pxs^tc-hNZ7UgdB)Jy-Fc@K-FDOYN zWDN3>CAAfK;HjvG7`GO>%7%sCbVRDE_oP%0igOkqOd3m}a0Em+^75SjKteTAVv=^u z;_fK{MqDz}re+Vljo8ot=lKbo=R;vl`QIh_B@4gNh9=eQm+%&rJVhRJ^(o5!t5;0v)#pjnWKjp%TRe2E7i_$qZGA=a_?Xg1DBo={rT`QZ{!E zl!PK%;RcR$i7aJ+2GeX0_Z#mZRbniP0Ht!1oXdyAFEy9;Uc~KCkd5G-(Qx3?IlDQr zA3A(fJE{W_!@L5e#I2j*C1A7E+gt%s4GTE-iwU0gS~*rHG+j~Ax}3U@>ZG!+o4!6( z$8`~w^n969a{AKKvdGuItejc#3tw^jNI8+QY9&-mGUUp>==`%Q1QE+-;rz!rp4e6y zDvqWQ6FZ&j7!&$JcB;tf;*nE_NB%q!q|DMu1B-RjIRpzkcN^I%i4n9W8nEn`isG2e z%1eriaw7n>?3^WLV=~LFGD;YWYWGoD^}d1~)h&B(T&fq1MkR$SIAO9JiPg{lj+@}| zx8D}=qZSkr|;hUB{tyIknsoWNlBS16+qj`F-ny3fC`~skJ;vBI`GEEqxdw* zQ8*6^NcVlky<$V9t74Y1eGamsVu$AB7A&rGC^H`$v5WfBP8(ry7YJD(n{4}sj{w(M z2~JVtfG#i!>3l+%ZJQ@VWn(HT23El7VhyMWizT>;+P{p<`zSOZ0l2O_V2Z*!8S(F> z#}>l}OG0z;(^|IwA+MWo_~P7n5U;*)Mm+N}5v7d^STlH`0A6zwhS$bsb-S4lUj`S} zCO;Hh*a?Q_oQ!Rb<_KuQHeHzZK~(%(a%@m)zSvkOI70M}4jr!9Z9;EtGLlk1a9fie zTkD4bkDS%Hs2x1aS zI#19K{Wtk0u?el@t|Wq7mB^Fec{I2t8mDEU+JnhLwZgJc?LM+l&6I^|iSxECjVe7; zEm5M|>KWpW`JyGYDfg4AY&1!jmvn%tm5DOE(3zjg2ufX8wb?brhC>)Nc*T^C086)2@ItK~qH9OysDWS_bk%V5_z?YV@4mOMZ4;E7nwx<%> z2t35cBANw`!?97qORJ|V#(Jm5mMW`yQ1$HsLZG)i5CWi{GO^MZWnlBXoK+xxmnGCKpsBbZCjio?N&* z0$t9Ay^T1;{dvbn!_Q&Hhxa?)OI6uqYGP&k|&n;7B<{oa#l9Dg$wDm^> z@yL`JV+^X3H69579&ziAhKeubfRm>Vh-iPCY0G#2GY?;6eE(joLnL~Jdapk zX_Jnp>lNuTwFQgk zTyDk+%{(7H4t%3(6J*Bbtf96b7wIHHtDYJWh#F8^Vs`X9RQ@s zO!68kh{FPS32m?;FED}3Q1Cdn8s0OkNtHVvpy>N72PiMT*8wtl`6oTZ9F1dygbB$faPi&t6(kD~T(+Cjl@J`5{ekad!ADkkkB(ep3mZ*0NQ?C&+$5 zjMIE#hO$)6Qc}pw(hEH-R9+_Sm=8&@q@x{})Uuz&m*H%_Aj^Yfcyc&#l|?gNlA7)A zgUw<6tcuNp2P1IlfF2|pAcjs?5~N@shbj?N;xP1D^E=W4O27NR+m4c~b(w0wBN~o! zh-$jWPPk1~%H@s#q}FUX{)B=%-5^wQ*KD9u`n~tNQ+kYKdd!0N+(_vGxrmdCk)&)* z+2WF;9vhZu5JOt-*+t(aQmUbD2_;sR*Gh)o5cbav!y!T!U-h6LYK5D4GM+BxiRD)d zti=?^^$OmBiLoax%S&IQf=D@YGBQ)i3B>QEp}M&M3k}561yS)w9%)lO(X}9)K&OH_ zT@p5KYadPJ* zD)`adj<`zQgY)B_Q~TtFVhP5@&}*g@(Mc$#J;fH=mH-iecs_tSSS3+a>Xt

!SFZJ~Z;`RMKg@}{Ys$!Iv9GxENQ$*WOOP1pNMA5`BF~&0p8-5(Y_Lho z3;$FY(A*bF5Lc3&Z{Zw}aY5Rej|era)eW^f4b%I2+Rj0IafyZ}EE=VWcxJykVZ_jm z8K^^H^&}qYu)PdVXrY$m;39{Vd{s->Fsvnun^O0lmiy@VxF$J&5(3ziydj%*)rz*; ztt_&By_)7y&H4}y*ShB^0-d%Fak$0nS z0xCGz^{PpV1GxnU=YVDQEX0R*_#|=Trx;gK!;mTxK|wA(*#V+sDW@bw-~AdajBYVt z!;??#Y8rBy487j7XMmd*j0Ns=)@wkwGKvN;5a%VyC=H*R@6s))$QmSu%7>aG9=ZJ- ztMbL`U!J^t@vKoO=Z$SndWRu+&IfEDYQbVb+|?Q^Kw1IhXvTYy-(d$8K{h z+@54QV{cO{+q-0yi7$WS^D9`#;U>fq&K+BvaWnVM*_h6rd~zZmvTL6<1$9I8a+7Bd zjz-*CC%ueqftooo^u%LFv16M^>Xc#5OF-j@a7AG-E|ik9loH@sVed}TC{W~P4~J9P zPs~1f$;kxARTV-1(W(v(g~H?Yfb=0+k_08{u;!)^9Qq(!0%FWm6wiwfBl5>aYYrE3 zP$y9>!x;XAucZFZ*JY@GN*g%LDdP~dN!BSdK2<1YUpa;)bsn$UO}?wFZf*NJZ?-PQ zdoMZGZl?)VbD@y8+3-*Kc5B?qX8Q%_R*yklMh;STNzT@aqtdDjFCF&Q2P;Qgt=7uM z#$a`IZGC=aIIeNF4jezhf>JQe^utorv(1@Jy#5oNp@Eb3Yx89}kdTy#kObRUtZd%@ z6vL%aLt=(kN)bcK;$gd8rateGv>vj+;pZn1StsCG|b zklkV% zQGJWk@}_4=?EX5a7n4&#D@j5E1w{x+w5hpldl?Tm%sV{-hja}2xN>$UdB{u0nv6tB z_)QWes8pPIh4(ZvuZfFuR7|t-`5)MH5Q!>n00G>8nfyCC`@(K6Qns3>SmJ z-%lmRs%660S)psuG-~8!yX-_z z4#|_;`CO~=IdUxSkYRjx{Cy=!9MXHVS&<^o?Nxj3(w3##IHGiB&R(j3k~0Ia##}+2 zAVWyzs%`!K0_fm=$0TQ{%}Nl;88?aEiH3)+(0s8Wu}s)pP(um!l1U4g8<7jPW;a(# z^QhZ+MJt54j(-d$pyr^&)|!omMsr4UMH%L!VSL=NZGGs!u9f$2mtaO5(6ArYR%VR> zS(h=kUWKOFHNO|llDA9aS661e#b1Y%1&i*HN7GK(yyC*PK2J)}vghZ>oLMrO(w#Y; zzr$P&GYS&mqp|=|n)3Rvhjd}VRMc=?8pKq#@o}h=+(sJh-nrW<;?>F7wE)`wzb!1( ztK{sg9a(%qMe@Y2-GqyO$Oc^e-kWdn58rr;-+9w5e%*#!{D#f8IL}5~tlDIY-?YKz zJ%d#Rv3fF6+b@;r0OV>xn8hiW)!}Fv9+5#7s8qyL$bvqE67(BU{NNHH zn-N}}b$DXd?UoNze!z6F<2jn*-T;^$$i$#2tvb%XxP{}bdqE8=xiXEY~R*I z`Qt7=oDfOnh!)IbDCvtViWpIU$OeWrL35c)>=$GGyOJf$t7%|b0BjgXn6Y2KdxuNc znPQXhIT*esB_>5{kn=$e_RW?42>ip#ug(5y9i0=o)88$L$4mO$;V@IRV=evRB z+-D=guE9mn;o2GWXe9l;BjP!yeg1sH!liG=`Uw?&*bO{WF_0Xe9gOZ~eyeP*DdwIK5P}e-Fa}d8k@c8-{^6kUK0` zWdp}yL3p})^GJM{+CCrEP`(13La!#!*Hs>b_jC#Ic-*Pgy9TDtPEc98)xk!7$F!~J zn^p(q?m8gt;2s?sBO3cjRLtW!YJ2#har`^&;m|}hm{3N)JaMlGsB8?9TL4P=gu@}F zp$mDjEs$|-kVs$cv#`qt;o(3Hl5}K~SQ!w|;DkaUV0tFQ(IY;=hob`RtS#!p4JWl6 zyt(3Kyn6^fqOvrD)I^$nD&3lBGZV_W6p%wYnL+OmzLbyrF0QjWM#Z*Sl!X3I)3ehz zkT5l9`Ql&go!QnzQEkc9=LMQ)T_<)~Z{MK>$Y(^?gx7LDw_x{`i|+my%N2R|NFLIn z=pO2{yE4(1G@pn2Qrl2(6`q$|sCl$K<@`;zs#c)Qi9KVcWTP}(PtH5q{6llfL_*q* z9}k%Yr1(GbUi!EjYp}Tu0s&`v+9siK}<+|4V_g*Ts~~jnffE4^Y_D=;FmTv z1cid<#q?D6pnMxVkRKg}rS;4s#U1wsn%6NVu}7iiE%l)6DD^P2)~~H>d$XCMo{b1_ zBP%~mc5th<-@qb3z3h!X3N(Y|@D3Hm)ln==1#(O1!tB{-F^pjlhRyS68hLlaT+}CC71JeF>JVn)* z0!teO<0JlstOsX5MKOAu$oxXFALxNi zr?_4}aWA*_A^(n%$NEfo0eOa7oyRijG1`+%Rl5*J)ubHn<^r)(im}%kQ~~CzY22Pd-!VxmKxz#@la^&CBL+&B17DHAAHuW@OH>cSk~P2qoD2Kd_nHFK7i!G zOu|r8O`!eWLs5SUGh*g>1dVox)iVeuwPshUcbo>iE>UVqY@ru|Il$Hth2kX%>=VBNYnr)Kmuz01<_rsj9q78?9GjSA`31F?*O87AYSvXE${aIzXL zmWy|QhsqwYZzy?B*3~Ytj=2E61XLr6yAwx>z#!XkuTSnGJT~Zm2)A|$N&rGYy}$H9 zDS4>6p*B(y87hy{QmNal&^HlJCK6KB$6RI-@2Njd#J^R7b;zQec%}r;rl#p30bcH& zv@0BLuOu=7eZgx(4Sbi8s?`p})t=*ycBGwaQVN!+H^e?{Z z@sdksvLS;$(Z6mB5T9f*xH#QOX!HlrhD=sdCHhyTs6xX!X5-U`wkTB$IqBGYzWZKjG>L1KHf%+utyYl{uw(+& z5xlgu-dJCy6f2se#=3%UmnbyG?g_01NTN_87cHeU5~yUr*^E1eT6t+FVqyJuCu}o_ zwfj~_Y%_}7`$lK1U)@(bWSg;m^Q}(VW~@5S<(Ty-B}<&Mp;`Dg$JUF**mtDH;NkD! zM~&;dfiJaLbco&1pPH)SD}1WW3RcCh@~cL)qhIA)Z6NBr;%6;D zbE|!=<;7?DTPvbHl0MgD`PlE8EL8BlHjC$Wc|Yd!!8W6NU$b<@evL1-u!FzRA6r-= z-{g}m2+VT7Y_kX&&d(F8$oXfRDP`(A`DlyrVqf8>ZI;60y;XHXpKUWq1YYj9EzCfb z@3xsTk5u_@n@Oh%`*5pf=iB|bh1#oqxm7c<=r6c3U|p2VE=nYE)1d2<@iZXKo(*nJ zJYlk@4vv!200}! zj>N2SZg#SG0eelr$wq+#gt*ztOE1n_I^bE@Bb>KoKS5^gCUF$uWJS0iQ4uCAI`5DM|^M-8yPlCY2vVCT_hJGwj|HuUK5g5Yiaj}vmU3D1wRZt&;5=I!!ZT3xE!p3-A+u*FA~d!yiu^sr*GB03 z@{DeG5(~jc>CDy4$kzWK)66gxX@PY72p|%=BBdg3T*riV__8+{-L5S_t2<#DoN;C{ z@rXr!1-SKPiq2mRxQ2^c+DV;##nbf6Fl3fnCaYmI>B^0(JJ?eR;olJI9WBXyaaB=F z0`Bd@Y294k4TUStkfxj=niw0i)4xD|$|G`L)src*DG+$XOgBC~GjXeUk?alJU#<=Z z6qBYOoA4U?_E9~Z9owtgO_h6zhklFR<}>tEyw)p+lPQa2zD=F|IanCxT_qMHr-uaM zv^iTa(^+I#O-MYO7X@3$CV@~d&^J_N7J2KK;88dThC8uYDPxe~HI(eD0IqC$P%l!UeA4 z#s2QogT4K~c90=p|Hbax&eNZsy#8_b8JO`4g@1i=@bssSl94?**nJj>&U!JlD&T;B z1!!dxrb;4#BVt-()iNw$|NLM6H;+Y~mTGf+eB81XxS9^wiYYeI?mbQ@bT~Nb5t(gQ z&1iwuk+SN{uih6d^0W2()FX2!@X5z!Yw*d(U(D_70I<=C31yza z0m?(?f*O6lfv>(s$S)P19P3E(GoesN*sJQW$cBg2HLo09oCTdx&$+?ht}}{iWqp+y zr3x)p^JvG|c{<)PPD$W;nVb*tb3&Y?oJsRO6u3TwB5~0yLY$@ZC#^TuAz`IL-FbCcrSD>DT#@Zt=wn=!B%biz>ja;1N3@g+Wb1SZca|xYTUt2Tq z9?#f;}CPlL|dm(qGa{XIg=WgLC0(y?BkF*_0yvK#T_ltNdh090WY2&j)kQR^R%lvc5zQ!Zw>G758M_vv z3KbZ*&-*4LhqN&bs_y{WI!2c^5YTDEBR&>6{~iWhhnIn;OY5{6HwB3Ir^z z!EYilDpfS(QF%L(89DuGuu|u3g@}U})^Dn*1pgTl=;l|jd0Z_0sw;_0U*^VYV5M0=e4-kc1T=$W1w#Q>{2&7y{St(zH76hw#xl-REurb!@@|Hllpw)9F#B;m3jNb)EAFb4U$w1 zh^7w>7PC(cCSKTR@h3a;%dmHL9V&3Q0%}8JCI{KW8NkDWmj*W}dhiWvy5i;WQO}Kn zyir5Yh9=*@rFE+kmua0TJT+&WWIjJ@u{z%pZa#%#5$Ly=QY7`Cub00)p`1JTN$>E# zkS@KVU(qYVz^m0`J~~fXO4`slIIVbi&syQl!?^TJ%zOClLVZq>)3SQ!d^|0w&O$Ka zJT#~E8No2u)n7~Qb6Gx{9Kf~#K4dl{&QBw>tDhWLclDp?(?I6X2{ znruOIVdfhRVD=+x8#P+*RV&;5Lo6ReJ{S&o)tM`rvFh zZKaPw*MNuFZL1ZP^&E>5M?5pKy^4?TJ9-LG=?L6T?V;mkKBPgC_ zM%LV@IJplA8UCg7CA)2RW@%JGkRnoIXedfS??i6Q%K{z}&r_QhAEJRNf;YJwY$6Ji z(gSTRZIVZ*Y)H#1H@)47gNOnZoey!B?Z9oR3g%N^-KajeD|Hd#dn_EhD&j~$JSwld zLgIZ-UFeV2gKnw=mFhnxGyNP2%Qxsc-$l=<(s3&E8`f=7^YIdRi>K^?^}n^BYCdMB zcVtIx-7ti0Y;Uov73c|M;0l#&&y^U^*5%~Du~zQ)-nYJ2Sa~8i*~=UHgls0>_(rBF z6jxJdkb00)T48zdXD)+xg!WYJoIIbw#0QX-9rjy z!ZdL*b(|j^!8h%!_g87R!H2+c`l$sIiZfV**7^)PR434U)?0~c}%gV2zbC& zwLvLx;KQ*|sE~B%zVUc;eTmAjQ}W3mDuK`@EWo#x*d?^QwYCw?FB-TuhcWE^48XC=WgdnfxX_cHRbjVHqo z#4MVz*2t+ZDD4?7*0#8EdPG%fuC4fsJm$!hMtnT>f_&T~rw%dIq|gT?VbIm!m=E@- zVor(!iooWm1PgF+XH4iuEF3qB>Fnxf67+n#Mv?{c#j|`Bz$*sCC8PAPTvO2HxMCfrn&E3FZr}Vm|Rx50FB2OcYFKyX`+$wAAyW#sn z473P0nb>F(mz_`i))L!%QK-!;&$KU26eZharHRD#n+3^FDZ2=eX_$pZ#_R3{fA-@T zdC`$(bkvtc@=Eqwfezq0IV}Y54yWV6j8#-;CxqNMf+y=KJWKb5!(s4_sVP3O&N{S- z;5-!)PzFq{a5q}5_o_0t2njQwMN}QyPE7D+L?1U8h=r=y>g(!M2jug9m{lmA zDYl2|d<-@uB}mfK74VFtowTq6M4nE@4_4BLtFFL+J{#EQ z7uATJ!`|WA(#G)$(j~4PANP;fmgkSy396e7^b3kJVu-2O@bB_c6r{sSA1oUx`wS8w z4=KdSR^f=j1B2J)?b`2W9RUb8tO))6Oe07`WCsf8$`wzTg6OLv>|W4u2oqn=DYALoQd? z)&=8LsxtkyVPA+}i4G4AyUuzcH$C_U?}!(8MJhoVaAOxc$B2Fb7Q8C! zeD&7P8v$;WHClb3goY`8F&8de?&oSEUz_gu@0SR{?@rEy2E zX1~5;mD-u_0Rusxz$b?aAc`bJU@tW?wVAtm>(vJ1c-eV9N#JE^BoZH|4Ec_^)oz0? zPCWQ@T8rMtyiCbVDs4|x3HzV1*FUNyj5F7km$Bs#lN0+P0%;wq!ue$UI|ZfmAabrK z67LMeB7~kDe1fTsC>_T~g8pFiCx9gCG5C3O2A~T}1-BA|c!R@f+@Ir6;zA~L{AlBF zX?f|W)!JU(UOxnk{04`SR5ZsSBn8<8&4-;NjE#gPizpd)J6NGKh zSKdCul+hS`p>IbP&I&Wa!C zJsjsnd(#+ZCyYAcizAzF$p)*ewS!NCqYHM8 z2h5vXlNqzV5JwWlcqkbzEXVm300&Si84p5T7g&ET_E^)+J8YA;{lR{!GF?%UQh|Gkdey~(N75;~YJ$BK1@9p+cb zob_BnBA!UzEI&2HeT%}yP;kyB_8;_Uh!JB(#&@Qt7&twMX+4ep8qn-%@R-42Ryh(pdZOkRc&d7#5O(T=Wd0GP2Pu!HmFN>C7I znIvFuc#G?Lt01hgCP5Y%h|A!fAmFhn*24B{()iVBQIe^I*EbnWz_4^zxWR~_ zEv)m5fXrSy*-q6|mk5Pa?NC%+lL9$`m+Nt?5@0OO*LjSrJY5N8ktEpJb8N{v@G=Af{BF{x(381@Q1e>^Q1iP8pF+dGgA8hZz5I!r^HpLfe4hH?DPvw- z?pvyy21U{HW_*d`5j=_)=GsxD39{TkPShTARHl>wXQ3abN$*ErrpFnys~8?T8Gu!kg*!&BdjpS&!&1(^qXuR5 zs=5i-^7>K#u+=&|+CE-7T3?_4sv6ce`^FlU=ZkA&jV`W@%?(ZE<+SQI-!VNq7eKF2=0$3|K&Li^&sde|PEl zma8V8tCwSQAbaTmoDdSu45{vLFuf$yqNEVZYHHYI?(5Twvk|Kiroyru00)}1KRbJuu5?6 zh<~O2{??+wIoTdj;~B{1w|vLFI-^(L*XB#)PU(P?XKVF@|x< zV;O894PI+TyQ-PW;1#cdIe1#L#-ZZkZq$IxMdtX^=sqwL6QFej01{x6SMJ7dCoUkltMIoD6VL7FI;*k`W z!LrY`g0CADj~fABT7eWu_{Bpx9Y61X8@>O!5oeh7hTbQWNrRbja5PB2HdHY6D#p;;nZ4jeR05ywfS=r^Og48@-Qqu%;MZQ#da@d z6}e$j#gpy!Bxlm=XWA5HXLBn`05=4k-P&wyTewX^ZO9Jxp6#{C@5BxtFm;5p)}3Rq z#;eUOSSJ7T7py=d%N9oEmuAIi3fJfhLx>Pa0GpPUvO)~WVq`Q=PZhPwDwft6byRx&d(XK4}RwbUBeuSYl zL$N7EXYgebJ)ALmI7N1vE{_njcltjL0M0&NHzdgXedBMVg@|U1^l9x(ChI+CNA6X& z`}URaG8kAN6YY|#U+JO*l|?)5laj~NoBMZo5m6w;5L`GD+27jG)}W~GD)!4Hzs8&vgyU2*ki2(lsp%c zo>PJz?}TAqege<>jhX$uEMqJM2DH5_N$5NE&O|rSIRCn;^u!gv`g*h8KkFjQJQ+4O{92iCLITz&J{Cso1_|@6~8UZ6qnq^WzF#8v#lg(B$26y)y;NB<~HA!kAWXZY$w*$_*1RV(_P`2e>) za`K21ic~A!#wKe<972?gi|E?A*b_#gD|UH7YT;tlD!A>$01XGrP=>|BKB?zVtnXkA z928q4f&CtjN`li<q6ll{Qc~8r2=|YjySRzbA|a<)t1Nv5DJn%?gGT~c-CAa)b-A&=J;y%w zEtXgir($C3c$X*LKXQjG)+Rdk%klW*#W{JFOKpXY`gR^uAx-9=-|oF`ie}t^lj7p^ zv@0&Ii&5`)U~PpQl&uUpGYqgaim93l6Tzj?-ckjE*%x6|4 zv-0bbG|B~}9+USiwZ8dIYy(0mM<9P2-NugXO-#8hlQ%FXcoE8$W1A9pF-e7TE;+8w z&sxQXrjBGfcTcl-jC{&jTv)~w5GUx(t z(33-b$}3aFli^hl4KJGb8)L8bxo}N)9tF|L!{gv_lfq%KNF}dSnq`^X*~Zx8d~D09 zX=SPkA^UT|ev%tTqx$|aJg*hzy`BmvK0nJ851fiGMU5T%hc)XIm7d4z(qeHZqu{J;n2OqT%;l~Z#rChTsTWn zNvrLc1=)*B3KvCw(#q7BgYh*Q7+IwcWtpaTyUPzB#)eyNeRdwT_`qq2w9`Pwyqk;y zSBYp&I3w1ClFerEWs#<=3mV&}X`>2$1Cm9*VOAx1)t@OL)g&Oc;aKwJWmv)%mp8zD z%*cjOglisEN9od!`IMBhY& zBQdi2-A!Ii^>+hULoLm)>{LZ`gGi14#WQQD{3>V^{Ry%iBdX{m? zPz~kSV-|BF+Or$mNaVybpkNq|OagNmR~|fYT-I_iG`lzFHph8ANJJ8!yz$a#7-3U4 zOHL*<4vq8g))Uq}lL7LD_;|`JJuGL8Ow?ORctA#b#GPsuNcS*@q^ISh(5%Rtvu!pjD_p22azCqj!rQPcC@#^{*dPAGVYaM9MpNIv z&4yPXMOAj7?loB`$?2tJ;4XvBlZk?9nKa9)NJ( z&8;7mP7$%El6?Sq=OQFG2^>(pr);4&RIC2f+EnbZYuG@*;t z({#IJf>Te1E%YBO=xWJyVnsJ*=}0B7(l;BaV#&1bnO4HHicHl3p_&anG*@U@o4gVs z-pTGNUWE@(VLlWp5^slE{1DuYZ0M(iccO733*4c=5ZQ|CBeGhBn&4wW`K?UC8;w0w zVNt|nCMYfgKF|$WsK&tj*#?T7FCQ6(a5oyU?OK&Q*5)87~EioKYbf(4f zFf^9wQzT!ZQY~vV-S{|BiCVMS`ZS!XV+J0BAu+c#%T_f5X8h&(ZV9d-J%4WSRIoJ! zhS1EGORB2e93|u_2O_g3xwV=pfQ%s@JdZpLjQ?CR2GS+tmSTD@eehPt} zk>?9-Xpjr$_Oj4kc!K{H{^Ylh%^F78uF=It&%NIooEI)i)=bifsdA*T5ApIoUGiyh zA-PkZIi#)^>W{@&_WR%{IAbsbP&$~QKKq{tSBeG8nni8l6afMmouf`lPZ_vM?0l?= zEYumPI|4rUVnTtvfk`a1*o)@kJ-}&7;DXBVn}Xr|iy@hLJwF>wN1GK$AE6fBJHeCcpVX#7^k|g8*ItOi zyuCz!FRsnld%9;3(x(octs)RR`*`??E<%*=kmF=`v?xBnn1ZJusEY-~skk2Q{%v&E zOOeG;PO>&4`{B>8|I&H0zx({fzqs4v;R3bx-P^0P!|^HTS|_!?E#Q!EpPWs=UiQBB z8J^#ra0JwB*>Oa}Y-_hyH(K?veq%59blv0hbo-i}j&5e;?BmOG2e0jD{Xy~&z>n

tEH0RDtT(B}141$h11H>E7V$i9k9DK-1}~)VD(|{^qI3lK z>!9bQRhzCy%#*_Wy;#nT_Z5RvX;!+=NxCRB=3FR1B!o!u$FjdCdyBQr*n zn|LZadS!cUMS6W*uYD$GnPDW60WoP2d(&32nN$PF5+$m@thM4Q3@lCLd4indaD5dd z=BUDfhoyBgn1u3tf51jSWE4Cx_lS4g|ngia!`C}^3 zPQqtFo&&zvh^q;Idft#*1=>Jsz=(}b5j|kA!qtjYk_e)d?cQnBx^+quONGu9@DDDc zQ{~wQoB=mUs2^TKjOC|-mQg)0g&{6^q)<-MCJ00^;Sj0liG&1}?w?X-|3Y*JJn-<< zl7d$AzpML*KIpvpv@*F-Rkbuo>FP>Z2E(ACxWZsxes#?TdA(FoIzo9bDX-HuWxriq z1>9w8w!Oq~AeJP>m@NzcGt6Z*Y2>0^x(UU1 zb-ua3PG(%0OBlLT6Ou`yM2{#HEv2H+-#{XRP`&Z)mNB6=vt2<;kT{3(OLvGvT(mz5 zZA*yO;s~KjKV1ReC9Y0YKl-C zKwZm;Nv~f%*uM_!q_8WMphI+HP<8AyBv6fp zclmzC$FezA7^=OtwBlj43%Eb_dQ2cImvt{jsN%_#fo)wP-5vCDK?=6AUy*=w&=lA?pmh_9a?d;%8GOU{ zNV9)v20v@HvgiIsUtF5pOWac zNxo0OXx2pj7swK3JOGH~{D4?2x?~;ZOENEgFWi-`ls%-ty%#;;$r{P2%#g{At@W9M z%l)3pTNxI>2dA-vcBy-GmwO3E76*qle>w1d~m28hBdth*m+D{ncE&1Bx7_N+%jbODH;DWp)u%)M%lz zq`&pZz=#m8u8b^s$RO`d&Om5%M8m9fmSWzc;OuE(6nAdr zMo*h}y+vE}R&)U+%az)9!y9iYG``GuiCuwT_ofnWrN{a&Q55<<0-t=qO1&nn;T8SbZvR423I((E zt0BU5n)&d7 zu9Q_rr_esJ+W+~#{+~;A!_wtmNoI(vJQ&eAD#NJ$+yDLlR8<&o^P`vG5||L9jR99Dsd$xqs2GMOjZGe-f?^%8I{-OE)HMB5ooUi(uQLR5KW?y}eiDT2-Xo zPWBspEuc*e$0qGrl%#Oor(R$e`!~HM7y^pQH%>Jk#PF8VilK;wA=9+5Q5qO)fI!n0 zO#bpsnbx)WrZrAK>M4d;iuoX-*uP_Y5?K@^Y%Ii^1QrwSwj!@J1<*`uOsa;2d60~q zbC|z0+SEg2dIbt5TX+*|ly0}~<@VlMC9QpPeLnp$aaBj$9NYbK!3(mH*Q)O+!-><~ zlQ}?9QOgvmC-RsETD&&{ja2F&Ux$~n{8uBDVMMg`5aHV>IL2=f56EO+vx5LlF~fGX zy>Ya3L|Fokw+4g5mDL+$39wbo4)?P~87H>7+E^w8FMh79xD*mqnIn9NB0KLx^iY+} zQ0V1*SBF^h7l#(H%eBmUG&^<(0jv7`t&&{ZSylQhf_|9Pc`T?ay7E0I@%v8TA2E5?Gfn2R4ko}J znwl45nmm$%0%eCySg7Qf2@BByvn@;?o0k9K{=Iu(R>(9bqnOF5{Tz~v2}STYF7|>l z?2;Zt8mq=uw2pqmulMfX;_#g_2@f6gMm%)N@ATGq+}PdoMpEXoB2I56Oabva@QHIy z3`gU`-=Jx=Of)GDHM;a)aYO|}O5jyTpfg^&IA;|Si_RbcO;nt7z%+G?Offrb!QxeP zkBW^*9~U5|-ZrH|SsTjW?^Va_pZE?p6;zkE%z(&HwV7B0S0%J%#|$|69MI;5jVhK4 z8bw%=ZRqKr-fX|=wsg|%{E&g2(iPM6GBAbU9)%<+_xSbt zR-R8CoOUpTU$moNcz*3P>*{`z)4h5mWQA}Em3I%dD^tPgRm-ewd3=tiL48QJd7KZrX63JJ zGg@+Sb;%}Ey%x)krGXMCtsQuHM1_@?Q%&Oc99teolr+;7q!E{Se+%;K+7NMkFZvXA z^fMIsXIEI+FeMoY*wE!dAz*IDNC)fwNARD{coEH>zKnlOzmLBveWmv`d%GUD@$uOq z2NFfikpulX!Jit8bXB5BLYR|R)8x0;W960sL5<1sA}PlvlKosvYJ4xDY*O|vqJOs( zi}BE$4H76Mj%li|MK|P&iGiP%J@%Fon|o0vUYYpNQAObptsL!&Jivf+` zQ*eq&))gtW)FdNfEUt*$Qx{6aFu1HXJ~;9hdBavisCX=XTZSYME3ZdPBs?fmfb z>&~;?Uv^*ay?M3!`k<~xk=6B80RgQG=ZzcTum_$|py{B%pR;#(&l`AAbDfR+eVar* zq@MeRwi`aCAO6R~{0WiV;~V{rEXG`FZ?c=8$$rtH(bt&?Eq!aT03poiYyO$|-fvu@ z`nZiIIYz3bZpBJjZ^6o70*{*UH!{0|cpvs%raGPxP{ps%lx%GXUi8-7OWsmk%5XuR ze3THw`t}yVaF*l!S~s+d**DVAOY|xH0hu^G?lFA>S+=@?!IO1MK+U>w!de zcKf;QR@3WNy181$9Aw%`o7(iDU&$=mj-j-WA1D zo#;okgPzUoJL*P@H*JsiNU>p_CY1#mP$STd=U0IEnFl=nkN!&$5@O!<#>NsdG2vKQ zWq6X?_iY~Q7L(xCK9RxXldg=T0YSUXJQ^RVW96a1C(Y1_2-RVJ@-m!)%u8De>xW5B zHQ{t;ggn<&pk!~fHPX2B2ouc-w+M$l1}EFu@E;P}PFUxjg*79>N>L>v3RNHG`Gq5c z%*>fYvF7u)L|R}g`KFfmqFL9n8TiL$r?g;us?ikGTVx%s`QD3DzD_(!53j#r`T4-* zW*#k3&}4sk!Y@P|DEK~f63$q7>0?B*6?mL4O|$OOy)vC>2Ti{fHY5N61TtP@BR&S* z;lY5?;oaaGve?|r<7+a6GQLZkOMaEXF%fw%mFc``O>Cvp<*BMNb8T3hPgx7V(e!Th zeZ#~y2DeQPg(YJp4>(!IRR?QJkiwAv$i1j%;WHRmr7R=d1$UPsCWl18cuxczyi(%s zu&qz%b6#sSEH}J@$bCUS_6@S}cV(I+Q$bP>_kkIjXo@RUR#oC^Qe_s1@@DBTxhwjz z?3@7R{wZxO6(gJ!XU*YFt0ru&Q?RQtW5)C27{IAkn#bqTl)@as1BF-);M7KSy)wAr zNnZCB6IZ=OZ`ZhyAjgv-qzLWvHc1v88k81{&vUlUi+gC1@vO(>2f^NXN#Am-K2Qj( zG@Uy2qv18*@ts||AqZb>ggJvH%~Dj;4Qf9apKMw zygvUP(dS&OV9Vr zwXL$EbNEQ_k9IsLuOeOLjJkVy0%w5YSD2`nn!=BIT?&qIKDzbY6m>*3=5)uk4hetG z->`>;VxM&MnUo&$*W#&(d^)+$P2YC2#fx8O%y-84{;Jx^m}8DybwKN#0{6^m!W%L- zyvw*YM%Eq@q6#?*&nCeh@7j1D{>u7r#RVt#Upq;BNZsQnAdT#doBoQH1;={JWTqU7 z{5oN$dhT?y0oPL)>xQIEG_F_fGybvf!?y?k^!1csvC;yqUAM-1X!fvtN8In7%$AiNfchA zxKQp^?hV~R#`=P<5l#n24mcgfGvuU`y#jdG6bdeU=$qHFIc<7g9Ww3@sje0s9X0>@ zGM6y$k1)9aN}ZmLtWSE36@0O%SSsXFoeXH5(JX<CQR+ZiQ zDpBo|r0uBM=j!i?)bLwDzVMu>wv5azO3?;~B#0!}zyM7uo50Du9s61;4aFJ642Q1r zYw|JW8_aFnytV|V*BFy3M|*H%mw+kL3}MsI6HrX6{!79kp_E30oW_ub&UR6TM0q*r z>cG{-<4OI=4Ix-gv99ja@c|G@J!O}<{N-n zs<1%*^2M*4Kex5kb$^Qrci$fzU+bszBR;N55^pf!qGY)eWr63616V!|DeHLKps2V! z#?Y;H92pux%eiUDh9OCzY!Zr=)^$)^MZ_p)Qg_?0JV?>$5VyD22&QP6QMv6#4m5&i z*_}JySnAc|_QTN79E?qHjPe2L`MGMYE)i_>N-bNrEey24$E|nXq`bGKi|Q@iSR(bd zQKdf9unY4b+T8b*TdO^hIBU&N&dl9|cel;Cq1Dl_aPke+tC$>e8tsS3loDR%hm9(fT+*n)i}5Yo7*)O6Kzj(t}!whf6vFvh`-y za^2Ux`OsuzyOkAP)>?VFgZ&R2Nw5C%@Ot5Cq_`TNN4JLZZg`IObI-Y;ispH2)~yu@ zvC3V8%^(2hD;@jpB?b4st2#BW_~fBP_pqI0zA*?XIjCAqS*Arztt4pD?egzu|| zK#8xvm}tLf9f)S{ZE!IbrdGH=yo=Qn`_i?cmS)HVtNt!%MZ&8|9`7Fy*eLcY)%~>Ir}PzQuiOxGARM`@~NDJ z^76Xc-?_n!(;lC6cjt_gM(KJ%)I(xT>M9oa9vcflAZfWZ=ziTa*B?CroV8G{W*6tg z%CUbjvf0#pqZON<8=h&Q%r?iBmD}fVkIZe8ob46sNrDgg3=|72Tcf!;(j)yVEMilG zzD*hC<9es4bd@mO(>cG2H(Otvu zhT3@8b~|NNR3P$V$nkH=r;HRgrpJ9%QhDI}#ulx;awchNg!CBqcw?NdnM;s2_&FQc zGftmjEl*VYS>0KiDftOW2r59Yvub*o^_5cBrDRGs(xp>ooeUf_6e#J(&h0&0L(6c|uO zj;9G_k)AOFvcm>ifbQvZ$mTnk;W>s~^T%mbL;~Hsq)CzNGrASkoSvVP?k9#o)ys%G z%XSr=0C`ZZkd(JTmFd=T8Fb;;*eJ#<7W z=>g)WASNz*lfK$sWSePCGEiPP6%FX6(OGdtgHL|S=Bw}uZVdOT$?`Y}vX5*{^cL-h zn!*gpyc0K(>50CRJ3W%fo$D1Hx7R~t-37i%o*~j#t!&I(+_bBDG(i(1Sg6gv5BuH_ zc@rjvi{~;NbXqWz$O}C(Fl&TyB5GluI*^t>tt(pfPAWkW*69Z^L{0_j!JQvL{IVA0 zoo{p`X;tu>8i4`Z-I0u`TO;YDC78(A;rWe~0e7+-29cfR)tFPh@F<~x(8p6Pnsb1&F~Ef(<5 zL1NFZhxS*Qv3(thck=vuPlJ0R38QoVSu>B-L*E6?)3#36K+|JOZu`(Y>z4I6mI_{F zRzA>9CuwroJN+o+x5`!LdE){zxm6fkK3Z%zKCui_B^`T*WI1It4-rUBhCt>FY|7S_ zH(`98XL*5|dzS{4dd+KxJ8S2nCL@QC4ZiZh2NuquTUXv}z2iNkEAKtc8ow-HG7q-9 zS*5)DT$R^>8wr3S+HTx;r#wVv&9;+;k!RYg%Q#`#aMqA5+2oU0roi__kTPsNKy=vJ z@v6%O0tZL-`0+y|JFiPxB^fcRmkR=w9wqG2P;; zawjWp*u+3|XsOtphl>y1MyjOop?BpmyzRZiy)rqfp|MtPVl^9ILL zB74!?hg5VZjB=LZ0TirMepkxyC@I{vch%&7^d!+4jZr(gTm#6C5tVHfr!+d6vL+!q z?}b7$g!EV$B?G~4Yx8L$dO`z=!y^k}DLOzncg+AKP-PM$loJNM;sihlDmJ}lsZMnt zQHDoS;N(JQMHb!lphFO1NE9V>R+i*sJXT)Gdo~v~rRfoQWL>AsA4A#|^Py=*ZT7ZU zhz;KDx6V$>D;nzHAk+JsH$~lHzdPed3+AO^4lhRBLEYih_Uu%Rb<(z~u<~-!?Zu@? z%2JOddqdSmcd^Li3cy8zO9OCDd^&cadYy{Krztiu8eqY64Nkjj%SN|Zlc3E1O{5*l}3o)6EVdzAZl~} z!$8}TGs!At@|}V^S?WQsIuOBC9u8GCWRK!3%}^TH@)W0sEHjO%lRBMqryE)} zvc}1WJ64MFV9POR2Fg2TRPFH;hdB77?%#%_G7xtoA3G*go{rA&1C=!j$FQpr>Z5^@ z(xT#J$>K1QVZJIgGM7CSX)axsbd#l3(`Z!FK$p_4k%5%oj;vsHGrUL4`s|HsA;I5u z;HcpA*M;>gZ)g}b`pnZ%^iH$-uI*lMovfEH?08w*)8;LEssX})^^dqnV`EphQ4JU6 zj8-ridB{ZHk|`Ry5WPqa*-7;MRK1~m)_ z9k!lHNEd{dYsfP>YA7(uoP(zdhn%ocO%NNAX-(^j>}q0ft65W;LMY;<`i3){;d2?z zlDBgm$mo7f-@ht`d4{?*09in$zppnfSx|>P?L4$tmD-)s+{WxR4L~-P|ZEX zJl*tIS+7vlD-`wXSW@sV{N4_kMheYjyfioEesLvIF>MbHY(#RZ17Njz^oYY@guObz zMo_HRx^UxetuA{ZsezYH@8f-Paq|U}uMG=6>46ZE0t?J@hE=gU>T7N$L?vg056a(h zrl$9VJJ9jiseGAzfL|()EQAh!h2QK=)bL1*vw-Mb4BQaVs~cvfWC%jn{nynY5mD+) zup>bqv3?R&>d2f!P0PNrMBl=D-z(Mavdj_!Lsv{3?w5=c243b!AqU9c(R4wWg>a%M z7d~5{jh;`sy|J{i@HaZV0MI>Um&+&xTg^gcB-Dm=+n%vR3@qg3vvbU{JyeJ2EJVQXZVLL_0;7r-5KwDP;@% z`G*uiG?>`C1TIAr4Q~wGgvQ9^$=o3y0_iqL`^pvY$U2DKXKtOj)z4!igsNn2(7Z~# zPg}%KkJad(1zL4omwG5XorD*9uaah4z?sc~I|aZUsUQGa_FKef zu*B4H9(SBE&Du!lfZCuMsc0hu{OK?dN^%i7OvPsh3b}1Dj0B#<*>^h$YV=P)PfXcV zb>c>(iA@(a<*{QR^z@ebhB5p``&Odsl#OjPw2mLb zVt|{=UX|k86D%(lMqjTr8qy@|Al1~{$^`G@S4#^Q%erV#X2V=tViu3(m6df$wkxZh z&R59pC#R>nhGC#X7E?xOm>X45rGuavIGCIP9YIywwHreo_0}ma!bfiVW8dsuj*Qaw zY#>DKAYpR#8b5^HCtL$#i}NF@AdH=VHXhxj8T)y@uf>5rw|Nvb@Uwg!bIQ{ zYvM4{8nBb+9Ms*XBLAQ(MG>n~x6$Gfj?tT3wOnwKEQ((!!GHnsI22aqe@!ZiodVwx zX%I`FBPx=BG_J^WR9dN{uo!}!=Of40JNHs4lRH*(1D+>4N zTA8LxFBDR;^o`Bcqpic9gi;ing|;D@{)P$>^w>Dp5o zeBrl$%J<0P+DjMGwYRpszPWL@z0zuJuN`l1t!%BAuf39rifgZ=AfFmb>%=KUKfF{8 zUcq^&^A!s-yP!_*?1H?eB_AU4Gs#k!gXCQ<>(xB)^K=O5CypsA)8%;bk=K#^YmTT>H(DU7#ihl?V*eB*I0?pALbqzTBupq{sAw{Z>`fK_L2K>Dgf&*2Zdtsj?hl7Gbu z%I7b5b$Kzfd={(ce=(g=x4tt6-T6Gs=enKbM~B0K$~JjeM)x?<0T0%Xx7KjJ3^w{J z8~x*%dpxSAbc;vjc!x`tP5BX~P$VN5WkuYZkll7l)`~DeVqBIN?3>dIaCYQmC15a& zF5I7{XQw~#j@_r^oHa^T4~qJBo9t9?rjrLJDA18T4M|O99@V{UeB>`N)X35epd`KA zSWQVyqkq@zwOy8(;iD-n&|puk{9BgejwTv6{WeaH{NB9(p2Ed;b)0L#sqVRIjK-}`im`ipdx_g})onyfANaF{1aym&A^VE&x-71)^#P@T_)q*@NQ!lOqnX1MYx+%cQRc~>=st#$> z9js6K;M0&5u)hj?5c!`WF%g4vZ+ed4?;>9cZ zxVvv9zvg5uTQtinnoN|sG#t0cVj%tvF__=V{v>AHOE_(tAJ}SaJb;`wi7dVF+0)|~ z@x=3dtK!_Ch3^*WyNk(b*;CU=$u~%hMZ&4%%d5nzs^;SalveIOT>Qdjq+IDQ!-?5y zt!!=gdq*qVm2+VpPR@k+(j;}DEFt*8oYQoNrI;p|U9;DN%OA+F3S`6GUL!m3q}X$! zU7bFietHxnU&n0}()#!qh^)?(03n>A(0oE$zw6R=XT{RYk3cdX(|I%;!ZqEyd<&)k z5Pz+%z#E;p1oxa92v0U_E>m{8PoY-ir#(NI6Qd4asm&`s&WCJhA^%23$4i~@PcqB| zyVms6c~>0<)YReV{9@Yi1-i)b2Y2rFjIs6wm9Zm4zH`@F{;o;MlepIfHc;&Y!WQVG z4vWRs7$gqEQSY=vk965-1J@xsFl|m~ChJ}U`7voFl?L_Y>I$_WU^-^s4Xw`Jgej_o zu?dHO3AzP>kAcSv($gkhvVaCdSDRe5ZCxkR>3QD1e;@1lgph~hGnnW90l$6kzI*OI z)9mK=S2mV4WL2uc1_r;Li#(&`@r0rCf#aVu%+4<$=e{=iHpD4MX(cx>|j2&?bLlmP~=&>Y;CQm4KNSvOA zg&4P{+tw)h^NXp!{%kNgcUm`%NR%BD*2a+*l4x>ZxWWGfe>9CyO@fz^o3p7~*H{eU z#?s`JI(9XubsDUiS$tk{Xnyvy6$EqDM!(Id5o#l;kx}3f>v*I~$IGnFh9L}o{6&24 zur+A2@L)p8iYh_EXk;l5S{w?;Xn@?8N8{6rvr%N@Qgt(-yZIj6#mKS{`saezX-f?} zLc11xT={&^7q0^Id5iZ}>mP&3xN`_9hkn7zR@wbjjq*)to!8Nx3fGd|<$MhB>Ixd* z*CeV@<}%Hs_JT<;Pk@Y#?KOfS-E`}dkpXvC7{R;Ixv2>=l@V!_UlOQ+p~&}@pm|`p zYlG^bH$2*2{~yg+O~(}Y1_sa}y0jj-c9D+Q^nea=#L;lN!$CiOMaRbUuPq^pKtfE= zX_x~U4Kqm3w7^S{OIsyg86edf?D6q%z0A54T&bt)sQA{`R2quIoLXy6t*j^G#ue zvEA~+OyJA$_~Qk;Btxk}cuU0&vBkLyW6A88T|rhuJ2-cyd_V^ z5`aHWU!2%Fl1KA5PdWyKlCfMO^aoES!@i{3rZu% zz_)h$Gqck*GBLF?JP`fnuy{n&7@OO|dq#pa1>e@c-ETJ*e~m)#jF|=A5?D5it`` z5{GdgrZy@3hyH(Jkvk#J(*6Eh`+9hycHUrsAOEywXU}v2O$Y4UP}<>yf#u6{%3#5HCt)qRSqe2Yh~Qw)RI%D2 zmoWu-)8~1u?!#&57@)I{bbow{z#7y|AlC6m@;Rz}+?5UfVg$VF(5>?TBp{MpQrw6b zujzZSXL`Sb9Fn$GUAWE16Hfnt$ei=(m7y4%I#xe0E%c@g)(1ySruF0ttx)5phPz`` zKu6s7=x9{uNV|=${28Ok5OSjd)N%ovv~s#?)MCUy$+NGSiw=j$!b0>whd%aT!!w4^ zr*zqgwJ*5^(uIPXiX-}pL$KL^x06ygFWH4Tx&Pwzcse}3`c?jPyQTDdgEU;-Slv8Y zS#Gt~myQOTYa0oNS9u+7Hwn^$|k>~`Mn zzI>kga_{xazdn1hA5N5e?pf#g{@$yyTAy_e_R`-yd-43QJHc({?UU!b2Y-b*w=bRs zo@{JI?iqbrvm{f(vff}K2IgJC1FwI6*@WOe!!a=>yD10EuCngAzPhY(0>Xhuwb!XU%afNco?(GJ zD<*&`zDw4UzD8bLSQF7QsA>b&*Y4AUz5Ty-c3&Utzu0}-dHU0n*FSn~DIaIo$?`$m z-+le$)oyt-i`j91;aM-;`0>}e?~gXO)(*EeR5LKVerUns(7-YQ?B zR^<+rTE-t`{eCnH7@Fr%yDfjZ1u&RU^T ztPSronVzp(r1Ny-$pIGC4;3AGwR`Xc)jkO`t1fYz(5ej+`W{1Gxi07F%dh({+?+HM zBSqiuB*&1x!NAYhaDH3L+TSSOLZzFhux*z6KAVf|< z)dFvKhbO9`K0;Ex_V~AkDj)djANY*`rlv|DJy0XFNK+1@D-?O&CqGeT0s7zWCw@cc z+H2sHTgEn-SHJ>(vVBwyN{6Zge8UkN;&sdp=x>3v!8A#bnoaedxNZw02yXOyb0G)rQL zV1lM82lRWia(Ly4BUB}x6+46BV0H4qfQXLH|CUy#59_B5Q?IDgmR62<)i}+Rsj|%( zdKh0yG~GhEMimZ;U=fUu;Pp^SAELPf0tvCkIR(EOie_VHW$?#~*B$R1?n=#4p%CaY zfw{>AC5@A}<63fM=K|J%>l@NYZMU%Vs<{PyYoi#OQ)Zw2hA`_QWdcm4;8d}$11LW!LyM2>}(oOt`g6Ft^lnM)4i> zauVBtr&Z;mc!J>%X77FEzyopc=mWct1Q@D+cSr=VZ5EH4&k7azvJj$@2&nX>VpeqX z($H2m%nKC`yt>3r=f&0K?MCIY_n2T4FjN>u&q#W=h?@hM*itBEEH)->>^KpY(*nY? zg{@Q?$aLJ7e2j$^cg%kLo|AbE{#y$cAL1A=T zg$mc`AK#cR#usnfiTDMnSszRVkf@6#ThsG6SmOr&Wq=hp=7$v8*8!F>Kj~2I1)(FU4iy!-4-oVKFowA=Jihp`ehIfh}~U#J(oG5RRE2H1{8>s44_&GxXh zUl$sC?U0H0f$@C{qw@61!;w-@L|4xI!-1v)8A5RYlQ;~_=VLbe>e)hhl8I0GT^EF> z)9!ml8@jqw$;m{);#}*w5EA}n>6vLa78&9X-rChKjJl`G&3muE`} z5o7UA*S&o!AQGq)4beVzyFYp2B=-O8eLwepkM?^IwHC3ubl`6fnLch zY%{gS22R11)mgJpqSr!fU3`l5Oz6v#@lf^J0E>!ESa!+;%Vxanzcarm474enciG|H`*)L22wQa4{6-anOfQ_zAfR@b6a8{Wyl(~3 zYNtu-dX(xGGzM4B_r{urBz@#}>@)9*b+%gXBVDf)Dru`Jhe`51GyHntLI2ScX8(L} z_~`TXgUKU&K+bDk-9qVy4`ZjoVNTI86T>)n6ZecC|ErpMlUup2`Zo0T{% zTYJ}K1S0o;7si?gcZJjy**c&sJ?biKPMKwc8l&NUNNOK~I?njiZ}u-Jm%4@61yA;& z%byBpN>gDTu}lRTRKOh6F1qWgTVVtKg!Oey-UcY|mS-O2Ps#A~0~?@#lT|19=c4(k zKL8Ihw20v`2Q|1+uS1&MD&Y>IH6T2fofDQ<;Y_~8c4ia`e_Qi3$7B2tsR>VrRhm#7 zi2ZUeY+-H7)(%z4T0O>W2JenvCx1q2aH%f)l`ZnNI|Gp10DP_KBp6($pA7p&wMo5+ z!H^grcdDqhy;)~c3@p9TQN1|FQ5}{6o0YFhgx}JnMIUL5#Znvt;-)?NhKv@T!z{8p z6skG;*!v)U`edxh*J=ri6BuSK5YTi(5syr$uB5^IZffqcgmFX-F8SWdi)Ln8c7zMX_(=fErHph>B1hMjP;kDAWfMo2%@? zAJl12c$}l19x(3%06S{lYZ~gLdVBC}cYmLc;n#bl#}?QyO068FFZAD2sP4EwOSi7j zX2e3f_h$EX=lRPgKfaB08S5q!ZKhNsKkj!vTu6>Tc9ZZQI0xwmZ;&s?{Vymb7y4R& zll|sWT>O^8=Mu&d57q z>f{nSOy&mkgEA>dZWBtVQ>fuz-&(d0enPY$fWdrg#jPAql6JuK5u<%ycoQIkRtM46rI$?LD{qNz2Ilt<-F{_28>Lt}B>%s^v z?Nm-IJ&LljA~JFy0CJc04iV#7Ih}Z}c84Cu)wz+SULH>@-J%v#yCB@umRgARNBbYa z{E!s5hnL3NE3k?cx3k*GaFW*&D~?MT{?IRjFBz=#v`YEtbIUa5DUBW@3Gqb`(PfV( zZ3SPe^(=my))RT-$`yIh1u*dK_Jf7v{sI~B9u+kLV%_b}?$-ReZ_37GTa}oJpq%~`jp=J&WwH7jkd%`%&7EqMdR*_pTo*X^yL z!q@Btp_c$NOBH@@ig;IX>Yofi_%M@-brZq{VGpMg-TE0gi75z$laWD#C^Yw zFD#7iLLpsB2!KCEIP6rl291Hkh=E4P#zjXLqiSTTy++4l-JqlZQO(3#?}1>6@x)|o zJrTst8II&WM_F6gD926W4%8~PGH`0~=#u~vwD9Ci*JS8T!khzt49pPa^K;EFxyrj6 z!S^^kJiCs=@X9acH$A?lGt<;p?6&F~_qT4K%Kd}6-eYi>X>_o{DNhCxu3!O#fUJxN zd`~5d0grrQ*7cfn%+zo5+?0wJ*zaT)sJwZh8TRtE_(xp67Asu0U$1r^4<@N0Q$cJ) zQS7!O^S@}Esea;+p#lE_45QtG3`lNhK zii%dfyly<0*OB;~Wv%r@W$fRBVEF;mdY5!bH)6d>k7>G33FKdr^e>yBnqRJTb%$C= z;+`FIQP`N4hjaTz${a%IJZdo&mU~drE*)Fk*a>c2Q4gWb243MB6q)aQ1hs)o8oL{S z=@uMGwwhCf{1U5`oz+^ht>qoEE~)}FD_u=iGA@h-v&gTaEQS#jhYoqfCh@GpT258LSj`9R-u5gIU7Je+x1dq(h zCU6swa7awWddK(n5AJq+=7R zl3{+-n{X;9i^^w{<%tmWZLV!KR>AMKwT`4)YgLOR0vC5uQyPd(Q9FF{8J4e+g#bEu zWMY0)i_J(ke7b<7O4~#m1wO&}qewgzzIC<%pMoj2bcFd-n$;>v+DcbI{WT-S{q@*m z{HcMUr$v!7oJ>q;EytWIjPrS8$^5EU7NN$9D-%B$2XEw>b=lklT4CWB1*X6`FXp(U zM5DSMgC^r4^LmS4L$Uph@UmtFyle)bCjl>Orflm8cv)JX--SB8V< zPwXy>YSQJ4?G>-+&qYwoEEjX6{zb28LqvfV`%p)_1Oay;;I+}fh-$cx*XK2Lk%AU8B;jOM3xg1o8&+Lgdq z8lwTTHWLTSBzmV?UA1~lsa4eZ(nH!z*@rATl+A916Jw_+HA8Lu$-&;M7f(eG5cPDQ zWo8w6Q%B?Hb5NvEWFp_knw&*eIYYYEg>@*~0+Mrl*;VehJXzgwze$wHh-{)`n9k2` zvw1R}DiH|>OVmj>>*7N&b_&Tz_inm2yM~$)M~A=0%(V>h;5Z%7P4Jz_@5*Q5V^Vz* z&0NDKO*U-d)wOGhCW5@?YS#lD_L1aANL6N{E-AW_TE&rGMCbF7ZNjazySy@5LYVUt z-eIx-=hc^hv=_YilsX2J#YFD)}2BN7I#o2cjERClQP?Y7@%!F5X@Jw;gpCGp@v zwz?CSVCTZYo-MIfD4_%zw#2$OZj=d{f{8a;txbH7o!qA@k&hRX1a8K#C!xyX+vtH4 zS0b9I3O-rjWFbmvNkHEBEZ*9kI7-#DX=5jRmZeTXNgyp(hitcZtesecQQ+>>q4BiykV)+4B3-ZyZ5F;#_YEgT!+A0Sev1fF>vF~ zJE^Z`2@o3D0`L0;!{y0e>4f1+>IB^W;ny--`1XjnmH633S8Y6g^a{CTS_@`Be57<7 z@Tfb6NdOOtf=Xgdxk=0nDTn3p*_2$ttZj0X*50|zf}$Kj%WG>k4WUWPP>A$lK0W8( zE`siD+Q7`jJ&IOE??f7I9LYq1)|(7-bM2=p#Y84~1k4IDj_V;E2F%_p0r_O%;>vT$ ziVg;Umvy4xq6DWZ_bAvnqX^xLT7Vwd%Cu(>V-a%7Okv*zoj>x=wKR>ycLMgYl5yekSgLk3_U~yQdWL%?SU_7^78h2 z9HHiqIUNH0A(@JcGf)_#LcR?y7-Ac4`D*H%qv@;DuHGVULP}lVVC>6V>^+6*DaVj& zyNu!LHjm-T^5(2DEJTBykr7_dDoNHC2R z$}myf#tJSbi}Yh9!A9%2Av&CKu13rdZP`oKbwJ$O2Aq*jx0tXnz#2pL%Qw6+cK?2X ze3D3*h)+3z*^Gpn6}eF7$Qnw02>E%0ooCojVt-@%nfD}$SGSX|TpjO;+MR)tb7Dz$ z$_$Z<6$9s0Rv>LEy_?NQbq({K8v4F_p?(;V@f01Hj-m%(Mh0yXSOS~PUMf7 zj}EQ01{!`qkIs>STl|$XiDZoDRMj%<)iX$nS^f=Z{f>KGK$bqSCkcooAWu&&-plg1HMaZ@F)8!O^wEj?O3)` znZKUgNU=bk@NY0Fjd7d}!xSlB!+0Ci|IpRHuVChRm|25^6^W#$_YZNIyALqmeNFm6 zA0j;j&bz9w_1LT|BBy3$5h35&VDc^cK}$lK3hO1>c!bm*=a6l$us(oUsI9GUh#mNv zZiY1Wq@mQr_(w_w0ZNcI>D|Hr#V63e7GR|$s~dh}=g^QK+4L8mzzgqHPth8BbZ39g z<|jS7Or;Mo;94p1H-{g~E6nUZ4!8S)CgcM1dOPbvfD_v0Gwc;TvISg=iS};mzI=dU zcXtp5$fcxJzY|$H1#%*8@Nj@k(RZcByA4~(PPdVOK(@nXdi{5WAIGvOY_2xsvo^xD zR)(s1Hth3!qS4(*XfDJ>=BbZTDpb~{1^%6eGLWV1>Y=jDIm2TACEYz>Ju| zUs02y_0sWjZ=^QH2ZL<_uKzD-M9P|c$c>2~*R~mMGZ|DSa8p-~8Qz`ZnG`=;=#s0& z&X#E)*CCxa24Q@3WjC<$&SvbOhg$VPl00-9_NGQc%Uhufe73btre~+H=hfp zo0X!>N(EnvE$|F}PszmQ|< z5e*t{CJ8N%CuiPwTqmZY)oOXCwSIi9KYKal6e1;~hK=W$B1EeYTeEJqhx#E3w&bH) zKvXHckU90oUxojIzbuJps<;N1y$(oivYY+N_>&vfr79A)IntA)ZS|-qb&*}3HMfu( z6${xcS*+vwJa6Ul-}+L2_tgKB^;Jt^#rO9ILeTjYbrJ7>O1}(DYH=@1G|u2C`aW_; zT2rPmxo%wlJFkP(kdb;zqCzTb*zIP%zJ^j4t{)L0d_XX{tU0(B7&O5?Djq~aDv=>J zKYKtFl@{hz0tLTFT;O|yf@D+@`7lg_D$l1@}|3g?RXZ!}C52$?x z^yhe@nbRb74R`|ASMB|XWuY1IXqdqohs!fbu@)O@@|qmyD%Gfq+(Ah;wZPc{ctjVv znWTiI78#(Gp`r(JjPO^W9qJj`3BVxS^PtM(x^R#G6r`cz3kO+h$bQ^?l20|eY1igj z&Bbp>v1F!t&R)y)Q5Bq{@SIW=j1SrEiOXHjG!kz*6-T6L^@vh>O$nBgn}!UfG8N$L zs^^v6#aoX~dlNllP%pt`4#x-)27NXMAq*I>hHjk$Gs}`m&&^DH@am zDnhgU_U%5WZ-ZHUntL4`1`CX(Lqm}twmPlKpJ4_ae1N%@9oEMawDNL1`Dm43?0e*Z z8UjiC+XTV?b; zGG)^%jX=cB#5UkQec^Oxm7z$_(Sy6dT~lh40l*`q*ak<3URVH8C$ceAnTN;6-H!tp z(z3hI>h^e1tKt=(M*RQUd-L=*t}IXV zf2|^nawP!~11C+OBquf4R<<>iD3`06VhSTkNF=~UfErTC?|X}Q`*<68|MgCKC4GM9 zoI6F_2mmB4$yLrOivZ%r9nU@UKp=xRn*yOtLG!tn&PD@y#cxYLmQfZ%b}E^T$!w^P z-?CdKG){(t?VEZrZ93lR74Va#7*{q?ySBSx&qkLl&n>%IMAc(Uv|Hmb_|df%u9m9S zS8}YinF<`7B-4$>ZUJs$v?LgKG|OOK!EC_1+7kid*$|BHIQ>AhF}bm}*8Cmz&{GUb zD!oGzms2#w*|nX0mDRhu5X760hNq@Jw{yXlG;@NZXcA>=(_wm2s5AARnaY4$YrQ+Y zn+MJ2;Le@i`psKgp&hdL{g^h@e-2iGDl2c0mjV4D$3J#6u!xR z_?2^JD`da$(gS(t6%RxI=>9g~Rj9@k)TF^VnIN7-T75ALY=k{}_?ql#IV2X z$};J8wvH>#_v^LiQ}CMdR97PVktGx%o$$BC+pz86L5zm1>|$<$#xa-LoZUP(AIg9Y zEtpwd9N3cTziiyOwRNjzSddbX%M<4S*jCFRZFLbaTg|~(0T~NGYjqA>g|E)%Cp>Vf zXJsu1DyvJt$!ZixRu_d3oeO(2MuA#E zweRRja`Y#comv=zq&)#n4q|%br8GRA2QoC59Kg)uJf&wRjPq9qAUbgDv*Z5S~ zzAQi%4lg}bmVn#O3FSoiThU0H6M3MTx=6*Mm?)jw+8H|G4w(FRv=aFton?tzb%k zOGRg1fu=(mM1iL5b{Tp_C5wEVAQ;%EK+u(d;G3R&n-q5 zwKwTCY^~b&qu~ebjkI;|p!^@Ks2Zowb!t=9?)D_?>0~%Xjm>vf|IN)ASFK3&*Y9@C z24&pKJIg){@~p|c3ot0)NnEGBT&MkoJGHN*^IpmGM($ZZ*WKKEovtj!L%s7DDDO7= z*X!LEyf}K8ix7qx&5vzLNq;o$pAn2_Zq)Bj1G>wftvUpd=M%teXL+#g7IfLuE+15u z#p>Ny-vQc>t%s1uFB7gj?xHSPOH64xP$xjDY56B(5M4@|g44PS^OO_~f^Q}yD~WNB zqIF1jL)om7VHf$ifaExr1SfJp0dXqQ6^K<$pQv=3vd8y$m*LRfZT9Rh5BQf}u1zm! zQ(IW-ESFJ*Jb@hjZTI=JrqofORKnH3zYueIGodmiR9loMR_8OdKjBL~_5va4Ugib< zDf7a4?VA>p4dsLBfKHXzqAJfw(vH+DDE)b<3oo@!gI+M3$X(}ro5BXYm5?3#^X7cJ zHwPiwA12BargCu@Ju*UM298lEKj^|HN20tsOTd@GFoUUeMBucp?3AIBKc=hZKgR1) z{n+_je3n007cI_OB?x4)<^9)<-l=&;&5Pi&o!-LxS@?e46+c~b!(8lvdE;& zeoxfl8^8?x5>_rRr1dV-U3X?q>|2NV)2oH~)1{=L{$;xB zE-GB9XJkyz`1{-rzd=8S4&=7H=L@nfx5fL?H(##u>fqwMuP00&>2JTy!+iDYLsaL9 zXh6E2zOZhc21!Ujq8rYu&KedtYl{0Be&XLv(k$`xqt@sst!t@aqxIsdUhsWULYX4( z4^u-Ksjk`<3g###WK!eUo6g8geoT$&V)OKW_gj5I{on%HNUXnrnI+UUKrKhE&^5|y zZ18H?1@zxX+X8z4QY1V=ikVEah3_nFPF%$){X?~QFWJKuni6 zja|%5gI=8Psc{kiNF8H6;`>e`EwS$o($wDOq5a;ddGh&u|v;n%p@s zu98PcJSL9a>P*if8c&btkZL8>m%J{XmCdp9nq+wk>6BTjq7yPLP5x5#GM7X!AVu;9 z(r?*LaN!!baLvWH`OclCPUX(+g)}-0$zAsFr$7oLKL*hS7sLYdJ*O&2jLC(YDi^tl zy>7~hEU)Z7Mz0;Gy5L)9#;dNhx-H_7Kh9QaSAGL!IPSgh{165^>Wk3N&i|aw)1INT zRz;5y6?7GW58G`-0`N17$ zrca!+mkrP$H{ioDXGqn)(BAV}PEIME6!C0coXDpU)dp-{033JXpcnxo3za!up9sf; zl|rgD>mCMS);lYCLH)tvz}(s?V9_|?0qPGqc>LJ;Tg)vO+&O0 z5s0Ncd`o>*`ft+)6UT~;PhH;i1|u$Ktken2@%b{XnAdhQy*RV29eyhew|Ea&5Q(`F z2;v-^of0w!vcp~e0;;0aTm`UdG zWzFloWwA*qU0uHdk5t*KwPNSjjjQ)cwYs`bmr-(myvIJP z^j{_UbWi_{AO#Q~jQ42gPAKmG0?)tgLC7KN!q{TaYe za1?HpU$4{_0S77ZGEKp(QiS-}m3K$Mj?aMsmO5R5cP6pJs5ev{g4N@fX*NU3RKgqX zNudjNAp;lm;e(Tm1tBz7EDw)+qAal{4{wM%yPAvc&m4e`MU+i>*dLQDth#}TSAVK+lc?Bsgu z+NuB!CP2!ZQU9e3|58TZot?q+h_{2)b8pnquN6$TWwKPf1<><_q``%9Df9|(9qOm$_vPyo;7~~Dop8DOhl+*YfoRKDzGxAAIw21#ZB^4>T1obON2zyPl0&q*+sp)Zd34KQ-3`AT&+c=Uw(3x7}U$-R)9p^+I<6# z?4E;NpunyJ5{;Yip+xf-sj&y(XnUiIWXGK1h7Ca5Vi@X9$4J|Q63A@2DS#qhuXxHC zk?qmendFV3^l*!)8#|Nt>qf<;J1p3RIXID;R?VAl(~hcDV~1R=b!yGoI#*@IvkC=$CZ5kwBWXWn4-kp zV41s$_oMgpD_=gdlsUGijErY>PK@uX|FX5Vv30w4HQaHFD_w%q$RDzO6hnqm2&rdH zDi!DosqOZ))gluPn^U5oz#|245IZn4WcJipWm+&z-|9nCv`Z?PrW+9Ml}}W!GlOrPdvrqhL0~ zs~aX!4Ft|qQtfe5W}oZU-(uk0eeK7$Yqs(R{^#J1rp|a7&Ec%^*sjZ;gS|!9LGc7#@k=Q!pkqm&AWjx^uS$T9q-HDBOQNhW0_0j zEL{$ky?6xwKK$-FlX8%YLDzg^7J1TcZR9Oji$Pha7yJ{_mWDK4nSr&8F|{l4Ebs_r zCgdx#9hBZ~IP-Z9F?RjFj0X=I<2vl%#a>v=777^Y1VjE+f4?HOMJE|s<MHY*|*v_>vuH@rbAU_z#Va&Q|~9vCEW3S@BOv3MVd%F zX+kMUfC_$Z8bYh4a{x zmnk>WPh3g10xNso`7VTxII$R#O8a0^auRvYAip^0b0{msiWFjz zk-d5Gp8L6t6bm1dy2*#g&$h*aV0SM+->)9)^vd8uzRq<)W0Bkm1_d;e4l5F$ND})g zAr4wpcQiFA*GH+8rv@f94&_{+8P2Ypp`JZ|G=7(zX8A6aVc7vPg~JQ#t0CDrjQSN} zG4?dIjVVj^<*~!cpIG2`#sWTrShCQ_L$CL*o(14BV&~1iz}goI#aX&9^&RLkQZ)yU zf8(z5RTW~YrZyJ>pv^>RrKig8kTt&p^uc{~yqKttbIY#_Qt;LM@QfIH0WQS;jk=nH zs>^*b8%^H&%BCKn0v06`XZ6$MJu^46NwjE$7-uZ=DKo?JJEBwbeEtn13&oa{Z9sUY zfU1iCRg<(DdQ=Z45e1%~htGl)ggnr%6PSNo{sqr<$pUUaW|oqX4bftKD(iT_BDu#`ku8$6e_=LLcw|P#9Fxp~b9ZI7Mj{ zFt7EEItm)rPpIqqltU~Ab*|>QAlJx!)^YD?CZel5vB(z2jlY9>&yGQ2~EX+4=lkHPsb1=VcY|n`~#X<|iW+=%U8;)175i7akWXF>}CmCAN z&B^uiS(|iIvwvP6VW|l{Rq9NDI^N7&jeB~iIkv{t{EWVj=NQ9Z_17cCJ6^P$v5#1i zRYZ@Ex{dc?2)lC=rXgWPs2IJl2~b&F%fS$5MHQ5fUTZOpj7&YF za4FEUFisl@92@=K%9W9k`P&G*iG^g`M|sEYCH{hZpHD2H=9=;MCgYXq8EVC_UtV62 zFo(6h1a(-B9(+vWNMoIm)^VFmomzmg5$Oh`BpmbuX`uYI714Y(g;h@! zU>q+LvSeyGUBlN@E99L*#POYFko?uh{K1H5i)UecEyruSvK4PIXg0qC1WJ1R>o*_VJVV6%}o_3cG`TnrbfLs4`vD>nipV5cj?7pCtB z&#-73GFctZ+~F7W(kO)%lD6zU#q`K?51nQg5uTY{M`Yq(OHWx|%Q1#(h9Aj)B=tE9 zIKps;5ZrA7>kzeYCIHKL8N9(Bgqp~(Yf^NGDu4&;AP?>An2Mlg>`BkaHJvhTjK(vE z-=zL@wsz&@fcsl-ZZ+31GF=hJWD!3G7f+>+R@c!HTjHhhUTDesx`;2s#$+#PfCtbv z&x0&@!xq7?(Q39!UNX%$B^*M5&)IzJm921FfV@i4(k`c9t7=M~FLNvvOJ?zhfy2L@0B)4g)p2jZWKaQCZ@gpmC78$N)yd%# z#SPq>T>eYmSbqRVK)Amce?Nv_D3*Ge3tY^#%me8lxE-A$+XmOQ&6NOK>K4_*Od`2) zAqsHA-MlBKh zTM|qPfGmt^#-5b{@X#>{8jTN^S3E~}G8Rpi>w=tapUc%nyiDzZGS`<(ZuR8npvfW(|pWF zW#gcfp7i>yF&(helw?`BkctI6x~feU5q$D$6q=QhpqA)|-?~E0iRit{cPKy*z^-n} zrR)$ZUkSmj+KFE<1xKK=j%SQ2QlD5nDBErEAibOy+Wu(Tg9&CDNG=cG1)vt;YVzq)a*SPO-vTz{Y>YG)M`|BmUmTUF z2xRhQ5iX=u1cyiLu1_fmDC7NPAnFfu7@Xt&xcdpQ=oGz|Hm@wOfVZ+OX-Mj1{Njyk z$I_A{*`#um7!4X9N{z;sBbk$BHSsPFyj7A$;}B=o!u}95`)){Sk>0mJXJ=d{oOH#- z&#v)(Ne}(YCoeI&JYUi;W#~;4xLv(C&Maq;LAoq`OuY*TtH{{_?nj|l~2Nk#gM+Njm{}3 zrs2_O$h*4)Ms?WoTXg(J9e>n08Xe{S8Pb8xR8olITf21)LrRV_!v4O5Ma zBt7dj5VUGCA4+Yx2{r5in;EDD5=t1(lWbW}0IZ>~>}m1+ZLl6J`&0l#WkH`uKj zeGUg+-0#lVPK6)RbSaAGL#mmJX+N82<98Uy2i(M#)l+4{yCLl*#C4Nqg?M=?GYpTC zF8nq~afUEt5e{FMhd`!8NIBy128IUiIIBbf> zVzGqMmXDjsuIN5!$FxJWquBa^?0DW)MffSq%#z4dH;Xs8nY^PQl< zpl{@;$_w!~!JZQDnzt9)U3aGNo`mB`vYY0lh!I_x4fnPpDTU1Wp9af?uQKllmqJqw#sGf(d?5%NL z+2}wzfM=7LJ@%@fEvja%fZlm9X;paaA5Tyud+a%az9AVn9ln`$(|2!>dju!VLNd6) z!%1K`91PwtnCTjVL{+pwn(ta77Xt#1t$p$Ckcs=33G*|%SF?eUwAx)D2JFL!uH-L5 zUa-NWEqGd;%LG-)rC=z>9er`Q8Xyr^|P@7dorEBLxLbas}nj+q{d-X>I~Y6 zAmmhd3sbA_M2|!PbMR;cFVYU9r`GqMv3UBA>;ObND3{u3aNar?bhiDMFw83kfK>f7 zl`W`pceUmLxf4I_p3>KV`_9M~#z)s@C90k8KXWJNEqpld)b_o4kRm#GU9e!8PWtc2 z#zT8`Iy%)mP9%0X`v9$^PEP?^Mr!6Kv7hzvJDaS3PYd|y#2PxW6?^Ns z(s`BB667i(&-~D@dpv`x&sfvOa$(&>>=8i?mcZq~`;A9x>P{AE$C8XYz=N|fsLHVF z=0h}s)U4G|0|@h`zA5HSC_ZE6P5)F+5pArI0myzBcv}T%(arv)`XwOYA&4Dif&IJP zVoc!s79kZ~7`4JtwRM|T>dx)Zoy1hU za0XBwY@D#3XRvnt8O%9$0mjdjemv={5QsA;TQxkjAc(=ZzB zH+mlOj<`EeA>NCQ9I}hrwu#bnXQ?LWys@^n=!E(cCc%rXHQU_UgFG}Z%pa~PxWDNM zCw8HFs&vf>?g&dVih!I727UnkaCis=@&#~vR`VIQJV+rk!CNX_lo;3r4jQ~})+wfo z(uC=RtBXbmfw4XB93NL#Ueo^w)vdGwZ0b3Cv10WCR7ELMch)U`8!c9rMcyaf@#ugc zB96b!(+mo?KVKAwdmYphpC(=cm1iiY-Eu=Xtp}jCRN$&&+eiXSVP~tk*wc#;1%?zF zriDIR#MCug?nw9Z?~%M6eNFzhR(>ba!rgbxv+e>U$DCJ&>eypkgz%WgS44Z-U9V{3 z)l;B(-SZyyO#i**yRP>N1`usQ)jy?WI*-vgK2QwxquedO(I7^y@+vJZa zI{uZ^UPtv)iVy-ly#p3C$ku-%J{<_a0H7QA^_5W*#6K$NRXli4XP-bhDsV2KdT~h0 z9X@9}#bek+UeKMLv4k&Ku!G98ghg0)n`!BMed^g;weNxFH$=pEiyDkY7nWwMuIK6q zhc}Hl&CnSJ_}-uUMQKLZ$CZ(dEHyA&c1e<;sNHsV8B`v@%b9h7J>BkP@q4VLl7el| zYjvFWTFra1p;1+H5l8BLsynI}#0c6L!c-a1JRy}dTXE^6R_;n8cKg3q(OQ~GI_=-9 zNZcZ|BU)Iwf43zq@2{96SeaWi`|fv-ohQ0C?QAgVpMf!N(%DQu?Gp6>z*Sd{)>nk}c_{OvQ{gv*01eJ(5fo=H z>P~ivx+L8fsQ{6RjZ|LaSw@q=zcu@3Q&g7{1$kx?E3)y}?$uQu-|frQX5@qb*M+_Q zS8|Owf%@tt*L8qr{uD7Yaa-Qwlyj(beY1gS%6mXr$az;P^E%RI)R`=P zy_m6pPZF}i3=D4(leDjPgeZ4(sUaK&s^>9~4!7O8>H&KN0|H0z)mdOncjWb+JNI%% z$~c7}Mg#h7kM4?5kW_D!h2>anVO%I^#0&eQ3DUg0hFzW$0KOtaB6GTs92>rRVa_Di zO~{-Cgd?URj(C4Mh42#m2`X2uRCzYFm7xDp?@v)9o6x#}rW$$t?D^wouU2wxjf*9> z-wvOh$Ct2D)wDL*S@~a-o`1fO{x)RB3OFz?LsCeMFUEq!MdJ)CT)AMZiLAx8XNJCK z;LT*4X(zHpA^aH=2OHyYFprS#V?6o5%8`vXYinx(b3mntNVGJ4c^pFE*vpLyl%RQ= z1whTbLSSYloB^{Qf&06dv#~+k*g%b$q*$@plM~8-g=jwSR5g~c>MioFU3}mW%*B;> zPO6x-voe-d{fot&yu&qQf|DUf;h|J3dJ}CcYnbz`yWGv3e$4H$JzZ`dg>F5b!T~gJ zPPg5K6%AZcJN1x1Gl`lkORkYR5{kBYHYII2Ex3_V#L1Clp&b4Z_0CdDJVGzOssyjI zGIMEEDL8QWPu}aAkWXUU(|~~D2ZXj9g@iBD(}f9Wz8^zD-Aul90iPAiW}BKMFQ>l| zcvn{hh>4E=0MkH1-L2FvqYU6%YA(&9GQLnR@(esFHYFOpv*~*w+O>i{+g>7pPKh!( zBiRD%bnGlh;!!ScP_RM#1=-}HY>SbJ^WY@r|C7ajhW%xQPoLCb8$4Ys?@E!0G@`rp z&hwxC+0GHL1_LL=@t4I$v+vdYaihP^)lb_gT){fasmNfIvRRYtl~NB2_gPC-z(k2@ z;oBdOPF!4|QrqNJk%n)~8kh@Ga|CfTgqo2}XZzdvX2ML|^ZiTNFhS0$)huPD7(%bt zoWSF~!x0!9a~LNnP&k390Z^&ULlsRCF-jd!SuZLF==CF&Z?H+V?d*#zt?~0w`pCRO zLC^jwnx|*!5i4Eu?+=et@genEHB-`O4XfBr%FsJLWF_o+t;oP#D--;#K&+G5<;iog zoae*ECFHzIn?}EqN%Z%yR>sVfQ3qFcXI;d>H6ypQ1d&&2nTqz=iA%Fq-^{;XiMqVb zUq(IXX%16Z_2FNa1V> zC}2mP5YLJ9#gPl*3xsIw<6#;JmC^vIKMp-r2dKuMboCpitI#lkjEy{#RG~IBF-rpu_P3<`$uF;+_bNTfslZPoc^@Vw1bS!=?I}d;k93cN64#KubR>MusE}0 zn#LHmMHZ9mp`0!BnnyUSrADgf`nsZHj|N8R(Ys$bOsWy8)W3z(SBwU)in+({wQX75 z&S0tY&v!A0(_Q3+g|=<}lB`GOa8XzG?7Pb`)`pwrgmTNU)ZY-ddm)Z=9*c|(S%NDr zV{U`4mf~>3NnDi8&Gs_K`d+}oMwm|1GGsV$5VfyvUH=vs9FY>fs=6gS`>&~U`R`2O z=2Eo_ax#msFU#^Q!l*2y0qQMI3;Pk;lw8xKDTJg>xOf7>gin!)oZyTT-yOIRVk86^ za~lay<{T1J^Y@Lkvq8!(aNFW!rd%cQ)X2v|hO*OcVMKMVg{J6Qzp;Mf_MO{!~HINF_^^$12y;wNl0 zV;9ClT!Sioi8r+Q19BatL_eQ8UM6`ldqSk!x|DfKFvli`Lcu*io>*5maG6IY*iDRs2q5Z)^0%J6_Q?PqH)`unTg5h z(-C0S&FS#Q*~65yR2kSyqp6I7Zdy93q%~??Pu`}<^;XtJpY$n|qmIHG{q@0XP!uwJBtK}1db>JfX(XZiQ^7qrN$yP4*(O&1%Xm~v6 z__^%3L%(Pt4cy`B*aCmuf?Ww$7-TD!^?W|hPhA$(A%^lDr)qLDwlGTJZwBf$!I>1i zb)8TKLqTGC^L8}rTF0TIQkuh=a7}72H-&m4DT1^RgNLf~o6^f}ip}j=0xH?~9@&hb zW)&iezF=(|1w}g}i$aPL*6_B2UE+IaQ_pq4n>;m6TKi>)`07jNWL*H zvwOht=_%z@B8Yx%fZa7lZ3n#5MC$M-fTk)us+sE2UzbVDPD;f>^=f8UXZC6SiOJmb z6^U}sr;=-I%^$5#c^^*3X1qQ8yZ>F20r>erHCSCRg1oob7${lHM|4keqp4IYo8Xy! zDz9Hdpd(?KyC$C>uGmXstph2x83<2hI9;i9Zod?T48q@rUgq=cziM)78_lz=VGSAEx zKr?)Bt#;K7U5r~VQOSH3A;Y_!!s*~KO(~;Nv+N)I6lsR- zWYe*KJQ%Zov_%x~+9J~+$@JZ0KX0sUrvZ~*)O9~op&Nbj@Ph{ul$I8ymxsnS_x%VvxeJ@HC6x6^zsBieS%Zq}ser!1Ov;e0!_C{<_x6>7$}ZL@@

', + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value} from './graph.ts';document.querySelector('#app').textContent=value;if(import.meta.hot)import.meta.hot.accept();`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value} from './before.ts';`, + ) + await writeFile( + path.join(directory, 'before.ts'), + `export const value='BEFORE';`, + ) + await writeFile( + path.join(directory, 'after.ts'), + `export const value='AFTER';`, + ) + const authoredSource = `export const value = 'BEFORE';\nexport function authoredThrow() {\n throw new Error('CACHED_CLOSURE_AUTHORED_THROW');\n}\n` + if (sourceMapMode) { + await writeFile( + path.join(directory, 'before.ts'), + `export {value, authoredThrow} from './cached-leaf.ts';`, + ) + await writeFile( + path.join(directory, 'cached-leaf.ts'), + authoredSource, + ) + await writeFile( + path.join(directory, 'after.ts'), + `export const value='AFTER';export function authoredThrow(){throw new Error('UNEXPECTED_AFTER_THROW')}`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value,authoredThrow} from './graph.ts';document.querySelector('#app').textContent=value;globalThis.__throwCached=authoredThrow;if(import.meta.hot)import.meta.hot.accept();`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value,authoredThrow} from './before.ts';`, + ) + } + if (largePairMode) { + await writeFile( + path.join(directory, 'shared.ts'), + `globalThis.sharedInits=(globalThis.sharedInits??0)+1;export const shared={initializations:globalThis.sharedInits};`, + ) + await writeFile( + path.join(directory, 'after.ts'), + `import {shared} from './shared.ts';export {shared};export const value='AFTER';export const padding={${Array.from({ length: Number(process.env.PURE_BUN_LARGE_FUNCTIONS ?? 40000) }, (_, index) => `k${index}:()=>${index}`).join(',')}};`, + ) + await writeFile( + path.join(directory, 'before.ts'), + `import {shared} from './shared.ts';export {shared};export const value='BEFORE';`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value,shared} from './before.ts';`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value,shared} from './graph.ts';import {shared as stable} from './shared.ts';document.querySelector('#app').textContent=value;globalThis.__pureShared={identity:shared===stable,initializations:shared.initializations};if(import.meta.hot){import.meta.hot.accept();import.meta.hot.on('bun:beforeUpdate',()=>console.debug('__PURE_LIFECYCLE__before'));import.meta.hot.on('bun:afterUpdate',()=>console.debug('__PURE_LIFECYCLE__after'));}`, + ) + } + await writeFile( + path.join(directory, 'server.ts'), + `import html from './index.html';const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}});console.log('READY '+JSON.stringify({url:server.url.href,pid:process.pid}));`, + ) + let readyResolve, readyReject + const ready = new Promise((resolve, reject) => { + readyResolve = resolve + readyReject = reject + }) + child = spawn(binary, ['server.ts'], { + cwd: directory, + env: { ...process.env, NODE_ENV: 'development' }, + stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, + }) + child.on('error', readyReject) + child.on('exit', (code, signal) => + readyReject(new Error(`Bun exited (${code},${signal})\n${logs}`)), + ) + let pending = '' + child.stdout.on('data', (chunk) => { + logs += chunk + pending += chunk + let newline + while ((newline = pending.indexOf('\n')) !== -1) { + const line = pending.slice(0, newline) + pending = pending.slice(newline + 1) + if (line.startsWith('READY ')) { + try { + readyResolve(JSON.parse(line.slice(6))) + } catch (error) { + readyReject(error) + } + } + } + }) + child.stderr.on('data', (chunk) => { + logs += chunk + }) + let timer + const info = await Promise.race([ + ready, + new Promise((_, reject) => { + timer = setTimeout( + () => reject(new Error(`Startup deadline\n${logs}`)), + 20000, + ) + }), + ]).finally(() => clearTimeout(timer)) + result.pid = info.pid + result.revision = execFileSync(binary, ['--revision'], { + encoding: 'utf8', + }).trim() + result.binarySha256 = createHash('sha256') + .update(await readFile(binary)) + .digest('hex') + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.__pureGraphDocumentToken = crypto.randomUUID() + }) + if (largePairMode) { + await context.addInitScript(() => { + const key = Symbol.for('bun:hmr') + let callback + Object.defineProperty(globalThis, key, { + configurable: true, + get() { + return callback + }, + set(original) { + callback = function (...args) { + const record = (kind) => + console.debug( + '__PURE_CALLBACK__' + + JSON.stringify({ + kind, + id: args[1], + keys: Object.keys(args[0]), + time: performance.now(), + documentToken: globalThis.__pureGraphDocumentToken, + }), + ) + record('start') + try { + return Reflect.apply(original, this, args) + } finally { + record('return') + } + } + }, + }) + }) + } + const page = await context.newPage() + const session = sourceMapMode ? await context.newCDPSession(page) : null + const scripts = new Map() + if (session) { + session.on('Debugger.scriptParsed', (script) => + scripts.set(script.scriptId, script), + ) + await session.send('Debugger.enable') + } + let phase = 'initial-A' + let pairedWrite + const assets = [] + page.on('load', () => { + result.documentLoads++ + }) + page.on('console', (message) => { + if (message.type() === 'error') { + result.errors.push({ phase, type: 'console', text: message.text() }) + } + }) + page.on('console', (message) => { + if (message.text().startsWith('__PURE_CALLBACK__')) { + ;(result.callbackEvents ??= []).push({ + ...JSON.parse(message.text().slice('__PURE_CALLBACK__'.length)), + phase, + }) + } + if (message.text().startsWith('__PURE_LIFECYCLE__')) { + ;(result.lifecycleEvents ??= []).push({ + phase, + event: message.text().slice('__PURE_LIFECYCLE__'.length), + }) + } + }) + page.on('pageerror', (error) => + result.errors.push({ phase, type: 'pageerror', text: error.message }), + ) + page.on('websocket', (socket) => + socket.on('framereceived', (event) => { + const bytes = Buffer.from(event.payload) + const sourceMapId = bytes + .toString('utf8') + .match( + /sourceMappingURL=\/_bun\/client\/([a-f0-9]{16})\.js\.map/, + )?.[1] + result.websocketFrames.push({ + phase, + bytes: bytes.length, + ...(sourceMapId ? { sourceMapId } : {}), + mentionedModules: mentions(bytes.toString('utf8')), + base64: bytes.toString('base64'), + }) + if ( + largePairMode && + phase === 'A-to-B' && + !pairedWrite && + bytes.toString('utf8').includes('self[Symbol.for("bun:hmr")]') + ) { + pairedWrite = writeFile( + path.join(directory, 'graph.ts'), + `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-TWO';`, + ) + } + }), + ) + page.on('response', (response) => { + if (new URL(response.url()).pathname.endsWith('.js')) { + const responsePhase = phase + assets.push( + response + .text() + .then(async (text) => { + const file = output.replace( + /\.json$/, + `-${name}-js${result.initialJavaScript.length}.txt`, + ) + result.initialJavaScript.push({ + phase: responsePhase, + url: response.url(), + mentionedModules: mentions(text), + file, + }) + await writeFile(file, text) + }) + .catch((error) => + result.initialJavaScript.push({ + phase: responsePhase, + error: String(error), + }), + ), + ) + } + }) + const checkpoint = async (expected) => { + await expect(page.locator('#app')).toHaveText(expected, { + timeout: 15000, + }) + assert.deepEqual( + await (await fetch(new URL('/__info', info.url))).json(), + { pid: info.pid }, + ) + await Promise.all(assets) + result.steps.push({ + phase, + text: expected, + documentToken: await page.evaluate( + () => globalThis.__pureGraphDocumentToken, + ), + documentLoads: result.documentLoads, + errorCount: result.errors.length, + }) + if (largePairMode) { + assert.deepEqual( + await page.evaluate(() => globalThis.__pureShared), + { identity: true, initializations: 1 }, + ) + } + } + const checkAuthoredThrow = async () => { + await session.send('Debugger.setPauseOnExceptions', { state: 'all' }) + let resumePromise + const paused = new Promise((resolve) => + session.once('Debugger.paused', (event) => { + resolve(event) + resumePromise = session.send('Debugger.resume') + }), + ) + const evaluation = session.send('Runtime.evaluate', { + expression: `try { globalThis.__throwCached() } catch(error) { error.message }`, + returnByValue: true, + }) + let pauseTimer + const event = await Promise.race([ + paused, + new Promise((_, reject) => { + pauseTimer = setTimeout( + () => reject(new Error('Expected authored exception pause')), + 15000, + ) + }), + ]).finally(() => clearTimeout(pauseTimer)) + await resumePromise + const evaluated = await evaluation + await session.send('Debugger.setPauseOnExceptions', { state: 'none' }) + assert.equal(evaluated.result.value, 'CACHED_CLOSURE_AUTHORED_THROW') + const frame = event.callFrames[0], + script = scripts.get(frame.location.scriptId) + assert.ok( + script?.sourceMapURL, + 'Throwing script must declare a source map', + ) + const { scriptSource } = await session.send( + 'Debugger.getScriptSource', + { scriptId: script.scriptId }, + ) + const mapUrl = script.sourceMapURL.startsWith('/') + ? new URL(script.sourceMapURL, info.url).href + : new URL( + script.sourceMapURL, + new URL(script.url || info.url, info.url), + ).href + assert.ok(!mapUrl.startsWith('data:'), 'Expected network source map') + const response = await fetch(mapUrl) + assert.equal(response.status, 200) + const map = await response.json(), + trace = AnyMap(map) + const generated = { + line: frame.location.lineNumber + 1, + column: frame.location.columnNumber, + } + const traced = originalPositionFor(trace, generated) + assert.ok(traced.source, 'Authored source is required') + const tracedFile = traced.source.startsWith('file:') + ? fileURLToPath(traced.source) + : path.resolve(directory, traced.source) + assert.equal( + path.normalize(tracedFile), + path.join(directory, 'cached-leaf.ts'), + ) + assert.equal(traced.line, 3) + assert.equal(traced.column, 2) + assert.equal( + sourceContentFor(trace, traced.source, true), + authoredSource, + ) + const snapshot = output.replace(/\.json$/, `-${name}-${phase}-throw`) + await writeFile(snapshot + '.js', scriptSource) + await writeFile(snapshot + '.js.map', JSON.stringify(map)) + ;(result.authoredThrows ??= []).push({ + phase, + scriptUrl: script.url, + sourceMapURL: script.sourceMapURL, + mapUrl, + generated, + traced, + sourceContentMatches: true, + snapshot, + }) + } + await page.goto(info.url) + await checkpoint('BEFORE') + if (sourceMapMode) { + await checkAuthoredThrow() + } + phase = 'A-to-B' + await writeFile( + path.join(directory, 'graph.ts'), + sourceMapMode + ? `export {value,authoredThrow} from './after.ts';` + : largePairMode + ? `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-ONE';` + : `export {value} from './after.ts';`, + ) + await checkpoint(largePairMode ? 'AFTER-TWO' : 'AFTER') + if (largePairMode) { + assert.ok( + pairedWrite, + 'Second public file write was triggered by first HMR frame', + ) + await pairedWrite + assert.equal( + result.documentLoads, + 1, + 'Paired updates must retain the document', + ) + } + if (reloadWhileAfter) { + phase = 'reload-B' + await page.reload() + await checkpoint('AFTER') + } + phase = 'B-to-A' + await writeFile( + path.join(directory, 'graph.ts'), + sourceMapMode + ? `export {value,authoredThrow} from './before.ts';` + : largePairMode + ? `export {value,shared} from './before.ts';` + : `export {value} from './before.ts';`, + ) + await checkpoint('BEFORE') + if (sourceMapMode) { + assert.equal( + result.documentLoads, + 2, + 'Restoration must not fall back to another document reload', + ) + await checkAuthoredThrow() + } + assert.deepEqual(result.errors, [], 'Unexpected browser errors') + result.passed = true + console.log(`PASS ${name}`) + } catch (error) { + result.error = error instanceof Error ? error.stack : String(error) + console.log(`FAIL ${name}: ${String(error).split('\n')[0]}`) + } finally { + result.serverLog = logs + try { + await context?.close() + } finally { + if (child && child.exitCode === null && child.signalCode === null) { + child.kill() + await new Promise((resolve) => child.once('exit', resolve)) + } + await rm(directory, { recursive: true, force: true }) + } + } + results.push(result) + await writeFile( + output, + JSON.stringify( + { + platform: process.platform, + node: process.version, + sourceMapMode, + largePairMode, + passed: results.filter((result) => result.passed).length, + cases: binaries.length * (sourceMapMode || largePairMode ? 1 : 2), + results, + }, + null, + 2, + ) + '\n', + ) + } + } +} finally { + await browser.close() +} +console.log( + `RESULT ${results.filter((result) => result.passed).length}/${results.length}; ${output}`, +) +if (results.some((result) => !result.passed)) { + process.exitCode = 1 +} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 3a7e5133ac3..ebc85748124 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -63,7 +63,7 @@ jobs: import hashlib, json, os, subprocess from pathlib import Path binary = Path('.native-proof/binary/bun') - manifest = json.loads(Path('.github/native-bun-validation/native-v10-manifest.json').read_text()) + manifest = json.loads(Path('.github/native-bun-validation/native-v12-manifest.json').read_text()) proof = { 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), 'base': manifest['head'], @@ -161,6 +161,22 @@ jobs: run: node .github/native-bun-validation/browser-setup.mjs - name: Install Chromium run: pnpm exec playwright install chromium --only-shell + - name: Preserve native HMR script order in the browser + id: hmr_order + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PURE_BUN_LARGE_PAIR: '1' + PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-hmr-order.json + run: node .github/native-bun-validation/pure-bun-graph-browser.mjs + - name: Map restored native dependencies to their authored source + id: restored_maps + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PURE_BUN_SOURCE_MAPS: '1' + PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-restored-maps.json + run: node .github/native-bun-validation/pure-bun-graph-browser.mjs - name: Production builds, navigation and source maps id: production continue-on-error: true @@ -240,5 +256,7 @@ jobs: CONFIGURATION: ${{ steps.configuration.outcome }} CONFIGURATION_BROWSER: ${{ steps.configuration_browser.outcome }} NATIVE_REGRESSIONS: ${{ steps.native_regressions.outcome }} + HMR_ORDER: ${{ steps.hmr_order.outcome }} + RESTORED_MAPS: ${{ steps.restored_maps.outcome }} run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success ]] + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success ]] From 5b61bd98951bf95cd430261373b6f9965c91d304 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 12:58:10 +0200 Subject: [PATCH 15/31] fix(router-plugin): canonicalize native Bun route module paths --- .../bun-basic-file-based/build.mjs | 82 +++++++++++++++++-- .../bun-basic-file-based/bun.spec.ts | 27 ++++++ .../bun-basic-file-based/dev-fixture.ts | 18 +++- .../bun-basic-file-based/dev.test.ts | 61 ++++++++++++++ .../src/core/router-composed-plugin.ts | 2 +- .../src/core/router-generator-plugin.ts | 37 +++++++-- 6 files changed, 211 insertions(+), 16 deletions(-) diff --git a/e2e/react-router/bun-basic-file-based/build.mjs b/e2e/react-router/bun-basic-file-based/build.mjs index d13d87ef461..08ac179f34c 100644 --- a/e2e/react-router/bun-basic-file-based/build.mjs +++ b/e2e/react-router/bun-basic-file-based/build.mjs @@ -1,10 +1,11 @@ -import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { cp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' import tanstackRouter, { tanstackRouter as namedTanstackRouter, } from '@tanstack/router-plugin/bun' import { verifyBunRouteSourceMaps } from './source-maps.mjs' +import { index, physical, rootRoute } from '@tanstack/virtual-file-routes' const here = path.dirname(fileURLToPath(import.meta.url)) const workspace = path.resolve(here, './.cache/bun-e2e') @@ -34,9 +35,11 @@ const markers = [ const supportsInputSourceMaps = await verifyBunRouteSourceMaps() -async function build(name, plugin, beforePlugins = []) { +async function build(name, plugin, beforePlugins = [], paths = {}) { + const entryFixture = paths.fixture ?? fixture + const treeFile = paths.generatedRouteTree ?? generatedRouteTree const result = await Bun.build({ - entrypoints: [path.join(fixture, 'main.tsx')], + entrypoints: [path.join(entryFixture, 'main.tsx')], outdir: path.join(workspace, name), target: 'browser', format: 'esm', @@ -60,12 +63,12 @@ async function build(name, plugin, beforePlugins = []) { })), ) const routeSource = await readFile( - path.join(fixture, 'routes/about.tsx'), + path.join(entryFixture, 'routes/about.tsx'), 'utf8', ) return { name, - routeTree: await readFile(generatedRouteTree, 'utf8'), + routeTree: await readFile(treeFile, 'utf8'), routeSourceMaps: outputs .filter( ({ path, source }) => @@ -195,7 +198,74 @@ await rm(path.join(fixture, 'routes/details.tsx')) await rm(path.join(fixture, 'routes/details.lazy.tsx')) builds.push(await build('edited', reusedPlugin)) -const manifest = { builds, generationFailure, supportsInputSourceMaps } +const aliasBuilds = [] +for (const name of [ + 'project-alias', + 'routes-alias', + 'tree-alias', + 'mounted-alias', +]) { + const directory = path.join(workspace, name) + const source = path.join(directory, 'source') + const alias = path.join(directory, 'alias') + await cp(path.join(here, 'fixture'), source, { recursive: true }) + await symlink( + source, + alias, + process.platform === 'win32' ? 'junction' : 'dir', + ) + const routesDirectory = path.join( + name === 'project-alias' || name === 'routes-alias' ? alias : source, + 'routes', + ) + const treeFile = path.join( + name === 'project-alias' || name === 'tree-alias' ? alias : source, + 'routeTree.gen.ts', + ) + let virtualRouteConfig + if (name === 'mounted-alias') { + const mounted = path.join(directory, 'mounted') + await mkdir(mounted) + await cp( + path.join(source, 'routes/about.tsx'), + path.join(mounted, 'about.tsx'), + ) + await symlink( + mounted, + path.join(source, 'mounted-alias'), + process.platform === 'win32' ? 'junction' : 'dir', + ) + virtualRouteConfig = rootRoute('__root.tsx', [ + index('index.tsx'), + physical('../mounted-alias'), + ]) + } + aliasBuilds.push( + await build( + name, + tanstackRouter({ + ...options, + routesDirectory, + generatedRouteTree: treeFile, + tmpDir: path.join(directory, 'tmp'), + virtualRouteConfig, + codeSplittingOptions: { defaultBehavior: [['loader'], ['component']] }, + }), + [], + { + fixture: name === 'project-alias' ? alias : source, + generatedRouteTree: treeFile, + }, + ), + ) +} + +const manifest = { + builds, + aliasBuilds, + generationFailure, + supportsInputSourceMaps, +} if (!process.argv.includes('--serve')) { console.log(JSON.stringify(manifest, null, 2)) } else { diff --git a/e2e/react-router/bun-basic-file-based/bun.spec.ts b/e2e/react-router/bun-basic-file-based/bun.spec.ts index 717bb9c0e65..7703b66afb4 100644 --- a/e2e/react-router/bun-basic-file-based/bun.spec.ts +++ b/e2e/react-router/bun-basic-file-based/bun.spec.ts @@ -74,6 +74,33 @@ test('generates routes before production bundling and refreshes reused plugins', expect(manifest.generationFailure).toMatch(/conflicting configuration paths/i) }) +test('splits routes through project, route-directory, generated-tree and mounted aliases', async ({ + request, +}) => { + const manifest = (await (await request.get('/__builds')).json()) as { + aliasBuilds: Array + } + expect(manifest.aliasBuilds.map(({ name }) => name)).toEqual([ + 'project-alias', + 'routes-alias', + 'tree-alias', + 'mounted-alias', + ]) + for (const build of manifest.aliasBuilds) { + expect(build.routeTree).toContain('/about') + const entrypoint = build.outputs.find(({ kind }) => kind === 'entry-point') + expect(entrypoint).toBeDefined() + expect(entrypoint!.markers).toEqual([]) + expect( + build.outputs.filter(({ markers }) => + markers.includes('ABOUT_NATIVE_BUN'), + ), + ).toEqual([ + expect.objectContaining({ kind: 'chunk', markers: ['ABOUT_NATIVE_BUN'] }), + ]) + } +}) + test('maps split route chunks to their authored source', async ({ request, }) => { diff --git a/e2e/react-router/bun-basic-file-based/dev-fixture.ts b/e2e/react-router/bun-basic-file-based/dev-fixture.ts index dec0e2a301a..acf6328642d 100644 --- a/e2e/react-router/bun-basic-file-based/dev-fixture.ts +++ b/e2e/react-router/bun-basic-file-based/dev-fixture.ts @@ -57,12 +57,14 @@ export async function startDevFixture({ virtualConfigFile = false, virtualConfigHelperDepth = 0, autoCodeSplitting = true, + projectAlias = false, }: { generatedExtension?: string virtualMount?: boolean virtualConfigFile?: boolean virtualConfigHelperDepth?: 0 | 1 | 2 autoCodeSplitting?: boolean + projectAlias?: boolean } = {}) { const executable = process.env.BUN_EXECUTABLE const repo = process.env.ROUTER_REPOSITORY_ROOT @@ -78,7 +80,8 @@ export async function startDevFixture({ const requireProject = createRequire( fileURLToPath(new URL('./package.json', import.meta.url)), ) - const directory = await mkdtemp(path.join(tmpdir(), 'router-bun-native-dev-')) + const container = await mkdtemp(path.join(tmpdir(), 'router-bun-native-dev-')) + const directory = projectAlias ? path.join(container, 'alias') : container const inlineMaps: Array = [] let logs = '' let child: ReturnType | undefined @@ -88,6 +91,15 @@ export async function startDevFixture({ await writeFile(file(name), source) } try { + if (projectAlias) { + const source = path.join(container, 'source') + await mkdir(source) + await symlink( + source, + directory, + process.platform === 'win32' ? 'junction' : 'dir', + ) + } for (const name of [ '@tanstack/router-plugin', '@tanstack/react-router', @@ -314,7 +326,7 @@ export default { name: 'observe-public-router-dev', setup(build) { await new Promise((resolve) => child!.once('exit', resolve)) } } - await rm(directory, { recursive: true, force: true }) + await rm(container, { recursive: true, force: true }) }, } } catch (error) { @@ -322,7 +334,7 @@ export default { name: 'observe-public-router-dev', setup(build) { if (child && child.exitCode === null && child.signalCode === null) { await new Promise((resolve) => child!.once('exit', resolve)) } - await rm(directory, { recursive: true, force: true }) + await rm(container, { recursive: true, force: true }) throw error } } diff --git a/e2e/react-router/bun-basic-file-based/dev.test.ts b/e2e/react-router/bun-basic-file-based/dev.test.ts index 1c603efd326..79352125ed0 100644 --- a/e2e/react-router/bun-basic-file-based/dev.test.ts +++ b/e2e/react-router/bun-basic-file-based/dev.test.ts @@ -17,12 +17,14 @@ const test = base.extend<{ virtualConfigFile: boolean virtualConfigHelperDepth: 0 | 1 | 2 autoCodeSplitting: boolean + projectAlias: boolean }>({ generatedExtension: ['ts', { option: true }], virtualMount: [false, { option: true }], virtualConfigFile: [false, { option: true }], virtualConfigHelperDepth: [0, { option: true }], autoCodeSplitting: [true, { option: true }], + projectAlias: [false, { option: true }], native: async ( { generatedExtension, @@ -30,6 +32,7 @@ const test = base.extend<{ virtualConfigFile, virtualConfigHelperDepth, autoCodeSplitting, + projectAlias, }, use, testInfo, @@ -40,6 +43,7 @@ const test = base.extend<{ virtualConfigFile, virtualConfigHelperDepth, autoCodeSplitting, + projectAlias, }) try { await testInfo.attach('versions.json', { @@ -117,6 +121,63 @@ const documentToken = (page: Page) => return (state.__bunDevDocumentToken ??= crypto.randomUUID()) }) +test.describe('project directory alias', () => { + test.use({ projectAlias: true }) + test('splits canonical route modules and watches the aliased generated tree', async ({ + page, + request, + native, + }, testInfo) => { + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + const initialToken = await documentToken(page) + await page.getByRole('link', { name: 'About', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('ABOUT_BEFORE') + expect(await documentToken(page)).toBe(initialToken) + const compiledRoute = () => + native.inlineMaps.find( + ({ contents }) => + contents.includes('AUTHORED_BEFORE') && + contents.includes('sourceMappingURL=data:'), + ) + await expect + .poll(compiledRoute, { + message: 'the canonical route receives the Router split transform', + }) + .toBeDefined() + const compiled = compiledRoute() + expectAuthoredPosition( + inlinePosition(compiled!.contents, 'AUTHORED_BEFORE'), + aboutSource(), + 'AUTHORED_BEFORE', + ) + await native.save( + 'routes/nested/empty/deep/added.tsx', + nestedSource('/nested/empty/deep/added', 'ALIASED_NESTED_ADDED'), + ) + await expect.poll(() => native.tree()).toContain('/nested/empty/deep/added') + await page.getByRole('link', { name: 'Nested added', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('ALIASED_NESTED_ADDED') + const checkpointToken = await documentToken(page) + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + expect(await documentToken(page)).toBe(checkpointToken) + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + await testInfo.attach('project-alias.json', { + body: JSON.stringify({ + sameProcess: true, + automaticDocumentReload: initialToken !== checkpointToken, + }), + contentType: 'application/json', + }) + }) +}) + function inlinePosition(contents: string, marker: string) { const match = contents.match( /\/\/# sourceMappingURL=data:application\/json[^,]*;base64,([^\s]+)/, diff --git a/packages/router-plugin/src/core/router-composed-plugin.ts b/packages/router-plugin/src/core/router-composed-plugin.ts index 9846940ee4f..60fc7631801 100644 --- a/packages/router-plugin/src/core/router-composed-plugin.ts +++ b/packages/router-plugin/src/core/router-composed-plugin.ts @@ -47,7 +47,7 @@ export const unpluginRouterComposedFactory: UnpluginFactory< } const routerGenerator = getPlugin( - createRouterGeneratorPlugin(options, routerPluginContext), + createRouterGeneratorPlugin(options, routerPluginContext, meta.framework), ) const routerCodeSplitter = getPlugin( createRouterCodeSplitterPlugin( diff --git a/packages/router-plugin/src/core/router-generator-plugin.ts b/packages/router-plugin/src/core/router-generator-plugin.ts index 99c0b0d8907..baab102ecbe 100644 --- a/packages/router-plugin/src/core/router-generator-plugin.ts +++ b/packages/router-plugin/src/core/router-generator-plugin.ts @@ -1,5 +1,7 @@ -import { readFile, readdir } from 'node:fs/promises' +import { realpathSync } from 'node:fs' +import { readFile, readdir, realpath } from 'node:fs/promises' import { + basename, dirname, extname, isAbsolute, @@ -10,10 +12,11 @@ import { import { Generator, resolveConfigPath } from '@tanstack/router-generator' import { getConfig } from './config' import { createRouterPluginContext } from './router-plugin-context' +import { normalizePath } from './utils' import type { GeneratorEvent } from '@tanstack/router-generator' import type { FSWatcher } from 'chokidar' -import type { UnpluginFactory } from 'unplugin' +import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' import type { Config } from './config' import type { RouterPluginContext } from './router-plugin-context' @@ -22,6 +25,7 @@ const PLUGIN_NAME = 'unplugin:router-generator' export function createRouterGeneratorPlugin( options: Partial Config)> | undefined = {}, routerPluginContext: RouterPluginContext, + framework?: UnpluginContextMeta['framework'], ): ReturnType Config)> | undefined>> { let ROOT: string = process.cwd() let userConfig: Config @@ -50,7 +54,20 @@ export function createRouterGeneratorPlugin( const runGenerator = async (event?: GeneratorEvent) => { await generator.run(event) - routerPluginContext.routesByFile = generator.getRoutesByFileMap() + const routesByFile = generator.getRoutesByFileMap() + // Bun resolves symlinks before invoking its module hooks. + routerPluginContext.routesByFile = + framework === 'bun' + ? new Map( + await Promise.all( + Array.from( + routesByFile, + async ([file, route]) => + [normalizePath(await realpath(file)), route] as const, + ), + ), + ) + : routesByFile } const generate = async (opts?: { @@ -92,10 +109,14 @@ export function createRouterGeneratorPlugin( 'reactFastRefresh' in build.config && build.config.reactFastRefresh ) { - const generatedRouteTree = resolve( + const configuredRouteTree = resolve( ROOT, userConfig.generatedRouteTree, ) + const generatedRouteTree = join( + realpathSync.native(dirname(configuredRouteTree)), + basename(configuredRouteTree), + ) const extension = extname(generatedRouteTree) build.onLoad( { @@ -217,6 +238,10 @@ export function createRouterGeneratorPlugin( export const unpluginRouterGeneratorFactory: UnpluginFactory< Partial Config)> | undefined -> = (options = {}) => { - return createRouterGeneratorPlugin(options, createRouterPluginContext()) +> = (options = {}, meta) => { + return createRouterGeneratorPlugin( + options, + createRouterPluginContext(), + meta.framework, + ) } From 70036aaca404d4b472f63b145b441b153fbd222c Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 13:06:36 +0200 Subject: [PATCH 16/31] test: isolate native macOS watcher diagnostics --- .../native-bun-validation/artifact-tests.py | 61 ++++++++++++++++++- .../mac-quiet-watch-tests.patch | 30 +++++++++ .github/workflows/bun-native-validation.yml | 2 +- 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 .github/native-bun-validation/mac-quiet-watch-tests.patch diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index a26ae1ecec5..7d8093a1c50 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -2,6 +2,7 @@ import json import os from pathlib import Path +import re import subprocess import xml.etree.ElementTree as ET @@ -17,15 +18,67 @@ assert expected["patchSha256"] == manifest["trackedPatchSha256"] assert expected["additionalFiles"] == manifest["additionalFiles"] binary.chmod(0o755) -source = root / ".native-test-source" +source = root / ".cache/native-bun-validation/test-source" subprocess.run([ "python3", str(root / ".github/native-bun-validation/prepare.py"), "--bun", str(source), "--out", str(proof / "native-source"), ], check=True) +adjustments = root / ".github/native-bun-validation/mac-quiet-watch-tests.patch" +patch = adjustments.read_bytes() +assert hashlib.sha256(patch).hexdigest() == "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062" +paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) +assert all(old == new for old, new in paths) +assert {old.decode() for old, _ in paths} == { + "test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts", +} +subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) +subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) +overrides = proof / "native-test-overrides" +overrides.mkdir(exist_ok=True) +(overrides / "adjustments.patch").write_bytes(patch) +adjusted_sources = {} +for old, _ in paths: + name = old.decode() + contents = (source / name).read_bytes() + adjusted_sources[name] = hashlib.sha256(contents).hexdigest() + target = overrides / name + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(contents) +(overrides / "proof.json").write_text(json.dumps({ + "binaryRuntimeUnchanged": True, + "testOnlyPatchSha256": hashlib.sha256(patch).hexdigest(), + "adjustedSourceSha256": adjusted_sources, +}, indent=2) + "\n") for cwd in [source, source / "test"]: subprocess.run([str(binary), "install", "--frozen-lockfile"], cwd=cwd, check=True) tests = manifest["testCommand"].split(" test ", 1)[1].split() assert len(tests) == 9 +isolated = [ + ("test/bake/dev/plugins.test.ts", "watchDirs preserves browser state when only a child file's contents change"), + ("test/bake/dev/plugins.test.ts", "watchDirs shares directory events with imported files and trailing-slash aliases"), + ("test/bake/dev/client-plugin-cache.test.ts", "client plugin cache probe: structural dependency update serves the current manifest"), + ("test/bake/dev/server-sourcemap.test.ts", "server-side source maps handle nested imports"), +] +isolated_results = [] +for index, (filename, title) in enumerate(isolated): + isolated_report = proof / f"native-isolated-{index}.xml" + run = subprocess.run([ + str(binary), "test", filename, "-t", re.escape(title), + "--reporter=junit", f"--reporter-outfile={isolated_report}", + ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={ + **os.environ, + "BUN_DEV_SERVER_VERBOSE_SYNC": "1", + "BUN_WATCHER_TRACE": str(proof / f"native-isolated-{index}-watcher.jsonl"), + }) + (proof / f"native-isolated-{index}.log").write_text(run.stdout) + selected = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] + passed = run.returncode == 0 and bool(selected) and all( + not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) + for case in selected + ) + isolated_results.append({"file": filename, "title": title, "passed": passed, "cases": len(selected)}) + print(json.dumps(isolated_results[-1])) +(proof / "native-isolated-results.json").write_text(json.dumps(isolated_results, indent=2) + "\n") report = proof / "native-results.xml" # Execute the verified, source-built artifact. The Bun CI build path ignores # trailing execution arguments, so a successful build alone is not a test run. @@ -34,10 +87,8 @@ ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) (proof / "native-regressions.log").write_text(result.stdout) print(result.stdout, end="") -result.check_returncode() cases = ET.parse(report).findall(".//testcase") assert cases, "Native test runner executed no cases" -assert not any(case.find("failure") is not None or case.find("error") is not None for case in cases) by_file = {filename: [] for filename in tests} for case in cases: filename = Path(case.attrib["file"]) @@ -52,7 +103,11 @@ "binarySha256": expected["sha256"], "selectedFiles": tests, "cases": len(cases), "skipped": sum(case.find("skipped") is not None for case in cases), + "failed": sum(case.find("failure") is not None or case.find("error") is not None for case in cases), "perFile": {filename: len(group) for filename, group in by_file.items()}, } (proof / "native-results.json").write_text(json.dumps(summary, indent=2) + "\n") print(json.dumps(summary, indent=2)) +result.check_returncode() +assert summary["failed"] == 0 +assert all(run["passed"] for run in isolated_results) diff --git a/.github/native-bun-validation/mac-quiet-watch-tests.patch b/.github/native-bun-validation/mac-quiet-watch-tests.patch new file mode 100644 index 00000000000..ca9acee4348 --- /dev/null +++ b/.github/native-bun-validation/mac-quiet-watch-tests.patch @@ -0,0 +1,30 @@ +diff --git a/test/bake/dev/plugins.test.ts b/test/bake/dev/plugins.test.ts +--- a/test/bake/dev/plugins.test.ts ++++ b/test/bake/dev/plugins.test.ts +@@ -134,7 +134,13 @@ + await c.expectElemText("button", "Count 1"); +- await dev.write("unrelated.txt", "first"); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("unrelated.txt", "first"); ++ }); + await c.expectElemText("button", "Count 1"); +- await dev.write("unrelated.txt", "second"); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("unrelated.txt", "second"); ++ }); + await c.expectElemText("button", "Count 1"); +- await dev.write("data/a.ts", `export default "second";`); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("data/a.ts", `export default "second";`); ++ }); + await c.expectElemText("button", "Count 1"); +diff --git a/test/bake/dev/client-plugin-cache.test.ts b/test/bake/dev/client-plugin-cache.test.ts +--- a/test/bake/dev/client-plugin-cache.test.ts ++++ b/test/bake/dev/client-plugin-cache.test.ts +@@ -92,3 +92,5 @@ + await client.click("button"); +- await dev.write("data/a.ts", `export default "second";`); ++ await client.expectNoWebSocketActivity(async () => { ++ await dev.write("data/a.ts", `export default "second";`); ++ }); + await client.expectElemText("button", "Count 1"); diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index ebc85748124..3f747f469bb 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -125,7 +125,7 @@ jobs: with: repository: RentnerKev/bun ref: dca7d25e95cca39316c659a377dba6803805549f - path: .native-test-source + path: .cache/native-bun-validation/test-source persist-credentials: false - name: Execute verified native artifact regressions id: native_regressions From 2ef767773dc91d9b47f09dbfc054e847abf25039 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 13:15:05 +0200 Subject: [PATCH 17/31] test: execute native Bun Chromium regression on macOS --- .../native-bun-validation/artifact-tests.py | 48 +++++++++++------- .github/native-bun-validation/chrome-test.py | 32 ++++++++++++ .../hmr-script-order-test.patch.gz | Bin 0 -> 2129 bytes .github/workflows/bun-native-validation.yml | 7 ++- 4 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 .github/native-bun-validation/chrome-test.py create mode 100644 .github/native-bun-validation/hmr-script-order-test.patch.gz diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index 7d8093a1c50..69efd904b06 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -1,3 +1,4 @@ +import gzip import hashlib import json import os @@ -23,30 +24,39 @@ "python3", str(root / ".github/native-bun-validation/prepare.py"), "--bun", str(source), "--out", str(proof / "native-source"), ], check=True) -adjustments = root / ".github/native-bun-validation/mac-quiet-watch-tests.patch" -patch = adjustments.read_bytes() -assert hashlib.sha256(patch).hexdigest() == "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062" -paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) -assert all(old == new for old, new in paths) -assert {old.decode() for old, _ in paths} == { - "test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts", -} -subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) -subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) overrides = proof / "native-test-overrides" overrides.mkdir(exist_ok=True) -(overrides / "adjustments.patch").write_bytes(patch) adjusted_sources = {} -for old, _ in paths: - name = old.decode() - contents = (source / name).read_bytes() - adjusted_sources[name] = hashlib.sha256(contents).hexdigest() - target = overrides / name - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(contents) +patches = {} +for name, digest, allowed_paths in [ + ("mac-quiet-watch-tests.patch", + "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062", + {"test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts"}), + ("hmr-script-order-test.patch.gz", + "b63245335607c7b9afaaddb7114d5f42a580d67b90119d3c5b0aecea0389d6bf", + {"test/js/bun/webview/webview-chrome.test.ts"}), +]: + patch = (root / ".github/native-bun-validation" / name).read_bytes() + if name.endswith(".gz"): + patch = gzip.decompress(patch) + assert hashlib.sha256(patch).hexdigest() == digest + paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) + assert all(old == new for old, new in paths) + assert {old.decode() for old, _ in paths} == allowed_paths + subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) + subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) + (overrides / name.removesuffix(".gz")).write_bytes(patch) + patches[name] = digest + for old, _ in paths: + filename = old.decode() + contents = (source / filename).read_bytes() + adjusted_sources[filename] = hashlib.sha256(contents).hexdigest() + target = overrides / filename + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(contents) (overrides / "proof.json").write_text(json.dumps({ "binaryRuntimeUnchanged": True, - "testOnlyPatchSha256": hashlib.sha256(patch).hexdigest(), + "testOnlyPatchSha256": patches, "adjustedSourceSha256": adjusted_sources, }, indent=2) + "\n") for cwd in [source, source / "test"]: diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py new file mode 100644 index 00000000000..f89c4a6b371 --- /dev/null +++ b/.github/native-bun-validation/chrome-test.py @@ -0,0 +1,32 @@ +import hashlib +import json +import os +from pathlib import Path +import subprocess +import xml.etree.ElementTree as ET + + +root = Path(os.environ["GITHUB_WORKSPACE"]) +binary = root / ".native-artifact/binary/bun" +proof = root / ".native-browser-proof" +source = root / ".cache/native-bun-validation/test-source" +expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) +assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] +report = proof / "native-chrome.xml" +title = "HMR applies a large update before the following small update" +result = subprocess.run([ + str(binary), "test", "test/js/bun/webview/webview-chrome.test.ts", "-t", title, + "--reporter=junit", f"--reporter-outfile={report}", +], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +(proof / "native-chrome.log").write_text(result.stdout) +print(result.stdout, end="") +cases = ET.parse(report).findall(".//testcase") if report.exists() else [] +passed = result.returncode == 0 and len(cases) == 1 and all( + not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) + for case in cases +) +(proof / "native-chrome.json").write_text(json.dumps({ + "binarySha256": expected["sha256"], "title": title, + "cases": len(cases), "passed": passed, +}, indent=2) + "\n") +assert passed, "Native Chromium ordering regression must execute and pass" diff --git a/.github/native-bun-validation/hmr-script-order-test.patch.gz b/.github/native-bun-validation/hmr-script-order-test.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..cce02f6413f2c432fb247d9530b2bd4058202a8e GIT binary patch literal 2129 zcmV-X2(I@ZiwFP!00002|GijkbKAHP{_bC~$7W7oMN!fX3*=+xdPf(tWf>0MSogm z{Uw{;akg~VUX)0&V4)@nRRPmy5FhX?X7|8e(buo1>>pt`jHAB~qr=xQ91LE)e0k98 z^`5o+LATp|o(4bv486nP5W4yYANV2{Qo#ct?`d`ynCm?YfEOp{`u8J^F0SgE-GGUqifln!2EhV2P3L+XM%!fjl7g{Tb znPL%o^2BHgOXOmAOlkrnO_rJB`h_UdIE0G~zMvn)vOo%|P%|itlBVg(h|DG9S)uTm z#c&$WS$ME9GEPO#vH;G`&aYQFTA8bj?r8aFHsjvWL9b?@QN)VkYL!I+L_*8WP*YmK ztT=Ix0Z2yUm`h707y4RD%|y&bvjU}d|9hzcpc@rC<0;#-$;Q?Mof$VmV`xO1=BwaY zn?Q$7lbA#q9=;Axew!G@M5ayNU?j>*93tFU0_*+nti@JKM|;R#xg|`UrXw8MZ8}= zUINYYlr!`oq*TrslsSrFFl93#naPToNK>)IU7%QCYE%?nfVycv60`ZkK^HKWG?jMT z*kw2Il7;LQk>t7R2^lkqjD{G%GbJ5rWxWwh-o*S4cs%w{CGYr6A0Ln3SWe@rv9}O$ znWCo(8I8TLzo0zBy419m?06DXlHDs5Ygb?sxI3Dbn7&0qC8l{5!A{tpOPVLh)H&K> zsc1160!xu+G;Q$Nmo3J5DyB5OPIwW_Ou#ZDIG|iXgo#+u2v&w$ap-i zEkS(BxZ*VB|E3D@sc=-`qjjBvEysilrf8T573!kQRc%Kd2Io>82X_C2|82?{Kh^^3 zwU&e})W~^-*RdSiUvp)NTuHpp? zms};6tPm;ox#Eq*zhlzo!E5|Qqy1jKJHcbeMVAyO7Ykl`Kc?~PeVK(tPL~;}&?;KQ zBe-$K+g4Bfz%6(^ghcl+sgNV5h^QuqUOfEs>f*Q1s>^39VuE;O9tk3*AGF}m_cz7X z@We(l{Xlf1DpW=n*hV_TpAN$T{tr9YnsM_H3~GHevfx~R9bALUNO!n}9D$OUw3uvC zlsHZ3J;(93yVFY-Jh3)BIX^IZ!8mms0Ep>-4*tE=8v8L{4-Tuh$c zW1{HPt;}NPIn)yv(f23VLF*O=*b=2!LdKSGDkWm`I@F^Dt~tor%d5gBNV$b44-Z99^2WWVQ4DmrpmWEwiSVMT?I^@S9uFz zx2g-`=9V)124d#CWJA;lgcH&o8|PeOtNOt7^dX5K#^#O~A)Bnydn4BfvT`wHvR+>% zIHUm~_zrcd1c#4h*WZvb{6P~ETnpiMhzPfxnKQaWYnjyCQZ>!uZN z`stqTY($~cJH6{K7n>e!|NNFg&B|~k-=tW(+v;X*3$UWmbx;*jThLdWvzo}D&kw8b zY95xJX(&Jh#q`d^GP}9Gxkc`q+pYeh&y`>+MC14uHvJt}T#uR3=$k1BdnRybid%@3 z5oL~DVHo0|UNo{nr;~nX#yZca;`xZ{*xBLiOyR-IFH$ zOj{JFmad5+aACrs#-yPM(`lzQ@xFiBMtegg-Xo74B)w+v+avxMcJ8(BNZ@UGs^*zEv~NyO z7In^W$SM-kwR9>~P9aq=8t`s46w`Wo(BvOWWhSqSYMHb;f=!U;oJ7WM@HO?@!YQ|N z81tgao>skX*RU&Gw^B=}Zl2H#PnTFdJdJoZK-G^~MRm#i)rNM#abDcXy9R^5KnyZ6d}| zC=*J5mokz}Gj-t~ZO_ye^8EG0Bmpf8oQus`odN#~M5r_0dm3@}qd+CCwfZc1jYGec zcKRoN*(1%B_oS+~;rAW~ zFEt+R>w;Si5SBc)2V)%I5~e?cj^J Date: Sat, 24 Oct 2026 13:21:33 +0200 Subject: [PATCH 18/31] test: pin reviewed native Chromium fixture --- .../native-bun-validation/artifact-tests.py | 2 +- .../hmr-script-order-test.patch.gz | Bin 2129 -> 2287 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index 69efd904b06..3c6bbeeef47 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -33,7 +33,7 @@ "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062", {"test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts"}), ("hmr-script-order-test.patch.gz", - "b63245335607c7b9afaaddb7114d5f42a580d67b90119d3c5b0aecea0389d6bf", + "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", {"test/js/bun/webview/webview-chrome.test.ts"}), ]: patch = (root / ".github/native-bun-validation" / name).read_bytes() diff --git a/.github/native-bun-validation/hmr-script-order-test.patch.gz b/.github/native-bun-validation/hmr-script-order-test.patch.gz index cce02f6413f2c432fb247d9530b2bd4058202a8e..5999aaa0ec696de2b787ca622861edf989e7b1b5 100644 GIT binary patch literal 2287 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 Date: Sat, 24 Oct 2026 13:47:54 +0200 Subject: [PATCH 19/31] test: correct native macOS result and path assertions --- .github/native-bun-validation/artifact-tests.py | 10 ++++++---- .github/native-bun-validation/chrome-test.py | 7 ++++--- .../native-bun-validation/combined-generator.mjs | 5 ++++- .../pure-bun-graph-browser.mjs | 13 +++++++++++-- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index 3c6bbeeef47..c36f6a1e926 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -81,12 +81,14 @@ "BUN_WATCHER_TRACE": str(proof / f"native-isolated-{index}-watcher.jsonl"), }) (proof / f"native-isolated-{index}.log").write_text(run.stdout) - selected = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] - passed = run.returncode == 0 and bool(selected) and all( + all_cases = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] + selected = [case for case in all_cases if case.attrib.get("name", "").endswith(title)] + passed = run.returncode == 0 and len(selected) == 1 and all( not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) for case in selected - ) - isolated_results.append({"file": filename, "title": title, "passed": passed, "cases": len(selected)}) + ) and all(case.find("skipped") is not None for case in all_cases if case not in selected) + isolated_results.append({"file": filename, "title": title, "passed": passed, + "cases": len(selected), "filteredOut": len(all_cases) - len(selected)}) print(json.dumps(isolated_results[-1])) (proof / "native-isolated-results.json").write_text(json.dumps(isolated_results, indent=2) + "\n") report = proof / "native-results.xml" diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py index f89c4a6b371..7f63e6e27fd 100644 --- a/.github/native-bun-validation/chrome-test.py +++ b/.github/native-bun-validation/chrome-test.py @@ -20,13 +20,14 @@ ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) (proof / "native-chrome.log").write_text(result.stdout) print(result.stdout, end="") -cases = ET.parse(report).findall(".//testcase") if report.exists() else [] +all_cases = ET.parse(report).findall(".//testcase") if report.exists() else [] +cases = [case for case in all_cases if case.attrib.get("name", "") == title] passed = result.returncode == 0 and len(cases) == 1 and all( not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) for case in cases -) +) and all(case.find("skipped") is not None for case in all_cases if case not in cases) (proof / "native-chrome.json").write_text(json.dumps({ "binarySha256": expected["sha256"], "title": title, - "cases": len(cases), "passed": passed, + "cases": len(cases), "filteredOut": len(all_cases) - len(cases), "passed": passed, }, indent=2) + "\n") assert passed, "Native Chromium ordering regression must execute and pass" diff --git a/.github/native-bun-validation/combined-generator.mjs b/.github/native-bun-validation/combined-generator.mjs index d4dafbf2076..6e86bd96879 100644 --- a/.github/native-bun-validation/combined-generator.mjs +++ b/.github/native-bun-validation/combined-generator.mjs @@ -2,6 +2,7 @@ import { mkdtemp, mkdir, readFile, + realpath, rename, rm, writeFile, @@ -39,7 +40,9 @@ const helperSource = (ext, name) => : `export default ${JSON.stringify(routeConfig(name))}\n` for (const scenario of cases) { - const root = await mkdtemp(path.join(tmpdir(), 'router-built-helper-')) + const root = await realpath( + await mkdtemp(path.join(tmpdir(), 'router-built-helper-')), + ) const checks = [] const record = (name, passed, details = undefined) => checks.push({ name, passed, details }) diff --git a/.github/native-bun-validation/pure-bun-graph-browser.mjs b/.github/native-bun-validation/pure-bun-graph-browser.mjs index 0e62ebf5753..56d26eea78d 100644 --- a/.github/native-bun-validation/pure-bun-graph-browser.mjs +++ b/.github/native-bun-validation/pure-bun-graph-browser.mjs @@ -2,7 +2,14 @@ import assert from 'node:assert/strict' import { spawn, execFileSync } from 'node:child_process' import { createHash } from 'node:crypto' import { createRequire } from 'node:module' -import { mkdtemp, mkdir, readFile, writeFile, rm } from 'node:fs/promises' +import { + mkdtemp, + mkdir, + readFile, + realpath, + writeFile, + rm, +} from 'node:fs/promises' import { tmpdir } from 'node:os' import path from 'node:path' import { fileURLToPath } from 'node:url' @@ -55,7 +62,9 @@ try { : [false, true]) { const name = `${label}-${reloadWhileAfter ? 'reload-B' : 'automatic'}` console.log(`START ${name}`) - const directory = await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')) + const directory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')), + ) const result = { name, label, From cc3ae72ddb5e5aeaf47b5a7a6d33ccdbbd08ca23 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 13:55:42 +0200 Subject: [PATCH 20/31] test: validate final native watcher and HMR batches on macOS --- .../native-bun-validation/artifact-tests.py | 10 +- .github/native-bun-validation/build-macos.sh | 2 +- .../native-v12-tracked.patch.gz | Bin 88090 -> 0 bytes ....gz => native-v15-additional-files.tar.gz} | Bin ...manifest.json => native-v15-manifest.json} | 20 +- .../native-v15-tracked.patch.gz | Bin 0 -> 91550 bytes .github/native-bun-validation/prepare.py | 10 +- .../pure-bun-pending-batches-browser.mjs | 360 ++++++++++++++++++ .github/workflows/bun-native-validation.yml | 14 +- 9 files changed, 401 insertions(+), 15 deletions(-) delete mode 100644 .github/native-bun-validation/native-v12-tracked.patch.gz rename .github/native-bun-validation/{native-v12-additional-files.tar.gz => native-v15-additional-files.tar.gz} (100%) rename .github/native-bun-validation/{native-v12-manifest.json => native-v15-manifest.json} (68%) create mode 100644 .github/native-bun-validation/native-v15-tracked.patch.gz create mode 100644 .github/native-bun-validation/pure-bun-pending-batches-browser.mjs diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index c36f6a1e926..b89b0aedf81 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -13,7 +13,7 @@ proof = root / ".native-browser-proof" proof.mkdir(exist_ok=True) expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -manifest = json.loads((root / ".github/native-bun-validation/native-v12-manifest.json").read_text()) +manifest = json.loads((root / ".github/native-bun-validation/native-v15-manifest.json").read_text()) assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] assert expected["base"] == manifest["head"] assert expected["patchSha256"] == manifest["trackedPatchSha256"] @@ -68,12 +68,18 @@ ("test/bake/dev/plugins.test.ts", "watchDirs shares directory events with imported files and trailing-slash aliases"), ("test/bake/dev/client-plugin-cache.test.ts", "client plugin cache probe: structural dependency update serves the current manifest"), ("test/bake/dev/server-sourcemap.test.ts", "server-side source maps handle nested imports"), + ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy"), + ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy with an atomic plugin dependency"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies with an async dependency"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once with an async dependency"), ] isolated_results = [] for index, (filename, title) in enumerate(isolated): isolated_report = proof / f"native-isolated-{index}.xml" run = subprocess.run([ - str(binary), "test", filename, "-t", re.escape(title), + str(binary), "test", filename, "-t", re.escape(title) + "$", "--reporter=junit", f"--reporter-outfile={isolated_report}", ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={ **os.environ, diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh index d4cbcee1e20..e6dadf39d3c 100644 --- a/.github/native-bun-validation/build-macos.sh +++ b/.github/native-bun-validation/build-macos.sh @@ -53,4 +53,4 @@ bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" # The CI build wrapper does not execute trailing arguments. Regressions run # against the verified binary in the artifact validation job. -bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" +GITHUB_SHA="$(git rev-parse HEAD)" bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" diff --git a/.github/native-bun-validation/native-v12-tracked.patch.gz b/.github/native-bun-validation/native-v12-tracked.patch.gz deleted file mode 100644 index 381a72325cbc773286635c9c6e455d0ee04d4b37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88090 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

g(%J*C+sHY90_{Nx9D`SL6$zBEGIB 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 diff --git a/.github/native-bun-validation/native-v12-additional-files.tar.gz b/.github/native-bun-validation/native-v15-additional-files.tar.gz similarity index 100% rename from .github/native-bun-validation/native-v12-additional-files.tar.gz rename to .github/native-bun-validation/native-v15-additional-files.tar.gz diff --git a/.github/native-bun-validation/native-v12-manifest.json b/.github/native-bun-validation/native-v15-manifest.json similarity index 68% rename from .github/native-bun-validation/native-v12-manifest.json rename to .github/native-bun-validation/native-v15-manifest.json index dffb563e200..ceabee96b15 100644 --- a/.github/native-bun-validation/native-v12-manifest.json +++ b/.github/native-bun-validation/native-v15-manifest.json @@ -1,7 +1,7 @@ { - "candidate": "native-v12", + "candidate": "native-v15", "head": "dca7d25e95cca39316c659a377dba6803805549f", - "trackedPatchSha256": "d4d09320680f3602c018b157fd5bbb595f9c2fda30b81a583dbaf8a1e043cd76", + "trackedPatchSha256": "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b", "additionalFiles": { "src/bundler/input_source_map.rs": "6afe1551ae56d44dfa6abccc89668cd582db68c79f65acf692abba457f678cbf", "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", @@ -25,9 +25,19 @@ "src/runtime/bake/dev_server/incremental_graph.rs": "59d319121c7d7a42760e0e0e4df08303e8c08bc885c70b2d487d980ebaf85a9c", "src/runtime/bake/dev_server/finalize.rs": "8bbc23a6df4e8444a4e6f71c1ef693c6b2445ee4ac5ad8e01139f2f627b89578", "src/runtime/bake/dev_server/render.rs": "2fa45a019c3b96d387f5419945f49aeead30f496d57368c64362cf426958bc15", - "src/runtime/bake/hmr-module.ts": "9fdb9e89a356a8631a8a99411db16066e62b017f594be7711127bb0ba3151773", + "src/runtime/bake/hmr-module.ts": "20660b5fefeb174dbefc832d429d93d7bc5859ea9458fc75b8b82f89410092ae", "src/runtime/bake/hmr-runtime-client.ts": "16fa1b0f4f5ed13a2f4e22e8a7059772f0cb1bee22cbb65ef535874b2d76f701", - "test/bake/dev/bundle.test.ts": "48a984dbdd53ded01bda8a1cc73de5756c745dfccf232af6b6cd75772ec07dfa" + "test/bake/dev/bundle.test.ts": "48a984dbdd53ded01bda8a1cc73de5756c745dfccf232af6b6cd75772ec07dfa", + "src/runtime/bake/dev_server/watcher_atomics.rs": "3efecf6b04601cbcf501df3304c30910c491bf03bce047d5707d318444256bd9", + "test/bake/dev/hot.test.ts": "8eb189558672bda096f54b957f0455656c04397f0c72a7cf50414666d2a935d6" }, - "windowsBinarySha256": "1de0e1882f6097fdb06baa9994aa07c8a1556971a26f2d4c0c457659d23cc02b" + "windowsBinarySha256": "56c24634993f1452d949924405ed06000530a9317c36c93a89fee3566beada85", + "changesSinceV12": [ + "Reclaim pending watcher events before collecting later batches", + "Preserve atomic plugin dependency events and rearm their file watches", + "Invalidate every affected HMR module before evaluating importers", + "Snapshot old accept callbacks and wait for asynchronous dependencies", + "Dispose shared accepting boundaries once per update", + "Six public regressions: two native watch cases and four client HMR cases" + ] } diff --git a/.github/native-bun-validation/native-v15-tracked.patch.gz b/.github/native-bun-validation/native-v15-tracked.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..5d9d00c1cbadd615bfd5ce66bb92699205504ec4 GIT binary patch literal 91550 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 N`T`U%tl?DI1pwbrT3P@A literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py index 53e07c8b61e..9f6a56d3be7 100644 --- a/.github/native-bun-validation/prepare.py +++ b/.github/native-bun-validation/prepare.py @@ -10,7 +10,7 @@ BASE = "dca7d25e95cca39316c659a377dba6803805549f" -PATCH_HASH = "d4d09320680f3602c018b157fd5bbb595f9c2fda30b81a583dbaf8a1e043cd76" +PATCH_HASH = "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b" ADDITIONAL = { "src/bundler/input_source_map.rs", "src/runtime/bake/dev_server/plugin_watch_store.rs", @@ -45,11 +45,11 @@ def main(): parser.add_argument("--check-assets-only", action="store_true") args = parser.parse_args() data = Path(__file__).resolve().parent - manifest = json.loads((data / "native-v12-manifest.json").read_text()) + manifest = json.loads((data / "native-v15-manifest.json").read_text()) assert manifest["head"] == BASE assert manifest["trackedPatchSha256"] == PATCH_HASH assert set(manifest["additionalFiles"]) == ADDITIONAL - patch = gzip.decompress((data / "native-v12-tracked.patch.gz").read_bytes()) + patch = gzip.decompress((data / "native-v15-tracked.patch.gz").read_bytes()) assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) assert paths, "No tracked patch paths" @@ -59,7 +59,7 @@ def main(): tracked.append(old.decode()) extra = {} archive = gzip.decompress( - (data / "native-v12-additional-files.tar.gz").read_bytes() + (data / "native-v15-additional-files.tar.gz").read_bytes() ) with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: for member in bundle.getmembers(): @@ -96,7 +96,7 @@ def main(): with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: for name in sorted(set(tracked) | ADDITIONAL): bundle.add(bun / name, arcname=name) - (out / "native-v12-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") + (out / "native-v15-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") (out / "tracked.patch").write_bytes(patch) for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: (out / name).write_bytes((bun / name).read_bytes()) diff --git a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs new file mode 100644 index 00000000000..a8f22394fd3 --- /dev/null +++ b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs @@ -0,0 +1,360 @@ +import assert from 'node:assert/strict' +import { spawn, execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { watch } from 'node:fs' +import { + mkdtemp, + mkdir, + readFile, + realpath, + writeFile, + rm, +} from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { setTimeout as batchInterval } from 'node:timers/promises' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +const binary = process.env.BUN_EXECUTABLE +assert.ok(binary, 'Set BUN_EXECUTABLE') +const output = + process.env.PENDING_BATCH_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/pure-bun-pending-batches-${process.platform}.json`, + ) +await mkdir(path.dirname(output), { recursive: true }) +const { chromium, expect } = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +)('@playwright/test') +const directory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pending-batches-')), +) +const controlDirectory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pending-control-')), +) +const releaseFile = path.join(controlDirectory, 'release') +const blockThread = process.env.PENDING_BATCH_BLOCK !== '0' +const nativeSync = process.env.PENDING_BATCH_NATIVE_SYNC === '1' +const captureHmr = process.env.PENDING_BATCH_CAPTURE_HMR === '1' +const tracePath = process.env.BUN_WATCHER_TRACE +if (nativeSync) { + assert.ok(tracePath, 'Native batch synchronization needs BUN_WATCHER_TRACE') +} +const result = { + binary, + blockThread, + nativeSync, + tracePath, + binarySha256: createHash('sha256') + .update(await readFile(binary)) + .digest('hex'), + revision: execFileSync(binary, ['--revision'], { encoding: 'utf8' }).trim(), + directory, + controlDirectory, + passed: false, + writes: [], + nativeBatches: [], + ipc: [], + browserErrors: [], + documentLoads: 0, +} +let child, + browser, + context, + logs = '', + page +const assetCaptures = [] +const snapshot = async () => ({ + text: await page.locator('#app').textContent(), + documentToken: await page.evaluate(() => globalThis.documentToken), + documentLoads: result.documentLoads, +}) +const waitNativeBatch = async (name) => { + const wanted = path.join(directory, name + '.ts').replaceAll('\\', '/') + let observer, timer + try { + const event = await new Promise((resolve, reject) => { + const check = async () => { + try { + const text = await readFile(tracePath, 'utf8') + for (const line of text + .slice(0, text.lastIndexOf('\n') + 1) + .split('\n') + .filter(Boolean)) { + const batch = JSON.parse(line) + const entry = Object.entries(batch.files).find( + ([filename]) => filename.replaceAll('\\', '/') === wanted, + ) + if (entry) { + resolve({ + name, + timestamp: batch.timestamp, + path: entry[0], + ...entry[1], + }) + return + } + } + } catch (error) { + if (error.code !== 'ENOENT') { + reject(error) + } + } + } + observer = watch(path.dirname(tracePath), (event, filename) => { + if (String(filename) === path.basename(tracePath)) { + void check() + } + }) + timer = setTimeout( + () => reject(new Error('Native watcher batch deadline for ' + name)), + 15000, + ) + void check() + }) + result.nativeBatches.push(event) + } finally { + observer?.close() + clearTimeout(timer) + } +} +try { + await writeFile( + path.join(directory, 'index.html'), + `

`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {a} from './a.ts';import {b} from './b.ts';import {c} from './c.ts';document.querySelector('#app').textContent=[a,b,c].join('|');if(import.meta.hot)import.meta.hot.accept();`, + ) + for (const name of ['a', 'b', 'c']) { + await writeFile( + path.join(directory, name + '.ts'), + `export const ${name}='${name.toUpperCase()}0';\n`, + ) + } + await writeFile( + path.join(directory, 'server.ts'), + ` + import html from './index.html';import {existsSync} from 'node:fs'; + const releaseFile=${JSON.stringify(releaseFile)}; + process.on('message',message=>{ + if(message==='block'){ + process.send({phase:'blocked',time:Date.now()}); + const deadline=Date.now()+15000; + while(!existsSync(releaseFile)){if(Date.now()>deadline){throw new Error('External release deadline exceeded')}} + process.send({phase:'released',time:Date.now()}); + } + }); + const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}}); + process.send({phase:'ready',url:server.url.href,pid:process.pid}); + `, + ) + let readyResolve, readyReject, blockedResolve, releasedResolve + const ready = new Promise((resolve, reject) => { + readyResolve = resolve + readyReject = reject + }) + const blocked = new Promise((resolve) => { + blockedResolve = resolve + }) + const released = new Promise((resolve) => { + releasedResolve = resolve + }) + child = spawn(binary, ['server.ts'], { + cwd: directory, + env: { ...process.env, NODE_ENV: 'development' }, + stdio: ['ignore', 'pipe', 'pipe', 'ipc'], + windowsHide: true, + }) + child.on('error', readyReject) + child.on('exit', (code, signal) => + readyReject(new Error(`Server exited ${code}/${signal}: ${logs}`)), + ) + child.stdout.on('data', (chunk) => { + logs += chunk + }) + child.stderr.on('data', (chunk) => { + logs += chunk + }) + child.on('message', (message) => { + result.ipc.push(message) + if (message.phase === 'ready') { + readyResolve(message) + } + if (message.phase === 'blocked') { + blockedResolve(message) + } + if (message.phase === 'released') { + releasedResolve(message) + } + }) + const deadline = async (promise, label) => { + let timer + return Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout( + () => reject(new Error(`${label} deadline: ${logs}`)), + 20000, + ) + }), + ]).finally(() => clearTimeout(timer)) + } + const info = await deadline(ready, 'Startup') + result.pid = info.pid + browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), + }) + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.documentToken = crypto.randomUUID() + }) + page = await context.newPage() + if (captureHmr) { + result.websocketFrames = [] + result.initialJavaScript = [] + const session = await context.newCDPSession(page) + await session.send('Network.enable') + session.on('Network.webSocketFrameReceived', (event) => { + const { opcode, payloadData } = event.response + const bytes = Buffer.from(payloadData, opcode === 2 ? 'base64' : 'utf8') + const decoded = bytes.toString('utf8') + const frame = { + requestId: event.requestId, + timestamp: event.timestamp, + opcode, + bytes: bytes.length, + base64: bytes.toString('base64'), + } + result.websocketFrames.push(frame) + if (decoded.includes('self[Symbol.for("bun:hmr")]')) { + frame.file = output.replace( + /\.json$/, + `-hmr${result.websocketFrames.length}.txt`, + ) + assetCaptures.push(writeFile(frame.file, decoded)) + } + }) + page.on('response', (response) => { + if (!new URL(response.url()).pathname.endsWith('.js')) { + return + } + const asset = { + url: response.url(), + file: output.replace( + /\.json$/, + `-initial${result.initialJavaScript.length}.js`, + ), + } + result.initialJavaScript.push(asset) + assetCaptures.push( + response + .text() + .then((text) => writeFile(asset.file, text)) + .catch((error) => { + asset.error = String(error) + }), + ) + }) + } + page.on('load', () => { + result.documentLoads++ + }) + page.on('console', (message) => { + if (message.type() === 'error') { + result.browserErrors.push({ type: 'console', text: message.text() }) + } + }) + page.on('pageerror', (error) => + result.browserErrors.push({ type: 'pageerror', text: error.message }), + ) + await page.goto(info.url) + await expect(page.locator('#app')).toHaveText('A0|B0|C0') + result.before = await snapshot() + if (blockThread) { + child.send('block') + await deadline(blocked, 'IPC block') + } + for (const name of ['a', 'b', 'c']) { + const started = Date.now(), + contents = `export const ${name}='${name.toUpperCase()}1';\n` + await writeFile(path.join(directory, name + '.ts'), contents) + result.writes.push({ name, started, finished: Date.now(), contents }) + if (nativeSync) { + await waitNativeBatch(name) + } else { + await batchInterval(150) + } + } + if (blockThread) { + await writeFile(releaseFile, 'release\n') + await deadline(released, 'IPC release') + } + try { + await expect(page.locator('#app')).toHaveText('A1|B1|C1', { timeout: 5000 }) + } finally { + result.after = await snapshot() + } + assert.equal( + result.after.documentToken, + result.before.documentToken, + 'Updates must retain the document', + ) + assert.equal(result.documentLoads, 1) + assert.deepEqual(result.browserErrors, []) + assert.deepEqual(await (await fetch(new URL('/__info', info.url))).json(), { + pid: info.pid, + }) + result.passed = true +} catch (error) { + result.error = error.stack ?? String(error) + result.moduleBytes = Object.fromEntries( + await Promise.all( + ['a', 'b', 'c'].map(async (name) => [ + name, + await readFile(path.join(directory, name + '.ts'), 'utf8'), + ]), + ), + ) + result.preservedFixture = true +} finally { + await writeFile(releaseFile, 'cleanup release\n').catch(() => {}) + await Promise.all(assetCaptures) + await context?.close() + await browser?.close() + if (child && child.exitCode === null && child.signalCode === null) { + child.kill() + await new Promise((resolve) => child.once('exit', resolve)) + } + result.serverLog = logs + if (result.passed) { + await rm(directory, { recursive: true, force: true }) + } + await rm(controlDirectory, { recursive: true, force: true }) + await writeFile(output, JSON.stringify(result, null, 2) + '\n') +} +console.log( + JSON.stringify({ + passed: result.passed, + before: result.before, + after: result.after, + writes: result.writes.map(({ name, started, finished }) => ({ + name, + started, + finished, + })), + error: result.error?.split('\n')[0], + output, + }), +) +if (!result.passed) { + process.exitCode = 1 +} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index f009dbafcb0..da8e675d3ba 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -63,7 +63,7 @@ jobs: import hashlib, json, os, subprocess from pathlib import Path binary = Path('.native-proof/binary/bun') - manifest = json.loads(Path('.github/native-bun-validation/native-v12-manifest.json').read_text()) + manifest = json.loads(Path('.github/native-bun-validation/native-v15-manifest.json').read_text()) proof = { 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), 'base': manifest['head'], @@ -181,6 +181,15 @@ jobs: PURE_BUN_SOURCE_MAPS: '1' PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-restored-maps.json run: node .github/native-bun-validation/pure-bun-graph-browser.mjs + - name: Apply every native watcher batch in the browser + id: pending_batches + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PENDING_BATCH_NATIVE_SYNC: '1' + BUN_WATCHER_TRACE: ${{ github.workspace }}/.native-browser-proof/pending-batches-watcher.jsonl + PENDING_BATCH_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pending-batches-browser.json + run: node .github/native-bun-validation/pure-bun-pending-batches-browser.mjs - name: Production builds, navigation and source maps id: production continue-on-error: true @@ -263,5 +272,6 @@ jobs: HMR_ORDER: ${{ steps.hmr_order.outcome }} RESTORED_MAPS: ${{ steps.restored_maps.outcome }} NATIVE_CHROME: ${{ steps.native_chrome.outcome }} + PENDING_BATCHES: ${{ steps.pending_batches.outcome }} run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success && "$NATIVE_CHROME" == success ]] + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success && "$NATIVE_CHROME" == success && "$PENDING_BATCHES" == success ]] From da0d5e8f9aadefd8d54fbe09f28113864d4517e5 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 14:23:43 +0200 Subject: [PATCH 21/31] test: verify external input maps with native platform artifacts --- .../native-bun-validation/artifact-tests.py | 5 +++ .../input-map-sync-test.patch | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 .github/native-bun-validation/input-map-sync-test.patch diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index b89b0aedf81..3e39ff5bd31 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -35,6 +35,9 @@ ("hmr-script-order-test.patch.gz", "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", {"test/js/bun/webview/webview-chrome.test.ts"}), + ("input-map-sync-test.patch", + "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", + {"test/bundler/bun-build-api.test.ts"}), ]: patch = (root / ".github/native-bun-validation" / name).read_bytes() if name.endswith(".gz"): @@ -74,6 +77,8 @@ ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once"), ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies with an async dependency"), ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once with an async dependency"), + ("test/bundler/bun-build-api.test.ts", "an external input source map is read synchronously"), + ("test/bundler/bun-build-api.test.ts", "an input source map named by a file: URL is composed"), ] isolated_results = [] for index, (filename, title) in enumerate(isolated): diff --git a/.github/native-bun-validation/input-map-sync-test.patch b/.github/native-bun-validation/input-map-sync-test.patch new file mode 100644 index 00000000000..55def6ae557 --- /dev/null +++ b/.github/native-bun-validation/input-map-sync-test.patch @@ -0,0 +1,37 @@ +diff --git a/test/bundler/bun-build-api.test.ts b/test/bundler/bun-build-api.test.ts +index 63574647..37ec09ad 100644 +--- a/test/bundler/bun-build-api.test.ts ++++ b/test/bundler/bun-build-api.test.ts +@@ -1133,6 +1133,32 @@ describe("Bun.build", () => { + ]); + }); + ++ test.concurrent("an external input source map is read synchronously", async () => { ++ const original = 'console.log("authored");\n'; ++ using dir = tempDir("build-api-external-input-map", { ++ "compiled.js": 'console.log("mapped");\n//# sourceMappingURL=compiled.js.map\n', ++ "compiled.js.map": JSON.stringify({ ++ version: 3, ++ sources: ["original.ts"], ++ sourcesContent: [original], ++ names: [], ++ mappings: "AAAA", ++ }), ++ }); ++ const root = String(dir); ++ const build = await Bun.build({ ++ entrypoints: [join(root, "compiled.js")], ++ target: "browser", ++ sourcemap: "external", ++ outdir: join(root, "out"), ++ }); ++ expect(build.logs).toEqual([]); ++ expect(build.success).toBe(true); ++ const output = JSON.parse(await Bun.file(join(root, "out/compiled.js.map")).text()); ++ expect(output.sources).toEqual(["../original.ts"]); ++ expect(output.sourcesContent).toEqual([original]); ++ }); ++ + // A `file:` URL in a `sourceMappingURL` comment names the sidecar by absolute + // path. Its query is dropped, like the query of a relative sidecar path. + test.concurrent("an input source map named by a file: URL is composed", async () => { From 20aa9225e08f845543fc63e7b29362cc65f39c11 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 14:24:13 +0200 Subject: [PATCH 22/31] test: preserve sidecar patch context in compressed artifact --- .../native-bun-validation/artifact-tests.py | 2 +- .../input-map-sync-test.patch | 37 ------------------ .../input-map-sync-test.patch.gz | Bin 0 -> 685 bytes 3 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 .github/native-bun-validation/input-map-sync-test.patch create mode 100644 .github/native-bun-validation/input-map-sync-test.patch.gz diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index 3e39ff5bd31..188d06c38ea 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -35,7 +35,7 @@ ("hmr-script-order-test.patch.gz", "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", {"test/js/bun/webview/webview-chrome.test.ts"}), - ("input-map-sync-test.patch", + ("input-map-sync-test.patch.gz", "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", {"test/bundler/bun-build-api.test.ts"}), ]: diff --git a/.github/native-bun-validation/input-map-sync-test.patch b/.github/native-bun-validation/input-map-sync-test.patch deleted file mode 100644 index 55def6ae557..00000000000 --- a/.github/native-bun-validation/input-map-sync-test.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/test/bundler/bun-build-api.test.ts b/test/bundler/bun-build-api.test.ts -index 63574647..37ec09ad 100644 ---- a/test/bundler/bun-build-api.test.ts -+++ b/test/bundler/bun-build-api.test.ts -@@ -1133,6 +1133,32 @@ describe("Bun.build", () => { - ]); - }); - -+ test.concurrent("an external input source map is read synchronously", async () => { -+ const original = 'console.log("authored");\n'; -+ using dir = tempDir("build-api-external-input-map", { -+ "compiled.js": 'console.log("mapped");\n//# sourceMappingURL=compiled.js.map\n', -+ "compiled.js.map": JSON.stringify({ -+ version: 3, -+ sources: ["original.ts"], -+ sourcesContent: [original], -+ names: [], -+ mappings: "AAAA", -+ }), -+ }); -+ const root = String(dir); -+ const build = await Bun.build({ -+ entrypoints: [join(root, "compiled.js")], -+ target: "browser", -+ sourcemap: "external", -+ outdir: join(root, "out"), -+ }); -+ expect(build.logs).toEqual([]); -+ expect(build.success).toBe(true); -+ const output = JSON.parse(await Bun.file(join(root, "out/compiled.js.map")).text()); -+ expect(output.sources).toEqual(["../original.ts"]); -+ expect(output.sourcesContent).toEqual([original]); -+ }); -+ - // A `file:` URL in a `sourceMappingURL` comment names the sidecar by absolute - // path. Its query is dropped, like the query of a relative sidecar path. - test.concurrent("an input source map named by a file: URL is composed", async () => { diff --git a/.github/native-bun-validation/input-map-sync-test.patch.gz b/.github/native-bun-validation/input-map-sync-test.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..9b996c641ce6787a8f6d950a96c75ad40b93ed87 GIT binary patch literal 685 zcmV;e0#f}SiwFP!00002|BY13PTN2f-RCQ=+y%B0+t8#z4N3*HT~PHQ6?H|CGPZA$ zq4tcK2M|^Kd+&^s*hx@@H)Gw$Ip;oR3O=7h951*5mKxM1&8#R&RPKy3%gZ8WHBX!? zF&eU01ogNm@CnAlcc-KA=rl=&rj)xb3or-LzFC*_jf_P2>*v>LCpV#3k~DY;*ZBzh%k_`%i8hLo`Fs^_B>+62(p-uO z31a^Z2t2|2ARy8${Ik=!N*t(vh^{*RsXCg{U zL+!ox>O<=FuG@E;{Opm@9oeo?TO-L+t6FkloRmBI2_58MxBpSA(J-|@Dk;d6eAK8~ ziA~W|0Xa9bZN1VOQa6Dv1=)gwy6~yS+=O1Io3@S;BR}6;R)#mXF9vCwQ?q^CC5A>> z+-(BUxW%6~gRYs<7`6?WQ<34Gs&s!zA_AwH!e~!G1D&kr-BB7ONxHKg|4m#kN+*B2 zFioECj=Sk;3KuYQnkO@$Ri{f03}*W`U`C}^6+t#z24;z%d4V}okgb4abeF8bHDb-o zGJz|4Anz@zm3tQoCEXPpK*|50Pj6guPIL-OX81!3=>Z(rOYhIYv*RQcUIzF=nmV+T TTuY6`!3*>cppU-!=LG-&_YXl) literal 0 HcmV?d00001 From 3681c83c7bbb908c1faedb370cce8218d55ff064 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 14:38:47 +0200 Subject: [PATCH 23/31] test: remove temporary native Bun validation harness --- .../native-bun-validation/artifact-tests.py | 136 ----- .../native-bun-validation/browser-setup.mjs | 64 --- .github/native-bun-validation/build-macos.sh | 56 -- .github/native-bun-validation/chrome-test.py | 33 -- .../combined-generator.mjs | 228 -------- .../helper-browser-preload.mjs | 21 - .../native-bun-validation/helper-browser.mjs | 279 --------- .../helper-import-preload.mjs | 13 - .../hmr-script-order-test.patch.gz | Bin 2287 -> 0 bytes .../input-map-sync-test.patch.gz | Bin 685 -> 0 bytes .../mac-quiet-watch-tests.patch | 30 - .../native-v15-additional-files.tar.gz | Bin 10601 -> 0 bytes .../native-v15-manifest.json | 43 -- .../native-v15-tracked.patch.gz | Bin 91550 -> 0 bytes .../path-identity-probe.ts | 63 -- .github/native-bun-validation/prepare.py | 106 ---- .../pure-bun-graph-browser.mjs | 538 ------------------ .../pure-bun-pending-batches-browser.mjs | 360 ------------ .../require-tests-reporter.mjs | 29 - .github/workflows/bun-native-validation.yml | 277 --------- 20 files changed, 2276 deletions(-) delete mode 100644 .github/native-bun-validation/artifact-tests.py delete mode 100644 .github/native-bun-validation/browser-setup.mjs delete mode 100644 .github/native-bun-validation/build-macos.sh delete mode 100644 .github/native-bun-validation/chrome-test.py delete mode 100644 .github/native-bun-validation/combined-generator.mjs delete mode 100644 .github/native-bun-validation/helper-browser-preload.mjs delete mode 100644 .github/native-bun-validation/helper-browser.mjs delete mode 100644 .github/native-bun-validation/helper-import-preload.mjs delete mode 100644 .github/native-bun-validation/hmr-script-order-test.patch.gz delete mode 100644 .github/native-bun-validation/input-map-sync-test.patch.gz delete mode 100644 .github/native-bun-validation/mac-quiet-watch-tests.patch delete mode 100644 .github/native-bun-validation/native-v15-additional-files.tar.gz delete mode 100644 .github/native-bun-validation/native-v15-manifest.json delete mode 100644 .github/native-bun-validation/native-v15-tracked.patch.gz delete mode 100644 .github/native-bun-validation/path-identity-probe.ts delete mode 100644 .github/native-bun-validation/prepare.py delete mode 100644 .github/native-bun-validation/pure-bun-graph-browser.mjs delete mode 100644 .github/native-bun-validation/pure-bun-pending-batches-browser.mjs delete mode 100644 .github/native-bun-validation/require-tests-reporter.mjs delete mode 100644 .github/workflows/bun-native-validation.yml diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py deleted file mode 100644 index 188d06c38ea..00000000000 --- a/.github/native-bun-validation/artifact-tests.py +++ /dev/null @@ -1,136 +0,0 @@ -import gzip -import hashlib -import json -import os -from pathlib import Path -import re -import subprocess -import xml.etree.ElementTree as ET - - -root = Path(os.environ["GITHUB_WORKSPACE"]) -binary = root / ".native-artifact/binary/bun" -proof = root / ".native-browser-proof" -proof.mkdir(exist_ok=True) -expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -manifest = json.loads((root / ".github/native-bun-validation/native-v15-manifest.json").read_text()) -assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] -assert expected["base"] == manifest["head"] -assert expected["patchSha256"] == manifest["trackedPatchSha256"] -assert expected["additionalFiles"] == manifest["additionalFiles"] -binary.chmod(0o755) -source = root / ".cache/native-bun-validation/test-source" -subprocess.run([ - "python3", str(root / ".github/native-bun-validation/prepare.py"), - "--bun", str(source), "--out", str(proof / "native-source"), -], check=True) -overrides = proof / "native-test-overrides" -overrides.mkdir(exist_ok=True) -adjusted_sources = {} -patches = {} -for name, digest, allowed_paths in [ - ("mac-quiet-watch-tests.patch", - "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062", - {"test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts"}), - ("hmr-script-order-test.patch.gz", - "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", - {"test/js/bun/webview/webview-chrome.test.ts"}), - ("input-map-sync-test.patch.gz", - "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", - {"test/bundler/bun-build-api.test.ts"}), -]: - patch = (root / ".github/native-bun-validation" / name).read_bytes() - if name.endswith(".gz"): - patch = gzip.decompress(patch) - assert hashlib.sha256(patch).hexdigest() == digest - paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) - assert all(old == new for old, new in paths) - assert {old.decode() for old, _ in paths} == allowed_paths - subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) - subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) - (overrides / name.removesuffix(".gz")).write_bytes(patch) - patches[name] = digest - for old, _ in paths: - filename = old.decode() - contents = (source / filename).read_bytes() - adjusted_sources[filename] = hashlib.sha256(contents).hexdigest() - target = overrides / filename - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(contents) -(overrides / "proof.json").write_text(json.dumps({ - "binaryRuntimeUnchanged": True, - "testOnlyPatchSha256": patches, - "adjustedSourceSha256": adjusted_sources, -}, indent=2) + "\n") -for cwd in [source, source / "test"]: - subprocess.run([str(binary), "install", "--frozen-lockfile"], cwd=cwd, check=True) -tests = manifest["testCommand"].split(" test ", 1)[1].split() -assert len(tests) == 9 -isolated = [ - ("test/bake/dev/plugins.test.ts", "watchDirs preserves browser state when only a child file's contents change"), - ("test/bake/dev/plugins.test.ts", "watchDirs shares directory events with imported files and trailing-slash aliases"), - ("test/bake/dev/client-plugin-cache.test.ts", "client plugin cache probe: structural dependency update serves the current manifest"), - ("test/bake/dev/server-sourcemap.test.ts", "server-side source maps handle nested imports"), - ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy"), - ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy with an atomic plugin dependency"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies with an async dependency"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once with an async dependency"), - ("test/bundler/bun-build-api.test.ts", "an external input source map is read synchronously"), - ("test/bundler/bun-build-api.test.ts", "an input source map named by a file: URL is composed"), -] -isolated_results = [] -for index, (filename, title) in enumerate(isolated): - isolated_report = proof / f"native-isolated-{index}.xml" - run = subprocess.run([ - str(binary), "test", filename, "-t", re.escape(title) + "$", - "--reporter=junit", f"--reporter-outfile={isolated_report}", - ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={ - **os.environ, - "BUN_DEV_SERVER_VERBOSE_SYNC": "1", - "BUN_WATCHER_TRACE": str(proof / f"native-isolated-{index}-watcher.jsonl"), - }) - (proof / f"native-isolated-{index}.log").write_text(run.stdout) - all_cases = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] - selected = [case for case in all_cases if case.attrib.get("name", "").endswith(title)] - passed = run.returncode == 0 and len(selected) == 1 and all( - not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) - for case in selected - ) and all(case.find("skipped") is not None for case in all_cases if case not in selected) - isolated_results.append({"file": filename, "title": title, "passed": passed, - "cases": len(selected), "filteredOut": len(all_cases) - len(selected)}) - print(json.dumps(isolated_results[-1])) -(proof / "native-isolated-results.json").write_text(json.dumps(isolated_results, indent=2) + "\n") -report = proof / "native-results.xml" -# Execute the verified, source-built artifact. The Bun CI build path ignores -# trailing execution arguments, so a successful build alone is not a test run. -result = subprocess.run([ - str(binary), "test", *tests, "--reporter=junit", f"--reporter-outfile={report}", -], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -(proof / "native-regressions.log").write_text(result.stdout) -print(result.stdout, end="") -cases = ET.parse(report).findall(".//testcase") -assert cases, "Native test runner executed no cases" -by_file = {filename: [] for filename in tests} -for case in cases: - filename = Path(case.attrib["file"]) - if not filename.is_absolute(): - filename = source / filename - relative = filename.resolve().relative_to(source.resolve()).as_posix() - assert relative in by_file, f"Unexpected test source: {relative}" - by_file[relative].append(case) -assert all(any(case.find("skipped") is None for case in group) for group in by_file.values()), \ - "Every selected native test file must execute a non-skipped case" -summary = { - "binarySha256": expected["sha256"], "selectedFiles": tests, - "cases": len(cases), - "skipped": sum(case.find("skipped") is not None for case in cases), - "failed": sum(case.find("failure") is not None or case.find("error") is not None for case in cases), - "perFile": {filename: len(group) for filename, group in by_file.items()}, -} -(proof / "native-results.json").write_text(json.dumps(summary, indent=2) + "\n") -print(json.dumps(summary, indent=2)) -result.check_returncode() -assert summary["failed"] == 0 -assert all(run["passed"] for run in isolated_results) diff --git a/.github/native-bun-validation/browser-setup.mjs b/.github/native-bun-validation/browser-setup.mjs deleted file mode 100644 index c68480e2d0d..00000000000 --- a/.github/native-bun-validation/browser-setup.mjs +++ /dev/null @@ -1,64 +0,0 @@ -import { mkdir, readFile, writeFile, chmod } from 'node:fs/promises' -import { createHash } from 'node:crypto' -import { execFileSync } from 'node:child_process' -import path from 'node:path' -import { pathToFileURL } from 'node:url' - -const repo = process.env.GITHUB_WORKSPACE -const binary = path.join(repo, '.native-artifact/binary/bun') -const proof = path.join(repo, '.native-browser-proof') -const cache = path.join(repo, 'packages/router-plugin/.cache/native-validation') -const preload = path.join(cache, 'preload.ts') -const upstream = path.join(repo, '.native-unplugin/dist/index.mjs') -const wrapper = path.join(cache, 'bin/bun') -await mkdir(path.dirname(wrapper), { recursive: true }) -await mkdir(proof, { recursive: true }) -await chmod(binary, 0o755) -const hash = createHash('sha256') - .update(await readFile(binary)) - .digest('hex') -const expected = JSON.parse( - await readFile(path.join(repo, '.native-artifact/binary-proof.json'), 'utf8'), -) -if (hash !== expected.sha256) { - throw new Error('Downloaded native Bun binary hash mismatch') -} -// Bun resolves this mock beside router-plugin's installed unplugin dependency. -await writeFile( - preload, - `import { mock } from 'bun:test'\nimport * as upstream from ${JSON.stringify(pathToFileURL(upstream).href)}\nmock.module('unplugin', () => upstream)\n`, -) -const quote = (value) => `'${value.replaceAll("'", "'\\''")}'` -await writeFile( - wrapper, - `#!/bin/sh\nexec ${quote(binary)} --preload ${quote(preload)} "$@"\n`, -) -await chmod(wrapper, 0o755) -const versions = { - routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { - cwd: repo, - encoding: 'utf8', - }).trim(), - unpluginHead: execFileSync('git', ['rev-parse', 'HEAD'], { - cwd: path.dirname(path.dirname(upstream)), - encoding: 'utf8', - }).trim(), - node: process.version, - bun: execFileSync(binary, ['--version'], { encoding: 'utf8' }).trim(), - binarySha256: hash, - nativeSource: expected, -} -await writeFile( - path.join(proof, 'versions.json'), - JSON.stringify(versions, null, 2) + '\n', -) -await writeFile(path.join(proof, 'preload.ts'), await readFile(preload)) -await writeFile( - process.env.GITHUB_ENV, - `BUN_EXECUTABLE=${binary}\nBUN_PLUGIN_PRELOAD=${preload}\nBUN_DEV_TEST_OUTPUT=${proof}/dev-results\n`, - { flag: 'a' }, -) -await writeFile(process.env.GITHUB_PATH, path.dirname(wrapper) + '\n', { - flag: 'a', -}) -console.log(JSON.stringify(versions, null, 2)) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh deleted file mode 100644 index e6dadf39d3c..00000000000 --- a/.github/native-bun-validation/build-macos.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -repo="$GITHUB_WORKSPACE" -proof="$repo/.native-proof" -mkdir -p "$proof" -{ - date -u - sw_vers - uname -a - sysctl hw.memsize hw.ncpu - df -h - xcodebuild -version - xcrun --show-sdk-path - node --version - bun --version - python3 --version - brew --version -} | tee "$proof/preflight.log" - -python3 "$repo/.github/native-bun-validation/prepare.py" \ - --bun "$repo/.native-bun" --out "$proof" | tee "$proof/source-verification.json" - -# CONTRIBUTING.md's macOS prerequisites, plus its required LLVM major. -brew update -brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm -export PATH="$(brew --prefix llvm)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" -export RUSTUP_TOOLCHAIN=nightly-2026-09-15 -export CARGO_BUILD_JOBS=1 -export CARGO_INCREMENTAL=0 -if ! command -v rustup >/dev/null; then - rustup-init -y --no-modify-path --profile minimal --default-toolchain none -fi -rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component rust-src -llvm_version="$(llvm-config --version)" -[[ "$llvm_version" =~ ^23\.1\.[0-9]+$ ]] || { echo "Expected LLVM 23.1.x, got $llvm_version"; exit 1; } -{ - brew list --versions - clang --version - llvm-config --version - rustc -vV - cargo --version - rustup show - cmake --version - ninja --version - ccache --version - df -h -} | tee "$proof/toolchain.log" - -cd "$repo/.native-bun" -bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" -bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" - -# The CI build wrapper does not execute trailing arguments. Regressions run -# against the verified binary in the artifact validation job. -GITHUB_SHA="$(git rev-parse HEAD)" bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py deleted file mode 100644 index 7f63e6e27fd..00000000000 --- a/.github/native-bun-validation/chrome-test.py +++ /dev/null @@ -1,33 +0,0 @@ -import hashlib -import json -import os -from pathlib import Path -import subprocess -import xml.etree.ElementTree as ET - - -root = Path(os.environ["GITHUB_WORKSPACE"]) -binary = root / ".native-artifact/binary/bun" -proof = root / ".native-browser-proof" -source = root / ".cache/native-bun-validation/test-source" -expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] -report = proof / "native-chrome.xml" -title = "HMR applies a large update before the following small update" -result = subprocess.run([ - str(binary), "test", "test/js/bun/webview/webview-chrome.test.ts", "-t", title, - "--reporter=junit", f"--reporter-outfile={report}", -], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -(proof / "native-chrome.log").write_text(result.stdout) -print(result.stdout, end="") -all_cases = ET.parse(report).findall(".//testcase") if report.exists() else [] -cases = [case for case in all_cases if case.attrib.get("name", "") == title] -passed = result.returncode == 0 and len(cases) == 1 and all( - not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) - for case in cases -) and all(case.find("skipped") is not None for case in all_cases if case not in cases) -(proof / "native-chrome.json").write_text(json.dumps({ - "binarySha256": expected["sha256"], "title": title, - "cases": len(cases), "filteredOut": len(all_cases) - len(cases), "passed": passed, -}, indent=2) + "\n") -assert passed, "Native Chromium ordering regression must execute and pass" diff --git a/.github/native-bun-validation/combined-generator.mjs b/.github/native-bun-validation/combined-generator.mjs deleted file mode 100644 index 6e86bd96879..00000000000 --- a/.github/native-bun-validation/combined-generator.mjs +++ /dev/null @@ -1,228 +0,0 @@ -import { - mkdtemp, - mkdir, - readFile, - realpath, - rename, - rm, - writeFile, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { - Generator, - getConfig, -} from '../../packages/router-generator/dist/esm/index.js' - -const normalize = (filename) => path.resolve(filename).replaceAll('\\', '/') -const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => - [1, 2].map((depth) => ({ ext, depth, dynamic: false })), -) -cases.push({ ext: 'mjs', depth: 2, dynamic: true }) -const results = [] -const routeNames = ['before', 'after', 'replacement'] -const configSource = (file, dynamic) => - file.endsWith('.cjs') - ? `const routes = require(${JSON.stringify(file)}); export default routes\n` - : dynamic - ? `export default (await import(${JSON.stringify(file)})).default\n` - : `import routes from ${JSON.stringify(file)}; export default routes\n` -const routeConfig = (name) => ({ - type: 'root', - file: '__root.tsx', - children: [{ type: 'route', path: `/${name}`, file: `${name}.tsx` }], -}) -const helperSource = (ext, name) => - ext === 'json' - ? JSON.stringify(routeConfig(name)) - : ext === 'cjs' - ? `module.exports = ${JSON.stringify(routeConfig(name))}\n` - : `export default ${JSON.stringify(routeConfig(name))}\n` - -for (const scenario of cases) { - const root = await realpath( - await mkdtemp(path.join(tmpdir(), 'router-built-helper-')), - ) - const checks = [] - const record = (name, passed, details = undefined) => - checks.push({ name, passed, details }) - try { - const projects = [] - for (const id of ['a', 'b']) { - const project = path.join(root, id) - const routes = path.join(project, 'routes') - await mkdir(routes, { recursive: true }) - await writeFile(path.join(project, 'package.json'), '{"type":"module"}\n') - await writeFile( - path.join(routes, '__root.tsx'), - `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, - ) - for (const suffix of routeNames) { - const name = `${id}-${suffix}` - await writeFile( - path.join(routes, `${name}.tsx`), - `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/${name}')({})\n`, - ) - } - const filename = path.join(project, `helper.${scenario.ext}`) - const configFile = path.join(project, 'virtual-routes.ts') - const bridge = path.join(project, 'bridge.ts') - await writeFile(filename, helperSource(scenario.ext, `${id}-before`)) - await writeFile( - configFile, - configSource( - scenario.depth === 2 ? './bridge.ts' : `./helper.${scenario.ext}`, - false, - ), - ) - if (scenario.depth === 2) { - await writeFile( - bridge, - configSource(`./helper.${scenario.ext}`, scenario.dynamic), - ) - } - const generatedRouteTree = path.join(project, 'routeTree.gen.ts') - const generator = new Generator({ - root: project, - config: getConfig( - { - routesDirectory: routes, - generatedRouteTree, - virtualRouteConfig: 'virtual-routes.ts', - tmpDir: path.join(project, 'tmp'), - disableLogging: true, - }, - project, - ), - }) - projects.push({ - id, - project, - filename, - configFile, - bridge, - generatedRouteTree, - generator, - }) - } - const [a, b] = projects - await Promise.all(projects.map((project) => project.generator.run())) - const expectedFiles = (project) => - [ - project.configFile, - ...(scenario.depth === 2 ? [project.bridge] : []), - project.filename, - ] - .map(normalize) - .sort() - for (const project of projects) { - const deps = project.generator - .getWatchDependencies() - .files.map(normalize) - .sort() - record( - `${project.id}:watch-dependencies`, - JSON.stringify(deps) === JSON.stringify(expectedFiles(project)), - { - expected: expectedFiles(project).map((filename) => - path.relative(root, filename), - ), - actual: deps.map((filename) => path.relative(root, filename)), - }, - ) - record( - `${project.id}:initial-tree`, - (await readFile(project.generatedRouteTree, 'utf8')).includes( - `'/${project.id}-before'`, - ), - ) - } - const initialB = await readFile(b.generatedRouteTree, 'utf8') - const stableA = await readFile(a.generatedRouteTree, 'utf8') - await a.generator.run() - record( - 'a:unchanged-generation', - (await readFile(a.generatedRouteTree, 'utf8')) === stableA, - ) - await writeFile(a.filename, helperSource(scenario.ext, 'a-after')) - await a.generator.run({ path: a.filename, type: 'update' }) - const eventTree = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:in-place-update-event', - eventTree.includes("'/a-after'") && !eventTree.includes("'/a-before'"), - ) - await a.generator.run() - const rerunTree = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:in-place-unconditional-rerun', - rerunTree.includes("'/a-after'") && !rerunTree.includes("'/a-before'"), - ) - record( - 'b:unchanged-after-a-edit', - (await readFile(b.generatedRouteTree, 'utf8')) === initialB, - ) - await writeFile( - `${a.filename}.next`, - helperSource(scenario.ext, 'a-replacement'), - ) - await rename(`${a.filename}.next`, a.filename) - await a.generator.run({ path: a.filename, type: 'update' }) - const replaced = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:atomic-replacement-event', - replaced.includes("'/a-replacement'") && !replaced.includes("'/a-after'"), - ) - await writeFile(b.filename, helperSource(scenario.ext, 'b-after')) - await b.generator.run({ path: b.filename, type: 'update' }) - record( - 'b:independent-update-event', - (await readFile(b.generatedRouteTree, 'utf8')).includes("'/b-after'"), - ) - await a.generator.run() - record( - 'a:no-cross-generator-leakage', - (await readFile(a.generatedRouteTree, 'utf8')) === replaced, - ) - record( - 'watch-dependencies-remain-isolated', - projects.every((project) => { - const deps = project.generator - .getWatchDependencies() - .files.map(normalize) - return ( - JSON.stringify(deps.sort()) === JSON.stringify(expectedFiles(project)) - ) - }), - ) - } catch (error) { - record( - 'execution', - false, - error instanceof Error ? error.stack : String(error), - ) - } finally { - await rm(root, { recursive: true, force: true }) - } - results.push({ - ...scenario, - passed: checks.every((check) => check.passed), - checks, - }) -} -const report = { - runtime: { - bun: process.versions.bun ?? null, - node: process.versions.node, - platform: process.platform, - arch: process.arch, - }, - mode: process.env.JITI_COMBINED_MODE ?? 'installed', - generator: 'packages/router-generator/dist/esm/index.js', - cases: results.length, - passed: results.filter((result) => result.passed).length, - results, -} -console.log(JSON.stringify(report, null, 2)) -if (report.passed !== report.cases) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/helper-browser-preload.mjs b/.github/native-bun-validation/helper-browser-preload.mjs deleted file mode 100644 index 42abdf9a47e..00000000000 --- a/.github/native-bun-validation/helper-browser-preload.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import { fileURLToPath, pathToFileURL } from 'node:url' -import path from 'node:path' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -await import( - pathToFileURL( - path.join( - root, - 'packages/router-plugin/.cache/helper-browser-override.mjs', - ), - ).href -) -await import( - pathToFileURL( - path.join( - root, - 'packages/router-generator/.cache/helper-browser-override.mjs', - ), - ).href -) diff --git a/.github/native-bun-validation/helper-browser.mjs b/.github/native-bun-validation/helper-browser.mjs deleted file mode 100644 index e5070f698e5..00000000000 --- a/.github/native-bun-validation/helper-browser.mjs +++ /dev/null @@ -1,279 +0,0 @@ -import assert from 'node:assert/strict' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { mkdir, readFile, writeFile } from 'node:fs/promises' -import path from 'node:path' -import { fileURLToPath, pathToFileURL } from 'node:url' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -process.env.ROUTER_REPOSITORY_ROOT = root -if (!process.env.BUN_EXECUTABLE) { - throw new Error('Set BUN_EXECUTABLE to the native Bun candidate') -} -process.env.BUN_PLUGIN_PRELOAD ??= fileURLToPath( - new URL('./helper-browser-preload.mjs', import.meta.url), -) -for (const [pkg, name, env, fallback] of [ - [ - 'router-plugin', - 'unplugin', - 'UNPLUGIN_CANDIDATE_ENTRY', - '.cache/upstream-drafts/unplugin/dist/index.mjs', - ], - [ - 'router-generator', - 'jiti', - 'JITI_CANDIDATE_ENTRY', - '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', - ], -]) { - const directory = path.join(root, 'packages', pkg, '.cache') - await mkdir(directory, { recursive: true }) - await writeFile( - path.join(directory, 'helper-browser-override.mjs'), - `import { mock } from 'bun:test'\nimport { pathToFileURL } from 'node:url'\nimport path from 'node:path'\nconst entry = process.env[${JSON.stringify(env)}] ?? path.join(process.env.ROUTER_REPOSITORY_ROOT, ${JSON.stringify(fallback)})\nconst actual = await import(pathToFileURL(path.resolve(entry)).href)\nmock.module(${JSON.stringify(name)}, () => actual)\n`, - ) -} -const projectRequire = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -) -const { chromium, expect } = projectRequire('@playwright/test') -const { startDevFixture } = await import( - pathToFileURL( - path.join(root, 'e2e/react-router/bun-basic-file-based/dev-fixture.ts'), - ).href -) -const output = - process.env.HELPER_BROWSER_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/helper-browser-${process.platform}.json`, - ) -const logFile = output.replace(/\.json$/, '.log') -await mkdir(path.dirname(output), { recursive: true }) -const log = [] -const say = (message) => { - log.push(message) - console.log(message) -} -const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => - [1, 2].map((depth) => ({ ext, depth, dynamic: false })), -) -cases.push({ ext: 'mjs', depth: 2, dynamic: true }) -const results = [] -const configSource = (file, dynamic = false) => - file.endsWith('.cjs') - ? `const config = require(${JSON.stringify(file)}); export default config\n` - : dynamic - ? `export default (await import(${JSON.stringify(file)})).default\n` - : `import config from ${JSON.stringify(file)}; export default config\n` -const configValue = (included) => ({ - type: 'root', - file: '__root.tsx', - children: [ - { type: 'index', file: 'index.tsx' }, - { type: 'route', path: '/about', file: 'about.tsx' }, - { - type: 'route', - path: `/virtual-${included}`, - file: `../virtual-pages/${included}.tsx`, - }, - ], -}) -const helperSource = (ext, included) => - ext === 'json' - ? JSON.stringify(configValue(included)) - : ext === 'cjs' - ? `module.exports = ${JSON.stringify(configValue(included))}\n` - : `export default ${JSON.stringify(configValue(included))}\n` -const sha256 = async (filename) => - createHash('sha256') - .update(await readFile(filename)) - .digest('hex') -const browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), -}) -try { - for (const scenario of cases) { - const name = `${scenario.ext}-depth${scenario.depth}${scenario.dynamic ? '-dynamic' : ''}` - say(`START ${name}`) - const result = { - ...scenario, - passed: false, - steps: [], - browserErrors: [], - documentLoads: 0, - } - let native, context - try { - native = await startDevFixture({ - virtualConfigFile: true, - virtualConfigHelperDepth: 1, - }) - result.pid = native.pid - result.versions = native.versions - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.__helperBrowserDocumentToken = crypto.randomUUID() - }) - const page = await context.newPage() - page.on('load', () => { - result.documentLoads++ - }) - page.on('pageerror', (error) => - result.browserErrors.push({ - type: 'pageerror', - message: error.message, - }), - ) - page.on('console', (message) => { - if ( - message.type() === 'error' && - !message.location().url.endsWith('/favicon.ico') - ) { - result.browserErrors.push({ - type: 'console', - message: message.text(), - location: message.location(), - }) - } - }) - const heading = page.getByRole('heading') - const goHome = async () => { - await page.getByRole('link', { name: 'Home', exact: true }).click() - await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) - } - const checkpoint = async (phase, included) => { - await expect - .poll( - async () => { - native.assertAlive() - const tree = await native.tree() - return ( - tree.includes(`/virtual-${included}`) && - !tree.includes( - `/virtual-${included === 'after' ? 'before' : 'after'}`, - ) - ) - }, - { - timeout: 15000, - message: `${name} ${phase}: automatic route-tree update`, - }, - ) - .toBe(true) - await page - .getByRole('link', { name: `Virtual ${included}`, exact: true }) - .click() - await expect(heading).toHaveText(`VIRTUAL_${included.toUpperCase()}`, { - timeout: 15000, - }) - native.assertAlive() - assert.deepEqual( - await (await fetch(new URL('/__native-info', native.url))).json(), - { pid: native.pid }, - ) - result.steps.push({ - phase, - route: `/virtual-${included}`, - samePid: true, - documentToken: await page.evaluate( - () => globalThis.__helperBrowserDocumentToken, - ), - documentLoads: result.documentLoads, - browserErrorCount: result.browserErrors.length, - }) - await goHome() - } - await page.goto(native.url) - await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) - await checkpoint('ts-bootstrap', 'before') - const helper = `config/browser-helper.${scenario.ext}` - await native.save(helper, helperSource(scenario.ext, 'after')) - if (scenario.depth === 2) { - await native.save( - 'config/browser-bridge.ts', - configSource(`./browser-helper.${scenario.ext}`, scenario.dynamic), - ) - } - await native.save( - 'virtual-routes.ts.next', - configSource( - scenario.depth === 2 - ? './config/browser-bridge.ts' - : `./config/browser-helper.${scenario.ext}`, - ), - ) - await native.rename('virtual-routes.ts.next', 'virtual-routes.ts') - await checkpoint('helper-graph-loaded', 'after') - await native.save(helper, helperSource(scenario.ext, 'before')) - await checkpoint('helper-in-place-edit', 'before') - await native.save(`${helper}.next`, helperSource(scenario.ext, 'after')) - await native.rename(`${helper}.next`, helper) - await checkpoint('helper-atomic-replacement', 'after') - assert.deepEqual( - result.browserErrors, - [], - `${name}: unexpected browser errors`, - ) - const serverErrors = native - .logs() - .split(/\r?\n/) - .filter((line) => /^(?:error:|panic:|thread .* panicked)/i.test(line)) - assert.deepEqual(serverErrors, [], `${name}: unexpected server errors`) - result.passed = true - say( - `PASS ${name}: browser navigation + automatic tree updates, in-place/atomic, same PID ${native.pid}, no browser errors`, - ) - } catch (error) { - result.error = error instanceof Error ? error.stack : String(error) - result.serverLog = native?.logs().slice(-12000) - say(`FAIL ${name}: ${String(error).split('\n')[0]}`) - } finally { - try { - await context?.close() - } finally { - await native?.close() - } - } - results.push(result) - await writeFile( - output, - JSON.stringify( - { - platform: process.platform, - node: process.version, - passed: results.filter((result) => result.passed).length, - cases: cases.length, - results, - }, - null, - 2, - ) + '\n', - ) - await writeFile(logFile, log.join('\n') + '\n') - } -} finally { - await browser.close() -} -const report = { - platform: process.platform, - arch: process.arch, - node: process.version, - binary: process.env.BUN_EXECUTABLE, - binarySha256: await sha256(process.env.BUN_EXECUTABLE), - preload: process.env.BUN_PLUGIN_PRELOAD, - passed: results.filter((result) => result.passed).length, - cases: cases.length, - results, -} -await writeFile(output, JSON.stringify(report, null, 2) + '\n') -say(`RESULT ${report.passed}/${report.cases} PASS; evidence ${output}`) -await writeFile(logFile, log.join('\n') + '\n') -if (report.passed !== report.cases) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/helper-import-preload.mjs b/.github/native-bun-validation/helper-import-preload.mjs deleted file mode 100644 index d871bbce50c..00000000000 --- a/.github/native-bun-validation/helper-import-preload.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { mock } from 'bun:test' -import { fileURLToPath, pathToFileURL } from 'node:url' -import path from 'node:path' -const repository = fileURLToPath(new URL('../../../', import.meta.url)) -const candidateEntry = process.env.JITI_CANDIDATE_ENTRY - ? path.resolve(process.env.JITI_CANDIDATE_ENTRY) - : path.join( - repository, - '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', - ) -const candidate = await import(pathToFileURL(candidateEntry).href) -mock.module('jiti', () => candidate) -process.env.JITI_COMBINED_MODE = 'candidate' diff --git a/.github/native-bun-validation/hmr-script-order-test.patch.gz b/.github/native-bun-validation/hmr-script-order-test.patch.gz deleted file mode 100644 index 5999aaa0ec696de2b787ca622861edf989e7b1b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2287 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 TTuY6`!3*>cppU-!=LG-&_YXl) diff --git a/.github/native-bun-validation/mac-quiet-watch-tests.patch b/.github/native-bun-validation/mac-quiet-watch-tests.patch deleted file mode 100644 index ca9acee4348..00000000000 --- a/.github/native-bun-validation/mac-quiet-watch-tests.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/test/bake/dev/plugins.test.ts b/test/bake/dev/plugins.test.ts ---- a/test/bake/dev/plugins.test.ts -+++ b/test/bake/dev/plugins.test.ts -@@ -134,7 +134,13 @@ - await c.expectElemText("button", "Count 1"); -- await dev.write("unrelated.txt", "first"); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("unrelated.txt", "first"); -+ }); - await c.expectElemText("button", "Count 1"); -- await dev.write("unrelated.txt", "second"); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("unrelated.txt", "second"); -+ }); - await c.expectElemText("button", "Count 1"); -- await dev.write("data/a.ts", `export default "second";`); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("data/a.ts", `export default "second";`); -+ }); - await c.expectElemText("button", "Count 1"); -diff --git a/test/bake/dev/client-plugin-cache.test.ts b/test/bake/dev/client-plugin-cache.test.ts ---- a/test/bake/dev/client-plugin-cache.test.ts -+++ b/test/bake/dev/client-plugin-cache.test.ts -@@ -92,3 +92,5 @@ - await client.click("button"); -- await dev.write("data/a.ts", `export default "second";`); -+ await client.expectNoWebSocketActivity(async () => { -+ await dev.write("data/a.ts", `export default "second";`); -+ }); - await client.expectElemText("button", "Count 1"); diff --git a/.github/native-bun-validation/native-v15-additional-files.tar.gz b/.github/native-bun-validation/native-v15-additional-files.tar.gz deleted file mode 100644 index e1f2d7a78af9308a8b8164c3b28c59ff10571685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10601 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 DD=fZe diff --git a/.github/native-bun-validation/native-v15-manifest.json b/.github/native-bun-validation/native-v15-manifest.json deleted file mode 100644 index ceabee96b15..00000000000 --- a/.github/native-bun-validation/native-v15-manifest.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "candidate": "native-v15", - "head": "dca7d25e95cca39316c659a377dba6803805549f", - "trackedPatchSha256": "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b", - "additionalFiles": { - "src/bundler/input_source_map.rs": "6afe1551ae56d44dfa6abccc89668cd582db68c79f65acf692abba457f678cbf", - "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", - "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", - "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", - "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", - "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" - }, - "changesSinceV9": [ - "Windows synchronous handles for external input-map reads", - "Watched leaf-directory rename regression and explicit Windows ancestor-rename restriction" - ], - "testCommand": "bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts", - "changesSinceV10": [ - "Reachable cached client dependency closure after a fresh page load", - "Preserve loaded module identity and original source maps", - "Execute browser HMR scripts in WebSocket insertion order", - "Four public cached-closure regression cases" - ], - "changedSourceSha256": { - "src/runtime/bake/dev_server/incremental_graph.rs": "59d319121c7d7a42760e0e0e4df08303e8c08bc885c70b2d487d980ebaf85a9c", - "src/runtime/bake/dev_server/finalize.rs": "8bbc23a6df4e8444a4e6f71c1ef693c6b2445ee4ac5ad8e01139f2f627b89578", - "src/runtime/bake/dev_server/render.rs": "2fa45a019c3b96d387f5419945f49aeead30f496d57368c64362cf426958bc15", - "src/runtime/bake/hmr-module.ts": "20660b5fefeb174dbefc832d429d93d7bc5859ea9458fc75b8b82f89410092ae", - "src/runtime/bake/hmr-runtime-client.ts": "16fa1b0f4f5ed13a2f4e22e8a7059772f0cb1bee22cbb65ef535874b2d76f701", - "test/bake/dev/bundle.test.ts": "48a984dbdd53ded01bda8a1cc73de5756c745dfccf232af6b6cd75772ec07dfa", - "src/runtime/bake/dev_server/watcher_atomics.rs": "3efecf6b04601cbcf501df3304c30910c491bf03bce047d5707d318444256bd9", - "test/bake/dev/hot.test.ts": "8eb189558672bda096f54b957f0455656c04397f0c72a7cf50414666d2a935d6" - }, - "windowsBinarySha256": "56c24634993f1452d949924405ed06000530a9317c36c93a89fee3566beada85", - "changesSinceV12": [ - "Reclaim pending watcher events before collecting later batches", - "Preserve atomic plugin dependency events and rearm their file watches", - "Invalidate every affected HMR module before evaluating importers", - "Snapshot old accept callbacks and wait for asynchronous dependencies", - "Dispose shared accepting boundaries once per update", - "Six public regressions: two native watch cases and four client HMR cases" - ] -} diff --git a/.github/native-bun-validation/native-v15-tracked.patch.gz b/.github/native-bun-validation/native-v15-tracked.patch.gz deleted file mode 100644 index 5d9d00c1cbadd615bfd5ce66bb92699205504ec4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91550 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 N`T`U%tl?DI1pwbrT3P@A diff --git a/.github/native-bun-validation/path-identity-probe.ts b/.github/native-bun-validation/path-identity-probe.ts deleted file mode 100644 index 0627529087c..00000000000 --- a/.github/native-bun-validation/path-identity-probe.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { mkdtemp, mkdir, realpath, symlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { dirname, join, resolve } from 'node:path' - -// Public API diagnostic only. Preserve the tiny fixture for artifact inspection. -const base = process.env.BUN_PATH_PROBE_ROOT ?? tmpdir() -const directory = await mkdtemp(join(base, 'bun-path-identity-')) -const source = join(directory, 'source') -await mkdir(source) -await writeFile(join(source, 'entry.ts'), 'export const value = 42;\n') -const alias = join(directory, 'alias') -await symlink(source, alias, process.platform === 'win32' ? 'junction' : 'dir') - -const results = [] -for (const entrypoint of [join(source, 'entry.ts'), join(alias, 'entry.ts')]) { - const loads: Array<{ path: string; resolveDir: string }> = [] - let exactPathHookCalls = 0 - const exactFilter = new RegExp( - `^${entrypoint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, - ) - const result = await Bun.build({ - entrypoints: [entrypoint], - write: false, - plugins: [ - { - name: 'public-path-identity', - setup(build) { - build.onLoad({ filter: exactFilter }, () => { - exactPathHookCalls++ - }) - build.onLoad({ filter: /entry\.ts$/ }, (args) => { - loads.push({ path: args.path, resolveDir: dirname(args.path) }) - }) - }, - }, - ], - }) - results.push({ - entrypoint, - resolved: resolve(entrypoint), - realpath: await realpath(entrypoint), - exactPathHookCalls, - loads, - success: result.success, - logs: result.logs.map((log) => log.message), - }) -} -console.log( - JSON.stringify( - { - platform: process.platform, - arch: process.arch, - version: Bun.version, - revision: Bun.revision, - tmpdir: tmpdir(), - tmpdirRealpath: await realpath(tmpdir()), - directory, - results, - }, - null, - 2, - ), -) diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py deleted file mode 100644 index 9f6a56d3be7..00000000000 --- a/.github/native-bun-validation/prepare.py +++ /dev/null @@ -1,106 +0,0 @@ -import argparse -import gzip -import hashlib -import io -import json -from pathlib import Path, PurePosixPath -import re -import subprocess -import tarfile - - -BASE = "dca7d25e95cca39316c659a377dba6803805549f" -PATCH_HASH = "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b" -ADDITIONAL = { - "src/bundler/input_source_map.rs", - "src/runtime/bake/dev_server/plugin_watch_store.rs", - "src/sourcemap/InputSourceMap.rs", - "test/bake/dev/barrel-hmr-renaming.test.ts", - "test/bake/dev/barrel-hmr.test.ts", - "test/bake/dev/client-plugin-cache.test.ts", -} - - -def digest(data): - return hashlib.sha256(data).hexdigest() - - -def allowed(name): - path = PurePosixPath(name) - return ( - not path.is_absolute() - and ".." not in path.parts - and "\\" not in name - and ( - name.startswith(("src/", "test/", "docs/")) - or name in {"Cargo.lock", "packages/bun-types/bun.d.ts"} - ) - ) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--bun", type=Path) - parser.add_argument("--out", type=Path) - parser.add_argument("--check-assets-only", action="store_true") - args = parser.parse_args() - data = Path(__file__).resolve().parent - manifest = json.loads((data / "native-v15-manifest.json").read_text()) - assert manifest["head"] == BASE - assert manifest["trackedPatchSha256"] == PATCH_HASH - assert set(manifest["additionalFiles"]) == ADDITIONAL - patch = gzip.decompress((data / "native-v15-tracked.patch.gz").read_bytes()) - assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" - paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) - assert paths, "No tracked patch paths" - tracked = [] - for old, new in paths: - assert old == new and allowed(old.decode()), "Unexpected tracked path" - tracked.append(old.decode()) - extra = {} - archive = gzip.decompress( - (data / "native-v15-additional-files.tar.gz").read_bytes() - ) - with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: - for member in bundle.getmembers(): - assert member.isfile(), "Non-regular archive entry" - assert member.name in ADDITIONAL and allowed(member.name) - assert member.name not in extra, "Duplicate archive entry" - content = bundle.extractfile(member).read() - assert digest(content) == manifest["additionalFiles"][member.name] - extra[member.name] = content - assert set(extra) == ADDITIONAL - print(json.dumps({"base": BASE, "patchSha256": PATCH_HASH, - "trackedPaths": tracked, "additionalFiles": manifest["additionalFiles"]}, indent=2)) - if args.check_assets_only: - return - assert args.bun and args.out, "--bun and --out are required" - bun = args.bun.resolve() - out = args.out.resolve() - actual = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=bun, text=True).strip() - assert actual == BASE, "Unexpected Bun checkout" - assert not subprocess.check_output(["git", "status", "--porcelain"], cwd=bun), "Bun checkout is dirty" - for name in extra: - assert not (bun / name).exists(), "Additional file already exists" - subprocess.run(["git", "apply", "--check", "-"], input=patch, cwd=bun, check=True) - subprocess.run(["git", "apply", "-"], input=patch, cwd=bun, check=True) - for name, content in extra.items(): - target = bun / name - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(content) - subprocess.run(["git", "diff", "--check"], cwd=bun, check=True) - for name, expected in manifest["changedSourceSha256"].items(): - assert allowed(name) and name in tracked - assert digest((bun / name).read_bytes()) == expected, f"Source hash mismatch: {name}" - out.mkdir(parents=True, exist_ok=True) - with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: - for name in sorted(set(tracked) | ADDITIONAL): - bundle.add(bun / name, arcname=name) - (out / "native-v15-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") - (out / "tracked.patch").write_bytes(patch) - for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: - (out / name).write_bytes((bun / name).read_bytes()) - - -if __name__ == "__main__": - main() diff --git a/.github/native-bun-validation/pure-bun-graph-browser.mjs b/.github/native-bun-validation/pure-bun-graph-browser.mjs deleted file mode 100644 index 56d26eea78d..00000000000 --- a/.github/native-bun-validation/pure-bun-graph-browser.mjs +++ /dev/null @@ -1,538 +0,0 @@ -import assert from 'node:assert/strict' -import { spawn, execFileSync } from 'node:child_process' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { - mkdtemp, - mkdir, - readFile, - realpath, - writeFile, - rm, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -const requireProject = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -) -const { chromium, expect } = requireProject('@playwright/test') -const sourceMapMode = process.env.PURE_BUN_SOURCE_MAPS === '1' -const largePairMode = process.env.PURE_BUN_LARGE_PAIR === '1' -const pluginRequire = createRequire( - path.join(root, 'packages/router-plugin/package.json'), -) -const babelRequire = createRequire(pluginRequire.resolve('@babel/core')) -const { AnyMap, originalPositionFor, sourceContentFor } = createRequire( - babelRequire.resolve('@jridgewell/remapping'), -)('@jridgewell/trace-mapping') -const binaries = [ - ['candidate', process.env.BUN_EXECUTABLE], - ['baseline', process.env.BUN_BASELINE_EXECUTABLE], - ['debug', process.env.BUN_DEBUG_EXECUTABLE], -].filter(([, binary]) => binary) -assert.ok(binaries.length, 'Set BUN_EXECUTABLE') -const output = - process.env.PURE_BUN_BROWSER_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/pure-bun-graph-${process.platform}.json`, - ) -await mkdir(path.dirname(output), { recursive: true }) -const browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), -}) -const results = [] -const mentions = (text) => - ['before.ts', 'after.ts', 'graph.ts', 'main.ts'].filter((name) => - text.includes(name), - ) -try { - for (const [label, binary] of binaries) { - for (const reloadWhileAfter of sourceMapMode - ? [true] - : largePairMode - ? [false] - : [false, true]) { - const name = `${label}-${reloadWhileAfter ? 'reload-B' : 'automatic'}` - console.log(`START ${name}`) - const directory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')), - ) - const result = { - name, - label, - binary, - reloadWhileAfter, - sourceMapMode, - largePairMode, - passed: false, - steps: [], - errors: [], - websocketFrames: [], - initialJavaScript: [], - documentLoads: 0, - } - let child, - context, - logs = '' - try { - await writeFile( - path.join(directory, 'index.html'), - '
', - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value} from './graph.ts';document.querySelector('#app').textContent=value;if(import.meta.hot)import.meta.hot.accept();`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value} from './before.ts';`, - ) - await writeFile( - path.join(directory, 'before.ts'), - `export const value='BEFORE';`, - ) - await writeFile( - path.join(directory, 'after.ts'), - `export const value='AFTER';`, - ) - const authoredSource = `export const value = 'BEFORE';\nexport function authoredThrow() {\n throw new Error('CACHED_CLOSURE_AUTHORED_THROW');\n}\n` - if (sourceMapMode) { - await writeFile( - path.join(directory, 'before.ts'), - `export {value, authoredThrow} from './cached-leaf.ts';`, - ) - await writeFile( - path.join(directory, 'cached-leaf.ts'), - authoredSource, - ) - await writeFile( - path.join(directory, 'after.ts'), - `export const value='AFTER';export function authoredThrow(){throw new Error('UNEXPECTED_AFTER_THROW')}`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value,authoredThrow} from './graph.ts';document.querySelector('#app').textContent=value;globalThis.__throwCached=authoredThrow;if(import.meta.hot)import.meta.hot.accept();`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value,authoredThrow} from './before.ts';`, - ) - } - if (largePairMode) { - await writeFile( - path.join(directory, 'shared.ts'), - `globalThis.sharedInits=(globalThis.sharedInits??0)+1;export const shared={initializations:globalThis.sharedInits};`, - ) - await writeFile( - path.join(directory, 'after.ts'), - `import {shared} from './shared.ts';export {shared};export const value='AFTER';export const padding={${Array.from({ length: Number(process.env.PURE_BUN_LARGE_FUNCTIONS ?? 40000) }, (_, index) => `k${index}:()=>${index}`).join(',')}};`, - ) - await writeFile( - path.join(directory, 'before.ts'), - `import {shared} from './shared.ts';export {shared};export const value='BEFORE';`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value,shared} from './before.ts';`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value,shared} from './graph.ts';import {shared as stable} from './shared.ts';document.querySelector('#app').textContent=value;globalThis.__pureShared={identity:shared===stable,initializations:shared.initializations};if(import.meta.hot){import.meta.hot.accept();import.meta.hot.on('bun:beforeUpdate',()=>console.debug('__PURE_LIFECYCLE__before'));import.meta.hot.on('bun:afterUpdate',()=>console.debug('__PURE_LIFECYCLE__after'));}`, - ) - } - await writeFile( - path.join(directory, 'server.ts'), - `import html from './index.html';const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}});console.log('READY '+JSON.stringify({url:server.url.href,pid:process.pid}));`, - ) - let readyResolve, readyReject - const ready = new Promise((resolve, reject) => { - readyResolve = resolve - readyReject = reject - }) - child = spawn(binary, ['server.ts'], { - cwd: directory, - env: { ...process.env, NODE_ENV: 'development' }, - stdio: ['ignore', 'pipe', 'pipe'], - windowsHide: true, - }) - child.on('error', readyReject) - child.on('exit', (code, signal) => - readyReject(new Error(`Bun exited (${code},${signal})\n${logs}`)), - ) - let pending = '' - child.stdout.on('data', (chunk) => { - logs += chunk - pending += chunk - let newline - while ((newline = pending.indexOf('\n')) !== -1) { - const line = pending.slice(0, newline) - pending = pending.slice(newline + 1) - if (line.startsWith('READY ')) { - try { - readyResolve(JSON.parse(line.slice(6))) - } catch (error) { - readyReject(error) - } - } - } - }) - child.stderr.on('data', (chunk) => { - logs += chunk - }) - let timer - const info = await Promise.race([ - ready, - new Promise((_, reject) => { - timer = setTimeout( - () => reject(new Error(`Startup deadline\n${logs}`)), - 20000, - ) - }), - ]).finally(() => clearTimeout(timer)) - result.pid = info.pid - result.revision = execFileSync(binary, ['--revision'], { - encoding: 'utf8', - }).trim() - result.binarySha256 = createHash('sha256') - .update(await readFile(binary)) - .digest('hex') - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.__pureGraphDocumentToken = crypto.randomUUID() - }) - if (largePairMode) { - await context.addInitScript(() => { - const key = Symbol.for('bun:hmr') - let callback - Object.defineProperty(globalThis, key, { - configurable: true, - get() { - return callback - }, - set(original) { - callback = function (...args) { - const record = (kind) => - console.debug( - '__PURE_CALLBACK__' + - JSON.stringify({ - kind, - id: args[1], - keys: Object.keys(args[0]), - time: performance.now(), - documentToken: globalThis.__pureGraphDocumentToken, - }), - ) - record('start') - try { - return Reflect.apply(original, this, args) - } finally { - record('return') - } - } - }, - }) - }) - } - const page = await context.newPage() - const session = sourceMapMode ? await context.newCDPSession(page) : null - const scripts = new Map() - if (session) { - session.on('Debugger.scriptParsed', (script) => - scripts.set(script.scriptId, script), - ) - await session.send('Debugger.enable') - } - let phase = 'initial-A' - let pairedWrite - const assets = [] - page.on('load', () => { - result.documentLoads++ - }) - page.on('console', (message) => { - if (message.type() === 'error') { - result.errors.push({ phase, type: 'console', text: message.text() }) - } - }) - page.on('console', (message) => { - if (message.text().startsWith('__PURE_CALLBACK__')) { - ;(result.callbackEvents ??= []).push({ - ...JSON.parse(message.text().slice('__PURE_CALLBACK__'.length)), - phase, - }) - } - if (message.text().startsWith('__PURE_LIFECYCLE__')) { - ;(result.lifecycleEvents ??= []).push({ - phase, - event: message.text().slice('__PURE_LIFECYCLE__'.length), - }) - } - }) - page.on('pageerror', (error) => - result.errors.push({ phase, type: 'pageerror', text: error.message }), - ) - page.on('websocket', (socket) => - socket.on('framereceived', (event) => { - const bytes = Buffer.from(event.payload) - const sourceMapId = bytes - .toString('utf8') - .match( - /sourceMappingURL=\/_bun\/client\/([a-f0-9]{16})\.js\.map/, - )?.[1] - result.websocketFrames.push({ - phase, - bytes: bytes.length, - ...(sourceMapId ? { sourceMapId } : {}), - mentionedModules: mentions(bytes.toString('utf8')), - base64: bytes.toString('base64'), - }) - if ( - largePairMode && - phase === 'A-to-B' && - !pairedWrite && - bytes.toString('utf8').includes('self[Symbol.for("bun:hmr")]') - ) { - pairedWrite = writeFile( - path.join(directory, 'graph.ts'), - `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-TWO';`, - ) - } - }), - ) - page.on('response', (response) => { - if (new URL(response.url()).pathname.endsWith('.js')) { - const responsePhase = phase - assets.push( - response - .text() - .then(async (text) => { - const file = output.replace( - /\.json$/, - `-${name}-js${result.initialJavaScript.length}.txt`, - ) - result.initialJavaScript.push({ - phase: responsePhase, - url: response.url(), - mentionedModules: mentions(text), - file, - }) - await writeFile(file, text) - }) - .catch((error) => - result.initialJavaScript.push({ - phase: responsePhase, - error: String(error), - }), - ), - ) - } - }) - const checkpoint = async (expected) => { - await expect(page.locator('#app')).toHaveText(expected, { - timeout: 15000, - }) - assert.deepEqual( - await (await fetch(new URL('/__info', info.url))).json(), - { pid: info.pid }, - ) - await Promise.all(assets) - result.steps.push({ - phase, - text: expected, - documentToken: await page.evaluate( - () => globalThis.__pureGraphDocumentToken, - ), - documentLoads: result.documentLoads, - errorCount: result.errors.length, - }) - if (largePairMode) { - assert.deepEqual( - await page.evaluate(() => globalThis.__pureShared), - { identity: true, initializations: 1 }, - ) - } - } - const checkAuthoredThrow = async () => { - await session.send('Debugger.setPauseOnExceptions', { state: 'all' }) - let resumePromise - const paused = new Promise((resolve) => - session.once('Debugger.paused', (event) => { - resolve(event) - resumePromise = session.send('Debugger.resume') - }), - ) - const evaluation = session.send('Runtime.evaluate', { - expression: `try { globalThis.__throwCached() } catch(error) { error.message }`, - returnByValue: true, - }) - let pauseTimer - const event = await Promise.race([ - paused, - new Promise((_, reject) => { - pauseTimer = setTimeout( - () => reject(new Error('Expected authored exception pause')), - 15000, - ) - }), - ]).finally(() => clearTimeout(pauseTimer)) - await resumePromise - const evaluated = await evaluation - await session.send('Debugger.setPauseOnExceptions', { state: 'none' }) - assert.equal(evaluated.result.value, 'CACHED_CLOSURE_AUTHORED_THROW') - const frame = event.callFrames[0], - script = scripts.get(frame.location.scriptId) - assert.ok( - script?.sourceMapURL, - 'Throwing script must declare a source map', - ) - const { scriptSource } = await session.send( - 'Debugger.getScriptSource', - { scriptId: script.scriptId }, - ) - const mapUrl = script.sourceMapURL.startsWith('/') - ? new URL(script.sourceMapURL, info.url).href - : new URL( - script.sourceMapURL, - new URL(script.url || info.url, info.url), - ).href - assert.ok(!mapUrl.startsWith('data:'), 'Expected network source map') - const response = await fetch(mapUrl) - assert.equal(response.status, 200) - const map = await response.json(), - trace = AnyMap(map) - const generated = { - line: frame.location.lineNumber + 1, - column: frame.location.columnNumber, - } - const traced = originalPositionFor(trace, generated) - assert.ok(traced.source, 'Authored source is required') - const tracedFile = traced.source.startsWith('file:') - ? fileURLToPath(traced.source) - : path.resolve(directory, traced.source) - assert.equal( - path.normalize(tracedFile), - path.join(directory, 'cached-leaf.ts'), - ) - assert.equal(traced.line, 3) - assert.equal(traced.column, 2) - assert.equal( - sourceContentFor(trace, traced.source, true), - authoredSource, - ) - const snapshot = output.replace(/\.json$/, `-${name}-${phase}-throw`) - await writeFile(snapshot + '.js', scriptSource) - await writeFile(snapshot + '.js.map', JSON.stringify(map)) - ;(result.authoredThrows ??= []).push({ - phase, - scriptUrl: script.url, - sourceMapURL: script.sourceMapURL, - mapUrl, - generated, - traced, - sourceContentMatches: true, - snapshot, - }) - } - await page.goto(info.url) - await checkpoint('BEFORE') - if (sourceMapMode) { - await checkAuthoredThrow() - } - phase = 'A-to-B' - await writeFile( - path.join(directory, 'graph.ts'), - sourceMapMode - ? `export {value,authoredThrow} from './after.ts';` - : largePairMode - ? `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-ONE';` - : `export {value} from './after.ts';`, - ) - await checkpoint(largePairMode ? 'AFTER-TWO' : 'AFTER') - if (largePairMode) { - assert.ok( - pairedWrite, - 'Second public file write was triggered by first HMR frame', - ) - await pairedWrite - assert.equal( - result.documentLoads, - 1, - 'Paired updates must retain the document', - ) - } - if (reloadWhileAfter) { - phase = 'reload-B' - await page.reload() - await checkpoint('AFTER') - } - phase = 'B-to-A' - await writeFile( - path.join(directory, 'graph.ts'), - sourceMapMode - ? `export {value,authoredThrow} from './before.ts';` - : largePairMode - ? `export {value,shared} from './before.ts';` - : `export {value} from './before.ts';`, - ) - await checkpoint('BEFORE') - if (sourceMapMode) { - assert.equal( - result.documentLoads, - 2, - 'Restoration must not fall back to another document reload', - ) - await checkAuthoredThrow() - } - assert.deepEqual(result.errors, [], 'Unexpected browser errors') - result.passed = true - console.log(`PASS ${name}`) - } catch (error) { - result.error = error instanceof Error ? error.stack : String(error) - console.log(`FAIL ${name}: ${String(error).split('\n')[0]}`) - } finally { - result.serverLog = logs - try { - await context?.close() - } finally { - if (child && child.exitCode === null && child.signalCode === null) { - child.kill() - await new Promise((resolve) => child.once('exit', resolve)) - } - await rm(directory, { recursive: true, force: true }) - } - } - results.push(result) - await writeFile( - output, - JSON.stringify( - { - platform: process.platform, - node: process.version, - sourceMapMode, - largePairMode, - passed: results.filter((result) => result.passed).length, - cases: binaries.length * (sourceMapMode || largePairMode ? 1 : 2), - results, - }, - null, - 2, - ) + '\n', - ) - } - } -} finally { - await browser.close() -} -console.log( - `RESULT ${results.filter((result) => result.passed).length}/${results.length}; ${output}`, -) -if (results.some((result) => !result.passed)) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs deleted file mode 100644 index a8f22394fd3..00000000000 --- a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs +++ /dev/null @@ -1,360 +0,0 @@ -import assert from 'node:assert/strict' -import { spawn, execFileSync } from 'node:child_process' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { watch } from 'node:fs' -import { - mkdtemp, - mkdir, - readFile, - realpath, - writeFile, - rm, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import { setTimeout as batchInterval } from 'node:timers/promises' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -const binary = process.env.BUN_EXECUTABLE -assert.ok(binary, 'Set BUN_EXECUTABLE') -const output = - process.env.PENDING_BATCH_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/pure-bun-pending-batches-${process.platform}.json`, - ) -await mkdir(path.dirname(output), { recursive: true }) -const { chromium, expect } = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -)('@playwright/test') -const directory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pending-batches-')), -) -const controlDirectory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pending-control-')), -) -const releaseFile = path.join(controlDirectory, 'release') -const blockThread = process.env.PENDING_BATCH_BLOCK !== '0' -const nativeSync = process.env.PENDING_BATCH_NATIVE_SYNC === '1' -const captureHmr = process.env.PENDING_BATCH_CAPTURE_HMR === '1' -const tracePath = process.env.BUN_WATCHER_TRACE -if (nativeSync) { - assert.ok(tracePath, 'Native batch synchronization needs BUN_WATCHER_TRACE') -} -const result = { - binary, - blockThread, - nativeSync, - tracePath, - binarySha256: createHash('sha256') - .update(await readFile(binary)) - .digest('hex'), - revision: execFileSync(binary, ['--revision'], { encoding: 'utf8' }).trim(), - directory, - controlDirectory, - passed: false, - writes: [], - nativeBatches: [], - ipc: [], - browserErrors: [], - documentLoads: 0, -} -let child, - browser, - context, - logs = '', - page -const assetCaptures = [] -const snapshot = async () => ({ - text: await page.locator('#app').textContent(), - documentToken: await page.evaluate(() => globalThis.documentToken), - documentLoads: result.documentLoads, -}) -const waitNativeBatch = async (name) => { - const wanted = path.join(directory, name + '.ts').replaceAll('\\', '/') - let observer, timer - try { - const event = await new Promise((resolve, reject) => { - const check = async () => { - try { - const text = await readFile(tracePath, 'utf8') - for (const line of text - .slice(0, text.lastIndexOf('\n') + 1) - .split('\n') - .filter(Boolean)) { - const batch = JSON.parse(line) - const entry = Object.entries(batch.files).find( - ([filename]) => filename.replaceAll('\\', '/') === wanted, - ) - if (entry) { - resolve({ - name, - timestamp: batch.timestamp, - path: entry[0], - ...entry[1], - }) - return - } - } - } catch (error) { - if (error.code !== 'ENOENT') { - reject(error) - } - } - } - observer = watch(path.dirname(tracePath), (event, filename) => { - if (String(filename) === path.basename(tracePath)) { - void check() - } - }) - timer = setTimeout( - () => reject(new Error('Native watcher batch deadline for ' + name)), - 15000, - ) - void check() - }) - result.nativeBatches.push(event) - } finally { - observer?.close() - clearTimeout(timer) - } -} -try { - await writeFile( - path.join(directory, 'index.html'), - `

`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {a} from './a.ts';import {b} from './b.ts';import {c} from './c.ts';document.querySelector('#app').textContent=[a,b,c].join('|');if(import.meta.hot)import.meta.hot.accept();`, - ) - for (const name of ['a', 'b', 'c']) { - await writeFile( - path.join(directory, name + '.ts'), - `export const ${name}='${name.toUpperCase()}0';\n`, - ) - } - await writeFile( - path.join(directory, 'server.ts'), - ` - import html from './index.html';import {existsSync} from 'node:fs'; - const releaseFile=${JSON.stringify(releaseFile)}; - process.on('message',message=>{ - if(message==='block'){ - process.send({phase:'blocked',time:Date.now()}); - const deadline=Date.now()+15000; - while(!existsSync(releaseFile)){if(Date.now()>deadline){throw new Error('External release deadline exceeded')}} - process.send({phase:'released',time:Date.now()}); - } - }); - const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}}); - process.send({phase:'ready',url:server.url.href,pid:process.pid}); - `, - ) - let readyResolve, readyReject, blockedResolve, releasedResolve - const ready = new Promise((resolve, reject) => { - readyResolve = resolve - readyReject = reject - }) - const blocked = new Promise((resolve) => { - blockedResolve = resolve - }) - const released = new Promise((resolve) => { - releasedResolve = resolve - }) - child = spawn(binary, ['server.ts'], { - cwd: directory, - env: { ...process.env, NODE_ENV: 'development' }, - stdio: ['ignore', 'pipe', 'pipe', 'ipc'], - windowsHide: true, - }) - child.on('error', readyReject) - child.on('exit', (code, signal) => - readyReject(new Error(`Server exited ${code}/${signal}: ${logs}`)), - ) - child.stdout.on('data', (chunk) => { - logs += chunk - }) - child.stderr.on('data', (chunk) => { - logs += chunk - }) - child.on('message', (message) => { - result.ipc.push(message) - if (message.phase === 'ready') { - readyResolve(message) - } - if (message.phase === 'blocked') { - blockedResolve(message) - } - if (message.phase === 'released') { - releasedResolve(message) - } - }) - const deadline = async (promise, label) => { - let timer - return Promise.race([ - promise, - new Promise((_, reject) => { - timer = setTimeout( - () => reject(new Error(`${label} deadline: ${logs}`)), - 20000, - ) - }), - ]).finally(() => clearTimeout(timer)) - } - const info = await deadline(ready, 'Startup') - result.pid = info.pid - browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), - }) - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.documentToken = crypto.randomUUID() - }) - page = await context.newPage() - if (captureHmr) { - result.websocketFrames = [] - result.initialJavaScript = [] - const session = await context.newCDPSession(page) - await session.send('Network.enable') - session.on('Network.webSocketFrameReceived', (event) => { - const { opcode, payloadData } = event.response - const bytes = Buffer.from(payloadData, opcode === 2 ? 'base64' : 'utf8') - const decoded = bytes.toString('utf8') - const frame = { - requestId: event.requestId, - timestamp: event.timestamp, - opcode, - bytes: bytes.length, - base64: bytes.toString('base64'), - } - result.websocketFrames.push(frame) - if (decoded.includes('self[Symbol.for("bun:hmr")]')) { - frame.file = output.replace( - /\.json$/, - `-hmr${result.websocketFrames.length}.txt`, - ) - assetCaptures.push(writeFile(frame.file, decoded)) - } - }) - page.on('response', (response) => { - if (!new URL(response.url()).pathname.endsWith('.js')) { - return - } - const asset = { - url: response.url(), - file: output.replace( - /\.json$/, - `-initial${result.initialJavaScript.length}.js`, - ), - } - result.initialJavaScript.push(asset) - assetCaptures.push( - response - .text() - .then((text) => writeFile(asset.file, text)) - .catch((error) => { - asset.error = String(error) - }), - ) - }) - } - page.on('load', () => { - result.documentLoads++ - }) - page.on('console', (message) => { - if (message.type() === 'error') { - result.browserErrors.push({ type: 'console', text: message.text() }) - } - }) - page.on('pageerror', (error) => - result.browserErrors.push({ type: 'pageerror', text: error.message }), - ) - await page.goto(info.url) - await expect(page.locator('#app')).toHaveText('A0|B0|C0') - result.before = await snapshot() - if (blockThread) { - child.send('block') - await deadline(blocked, 'IPC block') - } - for (const name of ['a', 'b', 'c']) { - const started = Date.now(), - contents = `export const ${name}='${name.toUpperCase()}1';\n` - await writeFile(path.join(directory, name + '.ts'), contents) - result.writes.push({ name, started, finished: Date.now(), contents }) - if (nativeSync) { - await waitNativeBatch(name) - } else { - await batchInterval(150) - } - } - if (blockThread) { - await writeFile(releaseFile, 'release\n') - await deadline(released, 'IPC release') - } - try { - await expect(page.locator('#app')).toHaveText('A1|B1|C1', { timeout: 5000 }) - } finally { - result.after = await snapshot() - } - assert.equal( - result.after.documentToken, - result.before.documentToken, - 'Updates must retain the document', - ) - assert.equal(result.documentLoads, 1) - assert.deepEqual(result.browserErrors, []) - assert.deepEqual(await (await fetch(new URL('/__info', info.url))).json(), { - pid: info.pid, - }) - result.passed = true -} catch (error) { - result.error = error.stack ?? String(error) - result.moduleBytes = Object.fromEntries( - await Promise.all( - ['a', 'b', 'c'].map(async (name) => [ - name, - await readFile(path.join(directory, name + '.ts'), 'utf8'), - ]), - ), - ) - result.preservedFixture = true -} finally { - await writeFile(releaseFile, 'cleanup release\n').catch(() => {}) - await Promise.all(assetCaptures) - await context?.close() - await browser?.close() - if (child && child.exitCode === null && child.signalCode === null) { - child.kill() - await new Promise((resolve) => child.once('exit', resolve)) - } - result.serverLog = logs - if (result.passed) { - await rm(directory, { recursive: true, force: true }) - } - await rm(controlDirectory, { recursive: true, force: true }) - await writeFile(output, JSON.stringify(result, null, 2) + '\n') -} -console.log( - JSON.stringify({ - passed: result.passed, - before: result.before, - after: result.after, - writes: result.writes.map(({ name, started, finished }) => ({ - name, - started, - finished, - })), - error: result.error?.split('\n')[0], - output, - }), -) -if (!result.passed) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/require-tests-reporter.mjs b/.github/native-bun-validation/require-tests-reporter.mjs deleted file mode 100644 index bb1972b99d2..00000000000 --- a/.github/native-bun-validation/require-tests-reporter.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import { writeFileSync } from 'node:fs' - -export default class RequireTestsReporter { - tests = [] - - onTestEnd(test, result) { - this.tests.push({ - title: test.titlePath().join(' > '), - status: result.status, - errors: result.errors, - }) - } - - onEnd(result) { - const passed = - this.tests.length > 0 && - this.tests.every((test) => test.status === 'passed') - writeFileSync( - process.env.NATIVE_REPORT, - JSON.stringify({ result, tests: this.tests }, null, 2) + '\n', - ) - if (!passed) { - console.error( - 'Native validation requires every selected test to execute and pass; skips fail validation.', - ) - return { status: 'failed' } - } - } -} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml deleted file mode 100644 index da8e675d3ba..00000000000 --- a/.github/workflows/bun-native-validation.yml +++ /dev/null @@ -1,277 +0,0 @@ -name: Temporary native Bun validation - -on: - workflow_dispatch: - inputs: - router_ref: - description: 'Exact Router commit for browser tests; empty builds Bun only' - type: string - default: '' - binary_run: - description: 'Existing successful native build run ID; empty builds Bun' - type: string - default: '' - -permissions: - contents: read - actions: read - -env: - CI: '1' - NX_DAEMON: 'false' - NX_NO_CLOUD: 'true' - -jobs: - native: - if: github.repository == 'RentnerKev/router' && inputs.binary_run == '' - runs-on: macos-15 - defaults: - run: - shell: bash - steps: - - name: Checkout validation harness - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - name: Checkout immutable Bun base - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/bun - ref: dca7d25e95cca39316c659a377dba6803805549f - path: .native-bun - persist-credentials: false - - name: Setup bootstrap Bun - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - with: - bun-version: '1.4.4' - - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: '26.10.0' - package-manager-cache: false - - name: Build native release binary - id: native_tests - run: bash .github/native-bun-validation/build-macos.sh - - name: Collect binary and final machine state - if: always() - run: | - mkdir -p .native-proof/binary - df -h > .native-proof/final-disk.log - if [[ -f .native-bun/build/native-release/bun-profile ]]; then - cp .native-bun/build/native-release/bun-profile .native-proof/binary/bun - python3 - <<'PY' - import hashlib, json, os, subprocess - from pathlib import Path - binary = Path('.native-proof/binary/bun') - manifest = json.loads(Path('.github/native-bun-validation/native-v15-manifest.json').read_text()) - proof = { - 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), - 'base': manifest['head'], - 'patchSha256': manifest['trackedPatchSha256'], - 'additionalFiles': manifest['additionalFiles'], - 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), - 'workflowRun': os.environ['GITHUB_RUN_ID'], - 'workflowCommit': os.environ['GITHUB_SHA'], - 'buildProfile': 'release --lto=off --canary=off', - } - Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') - PY - fi - - name: Upload native binary, source, toolchain and test proof - if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: native-macos-arm64-bun - path: .native-proof/ - include-hidden-files: true - if-no-files-found: error - retention-days: 14 - - browser: - if: always() && !cancelled() && github.repository == 'RentnerKev/router' && inputs.router_ref != '' && (inputs.binary_run != '' || needs.native.result == 'success') - needs: native - runs-on: macos-15 - defaults: - run: - shell: bash - steps: - - name: Checkout exact Router commit - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.router_ref || github.sha }} - persist-credentials: false - - name: Require immutable Router ref - env: - ROUTER_REF: ${{ inputs.router_ref || github.sha }} - run: | - [[ "$ROUTER_REF" =~ ^[0-9a-f]{40}$ ]] - [[ "$(git rev-parse HEAD)" == "$ROUTER_REF" ]] - - name: Download native binary and proof - env: - GH_TOKEN: ${{ github.token }} - BINARY_RUN: ${{ inputs.binary_run || github.run_id }} - run: | - [[ "$BINARY_RUN" =~ ^[0-9]+$ ]] - gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact - - name: Setup pnpm - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: '26.10.0' - package-manager-cache: false - - name: Checkout matching native regression sources - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/bun - ref: dca7d25e95cca39316c659a377dba6803805549f - path: .cache/native-bun-validation/test-source - persist-credentials: false - - name: Execute verified native artifact regressions - id: native_regressions - continue-on-error: true - run: python3 .github/native-bun-validation/artifact-tests.py - - name: Record native module path identity - run: .native-artifact/binary/bun .github/native-bun-validation/path-identity-probe.ts > .native-browser-proof/path-identity.json - - name: Install Router dependencies - run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' - - name: Checkout actual unplugin PR source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/unplugin - ref: 4d01143e6f60a6a93ed40411629ea4da14f540a7 - path: .native-unplugin - persist-credentials: false - - name: Build actual unplugin PR distribution - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - version: '12.14.0' - package_json_file: .native-unplugin/package.json - dest: ~/native-pnpm12 - - name: Install and build actual unplugin PR - run: | - pnpm --dir .native-unplugin install --frozen-lockfile - pnpm --dir .native-unplugin build - test -f .native-unplugin/dist/index.mjs - - name: Restore Router pnpm version - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - dest: ~/native-pnpm11 - - name: Prepare isolated native Bun wrapper and unplugin preload - run: node .github/native-bun-validation/browser-setup.mjs - - name: Install Chromium - run: pnpm exec playwright install chromium --only-shell - - name: Execute Bun's native Chromium ordering regression - id: native_chrome - continue-on-error: true - run: python3 .github/native-bun-validation/chrome-test.py - - name: Preserve native HMR script order in the browser - id: hmr_order - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PURE_BUN_LARGE_PAIR: '1' - PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-hmr-order.json - run: node .github/native-bun-validation/pure-bun-graph-browser.mjs - - name: Map restored native dependencies to their authored source - id: restored_maps - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PURE_BUN_SOURCE_MAPS: '1' - PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-restored-maps.json - run: node .github/native-bun-validation/pure-bun-graph-browser.mjs - - name: Apply every native watcher batch in the browser - id: pending_batches - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PENDING_BATCH_NATIVE_SYNC: '1' - BUN_WATCHER_TRACE: ${{ github.workspace }}/.native-browser-proof/pending-batches-watcher.jsonl - PENDING_BATCH_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pending-batches-browser.json - run: node .github/native-bun-validation/pure-bun-pending-batches-browser.mjs - - name: Production builds, navigation and source maps - id: production - continue-on-error: true - env: - NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/production-results.json - run: | - set -o pipefail - pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/production.log - - name: Native development navigation, HMR, recovery and source maps - id: development - if: ${{ !cancelled() && steps.production.outcome != 'skipped' }} - continue-on-error: true - env: - NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/development-results.json - run: | - set -o pipefail - pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun:dev --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/development.log - - name: Checkout actual Jiti PR source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/jiti - ref: 2669fd42050027531c7bbeb0e61b61f7ae35517a - path: .native-jiti - persist-credentials: false - - name: Build actual Jiti PR distribution - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - version: '10.30.3' - package_json_file: .native-jiti/package.json - dest: ~/native-pnpm10 - - name: Install and build actual Jiti PR - working-directory: .native-jiti - run: | - [[ "$(pnpm --ignore-workspace --version)" == '10.30.3' ]] - pnpm --ignore-workspace install --frozen-lockfile - pnpm --ignore-workspace build - test -f dist/jiti.cjs - - name: Imported virtual configuration helpers with actual Jiti PR - id: configuration - continue-on-error: true - env: - JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs - run: | - mkdir -p packages/router-generator/.cache - cp .github/native-bun-validation/helper-import-preload.mjs packages/router-generator/.cache/helper-import-preload.mjs - if "$BUN_EXECUTABLE" .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-installed.json; then - echo 'Installed Jiti also passed the helper cases.' - fi - "$BUN_EXECUTABLE" --preload ./packages/router-generator/.cache/helper-import-preload.mjs .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-candidate.json - - name: Imported helper edits in the running native browser - id: configuration_browser - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - UNPLUGIN_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-unplugin/dist/index.mjs - JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs - BUN_PLUGIN_PRELOAD: ${{ github.workspace }}/.github/native-bun-validation/helper-browser-preload.mjs - HELPER_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/configuration-browser.json - run: node .github/native-bun-validation/helper-browser.mjs - - name: Upload all browser results - if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: native-macos-arm64-router-browser - path: | - .native-browser-proof/ - e2e/react-router/bun-basic-file-based/test-results/ - e2e/react-router/bun-basic-file-based/.cache/ - include-hidden-files: true - if-no-files-found: warn - retention-days: 14 - - name: Require browser and configuration suites to pass - if: always() - env: - PRODUCTION: ${{ steps.production.outcome }} - DEVELOPMENT: ${{ steps.development.outcome }} - CONFIGURATION: ${{ steps.configuration.outcome }} - CONFIGURATION_BROWSER: ${{ steps.configuration_browser.outcome }} - NATIVE_REGRESSIONS: ${{ steps.native_regressions.outcome }} - HMR_ORDER: ${{ steps.hmr_order.outcome }} - RESTORED_MAPS: ${{ steps.restored_maps.outcome }} - NATIVE_CHROME: ${{ steps.native_chrome.outcome }} - PENDING_BATCHES: ${{ steps.pending_batches.outcome }} - run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success && "$NATIVE_CHROME" == success && "$PENDING_BATCHES" == success ]] From 4aec5dc8092e9cf8fb4207fa4b4e34cdbd9de2c6 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 14:50:28 +0200 Subject: [PATCH 24/31] test: check native macOS path identities with Bun CI runner --- .../native-bun-validation/artifact-tests.py | 169 ++++++++++++++++++ .../canonical-watcher-test.patch.gz | Bin 0 -> 496 bytes .github/native-bun-validation/chrome-test.py | 46 +++++ .../hmr-script-order-test.patch.gz | Bin 0 -> 2287 bytes .../input-map-sync-test.patch.gz | Bin 0 -> 685 bytes .../mac-quiet-watch-tests.patch | 30 ++++ .../native-v15-additional-files.tar.gz | Bin 0 -> 10601 bytes .../native-v15-manifest.json | 43 +++++ .../native-v15-tracked.patch.gz | Bin 0 -> 91550 bytes .github/native-bun-validation/prepare.py | 106 +++++++++++ .github/workflows/bun-native-validation.yml | 67 +++++++ 11 files changed, 461 insertions(+) create mode 100644 .github/native-bun-validation/artifact-tests.py create mode 100644 .github/native-bun-validation/canonical-watcher-test.patch.gz create mode 100644 .github/native-bun-validation/chrome-test.py create mode 100644 .github/native-bun-validation/hmr-script-order-test.patch.gz create mode 100644 .github/native-bun-validation/input-map-sync-test.patch.gz create mode 100644 .github/native-bun-validation/mac-quiet-watch-tests.patch create mode 100644 .github/native-bun-validation/native-v15-additional-files.tar.gz create mode 100644 .github/native-bun-validation/native-v15-manifest.json create mode 100644 .github/native-bun-validation/native-v15-tracked.patch.gz create mode 100644 .github/native-bun-validation/prepare.py create mode 100644 .github/workflows/bun-native-validation.yml diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py new file mode 100644 index 00000000000..0e5104ad1d8 --- /dev/null +++ b/.github/native-bun-validation/artifact-tests.py @@ -0,0 +1,169 @@ +import gzip +import hashlib +import json +import os +from pathlib import Path +import re +import subprocess +import xml.etree.ElementTree as ET + + +root = Path(os.environ["GITHUB_WORKSPACE"]) +binary = root / ".native-artifact/binary/bun" +proof = root / ".native-browser-proof" +proof.mkdir(exist_ok=True) +expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) +manifest = json.loads((root / ".github/native-bun-validation/native-v15-manifest.json").read_text()) +assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] +assert expected["base"] == manifest["head"] +assert expected["patchSha256"] == manifest["trackedPatchSha256"] +assert expected["additionalFiles"] == manifest["additionalFiles"] +binary.chmod(0o755) +source = root / ".cache/native-bun-validation/test-source" +subprocess.run([ + "python3", str(root / ".github/native-bun-validation/prepare.py"), + "--bun", str(source), "--out", str(proof / "native-source"), +], check=True) +for cwd in [source, source / "test"]: + subprocess.run([str(binary), "install", "--frozen-lockfile"], cwd=cwd, check=True) + +overrides = proof / "native-test-overrides" +overrides.mkdir(exist_ok=True) +adjusted_sources = {} +patches = {} +for name, digest, allowed_paths in [ + ("mac-quiet-watch-tests.patch", + "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062", + {"test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts"}), + ("hmr-script-order-test.patch.gz", + "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", + {"test/js/bun/webview/webview-chrome.test.ts"}), + ("input-map-sync-test.patch.gz", + "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", + {"test/bundler/bun-build-api.test.ts"}), + ("canonical-watcher-test.patch.gz", + "b16e88c921073f6fa1b6e4f714906453ec3f861f6724028cf9dc99453a4fc00b", + {"test/bake/dev/hot.test.ts"}), +]: + patch = (root / ".github/native-bun-validation" / name).read_bytes() + if name.endswith(".gz"): + patch = gzip.decompress(patch) + assert hashlib.sha256(patch).hexdigest() == digest + paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) + assert all(old == new for old, new in paths) + assert {old.decode() for old, _ in paths} == allowed_paths + if name == "canonical-watcher-test.patch.gz": + original_test = source / "test/bake/dev/hot.test.ts" + original_contents = original_test.read_bytes() + needle = b'const text = readFileSync(trace, "utf8").slice(offset);' + assert original_contents.count(needle) == 1 + original_test.write_bytes(original_contents.replace( + needle, needle + b'\n console.error("NATIVE_PATH_IDENTITY " + JSON.stringify({ expected: filename, trace: text }));', + )) + try: + before = subprocess.run([ + str(binary), "test", "test/bake/dev/hot.test.ts", "-t", + "retains separate watcher batches while the server thread is busy$", + ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + env={**os.environ, "BUN_DEV_SERVER_VERBOSE_SYNC": "1"}) + (proof / "native-watcher-path-before.log").write_text(before.stdout) + identities = [json.loads(line.split("NATIVE_PATH_IDENTITY ", 1)[1]) + for line in before.stdout.splitlines() if "NATIVE_PATH_IDENTITY " in line] + aliases = [] + for identity in identities: + for line in identity["trace"].rsplit("\n", 1)[0].splitlines() if "\n" in identity["trace"] else []: + for filename in json.loads(line)["files"]: + if os.path.realpath(identity["expected"]) == filename and os.path.normpath(identity["expected"]) != filename: + aliases.append({"fixturePath": identity["expected"], "nativePath": filename}) + assert before.returncode != 0 and aliases, "Reproduce a mismatched alias in the original test oracle" + (proof / "native-watcher-path-before.json").write_text(json.dumps({ + "failedBefore": True, "samePhysicalFile": aliases, + }, indent=2) + "\n") + finally: + original_test.write_bytes(original_contents) + subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) + subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) + (overrides / name.removesuffix(".gz")).write_bytes(patch) + patches[name] = digest + for old, _ in paths: + filename = old.decode() + contents = (source / filename).read_bytes() + adjusted_sources[filename] = hashlib.sha256(contents).hexdigest() + target = overrides / filename + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(contents) +(overrides / "proof.json").write_text(json.dumps({ + "binaryRuntimeUnchanged": True, + "testOnlyPatchSha256": patches, + "adjustedSourceSha256": adjusted_sources, +}, indent=2) + "\n") +tests = manifest["testCommand"].split(" test ", 1)[1].split() +assert len(tests) == 9 +isolated = [ + ("test/bake/dev/plugins.test.ts", "watchDirs preserves browser state when only a child file's contents change"), + ("test/bake/dev/plugins.test.ts", "watchDirs shares directory events with imported files and trailing-slash aliases"), + ("test/bake/dev/client-plugin-cache.test.ts", "client plugin cache probe: structural dependency update serves the current manifest"), + ("test/bake/dev/server-sourcemap.test.ts", "server-side source maps handle nested imports"), + ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy"), + ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy with an atomic plugin dependency"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies with an async dependency"), + ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once with an async dependency"), + ("test/bundler/bun-build-api.test.ts", "an external input source map is read synchronously"), + ("test/bundler/bun-build-api.test.ts", "an input source map named by a file: URL is composed"), +] +isolated_results = [] +for index, (filename, title) in enumerate(isolated): + isolated_report = proof / f"native-isolated-{index}.xml" + run = subprocess.run([ + str(binary), "test", filename, "-t", re.escape(title) + "$", + "--reporter=junit", f"--reporter-outfile={isolated_report}", + ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={ + **os.environ, + "BUN_DEV_SERVER_VERBOSE_SYNC": "1", + "BUN_WATCHER_TRACE": str(proof / f"native-isolated-{index}-watcher.jsonl"), + }) + (proof / f"native-isolated-{index}.log").write_text(run.stdout) + all_cases = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] + selected = [case for case in all_cases if case.attrib.get("name", "").endswith(title)] + passed = run.returncode == 0 and len(selected) == 1 and all( + not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) + for case in selected + ) and all(case.find("skipped") is not None for case in all_cases if case not in selected) + isolated_results.append({"file": filename, "title": title, "passed": passed, + "cases": len(selected), "filteredOut": len(all_cases) - len(selected)}) + print(json.dumps(isolated_results[-1])) +(proof / "native-isolated-results.json").write_text(json.dumps(isolated_results, indent=2) + "\n") +report = proof / "native-results.xml" +# Execute the verified, source-built artifact. The Bun CI build path ignores +# trailing execution arguments, so a successful build alone is not a test run. +result = subprocess.run([ + str(binary), "test", *tests, "--reporter=junit", f"--reporter-outfile={report}", +], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +(proof / "native-regressions.log").write_text(result.stdout) +print(result.stdout, end="") +cases = ET.parse(report).findall(".//testcase") +assert cases, "Native test runner executed no cases" +by_file = {filename: [] for filename in tests} +for case in cases: + filename = Path(case.attrib["file"]) + if not filename.is_absolute(): + filename = source / filename + relative = filename.resolve().relative_to(source.resolve()).as_posix() + assert relative in by_file, f"Unexpected test source: {relative}" + by_file[relative].append(case) +assert all(any(case.find("skipped") is None for case in group) for group in by_file.values()), \ + "Every selected native test file must execute a non-skipped case" +summary = { + "binarySha256": expected["sha256"], "selectedFiles": tests, + "cases": len(cases), + "skipped": sum(case.find("skipped") is not None for case in cases), + "failed": sum(case.find("failure") is not None or case.find("error") is not None for case in cases), + "perFile": {filename: len(group) for filename, group in by_file.items()}, +} +(proof / "native-results.json").write_text(json.dumps(summary, indent=2) + "\n") +print(json.dumps(summary, indent=2)) +result.check_returncode() +assert summary["failed"] == 0 +assert all(run["passed"] for run in isolated_results) diff --git a/.github/native-bun-validation/canonical-watcher-test.patch.gz b/.github/native-bun-validation/canonical-watcher-test.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ef7aba536d526e30a87bc8f166d0f483f299954 GIT binary patch literal 496 zcmVE3T@~`_hLCS=jDCQ$1IhUh~r1a5Gj-6bRkxhE@_kIh7*62u*2f- zxj^Y9?a;pJP+xYlBzbew?#Zj`1v>3^zt;=mIDXAL2*dDI|M3`cC%Q)Hf8%k0G{v1^ z_`CyYS6Kq*g26fAL6vJ`IVp)nk{f=2(o9y0jG!E3r88DWiz2{5iDwAOWN(Wi0`1n6 zFO`LpT6DCrl0SpAHUSlB-uZJ_%u-Lmw(fZ`Ur2j`}IQ_ zi)LoDV+b~-%I3Zi&w`QoE=A!e0^5pywD26@^t}Xs3Xd-WTcLPj?A#BeDOItb+W?NO z(vK00l#Uo9w7qS3vOP*Mx|n>T1*^@;sWm*W#S&MxX1+I?ttpz#7Dn$biv|w8GVMJ4 meA7*~BBKb6isjozD{+O&sClUKl2-G)OYjTPobOBY0{{Rzi}hIm literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py new file mode 100644 index 00000000000..e44becba0a0 --- /dev/null +++ b/.github/native-bun-validation/chrome-test.py @@ -0,0 +1,46 @@ +import hashlib +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import uuid +import xml.etree.ElementTree as ET + + +root = Path(os.environ["GITHUB_WORKSPACE"]) +binary = root / ".native-artifact/binary/bun" +proof = root / ".native-browser-proof" +source = root / ".cache/native-bun-validation/test-source" +expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) +assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] +report = proof / "native-chrome.xml" +prefix = "native-final-chrome-" + uuid.uuid4().hex + "-" +title = "HMR applies a large update before the following small update" +# Use Bun's CI runner and its existing startup budget; do not override a test timeout. +command = [ + "node", "scripts/runner.node.ts", "--exec-path", str(binary), + "--retries", "0", "--junit", "--junit-temp-dir", prefix, + "--results-json", str(proof / "native-chrome-runner.json"), + "test/js/bun/webview/webview-chrome.test.ts", +] +result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +(proof / "native-chrome.log").write_text(result.stdout) +print(result.stdout, end="") +reports = [path for folder in Path(tempfile.gettempdir()).glob(prefix + "*") for path in folder.glob("*.xml")] +assert len(reports) == 1, f"Expected the CI runner's JUnit report: {reports}" +shutil.copyfile(reports[0], report) +all_cases = ET.parse(report).findall(".//testcase") +cases = [case for case in all_cases if case.attrib.get("name", "") == title] +passed = result.returncode == 0 and len(cases) == 1 and all( + not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) + for case in cases +) +(proof / "native-chrome.json").write_text(json.dumps({ + "binarySha256": expected["sha256"], "title": title, + "cases": len(cases), "passed": passed, "runnerCommand": command, + "fullFileCases": len(all_cases), + "fullFileSkipped": sum(case.find("skipped") is not None for case in all_cases), +}, indent=2) + "\n") +assert passed, "Native Chromium ordering regression must execute and pass" diff --git a/.github/native-bun-validation/hmr-script-order-test.patch.gz b/.github/native-bun-validation/hmr-script-order-test.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..5999aaa0ec696de2b787ca622861edf989e7b1b5 GIT binary patch literal 2287 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 TTuY6`!3*>cppU-!=LG-&_YXl) literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/mac-quiet-watch-tests.patch b/.github/native-bun-validation/mac-quiet-watch-tests.patch new file mode 100644 index 00000000000..ca9acee4348 --- /dev/null +++ b/.github/native-bun-validation/mac-quiet-watch-tests.patch @@ -0,0 +1,30 @@ +diff --git a/test/bake/dev/plugins.test.ts b/test/bake/dev/plugins.test.ts +--- a/test/bake/dev/plugins.test.ts ++++ b/test/bake/dev/plugins.test.ts +@@ -134,7 +134,13 @@ + await c.expectElemText("button", "Count 1"); +- await dev.write("unrelated.txt", "first"); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("unrelated.txt", "first"); ++ }); + await c.expectElemText("button", "Count 1"); +- await dev.write("unrelated.txt", "second"); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("unrelated.txt", "second"); ++ }); + await c.expectElemText("button", "Count 1"); +- await dev.write("data/a.ts", `export default "second";`); ++ await c.expectNoWebSocketActivity(async () => { ++ await dev.write("data/a.ts", `export default "second";`); ++ }); + await c.expectElemText("button", "Count 1"); +diff --git a/test/bake/dev/client-plugin-cache.test.ts b/test/bake/dev/client-plugin-cache.test.ts +--- a/test/bake/dev/client-plugin-cache.test.ts ++++ b/test/bake/dev/client-plugin-cache.test.ts +@@ -92,3 +92,5 @@ + await client.click("button"); +- await dev.write("data/a.ts", `export default "second";`); ++ await client.expectNoWebSocketActivity(async () => { ++ await dev.write("data/a.ts", `export default "second";`); ++ }); + await client.expectElemText("button", "Count 1"); diff --git a/.github/native-bun-validation/native-v15-additional-files.tar.gz b/.github/native-bun-validation/native-v15-additional-files.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e1f2d7a78af9308a8b8164c3b28c59ff10571685 GIT binary patch literal 10601 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 DD=fZe literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/native-v15-manifest.json b/.github/native-bun-validation/native-v15-manifest.json new file mode 100644 index 00000000000..ceabee96b15 --- /dev/null +++ b/.github/native-bun-validation/native-v15-manifest.json @@ -0,0 +1,43 @@ +{ + "candidate": "native-v15", + "head": "dca7d25e95cca39316c659a377dba6803805549f", + "trackedPatchSha256": "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b", + "additionalFiles": { + "src/bundler/input_source_map.rs": "6afe1551ae56d44dfa6abccc89668cd582db68c79f65acf692abba457f678cbf", + "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", + "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", + "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", + "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", + "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" + }, + "changesSinceV9": [ + "Windows synchronous handles for external input-map reads", + "Watched leaf-directory rename regression and explicit Windows ancestor-rename restriction" + ], + "testCommand": "bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts", + "changesSinceV10": [ + "Reachable cached client dependency closure after a fresh page load", + "Preserve loaded module identity and original source maps", + "Execute browser HMR scripts in WebSocket insertion order", + "Four public cached-closure regression cases" + ], + "changedSourceSha256": { + "src/runtime/bake/dev_server/incremental_graph.rs": "59d319121c7d7a42760e0e0e4df08303e8c08bc885c70b2d487d980ebaf85a9c", + "src/runtime/bake/dev_server/finalize.rs": "8bbc23a6df4e8444a4e6f71c1ef693c6b2445ee4ac5ad8e01139f2f627b89578", + "src/runtime/bake/dev_server/render.rs": "2fa45a019c3b96d387f5419945f49aeead30f496d57368c64362cf426958bc15", + "src/runtime/bake/hmr-module.ts": "20660b5fefeb174dbefc832d429d93d7bc5859ea9458fc75b8b82f89410092ae", + "src/runtime/bake/hmr-runtime-client.ts": "16fa1b0f4f5ed13a2f4e22e8a7059772f0cb1bee22cbb65ef535874b2d76f701", + "test/bake/dev/bundle.test.ts": "48a984dbdd53ded01bda8a1cc73de5756c745dfccf232af6b6cd75772ec07dfa", + "src/runtime/bake/dev_server/watcher_atomics.rs": "3efecf6b04601cbcf501df3304c30910c491bf03bce047d5707d318444256bd9", + "test/bake/dev/hot.test.ts": "8eb189558672bda096f54b957f0455656c04397f0c72a7cf50414666d2a935d6" + }, + "windowsBinarySha256": "56c24634993f1452d949924405ed06000530a9317c36c93a89fee3566beada85", + "changesSinceV12": [ + "Reclaim pending watcher events before collecting later batches", + "Preserve atomic plugin dependency events and rearm their file watches", + "Invalidate every affected HMR module before evaluating importers", + "Snapshot old accept callbacks and wait for asynchronous dependencies", + "Dispose shared accepting boundaries once per update", + "Six public regressions: two native watch cases and four client HMR cases" + ] +} diff --git a/.github/native-bun-validation/native-v15-tracked.patch.gz b/.github/native-bun-validation/native-v15-tracked.patch.gz new file mode 100644 index 0000000000000000000000000000000000000000..5d9d00c1cbadd615bfd5ce66bb92699205504ec4 GIT binary patch literal 91550 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
-O^GVE~NKa z)k$h(7=g!?Wl8HEQ$_c^?@TQZDMKA0-8?~THsuehav@GZ`XN=2$STNcS|qOYA_p= ze`DH=$Ya%F^!ntgwK2HUXxzPX^UnI_a9E(lh*go%Uc`#9!`96^Fz({djk{vo&EIe; z)>dk-jQJZZ?pz`&v6}zc>)l_UJ^J@YdOK>uuUnkk_RXW+1Dnm!v(d8IKr%zGt#LCQ zmw~(M=X=B_6zwg>2@fFete{AdbpAa{fHrs zd!m(*cNo{fH4kgR^Rf!^j${^GB!cM@IoCh%cxl91vyOy6? zrn0nWud{q!_}PR>hxnwMHRjS>!Ni$&P4`|@T6lH{3rgNIAyC5mDZ|wXo)2tt9Bp6| zSEU!ki`n2}9pG_7nxx6rBQK+w*Sb0Vy02sQx~g)4#@e|4$~gdAr_0RjMi4hA1%tQ7 zBRd)1DT6DkDfdtR#A6+hdWa93)I2esTI8%^>^ZgqH%I9Sy;!}uUdxV<-9kL;wff~| z&DS~OHB*0ut=PN;0s}VxEWX?op#u5IZjfyo*L7fB!?Tud-_FhCq@Lf#!W~+yoklAA zbI!c2)Eh{Ay0R_~S2jyLOv_Cxv+!z!@G~2+Ru6aL2Jgg$`ms^ekBg|N@Fs<8brTSh z_^`$n?6u?B=}A^Rs%Y74LZRa!d9GF5SyS5z-XaP=932s{Nk{j2VPKJ;jrs?##%9H~ z0pQS-Zyd`PVj(pejcPd6zH;@aeAbRi5Ov6}E*eD1gTn;lMR*5m0XgKhNxp_~-(=pWhd(v^jhIWZ5xRnSvIj;-UB?Kj z`9ji49!iaf{}lqCeiVo|;RK(=4ttT06L2k>eUhU#?g)AOb5m{YPXO$e^L_Z_Fv0j- zwD@RAMj%ADj5z2SkP0U!Oi1Ft5bR~yyM+X(g0y<@t03+1si09|eOx2BAIoX@LNjwb zNoPu~t&Q7_b^5;+jTV)wdch-$A3u3tFA%#;Awq}>qYE=f0irV(*&z!ppjQOvcSc`^ zRv0}T!l_L<);OP@6uoF)@N3aIkG%3GeGXdL=HiW0iK0XFQ%}79hrN-PTs=iSE~H!Ze~;MrIZbjf^pt@aeOMk6u4|`fqKYWZ3kkk_DX{ z6`vC(a2~ayRi(Il%KtviJ@38EWOS2uWNt)elu>*cBlPc=CDRagB5WjND%oSJbU`;r z6Xz`;eGOkf&@dv>KKMVoNYnKqSQ=JNIp;JvhW5;zNDxG6MlD~7A8GN!%+o!Dw*m&^ zk&tJ?+Ic%{lIXdnKdg~X4-zh43KlD_-5wkdkicL)y`+Krl z_2fBu?b3%|PN)A0hxq&0w!UGPVeiKuYx`$XaF4mm-pAA4S8Y%XfE5I+R5XARU=qp5$}J$`wcP% zR!0N5yTEWFdhl&2`cor49v$N7`{^guY^Xv(Y9e(4e^Ag>W(eywLF_WrQx;>_A%|1`?fo~HE-fHwu$hHUsU`V&P)q>3B znLGEjtVmDWa*^B0R3t&5G{e~k527h6{myBB%DNa$aY&2&g8UA}9+ z18e9}%e-tei1IkB*lnOuSlyFzT>DL)k&}rrGjdWOp$qlOL>PfW4X_*=uM#X>MpTr` zku(SJu$F3zrId9LdA5_Uf!G|Yb@GO!ia;L&Bj zHAvMzt^WU&oy`tIKoH08eF{z`QE7V+;m}7}#HN*q1C>U^yZ1kX#THQ~lC`rRV|KFp zn_**98AgCodRQ9$x#-Zmo~>fK9%O@e;`z=E#O~eqH236)-tj16sbmAWNi#_YCn*MB_jXB&Rmdk1E%eZmZYv42-dD^!LsfK*=VDLIBi~eRY94WHX|LoQOC$fNO0R8c!JW zHh5q^e_N7jj`L@SHp<)K&YVdSr>sjqF0VK(&IFZFyb*YUM)o-UM>3{3_~Fdq6Muo} zjW#Crr~+ONSO8YPx?nn%z8Dk7J43U_#g?Ny5@IQMJ)UCW@I&jIPB_Lc@)5VL@!D;7 N`T`U%tl?DI1pwbrT3P@A literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py new file mode 100644 index 00000000000..9f6a56d3be7 --- /dev/null +++ b/.github/native-bun-validation/prepare.py @@ -0,0 +1,106 @@ +import argparse +import gzip +import hashlib +import io +import json +from pathlib import Path, PurePosixPath +import re +import subprocess +import tarfile + + +BASE = "dca7d25e95cca39316c659a377dba6803805549f" +PATCH_HASH = "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b" +ADDITIONAL = { + "src/bundler/input_source_map.rs", + "src/runtime/bake/dev_server/plugin_watch_store.rs", + "src/sourcemap/InputSourceMap.rs", + "test/bake/dev/barrel-hmr-renaming.test.ts", + "test/bake/dev/barrel-hmr.test.ts", + "test/bake/dev/client-plugin-cache.test.ts", +} + + +def digest(data): + return hashlib.sha256(data).hexdigest() + + +def allowed(name): + path = PurePosixPath(name) + return ( + not path.is_absolute() + and ".." not in path.parts + and "\\" not in name + and ( + name.startswith(("src/", "test/", "docs/")) + or name in {"Cargo.lock", "packages/bun-types/bun.d.ts"} + ) + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--bun", type=Path) + parser.add_argument("--out", type=Path) + parser.add_argument("--check-assets-only", action="store_true") + args = parser.parse_args() + data = Path(__file__).resolve().parent + manifest = json.loads((data / "native-v15-manifest.json").read_text()) + assert manifest["head"] == BASE + assert manifest["trackedPatchSha256"] == PATCH_HASH + assert set(manifest["additionalFiles"]) == ADDITIONAL + patch = gzip.decompress((data / "native-v15-tracked.patch.gz").read_bytes()) + assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" + paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) + assert paths, "No tracked patch paths" + tracked = [] + for old, new in paths: + assert old == new and allowed(old.decode()), "Unexpected tracked path" + tracked.append(old.decode()) + extra = {} + archive = gzip.decompress( + (data / "native-v15-additional-files.tar.gz").read_bytes() + ) + with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: + for member in bundle.getmembers(): + assert member.isfile(), "Non-regular archive entry" + assert member.name in ADDITIONAL and allowed(member.name) + assert member.name not in extra, "Duplicate archive entry" + content = bundle.extractfile(member).read() + assert digest(content) == manifest["additionalFiles"][member.name] + extra[member.name] = content + assert set(extra) == ADDITIONAL + print(json.dumps({"base": BASE, "patchSha256": PATCH_HASH, + "trackedPaths": tracked, "additionalFiles": manifest["additionalFiles"]}, indent=2)) + if args.check_assets_only: + return + assert args.bun and args.out, "--bun and --out are required" + bun = args.bun.resolve() + out = args.out.resolve() + actual = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=bun, text=True).strip() + assert actual == BASE, "Unexpected Bun checkout" + assert not subprocess.check_output(["git", "status", "--porcelain"], cwd=bun), "Bun checkout is dirty" + for name in extra: + assert not (bun / name).exists(), "Additional file already exists" + subprocess.run(["git", "apply", "--check", "-"], input=patch, cwd=bun, check=True) + subprocess.run(["git", "apply", "-"], input=patch, cwd=bun, check=True) + for name, content in extra.items(): + target = bun / name + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(content) + subprocess.run(["git", "diff", "--check"], cwd=bun, check=True) + for name, expected in manifest["changedSourceSha256"].items(): + assert allowed(name) and name in tracked + assert digest((bun / name).read_bytes()) == expected, f"Source hash mismatch: {name}" + out.mkdir(parents=True, exist_ok=True) + with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: + for name in sorted(set(tracked) | ADDITIONAL): + bundle.add(bun / name, arcname=name) + (out / "native-v15-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") + (out / "tracked.patch").write_bytes(patch) + for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: + (out / name).write_bytes((bun / name).read_bytes()) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml new file mode 100644 index 00000000000..11f1f258b1a --- /dev/null +++ b/.github/workflows/bun-native-validation.yml @@ -0,0 +1,67 @@ +name: Temporary native Bun regression validation + +on: + workflow_dispatch: + +permissions: + contents: read + actions: read + +env: + CI: '1' + NX_DAEMON: 'false' + NX_NO_CLOUD: 'true' + +jobs: + native: + if: github.repository == 'RentnerKev/router' + runs-on: macos-15 + defaults: + run: + shell: bash + steps: + - name: Checkout validation harness + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '26.10.0' + package-manager-cache: false + - name: Download verified final native binary + env: + GH_TOKEN: ${{ github.token }} + run: | + gh run download 40091857136 --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact + - name: Checkout matching native regression sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/bun + ref: dca7d25e95cca39316c659a377dba6803805549f + path: .cache/native-bun-validation/test-source + persist-credentials: false + - name: Verify watch-path oracle and run native regressions + id: native_tests + continue-on-error: true + run: python3 .github/native-bun-validation/artifact-tests.py + - name: Run native Chrome tests with Bun's CI runner + id: chrome + if: ${{ !cancelled() }} + continue-on-error: true + run: python3 .github/native-bun-validation/chrome-test.py + - name: Upload regression results + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: native-macos-arm64-final-regressions + path: .native-browser-proof/ + include-hidden-files: true + if-no-files-found: error + retention-days: 14 + - name: Require actual regression outcomes + if: always() + env: + NATIVE: ${{ steps.native_tests.outcome }} + CHROME: ${{ steps.chrome.outcome }} + run: '[[ "$NATIVE" == success && "$CHROME" == success ]]' From f892437ba8ef9eb5e6eb17dd043a4eabe0413285 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 14:56:02 +0200 Subject: [PATCH 25/31] test: observe watcher trace writes directly on macOS --- .../native-bun-validation/artifact-tests.py | 26 ++++++++++-------- .../canonical-watcher-test.patch.gz | Bin 496 -> 610 bytes .github/native-bun-validation/chrome-test.py | 12 +++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index 0e5104ad1d8..bc8e805486e 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -42,7 +42,7 @@ "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", {"test/bundler/bun-build-api.test.ts"}), ("canonical-watcher-test.patch.gz", - "b16e88c921073f6fa1b6e4f714906453ec3f861f6724028cf9dc99453a4fc00b", + "fd2796c31cf5d50270040db55dce53be19528dfed86c56b32ab5b9dc987dc73e", {"test/bake/dev/hot.test.ts"}), ]: patch = (root / ".github/native-bun-validation" / name).read_bytes() @@ -57,9 +57,13 @@ original_contents = original_test.read_bytes() needle = b'const text = readFileSync(trace, "utf8").slice(offset);' assert original_contents.count(needle) == 1 - original_test.write_bytes(original_contents.replace( + diagnostic = original_contents.replace( needle, needle + b'\n console.error("NATIVE_PATH_IDENTITY " + JSON.stringify({ expected: filename, trace: text }));', - )) + ) + timer = b'() => ready.reject(new Error("Watcher control event deadline exceeded")),' + assert diagnostic.count(timer) == 1 + diagnostic = diagnostic.replace(timer, b'() => { console.error("NATIVE_TRACE_AT_TIMEOUT " + JSON.stringify({ trace: readFileSync(trace, "utf8") })); ready.reject(new Error("Watcher control event deadline exceeded")); },') + original_test.write_bytes(diagnostic) try: before = subprocess.run([ str(binary), "test", "test/bake/dev/hot.test.ts", "-t", @@ -69,15 +73,15 @@ (proof / "native-watcher-path-before.log").write_text(before.stdout) identities = [json.loads(line.split("NATIVE_PATH_IDENTITY ", 1)[1]) for line in before.stdout.splitlines() if "NATIVE_PATH_IDENTITY " in line] - aliases = [] - for identity in identities: - for line in identity["trace"].rsplit("\n", 1)[0].splitlines() if "\n" in identity["trace"] else []: - for filename in json.loads(line)["files"]: - if os.path.realpath(identity["expected"]) == filename and os.path.normpath(identity["expected"]) != filename: - aliases.append({"fixturePath": identity["expected"], "nativePath": filename}) - assert before.returncode != 0 and aliases, "Reproduce a mismatched alias in the original test oracle" + final_traces = [json.loads(line.split("NATIVE_TRACE_AT_TIMEOUT ", 1)[1])["trace"] + for line in before.stdout.splitlines() if "NATIVE_TRACE_AT_TIMEOUT " in line] + expected_file = identities[-1]["expected"] + native_events = [json.loads(line) for trace in final_traces for line in trace.splitlines()] + assert before.returncode != 0 and any(expected_file in event["files"] for event in native_events), \ + "The native event must exist even though the test observer did not wake" (proof / "native-watcher-path-before.json").write_text(json.dumps({ - "failedBefore": True, "samePhysicalFile": aliases, + "failedBefore": True, "expectedFile": expected_file, + "nativeEventPresentAtTimeout": True, "events": native_events, }, indent=2) + "\n") finally: original_test.write_bytes(original_contents) diff --git a/.github/native-bun-validation/canonical-watcher-test.patch.gz b/.github/native-bun-validation/canonical-watcher-test.patch.gz index 6ef7aba536d526e30a87bc8f166d0f483f299954..de1c4a416f926997796528a213f7d61f9c7a9c85 100644 GIT binary patch literal 610 zcmV-o0-gOIiwFP!000003Z+v^PuwsNzVELX`G68_;(Z9ZDE>@jP| z+SHzX3Ha}olU`6>-YQb)|gHqpX_H7=-2yn3fg%{ zq_crQkeeI%Q;?ipmgpHM;7gmyS7FNR0h4WvXCGV;TQJHvg1W5|TDU{At zC~O4P|5%C)Tp7?WQC$j}K>_52#Aj?9i98CmfnvvquMEwuFt}=oKAbF_QKw0I{4!3? zP~JkZt=mZqKz;-FwKbm)qBZsYA#38Qp>mHmC@Dejo$mtcxCZdpa$<*iD~pE$R4M1_i_X;#}b8jqt-&Eo?`iP)f^aLF}B zdDwuZ9M^X!iIY3Wgnb!4oDUzq4q2Ob(=RP{-Fbtelk%*-Ek-QmglmfJ*)qC;@N7^T zwQy|$h3^|HlX@Va4~%b1v9#;=f2YadwVvv_+>+Odd7~*4ECW`?O|qBm-~6pjg>^)u w$c-~LY0gCvgJEy)g<)sFN=|EHaMVE3T@~`_hLCS=jDCQ$1IhUh~r1a5Gj-6bRkxhE@_kIh7*62u*2f- zxj^Y9?a;pJP+xYlBzbew?#Zj`1v>3^zt;=mIDXAL2*dDI|M3`cC%Q)Hf8%k0G{v1^ z_`CyYS6Kq*g26fAL6vJ`IVp)nk{f=2(o9y0jG!E3r88DWiz2{5iDwAOWN(Wi0`1n6 zFO`LpT6DCrl0SpAHUSlB-uZJ_%u-Lmw(fZ`Ur2j`}IQ_ zi)LoDV+b~-%I3Zi&w`QoE=A!e0^5pywD26@^t}Xs3Xd-WTcLPj?A#BeDOItb+W?NO z(vK00l#Uo9w7qS3vOP*Mx|n>T1*^@;sWm*W#S&MxX1+I?ttpz#7Dn$biv|w8GVMJ4 meA7*~BBKb6isjozD{+O&sClUKl2-G)OYjTPobOBY0{{Rzi}hIm diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py index e44becba0a0..28d92a7ec34 100644 --- a/.github/native-bun-validation/chrome-test.py +++ b/.github/native-bun-validation/chrome-test.py @@ -21,14 +21,18 @@ # Use Bun's CI runner and its existing startup budget; do not override a test timeout. command = [ "node", "scripts/runner.node.ts", "--exec-path", str(binary), - "--retries", "0", "--junit", "--junit-temp-dir", prefix, + "--retries", "0", "--vendor", "false", "--junit", "--junit-temp-dir", prefix, "--results-json", str(proof / "native-chrome-runner.json"), - "test/js/bun/webview/webview-chrome.test.ts", + "js/bun/webview/webview-chrome.test.ts", ] -result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + env={**os.environ, "PATH": str(binary.parent) + os.pathsep + os.environ["PATH"]}) (proof / "native-chrome.log").write_text(result.stdout) print(result.stdout, end="") -reports = [path for folder in Path(tempfile.gettempdir()).glob(prefix + "*") for path in folder.glob("*.xml")] +reports = [path for base in {Path(tempfile.gettempdir()), Path("/tmp")} + for folder in base.glob(prefix + "*") for path in folder.glob("*.xml")] +reports = [path for path in {path.resolve() for path in reports} + if any(case.attrib.get("name", "") == title for case in ET.parse(path).findall(".//testcase"))] assert len(reports) == 1, f"Expected the CI runner's JUnit report: {reports}" shutil.copyfile(reports[0], report) all_cases = ET.parse(report).findall(".//testcase") From b64d31beafdfa09487461748e5543f5c6f9e7548 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 15:04:58 +0200 Subject: [PATCH 26/31] test: isolate native artifact execution from CI helper lifetime --- .../native-bun-validation/artifact-tests.py | 4 +-- .github/native-bun-validation/chrome-test.py | 34 +++++++------------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index bc8e805486e..a45baa619a5 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -72,9 +72,9 @@ env={**os.environ, "BUN_DEV_SERVER_VERBOSE_SYNC": "1"}) (proof / "native-watcher-path-before.log").write_text(before.stdout) identities = [json.loads(line.split("NATIVE_PATH_IDENTITY ", 1)[1]) - for line in before.stdout.splitlines() if "NATIVE_PATH_IDENTITY " in line] + for line in before.stdout.splitlines() if line.startswith("NATIVE_PATH_IDENTITY ")] final_traces = [json.loads(line.split("NATIVE_TRACE_AT_TIMEOUT ", 1)[1])["trace"] - for line in before.stdout.splitlines() if "NATIVE_TRACE_AT_TIMEOUT " in line] + for line in before.stdout.splitlines() if line.startswith("NATIVE_TRACE_AT_TIMEOUT ")] expected_file = identities[-1]["expected"] native_events = [json.loads(line) for trace in final_traces for line in trace.splitlines()] assert before.returncode != 0 and any(expected_file in event["files"] for event in native_events), \ diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py index 28d92a7ec34..145f62b0b07 100644 --- a/.github/native-bun-validation/chrome-test.py +++ b/.github/native-bun-validation/chrome-test.py @@ -2,10 +2,7 @@ import json import os from pathlib import Path -import shutil import subprocess -import tempfile -import uuid import xml.etree.ElementTree as ET @@ -16,35 +13,28 @@ expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] report = proof / "native-chrome.xml" -prefix = "native-final-chrome-" + uuid.uuid4().hex + "-" title = "HMR applies a large update before the following small update" -# Use Bun's CI runner and its existing startup budget; do not override a test timeout. +# Match the existing CI runner's budget without starting its crash-remap service. +runner = (source / "scripts/runner.node.ts").read_text() +assert "const testTimeout = 3 * 60_000;" in runner +assert "const perTestTimeout = Math.ceil(timeout / 2) * (isAsan ? 3 : 1);" in runner command = [ - "node", "scripts/runner.node.ts", "--exec-path", str(binary), - "--retries", "0", "--vendor", "false", "--junit", "--junit-temp-dir", prefix, - "--results-json", str(proof / "native-chrome-runner.json"), - "js/bun/webview/webview-chrome.test.ts", + str(binary), "test", "test/js/bun/webview/webview-chrome.test.ts", "-t", title, + "--timeout=90000", "--reporter=junit", f"--reporter-outfile={report}", ] -result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - env={**os.environ, "PATH": str(binary.parent) + os.pathsep + os.environ["PATH"]}) +result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) (proof / "native-chrome.log").write_text(result.stdout) print(result.stdout, end="") -reports = [path for base in {Path(tempfile.gettempdir()), Path("/tmp")} - for folder in base.glob(prefix + "*") for path in folder.glob("*.xml")] -reports = [path for path in {path.resolve() for path in reports} - if any(case.attrib.get("name", "") == title for case in ET.parse(path).findall(".//testcase"))] -assert len(reports) == 1, f"Expected the CI runner's JUnit report: {reports}" -shutil.copyfile(reports[0], report) -all_cases = ET.parse(report).findall(".//testcase") +all_cases = ET.parse(report).findall(".//testcase") if report.exists() else [] cases = [case for case in all_cases if case.attrib.get("name", "") == title] passed = result.returncode == 0 and len(cases) == 1 and all( not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) for case in cases -) +) and all(case.find("skipped") is not None for case in all_cases if case not in cases) (proof / "native-chrome.json").write_text(json.dumps({ "binarySha256": expected["sha256"], "title": title, - "cases": len(cases), "passed": passed, "runnerCommand": command, - "fullFileCases": len(all_cases), - "fullFileSkipped": sum(case.find("skipped") is not None for case in all_cases), + "cases": len(cases), "filteredOut": len(all_cases) - len(cases), "passed": passed, + "budgetSource": "scripts/runner.node.ts: testTimeout / 2 (stable CI)", + "command": command, }, indent=2) + "\n") assert passed, "Native Chromium ordering regression must execute and pass" From 152f4f2d3d4c9c9cbc877e93b20494feb2e4f795 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 15:10:37 +0200 Subject: [PATCH 27/31] test: await native trace conditions without a second watcher --- .github/native-bun-validation/artifact-tests.py | 6 +++--- .../canonical-watcher-test.patch.gz | Bin 610 -> 0 bytes .../watcher-poll-test.patch.gz | Bin 0 -> 958 bytes 3 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 .github/native-bun-validation/canonical-watcher-test.patch.gz create mode 100644 .github/native-bun-validation/watcher-poll-test.patch.gz diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py index a45baa619a5..46a006fdde9 100644 --- a/.github/native-bun-validation/artifact-tests.py +++ b/.github/native-bun-validation/artifact-tests.py @@ -41,8 +41,8 @@ ("input-map-sync-test.patch.gz", "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", {"test/bundler/bun-build-api.test.ts"}), - ("canonical-watcher-test.patch.gz", - "fd2796c31cf5d50270040db55dce53be19528dfed86c56b32ab5b9dc987dc73e", + ("watcher-poll-test.patch.gz", + "9b519899a32da4eb217e3131e62d4ea2934805703d41dec1503f881a8e3f9743", {"test/bake/dev/hot.test.ts"}), ]: patch = (root / ".github/native-bun-validation" / name).read_bytes() @@ -52,7 +52,7 @@ paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) assert all(old == new for old, new in paths) assert {old.decode() for old, _ in paths} == allowed_paths - if name == "canonical-watcher-test.patch.gz": + if name == "watcher-poll-test.patch.gz": original_test = source / "test/bake/dev/hot.test.ts" original_contents = original_test.read_bytes() needle = b'const text = readFileSync(trace, "utf8").slice(offset);' diff --git a/.github/native-bun-validation/canonical-watcher-test.patch.gz b/.github/native-bun-validation/canonical-watcher-test.patch.gz deleted file mode 100644 index de1c4a416f926997796528a213f7d61f9c7a9c85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 610 zcmV-o0-gOIiwFP!000003Z+v^PuwsNzVELX`G68_;(Z9ZDE>@jP| z+SHzX3Ha}olU`6>-YQb)|gHqpX_H7=-2yn3fg%{ zq_crQkeeI%Q;?ipmgpHM;7gmyS7FNR0h4WvXCGV;TQJHvg1W5|TDU{At zC~O4P|5%C)Tp7?WQC$j}K>_52#Aj?9i98CmfnvvquMEwuFt}=oKAbF_QKw0I{4!3? zP~JkZt=mZqKz;-FwKbm)qBZsYA#38Qp>mHmC@Dejo$mtcxCZdpa$<*iD~pE$R4M1_i_X;#}b8jqt-&Eo?`iP)f^aLF}B zdDwuZ9M^X!iIY3Wgnb!4oDUzq4q2Ob(=RP{-Fbtelk%*-Ek-QmglmfJ*)qC;@N7^T zwQy|$h3^|HlX@Va4~%b1v9#;=f2YadwVvv_+>+Odd7~*4ECW`?O|qBm-~6pjg>^)u w$c-~LY0gCvgJEy)g<)sFN=|EHaMV}UwB4YK&4Uq&E0IO^gJ2WfE@xu5+XPrJ%Er~kLUF<`yxbgJ zL!smZJRx%&6xtg$HgTqm#`~LQ?F}nd{ciLwfv|rTwY!E{Ar<(U6q;hKc)FJMQ_4}#+pR^wHyZ2W_`wtCKo zHDsph;GjZ@B;{;lOzfJ29FleN6roueQx*fY#g?batGm7^LxwMhOHMb5?3wOQ2W z(vel(m1c7@mcsX{GJBCz`%?}gK0!GnNI@e#*oE&3XwBt_xL1$II^E1tvuW?d#ASw< zW9|h(s=typ|WlxSV1}G0AK6y^qPub@FnPIB$V9$zFc0%OG_iFRR_O?FBL6l6<$W ztrk3tach?9tmUOa)p!NtIq z+M~GSnzR}FJ}H(Vgy6+Bv=_KAdny Date: Sat, 24 Oct 2026 15:17:58 +0200 Subject: [PATCH 28/31] test: run complete native macOS validation with final regression synchronization --- .../native-bun-validation/browser-setup.mjs | 64 +++ .github/native-bun-validation/build-macos.sh | 56 ++ .../combined-generator.mjs | 228 ++++++++ .../helper-browser-preload.mjs | 21 + .../native-bun-validation/helper-browser.mjs | 279 +++++++++ .../helper-import-preload.mjs | 13 + .../path-identity-probe.ts | 63 ++ .../pure-bun-graph-browser.mjs | 538 ++++++++++++++++++ .../pure-bun-pending-batches-browser.mjs | 360 ++++++++++++ .../require-tests-reporter.mjs | 29 + .github/workflows/bun-native-validation.yml | 244 +++++++- 11 files changed, 1878 insertions(+), 17 deletions(-) create mode 100644 .github/native-bun-validation/browser-setup.mjs create mode 100644 .github/native-bun-validation/build-macos.sh create mode 100644 .github/native-bun-validation/combined-generator.mjs create mode 100644 .github/native-bun-validation/helper-browser-preload.mjs create mode 100644 .github/native-bun-validation/helper-browser.mjs create mode 100644 .github/native-bun-validation/helper-import-preload.mjs create mode 100644 .github/native-bun-validation/path-identity-probe.ts create mode 100644 .github/native-bun-validation/pure-bun-graph-browser.mjs create mode 100644 .github/native-bun-validation/pure-bun-pending-batches-browser.mjs create mode 100644 .github/native-bun-validation/require-tests-reporter.mjs diff --git a/.github/native-bun-validation/browser-setup.mjs b/.github/native-bun-validation/browser-setup.mjs new file mode 100644 index 00000000000..c68480e2d0d --- /dev/null +++ b/.github/native-bun-validation/browser-setup.mjs @@ -0,0 +1,64 @@ +import { mkdir, readFile, writeFile, chmod } from 'node:fs/promises' +import { createHash } from 'node:crypto' +import { execFileSync } from 'node:child_process' +import path from 'node:path' +import { pathToFileURL } from 'node:url' + +const repo = process.env.GITHUB_WORKSPACE +const binary = path.join(repo, '.native-artifact/binary/bun') +const proof = path.join(repo, '.native-browser-proof') +const cache = path.join(repo, 'packages/router-plugin/.cache/native-validation') +const preload = path.join(cache, 'preload.ts') +const upstream = path.join(repo, '.native-unplugin/dist/index.mjs') +const wrapper = path.join(cache, 'bin/bun') +await mkdir(path.dirname(wrapper), { recursive: true }) +await mkdir(proof, { recursive: true }) +await chmod(binary, 0o755) +const hash = createHash('sha256') + .update(await readFile(binary)) + .digest('hex') +const expected = JSON.parse( + await readFile(path.join(repo, '.native-artifact/binary-proof.json'), 'utf8'), +) +if (hash !== expected.sha256) { + throw new Error('Downloaded native Bun binary hash mismatch') +} +// Bun resolves this mock beside router-plugin's installed unplugin dependency. +await writeFile( + preload, + `import { mock } from 'bun:test'\nimport * as upstream from ${JSON.stringify(pathToFileURL(upstream).href)}\nmock.module('unplugin', () => upstream)\n`, +) +const quote = (value) => `'${value.replaceAll("'", "'\\''")}'` +await writeFile( + wrapper, + `#!/bin/sh\nexec ${quote(binary)} --preload ${quote(preload)} "$@"\n`, +) +await chmod(wrapper, 0o755) +const versions = { + routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: repo, + encoding: 'utf8', + }).trim(), + unpluginHead: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: path.dirname(path.dirname(upstream)), + encoding: 'utf8', + }).trim(), + node: process.version, + bun: execFileSync(binary, ['--version'], { encoding: 'utf8' }).trim(), + binarySha256: hash, + nativeSource: expected, +} +await writeFile( + path.join(proof, 'versions.json'), + JSON.stringify(versions, null, 2) + '\n', +) +await writeFile(path.join(proof, 'preload.ts'), await readFile(preload)) +await writeFile( + process.env.GITHUB_ENV, + `BUN_EXECUTABLE=${binary}\nBUN_PLUGIN_PRELOAD=${preload}\nBUN_DEV_TEST_OUTPUT=${proof}/dev-results\n`, + { flag: 'a' }, +) +await writeFile(process.env.GITHUB_PATH, path.dirname(wrapper) + '\n', { + flag: 'a', +}) +console.log(JSON.stringify(versions, null, 2)) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh new file mode 100644 index 00000000000..e6dadf39d3c --- /dev/null +++ b/.github/native-bun-validation/build-macos.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo="$GITHUB_WORKSPACE" +proof="$repo/.native-proof" +mkdir -p "$proof" +{ + date -u + sw_vers + uname -a + sysctl hw.memsize hw.ncpu + df -h + xcodebuild -version + xcrun --show-sdk-path + node --version + bun --version + python3 --version + brew --version +} | tee "$proof/preflight.log" + +python3 "$repo/.github/native-bun-validation/prepare.py" \ + --bun "$repo/.native-bun" --out "$proof" | tee "$proof/source-verification.json" + +# CONTRIBUTING.md's macOS prerequisites, plus its required LLVM major. +brew update +brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm +export PATH="$(brew --prefix llvm)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" +export RUSTUP_TOOLCHAIN=nightly-2026-09-15 +export CARGO_BUILD_JOBS=1 +export CARGO_INCREMENTAL=0 +if ! command -v rustup >/dev/null; then + rustup-init -y --no-modify-path --profile minimal --default-toolchain none +fi +rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component rust-src +llvm_version="$(llvm-config --version)" +[[ "$llvm_version" =~ ^23\.1\.[0-9]+$ ]] || { echo "Expected LLVM 23.1.x, got $llvm_version"; exit 1; } +{ + brew list --versions + clang --version + llvm-config --version + rustc -vV + cargo --version + rustup show + cmake --version + ninja --version + ccache --version + df -h +} | tee "$proof/toolchain.log" + +cd "$repo/.native-bun" +bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" +bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" + +# The CI build wrapper does not execute trailing arguments. Regressions run +# against the verified binary in the artifact validation job. +GITHUB_SHA="$(git rev-parse HEAD)" bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" diff --git a/.github/native-bun-validation/combined-generator.mjs b/.github/native-bun-validation/combined-generator.mjs new file mode 100644 index 00000000000..6e86bd96879 --- /dev/null +++ b/.github/native-bun-validation/combined-generator.mjs @@ -0,0 +1,228 @@ +import { + mkdtemp, + mkdir, + readFile, + realpath, + rename, + rm, + writeFile, +} from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { + Generator, + getConfig, +} from '../../packages/router-generator/dist/esm/index.js' + +const normalize = (filename) => path.resolve(filename).replaceAll('\\', '/') +const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => + [1, 2].map((depth) => ({ ext, depth, dynamic: false })), +) +cases.push({ ext: 'mjs', depth: 2, dynamic: true }) +const results = [] +const routeNames = ['before', 'after', 'replacement'] +const configSource = (file, dynamic) => + file.endsWith('.cjs') + ? `const routes = require(${JSON.stringify(file)}); export default routes\n` + : dynamic + ? `export default (await import(${JSON.stringify(file)})).default\n` + : `import routes from ${JSON.stringify(file)}; export default routes\n` +const routeConfig = (name) => ({ + type: 'root', + file: '__root.tsx', + children: [{ type: 'route', path: `/${name}`, file: `${name}.tsx` }], +}) +const helperSource = (ext, name) => + ext === 'json' + ? JSON.stringify(routeConfig(name)) + : ext === 'cjs' + ? `module.exports = ${JSON.stringify(routeConfig(name))}\n` + : `export default ${JSON.stringify(routeConfig(name))}\n` + +for (const scenario of cases) { + const root = await realpath( + await mkdtemp(path.join(tmpdir(), 'router-built-helper-')), + ) + const checks = [] + const record = (name, passed, details = undefined) => + checks.push({ name, passed, details }) + try { + const projects = [] + for (const id of ['a', 'b']) { + const project = path.join(root, id) + const routes = path.join(project, 'routes') + await mkdir(routes, { recursive: true }) + await writeFile(path.join(project, 'package.json'), '{"type":"module"}\n') + await writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, + ) + for (const suffix of routeNames) { + const name = `${id}-${suffix}` + await writeFile( + path.join(routes, `${name}.tsx`), + `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/${name}')({})\n`, + ) + } + const filename = path.join(project, `helper.${scenario.ext}`) + const configFile = path.join(project, 'virtual-routes.ts') + const bridge = path.join(project, 'bridge.ts') + await writeFile(filename, helperSource(scenario.ext, `${id}-before`)) + await writeFile( + configFile, + configSource( + scenario.depth === 2 ? './bridge.ts' : `./helper.${scenario.ext}`, + false, + ), + ) + if (scenario.depth === 2) { + await writeFile( + bridge, + configSource(`./helper.${scenario.ext}`, scenario.dynamic), + ) + } + const generatedRouteTree = path.join(project, 'routeTree.gen.ts') + const generator = new Generator({ + root: project, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree, + virtualRouteConfig: 'virtual-routes.ts', + tmpDir: path.join(project, 'tmp'), + disableLogging: true, + }, + project, + ), + }) + projects.push({ + id, + project, + filename, + configFile, + bridge, + generatedRouteTree, + generator, + }) + } + const [a, b] = projects + await Promise.all(projects.map((project) => project.generator.run())) + const expectedFiles = (project) => + [ + project.configFile, + ...(scenario.depth === 2 ? [project.bridge] : []), + project.filename, + ] + .map(normalize) + .sort() + for (const project of projects) { + const deps = project.generator + .getWatchDependencies() + .files.map(normalize) + .sort() + record( + `${project.id}:watch-dependencies`, + JSON.stringify(deps) === JSON.stringify(expectedFiles(project)), + { + expected: expectedFiles(project).map((filename) => + path.relative(root, filename), + ), + actual: deps.map((filename) => path.relative(root, filename)), + }, + ) + record( + `${project.id}:initial-tree`, + (await readFile(project.generatedRouteTree, 'utf8')).includes( + `'/${project.id}-before'`, + ), + ) + } + const initialB = await readFile(b.generatedRouteTree, 'utf8') + const stableA = await readFile(a.generatedRouteTree, 'utf8') + await a.generator.run() + record( + 'a:unchanged-generation', + (await readFile(a.generatedRouteTree, 'utf8')) === stableA, + ) + await writeFile(a.filename, helperSource(scenario.ext, 'a-after')) + await a.generator.run({ path: a.filename, type: 'update' }) + const eventTree = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:in-place-update-event', + eventTree.includes("'/a-after'") && !eventTree.includes("'/a-before'"), + ) + await a.generator.run() + const rerunTree = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:in-place-unconditional-rerun', + rerunTree.includes("'/a-after'") && !rerunTree.includes("'/a-before'"), + ) + record( + 'b:unchanged-after-a-edit', + (await readFile(b.generatedRouteTree, 'utf8')) === initialB, + ) + await writeFile( + `${a.filename}.next`, + helperSource(scenario.ext, 'a-replacement'), + ) + await rename(`${a.filename}.next`, a.filename) + await a.generator.run({ path: a.filename, type: 'update' }) + const replaced = await readFile(a.generatedRouteTree, 'utf8') + record( + 'a:atomic-replacement-event', + replaced.includes("'/a-replacement'") && !replaced.includes("'/a-after'"), + ) + await writeFile(b.filename, helperSource(scenario.ext, 'b-after')) + await b.generator.run({ path: b.filename, type: 'update' }) + record( + 'b:independent-update-event', + (await readFile(b.generatedRouteTree, 'utf8')).includes("'/b-after'"), + ) + await a.generator.run() + record( + 'a:no-cross-generator-leakage', + (await readFile(a.generatedRouteTree, 'utf8')) === replaced, + ) + record( + 'watch-dependencies-remain-isolated', + projects.every((project) => { + const deps = project.generator + .getWatchDependencies() + .files.map(normalize) + return ( + JSON.stringify(deps.sort()) === JSON.stringify(expectedFiles(project)) + ) + }), + ) + } catch (error) { + record( + 'execution', + false, + error instanceof Error ? error.stack : String(error), + ) + } finally { + await rm(root, { recursive: true, force: true }) + } + results.push({ + ...scenario, + passed: checks.every((check) => check.passed), + checks, + }) +} +const report = { + runtime: { + bun: process.versions.bun ?? null, + node: process.versions.node, + platform: process.platform, + arch: process.arch, + }, + mode: process.env.JITI_COMBINED_MODE ?? 'installed', + generator: 'packages/router-generator/dist/esm/index.js', + cases: results.length, + passed: results.filter((result) => result.passed).length, + results, +} +console.log(JSON.stringify(report, null, 2)) +if (report.passed !== report.cases) { + process.exitCode = 1 +} diff --git a/.github/native-bun-validation/helper-browser-preload.mjs b/.github/native-bun-validation/helper-browser-preload.mjs new file mode 100644 index 00000000000..42abdf9a47e --- /dev/null +++ b/.github/native-bun-validation/helper-browser-preload.mjs @@ -0,0 +1,21 @@ +import { fileURLToPath, pathToFileURL } from 'node:url' +import path from 'node:path' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +await import( + pathToFileURL( + path.join( + root, + 'packages/router-plugin/.cache/helper-browser-override.mjs', + ), + ).href +) +await import( + pathToFileURL( + path.join( + root, + 'packages/router-generator/.cache/helper-browser-override.mjs', + ), + ).href +) diff --git a/.github/native-bun-validation/helper-browser.mjs b/.github/native-bun-validation/helper-browser.mjs new file mode 100644 index 00000000000..e5070f698e5 --- /dev/null +++ b/.github/native-bun-validation/helper-browser.mjs @@ -0,0 +1,279 @@ +import assert from 'node:assert/strict' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath, pathToFileURL } from 'node:url' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +process.env.ROUTER_REPOSITORY_ROOT = root +if (!process.env.BUN_EXECUTABLE) { + throw new Error('Set BUN_EXECUTABLE to the native Bun candidate') +} +process.env.BUN_PLUGIN_PRELOAD ??= fileURLToPath( + new URL('./helper-browser-preload.mjs', import.meta.url), +) +for (const [pkg, name, env, fallback] of [ + [ + 'router-plugin', + 'unplugin', + 'UNPLUGIN_CANDIDATE_ENTRY', + '.cache/upstream-drafts/unplugin/dist/index.mjs', + ], + [ + 'router-generator', + 'jiti', + 'JITI_CANDIDATE_ENTRY', + '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', + ], +]) { + const directory = path.join(root, 'packages', pkg, '.cache') + await mkdir(directory, { recursive: true }) + await writeFile( + path.join(directory, 'helper-browser-override.mjs'), + `import { mock } from 'bun:test'\nimport { pathToFileURL } from 'node:url'\nimport path from 'node:path'\nconst entry = process.env[${JSON.stringify(env)}] ?? path.join(process.env.ROUTER_REPOSITORY_ROOT, ${JSON.stringify(fallback)})\nconst actual = await import(pathToFileURL(path.resolve(entry)).href)\nmock.module(${JSON.stringify(name)}, () => actual)\n`, + ) +} +const projectRequire = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +) +const { chromium, expect } = projectRequire('@playwright/test') +const { startDevFixture } = await import( + pathToFileURL( + path.join(root, 'e2e/react-router/bun-basic-file-based/dev-fixture.ts'), + ).href +) +const output = + process.env.HELPER_BROWSER_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/helper-browser-${process.platform}.json`, + ) +const logFile = output.replace(/\.json$/, '.log') +await mkdir(path.dirname(output), { recursive: true }) +const log = [] +const say = (message) => { + log.push(message) + console.log(message) +} +const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => + [1, 2].map((depth) => ({ ext, depth, dynamic: false })), +) +cases.push({ ext: 'mjs', depth: 2, dynamic: true }) +const results = [] +const configSource = (file, dynamic = false) => + file.endsWith('.cjs') + ? `const config = require(${JSON.stringify(file)}); export default config\n` + : dynamic + ? `export default (await import(${JSON.stringify(file)})).default\n` + : `import config from ${JSON.stringify(file)}; export default config\n` +const configValue = (included) => ({ + type: 'root', + file: '__root.tsx', + children: [ + { type: 'index', file: 'index.tsx' }, + { type: 'route', path: '/about', file: 'about.tsx' }, + { + type: 'route', + path: `/virtual-${included}`, + file: `../virtual-pages/${included}.tsx`, + }, + ], +}) +const helperSource = (ext, included) => + ext === 'json' + ? JSON.stringify(configValue(included)) + : ext === 'cjs' + ? `module.exports = ${JSON.stringify(configValue(included))}\n` + : `export default ${JSON.stringify(configValue(included))}\n` +const sha256 = async (filename) => + createHash('sha256') + .update(await readFile(filename)) + .digest('hex') +const browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), +}) +try { + for (const scenario of cases) { + const name = `${scenario.ext}-depth${scenario.depth}${scenario.dynamic ? '-dynamic' : ''}` + say(`START ${name}`) + const result = { + ...scenario, + passed: false, + steps: [], + browserErrors: [], + documentLoads: 0, + } + let native, context + try { + native = await startDevFixture({ + virtualConfigFile: true, + virtualConfigHelperDepth: 1, + }) + result.pid = native.pid + result.versions = native.versions + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.__helperBrowserDocumentToken = crypto.randomUUID() + }) + const page = await context.newPage() + page.on('load', () => { + result.documentLoads++ + }) + page.on('pageerror', (error) => + result.browserErrors.push({ + type: 'pageerror', + message: error.message, + }), + ) + page.on('console', (message) => { + if ( + message.type() === 'error' && + !message.location().url.endsWith('/favicon.ico') + ) { + result.browserErrors.push({ + type: 'console', + message: message.text(), + location: message.location(), + }) + } + }) + const heading = page.getByRole('heading') + const goHome = async () => { + await page.getByRole('link', { name: 'Home', exact: true }).click() + await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) + } + const checkpoint = async (phase, included) => { + await expect + .poll( + async () => { + native.assertAlive() + const tree = await native.tree() + return ( + tree.includes(`/virtual-${included}`) && + !tree.includes( + `/virtual-${included === 'after' ? 'before' : 'after'}`, + ) + ) + }, + { + timeout: 15000, + message: `${name} ${phase}: automatic route-tree update`, + }, + ) + .toBe(true) + await page + .getByRole('link', { name: `Virtual ${included}`, exact: true }) + .click() + await expect(heading).toHaveText(`VIRTUAL_${included.toUpperCase()}`, { + timeout: 15000, + }) + native.assertAlive() + assert.deepEqual( + await (await fetch(new URL('/__native-info', native.url))).json(), + { pid: native.pid }, + ) + result.steps.push({ + phase, + route: `/virtual-${included}`, + samePid: true, + documentToken: await page.evaluate( + () => globalThis.__helperBrowserDocumentToken, + ), + documentLoads: result.documentLoads, + browserErrorCount: result.browserErrors.length, + }) + await goHome() + } + await page.goto(native.url) + await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) + await checkpoint('ts-bootstrap', 'before') + const helper = `config/browser-helper.${scenario.ext}` + await native.save(helper, helperSource(scenario.ext, 'after')) + if (scenario.depth === 2) { + await native.save( + 'config/browser-bridge.ts', + configSource(`./browser-helper.${scenario.ext}`, scenario.dynamic), + ) + } + await native.save( + 'virtual-routes.ts.next', + configSource( + scenario.depth === 2 + ? './config/browser-bridge.ts' + : `./config/browser-helper.${scenario.ext}`, + ), + ) + await native.rename('virtual-routes.ts.next', 'virtual-routes.ts') + await checkpoint('helper-graph-loaded', 'after') + await native.save(helper, helperSource(scenario.ext, 'before')) + await checkpoint('helper-in-place-edit', 'before') + await native.save(`${helper}.next`, helperSource(scenario.ext, 'after')) + await native.rename(`${helper}.next`, helper) + await checkpoint('helper-atomic-replacement', 'after') + assert.deepEqual( + result.browserErrors, + [], + `${name}: unexpected browser errors`, + ) + const serverErrors = native + .logs() + .split(/\r?\n/) + .filter((line) => /^(?:error:|panic:|thread .* panicked)/i.test(line)) + assert.deepEqual(serverErrors, [], `${name}: unexpected server errors`) + result.passed = true + say( + `PASS ${name}: browser navigation + automatic tree updates, in-place/atomic, same PID ${native.pid}, no browser errors`, + ) + } catch (error) { + result.error = error instanceof Error ? error.stack : String(error) + result.serverLog = native?.logs().slice(-12000) + say(`FAIL ${name}: ${String(error).split('\n')[0]}`) + } finally { + try { + await context?.close() + } finally { + await native?.close() + } + } + results.push(result) + await writeFile( + output, + JSON.stringify( + { + platform: process.platform, + node: process.version, + passed: results.filter((result) => result.passed).length, + cases: cases.length, + results, + }, + null, + 2, + ) + '\n', + ) + await writeFile(logFile, log.join('\n') + '\n') + } +} finally { + await browser.close() +} +const report = { + platform: process.platform, + arch: process.arch, + node: process.version, + binary: process.env.BUN_EXECUTABLE, + binarySha256: await sha256(process.env.BUN_EXECUTABLE), + preload: process.env.BUN_PLUGIN_PRELOAD, + passed: results.filter((result) => result.passed).length, + cases: cases.length, + results, +} +await writeFile(output, JSON.stringify(report, null, 2) + '\n') +say(`RESULT ${report.passed}/${report.cases} PASS; evidence ${output}`) +await writeFile(logFile, log.join('\n') + '\n') +if (report.passed !== report.cases) { + process.exitCode = 1 +} diff --git a/.github/native-bun-validation/helper-import-preload.mjs b/.github/native-bun-validation/helper-import-preload.mjs new file mode 100644 index 00000000000..d871bbce50c --- /dev/null +++ b/.github/native-bun-validation/helper-import-preload.mjs @@ -0,0 +1,13 @@ +import { mock } from 'bun:test' +import { fileURLToPath, pathToFileURL } from 'node:url' +import path from 'node:path' +const repository = fileURLToPath(new URL('../../../', import.meta.url)) +const candidateEntry = process.env.JITI_CANDIDATE_ENTRY + ? path.resolve(process.env.JITI_CANDIDATE_ENTRY) + : path.join( + repository, + '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', + ) +const candidate = await import(pathToFileURL(candidateEntry).href) +mock.module('jiti', () => candidate) +process.env.JITI_COMBINED_MODE = 'candidate' diff --git a/.github/native-bun-validation/path-identity-probe.ts b/.github/native-bun-validation/path-identity-probe.ts new file mode 100644 index 00000000000..0627529087c --- /dev/null +++ b/.github/native-bun-validation/path-identity-probe.ts @@ -0,0 +1,63 @@ +import { mkdtemp, mkdir, realpath, symlink, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { dirname, join, resolve } from 'node:path' + +// Public API diagnostic only. Preserve the tiny fixture for artifact inspection. +const base = process.env.BUN_PATH_PROBE_ROOT ?? tmpdir() +const directory = await mkdtemp(join(base, 'bun-path-identity-')) +const source = join(directory, 'source') +await mkdir(source) +await writeFile(join(source, 'entry.ts'), 'export const value = 42;\n') +const alias = join(directory, 'alias') +await symlink(source, alias, process.platform === 'win32' ? 'junction' : 'dir') + +const results = [] +for (const entrypoint of [join(source, 'entry.ts'), join(alias, 'entry.ts')]) { + const loads: Array<{ path: string; resolveDir: string }> = [] + let exactPathHookCalls = 0 + const exactFilter = new RegExp( + `^${entrypoint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, + ) + const result = await Bun.build({ + entrypoints: [entrypoint], + write: false, + plugins: [ + { + name: 'public-path-identity', + setup(build) { + build.onLoad({ filter: exactFilter }, () => { + exactPathHookCalls++ + }) + build.onLoad({ filter: /entry\.ts$/ }, (args) => { + loads.push({ path: args.path, resolveDir: dirname(args.path) }) + }) + }, + }, + ], + }) + results.push({ + entrypoint, + resolved: resolve(entrypoint), + realpath: await realpath(entrypoint), + exactPathHookCalls, + loads, + success: result.success, + logs: result.logs.map((log) => log.message), + }) +} +console.log( + JSON.stringify( + { + platform: process.platform, + arch: process.arch, + version: Bun.version, + revision: Bun.revision, + tmpdir: tmpdir(), + tmpdirRealpath: await realpath(tmpdir()), + directory, + results, + }, + null, + 2, + ), +) diff --git a/.github/native-bun-validation/pure-bun-graph-browser.mjs b/.github/native-bun-validation/pure-bun-graph-browser.mjs new file mode 100644 index 00000000000..56d26eea78d --- /dev/null +++ b/.github/native-bun-validation/pure-bun-graph-browser.mjs @@ -0,0 +1,538 @@ +import assert from 'node:assert/strict' +import { spawn, execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { + mkdtemp, + mkdir, + readFile, + realpath, + writeFile, + rm, +} from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +const requireProject = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +) +const { chromium, expect } = requireProject('@playwright/test') +const sourceMapMode = process.env.PURE_BUN_SOURCE_MAPS === '1' +const largePairMode = process.env.PURE_BUN_LARGE_PAIR === '1' +const pluginRequire = createRequire( + path.join(root, 'packages/router-plugin/package.json'), +) +const babelRequire = createRequire(pluginRequire.resolve('@babel/core')) +const { AnyMap, originalPositionFor, sourceContentFor } = createRequire( + babelRequire.resolve('@jridgewell/remapping'), +)('@jridgewell/trace-mapping') +const binaries = [ + ['candidate', process.env.BUN_EXECUTABLE], + ['baseline', process.env.BUN_BASELINE_EXECUTABLE], + ['debug', process.env.BUN_DEBUG_EXECUTABLE], +].filter(([, binary]) => binary) +assert.ok(binaries.length, 'Set BUN_EXECUTABLE') +const output = + process.env.PURE_BUN_BROWSER_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/pure-bun-graph-${process.platform}.json`, + ) +await mkdir(path.dirname(output), { recursive: true }) +const browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), +}) +const results = [] +const mentions = (text) => + ['before.ts', 'after.ts', 'graph.ts', 'main.ts'].filter((name) => + text.includes(name), + ) +try { + for (const [label, binary] of binaries) { + for (const reloadWhileAfter of sourceMapMode + ? [true] + : largePairMode + ? [false] + : [false, true]) { + const name = `${label}-${reloadWhileAfter ? 'reload-B' : 'automatic'}` + console.log(`START ${name}`) + const directory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')), + ) + const result = { + name, + label, + binary, + reloadWhileAfter, + sourceMapMode, + largePairMode, + passed: false, + steps: [], + errors: [], + websocketFrames: [], + initialJavaScript: [], + documentLoads: 0, + } + let child, + context, + logs = '' + try { + await writeFile( + path.join(directory, 'index.html'), + '
', + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value} from './graph.ts';document.querySelector('#app').textContent=value;if(import.meta.hot)import.meta.hot.accept();`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value} from './before.ts';`, + ) + await writeFile( + path.join(directory, 'before.ts'), + `export const value='BEFORE';`, + ) + await writeFile( + path.join(directory, 'after.ts'), + `export const value='AFTER';`, + ) + const authoredSource = `export const value = 'BEFORE';\nexport function authoredThrow() {\n throw new Error('CACHED_CLOSURE_AUTHORED_THROW');\n}\n` + if (sourceMapMode) { + await writeFile( + path.join(directory, 'before.ts'), + `export {value, authoredThrow} from './cached-leaf.ts';`, + ) + await writeFile( + path.join(directory, 'cached-leaf.ts'), + authoredSource, + ) + await writeFile( + path.join(directory, 'after.ts'), + `export const value='AFTER';export function authoredThrow(){throw new Error('UNEXPECTED_AFTER_THROW')}`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value,authoredThrow} from './graph.ts';document.querySelector('#app').textContent=value;globalThis.__throwCached=authoredThrow;if(import.meta.hot)import.meta.hot.accept();`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value,authoredThrow} from './before.ts';`, + ) + } + if (largePairMode) { + await writeFile( + path.join(directory, 'shared.ts'), + `globalThis.sharedInits=(globalThis.sharedInits??0)+1;export const shared={initializations:globalThis.sharedInits};`, + ) + await writeFile( + path.join(directory, 'after.ts'), + `import {shared} from './shared.ts';export {shared};export const value='AFTER';export const padding={${Array.from({ length: Number(process.env.PURE_BUN_LARGE_FUNCTIONS ?? 40000) }, (_, index) => `k${index}:()=>${index}`).join(',')}};`, + ) + await writeFile( + path.join(directory, 'before.ts'), + `import {shared} from './shared.ts';export {shared};export const value='BEFORE';`, + ) + await writeFile( + path.join(directory, 'graph.ts'), + `export {value,shared} from './before.ts';`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {value,shared} from './graph.ts';import {shared as stable} from './shared.ts';document.querySelector('#app').textContent=value;globalThis.__pureShared={identity:shared===stable,initializations:shared.initializations};if(import.meta.hot){import.meta.hot.accept();import.meta.hot.on('bun:beforeUpdate',()=>console.debug('__PURE_LIFECYCLE__before'));import.meta.hot.on('bun:afterUpdate',()=>console.debug('__PURE_LIFECYCLE__after'));}`, + ) + } + await writeFile( + path.join(directory, 'server.ts'), + `import html from './index.html';const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}});console.log('READY '+JSON.stringify({url:server.url.href,pid:process.pid}));`, + ) + let readyResolve, readyReject + const ready = new Promise((resolve, reject) => { + readyResolve = resolve + readyReject = reject + }) + child = spawn(binary, ['server.ts'], { + cwd: directory, + env: { ...process.env, NODE_ENV: 'development' }, + stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, + }) + child.on('error', readyReject) + child.on('exit', (code, signal) => + readyReject(new Error(`Bun exited (${code},${signal})\n${logs}`)), + ) + let pending = '' + child.stdout.on('data', (chunk) => { + logs += chunk + pending += chunk + let newline + while ((newline = pending.indexOf('\n')) !== -1) { + const line = pending.slice(0, newline) + pending = pending.slice(newline + 1) + if (line.startsWith('READY ')) { + try { + readyResolve(JSON.parse(line.slice(6))) + } catch (error) { + readyReject(error) + } + } + } + }) + child.stderr.on('data', (chunk) => { + logs += chunk + }) + let timer + const info = await Promise.race([ + ready, + new Promise((_, reject) => { + timer = setTimeout( + () => reject(new Error(`Startup deadline\n${logs}`)), + 20000, + ) + }), + ]).finally(() => clearTimeout(timer)) + result.pid = info.pid + result.revision = execFileSync(binary, ['--revision'], { + encoding: 'utf8', + }).trim() + result.binarySha256 = createHash('sha256') + .update(await readFile(binary)) + .digest('hex') + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.__pureGraphDocumentToken = crypto.randomUUID() + }) + if (largePairMode) { + await context.addInitScript(() => { + const key = Symbol.for('bun:hmr') + let callback + Object.defineProperty(globalThis, key, { + configurable: true, + get() { + return callback + }, + set(original) { + callback = function (...args) { + const record = (kind) => + console.debug( + '__PURE_CALLBACK__' + + JSON.stringify({ + kind, + id: args[1], + keys: Object.keys(args[0]), + time: performance.now(), + documentToken: globalThis.__pureGraphDocumentToken, + }), + ) + record('start') + try { + return Reflect.apply(original, this, args) + } finally { + record('return') + } + } + }, + }) + }) + } + const page = await context.newPage() + const session = sourceMapMode ? await context.newCDPSession(page) : null + const scripts = new Map() + if (session) { + session.on('Debugger.scriptParsed', (script) => + scripts.set(script.scriptId, script), + ) + await session.send('Debugger.enable') + } + let phase = 'initial-A' + let pairedWrite + const assets = [] + page.on('load', () => { + result.documentLoads++ + }) + page.on('console', (message) => { + if (message.type() === 'error') { + result.errors.push({ phase, type: 'console', text: message.text() }) + } + }) + page.on('console', (message) => { + if (message.text().startsWith('__PURE_CALLBACK__')) { + ;(result.callbackEvents ??= []).push({ + ...JSON.parse(message.text().slice('__PURE_CALLBACK__'.length)), + phase, + }) + } + if (message.text().startsWith('__PURE_LIFECYCLE__')) { + ;(result.lifecycleEvents ??= []).push({ + phase, + event: message.text().slice('__PURE_LIFECYCLE__'.length), + }) + } + }) + page.on('pageerror', (error) => + result.errors.push({ phase, type: 'pageerror', text: error.message }), + ) + page.on('websocket', (socket) => + socket.on('framereceived', (event) => { + const bytes = Buffer.from(event.payload) + const sourceMapId = bytes + .toString('utf8') + .match( + /sourceMappingURL=\/_bun\/client\/([a-f0-9]{16})\.js\.map/, + )?.[1] + result.websocketFrames.push({ + phase, + bytes: bytes.length, + ...(sourceMapId ? { sourceMapId } : {}), + mentionedModules: mentions(bytes.toString('utf8')), + base64: bytes.toString('base64'), + }) + if ( + largePairMode && + phase === 'A-to-B' && + !pairedWrite && + bytes.toString('utf8').includes('self[Symbol.for("bun:hmr")]') + ) { + pairedWrite = writeFile( + path.join(directory, 'graph.ts'), + `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-TWO';`, + ) + } + }), + ) + page.on('response', (response) => { + if (new URL(response.url()).pathname.endsWith('.js')) { + const responsePhase = phase + assets.push( + response + .text() + .then(async (text) => { + const file = output.replace( + /\.json$/, + `-${name}-js${result.initialJavaScript.length}.txt`, + ) + result.initialJavaScript.push({ + phase: responsePhase, + url: response.url(), + mentionedModules: mentions(text), + file, + }) + await writeFile(file, text) + }) + .catch((error) => + result.initialJavaScript.push({ + phase: responsePhase, + error: String(error), + }), + ), + ) + } + }) + const checkpoint = async (expected) => { + await expect(page.locator('#app')).toHaveText(expected, { + timeout: 15000, + }) + assert.deepEqual( + await (await fetch(new URL('/__info', info.url))).json(), + { pid: info.pid }, + ) + await Promise.all(assets) + result.steps.push({ + phase, + text: expected, + documentToken: await page.evaluate( + () => globalThis.__pureGraphDocumentToken, + ), + documentLoads: result.documentLoads, + errorCount: result.errors.length, + }) + if (largePairMode) { + assert.deepEqual( + await page.evaluate(() => globalThis.__pureShared), + { identity: true, initializations: 1 }, + ) + } + } + const checkAuthoredThrow = async () => { + await session.send('Debugger.setPauseOnExceptions', { state: 'all' }) + let resumePromise + const paused = new Promise((resolve) => + session.once('Debugger.paused', (event) => { + resolve(event) + resumePromise = session.send('Debugger.resume') + }), + ) + const evaluation = session.send('Runtime.evaluate', { + expression: `try { globalThis.__throwCached() } catch(error) { error.message }`, + returnByValue: true, + }) + let pauseTimer + const event = await Promise.race([ + paused, + new Promise((_, reject) => { + pauseTimer = setTimeout( + () => reject(new Error('Expected authored exception pause')), + 15000, + ) + }), + ]).finally(() => clearTimeout(pauseTimer)) + await resumePromise + const evaluated = await evaluation + await session.send('Debugger.setPauseOnExceptions', { state: 'none' }) + assert.equal(evaluated.result.value, 'CACHED_CLOSURE_AUTHORED_THROW') + const frame = event.callFrames[0], + script = scripts.get(frame.location.scriptId) + assert.ok( + script?.sourceMapURL, + 'Throwing script must declare a source map', + ) + const { scriptSource } = await session.send( + 'Debugger.getScriptSource', + { scriptId: script.scriptId }, + ) + const mapUrl = script.sourceMapURL.startsWith('/') + ? new URL(script.sourceMapURL, info.url).href + : new URL( + script.sourceMapURL, + new URL(script.url || info.url, info.url), + ).href + assert.ok(!mapUrl.startsWith('data:'), 'Expected network source map') + const response = await fetch(mapUrl) + assert.equal(response.status, 200) + const map = await response.json(), + trace = AnyMap(map) + const generated = { + line: frame.location.lineNumber + 1, + column: frame.location.columnNumber, + } + const traced = originalPositionFor(trace, generated) + assert.ok(traced.source, 'Authored source is required') + const tracedFile = traced.source.startsWith('file:') + ? fileURLToPath(traced.source) + : path.resolve(directory, traced.source) + assert.equal( + path.normalize(tracedFile), + path.join(directory, 'cached-leaf.ts'), + ) + assert.equal(traced.line, 3) + assert.equal(traced.column, 2) + assert.equal( + sourceContentFor(trace, traced.source, true), + authoredSource, + ) + const snapshot = output.replace(/\.json$/, `-${name}-${phase}-throw`) + await writeFile(snapshot + '.js', scriptSource) + await writeFile(snapshot + '.js.map', JSON.stringify(map)) + ;(result.authoredThrows ??= []).push({ + phase, + scriptUrl: script.url, + sourceMapURL: script.sourceMapURL, + mapUrl, + generated, + traced, + sourceContentMatches: true, + snapshot, + }) + } + await page.goto(info.url) + await checkpoint('BEFORE') + if (sourceMapMode) { + await checkAuthoredThrow() + } + phase = 'A-to-B' + await writeFile( + path.join(directory, 'graph.ts'), + sourceMapMode + ? `export {value,authoredThrow} from './after.ts';` + : largePairMode + ? `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-ONE';` + : `export {value} from './after.ts';`, + ) + await checkpoint(largePairMode ? 'AFTER-TWO' : 'AFTER') + if (largePairMode) { + assert.ok( + pairedWrite, + 'Second public file write was triggered by first HMR frame', + ) + await pairedWrite + assert.equal( + result.documentLoads, + 1, + 'Paired updates must retain the document', + ) + } + if (reloadWhileAfter) { + phase = 'reload-B' + await page.reload() + await checkpoint('AFTER') + } + phase = 'B-to-A' + await writeFile( + path.join(directory, 'graph.ts'), + sourceMapMode + ? `export {value,authoredThrow} from './before.ts';` + : largePairMode + ? `export {value,shared} from './before.ts';` + : `export {value} from './before.ts';`, + ) + await checkpoint('BEFORE') + if (sourceMapMode) { + assert.equal( + result.documentLoads, + 2, + 'Restoration must not fall back to another document reload', + ) + await checkAuthoredThrow() + } + assert.deepEqual(result.errors, [], 'Unexpected browser errors') + result.passed = true + console.log(`PASS ${name}`) + } catch (error) { + result.error = error instanceof Error ? error.stack : String(error) + console.log(`FAIL ${name}: ${String(error).split('\n')[0]}`) + } finally { + result.serverLog = logs + try { + await context?.close() + } finally { + if (child && child.exitCode === null && child.signalCode === null) { + child.kill() + await new Promise((resolve) => child.once('exit', resolve)) + } + await rm(directory, { recursive: true, force: true }) + } + } + results.push(result) + await writeFile( + output, + JSON.stringify( + { + platform: process.platform, + node: process.version, + sourceMapMode, + largePairMode, + passed: results.filter((result) => result.passed).length, + cases: binaries.length * (sourceMapMode || largePairMode ? 1 : 2), + results, + }, + null, + 2, + ) + '\n', + ) + } + } +} finally { + await browser.close() +} +console.log( + `RESULT ${results.filter((result) => result.passed).length}/${results.length}; ${output}`, +) +if (results.some((result) => !result.passed)) { + process.exitCode = 1 +} diff --git a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs new file mode 100644 index 00000000000..a8f22394fd3 --- /dev/null +++ b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs @@ -0,0 +1,360 @@ +import assert from 'node:assert/strict' +import { spawn, execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { watch } from 'node:fs' +import { + mkdtemp, + mkdir, + readFile, + realpath, + writeFile, + rm, +} from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { setTimeout as batchInterval } from 'node:timers/promises' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +const binary = process.env.BUN_EXECUTABLE +assert.ok(binary, 'Set BUN_EXECUTABLE') +const output = + process.env.PENDING_BATCH_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/pure-bun-pending-batches-${process.platform}.json`, + ) +await mkdir(path.dirname(output), { recursive: true }) +const { chromium, expect } = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +)('@playwright/test') +const directory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pending-batches-')), +) +const controlDirectory = await realpath( + await mkdtemp(path.join(tmpdir(), 'bun-pending-control-')), +) +const releaseFile = path.join(controlDirectory, 'release') +const blockThread = process.env.PENDING_BATCH_BLOCK !== '0' +const nativeSync = process.env.PENDING_BATCH_NATIVE_SYNC === '1' +const captureHmr = process.env.PENDING_BATCH_CAPTURE_HMR === '1' +const tracePath = process.env.BUN_WATCHER_TRACE +if (nativeSync) { + assert.ok(tracePath, 'Native batch synchronization needs BUN_WATCHER_TRACE') +} +const result = { + binary, + blockThread, + nativeSync, + tracePath, + binarySha256: createHash('sha256') + .update(await readFile(binary)) + .digest('hex'), + revision: execFileSync(binary, ['--revision'], { encoding: 'utf8' }).trim(), + directory, + controlDirectory, + passed: false, + writes: [], + nativeBatches: [], + ipc: [], + browserErrors: [], + documentLoads: 0, +} +let child, + browser, + context, + logs = '', + page +const assetCaptures = [] +const snapshot = async () => ({ + text: await page.locator('#app').textContent(), + documentToken: await page.evaluate(() => globalThis.documentToken), + documentLoads: result.documentLoads, +}) +const waitNativeBatch = async (name) => { + const wanted = path.join(directory, name + '.ts').replaceAll('\\', '/') + let observer, timer + try { + const event = await new Promise((resolve, reject) => { + const check = async () => { + try { + const text = await readFile(tracePath, 'utf8') + for (const line of text + .slice(0, text.lastIndexOf('\n') + 1) + .split('\n') + .filter(Boolean)) { + const batch = JSON.parse(line) + const entry = Object.entries(batch.files).find( + ([filename]) => filename.replaceAll('\\', '/') === wanted, + ) + if (entry) { + resolve({ + name, + timestamp: batch.timestamp, + path: entry[0], + ...entry[1], + }) + return + } + } + } catch (error) { + if (error.code !== 'ENOENT') { + reject(error) + } + } + } + observer = watch(path.dirname(tracePath), (event, filename) => { + if (String(filename) === path.basename(tracePath)) { + void check() + } + }) + timer = setTimeout( + () => reject(new Error('Native watcher batch deadline for ' + name)), + 15000, + ) + void check() + }) + result.nativeBatches.push(event) + } finally { + observer?.close() + clearTimeout(timer) + } +} +try { + await writeFile( + path.join(directory, 'index.html'), + `

`, + ) + await writeFile( + path.join(directory, 'main.ts'), + `import {a} from './a.ts';import {b} from './b.ts';import {c} from './c.ts';document.querySelector('#app').textContent=[a,b,c].join('|');if(import.meta.hot)import.meta.hot.accept();`, + ) + for (const name of ['a', 'b', 'c']) { + await writeFile( + path.join(directory, name + '.ts'), + `export const ${name}='${name.toUpperCase()}0';\n`, + ) + } + await writeFile( + path.join(directory, 'server.ts'), + ` + import html from './index.html';import {existsSync} from 'node:fs'; + const releaseFile=${JSON.stringify(releaseFile)}; + process.on('message',message=>{ + if(message==='block'){ + process.send({phase:'blocked',time:Date.now()}); + const deadline=Date.now()+15000; + while(!existsSync(releaseFile)){if(Date.now()>deadline){throw new Error('External release deadline exceeded')}} + process.send({phase:'released',time:Date.now()}); + } + }); + const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}}); + process.send({phase:'ready',url:server.url.href,pid:process.pid}); + `, + ) + let readyResolve, readyReject, blockedResolve, releasedResolve + const ready = new Promise((resolve, reject) => { + readyResolve = resolve + readyReject = reject + }) + const blocked = new Promise((resolve) => { + blockedResolve = resolve + }) + const released = new Promise((resolve) => { + releasedResolve = resolve + }) + child = spawn(binary, ['server.ts'], { + cwd: directory, + env: { ...process.env, NODE_ENV: 'development' }, + stdio: ['ignore', 'pipe', 'pipe', 'ipc'], + windowsHide: true, + }) + child.on('error', readyReject) + child.on('exit', (code, signal) => + readyReject(new Error(`Server exited ${code}/${signal}: ${logs}`)), + ) + child.stdout.on('data', (chunk) => { + logs += chunk + }) + child.stderr.on('data', (chunk) => { + logs += chunk + }) + child.on('message', (message) => { + result.ipc.push(message) + if (message.phase === 'ready') { + readyResolve(message) + } + if (message.phase === 'blocked') { + blockedResolve(message) + } + if (message.phase === 'released') { + releasedResolve(message) + } + }) + const deadline = async (promise, label) => { + let timer + return Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout( + () => reject(new Error(`${label} deadline: ${logs}`)), + 20000, + ) + }), + ]).finally(() => clearTimeout(timer)) + } + const info = await deadline(ready, 'Startup') + result.pid = info.pid + browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), + }) + context = await browser.newContext() + await context.addInitScript(() => { + globalThis.documentToken = crypto.randomUUID() + }) + page = await context.newPage() + if (captureHmr) { + result.websocketFrames = [] + result.initialJavaScript = [] + const session = await context.newCDPSession(page) + await session.send('Network.enable') + session.on('Network.webSocketFrameReceived', (event) => { + const { opcode, payloadData } = event.response + const bytes = Buffer.from(payloadData, opcode === 2 ? 'base64' : 'utf8') + const decoded = bytes.toString('utf8') + const frame = { + requestId: event.requestId, + timestamp: event.timestamp, + opcode, + bytes: bytes.length, + base64: bytes.toString('base64'), + } + result.websocketFrames.push(frame) + if (decoded.includes('self[Symbol.for("bun:hmr")]')) { + frame.file = output.replace( + /\.json$/, + `-hmr${result.websocketFrames.length}.txt`, + ) + assetCaptures.push(writeFile(frame.file, decoded)) + } + }) + page.on('response', (response) => { + if (!new URL(response.url()).pathname.endsWith('.js')) { + return + } + const asset = { + url: response.url(), + file: output.replace( + /\.json$/, + `-initial${result.initialJavaScript.length}.js`, + ), + } + result.initialJavaScript.push(asset) + assetCaptures.push( + response + .text() + .then((text) => writeFile(asset.file, text)) + .catch((error) => { + asset.error = String(error) + }), + ) + }) + } + page.on('load', () => { + result.documentLoads++ + }) + page.on('console', (message) => { + if (message.type() === 'error') { + result.browserErrors.push({ type: 'console', text: message.text() }) + } + }) + page.on('pageerror', (error) => + result.browserErrors.push({ type: 'pageerror', text: error.message }), + ) + await page.goto(info.url) + await expect(page.locator('#app')).toHaveText('A0|B0|C0') + result.before = await snapshot() + if (blockThread) { + child.send('block') + await deadline(blocked, 'IPC block') + } + for (const name of ['a', 'b', 'c']) { + const started = Date.now(), + contents = `export const ${name}='${name.toUpperCase()}1';\n` + await writeFile(path.join(directory, name + '.ts'), contents) + result.writes.push({ name, started, finished: Date.now(), contents }) + if (nativeSync) { + await waitNativeBatch(name) + } else { + await batchInterval(150) + } + } + if (blockThread) { + await writeFile(releaseFile, 'release\n') + await deadline(released, 'IPC release') + } + try { + await expect(page.locator('#app')).toHaveText('A1|B1|C1', { timeout: 5000 }) + } finally { + result.after = await snapshot() + } + assert.equal( + result.after.documentToken, + result.before.documentToken, + 'Updates must retain the document', + ) + assert.equal(result.documentLoads, 1) + assert.deepEqual(result.browserErrors, []) + assert.deepEqual(await (await fetch(new URL('/__info', info.url))).json(), { + pid: info.pid, + }) + result.passed = true +} catch (error) { + result.error = error.stack ?? String(error) + result.moduleBytes = Object.fromEntries( + await Promise.all( + ['a', 'b', 'c'].map(async (name) => [ + name, + await readFile(path.join(directory, name + '.ts'), 'utf8'), + ]), + ), + ) + result.preservedFixture = true +} finally { + await writeFile(releaseFile, 'cleanup release\n').catch(() => {}) + await Promise.all(assetCaptures) + await context?.close() + await browser?.close() + if (child && child.exitCode === null && child.signalCode === null) { + child.kill() + await new Promise((resolve) => child.once('exit', resolve)) + } + result.serverLog = logs + if (result.passed) { + await rm(directory, { recursive: true, force: true }) + } + await rm(controlDirectory, { recursive: true, force: true }) + await writeFile(output, JSON.stringify(result, null, 2) + '\n') +} +console.log( + JSON.stringify({ + passed: result.passed, + before: result.before, + after: result.after, + writes: result.writes.map(({ name, started, finished }) => ({ + name, + started, + finished, + })), + error: result.error?.split('\n')[0], + output, + }), +) +if (!result.passed) { + process.exitCode = 1 +} diff --git a/.github/native-bun-validation/require-tests-reporter.mjs b/.github/native-bun-validation/require-tests-reporter.mjs new file mode 100644 index 00000000000..bb1972b99d2 --- /dev/null +++ b/.github/native-bun-validation/require-tests-reporter.mjs @@ -0,0 +1,29 @@ +import { writeFileSync } from 'node:fs' + +export default class RequireTestsReporter { + tests = [] + + onTestEnd(test, result) { + this.tests.push({ + title: test.titlePath().join(' > '), + status: result.status, + errors: result.errors, + }) + } + + onEnd(result) { + const passed = + this.tests.length > 0 && + this.tests.every((test) => test.status === 'passed') + writeFileSync( + process.env.NATIVE_REPORT, + JSON.stringify({ result, tests: this.tests }, null, 2) + '\n', + ) + if (!passed) { + console.error( + 'Native validation requires every selected test to execute and pass; skips fail validation.', + ) + return { status: 'failed' } + } + } +} diff --git a/.github/workflows/bun-native-validation.yml b/.github/workflows/bun-native-validation.yml index 11f1f258b1a..da8e675d3ba 100644 --- a/.github/workflows/bun-native-validation.yml +++ b/.github/workflows/bun-native-validation.yml @@ -1,7 +1,16 @@ -name: Temporary native Bun regression validation +name: Temporary native Bun validation on: workflow_dispatch: + inputs: + router_ref: + description: 'Exact Router commit for browser tests; empty builds Bun only' + type: string + default: '' + binary_run: + description: 'Existing successful native build run ID; empty builds Bun' + type: string + default: '' permissions: contents: read @@ -14,7 +23,7 @@ env: jobs: native: - if: github.repository == 'RentnerKev/router' + if: github.repository == 'RentnerKev/router' && inputs.binary_run == '' runs-on: macos-15 defaults: run: @@ -24,16 +33,93 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Checkout immutable Bun base + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/bun + ref: dca7d25e95cca39316c659a377dba6803805549f + path: .native-bun + persist-credentials: false + - name: Setup bootstrap Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: '1.4.4' - name: Setup Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '26.10.0' package-manager-cache: false - - name: Download verified final native binary + - name: Build native release binary + id: native_tests + run: bash .github/native-bun-validation/build-macos.sh + - name: Collect binary and final machine state + if: always() + run: | + mkdir -p .native-proof/binary + df -h > .native-proof/final-disk.log + if [[ -f .native-bun/build/native-release/bun-profile ]]; then + cp .native-bun/build/native-release/bun-profile .native-proof/binary/bun + python3 - <<'PY' + import hashlib, json, os, subprocess + from pathlib import Path + binary = Path('.native-proof/binary/bun') + manifest = json.loads(Path('.github/native-bun-validation/native-v15-manifest.json').read_text()) + proof = { + 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), + 'base': manifest['head'], + 'patchSha256': manifest['trackedPatchSha256'], + 'additionalFiles': manifest['additionalFiles'], + 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), + 'workflowRun': os.environ['GITHUB_RUN_ID'], + 'workflowCommit': os.environ['GITHUB_SHA'], + 'buildProfile': 'release --lto=off --canary=off', + } + Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') + PY + fi + - name: Upload native binary, source, toolchain and test proof + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: native-macos-arm64-bun + path: .native-proof/ + include-hidden-files: true + if-no-files-found: error + retention-days: 14 + + browser: + if: always() && !cancelled() && github.repository == 'RentnerKev/router' && inputs.router_ref != '' && (inputs.binary_run != '' || needs.native.result == 'success') + needs: native + runs-on: macos-15 + defaults: + run: + shell: bash + steps: + - name: Checkout exact Router commit + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ inputs.router_ref || github.sha }} + persist-credentials: false + - name: Require immutable Router ref + env: + ROUTER_REF: ${{ inputs.router_ref || github.sha }} + run: | + [[ "$ROUTER_REF" =~ ^[0-9a-f]{40}$ ]] + [[ "$(git rev-parse HEAD)" == "$ROUTER_REF" ]] + - name: Download native binary and proof env: GH_TOKEN: ${{ github.token }} + BINARY_RUN: ${{ inputs.binary_run || github.run_id }} run: | - gh run download 40091857136 --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact + [[ "$BINARY_RUN" =~ ^[0-9]+$ ]] + gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact + - name: Setup pnpm + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '26.10.0' + package-manager-cache: false - name: Checkout matching native regression sources uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -41,27 +127,151 @@ jobs: ref: dca7d25e95cca39316c659a377dba6803805549f path: .cache/native-bun-validation/test-source persist-credentials: false - - name: Verify watch-path oracle and run native regressions - id: native_tests + - name: Execute verified native artifact regressions + id: native_regressions continue-on-error: true run: python3 .github/native-bun-validation/artifact-tests.py - - name: Run native Chrome tests with Bun's CI runner - id: chrome - if: ${{ !cancelled() }} + - name: Record native module path identity + run: .native-artifact/binary/bun .github/native-bun-validation/path-identity-probe.ts > .native-browser-proof/path-identity.json + - name: Install Router dependencies + run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' + - name: Checkout actual unplugin PR source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/unplugin + ref: 4d01143e6f60a6a93ed40411629ea4da14f540a7 + path: .native-unplugin + persist-credentials: false + - name: Build actual unplugin PR distribution + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + version: '12.14.0' + package_json_file: .native-unplugin/package.json + dest: ~/native-pnpm12 + - name: Install and build actual unplugin PR + run: | + pnpm --dir .native-unplugin install --frozen-lockfile + pnpm --dir .native-unplugin build + test -f .native-unplugin/dist/index.mjs + - name: Restore Router pnpm version + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + dest: ~/native-pnpm11 + - name: Prepare isolated native Bun wrapper and unplugin preload + run: node .github/native-bun-validation/browser-setup.mjs + - name: Install Chromium + run: pnpm exec playwright install chromium --only-shell + - name: Execute Bun's native Chromium ordering regression + id: native_chrome continue-on-error: true run: python3 .github/native-bun-validation/chrome-test.py - - name: Upload regression results + - name: Preserve native HMR script order in the browser + id: hmr_order + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PURE_BUN_LARGE_PAIR: '1' + PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-hmr-order.json + run: node .github/native-bun-validation/pure-bun-graph-browser.mjs + - name: Map restored native dependencies to their authored source + id: restored_maps + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PURE_BUN_SOURCE_MAPS: '1' + PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-restored-maps.json + run: node .github/native-bun-validation/pure-bun-graph-browser.mjs + - name: Apply every native watcher batch in the browser + id: pending_batches + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + PENDING_BATCH_NATIVE_SYNC: '1' + BUN_WATCHER_TRACE: ${{ github.workspace }}/.native-browser-proof/pending-batches-watcher.jsonl + PENDING_BATCH_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pending-batches-browser.json + run: node .github/native-bun-validation/pure-bun-pending-batches-browser.mjs + - name: Production builds, navigation and source maps + id: production + continue-on-error: true + env: + NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/production-results.json + run: | + set -o pipefail + pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/production.log + - name: Native development navigation, HMR, recovery and source maps + id: development + if: ${{ !cancelled() && steps.production.outcome != 'skipped' }} + continue-on-error: true + env: + NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/development-results.json + run: | + set -o pipefail + pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun:dev --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/development.log + - name: Checkout actual Jiti PR source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: RentnerKev/jiti + ref: 2669fd42050027531c7bbeb0e61b61f7ae35517a + path: .native-jiti + persist-credentials: false + - name: Build actual Jiti PR distribution + uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 + with: + version: '10.30.3' + package_json_file: .native-jiti/package.json + dest: ~/native-pnpm10 + - name: Install and build actual Jiti PR + working-directory: .native-jiti + run: | + [[ "$(pnpm --ignore-workspace --version)" == '10.30.3' ]] + pnpm --ignore-workspace install --frozen-lockfile + pnpm --ignore-workspace build + test -f dist/jiti.cjs + - name: Imported virtual configuration helpers with actual Jiti PR + id: configuration + continue-on-error: true + env: + JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs + run: | + mkdir -p packages/router-generator/.cache + cp .github/native-bun-validation/helper-import-preload.mjs packages/router-generator/.cache/helper-import-preload.mjs + if "$BUN_EXECUTABLE" .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-installed.json; then + echo 'Installed Jiti also passed the helper cases.' + fi + "$BUN_EXECUTABLE" --preload ./packages/router-generator/.cache/helper-import-preload.mjs .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-candidate.json + - name: Imported helper edits in the running native browser + id: configuration_browser + continue-on-error: true + env: + ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} + UNPLUGIN_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-unplugin/dist/index.mjs + JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs + BUN_PLUGIN_PRELOAD: ${{ github.workspace }}/.github/native-bun-validation/helper-browser-preload.mjs + HELPER_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/configuration-browser.json + run: node .github/native-bun-validation/helper-browser.mjs + - name: Upload all browser results if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: native-macos-arm64-final-regressions - path: .native-browser-proof/ + name: native-macos-arm64-router-browser + path: | + .native-browser-proof/ + e2e/react-router/bun-basic-file-based/test-results/ + e2e/react-router/bun-basic-file-based/.cache/ include-hidden-files: true - if-no-files-found: error + if-no-files-found: warn retention-days: 14 - - name: Require actual regression outcomes + - name: Require browser and configuration suites to pass if: always() env: - NATIVE: ${{ steps.native_tests.outcome }} - CHROME: ${{ steps.chrome.outcome }} - run: '[[ "$NATIVE" == success && "$CHROME" == success ]]' + PRODUCTION: ${{ steps.production.outcome }} + DEVELOPMENT: ${{ steps.development.outcome }} + CONFIGURATION: ${{ steps.configuration.outcome }} + CONFIGURATION_BROWSER: ${{ steps.configuration_browser.outcome }} + NATIVE_REGRESSIONS: ${{ steps.native_regressions.outcome }} + HMR_ORDER: ${{ steps.hmr_order.outcome }} + RESTORED_MAPS: ${{ steps.restored_maps.outcome }} + NATIVE_CHROME: ${{ steps.native_chrome.outcome }} + PENDING_BATCHES: ${{ steps.pending_batches.outcome }} + run: | + [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success && "$NATIVE_CHROME" == success && "$PENDING_BATCHES" == success ]] From 815cbaaf209a131c50aae2b524b9f4559d09c287 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 15:19:51 +0200 Subject: [PATCH 29/31] chore: remove temporary native Bun validation infrastructure --- .../native-bun-validation/artifact-tests.py | 173 ------ .../native-bun-validation/browser-setup.mjs | 64 --- .github/native-bun-validation/build-macos.sh | 56 -- .github/native-bun-validation/chrome-test.py | 40 -- .../combined-generator.mjs | 228 -------- .../helper-browser-preload.mjs | 21 - .../native-bun-validation/helper-browser.mjs | 279 --------- .../helper-import-preload.mjs | 13 - .../hmr-script-order-test.patch.gz | Bin 2287 -> 0 bytes .../input-map-sync-test.patch.gz | Bin 685 -> 0 bytes .../mac-quiet-watch-tests.patch | 30 - .../native-v15-additional-files.tar.gz | Bin 10601 -> 0 bytes .../native-v15-manifest.json | 43 -- .../native-v15-tracked.patch.gz | Bin 91550 -> 0 bytes .../path-identity-probe.ts | 63 -- .github/native-bun-validation/prepare.py | 106 ---- .../pure-bun-graph-browser.mjs | 538 ------------------ .../pure-bun-pending-batches-browser.mjs | 360 ------------ .../require-tests-reporter.mjs | 29 - .../watcher-poll-test.patch.gz | Bin 958 -> 0 bytes .github/workflows/bun-native-validation.yml | 277 --------- 21 files changed, 2320 deletions(-) delete mode 100644 .github/native-bun-validation/artifact-tests.py delete mode 100644 .github/native-bun-validation/browser-setup.mjs delete mode 100644 .github/native-bun-validation/build-macos.sh delete mode 100644 .github/native-bun-validation/chrome-test.py delete mode 100644 .github/native-bun-validation/combined-generator.mjs delete mode 100644 .github/native-bun-validation/helper-browser-preload.mjs delete mode 100644 .github/native-bun-validation/helper-browser.mjs delete mode 100644 .github/native-bun-validation/helper-import-preload.mjs delete mode 100644 .github/native-bun-validation/hmr-script-order-test.patch.gz delete mode 100644 .github/native-bun-validation/input-map-sync-test.patch.gz delete mode 100644 .github/native-bun-validation/mac-quiet-watch-tests.patch delete mode 100644 .github/native-bun-validation/native-v15-additional-files.tar.gz delete mode 100644 .github/native-bun-validation/native-v15-manifest.json delete mode 100644 .github/native-bun-validation/native-v15-tracked.patch.gz delete mode 100644 .github/native-bun-validation/path-identity-probe.ts delete mode 100644 .github/native-bun-validation/prepare.py delete mode 100644 .github/native-bun-validation/pure-bun-graph-browser.mjs delete mode 100644 .github/native-bun-validation/pure-bun-pending-batches-browser.mjs delete mode 100644 .github/native-bun-validation/require-tests-reporter.mjs delete mode 100644 .github/native-bun-validation/watcher-poll-test.patch.gz delete mode 100644 .github/workflows/bun-native-validation.yml diff --git a/.github/native-bun-validation/artifact-tests.py b/.github/native-bun-validation/artifact-tests.py deleted file mode 100644 index 46a006fdde9..00000000000 --- a/.github/native-bun-validation/artifact-tests.py +++ /dev/null @@ -1,173 +0,0 @@ -import gzip -import hashlib -import json -import os -from pathlib import Path -import re -import subprocess -import xml.etree.ElementTree as ET - - -root = Path(os.environ["GITHUB_WORKSPACE"]) -binary = root / ".native-artifact/binary/bun" -proof = root / ".native-browser-proof" -proof.mkdir(exist_ok=True) -expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -manifest = json.loads((root / ".github/native-bun-validation/native-v15-manifest.json").read_text()) -assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] -assert expected["base"] == manifest["head"] -assert expected["patchSha256"] == manifest["trackedPatchSha256"] -assert expected["additionalFiles"] == manifest["additionalFiles"] -binary.chmod(0o755) -source = root / ".cache/native-bun-validation/test-source" -subprocess.run([ - "python3", str(root / ".github/native-bun-validation/prepare.py"), - "--bun", str(source), "--out", str(proof / "native-source"), -], check=True) -for cwd in [source, source / "test"]: - subprocess.run([str(binary), "install", "--frozen-lockfile"], cwd=cwd, check=True) - -overrides = proof / "native-test-overrides" -overrides.mkdir(exist_ok=True) -adjusted_sources = {} -patches = {} -for name, digest, allowed_paths in [ - ("mac-quiet-watch-tests.patch", - "65c3d33ff88d44e9748498ad7a34bb3113be8fdd940a39aaad4de4b98b2aa062", - {"test/bake/dev/plugins.test.ts", "test/bake/dev/client-plugin-cache.test.ts"}), - ("hmr-script-order-test.patch.gz", - "2d550b1127c34240788bf4a5ce5a5ca69c76ff0f83aca675373d2d2d04c854bc", - {"test/js/bun/webview/webview-chrome.test.ts"}), - ("input-map-sync-test.patch.gz", - "a9a19adad05b39a99efbe48d80cf06334cd0d53e93aa58a2f2cfb02bd7e5f487", - {"test/bundler/bun-build-api.test.ts"}), - ("watcher-poll-test.patch.gz", - "9b519899a32da4eb217e3131e62d4ea2934805703d41dec1503f881a8e3f9743", - {"test/bake/dev/hot.test.ts"}), -]: - patch = (root / ".github/native-bun-validation" / name).read_bytes() - if name.endswith(".gz"): - patch = gzip.decompress(patch) - assert hashlib.sha256(patch).hexdigest() == digest - paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) - assert all(old == new for old, new in paths) - assert {old.decode() for old, _ in paths} == allowed_paths - if name == "watcher-poll-test.patch.gz": - original_test = source / "test/bake/dev/hot.test.ts" - original_contents = original_test.read_bytes() - needle = b'const text = readFileSync(trace, "utf8").slice(offset);' - assert original_contents.count(needle) == 1 - diagnostic = original_contents.replace( - needle, needle + b'\n console.error("NATIVE_PATH_IDENTITY " + JSON.stringify({ expected: filename, trace: text }));', - ) - timer = b'() => ready.reject(new Error("Watcher control event deadline exceeded")),' - assert diagnostic.count(timer) == 1 - diagnostic = diagnostic.replace(timer, b'() => { console.error("NATIVE_TRACE_AT_TIMEOUT " + JSON.stringify({ trace: readFileSync(trace, "utf8") })); ready.reject(new Error("Watcher control event deadline exceeded")); },') - original_test.write_bytes(diagnostic) - try: - before = subprocess.run([ - str(binary), "test", "test/bake/dev/hot.test.ts", "-t", - "retains separate watcher batches while the server thread is busy$", - ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - env={**os.environ, "BUN_DEV_SERVER_VERBOSE_SYNC": "1"}) - (proof / "native-watcher-path-before.log").write_text(before.stdout) - identities = [json.loads(line.split("NATIVE_PATH_IDENTITY ", 1)[1]) - for line in before.stdout.splitlines() if line.startswith("NATIVE_PATH_IDENTITY ")] - final_traces = [json.loads(line.split("NATIVE_TRACE_AT_TIMEOUT ", 1)[1])["trace"] - for line in before.stdout.splitlines() if line.startswith("NATIVE_TRACE_AT_TIMEOUT ")] - expected_file = identities[-1]["expected"] - native_events = [json.loads(line) for trace in final_traces for line in trace.splitlines()] - assert before.returncode != 0 and any(expected_file in event["files"] for event in native_events), \ - "The native event must exist even though the test observer did not wake" - (proof / "native-watcher-path-before.json").write_text(json.dumps({ - "failedBefore": True, "expectedFile": expected_file, - "nativeEventPresentAtTimeout": True, "events": native_events, - }, indent=2) + "\n") - finally: - original_test.write_bytes(original_contents) - subprocess.run(["git", "apply", "--check", "-"], cwd=source, input=patch, check=True) - subprocess.run(["git", "apply", "-"], cwd=source, input=patch, check=True) - (overrides / name.removesuffix(".gz")).write_bytes(patch) - patches[name] = digest - for old, _ in paths: - filename = old.decode() - contents = (source / filename).read_bytes() - adjusted_sources[filename] = hashlib.sha256(contents).hexdigest() - target = overrides / filename - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(contents) -(overrides / "proof.json").write_text(json.dumps({ - "binaryRuntimeUnchanged": True, - "testOnlyPatchSha256": patches, - "adjustedSourceSha256": adjusted_sources, -}, indent=2) + "\n") -tests = manifest["testCommand"].split(" test ", 1)[1].split() -assert len(tests) == 9 -isolated = [ - ("test/bake/dev/plugins.test.ts", "watchDirs preserves browser state when only a child file's contents change"), - ("test/bake/dev/plugins.test.ts", "watchDirs shares directory events with imported files and trailing-slash aliases"), - ("test/bake/dev/client-plugin-cache.test.ts", "client plugin cache probe: structural dependency update serves the current manifest"), - ("test/bake/dev/server-sourcemap.test.ts", "server-side source maps handle nested imports"), - ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy"), - ("test/bake/dev/hot.test.ts", "retains separate watcher batches while the server thread is busy with an atomic plugin dependency"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies with an async dependency"), - ("test/bake/dev/hot.test.ts", "evaluates an accepting importer after all changed dependencies and disposes it once with an async dependency"), - ("test/bundler/bun-build-api.test.ts", "an external input source map is read synchronously"), - ("test/bundler/bun-build-api.test.ts", "an input source map named by a file: URL is composed"), -] -isolated_results = [] -for index, (filename, title) in enumerate(isolated): - isolated_report = proof / f"native-isolated-{index}.xml" - run = subprocess.run([ - str(binary), "test", filename, "-t", re.escape(title) + "$", - "--reporter=junit", f"--reporter-outfile={isolated_report}", - ], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={ - **os.environ, - "BUN_DEV_SERVER_VERBOSE_SYNC": "1", - "BUN_WATCHER_TRACE": str(proof / f"native-isolated-{index}-watcher.jsonl"), - }) - (proof / f"native-isolated-{index}.log").write_text(run.stdout) - all_cases = ET.parse(isolated_report).findall(".//testcase") if isolated_report.exists() else [] - selected = [case for case in all_cases if case.attrib.get("name", "").endswith(title)] - passed = run.returncode == 0 and len(selected) == 1 and all( - not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) - for case in selected - ) and all(case.find("skipped") is not None for case in all_cases if case not in selected) - isolated_results.append({"file": filename, "title": title, "passed": passed, - "cases": len(selected), "filteredOut": len(all_cases) - len(selected)}) - print(json.dumps(isolated_results[-1])) -(proof / "native-isolated-results.json").write_text(json.dumps(isolated_results, indent=2) + "\n") -report = proof / "native-results.xml" -# Execute the verified, source-built artifact. The Bun CI build path ignores -# trailing execution arguments, so a successful build alone is not a test run. -result = subprocess.run([ - str(binary), "test", *tests, "--reporter=junit", f"--reporter-outfile={report}", -], cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -(proof / "native-regressions.log").write_text(result.stdout) -print(result.stdout, end="") -cases = ET.parse(report).findall(".//testcase") -assert cases, "Native test runner executed no cases" -by_file = {filename: [] for filename in tests} -for case in cases: - filename = Path(case.attrib["file"]) - if not filename.is_absolute(): - filename = source / filename - relative = filename.resolve().relative_to(source.resolve()).as_posix() - assert relative in by_file, f"Unexpected test source: {relative}" - by_file[relative].append(case) -assert all(any(case.find("skipped") is None for case in group) for group in by_file.values()), \ - "Every selected native test file must execute a non-skipped case" -summary = { - "binarySha256": expected["sha256"], "selectedFiles": tests, - "cases": len(cases), - "skipped": sum(case.find("skipped") is not None for case in cases), - "failed": sum(case.find("failure") is not None or case.find("error") is not None for case in cases), - "perFile": {filename: len(group) for filename, group in by_file.items()}, -} -(proof / "native-results.json").write_text(json.dumps(summary, indent=2) + "\n") -print(json.dumps(summary, indent=2)) -result.check_returncode() -assert summary["failed"] == 0 -assert all(run["passed"] for run in isolated_results) diff --git a/.github/native-bun-validation/browser-setup.mjs b/.github/native-bun-validation/browser-setup.mjs deleted file mode 100644 index c68480e2d0d..00000000000 --- a/.github/native-bun-validation/browser-setup.mjs +++ /dev/null @@ -1,64 +0,0 @@ -import { mkdir, readFile, writeFile, chmod } from 'node:fs/promises' -import { createHash } from 'node:crypto' -import { execFileSync } from 'node:child_process' -import path from 'node:path' -import { pathToFileURL } from 'node:url' - -const repo = process.env.GITHUB_WORKSPACE -const binary = path.join(repo, '.native-artifact/binary/bun') -const proof = path.join(repo, '.native-browser-proof') -const cache = path.join(repo, 'packages/router-plugin/.cache/native-validation') -const preload = path.join(cache, 'preload.ts') -const upstream = path.join(repo, '.native-unplugin/dist/index.mjs') -const wrapper = path.join(cache, 'bin/bun') -await mkdir(path.dirname(wrapper), { recursive: true }) -await mkdir(proof, { recursive: true }) -await chmod(binary, 0o755) -const hash = createHash('sha256') - .update(await readFile(binary)) - .digest('hex') -const expected = JSON.parse( - await readFile(path.join(repo, '.native-artifact/binary-proof.json'), 'utf8'), -) -if (hash !== expected.sha256) { - throw new Error('Downloaded native Bun binary hash mismatch') -} -// Bun resolves this mock beside router-plugin's installed unplugin dependency. -await writeFile( - preload, - `import { mock } from 'bun:test'\nimport * as upstream from ${JSON.stringify(pathToFileURL(upstream).href)}\nmock.module('unplugin', () => upstream)\n`, -) -const quote = (value) => `'${value.replaceAll("'", "'\\''")}'` -await writeFile( - wrapper, - `#!/bin/sh\nexec ${quote(binary)} --preload ${quote(preload)} "$@"\n`, -) -await chmod(wrapper, 0o755) -const versions = { - routerHead: execFileSync('git', ['rev-parse', 'HEAD'], { - cwd: repo, - encoding: 'utf8', - }).trim(), - unpluginHead: execFileSync('git', ['rev-parse', 'HEAD'], { - cwd: path.dirname(path.dirname(upstream)), - encoding: 'utf8', - }).trim(), - node: process.version, - bun: execFileSync(binary, ['--version'], { encoding: 'utf8' }).trim(), - binarySha256: hash, - nativeSource: expected, -} -await writeFile( - path.join(proof, 'versions.json'), - JSON.stringify(versions, null, 2) + '\n', -) -await writeFile(path.join(proof, 'preload.ts'), await readFile(preload)) -await writeFile( - process.env.GITHUB_ENV, - `BUN_EXECUTABLE=${binary}\nBUN_PLUGIN_PRELOAD=${preload}\nBUN_DEV_TEST_OUTPUT=${proof}/dev-results\n`, - { flag: 'a' }, -) -await writeFile(process.env.GITHUB_PATH, path.dirname(wrapper) + '\n', { - flag: 'a', -}) -console.log(JSON.stringify(versions, null, 2)) diff --git a/.github/native-bun-validation/build-macos.sh b/.github/native-bun-validation/build-macos.sh deleted file mode 100644 index e6dadf39d3c..00000000000 --- a/.github/native-bun-validation/build-macos.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -repo="$GITHUB_WORKSPACE" -proof="$repo/.native-proof" -mkdir -p "$proof" -{ - date -u - sw_vers - uname -a - sysctl hw.memsize hw.ncpu - df -h - xcodebuild -version - xcrun --show-sdk-path - node --version - bun --version - python3 --version - brew --version -} | tee "$proof/preflight.log" - -python3 "$repo/.github/native-bun-validation/prepare.py" \ - --bun "$repo/.native-bun" --out "$proof" | tee "$proof/source-verification.json" - -# CONTRIBUTING.md's macOS prerequisites, plus its required LLVM major. -brew update -brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby llvm -export PATH="$(brew --prefix llvm)/bin:$(brew --prefix rustup-init)/bin:$HOME/.cargo/bin:$PATH" -export RUSTUP_TOOLCHAIN=nightly-2026-09-15 -export CARGO_BUILD_JOBS=1 -export CARGO_INCREMENTAL=0 -if ! command -v rustup >/dev/null; then - rustup-init -y --no-modify-path --profile minimal --default-toolchain none -fi -rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component rust-src -llvm_version="$(llvm-config --version)" -[[ "$llvm_version" =~ ^23\.1\.[0-9]+$ ]] || { echo "Expected LLVM 23.1.x, got $llvm_version"; exit 1; } -{ - brew list --versions - clang --version - llvm-config --version - rustc -vV - cargo --version - rustup show - cmake --version - ninja --version - ccache --version - df -h -} | tee "$proof/toolchain.log" - -cd "$repo/.native-bun" -bun install --frozen-lockfile 2>&1 | tee "$proof/root-install.log" -bun install --cwd test --frozen-lockfile 2>&1 | tee "$proof/test-install.log" - -# The CI build wrapper does not execute trailing arguments. Regressions run -# against the verified binary in the artifact validation job. -GITHUB_SHA="$(git rev-parse HEAD)" bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 2>&1 | tee "$proof/native-build.log" diff --git a/.github/native-bun-validation/chrome-test.py b/.github/native-bun-validation/chrome-test.py deleted file mode 100644 index 145f62b0b07..00000000000 --- a/.github/native-bun-validation/chrome-test.py +++ /dev/null @@ -1,40 +0,0 @@ -import hashlib -import json -import os -from pathlib import Path -import subprocess -import xml.etree.ElementTree as ET - - -root = Path(os.environ["GITHUB_WORKSPACE"]) -binary = root / ".native-artifact/binary/bun" -proof = root / ".native-browser-proof" -source = root / ".cache/native-bun-validation/test-source" -expected = json.loads((root / ".native-artifact/binary-proof.json").read_text()) -assert hashlib.sha256(binary.read_bytes()).hexdigest() == expected["sha256"] -report = proof / "native-chrome.xml" -title = "HMR applies a large update before the following small update" -# Match the existing CI runner's budget without starting its crash-remap service. -runner = (source / "scripts/runner.node.ts").read_text() -assert "const testTimeout = 3 * 60_000;" in runner -assert "const perTestTimeout = Math.ceil(timeout / 2) * (isAsan ? 3 : 1);" in runner -command = [ - str(binary), "test", "test/js/bun/webview/webview-chrome.test.ts", "-t", title, - "--timeout=90000", "--reporter=junit", f"--reporter-outfile={report}", -] -result = subprocess.run(command, cwd=source, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -(proof / "native-chrome.log").write_text(result.stdout) -print(result.stdout, end="") -all_cases = ET.parse(report).findall(".//testcase") if report.exists() else [] -cases = [case for case in all_cases if case.attrib.get("name", "") == title] -passed = result.returncode == 0 and len(cases) == 1 and all( - not any(case.find(tag) is not None for tag in ["failure", "error", "skipped"]) - for case in cases -) and all(case.find("skipped") is not None for case in all_cases if case not in cases) -(proof / "native-chrome.json").write_text(json.dumps({ - "binarySha256": expected["sha256"], "title": title, - "cases": len(cases), "filteredOut": len(all_cases) - len(cases), "passed": passed, - "budgetSource": "scripts/runner.node.ts: testTimeout / 2 (stable CI)", - "command": command, -}, indent=2) + "\n") -assert passed, "Native Chromium ordering regression must execute and pass" diff --git a/.github/native-bun-validation/combined-generator.mjs b/.github/native-bun-validation/combined-generator.mjs deleted file mode 100644 index 6e86bd96879..00000000000 --- a/.github/native-bun-validation/combined-generator.mjs +++ /dev/null @@ -1,228 +0,0 @@ -import { - mkdtemp, - mkdir, - readFile, - realpath, - rename, - rm, - writeFile, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { - Generator, - getConfig, -} from '../../packages/router-generator/dist/esm/index.js' - -const normalize = (filename) => path.resolve(filename).replaceAll('\\', '/') -const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => - [1, 2].map((depth) => ({ ext, depth, dynamic: false })), -) -cases.push({ ext: 'mjs', depth: 2, dynamic: true }) -const results = [] -const routeNames = ['before', 'after', 'replacement'] -const configSource = (file, dynamic) => - file.endsWith('.cjs') - ? `const routes = require(${JSON.stringify(file)}); export default routes\n` - : dynamic - ? `export default (await import(${JSON.stringify(file)})).default\n` - : `import routes from ${JSON.stringify(file)}; export default routes\n` -const routeConfig = (name) => ({ - type: 'root', - file: '__root.tsx', - children: [{ type: 'route', path: `/${name}`, file: `${name}.tsx` }], -}) -const helperSource = (ext, name) => - ext === 'json' - ? JSON.stringify(routeConfig(name)) - : ext === 'cjs' - ? `module.exports = ${JSON.stringify(routeConfig(name))}\n` - : `export default ${JSON.stringify(routeConfig(name))}\n` - -for (const scenario of cases) { - const root = await realpath( - await mkdtemp(path.join(tmpdir(), 'router-built-helper-')), - ) - const checks = [] - const record = (name, passed, details = undefined) => - checks.push({ name, passed, details }) - try { - const projects = [] - for (const id of ['a', 'b']) { - const project = path.join(root, id) - const routes = path.join(project, 'routes') - await mkdir(routes, { recursive: true }) - await writeFile(path.join(project, 'package.json'), '{"type":"module"}\n') - await writeFile( - path.join(routes, '__root.tsx'), - `import { createRootRoute } from '@tanstack/react-router'; export const Route = createRootRoute({})\n`, - ) - for (const suffix of routeNames) { - const name = `${id}-${suffix}` - await writeFile( - path.join(routes, `${name}.tsx`), - `import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/${name}')({})\n`, - ) - } - const filename = path.join(project, `helper.${scenario.ext}`) - const configFile = path.join(project, 'virtual-routes.ts') - const bridge = path.join(project, 'bridge.ts') - await writeFile(filename, helperSource(scenario.ext, `${id}-before`)) - await writeFile( - configFile, - configSource( - scenario.depth === 2 ? './bridge.ts' : `./helper.${scenario.ext}`, - false, - ), - ) - if (scenario.depth === 2) { - await writeFile( - bridge, - configSource(`./helper.${scenario.ext}`, scenario.dynamic), - ) - } - const generatedRouteTree = path.join(project, 'routeTree.gen.ts') - const generator = new Generator({ - root: project, - config: getConfig( - { - routesDirectory: routes, - generatedRouteTree, - virtualRouteConfig: 'virtual-routes.ts', - tmpDir: path.join(project, 'tmp'), - disableLogging: true, - }, - project, - ), - }) - projects.push({ - id, - project, - filename, - configFile, - bridge, - generatedRouteTree, - generator, - }) - } - const [a, b] = projects - await Promise.all(projects.map((project) => project.generator.run())) - const expectedFiles = (project) => - [ - project.configFile, - ...(scenario.depth === 2 ? [project.bridge] : []), - project.filename, - ] - .map(normalize) - .sort() - for (const project of projects) { - const deps = project.generator - .getWatchDependencies() - .files.map(normalize) - .sort() - record( - `${project.id}:watch-dependencies`, - JSON.stringify(deps) === JSON.stringify(expectedFiles(project)), - { - expected: expectedFiles(project).map((filename) => - path.relative(root, filename), - ), - actual: deps.map((filename) => path.relative(root, filename)), - }, - ) - record( - `${project.id}:initial-tree`, - (await readFile(project.generatedRouteTree, 'utf8')).includes( - `'/${project.id}-before'`, - ), - ) - } - const initialB = await readFile(b.generatedRouteTree, 'utf8') - const stableA = await readFile(a.generatedRouteTree, 'utf8') - await a.generator.run() - record( - 'a:unchanged-generation', - (await readFile(a.generatedRouteTree, 'utf8')) === stableA, - ) - await writeFile(a.filename, helperSource(scenario.ext, 'a-after')) - await a.generator.run({ path: a.filename, type: 'update' }) - const eventTree = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:in-place-update-event', - eventTree.includes("'/a-after'") && !eventTree.includes("'/a-before'"), - ) - await a.generator.run() - const rerunTree = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:in-place-unconditional-rerun', - rerunTree.includes("'/a-after'") && !rerunTree.includes("'/a-before'"), - ) - record( - 'b:unchanged-after-a-edit', - (await readFile(b.generatedRouteTree, 'utf8')) === initialB, - ) - await writeFile( - `${a.filename}.next`, - helperSource(scenario.ext, 'a-replacement'), - ) - await rename(`${a.filename}.next`, a.filename) - await a.generator.run({ path: a.filename, type: 'update' }) - const replaced = await readFile(a.generatedRouteTree, 'utf8') - record( - 'a:atomic-replacement-event', - replaced.includes("'/a-replacement'") && !replaced.includes("'/a-after'"), - ) - await writeFile(b.filename, helperSource(scenario.ext, 'b-after')) - await b.generator.run({ path: b.filename, type: 'update' }) - record( - 'b:independent-update-event', - (await readFile(b.generatedRouteTree, 'utf8')).includes("'/b-after'"), - ) - await a.generator.run() - record( - 'a:no-cross-generator-leakage', - (await readFile(a.generatedRouteTree, 'utf8')) === replaced, - ) - record( - 'watch-dependencies-remain-isolated', - projects.every((project) => { - const deps = project.generator - .getWatchDependencies() - .files.map(normalize) - return ( - JSON.stringify(deps.sort()) === JSON.stringify(expectedFiles(project)) - ) - }), - ) - } catch (error) { - record( - 'execution', - false, - error instanceof Error ? error.stack : String(error), - ) - } finally { - await rm(root, { recursive: true, force: true }) - } - results.push({ - ...scenario, - passed: checks.every((check) => check.passed), - checks, - }) -} -const report = { - runtime: { - bun: process.versions.bun ?? null, - node: process.versions.node, - platform: process.platform, - arch: process.arch, - }, - mode: process.env.JITI_COMBINED_MODE ?? 'installed', - generator: 'packages/router-generator/dist/esm/index.js', - cases: results.length, - passed: results.filter((result) => result.passed).length, - results, -} -console.log(JSON.stringify(report, null, 2)) -if (report.passed !== report.cases) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/helper-browser-preload.mjs b/.github/native-bun-validation/helper-browser-preload.mjs deleted file mode 100644 index 42abdf9a47e..00000000000 --- a/.github/native-bun-validation/helper-browser-preload.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import { fileURLToPath, pathToFileURL } from 'node:url' -import path from 'node:path' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -await import( - pathToFileURL( - path.join( - root, - 'packages/router-plugin/.cache/helper-browser-override.mjs', - ), - ).href -) -await import( - pathToFileURL( - path.join( - root, - 'packages/router-generator/.cache/helper-browser-override.mjs', - ), - ).href -) diff --git a/.github/native-bun-validation/helper-browser.mjs b/.github/native-bun-validation/helper-browser.mjs deleted file mode 100644 index e5070f698e5..00000000000 --- a/.github/native-bun-validation/helper-browser.mjs +++ /dev/null @@ -1,279 +0,0 @@ -import assert from 'node:assert/strict' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { mkdir, readFile, writeFile } from 'node:fs/promises' -import path from 'node:path' -import { fileURLToPath, pathToFileURL } from 'node:url' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -process.env.ROUTER_REPOSITORY_ROOT = root -if (!process.env.BUN_EXECUTABLE) { - throw new Error('Set BUN_EXECUTABLE to the native Bun candidate') -} -process.env.BUN_PLUGIN_PRELOAD ??= fileURLToPath( - new URL('./helper-browser-preload.mjs', import.meta.url), -) -for (const [pkg, name, env, fallback] of [ - [ - 'router-plugin', - 'unplugin', - 'UNPLUGIN_CANDIDATE_ENTRY', - '.cache/upstream-drafts/unplugin/dist/index.mjs', - ], - [ - 'router-generator', - 'jiti', - 'JITI_CANDIDATE_ENTRY', - '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', - ], -]) { - const directory = path.join(root, 'packages', pkg, '.cache') - await mkdir(directory, { recursive: true }) - await writeFile( - path.join(directory, 'helper-browser-override.mjs'), - `import { mock } from 'bun:test'\nimport { pathToFileURL } from 'node:url'\nimport path from 'node:path'\nconst entry = process.env[${JSON.stringify(env)}] ?? path.join(process.env.ROUTER_REPOSITORY_ROOT, ${JSON.stringify(fallback)})\nconst actual = await import(pathToFileURL(path.resolve(entry)).href)\nmock.module(${JSON.stringify(name)}, () => actual)\n`, - ) -} -const projectRequire = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -) -const { chromium, expect } = projectRequire('@playwright/test') -const { startDevFixture } = await import( - pathToFileURL( - path.join(root, 'e2e/react-router/bun-basic-file-based/dev-fixture.ts'), - ).href -) -const output = - process.env.HELPER_BROWSER_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/helper-browser-${process.platform}.json`, - ) -const logFile = output.replace(/\.json$/, '.log') -await mkdir(path.dirname(output), { recursive: true }) -const log = [] -const say = (message) => { - log.push(message) - console.log(message) -} -const cases = ['js', 'mjs', 'cjs', 'json'].flatMap((ext) => - [1, 2].map((depth) => ({ ext, depth, dynamic: false })), -) -cases.push({ ext: 'mjs', depth: 2, dynamic: true }) -const results = [] -const configSource = (file, dynamic = false) => - file.endsWith('.cjs') - ? `const config = require(${JSON.stringify(file)}); export default config\n` - : dynamic - ? `export default (await import(${JSON.stringify(file)})).default\n` - : `import config from ${JSON.stringify(file)}; export default config\n` -const configValue = (included) => ({ - type: 'root', - file: '__root.tsx', - children: [ - { type: 'index', file: 'index.tsx' }, - { type: 'route', path: '/about', file: 'about.tsx' }, - { - type: 'route', - path: `/virtual-${included}`, - file: `../virtual-pages/${included}.tsx`, - }, - ], -}) -const helperSource = (ext, included) => - ext === 'json' - ? JSON.stringify(configValue(included)) - : ext === 'cjs' - ? `module.exports = ${JSON.stringify(configValue(included))}\n` - : `export default ${JSON.stringify(configValue(included))}\n` -const sha256 = async (filename) => - createHash('sha256') - .update(await readFile(filename)) - .digest('hex') -const browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), -}) -try { - for (const scenario of cases) { - const name = `${scenario.ext}-depth${scenario.depth}${scenario.dynamic ? '-dynamic' : ''}` - say(`START ${name}`) - const result = { - ...scenario, - passed: false, - steps: [], - browserErrors: [], - documentLoads: 0, - } - let native, context - try { - native = await startDevFixture({ - virtualConfigFile: true, - virtualConfigHelperDepth: 1, - }) - result.pid = native.pid - result.versions = native.versions - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.__helperBrowserDocumentToken = crypto.randomUUID() - }) - const page = await context.newPage() - page.on('load', () => { - result.documentLoads++ - }) - page.on('pageerror', (error) => - result.browserErrors.push({ - type: 'pageerror', - message: error.message, - }), - ) - page.on('console', (message) => { - if ( - message.type() === 'error' && - !message.location().url.endsWith('/favicon.ico') - ) { - result.browserErrors.push({ - type: 'console', - message: message.text(), - location: message.location(), - }) - } - }) - const heading = page.getByRole('heading') - const goHome = async () => { - await page.getByRole('link', { name: 'Home', exact: true }).click() - await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) - } - const checkpoint = async (phase, included) => { - await expect - .poll( - async () => { - native.assertAlive() - const tree = await native.tree() - return ( - tree.includes(`/virtual-${included}`) && - !tree.includes( - `/virtual-${included === 'after' ? 'before' : 'after'}`, - ) - ) - }, - { - timeout: 15000, - message: `${name} ${phase}: automatic route-tree update`, - }, - ) - .toBe(true) - await page - .getByRole('link', { name: `Virtual ${included}`, exact: true }) - .click() - await expect(heading).toHaveText(`VIRTUAL_${included.toUpperCase()}`, { - timeout: 15000, - }) - native.assertAlive() - assert.deepEqual( - await (await fetch(new URL('/__native-info', native.url))).json(), - { pid: native.pid }, - ) - result.steps.push({ - phase, - route: `/virtual-${included}`, - samePid: true, - documentToken: await page.evaluate( - () => globalThis.__helperBrowserDocumentToken, - ), - documentLoads: result.documentLoads, - browserErrorCount: result.browserErrors.length, - }) - await goHome() - } - await page.goto(native.url) - await expect(heading).toHaveText('HOME_NATIVE_DEV', { timeout: 15000 }) - await checkpoint('ts-bootstrap', 'before') - const helper = `config/browser-helper.${scenario.ext}` - await native.save(helper, helperSource(scenario.ext, 'after')) - if (scenario.depth === 2) { - await native.save( - 'config/browser-bridge.ts', - configSource(`./browser-helper.${scenario.ext}`, scenario.dynamic), - ) - } - await native.save( - 'virtual-routes.ts.next', - configSource( - scenario.depth === 2 - ? './config/browser-bridge.ts' - : `./config/browser-helper.${scenario.ext}`, - ), - ) - await native.rename('virtual-routes.ts.next', 'virtual-routes.ts') - await checkpoint('helper-graph-loaded', 'after') - await native.save(helper, helperSource(scenario.ext, 'before')) - await checkpoint('helper-in-place-edit', 'before') - await native.save(`${helper}.next`, helperSource(scenario.ext, 'after')) - await native.rename(`${helper}.next`, helper) - await checkpoint('helper-atomic-replacement', 'after') - assert.deepEqual( - result.browserErrors, - [], - `${name}: unexpected browser errors`, - ) - const serverErrors = native - .logs() - .split(/\r?\n/) - .filter((line) => /^(?:error:|panic:|thread .* panicked)/i.test(line)) - assert.deepEqual(serverErrors, [], `${name}: unexpected server errors`) - result.passed = true - say( - `PASS ${name}: browser navigation + automatic tree updates, in-place/atomic, same PID ${native.pid}, no browser errors`, - ) - } catch (error) { - result.error = error instanceof Error ? error.stack : String(error) - result.serverLog = native?.logs().slice(-12000) - say(`FAIL ${name}: ${String(error).split('\n')[0]}`) - } finally { - try { - await context?.close() - } finally { - await native?.close() - } - } - results.push(result) - await writeFile( - output, - JSON.stringify( - { - platform: process.platform, - node: process.version, - passed: results.filter((result) => result.passed).length, - cases: cases.length, - results, - }, - null, - 2, - ) + '\n', - ) - await writeFile(logFile, log.join('\n') + '\n') - } -} finally { - await browser.close() -} -const report = { - platform: process.platform, - arch: process.arch, - node: process.version, - binary: process.env.BUN_EXECUTABLE, - binarySha256: await sha256(process.env.BUN_EXECUTABLE), - preload: process.env.BUN_PLUGIN_PRELOAD, - passed: results.filter((result) => result.passed).length, - cases: cases.length, - results, -} -await writeFile(output, JSON.stringify(report, null, 2) + '\n') -say(`RESULT ${report.passed}/${report.cases} PASS; evidence ${output}`) -await writeFile(logFile, log.join('\n') + '\n') -if (report.passed !== report.cases) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/helper-import-preload.mjs b/.github/native-bun-validation/helper-import-preload.mjs deleted file mode 100644 index d871bbce50c..00000000000 --- a/.github/native-bun-validation/helper-import-preload.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { mock } from 'bun:test' -import { fileURLToPath, pathToFileURL } from 'node:url' -import path from 'node:path' -const repository = fileURLToPath(new URL('../../../', import.meta.url)) -const candidateEntry = process.env.JITI_CANDIDATE_ENTRY - ? path.resolve(process.env.JITI_CANDIDATE_ENTRY) - : path.join( - repository, - '.cache/jiti-helper-investigation/upstream/lib/jiti.mjs', - ) -const candidate = await import(pathToFileURL(candidateEntry).href) -mock.module('jiti', () => candidate) -process.env.JITI_COMBINED_MODE = 'candidate' diff --git a/.github/native-bun-validation/hmr-script-order-test.patch.gz b/.github/native-bun-validation/hmr-script-order-test.patch.gz deleted file mode 100644 index 5999aaa0ec696de2b787ca622861edf989e7b1b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2287 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 TTuY6`!3*>cppU-!=LG-&_YXl) diff --git a/.github/native-bun-validation/mac-quiet-watch-tests.patch b/.github/native-bun-validation/mac-quiet-watch-tests.patch deleted file mode 100644 index ca9acee4348..00000000000 --- a/.github/native-bun-validation/mac-quiet-watch-tests.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/test/bake/dev/plugins.test.ts b/test/bake/dev/plugins.test.ts ---- a/test/bake/dev/plugins.test.ts -+++ b/test/bake/dev/plugins.test.ts -@@ -134,7 +134,13 @@ - await c.expectElemText("button", "Count 1"); -- await dev.write("unrelated.txt", "first"); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("unrelated.txt", "first"); -+ }); - await c.expectElemText("button", "Count 1"); -- await dev.write("unrelated.txt", "second"); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("unrelated.txt", "second"); -+ }); - await c.expectElemText("button", "Count 1"); -- await dev.write("data/a.ts", `export default "second";`); -+ await c.expectNoWebSocketActivity(async () => { -+ await dev.write("data/a.ts", `export default "second";`); -+ }); - await c.expectElemText("button", "Count 1"); -diff --git a/test/bake/dev/client-plugin-cache.test.ts b/test/bake/dev/client-plugin-cache.test.ts ---- a/test/bake/dev/client-plugin-cache.test.ts -+++ b/test/bake/dev/client-plugin-cache.test.ts -@@ -92,3 +92,5 @@ - await client.click("button"); -- await dev.write("data/a.ts", `export default "second";`); -+ await client.expectNoWebSocketActivity(async () => { -+ await dev.write("data/a.ts", `export default "second";`); -+ }); - await client.expectElemText("button", "Count 1"); diff --git a/.github/native-bun-validation/native-v15-additional-files.tar.gz b/.github/native-bun-validation/native-v15-additional-files.tar.gz deleted file mode 100644 index e1f2d7a78af9308a8b8164c3b28c59ff10571685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10601 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 DD=fZe diff --git a/.github/native-bun-validation/native-v15-manifest.json b/.github/native-bun-validation/native-v15-manifest.json deleted file mode 100644 index ceabee96b15..00000000000 --- a/.github/native-bun-validation/native-v15-manifest.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "candidate": "native-v15", - "head": "dca7d25e95cca39316c659a377dba6803805549f", - "trackedPatchSha256": "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b", - "additionalFiles": { - "src/bundler/input_source_map.rs": "6afe1551ae56d44dfa6abccc89668cd582db68c79f65acf692abba457f678cbf", - "src/runtime/bake/dev_server/plugin_watch_store.rs": "41277667be6a81103ff304092777fe9f6844ec9297749e271222237dabd4a2ac", - "src/sourcemap/InputSourceMap.rs": "4316069854c45b05ba6af337132e3645deb411910dd187917ff88b0103475a05", - "test/bake/dev/barrel-hmr-renaming.test.ts": "2295e6a998454d76e5e41a4007f1bc1c2c1663713bb1662bcdef6500d08ff66e", - "test/bake/dev/barrel-hmr.test.ts": "8b7a1c6c3d500392d4a275ca76639e6c9a48260fddc7bc55a7f2be651935d604", - "test/bake/dev/client-plugin-cache.test.ts": "1ac62623a0c0a8a30d5b87e0deee207591b10fdef5e1507855c592fa4a26061a" - }, - "changesSinceV9": [ - "Windows synchronous handles for external input-map reads", - "Watched leaf-directory rename regression and explicit Windows ancestor-rename restriction" - ], - "testCommand": "bun run build:release --lto=off --canary=off --build-dir=build/native-release -j1 test test/bake/dev/sourcemap.test.ts test/bake/dev/server-sourcemap.test.ts test/bake/dev/plugins.test.ts test/bake/serve-plugins-dev-server.test.ts test/bake/dev/client-plugin-cache.test.ts test/bake/dev/barrel-hmr-renaming.test.ts test/bake/dev/barrel-hmr.test.ts test/bake/dev/hot.test.ts test/bake/dev/bundle.test.ts", - "changesSinceV10": [ - "Reachable cached client dependency closure after a fresh page load", - "Preserve loaded module identity and original source maps", - "Execute browser HMR scripts in WebSocket insertion order", - "Four public cached-closure regression cases" - ], - "changedSourceSha256": { - "src/runtime/bake/dev_server/incremental_graph.rs": "59d319121c7d7a42760e0e0e4df08303e8c08bc885c70b2d487d980ebaf85a9c", - "src/runtime/bake/dev_server/finalize.rs": "8bbc23a6df4e8444a4e6f71c1ef693c6b2445ee4ac5ad8e01139f2f627b89578", - "src/runtime/bake/dev_server/render.rs": "2fa45a019c3b96d387f5419945f49aeead30f496d57368c64362cf426958bc15", - "src/runtime/bake/hmr-module.ts": "20660b5fefeb174dbefc832d429d93d7bc5859ea9458fc75b8b82f89410092ae", - "src/runtime/bake/hmr-runtime-client.ts": "16fa1b0f4f5ed13a2f4e22e8a7059772f0cb1bee22cbb65ef535874b2d76f701", - "test/bake/dev/bundle.test.ts": "48a984dbdd53ded01bda8a1cc73de5756c745dfccf232af6b6cd75772ec07dfa", - "src/runtime/bake/dev_server/watcher_atomics.rs": "3efecf6b04601cbcf501df3304c30910c491bf03bce047d5707d318444256bd9", - "test/bake/dev/hot.test.ts": "8eb189558672bda096f54b957f0455656c04397f0c72a7cf50414666d2a935d6" - }, - "windowsBinarySha256": "56c24634993f1452d949924405ed06000530a9317c36c93a89fee3566beada85", - "changesSinceV12": [ - "Reclaim pending watcher events before collecting later batches", - "Preserve atomic plugin dependency events and rearm their file watches", - "Invalidate every affected HMR module before evaluating importers", - "Snapshot old accept callbacks and wait for asynchronous dependencies", - "Dispose shared accepting boundaries once per update", - "Six public regressions: two native watch cases and four client HMR cases" - ] -} diff --git a/.github/native-bun-validation/native-v15-tracked.patch.gz b/.github/native-bun-validation/native-v15-tracked.patch.gz deleted file mode 100644 index 5d9d00c1cbadd615bfd5ce66bb92699205504ec4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91550 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
-O^GVE~NKa z)k$h(7=g!?Wl8HEQ$_c^?@TQZDMKA0-8?~THsuehav@GZ`XN=2$STNcS|qOYA_p= ze`DH=$Ya%F^!ntgwK2HUXxzPX^UnI_a9E(lh*go%Uc`#9!`96^Fz({djk{vo&EIe; z)>dk-jQJZZ?pz`&v6}zc>)l_UJ^J@YdOK>uuUnkk_RXW+1Dnm!v(d8IKr%zGt#LCQ zmw~(M=X=B_6zwg>2@fFete{AdbpAa{fHrs zd!m(*cNo{fH4kgR^Rf!^j${^GB!cM@IoCh%cxl91vyOy6? zrn0nWud{q!_}PR>hxnwMHRjS>!Ni$&P4`|@T6lH{3rgNIAyC5mDZ|wXo)2tt9Bp6| zSEU!ki`n2}9pG_7nxx6rBQK+w*Sb0Vy02sQx~g)4#@e|4$~gdAr_0RjMi4hA1%tQ7 zBRd)1DT6DkDfdtR#A6+hdWa93)I2esTI8%^>^ZgqH%I9Sy;!}uUdxV<-9kL;wff~| z&DS~OHB*0ut=PN;0s}VxEWX?op#u5IZjfyo*L7fB!?Tud-_FhCq@Lf#!W~+yoklAA zbI!c2)Eh{Ay0R_~S2jyLOv_Cxv+!z!@G~2+Ru6aL2Jgg$`ms^ekBg|N@Fs<8brTSh z_^`$n?6u?B=}A^Rs%Y74LZRa!d9GF5SyS5z-XaP=932s{Nk{j2VPKJ;jrs?##%9H~ z0pQS-Zyd`PVj(pejcPd6zH;@aeAbRi5Ov6}E*eD1gTn;lMR*5m0XgKhNxp_~-(=pWhd(v^jhIWZ5xRnSvIj;-UB?Kj z`9ji49!iaf{}lqCeiVo|;RK(=4ttT06L2k>eUhU#?g)AOb5m{YPXO$e^L_Z_Fv0j- zwD@RAMj%ADj5z2SkP0U!Oi1Ft5bR~yyM+X(g0y<@t03+1si09|eOx2BAIoX@LNjwb zNoPu~t&Q7_b^5;+jTV)wdch-$A3u3tFA%#;Awq}>qYE=f0irV(*&z!ppjQOvcSc`^ zRv0}T!l_L<);OP@6uoF)@N3aIkG%3GeGXdL=HiW0iK0XFQ%}79hrN-PTs=iSE~H!Ze~;MrIZbjf^pt@aeOMk6u4|`fqKYWZ3kkk_DX{ z6`vC(a2~ayRi(Il%KtviJ@38EWOS2uWNt)elu>*cBlPc=CDRagB5WjND%oSJbU`;r z6Xz`;eGOkf&@dv>KKMVoNYnKqSQ=JNIp;JvhW5;zNDxG6MlD~7A8GN!%+o!Dw*m&^ zk&tJ?+Ic%{lIXdnKdg~X4-zh43KlD_-5wkdkicL)y`+Krl z_2fBu?b3%|PN)A0hxq&0w!UGPVeiKuYx`$XaF4mm-pAA4S8Y%XfE5I+R5XARU=qp5$}J$`wcP% zR!0N5yTEWFdhl&2`cor49v$N7`{^guY^Xv(Y9e(4e^Ag>W(eywLF_WrQx;>_A%|1`?fo~HE-fHwu$hHUsU`V&P)q>3B znLGEjtVmDWa*^B0R3t&5G{e~k527h6{myBB%DNa$aY&2&g8UA}9+ z18e9}%e-tei1IkB*lnOuSlyFzT>DL)k&}rrGjdWOp$qlOL>PfW4X_*=uM#X>MpTr` zku(SJu$F3zrId9LdA5_Uf!G|Yb@GO!ia;L&Bj zHAvMzt^WU&oy`tIKoH08eF{z`QE7V+;m}7}#HN*q1C>U^yZ1kX#THQ~lC`rRV|KFp zn_**98AgCodRQ9$x#-Zmo~>fK9%O@e;`z=E#O~eqH236)-tj16sbmAWNi#_YCn*MB_jXB&Rmdk1E%eZmZYv42-dD^!LsfK*=VDLIBi~eRY94WHX|LoQOC$fNO0R8c!JW zHh5q^e_N7jj`L@SHp<)K&YVdSr>sjqF0VK(&IFZFyb*YUM)o-UM>3{3_~Fdq6Muo} zjW#Crr~+ONSO8YPx?nn%z8Dk7J43U_#g?Ny5@IQMJ)UCW@I&jIPB_Lc@)5VL@!D;7 N`T`U%tl?DI1pwbrT3P@A diff --git a/.github/native-bun-validation/path-identity-probe.ts b/.github/native-bun-validation/path-identity-probe.ts deleted file mode 100644 index 0627529087c..00000000000 --- a/.github/native-bun-validation/path-identity-probe.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { mkdtemp, mkdir, realpath, symlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { dirname, join, resolve } from 'node:path' - -// Public API diagnostic only. Preserve the tiny fixture for artifact inspection. -const base = process.env.BUN_PATH_PROBE_ROOT ?? tmpdir() -const directory = await mkdtemp(join(base, 'bun-path-identity-')) -const source = join(directory, 'source') -await mkdir(source) -await writeFile(join(source, 'entry.ts'), 'export const value = 42;\n') -const alias = join(directory, 'alias') -await symlink(source, alias, process.platform === 'win32' ? 'junction' : 'dir') - -const results = [] -for (const entrypoint of [join(source, 'entry.ts'), join(alias, 'entry.ts')]) { - const loads: Array<{ path: string; resolveDir: string }> = [] - let exactPathHookCalls = 0 - const exactFilter = new RegExp( - `^${entrypoint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, - ) - const result = await Bun.build({ - entrypoints: [entrypoint], - write: false, - plugins: [ - { - name: 'public-path-identity', - setup(build) { - build.onLoad({ filter: exactFilter }, () => { - exactPathHookCalls++ - }) - build.onLoad({ filter: /entry\.ts$/ }, (args) => { - loads.push({ path: args.path, resolveDir: dirname(args.path) }) - }) - }, - }, - ], - }) - results.push({ - entrypoint, - resolved: resolve(entrypoint), - realpath: await realpath(entrypoint), - exactPathHookCalls, - loads, - success: result.success, - logs: result.logs.map((log) => log.message), - }) -} -console.log( - JSON.stringify( - { - platform: process.platform, - arch: process.arch, - version: Bun.version, - revision: Bun.revision, - tmpdir: tmpdir(), - tmpdirRealpath: await realpath(tmpdir()), - directory, - results, - }, - null, - 2, - ), -) diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py deleted file mode 100644 index 9f6a56d3be7..00000000000 --- a/.github/native-bun-validation/prepare.py +++ /dev/null @@ -1,106 +0,0 @@ -import argparse -import gzip -import hashlib -import io -import json -from pathlib import Path, PurePosixPath -import re -import subprocess -import tarfile - - -BASE = "dca7d25e95cca39316c659a377dba6803805549f" -PATCH_HASH = "1a5cedfdb16551893d366b38bf7c5a0ad7d4d6c030e79c138623f3f282eabc2b" -ADDITIONAL = { - "src/bundler/input_source_map.rs", - "src/runtime/bake/dev_server/plugin_watch_store.rs", - "src/sourcemap/InputSourceMap.rs", - "test/bake/dev/barrel-hmr-renaming.test.ts", - "test/bake/dev/barrel-hmr.test.ts", - "test/bake/dev/client-plugin-cache.test.ts", -} - - -def digest(data): - return hashlib.sha256(data).hexdigest() - - -def allowed(name): - path = PurePosixPath(name) - return ( - not path.is_absolute() - and ".." not in path.parts - and "\\" not in name - and ( - name.startswith(("src/", "test/", "docs/")) - or name in {"Cargo.lock", "packages/bun-types/bun.d.ts"} - ) - ) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--bun", type=Path) - parser.add_argument("--out", type=Path) - parser.add_argument("--check-assets-only", action="store_true") - args = parser.parse_args() - data = Path(__file__).resolve().parent - manifest = json.loads((data / "native-v15-manifest.json").read_text()) - assert manifest["head"] == BASE - assert manifest["trackedPatchSha256"] == PATCH_HASH - assert set(manifest["additionalFiles"]) == ADDITIONAL - patch = gzip.decompress((data / "native-v15-tracked.patch.gz").read_bytes()) - assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" - paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) - assert paths, "No tracked patch paths" - tracked = [] - for old, new in paths: - assert old == new and allowed(old.decode()), "Unexpected tracked path" - tracked.append(old.decode()) - extra = {} - archive = gzip.decompress( - (data / "native-v15-additional-files.tar.gz").read_bytes() - ) - with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: - for member in bundle.getmembers(): - assert member.isfile(), "Non-regular archive entry" - assert member.name in ADDITIONAL and allowed(member.name) - assert member.name not in extra, "Duplicate archive entry" - content = bundle.extractfile(member).read() - assert digest(content) == manifest["additionalFiles"][member.name] - extra[member.name] = content - assert set(extra) == ADDITIONAL - print(json.dumps({"base": BASE, "patchSha256": PATCH_HASH, - "trackedPaths": tracked, "additionalFiles": manifest["additionalFiles"]}, indent=2)) - if args.check_assets_only: - return - assert args.bun and args.out, "--bun and --out are required" - bun = args.bun.resolve() - out = args.out.resolve() - actual = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=bun, text=True).strip() - assert actual == BASE, "Unexpected Bun checkout" - assert not subprocess.check_output(["git", "status", "--porcelain"], cwd=bun), "Bun checkout is dirty" - for name in extra: - assert not (bun / name).exists(), "Additional file already exists" - subprocess.run(["git", "apply", "--check", "-"], input=patch, cwd=bun, check=True) - subprocess.run(["git", "apply", "-"], input=patch, cwd=bun, check=True) - for name, content in extra.items(): - target = bun / name - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(content) - subprocess.run(["git", "diff", "--check"], cwd=bun, check=True) - for name, expected in manifest["changedSourceSha256"].items(): - assert allowed(name) and name in tracked - assert digest((bun / name).read_bytes()) == expected, f"Source hash mismatch: {name}" - out.mkdir(parents=True, exist_ok=True) - with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: - for name in sorted(set(tracked) | ADDITIONAL): - bundle.add(bun / name, arcname=name) - (out / "native-v15-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") - (out / "tracked.patch").write_bytes(patch) - for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: - (out / name).write_bytes((bun / name).read_bytes()) - - -if __name__ == "__main__": - main() diff --git a/.github/native-bun-validation/pure-bun-graph-browser.mjs b/.github/native-bun-validation/pure-bun-graph-browser.mjs deleted file mode 100644 index 56d26eea78d..00000000000 --- a/.github/native-bun-validation/pure-bun-graph-browser.mjs +++ /dev/null @@ -1,538 +0,0 @@ -import assert from 'node:assert/strict' -import { spawn, execFileSync } from 'node:child_process' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { - mkdtemp, - mkdir, - readFile, - realpath, - writeFile, - rm, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -const requireProject = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -) -const { chromium, expect } = requireProject('@playwright/test') -const sourceMapMode = process.env.PURE_BUN_SOURCE_MAPS === '1' -const largePairMode = process.env.PURE_BUN_LARGE_PAIR === '1' -const pluginRequire = createRequire( - path.join(root, 'packages/router-plugin/package.json'), -) -const babelRequire = createRequire(pluginRequire.resolve('@babel/core')) -const { AnyMap, originalPositionFor, sourceContentFor } = createRequire( - babelRequire.resolve('@jridgewell/remapping'), -)('@jridgewell/trace-mapping') -const binaries = [ - ['candidate', process.env.BUN_EXECUTABLE], - ['baseline', process.env.BUN_BASELINE_EXECUTABLE], - ['debug', process.env.BUN_DEBUG_EXECUTABLE], -].filter(([, binary]) => binary) -assert.ok(binaries.length, 'Set BUN_EXECUTABLE') -const output = - process.env.PURE_BUN_BROWSER_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/pure-bun-graph-${process.platform}.json`, - ) -await mkdir(path.dirname(output), { recursive: true }) -const browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), -}) -const results = [] -const mentions = (text) => - ['before.ts', 'after.ts', 'graph.ts', 'main.ts'].filter((name) => - text.includes(name), - ) -try { - for (const [label, binary] of binaries) { - for (const reloadWhileAfter of sourceMapMode - ? [true] - : largePairMode - ? [false] - : [false, true]) { - const name = `${label}-${reloadWhileAfter ? 'reload-B' : 'automatic'}` - console.log(`START ${name}`) - const directory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')), - ) - const result = { - name, - label, - binary, - reloadWhileAfter, - sourceMapMode, - largePairMode, - passed: false, - steps: [], - errors: [], - websocketFrames: [], - initialJavaScript: [], - documentLoads: 0, - } - let child, - context, - logs = '' - try { - await writeFile( - path.join(directory, 'index.html'), - '
', - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value} from './graph.ts';document.querySelector('#app').textContent=value;if(import.meta.hot)import.meta.hot.accept();`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value} from './before.ts';`, - ) - await writeFile( - path.join(directory, 'before.ts'), - `export const value='BEFORE';`, - ) - await writeFile( - path.join(directory, 'after.ts'), - `export const value='AFTER';`, - ) - const authoredSource = `export const value = 'BEFORE';\nexport function authoredThrow() {\n throw new Error('CACHED_CLOSURE_AUTHORED_THROW');\n}\n` - if (sourceMapMode) { - await writeFile( - path.join(directory, 'before.ts'), - `export {value, authoredThrow} from './cached-leaf.ts';`, - ) - await writeFile( - path.join(directory, 'cached-leaf.ts'), - authoredSource, - ) - await writeFile( - path.join(directory, 'after.ts'), - `export const value='AFTER';export function authoredThrow(){throw new Error('UNEXPECTED_AFTER_THROW')}`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value,authoredThrow} from './graph.ts';document.querySelector('#app').textContent=value;globalThis.__throwCached=authoredThrow;if(import.meta.hot)import.meta.hot.accept();`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value,authoredThrow} from './before.ts';`, - ) - } - if (largePairMode) { - await writeFile( - path.join(directory, 'shared.ts'), - `globalThis.sharedInits=(globalThis.sharedInits??0)+1;export const shared={initializations:globalThis.sharedInits};`, - ) - await writeFile( - path.join(directory, 'after.ts'), - `import {shared} from './shared.ts';export {shared};export const value='AFTER';export const padding={${Array.from({ length: Number(process.env.PURE_BUN_LARGE_FUNCTIONS ?? 40000) }, (_, index) => `k${index}:()=>${index}`).join(',')}};`, - ) - await writeFile( - path.join(directory, 'before.ts'), - `import {shared} from './shared.ts';export {shared};export const value='BEFORE';`, - ) - await writeFile( - path.join(directory, 'graph.ts'), - `export {value,shared} from './before.ts';`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {value,shared} from './graph.ts';import {shared as stable} from './shared.ts';document.querySelector('#app').textContent=value;globalThis.__pureShared={identity:shared===stable,initializations:shared.initializations};if(import.meta.hot){import.meta.hot.accept();import.meta.hot.on('bun:beforeUpdate',()=>console.debug('__PURE_LIFECYCLE__before'));import.meta.hot.on('bun:afterUpdate',()=>console.debug('__PURE_LIFECYCLE__after'));}`, - ) - } - await writeFile( - path.join(directory, 'server.ts'), - `import html from './index.html';const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}});console.log('READY '+JSON.stringify({url:server.url.href,pid:process.pid}));`, - ) - let readyResolve, readyReject - const ready = new Promise((resolve, reject) => { - readyResolve = resolve - readyReject = reject - }) - child = spawn(binary, ['server.ts'], { - cwd: directory, - env: { ...process.env, NODE_ENV: 'development' }, - stdio: ['ignore', 'pipe', 'pipe'], - windowsHide: true, - }) - child.on('error', readyReject) - child.on('exit', (code, signal) => - readyReject(new Error(`Bun exited (${code},${signal})\n${logs}`)), - ) - let pending = '' - child.stdout.on('data', (chunk) => { - logs += chunk - pending += chunk - let newline - while ((newline = pending.indexOf('\n')) !== -1) { - const line = pending.slice(0, newline) - pending = pending.slice(newline + 1) - if (line.startsWith('READY ')) { - try { - readyResolve(JSON.parse(line.slice(6))) - } catch (error) { - readyReject(error) - } - } - } - }) - child.stderr.on('data', (chunk) => { - logs += chunk - }) - let timer - const info = await Promise.race([ - ready, - new Promise((_, reject) => { - timer = setTimeout( - () => reject(new Error(`Startup deadline\n${logs}`)), - 20000, - ) - }), - ]).finally(() => clearTimeout(timer)) - result.pid = info.pid - result.revision = execFileSync(binary, ['--revision'], { - encoding: 'utf8', - }).trim() - result.binarySha256 = createHash('sha256') - .update(await readFile(binary)) - .digest('hex') - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.__pureGraphDocumentToken = crypto.randomUUID() - }) - if (largePairMode) { - await context.addInitScript(() => { - const key = Symbol.for('bun:hmr') - let callback - Object.defineProperty(globalThis, key, { - configurable: true, - get() { - return callback - }, - set(original) { - callback = function (...args) { - const record = (kind) => - console.debug( - '__PURE_CALLBACK__' + - JSON.stringify({ - kind, - id: args[1], - keys: Object.keys(args[0]), - time: performance.now(), - documentToken: globalThis.__pureGraphDocumentToken, - }), - ) - record('start') - try { - return Reflect.apply(original, this, args) - } finally { - record('return') - } - } - }, - }) - }) - } - const page = await context.newPage() - const session = sourceMapMode ? await context.newCDPSession(page) : null - const scripts = new Map() - if (session) { - session.on('Debugger.scriptParsed', (script) => - scripts.set(script.scriptId, script), - ) - await session.send('Debugger.enable') - } - let phase = 'initial-A' - let pairedWrite - const assets = [] - page.on('load', () => { - result.documentLoads++ - }) - page.on('console', (message) => { - if (message.type() === 'error') { - result.errors.push({ phase, type: 'console', text: message.text() }) - } - }) - page.on('console', (message) => { - if (message.text().startsWith('__PURE_CALLBACK__')) { - ;(result.callbackEvents ??= []).push({ - ...JSON.parse(message.text().slice('__PURE_CALLBACK__'.length)), - phase, - }) - } - if (message.text().startsWith('__PURE_LIFECYCLE__')) { - ;(result.lifecycleEvents ??= []).push({ - phase, - event: message.text().slice('__PURE_LIFECYCLE__'.length), - }) - } - }) - page.on('pageerror', (error) => - result.errors.push({ phase, type: 'pageerror', text: error.message }), - ) - page.on('websocket', (socket) => - socket.on('framereceived', (event) => { - const bytes = Buffer.from(event.payload) - const sourceMapId = bytes - .toString('utf8') - .match( - /sourceMappingURL=\/_bun\/client\/([a-f0-9]{16})\.js\.map/, - )?.[1] - result.websocketFrames.push({ - phase, - bytes: bytes.length, - ...(sourceMapId ? { sourceMapId } : {}), - mentionedModules: mentions(bytes.toString('utf8')), - base64: bytes.toString('base64'), - }) - if ( - largePairMode && - phase === 'A-to-B' && - !pairedWrite && - bytes.toString('utf8').includes('self[Symbol.for("bun:hmr")]') - ) { - pairedWrite = writeFile( - path.join(directory, 'graph.ts'), - `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-TWO';`, - ) - } - }), - ) - page.on('response', (response) => { - if (new URL(response.url()).pathname.endsWith('.js')) { - const responsePhase = phase - assets.push( - response - .text() - .then(async (text) => { - const file = output.replace( - /\.json$/, - `-${name}-js${result.initialJavaScript.length}.txt`, - ) - result.initialJavaScript.push({ - phase: responsePhase, - url: response.url(), - mentionedModules: mentions(text), - file, - }) - await writeFile(file, text) - }) - .catch((error) => - result.initialJavaScript.push({ - phase: responsePhase, - error: String(error), - }), - ), - ) - } - }) - const checkpoint = async (expected) => { - await expect(page.locator('#app')).toHaveText(expected, { - timeout: 15000, - }) - assert.deepEqual( - await (await fetch(new URL('/__info', info.url))).json(), - { pid: info.pid }, - ) - await Promise.all(assets) - result.steps.push({ - phase, - text: expected, - documentToken: await page.evaluate( - () => globalThis.__pureGraphDocumentToken, - ), - documentLoads: result.documentLoads, - errorCount: result.errors.length, - }) - if (largePairMode) { - assert.deepEqual( - await page.evaluate(() => globalThis.__pureShared), - { identity: true, initializations: 1 }, - ) - } - } - const checkAuthoredThrow = async () => { - await session.send('Debugger.setPauseOnExceptions', { state: 'all' }) - let resumePromise - const paused = new Promise((resolve) => - session.once('Debugger.paused', (event) => { - resolve(event) - resumePromise = session.send('Debugger.resume') - }), - ) - const evaluation = session.send('Runtime.evaluate', { - expression: `try { globalThis.__throwCached() } catch(error) { error.message }`, - returnByValue: true, - }) - let pauseTimer - const event = await Promise.race([ - paused, - new Promise((_, reject) => { - pauseTimer = setTimeout( - () => reject(new Error('Expected authored exception pause')), - 15000, - ) - }), - ]).finally(() => clearTimeout(pauseTimer)) - await resumePromise - const evaluated = await evaluation - await session.send('Debugger.setPauseOnExceptions', { state: 'none' }) - assert.equal(evaluated.result.value, 'CACHED_CLOSURE_AUTHORED_THROW') - const frame = event.callFrames[0], - script = scripts.get(frame.location.scriptId) - assert.ok( - script?.sourceMapURL, - 'Throwing script must declare a source map', - ) - const { scriptSource } = await session.send( - 'Debugger.getScriptSource', - { scriptId: script.scriptId }, - ) - const mapUrl = script.sourceMapURL.startsWith('/') - ? new URL(script.sourceMapURL, info.url).href - : new URL( - script.sourceMapURL, - new URL(script.url || info.url, info.url), - ).href - assert.ok(!mapUrl.startsWith('data:'), 'Expected network source map') - const response = await fetch(mapUrl) - assert.equal(response.status, 200) - const map = await response.json(), - trace = AnyMap(map) - const generated = { - line: frame.location.lineNumber + 1, - column: frame.location.columnNumber, - } - const traced = originalPositionFor(trace, generated) - assert.ok(traced.source, 'Authored source is required') - const tracedFile = traced.source.startsWith('file:') - ? fileURLToPath(traced.source) - : path.resolve(directory, traced.source) - assert.equal( - path.normalize(tracedFile), - path.join(directory, 'cached-leaf.ts'), - ) - assert.equal(traced.line, 3) - assert.equal(traced.column, 2) - assert.equal( - sourceContentFor(trace, traced.source, true), - authoredSource, - ) - const snapshot = output.replace(/\.json$/, `-${name}-${phase}-throw`) - await writeFile(snapshot + '.js', scriptSource) - await writeFile(snapshot + '.js.map', JSON.stringify(map)) - ;(result.authoredThrows ??= []).push({ - phase, - scriptUrl: script.url, - sourceMapURL: script.sourceMapURL, - mapUrl, - generated, - traced, - sourceContentMatches: true, - snapshot, - }) - } - await page.goto(info.url) - await checkpoint('BEFORE') - if (sourceMapMode) { - await checkAuthoredThrow() - } - phase = 'A-to-B' - await writeFile( - path.join(directory, 'graph.ts'), - sourceMapMode - ? `export {value,authoredThrow} from './after.ts';` - : largePairMode - ? `import {value as label,shared} from './after.ts';export {shared};export const value=label+'-ONE';` - : `export {value} from './after.ts';`, - ) - await checkpoint(largePairMode ? 'AFTER-TWO' : 'AFTER') - if (largePairMode) { - assert.ok( - pairedWrite, - 'Second public file write was triggered by first HMR frame', - ) - await pairedWrite - assert.equal( - result.documentLoads, - 1, - 'Paired updates must retain the document', - ) - } - if (reloadWhileAfter) { - phase = 'reload-B' - await page.reload() - await checkpoint('AFTER') - } - phase = 'B-to-A' - await writeFile( - path.join(directory, 'graph.ts'), - sourceMapMode - ? `export {value,authoredThrow} from './before.ts';` - : largePairMode - ? `export {value,shared} from './before.ts';` - : `export {value} from './before.ts';`, - ) - await checkpoint('BEFORE') - if (sourceMapMode) { - assert.equal( - result.documentLoads, - 2, - 'Restoration must not fall back to another document reload', - ) - await checkAuthoredThrow() - } - assert.deepEqual(result.errors, [], 'Unexpected browser errors') - result.passed = true - console.log(`PASS ${name}`) - } catch (error) { - result.error = error instanceof Error ? error.stack : String(error) - console.log(`FAIL ${name}: ${String(error).split('\n')[0]}`) - } finally { - result.serverLog = logs - try { - await context?.close() - } finally { - if (child && child.exitCode === null && child.signalCode === null) { - child.kill() - await new Promise((resolve) => child.once('exit', resolve)) - } - await rm(directory, { recursive: true, force: true }) - } - } - results.push(result) - await writeFile( - output, - JSON.stringify( - { - platform: process.platform, - node: process.version, - sourceMapMode, - largePairMode, - passed: results.filter((result) => result.passed).length, - cases: binaries.length * (sourceMapMode || largePairMode ? 1 : 2), - results, - }, - null, - 2, - ) + '\n', - ) - } - } -} finally { - await browser.close() -} -console.log( - `RESULT ${results.filter((result) => result.passed).length}/${results.length}; ${output}`, -) -if (results.some((result) => !result.passed)) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs b/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs deleted file mode 100644 index a8f22394fd3..00000000000 --- a/.github/native-bun-validation/pure-bun-pending-batches-browser.mjs +++ /dev/null @@ -1,360 +0,0 @@ -import assert from 'node:assert/strict' -import { spawn, execFileSync } from 'node:child_process' -import { createHash } from 'node:crypto' -import { createRequire } from 'node:module' -import { watch } from 'node:fs' -import { - mkdtemp, - mkdir, - readFile, - realpath, - writeFile, - rm, -} from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import { setTimeout as batchInterval } from 'node:timers/promises' -const root = - process.env.ROUTER_REPOSITORY_ROOT ?? - fileURLToPath(new URL('../../../', import.meta.url)) -const binary = process.env.BUN_EXECUTABLE -assert.ok(binary, 'Set BUN_EXECUTABLE') -const output = - process.env.PENDING_BATCH_OUTPUT ?? - path.join( - root, - `.cache/bun-dev-validation/results/pure-bun-pending-batches-${process.platform}.json`, - ) -await mkdir(path.dirname(output), { recursive: true }) -const { chromium, expect } = createRequire( - path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), -)('@playwright/test') -const directory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pending-batches-')), -) -const controlDirectory = await realpath( - await mkdtemp(path.join(tmpdir(), 'bun-pending-control-')), -) -const releaseFile = path.join(controlDirectory, 'release') -const blockThread = process.env.PENDING_BATCH_BLOCK !== '0' -const nativeSync = process.env.PENDING_BATCH_NATIVE_SYNC === '1' -const captureHmr = process.env.PENDING_BATCH_CAPTURE_HMR === '1' -const tracePath = process.env.BUN_WATCHER_TRACE -if (nativeSync) { - assert.ok(tracePath, 'Native batch synchronization needs BUN_WATCHER_TRACE') -} -const result = { - binary, - blockThread, - nativeSync, - tracePath, - binarySha256: createHash('sha256') - .update(await readFile(binary)) - .digest('hex'), - revision: execFileSync(binary, ['--revision'], { encoding: 'utf8' }).trim(), - directory, - controlDirectory, - passed: false, - writes: [], - nativeBatches: [], - ipc: [], - browserErrors: [], - documentLoads: 0, -} -let child, - browser, - context, - logs = '', - page -const assetCaptures = [] -const snapshot = async () => ({ - text: await page.locator('#app').textContent(), - documentToken: await page.evaluate(() => globalThis.documentToken), - documentLoads: result.documentLoads, -}) -const waitNativeBatch = async (name) => { - const wanted = path.join(directory, name + '.ts').replaceAll('\\', '/') - let observer, timer - try { - const event = await new Promise((resolve, reject) => { - const check = async () => { - try { - const text = await readFile(tracePath, 'utf8') - for (const line of text - .slice(0, text.lastIndexOf('\n') + 1) - .split('\n') - .filter(Boolean)) { - const batch = JSON.parse(line) - const entry = Object.entries(batch.files).find( - ([filename]) => filename.replaceAll('\\', '/') === wanted, - ) - if (entry) { - resolve({ - name, - timestamp: batch.timestamp, - path: entry[0], - ...entry[1], - }) - return - } - } - } catch (error) { - if (error.code !== 'ENOENT') { - reject(error) - } - } - } - observer = watch(path.dirname(tracePath), (event, filename) => { - if (String(filename) === path.basename(tracePath)) { - void check() - } - }) - timer = setTimeout( - () => reject(new Error('Native watcher batch deadline for ' + name)), - 15000, - ) - void check() - }) - result.nativeBatches.push(event) - } finally { - observer?.close() - clearTimeout(timer) - } -} -try { - await writeFile( - path.join(directory, 'index.html'), - `

`, - ) - await writeFile( - path.join(directory, 'main.ts'), - `import {a} from './a.ts';import {b} from './b.ts';import {c} from './c.ts';document.querySelector('#app').textContent=[a,b,c].join('|');if(import.meta.hot)import.meta.hot.accept();`, - ) - for (const name of ['a', 'b', 'c']) { - await writeFile( - path.join(directory, name + '.ts'), - `export const ${name}='${name.toUpperCase()}0';\n`, - ) - } - await writeFile( - path.join(directory, 'server.ts'), - ` - import html from './index.html';import {existsSync} from 'node:fs'; - const releaseFile=${JSON.stringify(releaseFile)}; - process.on('message',message=>{ - if(message==='block'){ - process.send({phase:'blocked',time:Date.now()}); - const deadline=Date.now()+15000; - while(!existsSync(releaseFile)){if(Date.now()>deadline){throw new Error('External release deadline exceeded')}} - process.send({phase:'released',time:Date.now()}); - } - }); - const server=Bun.serve({hostname:'127.0.0.1',port:0,development:{hmr:true},routes:{'/__info':()=>Response.json({pid:process.pid}),'/*':html}}); - process.send({phase:'ready',url:server.url.href,pid:process.pid}); - `, - ) - let readyResolve, readyReject, blockedResolve, releasedResolve - const ready = new Promise((resolve, reject) => { - readyResolve = resolve - readyReject = reject - }) - const blocked = new Promise((resolve) => { - blockedResolve = resolve - }) - const released = new Promise((resolve) => { - releasedResolve = resolve - }) - child = spawn(binary, ['server.ts'], { - cwd: directory, - env: { ...process.env, NODE_ENV: 'development' }, - stdio: ['ignore', 'pipe', 'pipe', 'ipc'], - windowsHide: true, - }) - child.on('error', readyReject) - child.on('exit', (code, signal) => - readyReject(new Error(`Server exited ${code}/${signal}: ${logs}`)), - ) - child.stdout.on('data', (chunk) => { - logs += chunk - }) - child.stderr.on('data', (chunk) => { - logs += chunk - }) - child.on('message', (message) => { - result.ipc.push(message) - if (message.phase === 'ready') { - readyResolve(message) - } - if (message.phase === 'blocked') { - blockedResolve(message) - } - if (message.phase === 'released') { - releasedResolve(message) - } - }) - const deadline = async (promise, label) => { - let timer - return Promise.race([ - promise, - new Promise((_, reject) => { - timer = setTimeout( - () => reject(new Error(`${label} deadline: ${logs}`)), - 20000, - ) - }), - ]).finally(() => clearTimeout(timer)) - } - const info = await deadline(ready, 'Startup') - result.pid = info.pid - browser = await chromium.launch({ - headless: true, - ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH - ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } - : {}), - }) - context = await browser.newContext() - await context.addInitScript(() => { - globalThis.documentToken = crypto.randomUUID() - }) - page = await context.newPage() - if (captureHmr) { - result.websocketFrames = [] - result.initialJavaScript = [] - const session = await context.newCDPSession(page) - await session.send('Network.enable') - session.on('Network.webSocketFrameReceived', (event) => { - const { opcode, payloadData } = event.response - const bytes = Buffer.from(payloadData, opcode === 2 ? 'base64' : 'utf8') - const decoded = bytes.toString('utf8') - const frame = { - requestId: event.requestId, - timestamp: event.timestamp, - opcode, - bytes: bytes.length, - base64: bytes.toString('base64'), - } - result.websocketFrames.push(frame) - if (decoded.includes('self[Symbol.for("bun:hmr")]')) { - frame.file = output.replace( - /\.json$/, - `-hmr${result.websocketFrames.length}.txt`, - ) - assetCaptures.push(writeFile(frame.file, decoded)) - } - }) - page.on('response', (response) => { - if (!new URL(response.url()).pathname.endsWith('.js')) { - return - } - const asset = { - url: response.url(), - file: output.replace( - /\.json$/, - `-initial${result.initialJavaScript.length}.js`, - ), - } - result.initialJavaScript.push(asset) - assetCaptures.push( - response - .text() - .then((text) => writeFile(asset.file, text)) - .catch((error) => { - asset.error = String(error) - }), - ) - }) - } - page.on('load', () => { - result.documentLoads++ - }) - page.on('console', (message) => { - if (message.type() === 'error') { - result.browserErrors.push({ type: 'console', text: message.text() }) - } - }) - page.on('pageerror', (error) => - result.browserErrors.push({ type: 'pageerror', text: error.message }), - ) - await page.goto(info.url) - await expect(page.locator('#app')).toHaveText('A0|B0|C0') - result.before = await snapshot() - if (blockThread) { - child.send('block') - await deadline(blocked, 'IPC block') - } - for (const name of ['a', 'b', 'c']) { - const started = Date.now(), - contents = `export const ${name}='${name.toUpperCase()}1';\n` - await writeFile(path.join(directory, name + '.ts'), contents) - result.writes.push({ name, started, finished: Date.now(), contents }) - if (nativeSync) { - await waitNativeBatch(name) - } else { - await batchInterval(150) - } - } - if (blockThread) { - await writeFile(releaseFile, 'release\n') - await deadline(released, 'IPC release') - } - try { - await expect(page.locator('#app')).toHaveText('A1|B1|C1', { timeout: 5000 }) - } finally { - result.after = await snapshot() - } - assert.equal( - result.after.documentToken, - result.before.documentToken, - 'Updates must retain the document', - ) - assert.equal(result.documentLoads, 1) - assert.deepEqual(result.browserErrors, []) - assert.deepEqual(await (await fetch(new URL('/__info', info.url))).json(), { - pid: info.pid, - }) - result.passed = true -} catch (error) { - result.error = error.stack ?? String(error) - result.moduleBytes = Object.fromEntries( - await Promise.all( - ['a', 'b', 'c'].map(async (name) => [ - name, - await readFile(path.join(directory, name + '.ts'), 'utf8'), - ]), - ), - ) - result.preservedFixture = true -} finally { - await writeFile(releaseFile, 'cleanup release\n').catch(() => {}) - await Promise.all(assetCaptures) - await context?.close() - await browser?.close() - if (child && child.exitCode === null && child.signalCode === null) { - child.kill() - await new Promise((resolve) => child.once('exit', resolve)) - } - result.serverLog = logs - if (result.passed) { - await rm(directory, { recursive: true, force: true }) - } - await rm(controlDirectory, { recursive: true, force: true }) - await writeFile(output, JSON.stringify(result, null, 2) + '\n') -} -console.log( - JSON.stringify({ - passed: result.passed, - before: result.before, - after: result.after, - writes: result.writes.map(({ name, started, finished }) => ({ - name, - started, - finished, - })), - error: result.error?.split('\n')[0], - output, - }), -) -if (!result.passed) { - process.exitCode = 1 -} diff --git a/.github/native-bun-validation/require-tests-reporter.mjs b/.github/native-bun-validation/require-tests-reporter.mjs deleted file mode 100644 index bb1972b99d2..00000000000 --- a/.github/native-bun-validation/require-tests-reporter.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import { writeFileSync } from 'node:fs' - -export default class RequireTestsReporter { - tests = [] - - onTestEnd(test, result) { - this.tests.push({ - title: test.titlePath().join(' > '), - status: result.status, - errors: result.errors, - }) - } - - onEnd(result) { - const passed = - this.tests.length > 0 && - this.tests.every((test) => test.status === 'passed') - writeFileSync( - process.env.NATIVE_REPORT, - JSON.stringify({ result, tests: this.tests }, null, 2) + '\n', - ) - if (!passed) { - console.error( - 'Native validation requires every selected test to execute and pass; skips fail validation.', - ) - return { status: 'failed' } - } - } -} diff --git a/.github/native-bun-validation/watcher-poll-test.patch.gz b/.github/native-bun-validation/watcher-poll-test.patch.gz deleted file mode 100644 index 5d3eaf82a9a02e6f3508f02715347ec38ed6ccdd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 958 zcmV;v13~;BiwFP!000003Z+%sZreBzefL*P^-xGFS(e?{PVFj5leR#B76{TT@~~Je zXlWF)kx4H(zG35kUr>}UwB4YK&4Uq&E0IO^gJ2WfE@xu5+XPrJ%Er~kLUF<`yxbgJ zL!smZJRx%&6xtg$HgTqm#`~LQ?F}nd{ciLwfv|rTwY!E{Ar<(U6q;hKc)FJMQ_4}#+pR^wHyZ2W_`wtCKo zHDsph;GjZ@B;{;lOzfJ29FleN6roueQx*fY#g?batGm7^LxwMhOHMb5?3wOQ2W z(vel(m1c7@mcsX{GJBCz`%?}gK0!GnNI@e#*oE&3XwBt_xL1$II^E1tvuW?d#ASw< zW9|h(s=typ|WlxSV1}G0AK6y^qPub@FnPIB$V9$zFc0%OG_iFRR_O?FBL6l6<$W ztrk3tach?9tmUOa)p!NtIq z+M~GSnzR}FJ}H(Vgy6+Bv=_KAdny .native-proof/final-disk.log - if [[ -f .native-bun/build/native-release/bun-profile ]]; then - cp .native-bun/build/native-release/bun-profile .native-proof/binary/bun - python3 - <<'PY' - import hashlib, json, os, subprocess - from pathlib import Path - binary = Path('.native-proof/binary/bun') - manifest = json.loads(Path('.github/native-bun-validation/native-v15-manifest.json').read_text()) - proof = { - 'sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), - 'base': manifest['head'], - 'patchSha256': manifest['trackedPatchSha256'], - 'additionalFiles': manifest['additionalFiles'], - 'version': subprocess.check_output([str(binary.resolve()), '--version'], text=True).strip(), - 'workflowRun': os.environ['GITHUB_RUN_ID'], - 'workflowCommit': os.environ['GITHUB_SHA'], - 'buildProfile': 'release --lto=off --canary=off', - } - Path('.native-proof/binary-proof.json').write_text(json.dumps(proof, indent=2) + '\n') - PY - fi - - name: Upload native binary, source, toolchain and test proof - if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: native-macos-arm64-bun - path: .native-proof/ - include-hidden-files: true - if-no-files-found: error - retention-days: 14 - - browser: - if: always() && !cancelled() && github.repository == 'RentnerKev/router' && inputs.router_ref != '' && (inputs.binary_run != '' || needs.native.result == 'success') - needs: native - runs-on: macos-15 - defaults: - run: - shell: bash - steps: - - name: Checkout exact Router commit - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.router_ref || github.sha }} - persist-credentials: false - - name: Require immutable Router ref - env: - ROUTER_REF: ${{ inputs.router_ref || github.sha }} - run: | - [[ "$ROUTER_REF" =~ ^[0-9a-f]{40}$ ]] - [[ "$(git rev-parse HEAD)" == "$ROUTER_REF" ]] - - name: Download native binary and proof - env: - GH_TOKEN: ${{ github.token }} - BINARY_RUN: ${{ inputs.binary_run || github.run_id }} - run: | - [[ "$BINARY_RUN" =~ ^[0-9]+$ ]] - gh run download "$BINARY_RUN" --repo "$GITHUB_REPOSITORY" --name native-macos-arm64-bun --dir .native-artifact - - name: Setup pnpm - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: '26.10.0' - package-manager-cache: false - - name: Checkout matching native regression sources - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/bun - ref: dca7d25e95cca39316c659a377dba6803805549f - path: .cache/native-bun-validation/test-source - persist-credentials: false - - name: Execute verified native artifact regressions - id: native_regressions - continue-on-error: true - run: python3 .github/native-bun-validation/artifact-tests.py - - name: Record native module path identity - run: .native-artifact/binary/bun .github/native-bun-validation/path-identity-probe.ts > .native-browser-proof/path-identity.json - - name: Install Router dependencies - run: pnpm install --frozen-lockfile --filter . --filter 'tanstack-router-e2e-react-bun-basic-file-based...' - - name: Checkout actual unplugin PR source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/unplugin - ref: 4d01143e6f60a6a93ed40411629ea4da14f540a7 - path: .native-unplugin - persist-credentials: false - - name: Build actual unplugin PR distribution - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - version: '12.14.0' - package_json_file: .native-unplugin/package.json - dest: ~/native-pnpm12 - - name: Install and build actual unplugin PR - run: | - pnpm --dir .native-unplugin install --frozen-lockfile - pnpm --dir .native-unplugin build - test -f .native-unplugin/dist/index.mjs - - name: Restore Router pnpm version - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - dest: ~/native-pnpm11 - - name: Prepare isolated native Bun wrapper and unplugin preload - run: node .github/native-bun-validation/browser-setup.mjs - - name: Install Chromium - run: pnpm exec playwright install chromium --only-shell - - name: Execute Bun's native Chromium ordering regression - id: native_chrome - continue-on-error: true - run: python3 .github/native-bun-validation/chrome-test.py - - name: Preserve native HMR script order in the browser - id: hmr_order - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PURE_BUN_LARGE_PAIR: '1' - PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-hmr-order.json - run: node .github/native-bun-validation/pure-bun-graph-browser.mjs - - name: Map restored native dependencies to their authored source - id: restored_maps - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PURE_BUN_SOURCE_MAPS: '1' - PURE_BUN_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pure-restored-maps.json - run: node .github/native-bun-validation/pure-bun-graph-browser.mjs - - name: Apply every native watcher batch in the browser - id: pending_batches - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - PENDING_BATCH_NATIVE_SYNC: '1' - BUN_WATCHER_TRACE: ${{ github.workspace }}/.native-browser-proof/pending-batches-watcher.jsonl - PENDING_BATCH_OUTPUT: ${{ github.workspace }}/.native-browser-proof/pending-batches-browser.json - run: node .github/native-bun-validation/pure-bun-pending-batches-browser.mjs - - name: Production builds, navigation and source maps - id: production - continue-on-error: true - env: - NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/production-results.json - run: | - set -o pipefail - pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/production.log - - name: Native development navigation, HMR, recovery and source maps - id: development - if: ${{ !cancelled() && steps.production.outcome != 'skipped' }} - continue-on-error: true - env: - NATIVE_REPORT: ${{ github.workspace }}/.native-browser-proof/development-results.json - run: | - set -o pipefail - pnpm nx run tanstack-router-e2e-react-bun-basic-file-based:test:e2e:bun:dev --outputStyle=stream --skipRemoteCache -- --reporter="line,$GITHUB_WORKSPACE/.github/native-bun-validation/require-tests-reporter.mjs" 2>&1 | tee .native-browser-proof/development.log - - name: Checkout actual Jiti PR source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - repository: RentnerKev/jiti - ref: 2669fd42050027531c7bbeb0e61b61f7ae35517a - path: .native-jiti - persist-credentials: false - - name: Build actual Jiti PR distribution - uses: pnpm/action-setup@739bfe42ca9233c5e6aca07c1a25a9d34aca49b0 # v6.0.7 - with: - version: '10.30.3' - package_json_file: .native-jiti/package.json - dest: ~/native-pnpm10 - - name: Install and build actual Jiti PR - working-directory: .native-jiti - run: | - [[ "$(pnpm --ignore-workspace --version)" == '10.30.3' ]] - pnpm --ignore-workspace install --frozen-lockfile - pnpm --ignore-workspace build - test -f dist/jiti.cjs - - name: Imported virtual configuration helpers with actual Jiti PR - id: configuration - continue-on-error: true - env: - JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs - run: | - mkdir -p packages/router-generator/.cache - cp .github/native-bun-validation/helper-import-preload.mjs packages/router-generator/.cache/helper-import-preload.mjs - if "$BUN_EXECUTABLE" .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-installed.json; then - echo 'Installed Jiti also passed the helper cases.' - fi - "$BUN_EXECUTABLE" --preload ./packages/router-generator/.cache/helper-import-preload.mjs .github/native-bun-validation/combined-generator.mjs > .native-browser-proof/configuration-candidate.json - - name: Imported helper edits in the running native browser - id: configuration_browser - continue-on-error: true - env: - ROUTER_REPOSITORY_ROOT: ${{ github.workspace }} - UNPLUGIN_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-unplugin/dist/index.mjs - JITI_CANDIDATE_ENTRY: ${{ github.workspace }}/.native-jiti/lib/jiti.mjs - BUN_PLUGIN_PRELOAD: ${{ github.workspace }}/.github/native-bun-validation/helper-browser-preload.mjs - HELPER_BROWSER_OUTPUT: ${{ github.workspace }}/.native-browser-proof/configuration-browser.json - run: node .github/native-bun-validation/helper-browser.mjs - - name: Upload all browser results - if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: native-macos-arm64-router-browser - path: | - .native-browser-proof/ - e2e/react-router/bun-basic-file-based/test-results/ - e2e/react-router/bun-basic-file-based/.cache/ - include-hidden-files: true - if-no-files-found: warn - retention-days: 14 - - name: Require browser and configuration suites to pass - if: always() - env: - PRODUCTION: ${{ steps.production.outcome }} - DEVELOPMENT: ${{ steps.development.outcome }} - CONFIGURATION: ${{ steps.configuration.outcome }} - CONFIGURATION_BROWSER: ${{ steps.configuration_browser.outcome }} - NATIVE_REGRESSIONS: ${{ steps.native_regressions.outcome }} - HMR_ORDER: ${{ steps.hmr_order.outcome }} - RESTORED_MAPS: ${{ steps.restored_maps.outcome }} - NATIVE_CHROME: ${{ steps.native_chrome.outcome }} - PENDING_BATCHES: ${{ steps.pending_batches.outcome }} - run: | - [[ "$PRODUCTION" == success && "$DEVELOPMENT" == success && "$CONFIGURATION" == success && "$CONFIGURATION_BROWSER" == success && "$NATIVE_REGRESSIONS" == success && "$HMR_ORDER" == success && "$RESTORED_MAPS" == success && "$NATIVE_CHROME" == success && "$PENDING_BATCHES" == success ]] From 0116a978e063d5469c6754a63086ef732b1fdfc4 Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 17:14:43 +0200 Subject: [PATCH 30/31] fix(router-plugin): address Bun integration review regressions --- .../bun-basic-file-based/build.mjs | 5 +- .../bun-basic-file-based/playwright.config.ts | 5 +- packages/router-generator/src/generator.ts | 8 ++- .../tests/virtual-config.test.ts | 56 +++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/e2e/react-router/bun-basic-file-based/build.mjs b/e2e/react-router/bun-basic-file-based/build.mjs index 08ac179f34c..3c5e82c5ad5 100644 --- a/e2e/react-router/bun-basic-file-based/build.mjs +++ b/e2e/react-router/bun-basic-file-based/build.mjs @@ -288,9 +288,9 @@ if (!process.argv.includes('--serve')) { ]), ), ) - Bun.serve({ + const server = Bun.serve({ hostname: '127.0.0.1', - port: Number(process.env.E2E_APP_PORT ?? 43187), + port: Number(process.env.E2E_APP_PORT ?? 0), fetch(request) { const url = new URL(request.url) const pathname = url.pathname @@ -314,4 +314,5 @@ if (!process.argv.includes('--serve')) { ) }, }) + console.log(`E2E app: ${server.url}`) } diff --git a/e2e/react-router/bun-basic-file-based/playwright.config.ts b/e2e/react-router/bun-basic-file-based/playwright.config.ts index fe88f232025..34cb7553a71 100644 --- a/e2e/react-router/bun-basic-file-based/playwright.config.ts +++ b/e2e/react-router/bun-basic-file-based/playwright.config.ts @@ -1,6 +1,7 @@ import { defineConfig, devices } from '@playwright/test' +import { appServerReady } from '@tanstack/router-e2e-utils' -const port = Number(process.env.E2E_APP_PORT ?? 43187) +const port = Number(process.env.E2E_APP_PORT ?? 0) export default defineConfig({ testDir: '.', @@ -17,7 +18,7 @@ export default defineConfig({ webServer: { command: 'bun build.mjs --serve', env: { E2E_APP_PORT: String(port) }, - url: `http://127.0.0.1:${port}/__builds`, + wait: appServerReady, reuseExistingServer: false, stdout: 'pipe', }, diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index 3b68f73ec99..cba9a393ddb 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -1660,7 +1660,13 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved } // Virtual configuration modules and the helpers loaded while evaluating them. - if (this.configFilePaths.has(path.resolve(filePath))) { + const resolvedFilePath = path.resolve(filePath) + if ( + this.configFilePaths.has(resolvedFilePath) || + (typeof this.config.virtualRouteConfig === 'string' && + resolvedFilePath === + path.resolve(this.root, this.config.virtualRouteConfig)) + ) { return true } diff --git a/packages/router-generator/tests/virtual-config.test.ts b/packages/router-generator/tests/virtual-config.test.ts index 1c0804050b3..49fe7fabc13 100644 --- a/packages/router-generator/tests/virtual-config.test.ts +++ b/packages/router-generator/tests/virtual-config.test.ts @@ -11,6 +11,62 @@ import path from 'node:path' import { expect, test } from 'vitest' import { Generator, getConfig } from '../src' +test.each( + ['relative', 'absolute'].flatMap((configPath) => + [ + { failure: 'syntax', source: 'export default {' }, + { + failure: 'schema', + source: "export default { type: 'root', file: 42 }", + }, + ].map((invalid) => ({ configPath, ...invalid })), + ), +)( + 'recovers from an initial $failure error in a $configPath virtual configuration', + async ({ configPath, source }) => { + const root = await mkdtemp(path.join(tmpdir(), 'router-virtual-recovery-')) + const routes = path.join(root, 'routes') + const configFile = path.join(root, 'virtual-routes.ts') + const generatedRouteTree = path.join(root, 'routeTree.gen.ts') + try { + await mkdir(routes) + await Promise.all([ + writeFile( + path.join(routes, '__root.tsx'), + `import { createRootRoute } from '@tanstack/react-router' +export const Route = createRootRoute({})\n`, + ), + writeFile(configFile, source), + ]) + const generator = new Generator({ + root, + config: getConfig( + { + routesDirectory: routes, + generatedRouteTree, + virtualRouteConfig: + configPath === 'relative' ? 'virtual-routes.ts' : configFile, + tmpDir: path.join(root, 'tmp'), + disableLogging: true, + }, + root, + ), + }) + await expect(generator.run()).rejects.toThrow() + await writeFile( + configFile, + "export default { type: 'root', file: '__root.tsx' }\n", + ) + await generator.run({ path: configFile, type: 'update' }) + expect(await readFile(generatedRouteTree, 'utf8')).toContain( + "import { Route as rootRouteImport } from './routes/__root'", + ) + } finally { + await rm(root, { recursive: true, force: true }) + } + }, +) + test.each([ { source: 'configuration', depth: 0 }, { source: 'helper', depth: 1 }, From 9b4292b8d891593cf2df0885c2a393a93c7f530a Mon Sep 17 00:00:00 2001 From: "HomePC\\Kevin" Date: Sat, 24 Oct 2026 17:55:39 +0200 Subject: [PATCH 31/31] fix(router-generator): retain configured watch inputs after startup errors --- .../bun-basic-file-based/dev-fixture.ts | 4 ++- .../bun-basic-file-based/dev.test.ts | 33 +++++++++++++++++++ packages/router-generator/src/generator.ts | 6 +++- .../tests/virtual-config.test.ts | 4 ++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/e2e/react-router/bun-basic-file-based/dev-fixture.ts b/e2e/react-router/bun-basic-file-based/dev-fixture.ts index acf6328642d..46def3758f2 100644 --- a/e2e/react-router/bun-basic-file-based/dev-fixture.ts +++ b/e2e/react-router/bun-basic-file-based/dev-fixture.ts @@ -55,6 +55,7 @@ export async function startDevFixture({ generatedExtension = 'ts', virtualMount = false, virtualConfigFile = false, + initialVirtualConfig, virtualConfigHelperDepth = 0, autoCodeSplitting = true, projectAlias = false, @@ -62,6 +63,7 @@ export async function startDevFixture({ generatedExtension?: string virtualMount?: boolean virtualConfigFile?: boolean + initialVirtualConfig?: string virtualConfigHelperDepth?: 0 | 1 | 2 autoCodeSplitting?: boolean projectAlias?: boolean @@ -138,7 +140,7 @@ export async function startDevFixture({ virtualConfigHelperDepth ? `config/helper${virtualConfigHelperDepth}.ts` : 'virtual-routes.ts', - virtualConfigSource('before'), + initialVirtualConfig ?? virtualConfigSource('before'), ) await save( 'virtual-pages/before.tsx', diff --git a/e2e/react-router/bun-basic-file-based/dev.test.ts b/e2e/react-router/bun-basic-file-based/dev.test.ts index 79352125ed0..105b495586b 100644 --- a/e2e/react-router/bun-basic-file-based/dev.test.ts +++ b/e2e/react-router/bun-basic-file-based/dev.test.ts @@ -15,6 +15,7 @@ const test = base.extend<{ generatedExtension: string virtualMount: boolean virtualConfigFile: boolean + initialVirtualConfig: string | undefined virtualConfigHelperDepth: 0 | 1 | 2 autoCodeSplitting: boolean projectAlias: boolean @@ -22,6 +23,7 @@ const test = base.extend<{ generatedExtension: ['ts', { option: true }], virtualMount: [false, { option: true }], virtualConfigFile: [false, { option: true }], + initialVirtualConfig: [undefined, { option: true }], virtualConfigHelperDepth: [0, { option: true }], autoCodeSplitting: [true, { option: true }], projectAlias: [false, { option: true }], @@ -30,6 +32,7 @@ const test = base.extend<{ generatedExtension, virtualMount, virtualConfigFile, + initialVirtualConfig, virtualConfigHelperDepth, autoCodeSplitting, projectAlias, @@ -41,6 +44,7 @@ const test = base.extend<{ generatedExtension, virtualMount, virtualConfigFile, + initialVirtualConfig, virtualConfigHelperDepth, autoCodeSplitting, projectAlias, @@ -601,6 +605,35 @@ test('repairs a syntax error in an active route without restarting the server', }) }) +for (const [failure, source] of [ + ['syntax', 'export default {'], + ['schema', "export default { type: 'root', file: 42 }"], +] as const) { + test.describe(`initial virtual configuration ${failure} error`, () => { + test.use({ virtualConfigFile: true, initialVirtualConfig: source }) + test('recovers on a new request without restarting Bun', async ({ + page, + request, + native, + }) => { + expect((await request.get(native.url)).status()).toBe(500) + await native.save('virtual-routes.ts', virtualConfigSource('after')) + await page.goto(native.url) + await expect(page.getByRole('heading')).toHaveText('HOME_NATIVE_DEV') + await page + .getByRole('link', { name: 'Virtual after', exact: true }) + .click() + await expect(page.getByRole('heading')).toHaveText('VIRTUAL_AFTER') + native.assertAlive() + expect( + await ( + await request.get(new URL('/__native-info', native.url).href) + ).json(), + ).toEqual({ pid: native.pid }) + }) + }) +} + for (const virtualConfigHelperDepth of [0, 1, 2] as const) { test.describe(`string virtual configuration with ${virtualConfigHelperDepth} helper imports`, () => { test.use({ virtualConfigFile: true, virtualConfigHelperDepth }) diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index cba9a393ddb..363590b168c 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -309,8 +309,12 @@ export class Generator { files: Array directories: Array } { + const files = new Set(this.configFilePaths) + if (typeof this.config.virtualRouteConfig === 'string') { + files.add(path.resolve(this.root, this.config.virtualRouteConfig)) + } return { - files: [...this.configFilePaths], + files: [...files], directories: [ ...new Set( [ diff --git a/packages/router-generator/tests/virtual-config.test.ts b/packages/router-generator/tests/virtual-config.test.ts index 49fe7fabc13..9d3fae6bc3e 100644 --- a/packages/router-generator/tests/virtual-config.test.ts +++ b/packages/router-generator/tests/virtual-config.test.ts @@ -1,6 +1,6 @@ import { - mkdtemp, mkdir, + mkdtemp, readFile, rename, rm, @@ -53,6 +53,7 @@ export const Route = createRootRoute({})\n`, ), }) await expect(generator.run()).rejects.toThrow() + expect(generator.getWatchDependencies().files).toEqual([configFile]) await writeFile( configFile, "export default { type: 'root', file: '__root.tsx' }\n", @@ -61,6 +62,7 @@ export const Route = createRootRoute({})\n`, expect(await readFile(generatedRouteTree, 'utf8')).toContain( "import { Route as rootRouteImport } from './routes/__root'", ) + expect(generator.getWatchDependencies().files).toEqual([configFile]) } finally { await rm(root, { recursive: true, force: true }) }

g(%J*C+sHY90_{Nx9D`SL6$zBEGIB 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 literal 0 HcmV?d00001 diff --git a/.github/native-bun-validation/prepare.py b/.github/native-bun-validation/prepare.py index f7d8a27519d..53e07c8b61e 100644 --- a/.github/native-bun-validation/prepare.py +++ b/.github/native-bun-validation/prepare.py @@ -10,7 +10,7 @@ BASE = "dca7d25e95cca39316c659a377dba6803805549f" -PATCH_HASH = "04da37bc9b4bea9c446a96c88b6288f3faec626d846be808af6291d0ceb669d5" +PATCH_HASH = "d4d09320680f3602c018b157fd5bbb595f9c2fda30b81a583dbaf8a1e043cd76" ADDITIONAL = { "src/bundler/input_source_map.rs", "src/runtime/bake/dev_server/plugin_watch_store.rs", @@ -45,11 +45,11 @@ def main(): parser.add_argument("--check-assets-only", action="store_true") args = parser.parse_args() data = Path(__file__).resolve().parent - manifest = json.loads((data / "native-v10-manifest.json").read_text()) + manifest = json.loads((data / "native-v12-manifest.json").read_text()) assert manifest["head"] == BASE assert manifest["trackedPatchSha256"] == PATCH_HASH assert set(manifest["additionalFiles"]) == ADDITIONAL - patch = gzip.decompress((data / "native-v10-tracked.patch.gz").read_bytes()) + patch = gzip.decompress((data / "native-v12-tracked.patch.gz").read_bytes()) assert digest(patch) == PATCH_HASH, "Tracked patch hash mismatch" paths = re.findall(rb"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE) assert paths, "No tracked patch paths" @@ -59,7 +59,7 @@ def main(): tracked.append(old.decode()) extra = {} archive = gzip.decompress( - (data / "native-v10-additional-files.tar.gz").read_bytes() + (data / "native-v12-additional-files.tar.gz").read_bytes() ) with tarfile.open(fileobj=io.BytesIO(archive)) as bundle: for member in bundle.getmembers(): @@ -89,11 +89,14 @@ def main(): target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(content) subprocess.run(["git", "diff", "--check"], cwd=bun, check=True) + for name, expected in manifest["changedSourceSha256"].items(): + assert allowed(name) and name in tracked + assert digest((bun / name).read_bytes()) == expected, f"Source hash mismatch: {name}" out.mkdir(parents=True, exist_ok=True) with tarfile.open(out / "applied-source.tar.gz", "w:gz") as bundle: for name in sorted(set(tracked) | ADDITIONAL): bundle.add(bun / name, arcname=name) - (out / "native-v10-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") + (out / "native-v12-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") (out / "tracked.patch").write_bytes(patch) for name in ["CONTRIBUTING.md", "rust-toolchain.toml", "package.json"]: (out / name).write_bytes((bun / name).read_bytes()) diff --git a/.github/native-bun-validation/pure-bun-graph-browser.mjs b/.github/native-bun-validation/pure-bun-graph-browser.mjs new file mode 100644 index 00000000000..0e62ebf5753 --- /dev/null +++ b/.github/native-bun-validation/pure-bun-graph-browser.mjs @@ -0,0 +1,529 @@ +import assert from 'node:assert/strict' +import { spawn, execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { createRequire } from 'node:module' +import { mkdtemp, mkdir, readFile, writeFile, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +const root = + process.env.ROUTER_REPOSITORY_ROOT ?? + fileURLToPath(new URL('../../../', import.meta.url)) +const requireProject = createRequire( + path.join(root, 'e2e/react-router/bun-basic-file-based/package.json'), +) +const { chromium, expect } = requireProject('@playwright/test') +const sourceMapMode = process.env.PURE_BUN_SOURCE_MAPS === '1' +const largePairMode = process.env.PURE_BUN_LARGE_PAIR === '1' +const pluginRequire = createRequire( + path.join(root, 'packages/router-plugin/package.json'), +) +const babelRequire = createRequire(pluginRequire.resolve('@babel/core')) +const { AnyMap, originalPositionFor, sourceContentFor } = createRequire( + babelRequire.resolve('@jridgewell/remapping'), +)('@jridgewell/trace-mapping') +const binaries = [ + ['candidate', process.env.BUN_EXECUTABLE], + ['baseline', process.env.BUN_BASELINE_EXECUTABLE], + ['debug', process.env.BUN_DEBUG_EXECUTABLE], +].filter(([, binary]) => binary) +assert.ok(binaries.length, 'Set BUN_EXECUTABLE') +const output = + process.env.PURE_BUN_BROWSER_OUTPUT ?? + path.join( + root, + `.cache/bun-dev-validation/results/pure-bun-graph-${process.platform}.json`, + ) +await mkdir(path.dirname(output), { recursive: true }) +const browser = await chromium.launch({ + headless: true, + ...(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH } + : {}), +}) +const results = [] +const mentions = (text) => + ['before.ts', 'after.ts', 'graph.ts', 'main.ts'].filter((name) => + text.includes(name), + ) +try { + for (const [label, binary] of binaries) { + for (const reloadWhileAfter of sourceMapMode + ? [true] + : largePairMode + ? [false] + : [false, true]) { + const name = `${label}-${reloadWhileAfter ? 'reload-B' : 'automatic'}` + console.log(`START ${name}`) + const directory = await mkdtemp(path.join(tmpdir(), 'bun-pure-graph-')) + const result = { + name, + label, + binary, + reloadWhileAfter, + sourceMapMode, + largePairMode, + passed: false, + steps: [], + errors: [], + websocketFrames: [], + initialJavaScript: [], + documentLoads: 0, + } + let child, + context, + logs = '' + try { + await writeFile( + path.join(directory, 'index.html'), + '