From 674f11d2673eaad753bc1f6f3f7954f97621cca6 Mon Sep 17 00:00:00 2001 From: MarketDataApp Date: Tue, 24 Feb 2026 21:44:17 -0300 Subject: [PATCH 1/4] feat: add worker tests, markdown serving, and SDK PHP redirect - Extract worker logic into handler.js for testability - Add 28 unit tests and 162 integration tests (vitest) - Serve clean markdown for .md URLs and Accept: text/markdown header - Strip frontmatter, imports, and convert MDX components to markdown - Redirect /docs/sdk-php/* to GitHub Pages - Point editUrl to self-hosted .md URLs instead of raw GitHub --- .gitignore | 1 + docusaurus.config.js | 16 +- worker/handler.integration.test.js | 78 ++++ worker/handler.js | 146 +++++++ worker/handler.test.js | 304 ++++++++++++++ worker/index.js | 86 +--- worker/package.json | 11 + worker/yarn.lock | 651 +++++++++++++++++++++++++++++ 8 files changed, 1200 insertions(+), 93 deletions(-) create mode 100644 worker/handler.integration.test.js create mode 100644 worker/handler.js create mode 100644 worker/handler.test.js create mode 100644 worker/package.json create mode 100644 worker/yarn.lock diff --git a/.gitignore b/.gitignore index 41e9d0b..9597e70 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ yarn-error.log* .env static/robots.txt +worker/node_modules diff --git a/docusaurus.config.js b/docusaurus.config.js index 8658d6e..b7efe09 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -93,8 +93,8 @@ const config = { sidebarPath: require.resolve("./sidebars.js"), editUrl: ({ docPath }) => { - const branch = process.env.PROD == "true" ? "main" : "dev"; - return `https://raw.githubusercontent.com/MarketDataApp/documentation/${branch}/api/${docPath}`; + const base = process.env.PROD == "true" ? "/docs" : "/docs-staging"; + return `https://www.marketdata.app${base}/api/${docPath.replace(/\.mdx?$/, '.md')}`; }, }, ], @@ -106,8 +106,8 @@ const config = { path: "sdk", routeBasePath: "sdk", editUrl: ({ docPath }) => { - const branch = process.env.PROD == "true" ? "main" : "dev"; - return `https://raw.githubusercontent.com/MarketDataApp/documentation/${branch}/sdk/${docPath}`; + const base = process.env.PROD == "true" ? "/docs" : "/docs-staging"; + return `https://www.marketdata.app${base}/sdk/${docPath.replace(/\.mdx?$/, '.md')}`; }, sidebarPath: require.resolve("./sidebars.js"), }, @@ -120,8 +120,8 @@ const config = { path: "sheets", routeBasePath: "sheets", editUrl: ({ docPath }) => { - const branch = process.env.PROD == "true" ? "main" : "dev"; - return `https://raw.githubusercontent.com/MarketDataApp/documentation/${branch}/sheets/${docPath}`; + const base = process.env.PROD == "true" ? "/docs" : "/docs-staging"; + return `https://www.marketdata.app${base}/sheets/${docPath.replace(/\.mdx?$/, '.md')}`; }, sidebarPath: require.resolve("./sidebars.js"), }, @@ -134,8 +134,8 @@ const config = { path: "account", routeBasePath: "account", editUrl: ({ docPath }) => { - const branch = process.env.PROD == "true" ? "main" : "dev"; - return `https://raw.githubusercontent.com/MarketDataApp/documentation/${branch}/account/${docPath}`; + const base = process.env.PROD == "true" ? "/docs" : "/docs-staging"; + return `https://www.marketdata.app${base}/account/${docPath.replace(/\.mdx?$/, '.md')}`; }, sidebarPath: require.resolve("./sidebars.js"), }, diff --git a/worker/handler.integration.test.js b/worker/handler.integration.test.js new file mode 100644 index 0000000..9c4f1d9 --- /dev/null +++ b/worker/handler.integration.test.js @@ -0,0 +1,78 @@ +/** + * Integration test: fetches the live sitemap and verifies every doc URL + * returns valid markdown via Accept: text/markdown header. + * + * Run with: yarn test:integration + * Requires network access to www.marketdata.app + */ +import { describe, it, expect } from 'vitest'; + +const SITEMAP_URL = 'https://www.marketdata.app/docs/sitemap.xml'; + +// Pages generated by Docusaurus that have no markdown source +const SKIP_PATTERNS = [ + '/docs/search', + '/docs/docs/', // root landing page (auto-generated) + '/tags', // tag listing pages +]; + +// Pages with no markdown source — auto-generated or mapped to unexpected paths +// See: https://github.com/MarketDataApp/documentation/issues/127 +const SKIP_EXACT = [ + '/docs/', // root page source is at docs/index.md, outside doc plugin paths + '/docs/sdk/stocks', // broken category URLs (should be /sdk/go/stocks, etc.) + '/docs/sdk/markets', + '/docs/sdk/options', +]; + +function shouldSkip(url) { + const path = new URL(url).pathname; + if (SKIP_EXACT.includes(path)) return true; + return SKIP_PATTERNS.some((pattern) => url.includes(pattern)); +} + +async function fetchSitemapUrls() { + const res = await fetch(SITEMAP_URL); + const xml = await res.text(); + const urls = []; + for (const match of xml.matchAll(/([^<]+)<\/loc>/g)) { + urls.push(match[1]); + } + return urls; +} + +describe('markdown serving (live sitemap)', async () => { + const allUrls = await fetchSitemapUrls(); + const docUrls = allUrls.filter((url) => !shouldSkip(url)); + + it(`sitemap has URLs to test`, () => { + expect(docUrls.length).toBeGreaterThan(50); + }); + + for (const url of docUrls) { + const path = new URL(url).pathname; + + it(`${path} returns markdown`, async () => { + const res = await fetch(url, { + headers: { Accept: 'text/markdown' }, + redirect: 'follow', + }); + + expect(res.status, `${path} returned ${res.status}`).toBe(200); + expect(res.headers.get('content-type')).toContain('text/markdown'); + + const text = await res.text(); + expect(text.length, `${path} returned empty body`).toBeGreaterThan(0); + + // Should not contain raw frontmatter + expect(text.startsWith('---\n'), `${path} still has frontmatter`).toBe(false); + + // Should not contain MDX import statements + expect(text, `${path} still has import statements`).not.toMatch(/^import\s+\w+\s+from\s+"/m); + + // Should not contain raw JSX tags from Docusaurus components + expect(text, `${path} still has `).not.toContain(''); + expect(text, `${path} still has to ### headings, strip wrappers + text = text.replace(/\n?/g, ''); + text = text.replace(/<\/Tabs>\n?/g, ''); + text = text.replace(/"]*(?:"[^"]*")?)*?label="([^"]*)"(?:[^>"]*(?:"[^"]*")?)*?>\n?/g, '### $1\n\n'); + text = text.replace(/<\/TabItem>\n?/g, ''); + // Clean up excess blank lines + text = text.replace(/\n{3,}/g, '\n\n').trim() + '\n'; + return text; +} + +/** + * Routes incoming requests to the appropriate Cloudflare Pages deployment + * based on the URL path. Non-matching requests pass through to the + * default origin (WordPress on cPanel). + * + * @param {Request} request - The incoming request + * @returns {Promise} + */ +async function handleRequest(request) { + const url = new URL(request.url); + + if (url.hostname !== ORIGINAL_HOSTNAME) { + return fetch(request); + } + + // Redirect legacy SDK PHP docs to GitHub Pages + const sdkPhpPrefix = '/docs/sdk-php/'; + if (url.pathname.startsWith(sdkPhpPrefix) || url.pathname === '/docs/sdk-php') { + let subpath = url.pathname.slice(sdkPhpPrefix.length); + // Fix doubled directory names (e.g. classes/classes/ → classes/) + subpath = subpath.replace(/^(\w+)\/\1\//, '$1/'); + return Response.redirect(`https://marketdataapp.github.io/sdk-php/${subpath}`, 301); + } + + // Serve raw markdown for .md URLs or Accept: text/markdown header + if (url.pathname.startsWith('/docs/')) { + const wantsMd = url.pathname.endsWith('.md'); + const acceptsMd = (request.headers.get('accept') || '').includes('text/markdown'); + + if (wantsMd || acceptsMd) { + const stem = wantsMd + ? url.pathname.slice('/docs/'.length, -3) + : url.pathname.replace(/\/$/, '').slice('/docs/'.length); + const base = `https://raw.githubusercontent.com/MarketDataApp/documentation/main`; + const candidates = [ + `${base}/${stem}.md`, + `${base}/${stem}.mdx`, + `${base}/${stem}/index.md`, + `${base}/${stem}/index.mdx`, + ]; + for (const candidate of candidates) { + const res = await fetch(candidate); + if (res.ok) { + const text = cleanMarkdown(await res.text()); + return new Response(text, { + headers: { 'content-type': 'text/markdown; charset=utf-8' }, + }); + } + } + } + } + + for (const route of ROUTES) { + if (matchesRoute(url.pathname, route.prefix)) { + // Docs sites don't serve robots.txt; block stale cached copies + if (url.pathname.endsWith('/robots.txt')) { + return new Response('', { status: 404 }); + } + + url.hostname = route.target; + const response = await fetch(new Request(url, request), { cf: { cacheEverything: true } }); + + if (response.status === 404) { + const pathname = new URL(request.url).pathname; + const referer = request.headers.get('referer'); + console.log({ level: '404', message: pathname, referer: referer || '' }); + } + + return response; + } + } + + return fetch(request); +} + +module.exports = { handleRequest, matchesRoute, cleanMarkdown, ROUTES, ORIGINAL_HOSTNAME }; diff --git a/worker/handler.test.js b/worker/handler.test.js new file mode 100644 index 0000000..c60804f --- /dev/null +++ b/worker/handler.test.js @@ -0,0 +1,304 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// Mock global fetch +const mockFetch = vi.fn(); +vi.stubGlobal('fetch', mockFetch); + +const { handleRequest, matchesRoute, cleanMarkdown } = require('./handler'); + +function makeRequest(url, options = {}) { + return new Request(url, options); +} + +beforeEach(() => { + vi.clearAllMocks(); +}); + +// --- matchesRoute --- + +describe('matchesRoute', () => { + it('matches path starting with prefix', () => { + expect(matchesRoute('/docs/api', '/docs/')).toBe(true); + }); + + it('matches exact path without trailing slash', () => { + expect(matchesRoute('/docs', '/docs/')).toBe(true); + }); + + it('does not match unrelated path', () => { + expect(matchesRoute('/other', '/docs/')).toBe(false); + }); + + it('does not match partial prefix', () => { + expect(matchesRoute('/documentation', '/docs/')).toBe(false); + }); + + it('/docs-staging/ does not match /docs/ prefix', () => { + expect(matchesRoute('/docs-staging/', '/docs/')).toBe(false); + }); +}); + +// --- cleanMarkdown --- + +describe('cleanMarkdown', () => { + it('strips frontmatter', () => { + const input = '---\ntitle: Test\nsidebar_position: 1\n---\n\n# Hello\n'; + expect(cleanMarkdown(input)).toBe('# Hello\n'); + }); + + it('strips import statements', () => { + const input = 'import Tabs from "@theme/Tabs";\nimport TabItem from "@theme/TabItem";\n\n# Hello\n'; + expect(cleanMarkdown(input)).toBe('# Hello\n'); + }); + + it('converts TabItem to headings and strips Tabs wrappers', () => { + const input = '\n\n\ncode here\n\n\n\n'; + const result = cleanMarkdown(input); + expect(result).toContain('### JavaScript'); + expect(result).not.toContain(''); + expect(result).not.toContain(''); + }); + + it('collapses excess blank lines', () => { + const input = '# A\n\n\n\n\n# B\n'; + expect(cleanMarkdown(input)).toBe('# A\n\n# B\n'); + }); +}); + +// --- handleRequest --- + +describe('handleRequest', () => { + + // --- Non-matching hostname --- + + describe('non-matching hostname', () => { + it('passes through requests for other hostnames', async () => { + const passthroughResponse = new Response('origin'); + mockFetch.mockResolvedValueOnce(passthroughResponse); + const req = makeRequest('https://other.example.com/docs/api'); + const res = await handleRequest(req); + expect(mockFetch).toHaveBeenCalledWith(req); + expect(res).toBe(passthroughResponse); + }); + }); + + // --- SDK PHP redirects --- + + describe('SDK PHP redirect', () => { + it('redirects /docs/sdk-php/ paths to GitHub Pages', async () => { + const req = makeRequest('https://www.marketdata.app/docs/sdk-php/classes/Client.html'); + const res = await handleRequest(req); + expect(res.status).toBe(301); + expect(res.headers.get('location')).toBe( + 'https://marketdataapp.github.io/sdk-php/classes/Client.html' + ); + }); + + it('redirects bare /docs/sdk-php', async () => { + const req = makeRequest('https://www.marketdata.app/docs/sdk-php'); + const res = await handleRequest(req); + expect(res.status).toBe(301); + expect(res.headers.get('location')).toBe( + 'https://marketdataapp.github.io/sdk-php/' + ); + }); + + it('fixes doubled directory names', async () => { + const req = makeRequest('https://www.marketdata.app/docs/sdk-php/classes/classes/Client.html'); + const res = await handleRequest(req); + expect(res.status).toBe(301); + expect(res.headers.get('location')).toBe( + 'https://marketdataapp.github.io/sdk-php/classes/Client.html' + ); + }); + }); + + // --- Markdown serving --- + + describe('markdown serving', () => { + const sampleMdx = [ + '---', + 'title: Test', + 'sidebar_position: 1', + '---', + '', + 'import Tabs from "@theme/Tabs";', + '', + '# Hello', + '', + '', + '', + '', + '```js', + 'console.log("hi");', + '```', + '', + '', + '', + ].join('\n'); + + it('serves cleaned markdown for .md URL', async () => { + mockFetch.mockResolvedValueOnce(new Response(sampleMdx, { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/stocks.md'); + const res = await handleRequest(req); + expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8'); + const text = await res.text(); + expect(text).not.toContain('---'); + expect(text).not.toContain('import '); + expect(text).toContain('### JavaScript'); + expect(text).toContain('# Hello'); + }); + + it('serves markdown for Accept: text/markdown header', async () => { + mockFetch.mockResolvedValueOnce(new Response('# Heading\n', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/stocks', { + headers: { Accept: 'text/markdown' }, + }); + const res = await handleRequest(req); + expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8'); + }); + + it('handles Accept header with trailing slash', async () => { + mockFetch.mockResolvedValueOnce(new Response('# Heading\n', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/options/', { + headers: { Accept: 'text/markdown' }, + }); + const res = await handleRequest(req); + expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8'); + }); + + it('tries multiple candidates until one succeeds', async () => { + mockFetch + .mockResolvedValueOnce(new Response('', { status: 404 })) // .md + .mockResolvedValueOnce(new Response('', { status: 404 })) // .mdx + .mockResolvedValueOnce(new Response('# Found\n', { status: 200 })); // index.md + const req = makeRequest('https://www.marketdata.app/docs/api/options.md'); + const res = await handleRequest(req); + expect(mockFetch).toHaveBeenCalledTimes(3); + const text = await res.text(); + expect(text).toContain('# Found'); + }); + + it('falls through when no markdown candidate found', async () => { + mockFetch + .mockResolvedValueOnce(new Response('', { status: 404 })) + .mockResolvedValueOnce(new Response('', { status: 404 })) + .mockResolvedValueOnce(new Response('', { status: 404 })) + .mockResolvedValueOnce(new Response('', { status: 404 })) + // Route proxy fetch + .mockResolvedValueOnce(new Response('html page', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/nonexistent.md'); + const res = await handleRequest(req); + expect(mockFetch).toHaveBeenCalledTimes(5); + }); + }); + + // --- robots.txt --- + + describe('robots.txt blocking', () => { + it('returns 404 for /docs/robots.txt', async () => { + const req = makeRequest('https://www.marketdata.app/docs/robots.txt'); + const res = await handleRequest(req); + expect(res.status).toBe(404); + expect(mockFetch).not.toHaveBeenCalled(); + }); + + it('returns 404 for /docs-staging/robots.txt', async () => { + const req = makeRequest('https://www.marketdata.app/docs-staging/robots.txt'); + const res = await handleRequest(req); + expect(res.status).toBe(404); + expect(mockFetch).not.toHaveBeenCalled(); + }); + }); + + // --- Route proxying --- + + describe('route proxying', () => { + it('proxies /docs/* to marketdata-docs.pages.dev', async () => { + mockFetch.mockResolvedValueOnce(new Response('page', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/stocks'); + await handleRequest(req); + const calledWith = mockFetch.mock.calls[0][0]; + expect(new URL(calledWith.url).hostname).toBe('marketdata-docs.pages.dev'); + }); + + it('proxies /docs-staging/* to staging', async () => { + mockFetch.mockResolvedValueOnce(new Response('page', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs-staging/api/stocks'); + await handleRequest(req); + const calledWith = mockFetch.mock.calls[0][0]; + expect(new URL(calledWith.url).hostname).toBe('marketdata-docs-staging.pages.dev'); + }); + + it('preserves the full path when proxying', async () => { + mockFetch.mockResolvedValueOnce(new Response('page', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/stocks/candles'); + await handleRequest(req); + const calledWith = mockFetch.mock.calls[0][0]; + expect(new URL(calledWith.url).pathname).toBe('/docs/api/stocks/candles'); + }); + + it('passes cf.cacheEverything option', async () => { + mockFetch.mockResolvedValueOnce(new Response('page', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api'); + await handleRequest(req); + const fetchOptions = mockFetch.mock.calls[0][1]; + expect(fetchOptions).toEqual({ cf: { cacheEverything: true } }); + }); + }); + + // --- 404 logging --- + + describe('404 logging', () => { + it('logs 404 responses with pathname and referer', async () => { + const consoleSpy = vi.spyOn(console, 'log'); + mockFetch.mockResolvedValueOnce(new Response('not found', { status: 404 })); + const req = makeRequest('https://www.marketdata.app/docs/missing-page', { + headers: { Referer: 'https://www.google.com/' }, + }); + await handleRequest(req); + expect(consoleSpy).toHaveBeenCalledWith({ + level: '404', + message: '/docs/missing-page', + referer: 'https://www.google.com/', + }); + consoleSpy.mockRestore(); + }); + + it('logs empty referer when none present', async () => { + const consoleSpy = vi.spyOn(console, 'log'); + mockFetch.mockResolvedValueOnce(new Response('not found', { status: 404 })); + const req = makeRequest('https://www.marketdata.app/docs/missing-page'); + await handleRequest(req); + expect(consoleSpy).toHaveBeenCalledWith({ + level: '404', + message: '/docs/missing-page', + referer: '', + }); + consoleSpy.mockRestore(); + }); + }); + + // --- Pass-through --- + + describe('pass-through for non-matching routes', () => { + it('passes through requests to non-docs paths', async () => { + const passthroughResponse = new Response('wordpress'); + mockFetch.mockResolvedValueOnce(passthroughResponse); + const req = makeRequest('https://www.marketdata.app/blog/some-post'); + const res = await handleRequest(req); + expect(mockFetch).toHaveBeenCalledWith(req); + expect(res).toBe(passthroughResponse); + }); + + it('passes through root path', async () => { + const passthroughResponse = new Response('homepage'); + mockFetch.mockResolvedValueOnce(passthroughResponse); + const req = makeRequest('https://www.marketdata.app/'); + const res = await handleRequest(req); + expect(mockFetch).toHaveBeenCalledWith(req); + expect(res).toBe(passthroughResponse); + }); + }); +}); diff --git a/worker/index.js b/worker/index.js index 0036b4d..618f5c1 100644 --- a/worker/index.js +++ b/worker/index.js @@ -1,88 +1,4 @@ -/** - * Cloudflare Worker to proxy /docs/ and /docs-staging/ paths - * from www.marketdata.app to Cloudflare Pages deployments. - * - * Last deployed: 2026-02-24 - * - * Routing: - * - www.marketdata.app/docs/* → marketdata-docs.pages.dev/docs/* - * - www.marketdata.app/docs-staging/* → marketdata-docs-staging.pages.dev/docs-staging/* - * - * The path is preserved as-is (including the /docs/ or /docs-staging/ prefix). - * Cloudflare Pages serves files from a matching directory structure in the - * build output, so no path rewriting is needed. - * - * Requests that don't match any route (e.g. the main WordPress site) - * are passed through unchanged. - */ - -const ORIGINAL_HOSTNAME = 'www.marketdata.app'; - -/** - * Route definitions mapping URL path prefixes to Cloudflare Pages targets. - * Order matters: /docs-staging/ must come before /docs/ to avoid - * /docs-staging/* being matched by the /docs/ prefix. - */ -const ROUTES = [ - { - prefix: '/docs-staging/', - target: 'marketdata-docs-staging.pages.dev', - }, - { - prefix: '/docs/', - target: 'marketdata-docs.pages.dev', - }, -]; - -/** - * Checks whether a URL path matches a route, handling both - * trailing-slash (/docs-staging/) and no-trailing-slash (/docs-staging) forms. - * - * @param {string} pathname - The URL path to check (e.g. "/docs-staging/api") - * @param {string} prefix - The route prefix to match (e.g. "/docs-staging/") - * @returns {boolean} - */ -function matchesRoute(pathname, prefix) { - return pathname.startsWith(prefix) || pathname === prefix.slice(0, -1); -} - -/** - * Routes incoming requests to the appropriate Cloudflare Pages deployment - * based on the URL path. Non-matching requests pass through to the - * default origin (WordPress on cPanel). - * - * @param {Request} request - The incoming request - * @returns {Promise} - */ -async function handleRequest(request) { - const url = new URL(request.url); - - if (url.hostname !== ORIGINAL_HOSTNAME) { - return fetch(request); - } - - for (const route of ROUTES) { - if (matchesRoute(url.pathname, route.prefix)) { - // Docs sites don't serve robots.txt; block stale cached copies - if (url.pathname.endsWith('/robots.txt')) { - return new Response('', { status: 404 }); - } - - url.hostname = route.target; - const response = await fetch(new Request(url, request), { cf: { cacheEverything: true } }); - - if (response.status === 404) { - const pathname = new URL(request.url).pathname; - const referer = request.headers.get('referer'); - console.log({ level: '404', message: pathname, referer: referer || '' }); - } - - return response; - } - } - - return fetch(request); -} +const { handleRequest } = require('./handler'); addEventListener('fetch', (event) => { event.respondWith(handleRequest(event.request)); diff --git a/worker/package.json b/worker/package.json new file mode 100644 index 0000000..400f358 --- /dev/null +++ b/worker/package.json @@ -0,0 +1,11 @@ +{ + "name": "marketdata-docusaurus-proxy", + "private": true, + "scripts": { + "test": "vitest run --exclude '**/*.integration.test.js'", + "test:integration": "vitest run handler.integration.test.js --test-timeout=30000" + }, + "devDependencies": { + "vitest": "^3.1.0" + } +} diff --git a/worker/yarn.lock b/worker/yarn.lock new file mode 100644 index 0000000..ea1ee89 --- /dev/null +++ b/worker/yarn.lock @@ -0,0 +1,651 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@esbuild/aix-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz#815b39267f9bffd3407ea6c376ac32946e24f8d2" + integrity sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg== + +"@esbuild/android-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz#19b882408829ad8e12b10aff2840711b2da361e8" + integrity sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg== + +"@esbuild/android-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz#90be58de27915efa27b767fcbdb37a4470627d7b" + integrity sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA== + +"@esbuild/android-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz#d7dcc976f16e01a9aaa2f9b938fbec7389f895ac" + integrity sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ== + +"@esbuild/darwin-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz#9f6cac72b3a8532298a6a4493ed639a8988e8abd" + integrity sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg== + +"@esbuild/darwin-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz#ac61d645faa37fd650340f1866b0812e1fb14d6a" + integrity sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg== + +"@esbuild/freebsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz#b8625689d73cf1830fe58c39051acdc12474ea1b" + integrity sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w== + +"@esbuild/freebsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz#07be7dd3c9d42fe0eccd2ab9f9ded780bc53bead" + integrity sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA== + +"@esbuild/linux-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz#bf31918fe5c798586460d2b3d6c46ed2c01ca0b6" + integrity sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg== + +"@esbuild/linux-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz#28493ee46abec1dc3f500223cd9f8d2df08f9d11" + integrity sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw== + +"@esbuild/linux-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz#750752a8b30b43647402561eea764d0a41d0ee29" + integrity sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg== + +"@esbuild/linux-loong64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz#a5a92813a04e71198c50f05adfaf18fc1e95b9ed" + integrity sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA== + +"@esbuild/linux-mips64el@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz#deb45d7fd2d2161eadf1fbc593637ed766d50bb1" + integrity sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw== + +"@esbuild/linux-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz#6f39ae0b8c4d3d2d61a65b26df79f6e12a1c3d78" + integrity sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA== + +"@esbuild/linux-riscv64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz#4c5c19c3916612ec8e3915187030b9df0b955c1d" + integrity sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ== + +"@esbuild/linux-s390x@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz#9ed17b3198fa08ad5ccaa9e74f6c0aff7ad0156d" + integrity sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw== + +"@esbuild/linux-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz#12383dcbf71b7cf6513e58b4b08d95a710bf52a5" + integrity sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA== + +"@esbuild/netbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz#dd0cb2fa543205fcd931df44f4786bfcce6df7d7" + integrity sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA== + +"@esbuild/netbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz#028ad1807a8e03e155153b2d025b506c3787354b" + integrity sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA== + +"@esbuild/openbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz#e3c16ff3490c9b59b969fffca87f350ffc0e2af5" + integrity sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw== + +"@esbuild/openbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz#c5a4693fcb03d1cbecbf8b422422468dfc0d2a8b" + integrity sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ== + +"@esbuild/openharmony-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz#082082444f12db564a0775a41e1991c0e125055e" + integrity sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g== + +"@esbuild/sunos-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz#5ab036c53f929e8405c4e96e865a424160a1b537" + integrity sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA== + +"@esbuild/win32-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz#38de700ef4b960a0045370c171794526e589862e" + integrity sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA== + +"@esbuild/win32-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz#451b93dc03ec5d4f38619e6cd64d9f9eff06f55c" + integrity sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q== + +"@esbuild/win32-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz#0eaf705c941a218a43dba8e09f1df1d6cd2f1f17" + integrity sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA== + +"@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@rollup/rollup-android-arm-eabi@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz#a6742c74c7d9d6d604ef8a48f99326b4ecda3d82" + integrity sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg== + +"@rollup/rollup-android-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz#97247be098de4df0c11971089fd2edf80a5da8cf" + integrity sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q== + +"@rollup/rollup-darwin-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz#674852cf14cf11b8056e0b1a2f4e872b523576cf" + integrity sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg== + +"@rollup/rollup-darwin-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz#36dfd7ed0aaf4d9d89d9ef983af72632455b0246" + integrity sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w== + +"@rollup/rollup-freebsd-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz#2f87c2074b4220260fdb52a9996246edfc633c22" + integrity sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA== + +"@rollup/rollup-freebsd-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz#9b5a26522a38a95dc06616d1939d4d9a76937803" + integrity sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg== + +"@rollup/rollup-linux-arm-gnueabihf@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz#86aa4859385a8734235b5e40a48e52d770758c3a" + integrity sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw== + +"@rollup/rollup-linux-arm-musleabihf@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz#cbe70e56e6ece8dac83eb773b624fc9e5a460976" + integrity sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA== + +"@rollup/rollup-linux-arm64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz#d14992a2e653bc3263d284bc6579b7a2890e1c45" + integrity sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA== + +"@rollup/rollup-linux-arm64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz#2fdd1ddc434ea90aeaa0851d2044789b4d07f6da" + integrity sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA== + +"@rollup/rollup-linux-loong64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz#8a181e6f89f969f21666a743cd411416c80099e7" + integrity sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg== + +"@rollup/rollup-linux-loong64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz#904125af2babc395f8061daa27b5af1f4e3f2f78" + integrity sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q== + +"@rollup/rollup-linux-ppc64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz#a57970ac6864c9a3447411a658224bdcf948be22" + integrity sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA== + +"@rollup/rollup-linux-ppc64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz#bb84de5b26870567a4267666e08891e80bb56a63" + integrity sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA== + +"@rollup/rollup-linux-riscv64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz#72d00d2c7fb375ce3564e759db33f17a35bffab9" + integrity sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg== + +"@rollup/rollup-linux-riscv64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz#4c166ef58e718f9245bd31873384ba15a5c1a883" + integrity sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg== + +"@rollup/rollup-linux-s390x-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz#bb5025cde9a61db478c2ca7215808ad3bce73a09" + integrity sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w== + +"@rollup/rollup-linux-x64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz#9b66b1f9cd95c6624c788f021c756269ffed1552" + integrity sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg== + +"@rollup/rollup-linux-x64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz#b007ca255dc7166017d57d7d2451963f0bd23fd9" + integrity sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg== + +"@rollup/rollup-openbsd-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz#e8b357b2d1aa2c8d76a98f5f0d889eabe93f4ef9" + integrity sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ== + +"@rollup/rollup-openharmony-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz#96c2e3f4aacd3d921981329831ff8dde492204dc" + integrity sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA== + +"@rollup/rollup-win32-arm64-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz#2d865149d706d938df8b4b8f117e69a77646d581" + integrity sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A== + +"@rollup/rollup-win32-ia32-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz#abe1593be0fa92325e9971c8da429c5e05b92c36" + integrity sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA== + +"@rollup/rollup-win32-x64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz#c4af3e9518c9a5cd4b1c163dc81d0ad4d82e7eab" + integrity sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA== + +"@rollup/rollup-win32-x64-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz#4584a8a87b29188a4c1fe987a9fcf701e256d86c" + integrity sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA== + +"@types/chai@^5.2.2": + version "5.2.3" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.3.tgz#8e9cd9e1c3581fa6b341a5aed5588eb285be0b4a" + integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== + dependencies: + "@types/deep-eql" "*" + assertion-error "^2.0.1" + +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + +"@types/estree@1.0.8", "@types/estree@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@vitest/expect@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.4.tgz#8362124cd811a5ee11c5768207b9df53d34f2433" + integrity sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/spy" "3.2.4" + "@vitest/utils" "3.2.4" + chai "^5.2.0" + tinyrainbow "^2.0.0" + +"@vitest/mocker@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.2.4.tgz#4471c4efbd62db0d4fa203e65cc6b058a85cabd3" + integrity sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ== + dependencies: + "@vitest/spy" "3.2.4" + estree-walker "^3.0.3" + magic-string "^0.30.17" + +"@vitest/pretty-format@3.2.4", "@vitest/pretty-format@^3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.4.tgz#3c102f79e82b204a26c7a5921bf47d534919d3b4" + integrity sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/runner@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.2.4.tgz#5ce0274f24a971f6500f6fc166d53d8382430766" + integrity sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ== + dependencies: + "@vitest/utils" "3.2.4" + pathe "^2.0.3" + strip-literal "^3.0.0" + +"@vitest/snapshot@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.2.4.tgz#40a8bc0346ac0aee923c0eefc2dc005d90bc987c" + integrity sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ== + dependencies: + "@vitest/pretty-format" "3.2.4" + magic-string "^0.30.17" + pathe "^2.0.3" + +"@vitest/spy@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.2.4.tgz#cc18f26f40f3f028da6620046881f4e4518c2599" + integrity sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw== + dependencies: + tinyspy "^4.0.3" + +"@vitest/utils@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.4.tgz#c0813bc42d99527fb8c5b138c7a88516bca46fea" + integrity sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA== + dependencies: + "@vitest/pretty-format" "3.2.4" + loupe "^3.1.4" + tinyrainbow "^2.0.0" + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +chai@^5.2.0: + version "5.3.3" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== + +debug@^4.4.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +es-module-lexer@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + +esbuild@^0.27.0: + version "0.27.3" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.3.tgz#5859ca8e70a3af956b26895ce4954d7e73bd27a8" + integrity sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.27.3" + "@esbuild/android-arm" "0.27.3" + "@esbuild/android-arm64" "0.27.3" + "@esbuild/android-x64" "0.27.3" + "@esbuild/darwin-arm64" "0.27.3" + "@esbuild/darwin-x64" "0.27.3" + "@esbuild/freebsd-arm64" "0.27.3" + "@esbuild/freebsd-x64" "0.27.3" + "@esbuild/linux-arm" "0.27.3" + "@esbuild/linux-arm64" "0.27.3" + "@esbuild/linux-ia32" "0.27.3" + "@esbuild/linux-loong64" "0.27.3" + "@esbuild/linux-mips64el" "0.27.3" + "@esbuild/linux-ppc64" "0.27.3" + "@esbuild/linux-riscv64" "0.27.3" + "@esbuild/linux-s390x" "0.27.3" + "@esbuild/linux-x64" "0.27.3" + "@esbuild/netbsd-arm64" "0.27.3" + "@esbuild/netbsd-x64" "0.27.3" + "@esbuild/openbsd-arm64" "0.27.3" + "@esbuild/openbsd-x64" "0.27.3" + "@esbuild/openharmony-arm64" "0.27.3" + "@esbuild/sunos-x64" "0.27.3" + "@esbuild/win32-arm64" "0.27.3" + "@esbuild/win32-ia32" "0.27.3" + "@esbuild/win32-x64" "0.27.3" + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +expect-type@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +loupe@^3.1.0, loupe@^3.1.4: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + +magic-string@^0.30.17: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.2, picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +rollup@^4.43.0: + version "4.59.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.59.0.tgz#cf74edac17c1486f562d728a4d923a694abdf06f" + integrity sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.59.0" + "@rollup/rollup-android-arm64" "4.59.0" + "@rollup/rollup-darwin-arm64" "4.59.0" + "@rollup/rollup-darwin-x64" "4.59.0" + "@rollup/rollup-freebsd-arm64" "4.59.0" + "@rollup/rollup-freebsd-x64" "4.59.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.59.0" + "@rollup/rollup-linux-arm-musleabihf" "4.59.0" + "@rollup/rollup-linux-arm64-gnu" "4.59.0" + "@rollup/rollup-linux-arm64-musl" "4.59.0" + "@rollup/rollup-linux-loong64-gnu" "4.59.0" + "@rollup/rollup-linux-loong64-musl" "4.59.0" + "@rollup/rollup-linux-ppc64-gnu" "4.59.0" + "@rollup/rollup-linux-ppc64-musl" "4.59.0" + "@rollup/rollup-linux-riscv64-gnu" "4.59.0" + "@rollup/rollup-linux-riscv64-musl" "4.59.0" + "@rollup/rollup-linux-s390x-gnu" "4.59.0" + "@rollup/rollup-linux-x64-gnu" "4.59.0" + "@rollup/rollup-linux-x64-musl" "4.59.0" + "@rollup/rollup-openbsd-x64" "4.59.0" + "@rollup/rollup-openharmony-arm64" "4.59.0" + "@rollup/rollup-win32-arm64-msvc" "4.59.0" + "@rollup/rollup-win32-ia32-msvc" "4.59.0" + "@rollup/rollup-win32-x64-gnu" "4.59.0" + "@rollup/rollup-win32-x64-msvc" "4.59.0" + fsevents "~2.3.2" + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.9.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + +strip-literal@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.1.0.tgz#222b243dd2d49c0bcd0de8906adbd84177196032" + integrity sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg== + dependencies: + js-tokens "^9.0.1" + +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.14, tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tinypool@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-4.0.4.tgz#d77a002fb53a88aa1429b419c1c92492e0c81f78" + integrity sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q== + +vite-node@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" + integrity sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg== + dependencies: + cac "^6.7.14" + debug "^4.4.1" + es-module-lexer "^1.7.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507" + integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== + dependencies: + esbuild "^0.27.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^3.1.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.4.tgz#0637b903ad79d1539a25bc34c0ed54b5c67702ea" + integrity sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/expect" "3.2.4" + "@vitest/mocker" "3.2.4" + "@vitest/pretty-format" "^3.2.4" + "@vitest/runner" "3.2.4" + "@vitest/snapshot" "3.2.4" + "@vitest/spy" "3.2.4" + "@vitest/utils" "3.2.4" + chai "^5.2.0" + debug "^4.4.1" + expect-type "^1.2.1" + magic-string "^0.30.17" + pathe "^2.0.3" + picomatch "^4.0.2" + std-env "^3.9.0" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinyglobby "^0.2.14" + tinypool "^1.1.1" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node "3.2.4" + why-is-node-running "^2.3.0" + +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" From 22ca8aa17f7cef03c0693c4a1b43241d7658856a Mon Sep 17 00:00:00 2001 From: MarketDataApp Date: Tue, 24 Feb 2026 21:48:07 -0300 Subject: [PATCH 2/4] fix: correct Go SDK sidebar category slugs to include /go/ prefix Closes #127 --- sdk/go/markets/index.mdx | 2 +- sdk/go/options/index.mdx | 2 +- sdk/go/stocks/index.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/go/markets/index.mdx b/sdk/go/markets/index.mdx index 09893fe..c0319c5 100644 --- a/sdk/go/markets/index.mdx +++ b/sdk/go/markets/index.mdx @@ -1,6 +1,6 @@ --- title: Markets -slug: /markets +slug: /go/markets sidebar_position: 9 --- diff --git a/sdk/go/options/index.mdx b/sdk/go/options/index.mdx index 48b4974..93cbc9a 100644 --- a/sdk/go/options/index.mdx +++ b/sdk/go/options/index.mdx @@ -1,6 +1,6 @@ --- title: Options -slug: /options +slug: /go/options sidebar_position: 11 --- diff --git a/sdk/go/stocks/index.mdx b/sdk/go/stocks/index.mdx index 41f7e61..b2c414e 100644 --- a/sdk/go/stocks/index.mdx +++ b/sdk/go/stocks/index.mdx @@ -1,6 +1,6 @@ --- title: Stocks -slug: /stocks +slug: /go/stocks sidebar_position: 10 --- From 312ab6d0d2c9587e6d51fd21977033c2e1e27122 Mon Sep 17 00:00:00 2001 From: MarketDataApp Date: Tue, 24 Feb 2026 21:52:14 -0300 Subject: [PATCH 3/4] fix: serve markdown for docs-staging URLs and use correct branch --- worker/handler.js | 12 ++++++++---- worker/handler.test.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/worker/handler.js b/worker/handler.js index 9ccb6d3..ea8fd60 100644 --- a/worker/handler.js +++ b/worker/handler.js @@ -93,15 +93,19 @@ async function handleRequest(request) { } // Serve raw markdown for .md URLs or Accept: text/markdown header - if (url.pathname.startsWith('/docs/')) { + const docsPrefix = url.pathname.startsWith('/docs-staging/') ? '/docs-staging/' + : url.pathname.startsWith('/docs/') ? '/docs/' : null; + + if (docsPrefix) { const wantsMd = url.pathname.endsWith('.md'); const acceptsMd = (request.headers.get('accept') || '').includes('text/markdown'); if (wantsMd || acceptsMd) { const stem = wantsMd - ? url.pathname.slice('/docs/'.length, -3) - : url.pathname.replace(/\/$/, '').slice('/docs/'.length); - const base = `https://raw.githubusercontent.com/MarketDataApp/documentation/main`; + ? url.pathname.slice(docsPrefix.length, -3) + : url.pathname.replace(/\/$/, '').slice(docsPrefix.length); + const branch = docsPrefix === '/docs-staging/' ? 'staging' : 'main'; + const base = `https://raw.githubusercontent.com/MarketDataApp/documentation/${branch}`; const candidates = [ `${base}/${stem}.md`, `${base}/${stem}.mdx`, diff --git a/worker/handler.test.js b/worker/handler.test.js index c60804f..ec286fd 100644 --- a/worker/handler.test.js +++ b/worker/handler.test.js @@ -180,6 +180,24 @@ describe('handleRequest', () => { expect(text).toContain('# Found'); }); + it('serves markdown for docs-staging URLs', async () => { + mockFetch.mockResolvedValueOnce(new Response('# Staging\n', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs-staging/api/stocks.md'); + const res = await handleRequest(req); + expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8'); + // Should fetch from staging branch + const fetchedUrl = mockFetch.mock.calls[0][0]; + expect(fetchedUrl).toContain('/staging/'); + }); + + it('fetches from main branch for /docs/ URLs', async () => { + mockFetch.mockResolvedValueOnce(new Response('# Prod\n', { status: 200 })); + const req = makeRequest('https://www.marketdata.app/docs/api/stocks.md'); + await handleRequest(req); + const fetchedUrl = mockFetch.mock.calls[0][0]; + expect(fetchedUrl).toContain('/main/'); + }); + it('falls through when no markdown candidate found', async () => { mockFetch .mockResolvedValueOnce(new Response('', { status: 404 })) From bdac0e7ff3d05924030ceac93d8c429b4606593e Mon Sep 17 00:00:00 2001 From: MarketDataApp Date: Tue, 24 Feb 2026 21:53:29 -0300 Subject: [PATCH 4/4] ci: run worker unit tests before deploy --- .github/workflows/deploy-docs.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 65eb221..6ddf449 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -86,6 +86,13 @@ jobs: echo "changed=false" >> "$GITHUB_OUTPUT" fi + - name: Test Worker + if: steps.worker.outputs.changed == 'true' + working-directory: worker + run: | + yarn install --frozen-lockfile + yarn test + - name: Deploy Worker if: steps.worker.outputs.changed == 'true' uses: cloudflare/wrangler-action@v3