diff --git a/.env.example b/.env.example index 06f69b9a..71905afa 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,7 @@ -# BrowserStack credentails -BROWSER_STACK_USERNAME= -BROWSER_STACK_ACCESS= +# Convert Staging SDK Key +CONVERT_STAGING_SDK_KEY= +CONVERT_STAGING_SDK_KEY2= +CONVERT_STAGING_SDK_KEY2_SECRET= # Logger LOG_LEVEL=2 diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index 9d672687..70c86d96 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -88,6 +88,12 @@ jobs: (cd packages/experience && npm publish --access public) env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - if: ${{ startsWith(env.RELEASE_TAG, 'js-sdk-cloudflare-v') }} + run: | + yarn cloudflare:build + (cd packages/cloudflare && npm publish --access public) + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - if: ${{ startsWith(env.RELEASE_TAG, 'js-sdk-v') }} run: | yarn sdk:build diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 63028700..dcb0225e 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -17,29 +17,37 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [18] + node: [22] # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/setup-node@v1 + - uses: actions/checkout@v4 with: - # The Node.js version to configure - node-version: ${{ matrix.node }} + fetch-depth: 2 - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v4 with: - fetch-depth: 2 - - name: Install needed libraries and packages + node-version: ${{ matrix.node }} + + - name: Setup Yarn + run: | + corepack enable + corepack prepare yarn@stable --activate + + - name: Install Playwright browsers run: | - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - - sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' - sudo apt-get update - sudo apt-get install -y google-chrome-stable + cd packages/js-sdk + npx playwright install --with-deps chromium - name: Runs the SDK QA checks + env: + CONVERT_STAGING_SDK_KEY: ${{ secrets.CONVERT_STAGING_SDK_KEY }} + CONVERT_STAGING_SDK_KEY2: ${{ secrets.CONVERT_STAGING_SDK_KEY2 }} + CONVERT_STAGING_SDK_KEY2_SECRET: ${{ secrets.CONVERT_STAGING_SDK_KEY2_SECRET }} run: | - yarn set version berry yarn cd packages/js-sdk yarn lint - yarn test + yarn build + yarn test:mocha + yarn test:browser diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 9b76dc63..cb9142e2 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -56,5 +56,6 @@ jobs: packages/data) yarn data:build && (cd packages/data && npm publish --access public) ;; packages/experience) yarn experience:build && (cd packages/experience && npm publish --access public) ;; packages/js-sdk) yarn sdk:build && (cd packages/js-sdk && npm publish --access public) ;; + packages/cloudflare) yarn cloudflare:build && (cd packages/cloudflare && npm publish --access public) ;; *) echo "Unknown path: $REL_PATH" && exit 1 ;; esac diff --git a/.gitignore b/.gitignore index 2ab095da..20e9e4df 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ lib/ dist/ docs/ coverage/ +test-results/ packages/demo-* .next demo/remixjs-server-side/build diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9ff278d1..c5517b45 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -10,5 +10,6 @@ "packages/segments": "2.1.2", "packages/api": "2.1.4", "packages/data": "3.3.3", - "packages/experience": "2.3.2" + "packages/experience": "2.3.2", + "packages/cloudflare": "1.0.0" } diff --git a/demo/cloudflare-workers/README.md b/demo/cloudflare-workers/README.md new file mode 100644 index 00000000..901aa935 --- /dev/null +++ b/demo/cloudflare-workers/README.md @@ -0,0 +1,252 @@ +# Convert SDK — Cloudflare Workers Demo + +Run Convert A/B tests at the Cloudflare edge with zero client-side flicker. This demo works out of the box with the Convert staging project (`10035569/10034190`) — the same credentials used by all other SDK demos. + +## Routes + +| Route | Location | Experiments | Features | +|-------|----------|-------------|----------| +| `/` | — | None (home page) | — | +| `/events` | `events` | `test-experience-ab-fullstack-1` | — | +| `/statistics` | `statistics` | All matching | `feature-4` | +| `/pricing` | `pricing` | All matching | `feature-5` | + +## How It Works + +``` +Visitor → Cloudflare Worker (localhost:8787) + ├── Fetch config from Convert CDN (edge-cached, ~1-5ms) + ├── Map URL path to location property (e.g. /events → "events") + ├── SDK: createContext → runExperience/runExperiences + ├── Fetch origin page (localhost:8888) + ├── HTMLRewriter: inject experiment results into HTML + ├── Set visitor cookie + cache headers + └── Respond (total overhead: ~5-8ms) + + └── Background (waitUntil): + └── Flush tracking events to Convert +``` + +No KV namespace is required. Config is cached using Cloudflare's native `cf.cacheTtl` fetch option (free, all plans). Visitor bucketing is deterministic — the same visitor ID always gets the same variation via a cookie. + +## Setup + +### 1. Install Dependencies + +From the monorepo root: + +```bash +yarn install +``` + +If the cloudflare package hasn't been built yet: + +```bash +yarn cloudflare:build +``` + +You don't need to publish `@convertcom/js-sdk-cloudflare` to npm — Yarn workspaces symlinks it to the local `packages/cloudflare/` directory, and Wrangler's bundler follows symlinks. + +### 2. Start the Origin Server + +The demo includes a simple origin server (`origin/`) that serves HTML pages for each route. The Worker proxies to this origin and modifies the response with experiment results. + +```bash +# Terminal 1 +cd demo/cloudflare-workers +yarn origin +``` + +This starts on http://localhost:8888 with pages for `/`, `/events`, `/statistics`, and `/pricing`. + +### 3. Start the Worker + +```bash +# Terminal 2 +cd demo/cloudflare-workers +yarn dev +``` + +This starts on http://localhost:8787. + +### 4. Open in Browser + +Visit http://localhost:8787/ and navigate to the different routes: + +- **Events** — Shows the bucketed variation for `test-experience-ab-fullstack-1` +- **Statistics** — Shows all matching variations + `feature-4` status +- **Pricing** — Shows all matching variations (both experiences) + `feature-5` status + +## Verification + +### Config Fetch + +Confirm the staging project config is accessible: + +```bash +curl -s "https://cdn-4.convertexperiments.com/api/v1/config/10035569/10034190" | head -c 200 +``` + +Should return JSON starting with `{"account_id":"10035569"...`. + +### Visitor Cookie + +```bash +curl -v http://localhost:8787/events 2>&1 | grep -i set-cookie +``` + +Expected: `Set-Cookie: convert_visitor_id=; Path=/; ...` + +### Deterministic Bucketing + +```bash +# Get a visitor ID +VISITOR_ID=$(curl -s -D- http://localhost:8787/events 2>&1 | grep -io 'convert_visitor_id=[^;]*' | cut -d= -f2) +echo "Visitor: $VISITOR_ID" + +# Same cookie → same variation every time +curl -s -b "convert_visitor_id=$VISITOR_ID" http://localhost:8787/events +curl -s -b "convert_visitor_id=$VISITOR_ID" http://localhost:8787/events +``` + +Both responses should show identical experiment results. + +### HTMLRewriter + +Compare the origin page vs the Worker-modified page: + +```bash +# Origin (unmodified) +curl -s http://localhost:8888/events | grep experiment-results + +# Worker (modified with bucketing results) +curl -s http://localhost:8787/events | grep experiment-results +``` + +The Worker response should contain variation names/keys instead of the placeholder text. + +### Cache Headers + +```bash +curl -s -D- http://localhost:8787/events 2>&1 | grep -iE 'cache-control|vary' +``` + +Expected: + +``` +Cache-Control: public, max-age=300 +Vary: Cookie +``` + +### Tracking Events + +Watch the Worker logs while making requests: + +```bash +# Terminal 3 +cd demo/cloudflare-workers +yarn tail +``` + +After visiting a page, you should see the SDK POST tracking data to Convert. In the Convert dashboard, the visitor count for the experience should increment. + +### Error Fallback + +Temporarily set an invalid SDK key in `wrangler.toml`: + +```toml +CONVERT_SDK_KEY = "invalid/key" +``` + +Restart `yarn dev` and visit http://localhost:8787/events — should return the unmodified origin page (graceful degradation via try/catch). + +### Bundle Validation + +```bash +cd demo/cloudflare-workers +npx wrangler deploy --dry-run --outdir /tmp/cf-bundle +``` + +Should succeed with bundle size ~296 KiB / ~58 KiB gzipped. + +## Checklist + +| Test | What to Verify | +|------|---------------| +| Config fetch | `curl` to CDN config endpoint returns JSON | +| Wrangler bundle | `--dry-run` succeeds | +| Worker starts | `yarn dev` runs without errors | +| Origin server | `yarn origin` serves pages on port 8888 | +| New visitor cookie | `Set-Cookie: convert_visitor_id=` in response | +| Deterministic bucketing | Same cookie → same variation on repeated requests | +| HTMLRewriter | Experiment results injected into HTML | +| Cache headers | `Cache-Control: public, max-age=300` + `Vary: Cookie` | +| Tracking events | Visitor count increments in Convert dashboard | +| Error fallback | Invalid SDK key → unmodified origin page returned | +| No KV required | All above works without any KV namespace configured | + +## Configuration + +The demo is pre-configured in `wrangler.toml`: + +```toml +CONVERT_SDK_KEY = "10035569/10034190" # Staging project +ORIGIN_URL = "http://localhost:8888" # Local origin server +``` + +To use your own project, update these values and adjust the experience/feature keys in `src/index.ts`. + +## Iterating on Package Changes + +If you modify `packages/cloudflare/src/` files: + +```bash +# Rebuild the package +yarn cloudflare:build + +# Restart the Worker (Ctrl+C, then yarn dev again) +``` + +## Production Deployment + +**Important:** The default `ORIGIN_URL` is `http://localhost:8888` which only works for local development. Deploying with this value will fail because `localhost` is not reachable from Cloudflare's network (you'll see a Cloudflare "Error 1003: Direct IP access not allowed" page). + +For production, update `ORIGIN_URL` in `wrangler.toml` to a publicly accessible origin: + +```toml +ORIGIN_URL = "https://your-site.com" +``` + +Then deploy: + +```bash +yarn deploy +``` + +## Optional: KV-Backed Persistence + +If you need to preserve bucketing across experience config changes or store custom visitor attributes, you can optionally add KV support. See the commented section at the bottom of `src/index.ts` for setup instructions. + +## Troubleshooting + +**"Cannot find module @convertcom/js-sdk-cloudflare"** +→ Run `yarn install` at the monorepo root to ensure workspace symlinks exist, then `yarn cloudflare:build`. + +**"Convert config fetch failed: 404"** +→ Verify your SDK key. Test directly: `curl https://cdn-4.convertexperiments.com/api/v1/config/ACCOUNT_ID/PROJECT_ID` + +**Experience returns null / string (RuleError)** +→ The experience key doesn't match, or location/audience rules don't match. Check that the experience is **Active** (not Draft/Paused) in Convert. + +**HTMLRewriter changes not visible** +→ Add `console.log('variation:', variation)` in the Worker and check Wrangler logs to confirm bucketing. + +**Tracking events not appearing in dashboard** +→ Confirm `ctx.waitUntil(context.releaseQueues(...))` is called. Check Wrangler logs for outbound POST requests. + +**Page hangs / infinite loop** +→ All `fetch(request)` calls must go through `fetchOrigin()` which rewrites the URL to `ORIGIN_URL`. Direct `fetch(request)` loops back to the Worker. + +## Documentation + +Full guide: [Cloudflare Workers Edge Experimentation](https://github.com/convertcom/javascript-sdk/wiki/CloudflareWorkers) diff --git a/demo/cloudflare-workers/origin/server.js b/demo/cloudflare-workers/origin/server.js new file mode 100644 index 00000000..89f313cf --- /dev/null +++ b/demo/cloudflare-workers/origin/server.js @@ -0,0 +1,126 @@ +/*! + * Simple origin server for the Cloudflare Workers demo. + * Generates HTML pages from a shared template that the Worker proxies and modifies. + * + * Usage: node origin/server.js + * Serves on http://localhost:8888 + */ + +const http = require('http'); + +const PORT = 8888; + +// Page definitions — only the unique content per route +const PAGES = { + '/': { + title: 'Convert Edge Demo', + body: ` +
+

Cloudflare Workers Demo

+

This page is served by a simple origin server and proxied through a Cloudflare Worker.

+

The Worker runs Convert A/B tests at the edge and modifies HTML before delivery — zero flicker.

+
+
+ Tip: Visit the Events, Statistics, + or Pricing pages to see experiments in action. + The home page has no experiments configured. +
` + }, + '/events': { + title: 'Events - Convert Edge Demo', + heading: 'Events', + description: 'Experience: test-experience-ab-fullstack-1 | Location: events', + featureLabel: 'Feature Status' + }, + '/statistics': { + title: 'Statistics - Convert Edge Demo', + heading: 'Statistics', + description: 'Runs all matching experiences | Feature: feature-4 | Location: statistics', + featureLabel: 'Feature Status (feature-4)' + }, + '/pricing': { + title: 'Pricing - Convert Edge Demo', + heading: 'Pricing', + description: + 'Runs all matching experiences | Feature: feature-5 | Location: pricing

' + + '

Experiences on this route: test-experience-ab-fullstack-1 and test-experience-ab-fullstack-4', + featureLabel: 'Feature Status (feature-5)' + } +}; + +// Shared layout template +function renderPage(page) { + const nav = `

`; + + // Home page uses custom body; experiment pages use a standard layout + const content = page.body || ` +
+

${page.heading}

+

${page.description}

+
+
+

Experiment Results

+
+ No experiment bucketing yet — this content is replaced by the Worker. +
+
+
+

${page.featureLabel}

+
+ No feature flag evaluated. +
+
+
+

Variation Caption

+
+ Original caption (not modified) +
+
`; + + return ` + + + + + ${page.title} + + + + ${nav} + ${content} + +`; +} + +const server = http.createServer((req, res) => { + const pathname = req.url.split('?')[0]; + const page = PAGES[pathname]; + + if (!page) { + res.writeHead(404, {'Content-Type': 'text/html'}); + res.end('

404 Not Found

'); + return; + } + + res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'}); + res.end(renderPage(page)); +}); + +server.listen(PORT, () => { + console.log(`Origin server running at http://localhost:${PORT}`); + console.log('Pages: /, /events, /statistics, /pricing'); +}); diff --git a/demo/cloudflare-workers/package.json b/demo/cloudflare-workers/package.json new file mode 100644 index 00000000..f4306cff --- /dev/null +++ b/demo/cloudflare-workers/package.json @@ -0,0 +1,22 @@ +{ + "name": "@convertcom/js-sdk-demo-cloudflare-workers", + "version": "1.0.0", + "author": "Convert Insights, Inc", + "license": "Apache-2.0", + "private": true, + "scripts": { + "origin": "node origin/server.js", + "dev": "wrangler dev", + "deploy": "wrangler deploy", + "tail": "wrangler tail" + }, + "dependencies": { + "@convertcom/js-sdk": "^4.3.4", + "@convertcom/js-sdk-cloudflare": "^1.0.0" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20241205.0", + "typescript": "^5.9.3", + "wrangler": "^3.99.0" + } +} diff --git a/demo/cloudflare-workers/src/index.ts b/demo/cloudflare-workers/src/index.ts new file mode 100644 index 00000000..01047842 --- /dev/null +++ b/demo/cloudflare-workers/src/index.ts @@ -0,0 +1,343 @@ +/*! + * Convert JS SDK - Cloudflare Workers Demo + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + * + * This Worker demonstrates edge experimentation using the Convert FullStack SDK. + * It proxies requests to an origin server and modifies HTML responses based on + * A/B test bucketing decisions — all at the Cloudflare edge with zero flicker. + * + * Routes (matching the staging project's location rules): + * / - Home page (no experiments) + * /events - Runs experience "test-experience-ab-fullstack-1" + * /statistics - Runs all matching experiences + feature "feature-4" + * /pricing - Runs all matching experiences + feature "feature-5" + */ + +import ConvertSDK, {BucketedVariation} from '@convertcom/js-sdk'; +import { + EdgeConfigCache, + getVisitorId, + setVisitorIdCookie, + generateVisitorId, + setCacheHeaders +} from '@convertcom/js-sdk-cloudflare'; + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +interface Env { + CONVERT_SDK_KEY: string; + // Origin server to proxy to. Set in wrangler.toml [vars]. + ORIGIN_URL: string; + // KV is optional — only needed if you enable the KVDataStore for + // persisting visitor bucketing data across experience config changes. + // CONVERT_KV: KVNamespace; +} + +// --------------------------------------------------------------------------- +// Route → Location mapping +// --------------------------------------------------------------------------- +// The staging project's locations match on a "location" property, not URL path. +// This mirrors the pattern used by the Node.js demo. + +// Route configuration — maps URL paths to location properties and feature keys. +// The staging project's locations match on a "location" property, not URL path. +// This mirrors the pattern used by the Node.js demo. [ConvertSDK] +const ROUTES: Record = { + '/events': {location: 'events', experienceKey: 'test-experience-ab-fullstack-1'}, + '/statistics': {location: 'statistics', featureKey: 'feature-4'}, + '/pricing': {location: 'pricing', featureKey: 'feature-5'} +}; + +// --------------------------------------------------------------------------- +// Origin fetch helper +// --------------------------------------------------------------------------- + +/** + * Fetch from the origin server instead of the Worker's own URL. + * Without this, `fetch(request)` in local dev loops back to the Worker. + */ +function fetchOrigin(request: Request, env: Env): Promise { + const originUrl = new URL(request.url); + const origin = new URL(env.ORIGIN_URL); + originUrl.hostname = origin.hostname; + originUrl.port = origin.port; + originUrl.protocol = origin.protocol; + return fetch(new Request(originUrl.toString(), request)); +} + +// --------------------------------------------------------------------------- +// SDK Singleton +// --------------------------------------------------------------------------- + +let sdk: InstanceType | null = null; +let sdkReadyPromise: Promise> | null = null; + +/** + * Initialise (or reuse) the SDK singleton. + * Uses EdgeConfigCache with Cloudflare's built-in fetch cache — the config + * response is cached at the edge for the TTL duration, no KV needed. + */ +async function getSDK(env: Env): Promise> { + if (sdk) return sdk; + if (sdkReadyPromise) return sdkReadyPromise; + + sdkReadyPromise = (async () => { + const configCache = new EdgeConfigCache( + env.CONVERT_SDK_KEY, + 300 // cache TTL in seconds (5 minutes) + ); + const configData = await configCache.getConfig(); + + const newSdk = new ConvertSDK({ + data: configData, + // Passing data directly avoids the timer-based refresh (setTimeout) + // which is meaningless in a stateless Worker environment. + network: {tracking: true} + }); + await newSdk.onReady(); + sdk = newSdk; + return sdk; + })(); + + return sdkReadyPromise; +} + +// --------------------------------------------------------------------------- +// Worker Entry Point +// --------------------------------------------------------------------------- + +export default { + async fetch( + request: Request, + env: Env, + ctx: ExecutionContext + ): Promise { + const url = new URL(request.url); + + // Only process HTML page requests (skip assets, API calls, etc.) + const accept = request.headers.get('Accept') || ''; + const wantsHtml = + accept.includes('text/html') || accept.includes('*/*') || accept === ''; + if ( + !wantsHtml || + url.pathname.startsWith('/api/') || + url.pathname.match(/\.\w{2,4}$/) + ) { + return fetchOrigin(request, env); + } + + // Check if this route has experiment configuration + const route = ROUTES[url.pathname]; + if (!route) { + // Home page or unknown route — serve origin unmodified with visitor cookie + const response = await fetchOrigin(request, env); + const headers = new Headers(response.headers); + if (!getVisitorId(request)) { + setVisitorIdCookie(headers, generateVisitorId()); + } + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers + }); + } + + try { + // 1. Initialise the SDK + const convert = await getSDK(env); + + // 2. Identify the visitor + let visitorId = getVisitorId(request); + const isNewVisitor = !visitorId; + if (isNewVisitor) { + visitorId = generateVisitorId(); + } + + // 3. Create visitor context with audience properties + // The staging project's "Adv Audience" requires mobile: true or desktop: true. + // This mirrors the Node.js demo's createContext(userId, {mobile: true}). + const context = convert.createContext(visitorId, {mobile: true}); + if (!context) { + return fetchOrigin(request, env); + } + + // Set default segments (mirrors Node.js demo) + context.setDefaultSegments({country: 'US'}); + + // 4. Run experiments based on route + const decisions = decideForRoute(context, route); + + // 5. Fetch the origin page + const originResponse = await fetchOrigin(request, env); + + // 6. Apply variations via HTMLRewriter + const modifiedResponse = applyDecisions(originResponse, decisions); + + // 7. Build response headers (visitor cookie + cache control) + const headers = new Headers(modifiedResponse.headers); + if (isNewVisitor) { + setVisitorIdCookie(headers, visitorId); + } + setCacheHeaders(headers, 300); + + // 8. Release tracking events in the background + // The SDK batches events with setTimeout which won't fire in Workers. + // releaseQueues() flushes immediately; waitUntil() keeps the isolate + // alive for the tracking POST without blocking the response. + ctx.waitUntil(context.releaseQueues('edge-request-complete')); + + return new Response(modifiedResponse.body, { + status: modifiedResponse.status, + statusText: modifiedResponse.statusText, + headers + }); + } catch (error) { + // On any SDK error, serve the origin page unmodified + console.error('Convert SDK error:', error); + return fetchOrigin(request, env); + } + } +} satisfies ExportedHandler; + +// --------------------------------------------------------------------------- +// Route-specific experiment logic +// --------------------------------------------------------------------------- + +interface RouteDecisions { + variation: BucketedVariation | null; + variations: BucketedVariation[]; + feature: any; +} + +/** + * Run experiments and features for the current route. + * Mirrors the Node.js demo's per-route decide() functions. + */ +function decideForRoute( + context: any, + route: {location: string; experienceKey?: string; featureKey?: string} +): RouteDecisions { + const decisions: RouteDecisions = { + variation: null, + variations: [], + feature: null + }; + const locationProperties = {location: route.location}; + + if (route.experienceKey) { + // Single experience (like the Node.js events route) + const bucketed = context.runExperience(route.experienceKey, { + locationProperties + }); + console.log('bucketed variation:', bucketed); + if (bucketed && typeof bucketed !== 'string') { + decisions.variation = bucketed; + } + } else { + // All matching experiences (like the Node.js statistics/pricing routes) + const bucketedAll = context.runExperiences({locationProperties}); + console.log('bucketed variation(s):', bucketedAll); + if (Array.isArray(bucketedAll)) { + decisions.variations = bucketedAll.filter( + (v: any) => v && typeof v !== 'string' + ); + } + } + + if (route.featureKey) { + const feature = context.runFeature(route.featureKey, {locationProperties}); + console.log('bucketed feature:', feature); + if (feature && feature.status === 'enabled') { + decisions.feature = feature; + } + } + + return decisions; +} + +// --------------------------------------------------------------------------- +// HTMLRewriter transformations +// --------------------------------------------------------------------------- + +/** + * Apply experiment decisions to the origin HTML response. + * Uses HTMLRewriter to inject bucketing results into the page. + */ +function applyDecisions( + response: Response, + decisions: RouteDecisions +): Response { + const {variation, variations, feature, route} = decisions; + + // Build a summary of all decisions for this request + const allVariations = + variation ? [variation] : variations.length ? variations : []; + if (allVariations.length === 0 && !feature) { + return response; // No experiments matched — return unmodified + } + + // Inject experiment results into the page + return new HTMLRewriter() + .on('#experiment-results', { + element(el) { + const items = allVariations + .map( + (v) => + `
  • ${v.experienceName || v.experienceKey}: ${v.name || v.key}
  • ` + ) + .join(''); + if (items) { + el.setInnerContent(`
      ${items}
    `, {html: true}); + } + } + }) + .on('#feature-status', { + element(el) { + if (feature) { + el.setInnerContent( + `Feature enabled: ${feature.key || 'yes'}`, + {html: true} + ); + } + } + }) + .on('#variation-caption', { + element(el) { + // Extract the "caption" variable from feature-1 (attached to the experience) + const v = allVariations[0]; + if ( + v && + Array.isArray(v.changes) && + v.changes.length && + v.changes[0].data?.variables_data?.caption + ) { + el.setInnerContent(v.changes[0].data.variables_data.caption); + } + } + }) + .transform(response); +} + +// --------------------------------------------------------------------------- +// Optional: KV-Backed Visitor Persistence +// --------------------------------------------------------------------------- + +// If you need to persist bucketing decisions across experience config changes +// (e.g. ensuring a visitor stays in the same variation even when rules change), +// add KV support: +// +// 1. Add to Env: CONVERT_KV: KVNamespace; +// 2. Add to wrangler.toml: [[kv_namespaces]] binding/id +// 3. Use in the handler: +// +// import { KVDataStore } from '@convertcom/js-sdk-cloudflare'; +// +// const dataStore = new KVDataStore(env.CONVERT_KV); +// await dataStore.load(visitorId); +// const context = convert.createContext(visitorId, { dataStore }); +// // ... run experiments ... +// ctx.waitUntil(dataStore.save(visitorId)); diff --git a/demo/cloudflare-workers/tsconfig.json b/demo/cloudflare-workers/tsconfig.json new file mode 100644 index 00000000..4a9d79a3 --- /dev/null +++ b/demo/cloudflare-workers/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "lib": ["ES2022"], + "types": ["@cloudflare/workers-types"], + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts"] +} diff --git a/demo/cloudflare-workers/wrangler.toml b/demo/cloudflare-workers/wrangler.toml new file mode 100644 index 00000000..231e77e8 --- /dev/null +++ b/demo/cloudflare-workers/wrangler.toml @@ -0,0 +1,24 @@ +name = "convert-edge-experiments" +main = "src/index.ts" +compatibility_date = "2024-12-01" + +[vars] +# Your Convert SDK key (account_id/project_id) +CONVERT_SDK_KEY = "10035569/10034190" +# Origin server URL — the Worker proxies to this and modifies the response. +# For local testing: "http://localhost:8888" +# For production: "https://your-site.com" +ORIGIN_URL = "http://localhost:8888" + +# ------------------------------------------------------------------ +# Optional: KV namespace for persisting visitor bucketing data. +# Only needed if you use KVDataStore (see demo/index.ts comments). +# Most setups do NOT need this — the SDK uses deterministic bucketing. +# +# Create with: wrangler kv namespace create CONVERT_KV +# Then uncomment and replace the id below. +# ------------------------------------------------------------------ +# [[kv_namespaces]] +# binding = "CONVERT_KV" +# id = "YOUR_KV_NAMESPACE_ID" +# preview_id = "YOUR_PREVIEW_NAMESPACE_ID" diff --git a/package.json b/package.json index f12b949d..bbc1a68e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "types:lint": "cd packages/types && yarn lint", "utils:lint": "cd packages/utils && yarn lint", "sdk:lint": "cd packages/js-sdk && yarn lint", - "lint": "yarn enums:lint && yarn types:lint && yarn utils:lint && yarn event:lint && yarn bucketing:lint && yarn logger:lint && yarn rules:lint && yarn segments:lint && yarn api:lint && yarn data:lint && yarn experience:lint && yarn sdk:lint", + "cloudflare:lint": "cd packages/cloudflare && yarn lint", + "lint": "yarn enums:lint && yarn types:lint && yarn utils:lint && yarn event:lint && yarn bucketing:lint && yarn logger:lint && yarn rules:lint && yarn segments:lint && yarn api:lint && yarn data:lint && yarn experience:lint && yarn sdk:lint && yarn cloudflare:lint", "api:build": "cd packages/api && yarn build", "bucketing:build": "cd packages/bucketing && yarn build", "data:build": "cd packages/data && yarn build", @@ -25,7 +26,8 @@ "types:build": "cd packages/types && yarn build", "utils:build": "cd packages/utils && yarn build", "sdk:build": "cd packages/js-sdk && yarn build", - "build": "yarn enums:build && yarn types:build && yarn utils:build && yarn event:build && yarn bucketing:build && yarn logger:build && yarn rules:build && yarn segments:build && yarn api:build && yarn data:build && yarn experience:build && yarn sdk:build", + "cloudflare:build": "cd packages/cloudflare && yarn build", + "build": "yarn enums:build && yarn types:build && yarn utils:build && yarn event:build && yarn bucketing:build && yarn logger:build && yarn rules:build && yarn segments:build && yarn api:build && yarn data:build && yarn experience:build && yarn sdk:build && yarn cloudflare:build", "api:test": "cd packages/api && yarn test:mocha", "bucketing:test": "cd packages/bucketing && yarn test:mocha", "data:test": "cd packages/data && yarn test:mocha", @@ -43,7 +45,8 @@ "demo:nestjs:start": "cd demo/nestjs && yarn start", "demo:nextjs:start": "cd demo/nextjs && yarn start", "demo:remixjs:client:start": "cd demo/remixjs-client-side && yarn dev", - "demo:remixjs:server:start": "cd demo/remixjs-server-side && yarn dev" + "demo:remixjs:server:start": "cd demo/remixjs-server-side && yarn dev", + "demo:cloudflare:start": "cd demo/cloudflare-workers && yarn dev" }, "private": true, "workspaces": [ diff --git a/packages/cloudflare/README.md b/packages/cloudflare/README.md new file mode 100644 index 00000000..bd861cc1 --- /dev/null +++ b/packages/cloudflare/README.md @@ -0,0 +1,79 @@ +# @convertcom/js-sdk-cloudflare + +Cloudflare Workers utilities for the [Convert JavaScript SDK](https://github.com/convertcom/javascript-sdk). Provides the glue code between the FullStack SDK and Cloudflare-specific APIs (HTMLRewriter, Workers Request/Response, edge caching). + +## Installation + +```bash +npm install @convertcom/js-sdk @convertcom/js-sdk-cloudflare +# or +yarn add @convertcom/js-sdk @convertcom/js-sdk-cloudflare +``` + +## What's Included + +| Export | Purpose | +|--------|---------| +| `EdgeConfigCache` | Cache SDK config using Cloudflare's native `fetch` cache (no KV needed) | +| `KVDataStore` | **Optional** KV-backed DataStore adapter for persisting bucketing decisions | +| `getVisitorId` | Parse visitor ID from Workers Request cookies | +| `setVisitorIdCookie` | Set visitor ID cookie on Workers Response | +| `generateVisitorId` | Generate a new UUID visitor ID | +| `buildCacheKey` | Create variation-aware cache keys for Cloudflare's Cache API | +| `setCacheHeaders` | Set `Cache-Control` + `Vary: Cookie` headers | + +## Quick Start + +```typescript +import ConvertSDK from '@convertcom/js-sdk'; +import { + EdgeConfigCache, + getVisitorId, + setVisitorIdCookie, + generateVisitorId +} from '@convertcom/js-sdk-cloudflare'; + +export default { + async fetch(request, env, ctx) { + // 1. Get config (cached at edge via Cloudflare's fetch cache — no KV) + const config = await new EdgeConfigCache(env.SDK_KEY).getConfig(); + + // 2. Init SDK + const sdk = new ConvertSDK({ data: config, network: { tracking: true } }); + await sdk.onReady(); + + // 3. Identify visitor + const visitorId = getVisitorId(request) || generateVisitorId(); + + // 4. Run experiment (deterministic bucketing — no persistence needed) + const context = sdk.createContext(visitorId); + const variation = context.runExperience('my-experiment'); + + // 5. Modify the page with HTMLRewriter (zero flicker) + const origin = await fetch(request); + let response = origin; + if (variation?.key === 'variation-1') { + response = new HTMLRewriter() + .on('h1', { element(el) { el.setInnerContent('New Headline'); } }) + .transform(origin); + } + + // 6. Set cookie and respond + const headers = new Headers(response.headers); + setVisitorIdCookie(headers, visitorId); + + // 7. Flush tracking events before Worker finishes + ctx.waitUntil(context.releaseQueues()); + + return new Response(response.body, { status: response.status, headers }); + } +}; +``` + +## Documentation + +See the full guide: [Cloudflare Workers Edge Experimentation](https://github.com/convertcom/javascript-sdk/wiki/CloudflareWorkers) + +## License + +Apache-2.0 diff --git a/packages/cloudflare/index.ts b/packages/cloudflare/index.ts new file mode 100644 index 00000000..640006de --- /dev/null +++ b/packages/cloudflare/index.ts @@ -0,0 +1,14 @@ +/*! + * Convert JS SDK - Cloudflare Workers Utilities + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + */ +export {KVDataStore} from './src/kv-data-store'; +export {EdgeConfigCache} from './src/edge-config-cache'; +export { + getVisitorId, + setVisitorIdCookie, + generateVisitorId +} from './src/cookie-helpers'; +export {buildCacheKey, setCacheHeaders} from './src/cache-helpers'; diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json new file mode 100644 index 00000000..039ec5ca --- /dev/null +++ b/packages/cloudflare/package.json @@ -0,0 +1,51 @@ +{ + "name": "@convertcom/js-sdk-cloudflare", + "version": "1.0.0", + "description": "Cloudflare Workers utilities for Convert JavaScript SDK", + "main": "./lib/index.js", + "module": "./lib/index.mjs", + "types": "./lib/index.d.ts", + "files": [ + "lib/**/**/*" + ], + "author": "Convert Insights, Inc", + "repository": { + "type": "git", + "url": "git+https://github.com/convertcom/javascript-sdk.git", + "directory": "packages/cloudflare" + }, + "license": "Apache-2.0", + "scripts": { + "clean": "rm -rf lib", + "prebuild": "yarn clean", + "build": "rollup -c ../../rollup.config.mjs", + "lint": "eslint src", + "lint:fix": "yarn lint -- --fix" + }, + "engines": { + "node": ">=18.0.0" + }, + "devDependencies": { + "@babel/cli": "^7.28.3", + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@eslint/eslintrc": "^3.3.1", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-terser": "^0.4.4", + "@typescript-eslint/parser": "^8.46.4", + "eslint": "^9.39.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "prettier": "^3.6.2", + "rollup": "^4.53.2", + "rollup-plugin-generate-package-json": "^3.2.0", + "rollup-plugin-modify": "^3.0.0", + "rollup-plugin-typescript2": "^0.36.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.46.4" + }, + "peerDependencies": { + "@convertcom/js-sdk": ">=4.0.0" + } +} diff --git a/packages/cloudflare/src/cache-helpers.ts b/packages/cloudflare/src/cache-helpers.ts new file mode 100644 index 00000000..039c1260 --- /dev/null +++ b/packages/cloudflare/src/cache-helpers.ts @@ -0,0 +1,59 @@ +/*! + * Convert JS SDK - Cloudflare Workers Utilities + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + */ + +/** + * Build a variation-aware cache key for Cloudflare's Cache API. + * + * Without this, Cloudflare's edge cache would serve the same cached response + * to all visitors regardless of their bucketed variation. By appending the + * variation key as a query parameter, each variation gets its own cache entry. + * + * @param request - The original incoming request + * @param variationKey - The bucketed variation key (e.g. 'variation-1') + * @returns A new Request with the variation key appended as a query parameter + * + * @example + * ```typescript + * const cacheKey = buildCacheKey(request, variation.key); + * const cache = caches.default; + * let response = await cache.match(cacheKey); + * if (!response) { + * response = await fetch(request); + * await cache.put(cacheKey, response.clone()); + * } + * ``` + */ +export function buildCacheKey(request: Request, variationKey: string): Request { + const url = new URL(request.url); + url.searchParams.set('_conv_v', variationKey); + return new Request(url.toString(), { + method: request.method, + headers: request.headers + }); +} + +/** + * Set cache control headers appropriate for A/B tested responses. + * + * Adds `Vary: Cookie` so that Cloudflare's cache correctly separates + * responses by visitor cookie. Sets a configurable max-age. + * + * @param headers - The response Headers object to modify + * @param maxAge - Cache max-age in seconds (default: 300 = 5 minutes) + */ +export function setCacheHeaders(headers: Headers, maxAge = 300): void { + headers.set('Cache-Control', `public, max-age=${maxAge}`); + // Ensure Vary includes Cookie so cached responses respect visitor bucketing + const existingVary = headers.get('Vary'); + if (existingVary) { + if (!existingVary.toLowerCase().includes('cookie')) { + headers.set('Vary', `${existingVary}, Cookie`); + } + } else { + headers.set('Vary', 'Cookie'); + } +} diff --git a/packages/cloudflare/src/cookie-helpers.ts b/packages/cloudflare/src/cookie-helpers.ts new file mode 100644 index 00000000..a35ea7f8 --- /dev/null +++ b/packages/cloudflare/src/cookie-helpers.ts @@ -0,0 +1,54 @@ +/*! + * Convert JS SDK - Cloudflare Workers Utilities + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + */ + +const DEFAULT_COOKIE_NAME = 'convert_visitor_id'; +const DEFAULT_MAX_AGE = 31536000; // 1 year in seconds + +/** + * Extract the visitor ID from a Workers Request cookie header. + * + * @param request - The incoming Workers Request + * @param cookieName - Cookie name to read (default: 'convert_visitor_id') + * @returns The visitor ID string, or null if not found + */ +export function getVisitorId( + request: Request, + cookieName = DEFAULT_COOKIE_NAME +): string | null { + const cookie = request.headers.get('Cookie') || ''; + const escaped = cookieName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const match = cookie.match(new RegExp(`(?:^|;)\\s*${escaped}=([^;]+)`)); + return match ? decodeURIComponent(match[1]) : null; +} + +/** + * Append a Set-Cookie header for the visitor ID on the response. + * + * @param headers - The response Headers object to modify + * @param visitorId - The visitor ID to persist + * @param cookieName - Cookie name to set (default: 'convert_visitor_id') + * @param maxAge - Cookie max-age in seconds (default: 31536000 = 1 year) + */ +export function setVisitorIdCookie( + headers: Headers, + visitorId: string, + cookieName = DEFAULT_COOKIE_NAME, + maxAge = DEFAULT_MAX_AGE +): void { + headers.append( + 'Set-Cookie', + `${cookieName}=${encodeURIComponent(visitorId)}; Path=/; Max-Age=${maxAge}; SameSite=Lax; Secure; HttpOnly` + ); +} + +/** + * Generate a new unique visitor ID using crypto.randomUUID(). + * Available in all Cloudflare Workers runtimes. + */ +export function generateVisitorId(): string { + return crypto.randomUUID(); +} diff --git a/packages/cloudflare/src/edge-config-cache.ts b/packages/cloudflare/src/edge-config-cache.ts new file mode 100644 index 00000000..51bc17f3 --- /dev/null +++ b/packages/cloudflare/src/edge-config-cache.ts @@ -0,0 +1,77 @@ +/*! + * Convert JS SDK - Cloudflare Workers Utilities + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + */ + +const DEFAULT_CONFIG_ENDPOINT = 'https://cdn-4.convertexperiments.com/api/v1'; + +/** + * Caches the Convert SDK configuration using Cloudflare's built-in fetch cache. + * + * Instead of requiring a KV namespace, this leverages the `cf` option on + * `fetch()` to cache the config response at the edge. This is simpler, + * works on all Cloudflare plans, and avoids KV read/write costs. + * + * @see https://developers.cloudflare.com/workers/examples/cache-using-fetch/ + * + * @example + * ```typescript + * const configCache = new EdgeConfigCache('YOUR_SDK_KEY'); + * const configData = await configCache.getConfig(); + * + * const sdk = new ConvertSDK({ data: configData }); + * ``` + */ +export class EdgeConfigCache { + private _sdkKey: string; + private _ttl: number; + private _configEndpoint: string; + + /** + * @param sdkKey - Your Convert SDK key (e.g. 'ACCOUNT_ID/PROJECT_ID') + * @param ttl - Cache TTL in seconds (default: 300 = 5 minutes) + * @param configEndpoint - Override the config CDN endpoint + */ + constructor(sdkKey: string, ttl = 300, configEndpoint?: string) { + this._sdkKey = sdkKey; + this._ttl = ttl; + this._configEndpoint = configEndpoint || DEFAULT_CONFIG_ENDPOINT; + } + + /** + * Get the SDK configuration, served from Cloudflare's edge cache when + * available. Falls back to fetching from the Convert CDN if the cache + * entry has expired. + */ + async getConfig(): Promise { + return this._fetch(this._ttl); + } + + /** + * Force-refresh the configuration by bypassing the edge cache. + * Use this for manual cache invalidation (e.g. via a cron trigger or webhook). + */ + async refreshConfig(): Promise { + return this._fetch(0); + } + + private async _fetch(cacheTtl: number): Promise { + const url = `${this._configEndpoint}/config/${this._sdkKey}`; + // The `cf` property is a Cloudflare Workers extension to the standard + // fetch API that controls edge caching behaviour. + const response = await fetch(url, { + headers: {'Content-Type': 'application/json'}, + cf: {cacheTtl, cacheEverything: true} + } as any); + + if (!response.ok) { + throw new Error( + `Convert config fetch failed: ${response.status} ${response.statusText}` + ); + } + + return response.json(); + } +} diff --git a/packages/cloudflare/src/kv-data-store.ts b/packages/cloudflare/src/kv-data-store.ts new file mode 100644 index 00000000..7074feb4 --- /dev/null +++ b/packages/cloudflare/src/kv-data-store.ts @@ -0,0 +1,115 @@ +/*! + * Convert JS SDK - Cloudflare Workers Utilities + * Version 1.0.0 + * Copyright(c) 2020 Convert Insights, Inc + * License Apache-2.0 + */ + +/** + * Minimal interface compatible with Cloudflare Workers KVNamespace. + * Avoids a hard dependency on @cloudflare/workers-types. + */ +interface KVNamespaceLike { + get(key: string): Promise; + put( + key: string, + value: string, + options?: {expirationTtl?: number} + ): Promise; +} + +/** + * **Optional** DataStore adapter for Cloudflare Workers KV. + * + * This is NOT required for basic A/B testing. The SDK uses deterministic + * MurmurHash bucketing, so the same visitor ID always gets the same + * variation. You only need this if you want to: + * + * - Preserve bucketing across experience config changes + * - Store custom visitor attributes between requests + * - Share state across multiple Workers or routes + * + * The Convert SDK expects a synchronous DataStore (get/set). + * Since KV is async, this adapter works in three phases: + * 1. load() - async read from KV into memory (call before SDK operations) + * 2. get/set - sync read/write on in-memory snapshot (used by SDK) + * 3. save() - async write from memory back to KV (call after SDK operations) + * + * **Note:** Cloudflare KV is a paid feature and may not be available on all + * plans. For most use cases, cookie-based visitor identification with + * deterministic bucketing is sufficient without KV persistence. + * + * @example + * ```typescript + * const dataStore = new KVDataStore(env.CONVERT_KV); + * await dataStore.load(visitorId); + * + * const sdk = new ConvertSDK({ data: configData, dataStore }); + * // ... run experiments ... + * + * await dataStore.save(visitorId); + * ``` + */ +export class KVDataStore { + private _data: Record = {}; + private _kv: KVNamespaceLike; + private _dirty = false; + private _prefix: string; + + /** + * @param kv - A Cloudflare KV namespace binding + * @param prefix - Key prefix for KV entries (default: 'visitor') + */ + constructor(kv: KVNamespaceLike, prefix = 'visitor') { + this._kv = kv; + this._prefix = prefix; + } + + /** + * Load visitor data from KV into memory. + * Call this BEFORE creating the SDK context. + */ + async load(visitorId: string): Promise { + const raw = await this._kv.get(`${this._prefix}:${visitorId}`); + try { + this._data = raw ? JSON.parse(raw) : {}; + } catch (e) { + // Corrupted data in KV, start fresh for this visitor. + this._data = {}; + } + this._dirty = false; + } + + /** + * Get a value by key (synchronous, reads from memory). + * Called internally by the SDK. + */ + get(key: string): any { + return this._data[key]; + } + + /** + * Set a value by key (synchronous, writes to memory). + * Called internally by the SDK. + */ + set(key: string, value: any): void { + this._data[key] = value; + this._dirty = true; + } + + /** + * Save visitor data from memory back to KV. + * Call this AFTER SDK operations are complete. + * @param visitorId - The visitor ID used in load() + * @param ttl - KV entry TTL in seconds (default: 86400 = 24 hours) + */ + async save(visitorId: string, ttl = 86400): Promise { + if (!this._dirty) return; + await this._kv.put( + `${this._prefix}:${visitorId}`, + JSON.stringify(this._data), + {expirationTtl: ttl} + ); + this._dirty = false; + } +} diff --git a/packages/js-sdk/TESTING.md b/packages/js-sdk/TESTING.md new file mode 100644 index 00000000..4ee0f790 --- /dev/null +++ b/packages/js-sdk/TESTING.md @@ -0,0 +1,199 @@ +# Testing Guide + +This document covers how to run and write tests for the `@convertcom/js-sdk` package. + +## Prerequisites + +- Node.js >= 22 +- Yarn (via corepack: `corepack enable && corepack prepare yarn@stable --activate`) +- Playwright Chromium browser: `npx playwright install --with-deps chromium` +- Built SDK bundles (run `yarn build` before browser/integration tests) + +## Test Suites + +The SDK has three test suites: + +| Suite | Runner | Scope | Command | +|-------|--------|-------|---------| +| **Unit tests** | Mocha + Chai | Core logic, context, feature manager, utilities | `yarn test:mocha` | +| **Browser tests** | Playwright | UMD bundle loaded in Chromium | `yarn test:browser` | +| **Integration tests** | Playwright | Full SDK lifecycle (init, bucket, feature, conversion) | `yarn test:browser` | + +### Run everything + +```bash +yarn build +yarn test:mocha +yarn test:browser +``` + +Or use the combined command (includes coverage): + +```bash +yarn build +yarn test +``` + +## Unit Tests (Mocha) + +Located in `tests/**/*.tests.ts`. These test SDK internals using Mocha + Chai with `ts-node/register`. + +```bash +yarn test:mocha +``` + +Test files: +- `tests/core.tests.ts` — Core class (init, context creation, events) +- `tests/context.tests.ts` — Context class (runExperience, runFeature, trackConversion) +- `tests/feature-manager.tests.ts` — Feature manager logic +- `tests/utils/*.tests.ts` — Array, object, string, and comparison utilities + +These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access. + +## Browser Tests (Playwright) + +Located in `tests/browser/`. These verify the built UMD bundle works correctly in a real browser environment. + +```bash +yarn build # Must build first — tests serve the built bundles +yarn test:browser +``` + +**How it works:** +1. Playwright starts a local HTTP server (`tests/browser/test-server.js`) on port 3939 +2. The server serves the built UMD bundle (`lib/index.umd.min.js`) and a test HTML page +3. Tests navigate to the page and use `page.evaluate()` to exercise the SDK in browser context + +Test file: +- `tests/browser/umd-bundle.spec.ts` — 19 tests covering SDK instantiation, experiences, features, conversions, segments, and invalid visitor handling + +These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access. + +## Integration Tests (Playwright) + +Located in `tests/integration/`. These run the full SDK lifecycle in Node.js context (not browser), matching the PHP SDK's `FullChainIntegrationTest` pattern. + +```bash +yarn build # Must build first — tests import from lib/ +yarn test:browser # Integration tests run as part of the Playwright suite +``` + +Test file: +- `tests/integration/full-chain.spec.ts` — 17 tests per mode covering: + - **Happy path:** init, ready event, experience bucketing, bucketing determinism, bucketing events, typed feature variables, full chain verification + - **Negative path:** unknown feature key, non-qualifying location, audience mismatch + - **Conversion tracking:** basic conversion, conversion events, goal deduplication, revenue tracking, forced multiple transactions, nonexistent goal + - **Complete chain:** init -> context -> bucket -> feature -> conversion -> flush + +### Auth Modes + +Integration tests run in up to 3 modes, following the PHP SDK pattern: + +| Mode | Config source | Env vars required | Always runs? | +|------|--------------|-------------------|-------------| +| `static` | `tests/integration/static-config.json` | None | Yes | +| `live` | CDN fetch (public key) | `CONVERT_STAGING_SDK_KEY` | No | +| `live-secret` | CDN fetch (authenticated) | `CONVERT_STAGING_SDK_KEY2`, `CONVERT_STAGING_SDK_KEY2_SECRET` | No | + +The `static` mode always runs using a snapshot of the staging project config. The `live` and `live-secret` modes are skipped when the corresponding env vars are not set. + +### Setting up env vars for live tests + +Copy `.env.example` to `.env` and fill in the values: + +```bash +# Public SDK key for unauthenticated CDN fetch +CONVERT_STAGING_SDK_KEY= + +# SDK key + secret for authenticated CDN fetch +CONVERT_STAGING_SDK_KEY2= +CONVERT_STAGING_SDK_KEY2_SECRET= +``` + +Then run with the env vars loaded: + +```bash +export $(grep -v '^#' .env | xargs) +yarn build +yarn test:browser +``` + +### Staging Project + +All integration tests use the shared staging project **"FS-Test-Proj - DO NOT DELETE"** (account `10035569`, project `10034190`). This is the same project used by the PHP SDK's integration tests. + +Key entities: +- **Experience:** `test-experience-ab-fullstack-4` — 50/50 split, pricing-location, no audiences +- **Feature-1:** boolean `enabled`, string `caption` +- **Feature-2:** float `price` (100), integer `button-height` (40), json `additionalData` +- **Goals:** `increase-engagement` (dom_interaction, no rules), `decrease-bounce-rate` (advanced) + +**Do not modify or delete this project.** Changes will break integration tests in both the JS and PHP SDKs. + +## Playwright Configuration + +Config file: `playwright.config.ts` + +- **Test server:** Auto-started on port 3939 (configurable via `PORT` env var) +- **Browser:** Chromium only, headless, with `--no-sandbox` +- **Workers:** 1 (sequential execution — tests share SDK state) +- **Timeout:** 60 seconds per test +- **Retries:** 2 on CI, 0 locally +- **Traces:** Retained on failure + +## CI + +Tests run in GitHub Actions via `.github/workflows/qa.yml`: + +``` +yarn → build → lint → test:mocha → test:browser +``` + +Live integration tests run in CI when the `CONVERT_STAGING_SDK_KEY`, `CONVERT_STAGING_SDK_KEY2`, and `CONVERT_STAGING_SDK_KEY2_SECRET` secrets are configured in the repository. + +## Writing New Tests + +### Adding a unit test + +Add a `.tests.ts` file under `tests/`. It will be picked up automatically by the mocha glob `tests/**/*.tests.ts`. + +```typescript +import 'mocha'; +import {expect} from 'chai'; + +describe('MyFeature', () => { + it('should do something', () => { + expect(true).to.be.true; + }); +}); +``` + +### Adding a browser test + +Add assertions to `tests/browser/umd-bundle.spec.ts` or create a new `.spec.ts` file under `tests/browser/`. + +```typescript +import {test, expect} from '@playwright/test'; + +test('SDK does something in browser', async ({page}) => { + await page.goto('/'); + const result = await page.evaluate(() => { + // ConvertSDK is available as a global from the UMD bundle + return typeof ConvertSDK; + }); + expect(result).toBe('function'); +}); +``` + +### Adding an integration test + +Add tests inside the `for (const mode of modes)` loop in `tests/integration/full-chain.spec.ts` to ensure they run in all auth modes. + +```typescript +test('My new integration test', async () => { + const sdk = createSdk(mode); + await sdk.onReady(); + const context = sdk.createContext('my-visitor-id'); + // ... exercise SDK and assert +}); +``` diff --git a/packages/js-sdk/index.browser.cjs.tests.js b/packages/js-sdk/index.browser.cjs.tests.js deleted file mode 100644 index 4efa54ef..00000000 --- a/packages/js-sdk/index.browser.cjs.tests.js +++ /dev/null @@ -1,7 +0,0 @@ -import * as ConvertSDK from './lib/index'; -import runTests from './index.tests'; - -describe('Karma browser tests for CommonJS bundle', function () { - // eslint-disable-next-line mocha/no-setup-in-describe - runTests(ConvertSDK); -}); diff --git a/packages/js-sdk/index.browser.umd.tests.js b/packages/js-sdk/index.browser.umd.tests.js deleted file mode 100644 index 88982033..00000000 --- a/packages/js-sdk/index.browser.umd.tests.js +++ /dev/null @@ -1,12 +0,0 @@ -// No SDK library imports here. A UMD script should be already loaded in browser by karma -import {assert} from 'chai'; -import runTests from './index.tests'; - -describe('Karma browser tests for UMD bundle', function () { - it('Should have an SDK instance in namespace', function () { - // eslint-disable-next-line no-undef - assert.isDefined(ConvertSDK); - }); - // eslint-disable-next-line mocha/no-setup-in-describe,no-undef - runTests(ConvertSDK); -}); diff --git a/packages/js-sdk/index.tests.js b/packages/js-sdk/index.tests.js deleted file mode 100644 index 053b6ffd..00000000 --- a/packages/js-sdk/index.tests.js +++ /dev/null @@ -1,247 +0,0 @@ -/* eslint-disable mocha/consistent-spacing-between-blocks */ -import {expect} from 'chai'; -import {assert} from 'chai'; -import testConfig from './tests/test-config.json'; -import { - getFeaturesWithStatuses, - getMultipleFeatureWithStatus, - getSingleFeatureWithStatus, - getVariationsAcrossAllExperiences -} from './tests/setup/shared'; - -class DataStore { - data = {}; - get(key) { - if (!key) return this.data; - return this.data[key.toString()]; - } - set(key, value) { - if (!key) throw new Error('Invalid DataStore key!'); - this.data[key.toString()] = value; - } -} - -const dataStore = new DataStore(); -testConfig.dataStore = dataStore; -testConfig.events = { - batch_size: 1, - release_interval: 1000 -}; - -const accountId = testConfig.data.account_id; -const projectId = testConfig.data.project.id; -const visitorId = 'XXX'; -const storeKey = `${accountId}-${projectId}-${visitorId}`; - -const defaultSegments = {browser: 'chrome'}; - -// eslint-disable-next-line mocha/no-exports -export default function runTests(bundle) { - const ConvertSDK = bundle.default; - let convert, context; - describe('Basic SDK instance', function () { - // eslint-disable-next-line mocha/no-hooks-for-single-case - beforeEach(function () { - convert = new ConvertSDK(testConfig); - }); - it('Should have an SDK instance as an object', function () { - expect(bundle).to.be.an('object'); - }); - it('Should have a constructor', function () { - expect(ConvertSDK).to.be.a('function'); - }); - it('Should create a default SDK instance and fire ready event. Expect no errors', function (done) { - convert.on('ready', function (args, err) { - expect(err).to.be.null; - //expect(convert).to.have.property('version').which.is.a('string'); - expect(convert).to.be.an('object'); - done(); - }); - }); - it('Should create a default SDK instance and resolve a promise. Expect no errors', async function () { - await convert.onReady(); - assert.equal(true, true); - }); - it('Shoud successfully create visitor context', function () { - const visitorContext = convert.createContext(visitorId, defaultSegments); - expect(visitorContext).to.be.an('object'); - [ - 'runExperience', - 'runExperiences', - 'runFeature', - 'runFeatures', - 'trackConversion', - 'setDefaultSegments', - 'runCustomSegments' - ].forEach((method) => { - expect(visitorContext).to.have.a.property(method); - }); - }); - }); - describe('Basic SDK methods', function () { - // eslint-disable-next-line mocha/no-hooks-for-single-case - before(function () { - convert = new ConvertSDK(testConfig); - }); - // eslint-disable-next-line mocha/no-hooks-for-single-case - beforeEach(function () { - context = convert.createContext(visitorId, defaultSegments); - }); - it('Shoud successfully get variation from specific experience', function (done) { - const experienceKey = 'test-experience-ab-fullstack-2'; - const variation = context.runExperience(experienceKey, { - locationProperties: {url: 'https://convert.com/'}, - visitorProperties: { - varName3: 'something' - } - }); - expect(variation) - .to.be.an('object') - .that.have.keys( - 'experienceId', - 'experienceKey', - 'experienceName', - 'bucketingAllocation', - 'id', - 'key', - 'name', - 'status', - 'changes', - 'is_baseline', - 'traffic_allocation' - ); - expect(variation.experienceKey).to.equal(experienceKey); - done(); - }); - it('Shoud successfully get variations across all experiences', function (done) { - getVariationsAcrossAllExperiences( - { - accountId, - projectId, - context - }, - done - ); - }); - it('Shoud successfully get a single feature and its status', function (done) { - const featureId = '10025'; - getSingleFeatureWithStatus( - { - accountId, - projectId, - featureId, - context - }, - done - ); - }); - it('Shoud successfully get multiple features and its status', function (done) { - getMultipleFeatureWithStatus( - { - accountId, - projectId, - context - }, - done - ); - }); - it('Shoud successfully get features and their statuses', function (done) { - getFeaturesWithStatuses( - { - accountId, - projectId, - context - }, - done - ); - }); - it('Should trigger Conversion', function () { - const goalKey = 'increase-engagement'; - const response = context.trackConversion(goalKey, { - ruleData: { - action: 'buy' - }, - conversionData: [ - { - key: 'amount', - value: 10.3 - }, - { - key: 'productsCount', - value: 2 - } - ] - }); - expect(response).to.be.undefined; - }); - it('Should successfully set default segments', function (done) { - const segments = {country: 'US'}; - context.setDefaultSegments(segments); - setTimeout(function () { - const localSegments = dataStore.get(storeKey); - expect(localSegments) - .to.have.property('segments') - .that.deep.equal({ - ...segments, - ...defaultSegments - }); - done(); - }, testConfig.events.release_interval + 1); - }); - it('Should successfully set custom segments', function (done) { - const segmentKey = 'test-segments-1'; - const segmentId = '200299434'; - context.runCustomSegments(segmentKey, { - ruleData: { - enabled: true - } - }); - setTimeout(function () { - const {segments} = dataStore.get(storeKey) || {}; - expect(segments) - .to.be.an('object') - .that.has.property('customSegments') - .to.deep.equal([segmentId]); - done(); - }, testConfig.events.release_interval + 1); - }); - }); - describe('Test invalid visitor', function () { - // eslint-disable-next-line mocha/no-hooks-for-single-case - before(function () { - convert = new ConvertSDK(testConfig); - }); - // eslint-disable-next-line mocha/no-hooks-for-single-case - beforeEach(function () { - context = convert.createContext(); - }); - it('Shoud fail to get variation from specific experience if no visitor is set', function () { - const experienceKey = 'test-experience-ab-fullstack-2'; - const variation = context.runExperience(experienceKey); - expect(variation).to.be.undefined; - }); - it('Shoud fail to get variations across all experiences if no visitor is set', function () { - const variations = context.runExperiences(); - expect(variations).to.be.undefined; - }); - it('Shoud fail to get feature and its status if no visitor is set', function () { - const featureKey = 'feature-1'; - const features = context.runFeature(featureKey); - expect(features).to.be.undefined; - }); - it('Shoud fail to get features and their statuses if no visitor is set', function () { - const features = context.runFeatures(); - expect(features).to.be.undefined; - }); - it('Should fail to trigger Conversion if no visitor is set', function () { - const goalKey = 'increase-engagement'; - const output = context.trackConversion(goalKey); - expect(output).to.be.undefined; - }); - it('Should fail to set custom segments if no visitor is set', function () { - const segmentKey = 'test-segments-1'; - const output = context.runCustomSegments(segmentKey); - expect(output).to.be.undefined; - }); - }); -} diff --git a/packages/js-sdk/karma.base.conf.js b/packages/js-sdk/karma.base.conf.js deleted file mode 100644 index cdde42e4..00000000 --- a/packages/js-sdk/karma.base.conf.js +++ /dev/null @@ -1,104 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const dotenv = require('dotenv'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const path = require('path'); -dotenv.config(); -// eslint-disable-next-line @typescript-eslint/no-var-requires -process.env.CHROME_BIN = require('puppeteer').executablePath(); -module.exports = { - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: './', - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha', 'chai', 'webpack'], - - // list of files / patterns to load in the browser - files: [], - - // list of files / patterns to exclude - exclude: [], - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: {}, - - plugins: [ - 'karma-mocha', - 'karma-chai', - 'karma-webpack', - 'karma-chrome-launcher', - require('karma-browserstack-launcher'), - 'karma-mocha-reporter' - ], - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - // reporters: ['progress'], - reporters: ['mocha', 'BrowserStack'], - - // web server port - port: 9876, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: true, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity, - - browserStack: { - username: process.env.BROWSER_STACK_USERNAME, - accessKey: process.env.BROWSER_STACK_ACCESS, - startTunnel: true - }, - webpack: { - mode: 'production', - devtool: 'inline-source-map', - performance: { - hints: false - } - }, - // define browsers - customLaunchers: { - bs_firefox100_win10: { - base: 'BrowserStack', - os: 'Windows', - os_version: '10', - browser: 'firefox', - device: null, - browser_version: '100.0', - real_mobile: null - }, - bs_chrome_100_osx: { - base: 'BrowserStack', - os: 'OS X', - os_version: 'Mojave', - browser: 'chrome', - device: null, - browser_version: '100.0', - real_mobile: null - }, - custom_chrome_headless: { - base: 'ChromeHeadless', - chromeDataDir: path.resolve(__dirname, 'webpack-build/.chrome-karma'), - flags: [ - '--disable-gpu', - '--no-sandbox', - '--crash-dumps-dir=' + - path.resolve(__dirname, 'webpack-build/.chrome-karma-crash') - ] - } - }, - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['custom_chrome_headless'] -}; diff --git a/packages/js-sdk/karma.cjs.conf.js b/packages/js-sdk/karma.cjs.conf.js deleted file mode 100644 index 735db53b..00000000 --- a/packages/js-sdk/karma.cjs.conf.js +++ /dev/null @@ -1,28 +0,0 @@ -// Karma configuration -// eslint-disable-next-line @typescript-eslint/no-var-requires -const baseConfig = require('./karma.base.conf.js'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const path = require('path'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const os = require('os'); -module.exports = function (config) { - config.set({ - ...baseConfig, - - files: [{pattern: './index.browser.cjs.tests.js'}], - preprocessors: { - './index.browser.cjs.tests.js': ['webpack'] - }, - webpack: { - output: { - filename: '[name].js', - path: - path.join(os.tmpdir(), '_karma_webpack_') + - Math.floor(Math.random() * 1000000) - } - }, - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO - }); -}; diff --git a/packages/js-sdk/karma.umd.conf.js b/packages/js-sdk/karma.umd.conf.js deleted file mode 100644 index 10f596d8..00000000 --- a/packages/js-sdk/karma.umd.conf.js +++ /dev/null @@ -1,30 +0,0 @@ -// Karma configuration -// eslint-disable-next-line @typescript-eslint/no-var-requires -const baseConfig = require('./karma.base.conf.js'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const path = require('path'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const os = require('os'); -module.exports = function (config) { - config.set({ - ...baseConfig, - // list of files / patterns to load in the browser - files: ['./lib/index.umd.min.js', './index.browser.umd.tests.js'], - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - './index.browser.umd.tests.js': ['webpack'] - }, - webpack: { - output: { - filename: '[name].js', - path: - path.join(os.tmpdir(), '_karma_webpack_') + - Math.floor(Math.random() * 1000000) - } - }, - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO - }); -}; diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index bafceeb9..8bb9c249 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -16,12 +16,10 @@ }, "license": "Apache-2.0", "scripts": { - "pretest": "mkdir -p webpack-build && rm -rf coverage", + "pretest": "rm -rf coverage", "test": "nyc yarn test:all && yarn coverage", "test:all": "yarn test:mocha && yarn test:browser", - "test:browser": "yarn build && yarn test:cjsbrowser && yarn test:umdbrowser", - "test:cjsbrowser": "karma start karma.cjs.conf.js --single-run", - "test:umdbrowser": "karma start karma.umd.conf.js --single-run", + "test:browser": "playwright test --config playwright.config.ts --project chromium", "test:server": "nyc yarn test:mocha", "test:mocha": "mocha -r ts-node/register --recursive \"tests/**/*.tests.ts\" --exit", "clean": "rm -rf lib", @@ -43,6 +41,7 @@ "@babel/preset-env": "^7.28.5", "@eslint/eslintrc": "^3.3.1", "@jsdoc/salty": "^0.2.9", + "@playwright/test": "^1.52.0", "@rollup/plugin-babel": "^6.1.0", "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", @@ -68,20 +67,9 @@ "eslint-plugin-prettier": "^5.5.4", "glob": "^11.0.3", "istanbul-cobertura-badger": "^1.3.1", - "karma": "^6.4.4", - "karma-browserify": "^8.1.0", - "karma-browserstack-launcher": "^1.6.0", - "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^3.2.0", - "karma-cli": "^2.0.0", - "karma-mocha": "^2.0.1", - "karma-mocha-reporter": "^2.2.5", - "karma-sourcemap-loader": "^0.4.0", - "karma-webpack": "5.0.1", "mocha": "^11.7.5", "nyc": "^17.1.0", "prettier": "^3.6.2", - "puppeteer": "^24.29.1", "rollup": "^4.53.2", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-generate-package-json": "^3.2.0", @@ -97,15 +85,6 @@ "watchify": "^4.0.0", "webpack": "^5.102.1" }, - "overrides": { - "karma-browserstack-launcher": { - "browserstack": { - ".": "1.6.1", - "https-proxy-agent": "7.0.4" - }, - "browserstack-local": "1.5.5" - } - }, "version": "4.3.4", "peerDependencies": { "@convertcom/js-sdk-api": ">=2.1.4", diff --git a/packages/js-sdk/playwright.config.ts b/packages/js-sdk/playwright.config.ts new file mode 100644 index 00000000..e3654dbf --- /dev/null +++ b/packages/js-sdk/playwright.config.ts @@ -0,0 +1,51 @@ +import {defineConfig, devices} from '@playwright/test'; + +const PORT = process.env.PORT || 3939; + +/** + * Playwright configuration for JS SDK browser and integration tests. + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + testMatch: ['browser/**/*.spec.ts', 'integration/**/*.spec.ts'], + /* Run tests sequentially — SDK tests share state */ + fullyParallel: false, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Single worker to avoid port conflicts and shared state issues */ + workers: 1, + /* Reporter to use */ + reporter: [['list']], + /* Shared settings for all the projects below */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + /* Collect trace when retrying the failed test */ + trace: 'retain-on-failure' + }, + /* Each test is given 60 seconds */ + timeout: 60_000, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + launchOptions: { + args: ['--disable-gpu', '--no-sandbox'] + } + } + } + ], + + /* Run local test server before starting the tests */ + webServer: { + command: `node tests/browser/test-server.js`, + url: `http://localhost:${PORT}`, + reuseExistingServer: false + } +}); diff --git a/packages/js-sdk/tests/browser/test-page.html b/packages/js-sdk/tests/browser/test-page.html new file mode 100644 index 00000000..e2a79f5a --- /dev/null +++ b/packages/js-sdk/tests/browser/test-page.html @@ -0,0 +1,26 @@ + + + + + + JS SDK Browser Test + + + +
    + + + diff --git a/packages/js-sdk/tests/browser/test-server.js b/packages/js-sdk/tests/browser/test-server.js new file mode 100644 index 00000000..ae73e0d9 --- /dev/null +++ b/packages/js-sdk/tests/browser/test-server.js @@ -0,0 +1,52 @@ +const http = require('http'); +const fs = require('fs'); +const path = require('path'); + +const PORT = process.env.PORT || 3939; +const ROOT = path.resolve(__dirname, '..', '..'); + +const MIME_TYPES = { + '.html': 'text/html', + '.js': 'application/javascript', + '.mjs': 'application/javascript', + '.json': 'application/json', + '.css': 'text/css' +}; + +const ROUTES = { + '/': path.join(ROOT, 'tests/browser/test-page.html'), + '/umd.html': path.join(ROOT, 'tests/browser/test-page.html'), + '/lib/index.js': path.join(ROOT, 'lib/index.js'), + '/lib/index.umd.min.js': path.join(ROOT, 'lib/index.umd.min.js'), + '/test-config.json': path.join(ROOT, 'tests/test-config.json'), + '/static-config.json': path.join( + ROOT, + 'tests/integration/static-config.json' + ) +}; + +const server = http.createServer((req, res) => { + const url = req.url.split('?')[0]; + const filePath = ROUTES[url]; + + if (!filePath) { + res.writeHead(404, {'Content-Type': 'text/plain'}); + res.end('Not Found'); + return; + } + + try { + const content = fs.readFileSync(filePath); + const ext = path.extname(filePath); + const contentType = MIME_TYPES[ext] || 'application/octet-stream'; + res.writeHead(200, {'Content-Type': contentType}); + res.end(content); + } catch (err) { + res.writeHead(500, {'Content-Type': 'text/plain'}); + res.end('Internal Server Error: ' + err.message); + } +}); + +server.listen(PORT, () => { + console.log(`Test server listening on http://localhost:${PORT}`); +}); diff --git a/packages/js-sdk/tests/browser/umd-bundle.spec.ts b/packages/js-sdk/tests/browser/umd-bundle.spec.ts new file mode 100644 index 00000000..3779685a --- /dev/null +++ b/packages/js-sdk/tests/browser/umd-bundle.spec.ts @@ -0,0 +1,365 @@ +import {test, expect, Page} from '@playwright/test'; + +// Helper: navigate to UMD test page and wait for config to load +async function setupPage(page: Page) { + await page.goto('/umd.html'); + await page.waitForFunction( + () => (window as any).__CONFIG_LOADED__ === true, + {timeout: 5000} + ); +} + +// Helper: inject SDK factory and DataStore onto window so page.evaluate() +// callbacks can call window.__createSdk() / window.__createContext() without +// repeating the boilerplate every time. +async function injectHelpers(page: Page) { + await page.evaluate(() => { + const w = window as any; + w.__createSdk = (extraConfig?: Record) => { + const config = {...w.__TEST_CONFIG__}; + config.events = {batch_size: 1, release_interval: 1000}; + Object.assign(config, extraConfig || {}); + return new w.ConvertSDK.default(config); + }; + w.__createContext = ( + visitorId?: string, + visitorProps?: Record, + extraConfig?: Record + ) => { + const sdk = w.__createSdk(extraConfig); + return sdk.createContext(visitorId, visitorProps); + }; + // Shorthand: create context with default test visitor + w.__defaultContext = (extraConfig?: Record) => + w.__createContext('XXX', {browser: 'chrome'}, extraConfig); + w.__makeDataStore = () => ({ + data: {} as Record, + get(key: string) { + if (!key) return this.data; + return this.data[key.toString()]; + }, + set(key: string, value: any) { + if (!key) throw new Error('Invalid DataStore key!'); + this.data[key.toString()] = value; + } + }); + w.__createSegmentTestContext = () => { + const dataStore = w.__makeDataStore(); + const sdk = w.__createSdk({dataStore}); + const accountId = w.__TEST_CONFIG__.data.account_id; + const projectId = w.__TEST_CONFIG__.data.project.id; + const visitorId = 'XXX'; + const storeKey = `${accountId}-${projectId}-${visitorId}`; + const context = sdk.createContext(visitorId, {browser: 'chrome'}); + return {context, dataStore, storeKey}; + }; + }); +} + +// Combined setup: navigate + inject helpers +async function setup(page: Page) { + await setupPage(page); + await injectHelpers(page); +} + +// Qualifying attributes used across multiple tests +const LOCATION_PROPS = { + locationProperties: {url: 'https://convert.com/'}, + visitorProperties: {varName3: 'something'} +}; + +// Expected object keys for SDK return types (pre-sorted for assertion) +const cmp = (a: string, b: string) => a.localeCompare(b); +const VARIATION_KEYS = [ + 'bucketingAllocation', 'changes', 'experienceId', 'experienceKey', + 'experienceName', 'id', 'is_baseline', 'key', 'name', 'status', + 'traffic_allocation' +].sort(cmp); +const FEATURE_KEYS = [ + 'experienceId', 'experienceKey', 'experienceName', 'id', 'key', + 'name', 'status', 'variables' +].sort(cmp); +const FEATURE_DISABLED_KEYS = ['id', 'key', 'name', 'status'].sort(cmp); + +test.describe('UMD bundle browser tests', () => { + test.describe('Basic SDK instance', () => { + test('Should have ConvertSDK as a global', async ({page}) => { + await setupPage(page); + const hasSDK = await page.evaluate( + () => typeof (window as any).ConvertSDK !== 'undefined' + ); + expect(hasSDK).toBe(true); + }); + + test('Should have a constructor', async ({page}) => { + await setupPage(page); + const isFunction = await page.evaluate( + () => typeof (window as any).ConvertSDK.default === 'function' + ); + expect(isFunction).toBe(true); + }); + + test('Should create a default SDK instance and fire ready event with no errors', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate(() => { + return new Promise((resolve) => { + const sdk = (window as any).__createSdk(); + sdk.on('ready', (_args: any, err: any) => { + resolve({hasError: err !== null, isObject: typeof sdk === 'object'}); + }); + }); + }); + expect((result as any).hasError).toBe(false); + expect((result as any).isObject).toBe(true); + }); + + test('Should create a default SDK instance and resolve onReady promise', async ({ + page + }) => { + await setup(page); + const resolved = await page.evaluate(async () => { + const sdk = (window as any).__createSdk(); + await sdk.onReady(); + return true; + }); + expect(resolved).toBe(true); + }); + + test('Should successfully create visitor context', async ({page}) => { + await setup(page); + const result = await page.evaluate(() => { + const context = (window as any).__defaultContext(); + const methods = [ + 'runExperience', + 'runExperiences', + 'runFeature', + 'runFeatures', + 'trackConversion', + 'setDefaultSegments', + 'runCustomSegments' + ]; + const hasMethods = methods.every( + (m) => typeof context[m] === 'function' + ); + return {isObject: typeof context === 'object', hasMethods}; + }); + expect((result as any).isObject).toBe(true); + expect((result as any).hasMethods).toBe(true); + }); + }); + + test.describe('Basic SDK methods', () => { + test('Should successfully get variation from specific experience', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + const variation = context.runExperience( + 'test-experience-ab-fullstack-2', + props + ); + return { + isObject: typeof variation === 'object' && variation !== null, + experienceKey: variation?.experienceKey, + keys: variation ? Object.keys(variation).sort((a, b) => a.localeCompare(b)) : [] + }; + }, LOCATION_PROPS); + expect((result as any).isObject).toBe(true); + expect((result as any).experienceKey).toBe( + 'test-experience-ab-fullstack-2' + ); + expect((result as any).keys).toEqual(VARIATION_KEYS); + }); + + test('Should successfully get variations across all experiences', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + const variations = context.runExperiences(props); + return { + isArray: Array.isArray(variations), + length: variations?.length, + ids: variations?.map((v: any) => v.id) + }; + }, LOCATION_PROPS); + expect((result as any).isArray).toBe(true); + expect((result as any).length).toBe(2); + const validIds = ['100299456', '100299457', '100299460', '100299461']; + for (const id of (result as any).ids) { + expect(validIds).toContain(id); + } + }); + + test('Should successfully get a single feature and its status', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + const feature = context.runFeature('feature-2', props); + return { + isObject: typeof feature === 'object' && feature !== null, + id: feature?.id, + keys: feature ? Object.keys(feature).sort((a, b) => a.localeCompare(b)) : [] + }; + }, LOCATION_PROPS); + expect((result as any).isObject).toBe(true); + expect((result as any).id).toBe('10025'); + expect((result as any).keys).toEqual(FEATURE_KEYS); + }); + + test('Should successfully get multiple features and their status', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + const features = context.runFeature('feature-1', props); + return { + isArray: Array.isArray(features), + length: features?.length, + ids: features?.map((f: any) => f.id) + }; + }, LOCATION_PROPS); + expect((result as any).isArray).toBe(true); + expect((result as any).length).toBe(2); + const validIds = ['10024', '10025']; + for (const id of (result as any).ids) { + expect(validIds).toContain(id); + } + }); + + test('Should successfully get features and their statuses', async ({ + page + }) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + const features = context.runFeatures(props); + return { + isArray: Array.isArray(features), + length: features?.length, + ids: features?.map((f: any) => f.id), + enabledKeys: features + ?.filter((f: any) => f.status === 'enabled') + .map((f: any) => Object.keys(f).sort((a, b) => a.localeCompare(b))), + disabledKeys: features + ?.filter((f: any) => f.status === 'disabled') + .map((f: any) => Object.keys(f).sort((a, b) => a.localeCompare(b))) + }; + }, LOCATION_PROPS); + expect((result as any).isArray).toBe(true); + expect((result as any).length).toBe(4); + const validIds = ['10024', '10025', '10026']; + for (const id of (result as any).ids.filter( + (id: string) => id !== undefined + )) { + expect(validIds).toContain(id); + } + for (const keys of (result as any).enabledKeys) { + expect(keys).toEqual(FEATURE_KEYS); + } + for (const keys of (result as any).disabledKeys) { + expect(keys).toEqual(FEATURE_DISABLED_KEYS); + } + }); + + test('Should trigger Conversion', async ({page}) => { + await setup(page); + const result = await page.evaluate((props) => { + const context = (window as any).__defaultContext(); + context.runExperience('test-experience-ab-fullstack-2', props); + const response = context.trackConversion('increase-engagement', { + ruleData: {action: 'buy'}, + conversionData: [ + {key: 'amount', value: 10.3}, + {key: 'productsCount', value: 2} + ] + }); + return {isUndefined: response === undefined}; + }, LOCATION_PROPS); + expect((result as any).isUndefined).toBe(true); + }); + + test('Should successfully set default segments', async ({page}) => { + await setup(page); + const result = await page.evaluate(() => { + return new Promise((resolve) => { + const {context, dataStore, storeKey} = ( + window as any + ).__createSegmentTestContext(); + context.setDefaultSegments({country: 'US'}); + + setTimeout(() => { + const localSegments = dataStore.get(storeKey); + resolve({ + hasSegments: localSegments?.segments !== undefined, + segments: localSegments?.segments + }); + }, 1100); + }); + }); + expect((result as any).hasSegments).toBe(true); + expect((result as any).segments).toEqual({ + country: 'US', + browser: 'chrome' + }); + }); + + test('Should successfully set custom segments', async ({page}) => { + await setup(page); + const result = await page.evaluate(() => { + return new Promise((resolve) => { + const {context, dataStore, storeKey} = ( + window as any + ).__createSegmentTestContext(); + context.runCustomSegments('test-segments-1', { + ruleData: {enabled: true} + }); + + setTimeout(() => { + const data = dataStore.get(storeKey); + resolve({ + hasCustomSegments: + data?.segments?.customSegments !== undefined, + customSegments: data?.segments?.customSegments + }); + }, 1100); + }); + }); + expect((result as any).hasCustomSegments).toBe(true); + expect((result as any).customSegments).toEqual(['200299434']); + }); + }); + + test.describe('Test invalid visitor', () => { + // All SDK methods should return undefined when no visitor ID is set + const invalidVisitorCases = [ + {method: 'runExperience', args: ['test-experience-ab-fullstack-2']}, + {method: 'runExperiences', args: []}, + {method: 'runFeature', args: ['feature-1']}, + {method: 'runFeatures', args: []}, + {method: 'trackConversion', args: ['increase-engagement']}, + {method: 'runCustomSegments', args: ['test-segments-1']} + ]; + + for (const {method, args} of invalidVisitorCases) { + test(`Should fail ${method} if no visitor is set`, async ({page}) => { + await setup(page); + const result = await page.evaluate( + ({m, a}) => { + const context = (window as any).__createContext(); + return context[m](...a); + }, + {m: method, a: args} + ); + expect(result).toBeUndefined(); + }); + } + }); +}); diff --git a/packages/js-sdk/tests/integration/full-chain.spec.ts b/packages/js-sdk/tests/integration/full-chain.spec.ts new file mode 100644 index 00000000..5aba02e1 --- /dev/null +++ b/packages/js-sdk/tests/integration/full-chain.spec.ts @@ -0,0 +1,462 @@ +import {test, expect} from '@playwright/test'; + +// Import from the built CJS bundle — same as consumers would use +// eslint-disable-next-line @typescript-eslint/no-var-requires +const SDK = require('../../lib/index'); +const ConvertSDK = SDK.default; +const {SystemEvents} = SDK; + +// Static config for offline/always-run mode +// eslint-disable-next-line @typescript-eslint/no-var-requires +const staticConfig = require('./static-config.json'); + +// --- Constants matching staging project "FS-Test-Proj - DO NOT DELETE" --- +const EXPERIENCE_KEY = 'test-experience-ab-fullstack-4'; +const FEATURE_TYPED_KEY = 'feature-2'; +const FEATURE_BASIC_KEY = 'feature-1'; +const GOAL_KEY = 'increase-engagement'; +const VARIATION_IDS = ['1003180877', '1003180878']; + +// Experience -1 has audience "adv-audience" requiring (desktop=true AND browser!="CH") OR (mobile=true) +const EXPERIENCE_WITH_AUDIENCE_KEY = 'test-experience-ab-fullstack-1'; + +// Location "pricing-location" requires location=pricing +const qualifyingAttributes = { + locationProperties: {location: 'pricing'} +}; + +// --- In-memory DataStore for dedup tests --- +class MemoryDataStore { + private data: Record = {}; + get(key: string): any { + if (!key) return this.data; + return this.data[key.toString()]; + } + set(key: string, value: any): void { + if (!key) throw new Error('Invalid DataStore key!'); + this.data[key.toString()] = value; + } +} + +// --- Dual-mode: static always runs, live only when env var is set --- +const modes: Array<'static' | 'live' | 'live-secret'> = [ + 'static', + ...(process.env.CONVERT_STAGING_SDK_KEY ? (['live'] as const) : []), + ...(process.env.CONVERT_STAGING_SDK_KEY2 && + process.env.CONVERT_STAGING_SDK_KEY2_SECRET + ? (['live-secret'] as const) + : []) +]; + +function createSdk( + mode: 'static' | 'live' | 'live-secret', + overrides: Record = {} +) { + if (mode === 'live') { + return new ConvertSDK({ + sdkKey: process.env.CONVERT_STAGING_SDK_KEY, + environment: 'staging', + network: {tracking: false}, + ...overrides + }); + } + if (mode === 'live-secret') { + return new ConvertSDK({ + sdkKey: process.env.CONVERT_STAGING_SDK_KEY2, + sdkKeySecret: process.env.CONVERT_STAGING_SDK_KEY2_SECRET, + environment: 'staging', + network: {tracking: false}, + ...overrides + }); + } + return new ConvertSDK({ + data: staticConfig, + environment: 'staging', + network: {tracking: false}, + ...overrides + }); +} + +// Helper: create SDK, wait for ready, and create a visitor context +async function createReadyContext( + mode: 'static' | 'live' | 'live-secret', + visitorId: string, + overrides: Record = {} +) { + const sdk = createSdk(mode, overrides); + await sdk.onReady(); + const context = sdk.createContext(visitorId); + return {sdk, context}; +} + +// Helper: create SDK with tracking enabled and a fresh MemoryDataStore +function createTrackingSdk( + mode: 'static' | 'live' | 'live-secret', + overrides: Record = {} +) { + const dataStore = new MemoryDataStore(); + const sdk = createSdk(mode, { + network: {tracking: true}, + dataStore, + ...overrides + }); + return {sdk, dataStore}; +} + +// Helper: create tracking SDK, wait for ready, create context, and bucket into experience +async function createBucketedTrackingContext( + mode: 'static' | 'live' | 'live-secret', + visitorId: string, + overrides: Record = {} +) { + const {sdk, dataStore} = createTrackingSdk(mode, overrides); + await sdk.onReady(); + const context = sdk.createContext(visitorId); + context.runExperience(EXPERIENCE_KEY, qualifyingAttributes); + return {sdk, dataStore, context}; +} + +// Helper: bucket into experience + run feature, return both with assertions +function bucketAndVerifyFeature(context: any) { + const variation = context.runExperience(EXPERIENCE_KEY, qualifyingAttributes); + expect(variation).toBeDefined(); + expect(VARIATION_IDS).toContain(variation.id); + + const feature = context.runFeature(FEATURE_TYPED_KEY, qualifyingAttributes); + expect(feature).toBeDefined(); + expect(feature.status).toBe('enabled'); + expect(feature.variables.price).toBe(100); + + return {variation, feature}; +} + +for (const mode of modes) { + test.describe(`Full-chain integration tests [${mode} mode]`, () => { + // --- Happy Path --- + + test('SDK initializes and is ready', async () => { + const sdk = createSdk(mode); + await sdk.onReady(); + }); + + test('Ready event fired on init', async () => { + const sdk = createSdk(mode); + let readyCalled = 0; + let readyError: any = null; + sdk.on(SystemEvents.READY, (_args: any, err: any) => { + readyCalled++; + readyError = err; + }); + await sdk.onReady(); + expect(readyCalled).toBe(1); + expect(readyError).toBeNull(); + }); + + test('Create context and run experience', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-integration-test' + ); + const variation = context.runExperience( + EXPERIENCE_KEY, + qualifyingAttributes + ); + expect(variation).toBeDefined(); + expect(variation).not.toBeNull(); + expect(variation.experienceKey).toBe(EXPERIENCE_KEY); + expect(VARIATION_IDS).toContain(variation.id); + expect(variation.changes).toBeDefined(); + expect(Array.isArray(variation.changes)).toBe(true); + expect(variation.changes.length).toBeGreaterThan(0); + }); + + test('Bucketing determinism', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-determinism-test' + ); + + const results: string[] = []; + for (let i = 0; i < 10; i++) { + const variation = context.runExperience( + EXPERIENCE_KEY, + qualifyingAttributes + ); + expect(variation).toBeDefined(); + results.push(variation.id); + } + + // All 10 runs should return the same variation + const uniqueIds = [...new Set(results)]; + expect(uniqueIds).toHaveLength(1); + expect(VARIATION_IDS).toContain(uniqueIds[0]); + }); + + test('Bucketing event fired on experience', async () => { + const {sdk, context} = await createReadyContext( + mode, + 'visitor-bucketing-event-test' + ); + + let bucketingFired = false; + sdk.on(SystemEvents.BUCKETING, () => { + bucketingFired = true; + }); + context.runExperience(EXPERIENCE_KEY, qualifyingAttributes); + expect(bucketingFired).toBe(true); + }); + + test('Run feature with typed variables', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-feature-typed-test' + ); + + // Must run experience first to bucket into a variation + context.runExperience(EXPERIENCE_KEY, qualifyingAttributes); + + const feature = context.runFeature( + FEATURE_TYPED_KEY, + qualifyingAttributes + ); + expect(feature).toBeDefined(); + expect(feature).not.toBeNull(); + expect(feature.status).toBe('enabled'); + + // Verify typed variables + expect(feature.variables).toBeDefined(); + expect(typeof feature.variables.price).toBe('number'); + expect(feature.variables.price).toBe(100); + expect(typeof feature.variables['button-height']).toBe('number'); + expect(feature.variables['button-height']).toBe(40); + expect(typeof feature.variables.additionalData).toBe('object'); + expect(feature.variables.additionalData.foo).toBe('bar'); + expect(feature.variables.additionalData.v).toBe(2); + }); + + test('Full chain: init -> context -> bucket -> feature -> verify', async () => { + const {sdk, context} = await createReadyContext( + mode, + 'visitor-full-chain-test' + ); + + let readyFired = false; + let bucketingFired = false; + sdk.on(SystemEvents.READY, () => { + readyFired = true; + }); + sdk.on(SystemEvents.BUCKETING, () => { + bucketingFired = true; + }); + + expect(readyFired).toBe(true); + bucketAndVerifyFeature(context); + expect(bucketingFired).toBe(true); + }); + + // --- Negative Path --- + + test('Run feature with unknown key returns disabled status', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-negative-test' + ); + const result = context.runFeature('nonexistent-feature'); + // SDK returns a BucketedFeature with status 'disabled' for unknown features + expect(result).toBeDefined(); + expect(result.key).toBe('nonexistent-feature'); + expect(result.status).toBe('disabled'); + }); + + test('Run experience with non-qualifying location returns null', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-non-qualifying-test' + ); + const result = context.runExperience(EXPERIENCE_KEY, { + locationProperties: {location: 'nonexistent'} + }); + // SDK returns null when location doesn't match + expect(result).toBeNull(); + }); + + test('Run experience with audience and no visitor properties returns null', async () => { + const {context} = await createReadyContext( + mode, + 'visitor-audience-test' + ); + // exp-1 has audience requiring (desktop=true AND browser!="CH") OR (mobile=true) + // Passing only locationProperties and no visitorProperties should fail audience check + const result = context.runExperience(EXPERIENCE_WITH_AUDIENCE_KEY, { + locationProperties: {location: 'pricing'} + }); + // SDK returns null when audience doesn't match + expect(result).toBeNull(); + }); + + // --- Conversion Tracking --- + + test('Track conversion', async () => { + const {context} = await createBucketedTrackingContext( + mode, + 'visitor-conversion-test' + ); + // increase-engagement goal has rules: null, so no ruleData should be passed + const result = context.trackConversion(GOAL_KEY); + // trackConversion returns undefined on success + expect(result).toBeUndefined(); + }); + + test('Conversion event fired on trackConversion', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-conversion-event-test' + ); + + let conversionFired = false; + let conversionData: any = null; + sdk.on(SystemEvents.CONVERSION, (data: any) => { + conversionFired = true; + conversionData = data; + }); + + // increase-engagement goal has rules: null, so no ruleData should be passed + context.trackConversion(GOAL_KEY); + + expect(conversionFired).toBe(true); + expect(conversionData).toBeDefined(); + }); + + test('Goal deduplication', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-dedup-test' + ); + + let conversionCount = 0; + sdk.on(SystemEvents.CONVERSION, () => { + conversionCount++; + }); + + // First call — increase-engagement has no rules, so no ruleData + context.trackConversion(GOAL_KEY); + // Second call — should be deduplicated + context.trackConversion(GOAL_KEY); + + expect(conversionCount).toBe(1); + }); + + test('Track conversion with revenue', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-revenue-test' + ); + + let queueReleased = false; + sdk.on(SystemEvents.API_QUEUE_RELEASED, () => { + queueReleased = true; + }); + + // increase-engagement goal has rules: null, so no ruleData + const result = context.trackConversion(GOAL_KEY, { + conversionData: [ + {key: 'amount', value: 49.99}, + {key: 'transactionId', value: 'txn-integration-001'} + ] + }); + + expect(result).toBeUndefined(); + + // Wait for the queue to release + await new Promise((resolve) => { + if (queueReleased) { + resolve(); + } else { + const checkInterval = setInterval(() => { + if (queueReleased) { + clearInterval(checkInterval); + resolve(); + } + }, 100); + // Timeout after 5 seconds + setTimeout(() => { + clearInterval(checkInterval); + resolve(); + }, 5000); + } + }); + }); + + test('Force multiple transactions', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-force-multi-test' + ); + + let conversionCount = 0; + sdk.on(SystemEvents.CONVERSION, () => { + conversionCount++; + }); + + // First call — no ruleData since increase-engagement has rules: null + context.trackConversion(GOAL_KEY, { + conversionData: [{key: 'amount', value: 10}] + }); + + // Second call with forceMultipleTransactions — should NOT be deduplicated + context.trackConversion(GOAL_KEY, { + conversionData: [{key: 'amount', value: 20}], + conversionSetting: {forceMultipleTransactions: true} + }); + + expect(conversionCount).toBe(2); + }); + + test('Track conversion with nonexistent goal returns undefined', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-fake-goal-test' + ); + + let conversionFired = false; + sdk.on(SystemEvents.CONVERSION, () => { + conversionFired = true; + }); + + const result = context.trackConversion('totally-fake-goal'); + expect(result).toBeUndefined(); + expect(conversionFired).toBe(false); + }); + + // --- Complete Chain --- + + test('Complete chain: init -> context -> bucket -> feature -> conversion -> flush', async () => { + const {sdk, context} = await createBucketedTrackingContext( + mode, + 'visitor-complete-chain-test', + {events: {batch_size: 1, release_interval: 1000}} + ); + + let conversionFired = false; + sdk.on(SystemEvents.CONVERSION, () => { + conversionFired = true; + }); + + // Verify feature (experience already bucketed by createBucketedTrackingContext) + const feature = context.runFeature( + FEATURE_TYPED_KEY, + qualifyingAttributes + ); + expect(feature).toBeDefined(); + expect(feature.status).toBe('enabled'); + expect(feature.variables.price).toBe(100); + + // Track conversion — no ruleData since increase-engagement has rules: null + const conversionResult = context.trackConversion(GOAL_KEY, { + conversionData: [{key: 'amount', value: 99.99}] + }); + expect(conversionResult).toBeUndefined(); + expect(conversionFired).toBe(true); + }); + }); +} diff --git a/packages/js-sdk/tests/integration/static-config.json b/packages/js-sdk/tests/integration/static-config.json new file mode 100644 index 00000000..f324b7bb --- /dev/null +++ b/packages/js-sdk/tests/integration/static-config.json @@ -0,0 +1 @@ +{"account_id":"10035569","project":{"id":"10034190","name":"FS-Test-Proj - DO NOT DELETE","type":"fullstack","utc_offset":"0","domains":[],"global_javascript":"","settings":{"include_jquery":false,"include_jquery_v1":false,"disable_spa_functionality":false,"do_not_track_referral":false,"allow_crossdomain_tracking":false,"data_anonymization":false,"do_not_track":"OFF","global_privacy_control":"OFF","min_order_value":0,"max_order_value":99999,"version":"2026-03-22T07:46:28+00:00-259","tracking_script":null,"outliers":{"order_value":{"detection_type":"none"},"products_ordered_count":{"detection_type":"none"}},"placeholders":[],"global_javascript_placeholders":[],"integrations":{"google_analytics":{"enabled":false},"kissmetrics":{"enabled":false},"visitor_insights":{"tracking_id":null}}},"custom_domain":null},"experiences":[{"id":"100334665","name":"Test Experience AB Fullstack","type":"a\/b_fullstack","status":"active","global_js":"","global_css":"","environment":"staging","settings":{"min_order_value":0,"max_order_value":99999,"matching_options":{"audiences":"any","locations":"any"},"placeholders":[],"outliers":{"order_value":{"detection_type":"none"},"products_ordered_count":{"detection_type":"none"}}},"key":"test-experience-ab-fullstack-1","version":8,"locations":["1003350","1003351","1003352","10036409"],"site_area":null,"audiences":["10033684"],"goals":["100322784"],"integrations":[],"environments":["staging"],"variations":[{"id":"1003142550","name":"Original Page","key":"1003142550-original-page","status":"running","changes":[{"id":1003122037,"type":"fullStackFeature","data":{"feature_id":10031,"variables_data":{"enabled":false,"caption":"Click this"}}}],"traffic_allocation":50.0},{"id":"1003142551","name":"Variation 1","key":"1003142551-variation-1","status":"running","changes":[{"id":1003122038,"type":"fullStackFeature","data":{"feature_id":10031,"variables_data":{"enabled":false,"caption":"Click that"}}}],"traffic_allocation":50.0}]},{"id":"100349071","name":"Test Experience AB Fullstack 4","type":"a\/b_fullstack","status":"active","global_js":"","global_css":"","environment":"staging","settings":{"min_order_value":0,"max_order_value":99999,"matching_options":{"audiences":"any","locations":"any"},"placeholders":[],"outliers":{"order_value":{"detection_type":"none"},"products_ordered_count":{"detection_type":"none"}}},"key":"test-experience-ab-fullstack-4","version":11,"locations":["1003352"],"site_area":null,"audiences":[],"goals":["100322782","100322783"],"integrations":[],"environments":["staging"],"variations":[{"id":"1003180877","name":"Original","key":"original","status":"running","changes":[{"id":1003183443,"type":"fullStackFeature","data":{"feature_id":100334,"variables_data":{"price":100,"button-height":40,"additionalData":{"foo":"bar","v":2}}}},{"id":1003183444,"type":"fullStackFeature","data":{"feature_id":10031,"variables_data":{"enabled":false,"caption":"Click that"}}}],"traffic_allocation":50.0},{"id":"1003180878","name":"Variation 1","key":"variation-1","status":"running","changes":[{"id":1003183445,"type":"fullStackFeature","data":{"feature_id":100334,"variables_data":{"price":100,"button-height":40,"additionalData":{"foo":"bar","v":2}}}},{"id":1003183446,"type":"fullStackFeature","data":{"feature_id":10031,"variables_data":{"enabled":false,"caption":"Not allowed"}}}],"traffic_allocation":50.0}]}],"audiences":[{"id":"10033684","name":"Adv Audience","key":"adv-audience","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_bool_key_value","matching":{"match_type":"equals","negated":false},"value":true,"key":"desktop"}]},{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":true},"value":"CH","key":"browser"}]}]},{"AND":[{"OR_WHEN":[{"rule_type":"generic_bool_key_value","matching":{"match_type":"equals","negated":false},"value":true,"key":"mobile"}]}]}]},"type":"permanent"}],"segments":[{"id":"10033690","name":"Test Segments","key":"test-segment-1","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_bool_key_value","matching":{"match_type":"equals","negated":false},"value":true,"key":"enabled"}]}]}]}}],"goals":[{"id":"100322782","name":"Decrease BounceRate","key":"decrease-bounce-rate","type":"advanced","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"pages_visited_count","matching":{"match_type":"lessEqual","negated":true},"value":1,"key":"d"},{"rule_type":"visit_duration","matching":{"match_type":"lessEqual","negated":true},"value":10}]}]}]}},{"id":"100322783","name":"Increase Engagement","key":"increase-engagement","type":"dom_interaction","rules":null,"settings":{"tracked_items":[{"event":"click","selector":"a"},{"event":"submit","selector":"form"}]}},{"id":"100322784","name":"primary button click","key":"button-primary-click","type":"revenue","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"buy","key":"action"}]}]}]},"settings":{"triggering_type":"manual"}}],"locations":[{"id":"1003350","key":"events-location","name":"Events Location","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"events","key":"location"}]}]}]},"trigger":{"type":"upon_run"}},{"id":"1003351","key":"statistics-location","name":"Statistics Location","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"statistics","key":"location"}]}]}]},"trigger":{"type":"upon_run"}},{"id":"1003352","key":"pricing-location","name":"Pricing Location","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"pricing","key":"location"}]}]}]},"trigger":{"type":"upon_run"}},{"id":"10036407","key":"homescreen","name":"HomeScreen","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"home","key":"screen"},{"rule_type":"generic_text_key_value","matching":{"match_type":"matches","negated":false},"value":"https:\/\/test.com","key":"feature"}]}]}]},"trigger":{"type":"upon_run"}},{"id":"10036409","key":"dasadsa","name":"dasadsa","rules":{"OR":[{"AND":[{"OR_WHEN":[{"rule_type":"generic_numeric_key_value","matching":{"match_type":"less","negated":false},"value":5,"key":"feature"}]}]}]},"trigger":{"type":"upon_run"}}],"archived_experiences":["100334668","100344096"],"features":[{"id":"10031","name":"Feature 1","key":"feature-1","variables":[{"key":"enabled","type":"boolean"},{"key":"caption","type":"string"}]},{"id":"10032","name":"Feature 4","key":"feature-4","variables":[{"key":"statistics","type":"json"}]},{"id":"10033","name":"Feature 5","key":"feature-5","variables":[{"key":"plans","type":"json"}]},{"id":"100320","name":"Button","key":"button","variables":[{"key":"Border","type":"boolean"},{"key":"Color","type":"string"}]},{"id":"100334","name":"Feature 2","key":"feature-2","variables":[{"key":"price","type":"float"},{"key":"button-height","type":"integer"},{"key":"additionalData","type":"json"}]},{"id":"100335","name":"Not Attached Feature 3","key":"not-attached-feature-3","variables":[{"key":"fee","type":"float"},{"key":"link","type":"string"},{"key":"additionalData","type":"json"}]}],"_s_t":"2026-03-22 08:01:02Z","is_debug":false} \ No newline at end of file diff --git a/release-please-config.json b/release-please-config.json index 4621a199..7eb84481 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -74,6 +74,12 @@ "draft": false, "prerelease": false, "monorepo-tags": true + }, + "packages/cloudflare": { + "changelog-path": "CHANGELOG.md", + "draft": false, + "prerelease": false, + "monorepo-tags": true } }, "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" diff --git a/yarn.lock b/yarn.lock index 90f8c33b..cc4cd58d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3185,6 +3185,70 @@ __metadata: languageName: node linkType: hard +"@cloudflare/kv-asset-handler@npm:0.3.4": + version: 0.3.4 + resolution: "@cloudflare/kv-asset-handler@npm:0.3.4" + dependencies: + mime: "npm:^3.0.0" + checksum: 10c0/5895d28a4489f470acd217485e3ffbbe2e4a63b0772bb2925ee0f646b6ccce1fd224e07c4610cf514b5e7d0100053c81745a21c0af9a89a98fe16990a4e38ce7 + languageName: node + linkType: hard + +"@cloudflare/unenv-preset@npm:2.0.2": + version: 2.0.2 + resolution: "@cloudflare/unenv-preset@npm:2.0.2" + peerDependencies: + unenv: 2.0.0-rc.14 + workerd: ^1.20250124.0 + peerDependenciesMeta: + workerd: + optional: true + checksum: 10c0/8efc49c9c8eec3c03e75bfc65115c54635aef886461f605e4d6e72a594c6e6dd20e05cdedb174feec7c4d7a88ef962eed7380e64c48209f31d56d34ee479a617 + languageName: node + linkType: hard + +"@cloudflare/workerd-darwin-64@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "@cloudflare/workerd-darwin-64@npm:1.20250718.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@cloudflare/workerd-darwin-arm64@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20250718.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@cloudflare/workerd-linux-64@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "@cloudflare/workerd-linux-64@npm:1.20250718.0" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@cloudflare/workerd-linux-arm64@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "@cloudflare/workerd-linux-arm64@npm:1.20250718.0" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@cloudflare/workerd-windows-64@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "@cloudflare/workerd-windows-64@npm:1.20250718.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@cloudflare/workers-types@npm:^4.20241205.0": + version: 4.20260405.1 + resolution: "@cloudflare/workers-types@npm:4.20260405.1" + checksum: 10c0/931bc1566dc61ea48e78dbd6a3c3d50465bf5031e66f9d19b085cc9b106f110f625b35d5258c111e41fa45a37fd8f84920ce1aecc8f1cb66a282179e5e8b96ae + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -3289,6 +3353,33 @@ __metadata: languageName: unknown linkType: soft +"@convertcom/js-sdk-cloudflare@npm:^1.0.0, @convertcom/js-sdk-cloudflare@workspace:packages/cloudflare": + version: 0.0.0-use.local + resolution: "@convertcom/js-sdk-cloudflare@workspace:packages/cloudflare" + dependencies: + "@babel/cli": "npm:^7.28.3" + "@babel/core": "npm:^7.28.5" + "@babel/preset-env": "npm:^7.28.5" + "@eslint/eslintrc": "npm:^3.3.1" + "@rollup/plugin-babel": "npm:^6.1.0" + "@rollup/plugin-commonjs": "npm:^29.0.0" + "@rollup/plugin-terser": "npm:^0.4.4" + "@typescript-eslint/parser": "npm:^8.46.4" + eslint: "npm:^9.39.1" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + prettier: "npm:^3.6.2" + rollup: "npm:^4.53.2" + rollup-plugin-generate-package-json: "npm:^3.2.0" + rollup-plugin-modify: "npm:^3.0.0" + rollup-plugin-typescript2: "npm:^0.36.0" + typescript: "npm:^5.9.3" + typescript-eslint: "npm:^8.46.4" + peerDependencies: + "@convertcom/js-sdk": ">=4.0.0" + languageName: unknown + linkType: soft + "@convertcom/js-sdk-data@workspace:packages/data": version: 0.0.0-use.local resolution: "@convertcom/js-sdk-data@workspace:packages/data" @@ -3341,6 +3432,18 @@ __metadata: languageName: unknown linkType: soft +"@convertcom/js-sdk-demo-cloudflare-workers@workspace:demo/cloudflare-workers": + version: 0.0.0-use.local + resolution: "@convertcom/js-sdk-demo-cloudflare-workers@workspace:demo/cloudflare-workers" + dependencies: + "@cloudflare/workers-types": "npm:^4.20241205.0" + "@convertcom/js-sdk": "npm:^4.3.4" + "@convertcom/js-sdk-cloudflare": "npm:^1.0.0" + typescript: "npm:^5.9.3" + wrangler: "npm:^3.99.0" + languageName: unknown + linkType: soft + "@convertcom/js-sdk-demo-nodejs@workspace:demo/nodejs": version: 0.0.0-use.local resolution: "@convertcom/js-sdk-demo-nodejs@workspace:demo/nodejs" @@ -3714,7 +3817,7 @@ __metadata: languageName: unknown linkType: soft -"@convertcom/js-sdk@workspace:packages/js-sdk": +"@convertcom/js-sdk@npm:^4.3.4, @convertcom/js-sdk@workspace:packages/js-sdk": version: 0.0.0-use.local resolution: "@convertcom/js-sdk@workspace:packages/js-sdk" dependencies: @@ -3723,6 +3826,7 @@ __metadata: "@babel/preset-env": "npm:^7.28.5" "@eslint/eslintrc": "npm:^3.3.1" "@jsdoc/salty": "npm:^0.2.9" + "@playwright/test": "npm:^1.52.0" "@rollup/plugin-babel": "npm:^6.1.0" "@rollup/plugin-commonjs": "npm:^29.0.0" "@rollup/plugin-json": "npm:^6.1.0" @@ -3748,20 +3852,9 @@ __metadata: eslint-plugin-prettier: "npm:^5.5.4" glob: "npm:^11.0.3" istanbul-cobertura-badger: "npm:^1.3.1" - karma: "npm:^6.4.4" - karma-browserify: "npm:^8.1.0" - karma-browserstack-launcher: "npm:^1.6.0" - karma-chai: "npm:^0.1.0" - karma-chrome-launcher: "npm:^3.2.0" - karma-cli: "npm:^2.0.0" - karma-mocha: "npm:^2.0.1" - karma-mocha-reporter: "npm:^2.2.5" - karma-sourcemap-loader: "npm:^0.4.0" - karma-webpack: "npm:5.0.1" mocha: "npm:^11.7.5" nyc: "npm:^17.1.0" prettier: "npm:^3.6.2" - puppeteer: "npm:^24.29.1" rollup: "npm:^4.53.2" rollup-plugin-copy: "npm:^3.5.0" rollup-plugin-generate-package-json: "npm:^3.2.0" @@ -3791,7 +3884,7 @@ __metadata: languageName: unknown linkType: soft -"@cspotcode/source-map-support@npm:^0.8.0": +"@cspotcode/source-map-support@npm:0.8.1, @cspotcode/source-map-support@npm:^0.8.0": version: 0.8.1 resolution: "@cspotcode/source-map-support@npm:0.8.1" dependencies: @@ -3983,6 +4076,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/runtime@npm:^1.2.0": + version: 1.9.2 + resolution: "@emnapi/runtime@npm:1.9.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/61c3a59e0c36784558b8d58eb02bd04815aa5fb0dbfbaf84d1b3050a78aa0cc63ea129ae806bd1e48062bfeb7fc36eb0e5431740d62f64ea51bdf426404b8caa + languageName: node + linkType: hard + "@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.5.0, @emnapi/runtime@npm:^1.6.0, @emnapi/runtime@npm:^1.7.0": version: 1.7.0 resolution: "@emnapi/runtime@npm:1.7.0" @@ -4031,6 +4133,27 @@ __metadata: languageName: node linkType: hard +"@esbuild-plugins/node-globals-polyfill@npm:0.2.3": + version: 0.2.3 + resolution: "@esbuild-plugins/node-globals-polyfill@npm:0.2.3" + peerDependencies: + esbuild: "*" + checksum: 10c0/da3591b3943076a8d4a78320c176f37e5a5802512e2c3a792d4dfe495c051e097668dc56513160147b43e86987078559490164905ef41d1326ac0a9e7a6498ac + languageName: node + linkType: hard + +"@esbuild-plugins/node-modules-polyfill@npm:0.2.2": + version: 0.2.2 + resolution: "@esbuild-plugins/node-modules-polyfill@npm:0.2.2" + dependencies: + escape-string-regexp: "npm:^4.0.0" + rollup-plugin-node-polyfills: "npm:^0.2.1" + peerDependencies: + esbuild: "*" + checksum: 10c0/8573eb409d19769ea6a2f621d8d7e344d84a9f19d03f37f4ace053e23dab8eeea08feea871c1704a2d39c0859adadfba808b59a50de4d227cb3879dbd90e7f52 + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.19.12": version: 0.19.12 resolution: "@esbuild/aix-ppc64@npm:0.19.12" @@ -4052,6 +4175,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm64@npm:0.17.19" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/android-arm64@npm:0.17.6" @@ -4080,6 +4210,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm@npm:0.17.19" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/android-arm@npm:0.17.6" @@ -4108,6 +4245,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-x64@npm:0.17.19" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/android-x64@npm:0.17.6" @@ -4136,6 +4280,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-arm64@npm:0.17.19" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/darwin-arm64@npm:0.17.6" @@ -4164,6 +4315,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-x64@npm:0.17.19" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/darwin-x64@npm:0.17.6" @@ -4192,6 +4350,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-arm64@npm:0.17.19" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/freebsd-arm64@npm:0.17.6" @@ -4220,6 +4385,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-x64@npm:0.17.19" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/freebsd-x64@npm:0.17.6" @@ -4248,6 +4420,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm64@npm:0.17.19" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-arm64@npm:0.17.6" @@ -4276,6 +4455,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm@npm:0.17.19" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-arm@npm:0.17.6" @@ -4304,6 +4490,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ia32@npm:0.17.19" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-ia32@npm:0.17.6" @@ -4332,6 +4525,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-loong64@npm:0.17.19" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-loong64@npm:0.17.6" @@ -4360,6 +4560,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-mips64el@npm:0.17.19" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-mips64el@npm:0.17.6" @@ -4388,6 +4595,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ppc64@npm:0.17.19" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-ppc64@npm:0.17.6" @@ -4416,6 +4630,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-riscv64@npm:0.17.19" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-riscv64@npm:0.17.6" @@ -4444,6 +4665,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-s390x@npm:0.17.19" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-s390x@npm:0.17.6" @@ -4472,6 +4700,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-x64@npm:0.17.19" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/linux-x64@npm:0.17.6" @@ -4507,6 +4742,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/netbsd-x64@npm:0.17.19" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/netbsd-x64@npm:0.17.6" @@ -4542,6 +4784,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/openbsd-x64@npm:0.17.19" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/openbsd-x64@npm:0.17.6" @@ -4577,6 +4826,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/sunos-x64@npm:0.17.19" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/sunos-x64@npm:0.17.6" @@ -4605,6 +4861,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-arm64@npm:0.17.19" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/win32-arm64@npm:0.17.6" @@ -4633,6 +4896,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-ia32@npm:0.17.19" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/win32-ia32@npm:0.17.6" @@ -4661,6 +4931,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-x64@npm:0.17.19" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.17.6": version: 0.17.6 resolution: "@esbuild/win32-x64@npm:0.17.6" @@ -4819,6 +5096,13 @@ __metadata: languageName: node linkType: hard +"@fastify/busboy@npm:^2.0.0": + version: 2.1.1 + resolution: "@fastify/busboy@npm:2.1.1" + checksum: 10c0/6f8027a8cba7f8f7b736718b013f5a38c0476eea67034c94a0d3c375e2b114366ad4419e6a6fa7ffc2ef9c6d3e0435d76dd584a7a1cbac23962fda7650b579e3 + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -4875,6 +5159,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@img/sharp-darwin-arm64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-darwin-arm64@npm:0.34.5" @@ -4887,6 +5183,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@img/sharp-darwin-x64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-darwin-x64@npm:0.34.5" @@ -4899,6 +5207,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@img/sharp-libvips-darwin-arm64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-darwin-arm64@npm:1.2.4" @@ -4906,6 +5221,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@img/sharp-libvips-darwin-x64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-darwin-x64@npm:1.2.4" @@ -4913,6 +5235,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-arm64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linux-arm64@npm:1.2.4" @@ -4920,6 +5249,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-arm@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linux-arm@npm:1.2.4" @@ -4941,6 +5277,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-s390x@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linux-s390x@npm:1.2.4" @@ -4948,6 +5291,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-libvips-linux-x64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linux-x64@npm:1.2.4" @@ -4955,6 +5305,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4" @@ -4962,6 +5319,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-libvips-linuxmusl-x64@npm:1.2.4": version: 1.2.4 resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.2.4" @@ -4969,6 +5333,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-arm64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linux-arm64@npm:0.34.5" @@ -4981,6 +5357,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-arm@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linux-arm@npm:0.34.5" @@ -5017,6 +5405,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-s390x@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linux-s390x@npm:0.34.5" @@ -5029,6 +5429,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@img/sharp-linux-x64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linux-x64@npm:0.34.5" @@ -5041,6 +5453,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-linuxmusl-arm64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linuxmusl-arm64@npm:0.34.5" @@ -5053,6 +5477,18 @@ __metadata: languageName: node linkType: hard +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@img/sharp-linuxmusl-x64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-linuxmusl-x64@npm:0.34.5" @@ -5065,6 +5501,15 @@ __metadata: languageName: node linkType: hard +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": "npm:^1.2.0" + conditions: cpu=wasm32 + languageName: node + linkType: hard + "@img/sharp-wasm32@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-wasm32@npm:0.34.5" @@ -5081,6 +5526,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@img/sharp-win32-ia32@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-win32-ia32@npm:0.34.5" @@ -5088,6 +5540,13 @@ __metadata: languageName: node linkType: hard +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@img/sharp-win32-x64@npm:0.34.5": version: 0.34.5 resolution: "@img/sharp-win32-x64@npm:0.34.5" @@ -6470,6 +6929,17 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:^1.52.0": + version: 1.59.1 + resolution: "@playwright/test@npm:1.59.1" + dependencies: + playwright: "npm:1.59.1" + bin: + playwright: cli.js + checksum: 10c0/8c2d94a860d3c254a0b114df2f888ad0a0e9310f45b6059bd5d4da196d965cadf6922267cef0881cfa9784d4bef6d78363d2c2d94caa64be67ff644c41162137 + languageName: node + linkType: hard + "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.3": version: 0.5.15 resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.15" @@ -6507,23 +6977,6 @@ __metadata: languageName: node linkType: hard -"@puppeteer/browsers@npm:2.10.13": - version: 2.10.13 - resolution: "@puppeteer/browsers@npm:2.10.13" - dependencies: - debug: "npm:^4.4.3" - extract-zip: "npm:^2.0.1" - progress: "npm:^2.0.3" - proxy-agent: "npm:^6.5.0" - semver: "npm:^7.7.3" - tar-fs: "npm:^3.1.1" - yargs: "npm:^17.7.2" - bin: - browsers: lib/cjs/main-cli.js - checksum: 10c0/b6e003649f5d5231fa8c3aab32423cd3f89cdacc4cf8cf7e0e85b40c53858b09be4c5daf32bbbe481bdaaee1bc28bc78bfb5c19495de8d8736c9728ec25b7a02 - languageName: node - linkType: hard - "@remix-run/css-bundle@npm:^2.17.2": version: 2.17.2 resolution: "@remix-run/css-bundle@npm:2.17.2" @@ -7154,13 +7607,6 @@ __metadata: languageName: node linkType: hard -"@socket.io/component-emitter@npm:~3.1.0": - version: 3.1.2 - resolution: "@socket.io/component-emitter@npm:3.1.2" - checksum: 10c0/c4242bad66f67e6f7b712733d25b43cbb9e19a595c8701c3ad99cbeb5901555f78b095e24852f862fffb43e96f1d8552e62def885ca82ae1bb05da3668fd87d7 - languageName: node - linkType: hard - "@surma/rollup-plugin-off-main-thread@npm:^2.2.3": version: 2.2.3 resolution: "@surma/rollup-plugin-off-main-thread@npm:2.2.3" @@ -7502,13 +7948,6 @@ __metadata: languageName: node linkType: hard -"@tootallnate/quickjs-emscripten@npm:^0.23.0": - version: 0.23.0 - resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" - checksum: 10c0/2a939b781826fb5fd3edd0f2ec3b321d259d760464cf20611c9877205aaca3ccc0b7304dea68416baa0d568e82cd86b17d29548d1e5139fa3155a4a86a2b4b49 - languageName: node - linkType: hard - "@trysound/sax@npm:0.2.0": version: 0.2.0 resolution: "@trysound/sax@npm:0.2.0" @@ -7692,13 +8131,6 @@ __metadata: languageName: node linkType: hard -"@types/cookie@npm:^0.4.1": - version: 0.4.1 - resolution: "@types/cookie@npm:0.4.1" - checksum: 10c0/f96afe12bd51be1ec61410b0641243d93fa3a494702407c787a4c872b5c8bcd39b224471452055e44a9ce42af1a636e87d161994226eaf4c2be9c30f60418409 - languageName: node - linkType: hard - "@types/cookie@npm:^0.6.0": version: 0.6.0 resolution: "@types/cookie@npm:0.6.0" @@ -7713,15 +8145,6 @@ __metadata: languageName: node linkType: hard -"@types/cors@npm:^2.8.12": - version: 2.8.17 - resolution: "@types/cors@npm:2.8.17" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/457364c28c89f3d9ed34800e1de5c6eaaf344d1bb39af122f013322a50bc606eb2aa6f63de4e41a7a08ba7ef454473926c94a830636723da45bf786df032696d - languageName: node - linkType: hard - "@types/debug@npm:^4.0.0": version: 4.1.12 resolution: "@types/debug@npm:4.1.12" @@ -8044,7 +8467,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=10.0.0": +"@types/node@npm:*": version: 20.14.5 resolution: "@types/node@npm:20.14.5" dependencies: @@ -8305,15 +8728,6 @@ __metadata: languageName: node linkType: hard -"@types/yauzl@npm:^2.9.1": - version: 2.10.3 - resolution: "@types/yauzl@npm:2.10.3" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/f1b7c1b99fef9f2fe7f1985ef7426d0cebe48cd031f1780fcdc7451eec7e31ac97028f16f50121a59bcf53086a1fc8c856fd5b7d3e00970e43d92ae27d6b43dc - languageName: node - linkType: hard - "@typescript-eslint/eslint-plugin@npm:8.46.4, @typescript-eslint/eslint-plugin@npm:^8.46.4": version: 8.46.4 resolution: "@typescript-eslint/eslint-plugin@npm:8.46.4" @@ -9245,6 +9659,13 @@ __metadata: languageName: node linkType: hard +"acorn-walk@npm:8.3.2": + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 10c0/7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52 + languageName: node + linkType: hard + "acorn-walk@npm:^7.0.0, acorn-walk@npm:^7.1.1": version: 7.2.0 resolution: "acorn-walk@npm:7.2.0" @@ -9261,6 +9682,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:8.14.0, acorn@npm:^8.0.0, acorn@npm:^8.14.0": + version: 8.14.0 + resolution: "acorn@npm:8.14.0" + bin: + acorn: bin/acorn + checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7 + languageName: node + linkType: hard + "acorn@npm:^3.1.0": version: 3.3.0 resolution: "acorn@npm:3.3.0" @@ -9288,15 +9718,6 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.14.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" - bin: - acorn: bin/acorn - checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7 - languageName: node - linkType: hard - "acorn@npm:^8.11.0, acorn@npm:^8.12.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.12.0 resolution: "acorn@npm:8.12.0" @@ -9332,7 +9753,7 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:6, agent-base@npm:^6.0.2": +"agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" dependencies: @@ -9341,15 +9762,6 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^4.3.0": - version: 4.3.0 - resolution: "agent-base@npm:4.3.0" - dependencies: - es6-promisify: "npm:^5.0.0" - checksum: 10c0/a618d4e4ca7c0c2023b2664346570773455c501a930718764f65016a8a9eea6d2ab5ba54255589e46de529bab4026a088523dce17f94e34ba385af1f644febe1 - languageName: node - linkType: hard - "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": version: 7.1.1 resolution: "agent-base@npm:7.1.1" @@ -9359,13 +9771,6 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.1.2": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe - languageName: node - linkType: hard - "aggregate-error@npm:^3.0.0": version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" @@ -9526,13 +9931,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^3.0.0": - version: 3.0.1 - resolution: "ansi-regex@npm:3.0.1" - checksum: 10c0/d108a7498b8568caf4a46eea4f1784ab4e0dfb2e3f3938c697dee21443d622d765c958f2b7e2b9f6b9e55e2e2af0584eaa9915d51782b89a841c28e744e7a167 - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -9912,6 +10310,15 @@ __metadata: languageName: node linkType: hard +"as-table@npm:^1.0.36": + version: 1.0.55 + resolution: "as-table@npm:1.0.55" + dependencies: + printable-characters: "npm:^1.0.42" + checksum: 10c0/8c5693a84621fe53c62fcad6b779dc55c5caf4d43b8e67077964baea4a337769ef53f590d7395c806805b4ef1a391b614ba9acdee19b2ca4309ddedaf13894e6 + languageName: node + linkType: hard + "asap@npm:^2.0.0, asap@npm:~2.0.3, asap@npm:~2.0.6": version: 2.0.6 resolution: "asap@npm:2.0.6" @@ -9988,15 +10395,6 @@ __metadata: languageName: node linkType: hard -"ast-types@npm:^0.13.4": - version: 0.13.4 - resolution: "ast-types@npm:0.13.4" - dependencies: - tslib: "npm:^2.0.1" - checksum: 10c0/3a1a409764faa1471601a0ad01b3aa699292991aa9c8a30c7717002cabdf5d98008e7b53ae61f6e058f757fc6ba965e147967a93c13e62692c907d79cfb245f8 - languageName: node - linkType: hard - "ast-types@npm:^0.14.2": version: 0.14.2 resolution: "ast-types@npm:0.14.2" @@ -10107,13 +10505,6 @@ __metadata: languageName: node linkType: hard -"b4a@npm:^1.6.4": - version: 1.6.6 - resolution: "b4a@npm:1.6.6" - checksum: 10c0/56f30277666cb511a15829e38d369b114df7dc8cec4cedc09cc5d685bc0f27cb63c7bcfb58e09a19a1b3c4f2541069ab078b5328542e85d74a39620327709a38 - languageName: node - linkType: hard - "babel-jest@npm:30.2.0": version: 30.2.0 resolution: "babel-jest@npm:30.2.0" @@ -10427,114 +10818,35 @@ __metadata: languageName: node linkType: hard -"babel-walk@npm:3.0.0-canary-5": - version: 3.0.0-canary-5 - resolution: "babel-walk@npm:3.0.0-canary-5" - dependencies: - "@babel/types": "npm:^7.9.6" - checksum: 10c0/17b689874d15c37714cedf6797dd9321dcb998d8e0dda9a8fe8c8bbbf128bbdeb8935cf56e8630d6b67eae76d2a0bc1e470751e082c3b0e30b80d58beafb5e64 - languageName: node - linkType: hard - -"babylon@npm:^6.18.0": - version: 6.18.0 - resolution: "babylon@npm:6.18.0" - bin: - babylon: ./bin/babylon.js - checksum: 10c0/9b1bf946e16782deadb1f5414c1269efa6044eb1e97a3de2051f09a3f2a54e97be3542d4242b28d23de0ef67816f519d38ce1ec3ddb7be306131c39a60e5a667 - languageName: node - linkType: hard - -"bail@npm:^2.0.0": - version: 2.0.2 - resolution: "bail@npm:2.0.2" - checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"bare-events@npm:^2.2.0": - version: 2.4.2 - resolution: "bare-events@npm:2.4.2" - checksum: 10c0/09fa923061f31f815e83504e2ed4a8ba87732a01db40a7fae703dbb7eef7f05d99264b5e186074cbe9698213990d1af564c62cca07a5ff88baea8099ad9a6303 - languageName: node - linkType: hard - -"bare-events@npm:^2.5.4, bare-events@npm:^2.7.0": - version: 2.8.2 - resolution: "bare-events@npm:2.8.2" - peerDependencies: - bare-abort-controller: "*" - peerDependenciesMeta: - bare-abort-controller: - optional: true - checksum: 10c0/53fef240cf2cdcca62f78b6eead90ddb5a59b0929f414b13a63764c2b4f9de98ea8a578d033b04d64bb7b86dfbc402e937984e69950855cc3754c7b63da7db21 - languageName: node - linkType: hard - -"bare-fs@npm:^4.0.1": - version: 4.5.1 - resolution: "bare-fs@npm:4.5.1" +"babel-walk@npm:3.0.0-canary-5": + version: 3.0.0-canary-5 + resolution: "babel-walk@npm:3.0.0-canary-5" dependencies: - bare-events: "npm:^2.5.4" - bare-path: "npm:^3.0.0" - bare-stream: "npm:^2.6.4" - bare-url: "npm:^2.2.2" - fast-fifo: "npm:^1.3.2" - peerDependencies: - bare-buffer: "*" - peerDependenciesMeta: - bare-buffer: - optional: true - checksum: 10c0/ea977c101802dd1fcde80e8847443e584a9f1a8b13f688ddc2658a989cca6762c789db66b0de035a2fcc3d7497dbcb361986383bbbdcf73bb6bb8df1342eef01 - languageName: node - linkType: hard - -"bare-os@npm:^3.0.1": - version: 3.6.2 - resolution: "bare-os@npm:3.6.2" - checksum: 10c0/7d917bc202b7efbb6b78658403fac04ae4e91db98d38cbd24037f896a2b1b4f4571d8cd408d12bed6a4c406d6abaf8d03836eacbcc4c75a0b6974e268574fc5a + "@babel/types": "npm:^7.9.6" + checksum: 10c0/17b689874d15c37714cedf6797dd9321dcb998d8e0dda9a8fe8c8bbbf128bbdeb8935cf56e8630d6b67eae76d2a0bc1e470751e082c3b0e30b80d58beafb5e64 languageName: node linkType: hard -"bare-path@npm:^3.0.0": - version: 3.0.0 - resolution: "bare-path@npm:3.0.0" - dependencies: - bare-os: "npm:^3.0.1" - checksum: 10c0/56a3ca82a9f808f4976cb1188640ac206546ce0ddff582afafc7bd2a6a5b31c3bd16422653aec656eeada2830cfbaa433c6cbf6d6b4d9eba033d5e06d60d9a68 +"babylon@npm:^6.18.0": + version: 6.18.0 + resolution: "babylon@npm:6.18.0" + bin: + babylon: ./bin/babylon.js + checksum: 10c0/9b1bf946e16782deadb1f5414c1269efa6044eb1e97a3de2051f09a3f2a54e97be3542d4242b28d23de0ef67816f519d38ce1ec3ddb7be306131c39a60e5a667 languageName: node linkType: hard -"bare-stream@npm:^2.6.4": - version: 2.7.0 - resolution: "bare-stream@npm:2.7.0" - dependencies: - streamx: "npm:^2.21.0" - peerDependencies: - bare-buffer: "*" - bare-events: "*" - peerDependenciesMeta: - bare-buffer: - optional: true - bare-events: - optional: true - checksum: 10c0/3acd840b7b288dc066226c36446ff605fba2ecce98f1a0ce6aa611b81aabbcd204046a3209bce172373d17eaeaa5b7d35a85649c18ffcb9f2c783242854e99bd +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b languageName: node linkType: hard -"bare-url@npm:^2.2.2": - version: 2.3.2 - resolution: "bare-url@npm:2.3.2" - dependencies: - bare-path: "npm:^3.0.0" - checksum: 10c0/4fd0046314390a54404519d9db20e130ab3a341ef638d040f9603ae3fa0a1d84f6970357d21c8fc64e6163d1f61fd212cb1cfa4cb537dfead99fb06e3c030b15 +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee languageName: node linkType: hard @@ -10545,13 +10857,6 @@ __metadata: languageName: node linkType: hard -"base64id@npm:2.0.0, base64id@npm:~2.0.0": - version: 2.0.0 - resolution: "base64id@npm:2.0.0" - checksum: 10c0/6919efd237ed44b9988cbfc33eca6f173a10e810ce50292b271a1a421aac7748ef232a64d1e6032b08f19aae48dce6ee8f66c5ae2c9e5066c82b884861d4d453 - languageName: node - linkType: hard - "baseline-browser-mapping@npm:^2.8.25": version: 2.8.25 resolution: "baseline-browser-mapping@npm:2.8.25" @@ -10570,13 +10875,6 @@ __metadata: languageName: node linkType: hard -"basic-ftp@npm:^5.0.2": - version: 5.0.5 - resolution: "basic-ftp@npm:5.0.5" - checksum: 10c0/be983a3997749856da87b839ffce6b8ed6c7dbf91ea991d5c980d8add275f9f2926c19f80217ac3e7f353815be879371d636407ca72b038cea8cab30e53928a6 - languageName: node - linkType: hard - "batch@npm:0.6.1": version: 0.6.1 resolution: "batch@npm:0.6.1" @@ -10641,6 +10939,13 @@ __metadata: languageName: node linkType: hard +"blake3-wasm@npm:2.1.5": + version: 2.1.5 + resolution: "blake3-wasm@npm:2.1.5" + checksum: 10c0/5dc729d8e3a9d1d7ab016b36cdda264a327ada0239716df48435163e11d2bf6df25d6e421655a1f52649098ae49555268a654729b7d02768f77c571ab37ef814 + languageName: node + linkType: hard + "bluebird@npm:^3.7.2": version: 3.7.2 resolution: "bluebird@npm:3.7.2" @@ -11035,28 +11340,6 @@ __metadata: languageName: node linkType: hard -"browserstack-local@npm:^1.3.7": - version: 1.5.5 - resolution: "browserstack-local@npm:1.5.5" - dependencies: - agent-base: "npm:^6.0.2" - https-proxy-agent: "npm:^5.0.1" - is-running: "npm:^2.1.0" - ps-tree: "npm:=1.2.0" - temp-fs: "npm:^0.9.9" - checksum: 10c0/329b5a68129d17f2b9a37a7b2788847fe25cf59378e6e8c966f387124a5ab651a2c57aa20183a6a5399d93db4545797706c006d24f29723d9f6ea100b8e1b5bc - languageName: node - linkType: hard - -"browserstack@npm:~1.5.1": - version: 1.5.3 - resolution: "browserstack@npm:1.5.3" - dependencies: - https-proxy-agent: "npm:^2.2.1" - checksum: 10c0/118704796f0a83aab4d23c7aa506a80cb4cd8338ddafe1fb184cb664c6d9c5527d4748df1529deeeffce53cd6f1e123f329c328ff8a4443ebc6698255a4b3c75 - languageName: node - linkType: hard - "bs-logger@npm:^0.2.6": version: 0.2.6 resolution: "bs-logger@npm:0.2.6" @@ -11075,13 +11358,6 @@ __metadata: languageName: node linkType: hard -"buffer-crc32@npm:~0.2.3": - version: 0.2.13 - resolution: "buffer-crc32@npm:0.2.13" - checksum: 10c0/cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150 - languageName: node - linkType: hard - "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -11484,7 +11760,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.1, chalk@npm:^2.1.0, chalk@npm:^2.3.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.3.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -11625,18 +11901,6 @@ __metadata: languageName: node linkType: hard -"chromium-bidi@npm:10.5.1": - version: 10.5.1 - resolution: "chromium-bidi@npm:10.5.1" - dependencies: - mitt: "npm:^3.0.1" - zod: "npm:^3.24.1" - peerDependencies: - devtools-protocol: "*" - checksum: 10c0/094fca13c1361a1cd6b951cf21f7d68f9cb0d1a5aee31b55f0ace5bb144c4606f2cff5625a6328146e5c326f3baaae45a2cc1e11ca47cb9ad36aaf35107647fe - languageName: node - linkType: hard - "ci-info@npm:^3.2.0": version: 3.9.0 resolution: "ci-info@npm:3.9.0" @@ -11884,13 +12148,33 @@ __metadata: languageName: node linkType: hard -"color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: "npm:^1.0.0" + simple-swizzle: "npm:^0.2.2" + checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404 + languageName: node + linkType: hard + +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: "npm:^2.0.1" + color-string: "npm:^1.9.0" + checksum: 10c0/7fbe7cfb811054c808349de19fb380252e5e34e61d7d168ec3353e9e9aacb1802674bddc657682e4e9730c2786592a4de6f8283e7e0d3870b829bb0b7b2f6118 + languageName: node + linkType: hard + "colord@npm:^2.9.1": version: 2.9.3 resolution: "colord@npm:2.9.3" @@ -12098,18 +12382,6 @@ __metadata: languageName: node linkType: hard -"connect@npm:^3.7.0": - version: 3.7.0 - resolution: "connect@npm:3.7.0" - dependencies: - debug: "npm:2.6.9" - finalhandler: "npm:1.1.2" - parseurl: "npm:~1.3.3" - utils-merge: "npm:1.0.1" - checksum: 10c0/f120c6116bb16a0a7d2703c0b4a0cd7ed787dc5ec91978097bf62aa967289020a9f41a9cd3c3276a7b92aaa36f382d2cd35fed7138fd466a55c8e9fdbed11ca8 - languageName: node - linkType: hard - "consola@npm:^3.2.3": version: 3.4.2 resolution: "consola@npm:3.4.2" @@ -12185,7 +12457,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0, convert-source-map@npm:^1.8.0": +"convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b @@ -12258,13 +12530,6 @@ __metadata: languageName: node linkType: hard -"cookie@npm:~0.4.1": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: 10c0/beab41fbd7c20175e3a2799ba948c1dcc71ef69f23fe14eeeff59fc09f50c517b0f77098db87dbb4c55da802f9d86ee86cdc1cd3efd87760341551838d53fca2 - languageName: node - linkType: hard - "cookiejar@npm:^2.1.4": version: 2.1.4 resolution: "cookiejar@npm:2.1.4" @@ -12330,7 +12595,7 @@ __metadata: languageName: node linkType: hard -"cors@npm:2.8.5, cors@npm:~2.8.5": +"cors@npm:2.8.5": version: 2.8.5 resolution: "cors@npm:2.8.5" dependencies: @@ -12383,23 +12648,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^9.0.0": - version: 9.0.0 - resolution: "cosmiconfig@npm:9.0.0" - dependencies: - env-paths: "npm:^2.2.1" - import-fresh: "npm:^3.3.0" - js-yaml: "npm:^4.1.0" - parse-json: "npm:^5.2.0" - peerDependencies: - typescript: ">=4.9.5" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/1c1703be4f02a250b1d6ca3267e408ce16abfe8364193891afc94c2d5c060b69611fdc8d97af74b7e6d5d1aac0ab2fb94d6b079573146bc2d756c2484ce5f0ee - languageName: node - linkType: hard - "create-ecdh@npm:^4.0.0": version: 4.0.4 resolution: "create-ecdh@npm:4.0.4" @@ -12776,13 +13024,6 @@ __metadata: languageName: node linkType: hard -"custom-event@npm:~1.0.0": - version: 1.0.1 - resolution: "custom-event@npm:1.0.1" - checksum: 10c0/86cd8497328b1e17dcda894c8df34a73b7a99f915123940d39b33c709482b2d3a2e689cd5e79e4775eb4167227689f57a2ae2f99a3f0bc9c54c0ac1b06853bd5 - languageName: node - linkType: hard - "damerau-levenshtein@npm:^1.0.8": version: 1.0.8 resolution: "damerau-levenshtein@npm:1.0.8" @@ -12797,6 +13038,13 @@ __metadata: languageName: node linkType: hard +"data-uri-to-buffer@npm:^2.0.0": + version: 2.0.2 + resolution: "data-uri-to-buffer@npm:2.0.2" + checksum: 10c0/341b6191ed65fa453e97a6d44db06082121ebc2ef3e6e096dfb6a1ebbc75e8be39d4199a5b4dba0f0efc43f2a3b2bcc276d85cf1407eba880eb09ebf17c3c31e + languageName: node + linkType: hard + "data-uri-to-buffer@npm:^3.0.1": version: 3.0.1 resolution: "data-uri-to-buffer@npm:3.0.1" @@ -12804,13 +13052,6 @@ __metadata: languageName: node linkType: hard -"data-uri-to-buffer@npm:^6.0.2": - version: 6.0.2 - resolution: "data-uri-to-buffer@npm:6.0.2" - checksum: 10c0/f76922bf895b3d7d443059ff278c9cc5efc89d70b8b80cd9de0aa79b3adc6d7a17948eefb8692e30398c43635f70ece1673d6085cc9eba2878dbc6c6da5292ac - languageName: node - linkType: hard - "data-urls@npm:^2.0.0": version: 2.0.0 resolution: "data-urls@npm:2.0.0" @@ -12888,13 +13129,6 @@ __metadata: languageName: node linkType: hard -"date-format@npm:^4.0.14": - version: 4.0.14 - resolution: "date-format@npm:4.0.14" - checksum: 10c0/1c67a4d77c677bb880328c81d81f5b9ed7fbf672bdaff74e5a0f7314b21188f3a829b06acf120c70cc1df876a7724e3e5c23d511e86d64656a3035a76ac3930b - languageName: node - linkType: hard - "de-indent@npm:^1.0.2": version: 1.0.2 resolution: "de-indent@npm:1.0.2" @@ -12911,7 +13145,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:~4.3.1, debug@npm:~4.3.2, debug@npm:~4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5": version: 4.3.5 resolution: "debug@npm:4.3.5" dependencies: @@ -12923,7 +13157,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.1.0, debug@npm:^3.2.7": +"debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: @@ -13117,14 +13351,10 @@ __metadata: languageName: node linkType: hard -"degenerator@npm:^5.0.0": - version: 5.0.1 - resolution: "degenerator@npm:5.0.1" - dependencies: - ast-types: "npm:^0.13.4" - escodegen: "npm:^2.1.0" - esprima: "npm:^4.0.1" - checksum: 10c0/e48d8a651edeb512a648711a09afec269aac6de97d442a4bb9cf121a66877e0eec11b9727100a10252335c0666ae1c84a8bc1e3a3f47788742c975064d2c7b1c +"defu@npm:^6.1.4": + version: 6.1.6 + resolution: "defu@npm:6.1.6" + checksum: 10c0/6755a914d4d1b40346d582cadf3af0c4efb1b89c462631f4c8a20c933da88d5da674344dd0856426d611d5fc0c65a3ffa82388519127b06f1a688dc103ddf5ba languageName: node linkType: hard @@ -13300,13 +13530,6 @@ __metadata: languageName: node linkType: hard -"devtools-protocol@npm:0.0.1521046": - version: 0.0.1521046 - resolution: "devtools-protocol@npm:0.0.1521046" - checksum: 10c0/ba4b83a94e2b9c26772b22a8f6029ff296976a72db8e4567c9076393fccc39a452f6c0530869eebe2e1ad483db0e6233cd6b7b723ce466a05660c758f5e06db0 - languageName: node - linkType: hard - "dezalgo@npm:^1.0.4": version: 1.0.4 resolution: "dezalgo@npm:1.0.4" @@ -13317,13 +13540,6 @@ __metadata: languageName: node linkType: hard -"di@npm:^0.0.1": - version: 0.0.1 - resolution: "di@npm:0.0.1" - checksum: 10c0/fbca4cc93e8c493d50f82df3a9ecaa5d8b2935674aabddeb8f68db3ab03c942c201f9c3d920de094407392ee6f488eac16b96f500c0ea6b408634864b7b939d1 - languageName: node - linkType: hard - "didyoumean@npm:^1.2.2": version: 1.2.2 resolution: "didyoumean@npm:1.2.2" @@ -13436,18 +13652,6 @@ __metadata: languageName: node linkType: hard -"dom-serialize@npm:^2.2.1": - version: 2.2.1 - resolution: "dom-serialize@npm:2.2.1" - dependencies: - custom-event: "npm:~1.0.0" - ent: "npm:~2.2.0" - extend: "npm:^3.0.0" - void-elements: "npm:^2.0.0" - checksum: 10c0/ceb6e62b73c658986ca4c9b8b2fae358d8ae914eb06712d137da595a327c3bbca45a762f412a6d181f892ce5e3cffb855c2db2b64c53ad0534b2a0ad8e65b05e - languageName: node - linkType: hard - "dom-serializer@npm:0": version: 0.2.2 resolution: "dom-serializer@npm:0.2.2" @@ -13610,7 +13814,7 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:^0.1.2, duplexer@npm:~0.1.1": +"duplexer@npm:^0.1.2": version: 0.1.2 resolution: "duplexer@npm:0.1.2" checksum: 10c0/c57bcd4bdf7e623abab2df43a7b5b23d18152154529d166c1e0da6bee341d84c432d157d7e97b32fecb1bf3a8b8857dd85ed81a915789f550637ed25b8e64fc2 @@ -13764,31 +13968,6 @@ __metadata: languageName: node linkType: hard -"engine.io-parser@npm:~5.2.1": - version: 5.2.2 - resolution: "engine.io-parser@npm:5.2.2" - checksum: 10c0/38e71a92ed75e2873d4d9cfab7f889e4a3cfc939b689abd1045e1b2ef9f1a50d0350a2bef69f33d313c1aa626232702da5a9043a1038d76f5ecc0be440c648ab - languageName: node - linkType: hard - -"engine.io@npm:~6.5.2": - version: 6.5.5 - resolution: "engine.io@npm:6.5.5" - dependencies: - "@types/cookie": "npm:^0.4.1" - "@types/cors": "npm:^2.8.12" - "@types/node": "npm:>=10.0.0" - accepts: "npm:~1.3.4" - base64id: "npm:2.0.0" - cookie: "npm:~0.4.1" - cors: "npm:~2.8.5" - debug: "npm:~4.3.1" - engine.io-parser: "npm:~5.2.1" - ws: "npm:~8.17.1" - checksum: 10c0/b0994134917c5d3649fd7aea283492eaf092131e572a8d379c7c9081548b42cff756730b4641edd0d1598148dd3be253c4d634cea2ba5c59622d175d9e567469 - languageName: node - linkType: hard - "enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.17.0, enhanced-resolve@npm:^5.7.0": version: 5.17.0 resolution: "enhanced-resolve@npm:5.17.0" @@ -13819,13 +13998,6 @@ __metadata: languageName: node linkType: hard -"ent@npm:~2.2.0": - version: 2.2.0 - resolution: "ent@npm:2.2.0" - checksum: 10c0/d12c504d93afb8b22551323f78f60f0a2660289cf2de2210bdd2fdb07ac204956da23510a7711bf48079aa0aa726e21724224de6c6289120ddcf27652b30cb17 - languageName: node - linkType: hard - "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" @@ -13840,7 +14012,7 @@ __metadata: languageName: node linkType: hard -"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": +"env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 @@ -14173,22 +14345,6 @@ __metadata: languageName: node linkType: hard -"es6-promise@npm:^4.0.3": - version: 4.2.8 - resolution: "es6-promise@npm:4.2.8" - checksum: 10c0/2373d9c5e9a93bdd9f9ed32ff5cb6dd3dd785368d1c21e9bbbfd07d16345b3774ae260f2bd24c8f836a6903f432b4151e7816a7fa8891ccb4e1a55a028ec42c3 - languageName: node - linkType: hard - -"es6-promisify@npm:^5.0.0": - version: 5.0.0 - resolution: "es6-promisify@npm:5.0.0" - dependencies: - es6-promise: "npm:^4.0.3" - checksum: 10c0/23284c6a733cbf7842ec98f41eac742c9f288a78753c4fe46652bae826446ced7615b9e8a5c5f121a08812b1cd478ea58630f3e1c3d70835bd5dcd69c7cd75c9 - languageName: node - linkType: hard - "esbuild-plugins-node-modules-polyfill@npm:^1.6.0": version: 1.6.8 resolution: "esbuild-plugins-node-modules-polyfill@npm:1.6.8" @@ -14202,6 +14358,83 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:0.17.19": + version: 0.17.19 + resolution: "esbuild@npm:0.17.19" + dependencies: + "@esbuild/android-arm": "npm:0.17.19" + "@esbuild/android-arm64": "npm:0.17.19" + "@esbuild/android-x64": "npm:0.17.19" + "@esbuild/darwin-arm64": "npm:0.17.19" + "@esbuild/darwin-x64": "npm:0.17.19" + "@esbuild/freebsd-arm64": "npm:0.17.19" + "@esbuild/freebsd-x64": "npm:0.17.19" + "@esbuild/linux-arm": "npm:0.17.19" + "@esbuild/linux-arm64": "npm:0.17.19" + "@esbuild/linux-ia32": "npm:0.17.19" + "@esbuild/linux-loong64": "npm:0.17.19" + "@esbuild/linux-mips64el": "npm:0.17.19" + "@esbuild/linux-ppc64": "npm:0.17.19" + "@esbuild/linux-riscv64": "npm:0.17.19" + "@esbuild/linux-s390x": "npm:0.17.19" + "@esbuild/linux-x64": "npm:0.17.19" + "@esbuild/netbsd-x64": "npm:0.17.19" + "@esbuild/openbsd-x64": "npm:0.17.19" + "@esbuild/sunos-x64": "npm:0.17.19" + "@esbuild/win32-arm64": "npm:0.17.19" + "@esbuild/win32-ia32": "npm:0.17.19" + "@esbuild/win32-x64": "npm:0.17.19" + dependenciesMeta: + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/c7ac14bfaaebe4745d5d18347b4f6854fd1140acb9389e88dbfa5c20d4e2122451d9647d5498920470a880a605d6e5502b5c2102da6c282b01f129ddd49d2874 + languageName: node + linkType: hard + "esbuild@npm:0.17.6": version: 0.17.6 resolution: "esbuild@npm:0.17.6" @@ -14589,7 +14822,7 @@ __metadata: languageName: node linkType: hard -"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0": +"escodegen@npm:^2.0.0": version: 2.1.0 resolution: "escodegen@npm:2.1.0" dependencies: @@ -15382,6 +15615,13 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^0.6.1": + version: 0.6.1 + resolution: "estree-walker@npm:0.6.1" + checksum: 10c0/6dabc855faa04a1ffb17b6a9121b6008ba75ab5a163ad9dc3d7fca05cfda374c5f5e91418d783496620ca75e99a73c40874d8b75f23b4117508cc8bde78e7b41 + languageName: node + linkType: hard + "estree-walker@npm:^1.0.1": version: 1.0.1 resolution: "estree-walker@npm:1.0.1" @@ -15429,21 +15669,6 @@ __metadata: languageName: node linkType: hard -"event-stream@npm:=3.3.4": - version: 3.3.4 - resolution: "event-stream@npm:3.3.4" - dependencies: - duplexer: "npm:~0.1.1" - from: "npm:~0" - map-stream: "npm:~0.1.0" - pause-stream: "npm:0.0.11" - split: "npm:0.3" - stream-combiner: "npm:~0.0.4" - through: "npm:~2.3.1" - checksum: 10c0/c3ec4e1efc27ab3e73a98923f0a2fa9a19051b87068fea2f3d53d2e4e8c5cfdadf8c8a115b17f3d90b16a46432d396bad91b6e8d0cceb3e449be717a03b75209 - languageName: node - linkType: hard - "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1" @@ -15458,15 +15683,6 @@ __metadata: languageName: node linkType: hard -"events-universal@npm:^1.0.0": - version: 1.0.1 - resolution: "events-universal@npm:1.0.1" - dependencies: - bare-events: "npm:^2.7.0" - checksum: 10c0/a1d9a5e9f95843650f8ec240dd1221454c110189a9813f32cdf7185759b43f1f964367ac7dca4ebc69150b59043f2d77c7e122b0d03abf7c25477ea5494785a5 - languageName: node - linkType: hard - "events@npm:^3.0.0, events@npm:^3.2.0": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -15676,6 +15892,13 @@ __metadata: languageName: node linkType: hard +"exsolve@npm:^1.0.1": + version: 1.0.8 + resolution: "exsolve@npm:1.0.8" + checksum: 10c0/65e44ae05bd4a4a5d87cfdbbd6b8f24389282cf9f85fa5feb17ca87ad3f354877e6af4cd99e02fc29044174891f82d1d68c77f69234410eb8f163530e6278c67 + languageName: node + linkType: hard + "extend@npm:^3.0.0": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -15683,23 +15906,6 @@ __metadata: languageName: node linkType: hard -"extract-zip@npm:^2.0.1": - version: 2.0.1 - resolution: "extract-zip@npm:2.0.1" - dependencies: - "@types/yauzl": "npm:^2.9.1" - debug: "npm:^4.1.1" - get-stream: "npm:^5.1.0" - yauzl: "npm:^2.10.0" - dependenciesMeta: - "@types/yauzl": - optional: true - bin: - extract-zip: cli.js - checksum: 10c0/9afbd46854aa15a857ae0341a63a92743a7b89c8779102c3b4ffc207516b2019337353962309f85c66ee3d9092202a83cdc26dbf449a11981272038443974aee - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -15714,13 +15920,6 @@ __metadata: languageName: node linkType: hard -"fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2": - version: 1.3.2 - resolution: "fast-fifo@npm:1.3.2" - checksum: 10c0/d53f6f786875e8b0529f784b59b4b05d4b5c31c651710496440006a398389a579c8dbcd2081311478b5bf77f4b0b21de69109c5a4eabea9d8e8783d1eb864e4c - languageName: node - linkType: hard - "fast-glob@npm:3.3.1": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" @@ -15811,15 +16010,6 @@ __metadata: languageName: node linkType: hard -"fd-slicer@npm:~1.1.0": - version: 1.1.0 - resolution: "fd-slicer@npm:1.1.0" - dependencies: - pend: "npm:~1.2.0" - checksum: 10c0/304dd70270298e3ffe3bcc05e6f7ade2511acc278bc52d025f8918b48b6aa3b77f10361bddfadfe2a28163f7af7adbdce96f4d22c31b2f648ba2901f0c5fc20e - languageName: node - linkType: hard - "fdir@npm:^6.2.0, fdir@npm:^6.5.0": version: 6.5.0 resolution: "fdir@npm:6.5.0" @@ -15907,27 +16097,12 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 - languageName: node - linkType: hard - -"finalhandler@npm:1.1.2": - version: 1.1.2 - resolution: "finalhandler@npm:1.1.2" - dependencies: - debug: "npm:2.6.9" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - on-finished: "npm:~2.3.0" - parseurl: "npm:~1.3.3" - statuses: "npm:~1.5.0" - unpipe: "npm:~1.0.0" - checksum: 10c0/6a96e1f5caab085628c11d9fdceb82ba608d5e426c6913d4d918409baa271037a47f28fbba73279e8ad614f0b8fa71ea791d265e408d760793829edd8c2f4584 +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 languageName: node linkType: hard @@ -16045,7 +16220,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.2.7, flatted@npm:^3.2.9": +"flatted@npm:^3.2.9": version: 3.3.1 resolution: "flatted@npm:3.3.1" checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf @@ -16245,13 +16420,6 @@ __metadata: languageName: node linkType: hard -"from@npm:~0": - version: 0.1.7 - resolution: "from@npm:0.1.7" - checksum: 10c0/3aab5aea8fe8e1f12a5dee7f390d46a93431ce691b6222dcd5701c5d34378e51ca59b44967da1105a0f90fcdf5d7629d963d51e7ccd79827d19693bdcfb688d4 - languageName: node - linkType: hard - "fromentries@npm:^1.2.0": version: 1.3.2 resolution: "fromentries@npm:1.3.2" @@ -16277,17 +16445,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.2.0": - version: 11.2.0 - resolution: "fs-extra@npm:11.2.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 - languageName: node - linkType: hard - "fs-extra@npm:^8.1.0": version: 8.1.0 resolution: "fs-extra@npm:8.1.0" @@ -16350,6 +16507,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@npm:^2.3.2, fsevents@npm:^2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -16360,6 +16527,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin": + version: 2.3.2 + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A^2.3.3#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" @@ -16518,12 +16694,13 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^5.1.0": - version: 5.2.0 - resolution: "get-stream@npm:5.2.0" +"get-source@npm:^2.0.12": + version: 2.0.12 + resolution: "get-source@npm:2.0.12" dependencies: - pump: "npm:^3.0.0" - checksum: 10c0/43797ffd815fbb26685bf188c8cfebecb8af87b3925091dd7b9a9c915993293d78e3c9e1bce125928ff92f2d0796f3889b92b5ec6d58d1041b574682132e0a80 + data-uri-to-buffer: "npm:^2.0.0" + source-map: "npm:^0.6.1" + checksum: 10c0/b1db46d28902344fd9407e1f0ed0b8f3a85cb4650f85ba8cee9c0b422fc75118172f12f735706e2c6e034617b13a2fbc5266e7fab617ecb184f0cee074b9dd3e languageName: node linkType: hard @@ -16574,18 +16751,6 @@ __metadata: languageName: node linkType: hard -"get-uri@npm:^6.0.1": - version: 6.0.3 - resolution: "get-uri@npm:6.0.3" - dependencies: - basic-ftp: "npm:^5.0.2" - data-uri-to-buffer: "npm:^6.0.2" - debug: "npm:^4.3.4" - fs-extra: "npm:^11.2.0" - checksum: 10c0/8d801c462cd5b9c171d4d9e5f17afce3d9ebfbbfb006a88e3e768ce0071a8e2e59ee1ce822915fc43b9d6b83fde7b8d1c9648330ae89778fa41ad774df8ee0ac - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -16604,7 +16769,7 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": +"glob-to-regexp@npm:0.4.1, glob-to-regexp@npm:^0.4.1": version: 0.4.1 resolution: "glob-to-regexp@npm:0.4.1" checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 @@ -16658,7 +16823,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.5, glob@npm:^7.1.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.0": +"glob@npm:^7.1.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -16785,7 +16950,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -17031,13 +17196,6 @@ __metadata: languageName: node linkType: hard -"hat@npm:^0.0.3": - version: 0.0.3 - resolution: "hat@npm:0.0.3" - checksum: 10c0/9d502b26b612ed3e66491296873119574e61a4ef99dfc5501f7bf86115fde35d0f76b1167257c8224c88092eda04e40feda805ad5b86c3b90203f4e15fd99f53 - languageName: node - linkType: hard - "he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" @@ -17246,7 +17404,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.1": +"http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" dependencies: @@ -17288,17 +17446,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^2.2.1": - version: 2.2.4 - resolution: "https-proxy-agent@npm:2.2.4" - dependencies: - agent-base: "npm:^4.3.0" - debug: "npm:^3.1.0" - checksum: 10c0/4bdde8fcd9ea0adc4a77282de2b4f9e27955e0441425af0f27f0fe01006946b80eaee6749e08e838d350c06ed2ebd5d11347d3beb88c45eacb0667e27276cdad - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": +"https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" dependencies: @@ -17318,16 +17466,6 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.6": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac - languageName: node - linkType: hard - "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" @@ -17552,13 +17690,6 @@ __metadata: languageName: node linkType: hard -"ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 - languageName: node - linkType: hard - "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -17638,6 +17769,13 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.3.1": + version: 0.3.4 + resolution: "is-arrayish@npm:0.3.4" + checksum: 10c0/1fa672a2f0bedb74154440310f616c0b6e53a95cf0625522ae050f06626d1cabd1a3d8085c882dc45c61ad0e7df2529aff122810b3b4a552880bf170d6df94e0 + languageName: node + linkType: hard + "is-async-function@npm:^2.0.0": version: 2.0.0 resolution: "is-async-function@npm:2.0.0" @@ -18122,13 +18260,6 @@ __metadata: languageName: node linkType: hard -"is-running@npm:^2.1.0": - version: 2.1.0 - resolution: "is-running@npm:2.1.0" - checksum: 10c0/3caf610508336e7b4d3f63323138ea479f38b7f74c9318254c6c999e06cc9f9bc23727183bb103a3564d517c0b3b9ac057768b3a681c6a63a246089c3ac01c8b - languageName: node - linkType: hard - "is-set@npm:^2.0.3": version: 2.0.3 resolution: "is-set@npm:2.0.3" @@ -18297,13 +18428,6 @@ __metadata: languageName: node linkType: hard -"isbinaryfile@npm:^4.0.8": - version: 4.0.10 - resolution: "isbinaryfile@npm:4.0.10" - checksum: 10c0/0703d8cfeb69ed79e6d173120f327450011a066755150a6bbf97ffecec1069a5f2092777868315b21359098c84b54984871cad1abce877ad9141fb2caf3dcabf - languageName: node - linkType: hard - "isbot@npm:^5.1.32": version: 5.1.32 resolution: "isbot@npm:5.1.32" @@ -19549,13 +19673,6 @@ __metadata: languageName: node linkType: hard -"js-string-escape@npm:^1.0.0": - version: 1.0.1 - resolution: "js-string-escape@npm:1.0.1" - checksum: 10c0/2c33b9ff1ba6b84681c51ca0997e7d5a1639813c95d5b61cb7ad47e55cc28fa4a0b1935c3d218710d8e6bcee5d0cd8c44755231e3a4e45fc604534d9595a3628 - languageName: node - linkType: hard - "js-stringify@npm:^1.0.1, js-stringify@npm:^1.0.2": version: 1.0.2 resolution: "js-stringify@npm:1.0.2" @@ -19858,145 +19975,6 @@ __metadata: languageName: node linkType: hard -"karma-browserify@npm:^8.1.0": - version: 8.1.0 - resolution: "karma-browserify@npm:8.1.0" - dependencies: - convert-source-map: "npm:^1.8.0" - hat: "npm:^0.0.3" - js-string-escape: "npm:^1.0.0" - lodash: "npm:^4.17.21" - minimatch: "npm:^3.0.0" - os-shim: "npm:^0.1.3" - peerDependencies: - browserify: ">=10 <18" - karma: ">=4.3.0" - watchify: ">=3 <5" - checksum: 10c0/2de3e52a8038a9768b9d69cffcad64d9ab212df8f2c095504261a856a71d08abde022967e55a8d50ca2062de35675f4ae9be5831c79da019c0fd053a1dde7c2b - languageName: node - linkType: hard - -"karma-browserstack-launcher@npm:^1.6.0": - version: 1.6.0 - resolution: "karma-browserstack-launcher@npm:1.6.0" - dependencies: - browserstack: "npm:~1.5.1" - browserstack-local: "npm:^1.3.7" - q: "npm:~1.5.0" - peerDependencies: - karma: ">=0.9" - checksum: 10c0/d3e326732157000710d3c7a3751e82611ba7b3fdb25cdc86e059a6441855446273094887854e67a68ded654d7a033142fa2355b457e416a074c17fc16795e2c9 - languageName: node - linkType: hard - -"karma-chai@npm:^0.1.0": - version: 0.1.0 - resolution: "karma-chai@npm:0.1.0" - peerDependencies: - chai: "*" - karma: ">=0.10.9" - checksum: 10c0/f4a8ff07d34523830a7ddfa220121ee9be32fbc44303ead9b064698acd60a0ab4db35e911a8ce74a96af8739b8ba34688670bf63f3054adf43bd45dc256cdcc2 - languageName: node - linkType: hard - -"karma-chrome-launcher@npm:^3.2.0": - version: 3.2.0 - resolution: "karma-chrome-launcher@npm:3.2.0" - dependencies: - which: "npm:^1.2.1" - checksum: 10c0/0cec1ae7d922110dc29cee36389d597157c82f019c8917259f9fa93d1f5ee8e19141c2eb74bfe30797cdb3adbc51a6b65fd18a9ebc1527c725c4acf62cd46d04 - languageName: node - linkType: hard - -"karma-cli@npm:^2.0.0": - version: 2.0.0 - resolution: "karma-cli@npm:2.0.0" - dependencies: - resolve: "npm:^1.3.3" - bin: - karma: ./bin/karma - checksum: 10c0/4066c22d172d7cbce6be7de5529aa2200203ba958e47359cfe0c45dc29c5970dd3dc1863aef0f3fb17c6b21a5ba938959b17da606241ed844a788a283f94282b - languageName: node - linkType: hard - -"karma-mocha-reporter@npm:^2.2.5": - version: 2.2.5 - resolution: "karma-mocha-reporter@npm:2.2.5" - dependencies: - chalk: "npm:^2.1.0" - log-symbols: "npm:^2.1.0" - strip-ansi: "npm:^4.0.0" - peerDependencies: - karma: ">=0.13" - checksum: 10c0/5a26ea58fb683a6d6a7f8b6f6e51f8678432adfa6425356fb125c9e8dba4489061385b819dfd19e943ffe8f3e0f86a529386b7793d3065cd59d4756517023aba - languageName: node - linkType: hard - -"karma-mocha@npm:^2.0.1": - version: 2.0.1 - resolution: "karma-mocha@npm:2.0.1" - dependencies: - minimist: "npm:^1.2.3" - checksum: 10c0/99ef62d863f6bf8cb11df0f4a9d47615369a0ce8a937d9a0cd7fb83fdbb0ef7420c7ea396de514be48500fac1563a00ab964b7d1adc4ee3f5a875ebf07eb012d - languageName: node - linkType: hard - -"karma-sourcemap-loader@npm:^0.4.0": - version: 0.4.0 - resolution: "karma-sourcemap-loader@npm:0.4.0" - dependencies: - graceful-fs: "npm:^4.2.10" - checksum: 10c0/8f77516330bc78d7c4d22469bdfd96b82acf7a285e2c19b8f30ae9d9bb21c7d817b0c32b9e5ea6ae002b16365e124afea121910c089c641320ce5595cafaadac - languageName: node - linkType: hard - -"karma-webpack@npm:5.0.1": - version: 5.0.1 - resolution: "karma-webpack@npm:5.0.1" - dependencies: - glob: "npm:^7.1.3" - minimatch: "npm:^9.0.3" - webpack-merge: "npm:^4.1.5" - peerDependencies: - webpack: ^5.0.0 - checksum: 10c0/ef7208a6b2746819693c654d6da4a1c7794edb72690006181e1c2897ff8415644e6745ca46bdf170e30c2b82d4b9f16284af5e71fcae026b32de0a08adb14c7d - languageName: node - linkType: hard - -"karma@npm:^6.4.4": - version: 6.4.4 - resolution: "karma@npm:6.4.4" - dependencies: - "@colors/colors": "npm:1.5.0" - body-parser: "npm:^1.19.0" - braces: "npm:^3.0.2" - chokidar: "npm:^3.5.1" - connect: "npm:^3.7.0" - di: "npm:^0.0.1" - dom-serialize: "npm:^2.2.1" - glob: "npm:^7.1.7" - graceful-fs: "npm:^4.2.6" - http-proxy: "npm:^1.18.1" - isbinaryfile: "npm:^4.0.8" - lodash: "npm:^4.17.21" - log4js: "npm:^6.4.1" - mime: "npm:^2.5.2" - minimatch: "npm:^3.0.4" - mkdirp: "npm:^0.5.5" - qjobs: "npm:^1.2.0" - range-parser: "npm:^1.2.1" - rimraf: "npm:^3.0.2" - socket.io: "npm:^4.7.2" - source-map: "npm:^0.6.1" - tmp: "npm:^0.2.1" - ua-parser-js: "npm:^0.7.30" - yargs: "npm:^16.1.1" - bin: - karma: bin/karma - checksum: 10c0/1658c4b7396c0edf6f048289182e075b561902e02992e1a3eb72f56f67090ff0c7ad7c91ab099e88a790c60f9500c5a6f974d75f1769e3ea2dfccda52876ec0b - languageName: node - linkType: hard - "keyv@npm:^4.5.3, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -20426,15 +20404,6 @@ __metadata: languageName: node linkType: hard -"log-symbols@npm:^2.1.0": - version: 2.2.0 - resolution: "log-symbols@npm:2.2.0" - dependencies: - chalk: "npm:^2.0.1" - checksum: 10c0/574eb4205f54f0605021aa67ebb372c30ca64e8ddd439efeb8507af83c776dce789e83614e80059014d9e48dcc94c4b60cef2e85f0dc944eea27c799cec62353 - languageName: node - linkType: hard - "log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" @@ -20445,19 +20414,6 @@ __metadata: languageName: node linkType: hard -"log4js@npm:^6.4.1": - version: 6.9.1 - resolution: "log4js@npm:6.9.1" - dependencies: - date-format: "npm:^4.0.14" - debug: "npm:^4.3.4" - flatted: "npm:^3.2.7" - rfdc: "npm:^1.3.0" - streamroller: "npm:^3.1.5" - checksum: 10c0/05846e48f72d662800c8189bd178c42b4aa2f0c574cfc90a1942cf90b76f621c44019e26796c8fd88da1b6f0fe8272cba607cbaad6ae6ede50a7a096b58197ea - languageName: node - linkType: hard - "longest-streak@npm:^3.0.0": version: 3.1.0 resolution: "longest-streak@npm:3.1.0" @@ -20541,7 +20497,7 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.14.1, lru-cache@npm:^7.4.4, lru-cache@npm:^7.5.1, lru-cache@npm:^7.7.1": +"lru-cache@npm:^7.4.4, lru-cache@npm:^7.5.1, lru-cache@npm:^7.7.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" checksum: 10c0/b3a452b491433db885beed95041eb104c157ef7794b9c9b4d647be503be91769d11206bb573849a16b4cc0d03cbd15ffd22df7960997788b74c1d399ac7a4fed @@ -20566,7 +20522,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.25.0, magic-string@npm:^0.25.7": +"magic-string@npm:^0.25.0, magic-string@npm:^0.25.3, magic-string@npm:^0.25.7": version: 0.25.9 resolution: "magic-string@npm:0.25.9" dependencies: @@ -20657,13 +20613,6 @@ __metadata: languageName: node linkType: hard -"map-stream@npm:~0.1.0": - version: 0.1.0 - resolution: "map-stream@npm:0.1.0" - checksum: 10c0/7dd6debe511c1b55d9da75e1efa65a28b1252a2d8357938d2e49b412713c478efbaefb0cdf0ee0533540c3bf733e8f9f71e1a15aa0fe74bf71b64e75bf1576bd - languageName: node - linkType: hard - "markdown-extensions@npm:^1.0.0": version: 1.1.1 resolution: "markdown-extensions@npm:1.1.1" @@ -21415,7 +21364,7 @@ __metadata: languageName: node linkType: hard -"mime@npm:2.6.0, mime@npm:^2.5.2": +"mime@npm:2.6.0": version: 2.6.0 resolution: "mime@npm:2.6.0" bin: @@ -21424,6 +21373,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^3.0.0": + version: 3.0.0 + resolution: "mime@npm:3.0.0" + bin: + mime: cli.js + checksum: 10c0/402e792a8df1b2cc41cb77f0dcc46472b7944b7ec29cb5bbcd398624b6b97096728f1239766d3fdeb20551dd8d94738344c195a6ea10c4f906eb0356323b0531 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -21450,6 +21408,27 @@ __metadata: languageName: node linkType: hard +"miniflare@npm:3.20250718.3": + version: 3.20250718.3 + resolution: "miniflare@npm:3.20250718.3" + dependencies: + "@cspotcode/source-map-support": "npm:0.8.1" + acorn: "npm:8.14.0" + acorn-walk: "npm:8.3.2" + exit-hook: "npm:2.2.1" + glob-to-regexp: "npm:0.4.1" + stoppable: "npm:1.1.0" + undici: "npm:^5.28.5" + workerd: "npm:1.20250718.0" + ws: "npm:8.18.0" + youch: "npm:3.3.4" + zod: "npm:3.22.3" + bin: + miniflare: bootstrap.js + checksum: 10c0/ebabf4640c6d736589a91833eb5bd00c218175d8fc7ae938fff9014c0ec01d1fc80b11f961df79cd8cdef8d26c4d5ccdb63d5f618f671a1f0b59dc0f5a368ae5 + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -21464,7 +21443,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.0, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -21500,7 +21479,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.3, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4": version: 9.0.4 resolution: "minimatch@npm:9.0.4" dependencies: @@ -21509,7 +21488,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.1.0, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": +"minimist@npm:^1.1.0, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 @@ -21609,13 +21588,6 @@ __metadata: languageName: node linkType: hard -"mitt@npm:^3.0.1": - version: 3.0.1 - resolution: "mitt@npm:3.0.1" - checksum: 10c0/3ab4fdecf3be8c5255536faa07064d05caa3dd332bd318ff02e04621f7b3069ca1de9106cfe8e7ced675abfc2bec2ce4c4ef321c4a1bb1fb29df8ae090741913 - languageName: node - linkType: hard - "mkdirp-classic@npm:^0.5.2": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" @@ -21623,7 +21595,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^0.5.3, mkdirp@npm:^0.5.5, mkdirp@npm:^0.5.6, mkdirp@npm:~0.5.1": +"mkdirp@npm:^0.5.3, mkdirp@npm:^0.5.6, mkdirp@npm:~0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -21817,6 +21789,15 @@ __metadata: languageName: node linkType: hard +"mustache@npm:^4.2.0": + version: 4.2.0 + resolution: "mustache@npm:4.2.0" + bin: + mustache: bin/mustache + checksum: 10c0/1f8197e8a19e63645a786581d58c41df7853da26702dbc005193e2437c98ca49b255345c173d50c08fe4b4dbb363e53cb655ecc570791f8deb09887248dd34a2 + languageName: node + linkType: hard + "mute-stream@npm:^3.0.0": version: 3.0.0 resolution: "mute-stream@npm:3.0.0" @@ -21904,13 +21885,6 @@ __metadata: languageName: node linkType: hard -"netmask@npm:^2.0.2": - version: 2.0.2 - resolution: "netmask@npm:2.0.2" - checksum: 10c0/cafd28388e698e1138ace947929f842944d0f1c0b87d3fa2601a61b38dc89397d33c0ce2c8e7b99e968584b91d15f6810b91bef3f3826adf71b1833b61d4bf4f - languageName: node - linkType: hard - "next@npm:16.0.1": version: 16.0.1 resolution: "next@npm:16.0.1" @@ -22400,6 +22374,13 @@ __metadata: languageName: node linkType: hard +"ohash@npm:^2.0.10": + version: 2.0.11 + resolution: "ohash@npm:2.0.11" + checksum: 10c0/d07c8d79cc26da082c1a7c8d5b56c399dd4ed3b2bd069fcae6bae78c99a9bcc3ad813b1e1f49ca2f335292846d689c6141a762cf078727d2302a33d414e69c79 + languageName: node + linkType: hard + "on-finished@npm:2.4.1, on-finished@npm:^2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -22513,13 +22494,6 @@ __metadata: languageName: node linkType: hard -"os-shim@npm:^0.1.3": - version: 0.1.3 - resolution: "os-shim@npm:0.1.3" - checksum: 10c0/eaa09098c0f6a3115b2d0c027927cba9c2706e362b7767021b7ac83d159f18806ac1e95786b496d1912ce1aea8a6866e526d3f18f075c7c719eb08a0ffb9177f - languageName: node - linkType: hard - "ospec@npm:3.1.0": version: 3.1.0 resolution: "ospec@npm:3.1.0" @@ -22638,32 +22612,6 @@ __metadata: languageName: node linkType: hard -"pac-proxy-agent@npm:^7.1.0": - version: 7.2.0 - resolution: "pac-proxy-agent@npm:7.2.0" - dependencies: - "@tootallnate/quickjs-emscripten": "npm:^0.23.0" - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - get-uri: "npm:^6.0.1" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.6" - pac-resolver: "npm:^7.0.1" - socks-proxy-agent: "npm:^8.0.5" - checksum: 10c0/0265c17c9401c2ea735697931a6553a0c6d8b20c4d7d4e3b3a0506080ba69a8d5ad656e2a6be875411212e2b6ed7a4d9526dd3997e08581fdfb1cbcad454c296 - languageName: node - linkType: hard - -"pac-resolver@npm:^7.0.1": - version: 7.0.1 - resolution: "pac-resolver@npm:7.0.1" - dependencies: - degenerator: "npm:^5.0.0" - netmask: "npm:^2.0.2" - checksum: 10c0/5f3edd1dd10fded31e7d1f95776442c3ee51aa098c28b74ede4927d9677ebe7cebb2636750c24e945f5b84445e41ae39093d3a1014a994e5ceb9f0b1b88ebff5 - languageName: node - linkType: hard - "package-hash@npm:^4.0.0": version: 4.0.0 resolution: "package-hash@npm:4.0.0" @@ -22909,15 +22857,6 @@ __metadata: languageName: node linkType: hard -"pause-stream@npm:0.0.11": - version: 0.0.11 - resolution: "pause-stream@npm:0.0.11" - dependencies: - through: "npm:~2.3" - checksum: 10c0/86f12c64cdaaa8e45ebaca4e39a478e1442db8b4beabc280b545bfaf79c0e2f33c51efb554aace5c069cc441c7b924ba484837b345eaa4ba6fc940d62f826802 - languageName: node - linkType: hard - "pbkdf2@npm:>=3.1.3": version: 3.1.5 resolution: "pbkdf2@npm:3.1.5" @@ -22943,13 +22882,6 @@ __metadata: languageName: node linkType: hard -"pend@npm:~1.2.0": - version: 1.2.0 - resolution: "pend@npm:1.2.0" - checksum: 10c0/8a87e63f7a4afcfb0f9f77b39bb92374afc723418b9cb716ee4257689224171002e07768eeade4ecd0e86f1fa3d8f022994219fb45634f2dbd78c6803e452458 - languageName: node - linkType: hard - "performance-now@npm:^2.1.0": version: 2.1.0 resolution: "performance-now@npm:2.1.0" @@ -23083,6 +23015,30 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.59.1": + version: 1.59.1 + resolution: "playwright-core@npm:1.59.1" + bin: + playwright-core: cli.js + checksum: 10c0/d41a74d9681ce3beb3d5239e9ed577710b4ad099a6ca2476219c6599d51e9cb4b80bd72ed82c528da6a5d929c18ae3b872cf02bb83f78fa1c2cb9199c501abee + languageName: node + linkType: hard + +"playwright@npm:1.59.1": + version: 1.59.1 + resolution: "playwright@npm:1.59.1" + dependencies: + fsevents: "npm:2.3.2" + playwright-core: "npm:1.59.1" + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 10c0/dfe38396e616e5c4f98825ce90037bb96e477c5a2bd9258a24854f8ce72a8a41427b19098863866f85aa0216e70287dd537c4438d761aca93995e31ae099c533 + languageName: node + linkType: hard + "pluralize@npm:8.0.0": version: 8.0.0 resolution: "pluralize@npm:8.0.0" @@ -24145,6 +24101,13 @@ __metadata: languageName: node linkType: hard +"printable-characters@npm:^1.0.42": + version: 1.0.42 + resolution: "printable-characters@npm:1.0.42" + checksum: 10c0/7c94d94c6041a37c385af770c7402ad5a2e8a3429ca4d2505a9f19fde39bac9a8fd1edfbfa02f1eae5b4b0f3536b6b8ee6c84621f7c0fcb41476b2df6ee20e4b + languageName: node + linkType: hard + "private@npm:^0.1.8": version: 0.1.8 resolution: "private@npm:0.1.8" @@ -24189,13 +24152,6 @@ __metadata: languageName: node linkType: hard -"progress@npm:^2.0.3": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: 10c0/1697e07cb1068055dbe9fe858d242368ff5d2073639e652b75a7eb1f2a1a8d4afd404d719de23c7b48481a6aa0040686310e2dac2f53d776daa2176d3f96369c - languageName: node - linkType: hard - "promise-inflight@npm:^1.0.1": version: 1.0.1 resolution: "promise-inflight@npm:1.0.1" @@ -24269,40 +24225,6 @@ __metadata: languageName: node linkType: hard -"proxy-agent@npm:^6.5.0": - version: 6.5.0 - resolution: "proxy-agent@npm:6.5.0" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - http-proxy-agent: "npm:^7.0.1" - https-proxy-agent: "npm:^7.0.6" - lru-cache: "npm:^7.14.1" - pac-proxy-agent: "npm:^7.1.0" - proxy-from-env: "npm:^1.1.0" - socks-proxy-agent: "npm:^8.0.5" - checksum: 10c0/7fd4e6f36bf17098a686d4aee3b8394abfc0b0537c2174ce96b0a4223198b9fafb16576c90108a3fcfc2af0168bd7747152bfa1f58e8fee91d3780e79aab7fd8 - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b - languageName: node - linkType: hard - -"ps-tree@npm:=1.2.0": - version: 1.2.0 - resolution: "ps-tree@npm:1.2.0" - dependencies: - event-stream: "npm:=3.3.4" - bin: - ps-tree: ./bin/ps-tree.js - checksum: 10c0/9d1c159e0890db5aa05f84d125193c2190a6c4ecd457596fd25e7611f8f747292a846459dcc0244e27d45529d4cea6d1010c3a2a087fad02624d12fdb7d97c22 - languageName: node - linkType: hard - "pseudomap@npm:^1.0.2": version: 1.0.2 resolution: "pseudomap@npm:1.0.2" @@ -24625,41 +24547,10 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - -"puppeteer-core@npm:24.29.1": - version: 24.29.1 - resolution: "puppeteer-core@npm:24.29.1" - dependencies: - "@puppeteer/browsers": "npm:2.10.13" - chromium-bidi: "npm:10.5.1" - debug: "npm:^4.4.3" - devtools-protocol: "npm:0.0.1521046" - typed-query-selector: "npm:^2.12.0" - webdriver-bidi-protocol: "npm:0.3.8" - ws: "npm:^8.18.3" - checksum: 10c0/dd767012045a497ba29f8367fa4d149a1cd75db00c01528b5082548d5920278f76b88314a820b470a22a103e9c87dc7b1f09852d81a4958fe97fdae5acc7288f - languageName: node - linkType: hard - -"puppeteer@npm:^24.29.1": - version: 24.29.1 - resolution: "puppeteer@npm:24.29.1" - dependencies: - "@puppeteer/browsers": "npm:2.10.13" - chromium-bidi: "npm:10.5.1" - cosmiconfig: "npm:^9.0.0" - devtools-protocol: "npm:0.0.1521046" - puppeteer-core: "npm:24.29.1" - typed-query-selector: "npm:^2.12.0" - bin: - puppeteer: lib/cjs/puppeteer/node/cli.js - checksum: 10c0/2ca726f077929b190b50a96c8e968162194cd7b83af324005aa767f73862926223eb9cd60d00de81d71f435b74aad274103c644b1b773a39d804d47fefe687bb +"punycode@npm:^2.1.0, punycode@npm:^2.1.1": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 languageName: node linkType: hard @@ -24670,20 +24561,13 @@ __metadata: languageName: node linkType: hard -"q@npm:^1.1.2, q@npm:~1.5.0": +"q@npm:^1.1.2": version: 1.5.1 resolution: "q@npm:1.5.1" checksum: 10c0/7855fbdba126cb7e92ef3a16b47ba998c0786ec7fface236e3eb0135b65df36429d91a86b1fff3ab0927b4ac4ee88a2c44527c7c3b8e2a37efbec9fe34803df4 languageName: node linkType: hard -"qjobs@npm:^1.2.0": - version: 1.2.0 - resolution: "qjobs@npm:1.2.0" - checksum: 10c0/772207772b856a3b1ec673b11a6cda074f1b82821644f2d042504b438ea3ea1fe918555547491e717e8694ec105379fe5139fc5ddd7937b21f7712bb648ed01d - languageName: node - linkType: hard - "qs@npm:6.11.0": version: 6.11.0 resolution: "qs@npm:6.11.0" @@ -24741,13 +24625,6 @@ __metadata: languageName: node linkType: hard -"queue-tick@npm:^1.0.1": - version: 1.0.1 - resolution: "queue-tick@npm:1.0.1" - checksum: 10c0/0db998e2c9b15215317dbcf801e9b23e6bcde4044e115155dae34f8e7454b9a783f737c9a725528d677b7a66c775eb7a955cf144fe0b87f62b575ce5bfd515a9 - languageName: node - linkType: hard - "raf@npm:^3.4.1": version: 3.4.1 resolution: "raf@npm:3.4.1" @@ -25667,7 +25544,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.4, resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:^1.3.2, resolve@npm:^1.3.3, resolve@npm:^1.4.0": +"resolve@npm:^1.1.4, resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:^1.3.2, resolve@npm:^1.4.0": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -25706,8 +25583,7 @@ __metadata: languageName: node linkType: hard -? "resolve@patch:resolve@npm%3A^1.1.4#optional!builtin, resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.3.2#optional!builtin, resolve@patch:resolve@npm%3A^1.3.3#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin" -: +"resolve@patch:resolve@npm%3A^1.1.4#optional!builtin, resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.3.2#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -25777,13 +25653,6 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.3.0": - version: 1.4.1 - resolution: "rfdc@npm:1.4.1" - checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7 - languageName: node - linkType: hard - "right-align@npm:^0.1.1": version: 0.1.3 resolution: "right-align@npm:0.1.3" @@ -25804,17 +25673,6 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:~2.5.2": - version: 2.5.4 - resolution: "rimraf@npm:2.5.4" - dependencies: - glob: "npm:^7.0.5" - bin: - rimraf: ./bin.js - checksum: 10c0/02556efee08012469e358ed54f6e59e2a3589f07d4b15c6156ae57d391cb6983dd35d02a2a1b9c4c9d129d90fb00db980a5c44ea248ecff2737c246ed02686b1 - languageName: node - linkType: hard - "ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": version: 2.0.2 resolution: "ripemd160@npm:2.0.2" @@ -25876,6 +25734,17 @@ __metadata: languageName: node linkType: hard +"rollup-plugin-inject@npm:^3.0.0": + version: 3.0.2 + resolution: "rollup-plugin-inject@npm:3.0.2" + dependencies: + estree-walker: "npm:^0.6.1" + magic-string: "npm:^0.25.3" + rollup-pluginutils: "npm:^2.8.1" + checksum: 10c0/35b9d955039b56b43750a9e458bb51b7956b048b6d3ca57b1f03462aa5a0cb176d1b677d95e909b64eee4e9adf73c02f569ad8c0ab5aafdec818ff51700c114c + languageName: node + linkType: hard + "rollup-plugin-jsdoc@npm:^0.1.2": version: 0.1.2 resolution: "rollup-plugin-jsdoc@npm:0.1.2" @@ -25895,6 +25764,15 @@ __metadata: languageName: node linkType: hard +"rollup-plugin-node-polyfills@npm:^0.2.1": + version: 0.2.1 + resolution: "rollup-plugin-node-polyfills@npm:0.2.1" + dependencies: + rollup-plugin-inject: "npm:^3.0.0" + checksum: 10c0/30f9e09cbbf979b1212e0c455d74c3a061994fc19ddf160da4634b11377222cea5903a5ba05db66be849f550cde9ffc80ecbfcfb48544045d08bfc408501417d + languageName: node + linkType: hard + "rollup-plugin-terser@npm:^7.0.0": version: 7.0.2 resolution: "rollup-plugin-terser@npm:7.0.2" @@ -25925,6 +25803,15 @@ __metadata: languageName: node linkType: hard +"rollup-pluginutils@npm:^2.8.1": + version: 2.8.2 + resolution: "rollup-pluginutils@npm:2.8.2" + dependencies: + estree-walker: "npm:^0.6.1" + checksum: 10c0/20947bec5a5dd68b5c5c8423911e6e7c0ad834c451f1a929b1f4e2bc08836ad3f1a722ef2bfcbeca921870a0a283f13f064a317dc7a6768496e98c9a641ba290 + languageName: node + linkType: hard + "rollup@npm:>=2.79.2": version: 4.53.2 resolution: "rollup@npm:4.53.2" @@ -26576,6 +26463,75 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.33.5": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.33.5" + "@img/sharp-darwin-x64": "npm:0.33.5" + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + "@img/sharp-linux-arm": "npm:0.33.5" + "@img/sharp-linux-arm64": "npm:0.33.5" + "@img/sharp-linux-s390x": "npm:0.33.5" + "@img/sharp-linux-x64": "npm:0.33.5" + "@img/sharp-linuxmusl-arm64": "npm:0.33.5" + "@img/sharp-linuxmusl-x64": "npm:0.33.5" + "@img/sharp-wasm32": "npm:0.33.5" + "@img/sharp-win32-ia32": "npm:0.33.5" + "@img/sharp-win32-x64": "npm:0.33.5" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.3" + semver: "npm:^7.6.3" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 + languageName: node + linkType: hard + "sharp@npm:^0.34.4": version: 0.34.5 resolution: "sharp@npm:0.34.5" @@ -26773,6 +26729,15 @@ __metadata: languageName: node linkType: hard +"simple-swizzle@npm:^0.2.2": + version: 0.2.4 + resolution: "simple-swizzle@npm:0.2.4" + dependencies: + is-arrayish: "npm:^0.3.1" + checksum: 10c0/846c3fdd1325318d5c71295cfbb99bfc9edc4c8dffdda5e6e9efe30482bbcd32cf360fc2806f46ac43ff7d09bcfaff20337bb79f826f0e6a8e366efd3cdd7868 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -26815,41 +26780,6 @@ __metadata: languageName: node linkType: hard -"socket.io-adapter@npm:~2.5.2": - version: 2.5.5 - resolution: "socket.io-adapter@npm:2.5.5" - dependencies: - debug: "npm:~4.3.4" - ws: "npm:~8.17.1" - checksum: 10c0/04a5a2a9c4399d1b6597c2afc4492ab1e73430cc124ab02b09e948eabf341180b3866e2b61b5084cb899beb68a4db7c328c29bda5efb9207671b5cb0bc6de44e - languageName: node - linkType: hard - -"socket.io-parser@npm:~4.2.4": - version: 4.2.4 - resolution: "socket.io-parser@npm:4.2.4" - dependencies: - "@socket.io/component-emitter": "npm:~3.1.0" - debug: "npm:~4.3.1" - checksum: 10c0/9383b30358fde4a801ea4ec5e6860915c0389a091321f1c1f41506618b5cf7cd685d0a31c587467a0c4ee99ef98c2b99fb87911f9dfb329716c43b587f29ca48 - languageName: node - linkType: hard - -"socket.io@npm:^4.7.2": - version: 4.7.5 - resolution: "socket.io@npm:4.7.5" - dependencies: - accepts: "npm:~1.3.4" - base64id: "npm:~2.0.0" - cors: "npm:~2.8.5" - debug: "npm:~4.3.2" - engine.io: "npm:~6.5.2" - socket.io-adapter: "npm:~2.5.2" - socket.io-parser: "npm:~4.2.4" - checksum: 10c0/221a2cd25f6077d6672cb8b19921336e1acf06788d4bade74953dc96dbfd8b788a5f721b051341a34ee81ef8e1b2028d39ad5257516776400a3f8f3f01255c5e - languageName: node - linkType: hard - "sockjs@npm:^0.3.24": version: 0.3.24 resolution: "sockjs@npm:0.3.24" @@ -26872,17 +26802,6 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^8.0.5": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 - languageName: node - linkType: hard - "socks@npm:^2.7.1": version: 2.8.3 resolution: "socks@npm:2.8.3" @@ -26893,16 +26812,6 @@ __metadata: languageName: node linkType: hard -"socks@npm:^2.8.3": - version: 2.8.7 - resolution: "socks@npm:2.8.7" - dependencies: - ip-address: "npm:^10.0.1" - smart-buffer: "npm:^4.2.0" - checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 - languageName: node - linkType: hard - "sort-keys@npm:^2.0.0": version: 2.0.0 resolution: "sort-keys@npm:2.0.0" @@ -27085,15 +26994,6 @@ __metadata: languageName: node linkType: hard -"split@npm:0.3": - version: 0.3.3 - resolution: "split@npm:0.3.3" - dependencies: - through: "npm:2" - checksum: 10c0/88c09b1b4de84953bf5d6c153123a1fbb20addfea9381f70d27b4eb6b2bfbadf25d313f8f5d3fd727d5679b97bfe54da04766b91010f131635bf49e51d5db3fc - languageName: node - linkType: hard - "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -27147,6 +27047,16 @@ __metadata: languageName: node linkType: hard +"stacktracey@npm:^2.1.8": + version: 2.2.0 + resolution: "stacktracey@npm:2.2.0" + dependencies: + as-table: "npm:^1.0.36" + get-source: "npm:^2.0.12" + checksum: 10c0/fc5d58a85e76a1a13ce1a2ecac4029c5e889a7c437259023f5514dfc3b107603de944c46faa6c930e4991fe13d91deb385e9537ef7f6deb1bd2d8188f69eec30 + languageName: node + linkType: hard + "static-eval@npm:2.0.2": version: 2.0.2 resolution: "static-eval@npm:2.0.2" @@ -27163,7 +27073,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.4.0 < 2, statuses@npm:~1.5.0": +"statuses@npm:>= 1.4.0 < 2": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: 10c0/e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 @@ -27187,6 +27097,13 @@ __metadata: languageName: node linkType: hard +"stoppable@npm:1.1.0": + version: 1.1.0 + resolution: "stoppable@npm:1.1.0" + checksum: 10c0/ba91b65e6442bf6f01ce837a727ece597a977ed92a05cb9aea6bf446c5e0dcbccc28f31b793afa8aedd8f34baaf3335398d35f903938d5493f7fbe386a1e090e + languageName: node + linkType: hard + "stream-browserify@npm:^3.0.0": version: 3.0.0 resolution: "stream-browserify@npm:3.0.0" @@ -27207,15 +27124,6 @@ __metadata: languageName: node linkType: hard -"stream-combiner@npm:~0.0.4": - version: 0.0.4 - resolution: "stream-combiner@npm:0.0.4" - dependencies: - duplexer: "npm:~0.1.1" - checksum: 10c0/8075a94c0eb0f20450a8236cb99d4ce3ea6e6a4b36d8baa7440b1a08cde6ffd227debadffaecd80993bd334282875d0e927ab5b88484625e01970dd251004ff5 - languageName: node - linkType: hard - "stream-http@npm:^3.0.0": version: 3.2.0 resolution: "stream-http@npm:3.2.0" @@ -27252,17 +27160,6 @@ __metadata: languageName: node linkType: hard -"streamroller@npm:^3.1.5": - version: 3.1.5 - resolution: "streamroller@npm:3.1.5" - dependencies: - date-format: "npm:^4.0.14" - debug: "npm:^4.3.4" - fs-extra: "npm:^8.1.0" - checksum: 10c0/0bdeec34ad37487d959ba908f17067c938f544db88b5bb1669497a67a6b676413229ce5a6145c2812d06959ebeb8842e751076647d4b323ca06be612963b9099 - languageName: node - linkType: hard - "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" @@ -27270,32 +27167,6 @@ __metadata: languageName: node linkType: hard -"streamx@npm:^2.15.0": - version: 2.18.0 - resolution: "streamx@npm:2.18.0" - dependencies: - bare-events: "npm:^2.2.0" - fast-fifo: "npm:^1.3.2" - queue-tick: "npm:^1.0.1" - text-decoder: "npm:^1.1.0" - dependenciesMeta: - bare-events: - optional: true - checksum: 10c0/ef50f419252a73dd35abcde72329eafbf5ad9cd2e27f0cc3abebeff6e0dbea124ac6d3e16acbdf081cce41b4125393ac22f9848fcfa19e640830734883e622ba - languageName: node - linkType: hard - -"streamx@npm:^2.21.0": - version: 2.23.0 - resolution: "streamx@npm:2.23.0" - dependencies: - events-universal: "npm:^1.0.0" - fast-fifo: "npm:^1.3.2" - text-decoder: "npm:^1.1.0" - checksum: 10c0/15708ce37818d588632fe1104e8febde573e33e8c0868bf583fce0703f3faf8d2a063c278e30df2270206811b69997f64eb78792099933a1fe757e786fbcbd44 - languageName: node - linkType: hard - "string-hash@npm:^1.1.3": version: 1.1.3 resolution: "string-hash@npm:1.1.3" @@ -27523,15 +27394,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-ansi@npm:4.0.0" - dependencies: - ansi-regex: "npm:^3.0.0" - checksum: 10c0/d75d9681e0637ea316ddbd7d4d3be010b1895a17e885155e0ed6a39755ae0fd7ef46e14b22162e66a62db122d3a98ab7917794e255532ab461bb0a04feb03e7d - languageName: node - linkType: hard - "strip-ansi@npm:^7.0.1": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" @@ -27964,23 +27826,6 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^3.1.1": - version: 3.1.1 - resolution: "tar-fs@npm:3.1.1" - dependencies: - bare-fs: "npm:^4.0.1" - bare-path: "npm:^3.0.0" - pump: "npm:^3.0.0" - tar-stream: "npm:^3.1.5" - dependenciesMeta: - bare-fs: - optional: true - bare-path: - optional: true - checksum: 10c0/0c677d711c4aa41f94e1a712aa647022ba1910ff84430739e5d9e95a615e3ea1b7112dc93164fc8ce30dc715befcf9cfdc64da27d4e7958d73c59bda06aa0d8e - languageName: node - linkType: hard - "tar-stream@npm:^2.1.4": version: 2.2.0 resolution: "tar-stream@npm:2.2.0" @@ -27994,17 +27839,6 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^3.1.5": - version: 3.1.7 - resolution: "tar-stream@npm:3.1.7" - dependencies: - b4a: "npm:^1.6.4" - fast-fifo: "npm:^1.2.0" - streamx: "npm:^2.15.0" - checksum: 10c0/a09199d21f8714bd729993ac49b6c8efcb808b544b89f23378ad6ffff6d1cb540878614ba9d4cfec11a64ef39e1a6f009a5398371491eb1fda606ffc7f70f718 - languageName: node - linkType: hard - "tar@npm:^6.1.11, tar@npm:^6.1.2": version: 6.2.1 resolution: "tar@npm:6.2.1" @@ -28026,15 +27860,6 @@ __metadata: languageName: node linkType: hard -"temp-fs@npm:^0.9.9": - version: 0.9.9 - resolution: "temp-fs@npm:0.9.9" - dependencies: - rimraf: "npm:~2.5.2" - checksum: 10c0/6b5584a794a7a83c5618b025f4b7f7a4d01c1e6a696289fa7bba128193f781cffc6b044962775bea2a43418bf2731f994cb8444e1196b23dafe4e7bae04d9a7f - languageName: node - linkType: hard - "tempy@npm:^0.6.0": version: 0.6.0 resolution: "tempy@npm:0.6.0" @@ -28140,15 +27965,6 @@ __metadata: languageName: node linkType: hard -"text-decoder@npm:^1.1.0": - version: 1.1.0 - resolution: "text-decoder@npm:1.1.0" - dependencies: - b4a: "npm:^1.6.4" - checksum: 10c0/623a6cfb5ee86c250fea31f369a0d40e4ef5c2c32ce8db43492648b51193858213e61bf47a6078f285053715dcc6342806ce6ea9a49d7847ffca282ca88ad7e8 - languageName: node - linkType: hard - "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -28200,7 +28016,7 @@ __metadata: languageName: node linkType: hard -"through@npm:2, through@npm:>=2.2.7 <3, through@npm:~2.3, through@npm:~2.3.1": +"through@npm:>=2.2.7 <3": version: 2.3.8 resolution: "through@npm:2.3.8" checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc @@ -28233,13 +28049,6 @@ __metadata: languageName: node linkType: hard -"tmp@npm:^0.2.1": - version: 0.2.3 - resolution: "tmp@npm:0.2.3" - checksum: 10c0/3e809d9c2f46817475b452725c2aaa5d11985cf18d32a7a970ff25b568438e2c076c2e8609224feef3b7923fa9749b74428e3e634f6b8e520c534eef2fd24125 - languageName: node - linkType: hard - "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -28860,13 +28669,6 @@ __metadata: languageName: node linkType: hard -"typed-query-selector@npm:^2.12.0": - version: 2.12.0 - resolution: "typed-query-selector@npm:2.12.0" - checksum: 10c0/069509887ecfff824a470f5f93d300cc9223cb059a36c47ac685f2812c4c9470340e07615893765e4264cef1678507532fa78f642fd52f276b589f7f5d791f79 - languageName: node - linkType: hard - "typedarray-to-buffer@npm:^3.1.5": version: 3.1.5 resolution: "typedarray-to-buffer@npm:3.1.5" @@ -28998,13 +28800,6 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.30": - version: 0.7.38 - resolution: "ua-parser-js@npm:0.7.38" - checksum: 10c0/da963eae1618f0c60d0812851a4d478fb8bb127ee6e5c566b8dac27eeb25757d818d9ade2c312d73018f2bb3c3e629d26c066fcda3cb9d55a31289c9566198df - languageName: node - linkType: hard - "uc.micro@npm:^1.0.1, uc.micro@npm:^1.0.5": version: 1.0.6 resolution: "uc.micro@npm:1.0.6" @@ -29143,6 +28938,15 @@ __metadata: languageName: node linkType: hard +"undici@npm:^5.28.5": + version: 5.29.0 + resolution: "undici@npm:5.29.0" + dependencies: + "@fastify/busboy": "npm:^2.0.0" + checksum: 10c0/e4e4d631ca54ee0ad82d2e90e7798fa00a106e27e6c880687e445cc2f13b4bc87c5eba2a88c266c3eecffb18f26e227b778412da74a23acc374fca7caccec49b + languageName: node + linkType: hard + "undici@npm:^6.21.2": version: 6.22.0 resolution: "undici@npm:6.22.0" @@ -29150,6 +28954,19 @@ __metadata: languageName: node linkType: hard +"unenv@npm:2.0.0-rc.14": + version: 2.0.0-rc.14 + resolution: "unenv@npm:2.0.0-rc.14" + dependencies: + defu: "npm:^6.1.4" + exsolve: "npm:^1.0.1" + ohash: "npm:^2.0.10" + pathe: "npm:^2.0.3" + ufo: "npm:^1.5.4" + checksum: 10c0/85372028cafb1726dfbe4dbb34953580827936f527022f6b03eaaf1b947d9354cf39ed505203edb11e77791d01778cb2287b2db03f516ed4503de9182a821f94 + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -29803,7 +29620,7 @@ __metadata: languageName: node linkType: hard -"void-elements@npm:^2.0.0, void-elements@npm:^2.0.1": +"void-elements@npm:^2.0.1": version: 2.0.1 resolution: "void-elements@npm:2.0.1" checksum: 10c0/23b4f35bbeabcaa5c87a9f638ae80862a9313dccbaa8973b0eada81dbe97488ae11baf4d8aa2846bc397d31456afdfd8d791bb44c542f83735e6d04af6996f4d @@ -29965,13 +29782,6 @@ __metadata: languageName: node linkType: hard -"webdriver-bidi-protocol@npm:0.3.8": - version: 0.3.8 - resolution: "webdriver-bidi-protocol@npm:0.3.8" - checksum: 10c0/288134377635b9cd24cc73f9b715d169eea39eeb8d50afbafd90ca313379fa9b2964e666c90256d2b34a6089e3531cc1e17a0d289d3b8f9b224a2bba73fb03e3 - languageName: node - linkType: hard - "webidl-conversions@npm:^4.0.2": version: 4.0.2 resolution: "webidl-conversions@npm:4.0.2" @@ -30067,15 +29877,6 @@ __metadata: languageName: node linkType: hard -"webpack-merge@npm:^4.1.5": - version: 4.2.2 - resolution: "webpack-merge@npm:4.2.2" - dependencies: - lodash: "npm:^4.17.15" - checksum: 10c0/283cb4ffe4d4ae6de23d595154868780126835ded241748da0b070c6cca6974c229493ac0b6b7160c2c92950c950c8e5edf036a192da78e32e22a9c81593ad16 - languageName: node - linkType: hard - "webpack-node-externals@npm:3.0.0": version: 3.0.0 resolution: "webpack-node-externals@npm:3.0.0" @@ -30407,7 +30208,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^1.2.1, which@npm:^1.3.1": +"which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" dependencies: @@ -30715,6 +30516,32 @@ __metadata: languageName: node linkType: hard +"workerd@npm:1.20250718.0": + version: 1.20250718.0 + resolution: "workerd@npm:1.20250718.0" + dependencies: + "@cloudflare/workerd-darwin-64": "npm:1.20250718.0" + "@cloudflare/workerd-darwin-arm64": "npm:1.20250718.0" + "@cloudflare/workerd-linux-64": "npm:1.20250718.0" + "@cloudflare/workerd-linux-arm64": "npm:1.20250718.0" + "@cloudflare/workerd-windows-64": "npm:1.20250718.0" + dependenciesMeta: + "@cloudflare/workerd-darwin-64": + optional: true + "@cloudflare/workerd-darwin-arm64": + optional: true + "@cloudflare/workerd-linux-64": + optional: true + "@cloudflare/workerd-linux-arm64": + optional: true + "@cloudflare/workerd-windows-64": + optional: true + bin: + workerd: bin/workerd + checksum: 10c0/94ac61da99310331ec21c5fb10072791af78a8080059153793ff81796a7c372ce2b40274614590982ceb2f4b1b395997f1d93b635c3c282583624a36eff8970d + languageName: node + linkType: hard + "workerpool@npm:^9.2.0": version: 9.3.4 resolution: "workerpool@npm:9.3.4" @@ -30722,6 +30549,39 @@ __metadata: languageName: node linkType: hard +"wrangler@npm:^3.99.0": + version: 3.114.17 + resolution: "wrangler@npm:3.114.17" + dependencies: + "@cloudflare/kv-asset-handler": "npm:0.3.4" + "@cloudflare/unenv-preset": "npm:2.0.2" + "@esbuild-plugins/node-globals-polyfill": "npm:0.2.3" + "@esbuild-plugins/node-modules-polyfill": "npm:0.2.2" + blake3-wasm: "npm:2.1.5" + esbuild: "npm:0.17.19" + fsevents: "npm:~2.3.2" + miniflare: "npm:3.20250718.3" + path-to-regexp: "npm:6.3.0" + sharp: "npm:^0.33.5" + unenv: "npm:2.0.0-rc.14" + workerd: "npm:1.20250718.0" + peerDependencies: + "@cloudflare/workers-types": ^4.20250408.0 + dependenciesMeta: + fsevents: + optional: true + sharp: + optional: true + peerDependenciesMeta: + "@cloudflare/workers-types": + optional: true + bin: + wrangler: bin/wrangler.js + wrangler2: bin/wrangler.js + checksum: 10c0/83cedac5b95b1f78ee6213fe585be5a7f7cfa2885ac482b8e75ca3e13d3ba5b0746fae5aaf82c2652c704755fe74889b69e0e2b75b6db8bb095ff7cb42b9a167 + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -30820,39 +30680,39 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.4.6, ws@npm:^7.5.10": - version: 7.5.10 - resolution: "ws@npm:7.5.10" +"ws@npm:8.18.0": + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: ">=5.0.2" peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d + checksum: 10c0/25eb33aff17edcb90721ed6b0eb250976328533ad3cd1a28a274bd263682e7296a6591ff1436d6cbc50fa67463158b062f9d1122013b361cec99a05f84680e06 languageName: node linkType: hard -"ws@npm:^8.13.0, ws@npm:~8.17.1": - version: 8.17.1 - resolution: "ws@npm:8.17.1" +"ws@npm:^7.4.6, ws@npm:^7.5.10": + version: 7.5.10 + resolution: "ws@npm:7.5.10" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" + utf-8-validate: ^5.0.2 peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 10c0/f4a49064afae4500be772abdc2211c8518f39e1c959640457dcee15d4488628620625c783902a52af2dd02f68558da2868fd06e6fd0e67ebcd09e6881b1b5bfe + checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d languageName: node linkType: hard -"ws@npm:^8.18.3": - version: 8.18.3 - resolution: "ws@npm:8.18.3" +"ws@npm:^8.13.0": + version: 8.17.1 + resolution: "ws@npm:8.17.1" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -30861,7 +30721,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 + checksum: 10c0/f4a49064afae4500be772abdc2211c8518f39e1c959640457dcee15d4488628620625c783902a52af2dd02f68558da2868fd06e6fd0e67ebcd09e6881b1b5bfe languageName: node linkType: hard @@ -31009,7 +30869,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^16.1.1, yargs@npm:^16.2.0": +"yargs@npm:^16.2.0": version: 16.2.0 resolution: "yargs@npm:16.2.0" dependencies: @@ -31051,16 +30911,6 @@ __metadata: languageName: node linkType: hard -"yauzl@npm:^2.10.0": - version: 2.10.0 - resolution: "yauzl@npm:2.10.0" - dependencies: - buffer-crc32: "npm:~0.2.3" - fd-slicer: "npm:~1.1.0" - checksum: 10c0/f265002af7541b9ec3589a27f5fb8f11cf348b53cc15e2751272e3c062cd73f3e715bc72d43257de71bbaecae446c3f1b14af7559e8ab0261625375541816422 - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -31082,6 +30932,17 @@ __metadata: languageName: node linkType: hard +"youch@npm:3.3.4": + version: 3.3.4 + resolution: "youch@npm:3.3.4" + dependencies: + cookie: "npm:^0.7.1" + mustache: "npm:^4.2.0" + stacktracey: "npm:^2.1.8" + checksum: 10c0/ab573c7dccebdaf2d6b084d262d5bfb22ad5c049fb1ad3e2d6a840af851042dd3a8a072665c5a5ee73c75bbc1618fbc08f1371ac896e54556bced0ddf996b026 + languageName: node + linkType: hard + "zod-validation-error@npm:^3.5.0 || ^4.0.0": version: 4.0.2 resolution: "zod-validation-error@npm:4.0.2" @@ -31091,10 +30952,10 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.24.1": - version: 3.25.76 - resolution: "zod@npm:3.25.76" - checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c +"zod@npm:3.22.3": + version: 3.22.3 + resolution: "zod@npm:3.22.3" + checksum: 10c0/cb4b24aed7dec98552eb9042e88cbd645455bf2830e5704174d2da96f554dabad4630e3b4f6623e1b6562b9eaa43535a37b7f2011f29b8d8e9eabe1ddf3b656b languageName: node linkType: hard