Skill: ga4-multi-property (version 1.0.0)

--- name: ga4-analytics description: "Google Analytics 4, Search Console, and Indexing API toolkit. Analyze website traffic, page performance, user demographics, real-time visitors, search queries, and SEO metrics. Use when the user asks to: check site traffic, analyze page views, see traffic sources, view user demographics, get real-time visitor data, check search console queries, analyze SEO performance, request URL re-indexing, inspect index status, compare date ranges, check bounce rates, view conversion data, or get e-commerce revenue. Requires a Google Cloud service account with GA4 and Search Console access." --- # GA4 Analytics Toolkit ## Setup Install dependencies: ```bash cd scripts && npm install ``` Configure credentials by creating a `.env` file in the project root: ``` GA4_PROPERTY_ID=123456789 GA4_CLIENT_EMAIL=[REDACTED_SECRET] GA4_PRIVATE_KEY="[REDACTED_SECRET]\n" SEARCH_CONSOLE_SITE_URL=https://your-domain.com GA4_DEFAULT_DATE_RANGE=30d ``` **Prerequisites**: A Google Cloud project with the Analytics Data API, Search Console API, and Indexing API enabled. A service account with access to your GA4 property and Search Console. ## Quick Start | User says | Function to call | |-----------|-----------------| | "Show me site traffic for the last 30 days" | `siteOverview("30d")` | | "What are my top search queries?" | `searchConsoleOverview("30d")` | | "Who's on the site right now?" | `liveSnapshot()` | | "Reindex these URLs" | `reindexUrls(["https://example.com/page1", ...])` | | "Compare this month vs last month" | `compareDateRanges({startDate: "30daysAgo", endDate: "today"}, {startDate: "60daysAgo", endDate: "31daysAgo"})` | | "What pages get the most traffic?" | `contentPerformance("30d")` | Execute functions by importing from `scripts/src/index.ts`: ```typescript import { siteOverview, searchConsoleOverview } from './scripts/src/index.js'; const overview = await siteOverview('30d'); ``` Or run directly with tsx: ```bash npx tsx scripts/src/index.ts ``` ## Workflow Pattern Every analysis follows three phases: ### 1. Analyze Run API functions. Each call hits the Google APIs and returns structured data. ### 2. Auto-Save All results automatically save as timestamped JSON files to `results/{category}/`. File naming pattern: `YYYYMMDD_HHMMSS__operation__extra_info.json` ### 3. Summarize After analysis, read the saved JSON files and create a markdown summary in `results/summaries/` with data tables, trends, and recommendations. ## High-Level Functions ### GA4 Analytics | Function | Purpose | What it gathers | |----------|---------|----------------| | `siteOverview(dateRange?)` | Comprehensive site snapshot | Page views, traffic sources, demographics, events | | `trafficAnalysis(dateRange?)` | Traffic deep-dive | Sources, sessions by source/medium, new vs returning | | `contentPerformance(dateRange?)` | Top pages analysis | Page views, landing pages, exit pages | | `userBehavior(dateRange?)` | Engagement patterns | Demographics, events, daily engagement metrics | | `compareDateRanges(range1, range2)` | Period comparison | Side-by-side metrics for two date ranges | | `liveSnapshot()` | Real-time data | Active users, current pages, current events | ### Search Console | Function | Purpose | What it gathers | |----------|---------|----------------| | `searchConsoleOverview(dateRange?)` | SEO snapshot | Top queries, pages, device, country breakdown | | `keywordAnalysis(dateRange?)` | Keyword deep-dive | Queries with device breakdown | | `seoPagePerformance(dateRange?)` | Page SEO metrics | Top pages by clicks, country breakdown | ### Indexing | Function | Purpose | |----------|---------| | `reindexUrls(urls)` | Request re-indexing for multiple URLs | | `checkIndexStatus(urls)` | Check if URLs are indexed | ### Utility | Function | Purpose | |----------|---------| | `getAvailableFields()` | List all available GA4 dimensions and metrics | ### Individual API Functions For granular control, import specific functions from the API modules. See [references/api-reference.md](references/api-reference.md) for the complete list of 30+ API functions with parameters, types, and examples. ## Date Ranges All functions accept flexible date range formats: | Format | Example | Description | |--------|---------|-------------| | Shorthand | `"7d"`, `"30d"`, `"90d"` | Days ago to today | | Explicit | `{startDate: "2024-01-01", endDate: "2024-01-31"}` | Specific dates | | GA4 relative | `{startDate: "30daysAgo", endDate: "today"}` | GA4 relative format | Default is `"30d"` (configurable via `GA4_DEFAULT_DATE_RANGE` in `.env`). ## Results Storage Results auto-save to `results/` with this structure: ``` results/ ├── reports/ # GA4 standard reports ├── realtime/ # Real-time snapshots ├── searchconsole/ # Search Console data ├── indexing/ # Indexing API results └── summaries/ # Human-readable markdown summaries ``` ### Managing Results ```typescript import { listResults, loadResult, getLatestResult } from './scripts/src/index.js'; // List recent results const files = listResults('reports', 10); // Load a specific result const data = loadResult(files[0]); // Get most recent result for an operation const latest = getLatestResult('reports', 'site_overview'); ``` ## Common Dimensions and Metrics ### Dimensions `pagePath`, `pageTitle`, `sessionSource`, `sessionMedium`, `country`, `deviceCategory`, `browser`, `date`, `eventName`, `landingPage`, `newVsReturning` ### Metrics `screenPageViews`, `activeUsers`, `sessions`, `newUsers`, `bounceRate`, `averageSessionDuration`, `engagementRate`, `conversions`, `totalRevenue`, `eventCount` ## Tips 1. **Specify date ranges** — "last 7 days" or "last 90 days" gives different insights than the default 30 days 2. **Request summaries** — After pulling data, ask for a markdown summary with tables and insights 3. **Compare periods** — Use `compareDateRanges()` to spot trends (this month vs last month) 4. **Check real-time data** — `liveSnapshot()` shows who's on the site right now 5. **Combine GA4 + Search Console** — Traffic data plus search query data gives the full picture

path: references/api-reference.md
content: # API Reference

Complete function reference for all GA4 Analytics Toolkit modules.

## Table of Contents

- [Reports API](#reports-api) (7 functions)
- [Realtime API](#realtime-api) (4 functions)
- [Metadata API](#metadata-api) (3 functions)
- [Search Console API](#search-console-api) (6 functions)
- [Indexing API](#indexing-api) (4 functions)
- [Bulk Lookup API](#bulk-lookup-api) (3 functions)
- [Storage](#storage) (4 functions)

---

## Reports API

Import: `from './api/reports.js'`

### `parseDateRange(range?)`

Parse shorthand date range (e.g., "7d", "30d") to GA4 date range format.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `range` | `string \| DateRange \| undefined` | Settings default | Date range to parse |

**Returns:** `DateRange` — `{startDate: string, endDate: string}`

### `runReport(options)`

Run a custom GA4 report with arbitrary dimensions and metrics.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `options.dimensions` | `string[]` | required | GA4 dimension names |
| `options.metrics` | `string[]` | required | GA4 metric names |
| `options.dateRange` | `string \| DateRange` | `"30d"` | Date range |
| `options.filters` | `Record<string, string>` | `undefined` | Dimension filters |
| `options.orderBy` | `string[]` | `undefined` | Sort order |
| `options.limit` | `number` | `undefined` | Row limit |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<ReportResponse>` — Rows with dimension and metric values.

### `getPageViews(dateRange?)`

Get page view data with paths, titles, users, and session duration.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `pagePath`, `pageTitle`
**Metrics:** `screenPageViews`, `activeUsers`, `averageSessionDuration`

### `getTrafficSources(dateRange?)`

Get traffic source data by source, medium, and campaign.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `sessionSource`, `sessionMedium`, `sessionCampaignName`
**Metrics:** `sessions`, `activeUsers`, `newUsers`, `bounceRate`

### `getUserDemographics(dateRange?)`

Get user demographic data by country, device, and browser.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `country`, `deviceCategory`, `browser`
**Metrics:** `activeUsers`, `sessions`, `newUsers`

### `getEventCounts(dateRange?)`

Get event count data by event name.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `eventName`
**Metrics:** `eventCount`, `eventCountPerUser`, `activeUsers`

### `getConversions(dateRange?)`

Get conversion data by event name and source.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `eventName`, `sessionSource`
**Metrics:** `conversions`, `totalRevenue`

### `getEcommerceRevenue(dateRange?)`

Get e-commerce revenue data by date and transaction.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| DateRange` | `"30d"` | Date range |

**Dimensions:** `date`, `transactionId`
**Metrics:** `totalRevenue`, `ecommercePurchases`, `averagePurchaseRevenue`

---

## Realtime API

Import: `from './api/realtime.js'`

### `getActiveUsers(save?)`

Get current active users by screen/page name.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<RealtimeResponse>` — Active users by `unifiedScreenName`.

### `getRealtimeEvents(save?)`

Get currently firing events.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<RealtimeResponse>` — Event counts by `eventName`.

### `getRealtimePages(save?)`

Get currently viewed pages.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<RealtimeResponse>` — Page views by `unifiedScreenName`.

### `getRealtimeSources(save?)`

Get current traffic sources.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<RealtimeResponse>` — Active users by `firstUserSource` and `firstUserMedium`.

---

## Metadata API

Import: `from './api/metadata.js'`

### `getAvailableDimensions(save?)`

Get all available dimensions for the GA4 property.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<MetadataResponse>` — Array of `{apiName, uiName, description}`.

### `getAvailableMetrics(save?)`

Get all available metrics for the GA4 property.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<MetadataResponse>` — Array of `{apiName, uiName, description}`.

### `getPropertyMetadata(save?)`

Get full property metadata (dimensions + metrics combined).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<MetadataResponse>` — Full metadata response.

---

## Search Console API

Import: `from './api/searchConsole.js'`

### `querySearchAnalytics(options)`

Run a custom Search Console analytics query.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `options.dimensions` | `string[]` | `["query"]` | Dimensions: `query`, `page`, `device`, `country`, `searchAppearance` |
| `options.dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |
| `options.rowLimit` | `number` | `1000` | Max rows |
| `options.startRow` | `number` | `0` | Pagination offset |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<SearchAnalyticsResponse>` — Rows with `{keys, clicks, impressions, ctr, position}`.

### `getTopQueries(dateRange?)`

Get top 100 search queries by clicks.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |

**Returns:** `Promise<SearchAnalyticsResponse>`

### `getTopPages(dateRange?)`

Get top 100 pages by search impressions.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |

**Returns:** `Promise<SearchAnalyticsResponse>`

### `getDevicePerformance(dateRange?)`

Get search performance breakdown by device type (desktop, mobile, tablet).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |

**Returns:** `Promise<SearchAnalyticsResponse>`

### `getCountryPerformance(dateRange?)`

Get search performance by country (top 50).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |

**Returns:** `Promise<SearchAnalyticsResponse>`

### `getSearchAppearance(dateRange?)`

Get search appearance data (rich results, AMP, etc.).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dateRange` | `string \| SearchConsoleDateRange` | `"30d"` | Date range |

**Returns:** `Promise<SearchAnalyticsResponse>`

---

## Indexing API

Import: `from './api/indexing.js'`

### `requestIndexing(url, options?)`

Request Google to re-crawl a single URL.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | `string` | required | Full URL to request indexing for |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<UrlNotificationResult>` — `{url, type: 'URL_UPDATED', notifyTime}`.

### `requestIndexingBatch(urls, options?)`

Request re-crawling for multiple URLs (processed sequentially to avoid rate limits).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | `string[]` | required | Array of URLs |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<UrlNotificationResult[]>`

### `removeFromIndex(url, options?)`

Request URL removal from Google's index.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | `string` | required | URL to remove |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<UrlNotificationResult>` — `{url, type: 'URL_DELETED', notifyTime}`.

### `inspectUrl(url, options?)`

Check a URL's index status, mobile usability, and rich results.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | `string` | required | URL to inspect |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<UrlInspectionResult>` — Contains `indexStatus.verdict` ('PASS' | 'FAIL' | 'NEUTRAL'), `coverageState`, `lastCrawlTime`, `mobileUsability`, `richResults`.

---

## Bulk Lookup API

Import: `from './api/bulk-lookup.js'`

### `normalizeUrls(urls)`

Normalize page paths: trim whitespace, add leading slash.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | `string[]` | required | Array of page paths |

**Returns:** `string[]` — Normalized paths.

### `buildUrlFilter(urls)`

Build a GA4 dimension filter expression for a list of page paths.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | `string[]` | required | Normalized page paths |

**Returns:** `DimensionFilterExpression | null`

### `getMetricsForUrls(urls, options?)`

Get GA4 metrics for specific page paths (bulk lookup).

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | `string[]` | required | Page paths (e.g., `["/pricing", "/about"]`) |
| `options.dateRange` | `string \| DateRange` | `"30d"` | Date range |
| `options.metrics` | `string[]` | `["screenPageViews", "activeUsers", "averageSessionDuration", "bounceRate", "engagementRate"]` | Metrics to retrieve |
| `options.save` | `boolean` | `true` | Save results to JSON |

**Returns:** `Promise<ReportResponse>` — Metrics for each URL.

---

## Storage

Import: `from './core/storage.js'`

### `saveResult<T>(data, category, operation, extraInfo?)`

Save result data to a timestamped JSON file with metadata wrapper.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `data` | `T` | required | Data to save |
| `category` | `string` | required | Category directory (e.g., `"reports"`, `"realtime"`) |
| `operation` | `string` | required | Operation name (e.g., `"page_views"`) |
| `extraInfo` | `string` | `undefined` | Optional extra info for filename |

**Returns:** `string` — Full path to the saved file.

### `loadResult<T>(filepath)`

Load a previously saved result from a JSON file.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `filepath` | `string` | required | Path to the JSON file |

**Returns:** `SavedResult<T> | null`

### `listResults(category, limit?)`

List saved result files for a category, sorted newest first.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `category` | `string` | required | Category to list |
| `limit` | `number` | `undefined` | Max results to return |

**Returns:** `string[]` — Array of file paths.

### `getLatestResult<T>(category, operation?)`

Get the most recent result for a category, optionally filtered by operation.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `category` | `string` | required | Category to search |
| `operation` | `string` | `undefined` | Filter by operation name |

**Returns:** `SavedResult<T> | null`


path: scripts/package-lock.json
content: {
  "name": "ga4-toolkit",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "ga4-toolkit",
      "version": "1.0.0",
      "dependencies": {
        "@google-analytics/data": "^4.9.0",
        "@googleapis/indexing": "^6.0.1",
        "@googleapis/searchconsole": "^6.0.1",
        "dotenv": "^16.4.7",
        "googleapis": "^170.0.0",
        "tsx": "^4.19.2",
        "typescript": "^5.7.2"
      },
      "engines": {
        "node": ">=18.0.0"
      }
    },
    "node_modules/@esbuild/aix-ppc64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "ppc64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "aix"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/android-arm": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/android-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/android-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/darwin-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/darwin-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/freebsd-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/freebsd-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-arm": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-ia32": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "ia32"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-loong64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "loong64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-mips64el": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "mips64el"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-ppc64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "ppc64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-riscv64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "riscv64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-s390x": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "s390x"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/linux-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/netbsd-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "netbsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/netbsd-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "netbsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/openbsd-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "openbsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/openbsd-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "openbsd"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/openharmony-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "openharmony"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/sunos-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "sunos"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/win32-arm64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/win32-ia32": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "ia32"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@esbuild/win32-x64": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@google-analytics/data": {
      "version": "4.12.1",
      "resolved": "https://registry.npmjs.org/@google-analytics/data/-/data-4.12.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "google-gax": "^4.0.3"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/@googleapis/indexing": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/@googleapis/indexing/-/indexing-6.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "googleapis-common": "^8.0.0"
      },
      "engines": {
        "node": ">=12.0.0"
      }
    },
    "node_modules/@googleapis/searchconsole": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/@googleapis/searchconsole/-/searchconsole-6.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "googleapis-common": "^8.0.0"
      },
      "engines": {
        "node": ">=12.0.0"
      }
    },
    "node_modules/@grpc/grpc-js": {
      "version": "1.14.3",
      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@grpc/proto-loader": "^0.8.0",
        "@js-sdsl/ordered-map": "^4.4.2"
      },
      "engines": {
        "node": ">=12.10.0"
      }
    },
    "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": {
      "version": "0.8.0",
      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "lodash.camelcase": "^4.3.0",
        "long": "^5.0.0",
        "protobufjs": "^7.5.3",
        "yargs": "^17.7.2"
      },
      "bin": {
        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/@grpc/proto-loader": {
      "version": "0.7.15",
      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "lodash.camelcase": "^4.3.0",
        "long": "^5.0.0",
        "protobufjs": "^7.2.5",
        "yargs": "^17.7.2"
      },
      "bin": {
        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/@isaacs/cliui": {
      "version": "8.0.2",
      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "string-width": "^5.1.2",
        "string-width-cjs": "npm:string-width@^4.2.0",
        "strip-ansi": "^7.0.1",
        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
        "wrap-ansi": "^8.1.0",
        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
      "version": "6.2.2",
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
      }
    },
    "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
      "version": "6.2.3",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
      }
    },
    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
      "version": "9.2.2",
      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@isaacs/cliui/node_modules/string-width": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "eastasianwidth": "^0.2.0",
        "emoji-regex": "^9.2.2",
        "strip-ansi": "^7.0.1"
      },
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
      "version": "7.1.2",
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-regex": "^6.0.1"
      },
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
      }
    },
    "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
      "version": "8.1.0",
      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-styles": "^6.1.0",
        "string-width": "^5.0.1",
        "strip-ansi": "^7.0.1"
      },
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
      }
    },
    "node_modules/@js-sdsl/ordered-map": {
      "version": "4.4.2",
      "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/js-sdsl"
      }
    },
    "node_modules/@pkgjs/parseargs": {
      "version": "0.11.0",
      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/@protobufjs/aspromise": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/base64": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/codegen": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/eventemitter": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/fetch": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "@protobufjs/aspromise": "^1.1.1",
        "@protobufjs/inquire": "^1.1.0"
      }
    },
    "node_modules/@protobufjs/float": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/inquire": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/path": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/pool": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@protobufjs/utf8": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/@tootallnate/once": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@types/caseless": {
      "version": "0.12.5",
      "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@types/long": {
      "version": "4.0.2",
      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/@types/node": {
      "version": "25.0.10",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "undici-types": "~7.16.0"
      }
    },
    "node_modules/@types/request": {
      "version": "2.48.13",
      "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/caseless": "*",
        "@types/node": "*",
        "@types/tough-cookie": "*",
        "form-data": "^2.5.5"
      }
    },
    "node_modules/@types/tough-cookie": {
      "version": "4.0.5",
      "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/abort-controller": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "event-target-shim": "^5.0.0"
      },
      "engines": {
        "node": ">=6.5"
      }
    },
    "node_modules/agent-base": {
      "version": "7.1.4",
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 14"
      }
    },
    "node_modules/ansi-regex": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/ansi-styles": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "color-convert": "^2.0.1"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
      }
    },
    "node_modules/asynckit": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/balanced-match": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/base64-js": {
      "version": "1.5.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/bignumber.js": {
      "version": "9.3.1",
      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/brace-expansion": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "balanced-match": "^1.0.0"
      }
    },
    "node_modules/buffer-equal-constant-time": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause"
    },
    "node_modules/call-bind-apply-helpers": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/call-bound": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "get-intrinsic": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/cliui": {
      "version": "8.0.1",
      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "string-width": "^4.2.0",
        "strip-ansi": "^6.0.1",
        "wrap-ansi": "^7.0.0"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/color-convert": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "color-name": "~1.1.4"
      },
      "engines": {
        "node": ">=7.0.0"
      }
    },
    "node_modules/color-name": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/combined-stream": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "delayed-stream": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/cross-spawn": {
      "version": "7.0.6",
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "path-key": "^3.1.0",
        "shebang-command": "^2.0.0",
        "which": "^2.0.1"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/data-uri-to-buffer": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 12"
      }
    },
    "node_modules/debug": {
      "version": "4.4.3",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/delayed-stream": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/dotenv": {
      "version": "16.6.1",
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://dotenvx.com"
      }
    },
    "node_modules/dunder-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.1",
        "es-errors": "^1.3.0",
        "gopd": "^1.2.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/duplexify": {
      "version": "4.1.3",
      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "end-of-stream": "^1.4.1",
        "inherits": "^2.0.3",
        "readable-stream": "^3.1.1",
        "stream-shift": "^1.0.2"
      }
    },
    "node_modules/eastasianwidth": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/ecdsa-sig-formatter": {
      "version": "1.0.11",
      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/emoji-regex": {
      "version": "8.0.0",
      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/end-of-stream": {
      "version": "1.4.5",
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "once": "^1.4.0"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-object-atoms": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/esbuild": {
      "version": "0.27.2",
      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "bin": {
        "esbuild": "bin/esbuild"
      },
      "engines": {
        "node": ">=18"
      },
      "optionalDependencies": {
        "@esbuild/aix-ppc64": "0.27.2",
        "@esbuild/android-arm": "0.27.2",
        "@esbuild/android-arm64": "0.27.2",
        "@esbuild/android-x64": "0.27.2",
        "@esbuild/darwin-arm64": "0.27.2",
        "@esbuild/darwin-x64": "0.27.2",
        "@esbuild/freebsd-arm64": "0.27.2",
        "@esbuild/freebsd-x64": "0.27.2",
        "@esbuild/linux-arm": "0.27.2",
        "@esbuild/linux-arm64": "0.27.2",
        "@esbuild/linux-ia32": "0.27.2",
        "@esbuild/linux-loong64": "0.27.2",
        "@esbuild/linux-mips64el": "0.27.2",
        "@esbuild/linux-ppc64": "0.27.2",
        "@esbuild/linux-riscv64": "0.27.2",
        "@esbuild/linux-s390x": "0.27.2",
        "@esbuild/linux-x64": "0.27.2",
        "@esbuild/netbsd-arm64": "0.27.2",
        "@esbuild/netbsd-x64": "0.27.2",
        "@esbuild/openbsd-arm64": "0.27.2",
        "@esbuild/openbsd-x64": "0.27.2",
        "@esbuild/openharmony-arm64": "0.27.2",
        "@esbuild/sunos-x64": "0.27.2",
        "@esbuild/win32-arm64": "0.27.2",
        "@esbuild/win32-ia32": "0.27.2",
        "@esbuild/win32-x64": "0.27.2"
      }
    },
    "node_modules/escalade": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/event-target-shim": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/extend": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fetch-blob": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/jimmywarting"
        },
        {
          "type": "paypal",
          "url": "https://paypal.me/jimmywarting"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "node-domexception": "^1.0.0",
        "web-streams-polyfill": "^3.0.3"
      },
      "engines": {
        "node": "^12.20 || >= 14.13"
      }
    },
    "node_modules/foreground-child": {
      "version": "3.3.1",
      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "cross-spawn": "^7.0.6",
        "signal-exit": "^4.0.1"
      },
      "engines": {
        "node": ">=14"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/form-data": {
      "version": "2.5.5",
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "asynckit": "^0.4.0",
        "combined-stream": "^1.0.8",
        "es-set-tostringtag": "^2.1.0",
        "hasown": "^2.0.2",
        "mime-types": "^2.1.35",
        "safe-buffer": "^5.2.1"
      },
      "engines": {
        "node": ">= 0.12"
      }
    },
    "node_modules/formdata-polyfill": {
      "version": "4.0.10",
      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fetch-blob": "^3.1.2"
      },
      "engines": {
        "node": ">=12.20.0"
      }
    },
    "node_modules/fsevents": {
      "version": "2.3.3",
      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/gaxios": {
      "version": "6.7.1",
      "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "extend": "^3.0.2",
        "https-proxy-agent": "^7.0.1",
        "is-stream": "^2.0.0",
        "node-fetch": "^2.6.9",
        "uuid": "^9.0.1"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/gcp-metadata": {
      "version": "6.1.1",
      "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "gaxios": "^6.1.1",
        "google-logging-utils": "^0.0.2",
        "json-bigint": "^1.0.0"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/get-caller-file": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": "6.* || 8.* || >= 10.*"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "es-define-property": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "function-bind": "^1.1.2",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "has-symbols": "^1.1.0",
        "hasown": "^2.0.2",
        "math-intrinsics": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/get-tsconfig": {
      "version": "4.13.0",
      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "resolve-pkg-maps": "^1.0.0"
      },
      "funding": {
        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
      }
    },
    "node_modules/glob": {
      "version": "10.5.0",
      "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "foreground-child": "^3.1.0",
        "jackspeak": "^3.1.2",
        "minimatch": "^9.0.4",
        "minipass": "^7.1.2",
        "package-json-from-dist": "^1.0.0",
        "path-scurry": "^1.11.1"
      },
      "bin": {
        "glob": "dist/esm/bin.mjs"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/google-auth-library": {
      "version": "9.15.1",
      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "base64-js": "^1.3.0",
        "ecdsa-sig-formatter": "^1.0.11",
        "gaxios": "^6.1.1",
        "gcp-metadata": "^6.1.0",
        "gtoken": "^7.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/google-gax": {
      "version": "4.6.1",
      "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.6.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "@grpc/grpc-js": "^1.10.9",
        "@grpc/proto-loader": "^0.7.13",
        "@types/long": "^4.0.0",
        "abort-controller": "^3.0.0",
        "duplexify": "^4.0.0",
        "google-auth-library": "^9.3.0",
        "node-fetch": "^2.7.0",
        "object-hash": "^3.0.0",
        "proto3-json-serializer": "^2.0.2",
        "protobufjs": "^7.3.2",
        "retry-request": "^7.0.0",
        "uuid": "^9.0.1"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/google-logging-utils": {
      "version": "0.0.2",
      "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/googleapis": {
      "version": "170.1.0",
      "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-170.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "google-auth-library": "^10.2.0",
        "googleapis-common": "^8.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis-common": {
      "version": "8.0.1",
      "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-8.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "extend": "^3.0.2",
        "gaxios": "^7.0.0-rc.4",
        "google-auth-library": "^10.1.0",
        "qs": "^6.7.0",
        "url-template": "^2.0.8"
      },
      "engines": {
        "node": ">=18.0.0"
      }
    },
    "node_modules/googleapis-common/node_modules/gaxios": {
      "version": "7.1.3",
      "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "extend": "^3.0.2",
        "https-proxy-agent": "^7.0.1",
        "node-fetch": "^3.3.2",
        "rimraf": "^5.0.1"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis-common/node_modules/gcp-metadata": {
      "version": "8.1.2",
      "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "gaxios": "^7.0.0",
        "google-logging-utils": "^1.0.0",
        "json-bigint": "^1.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis-common/node_modules/google-auth-library": {
      "version": "10.5.0",
      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "base64-js": "^1.3.0",
        "ecdsa-sig-formatter": "^1.0.11",
        "gaxios": "^7.0.0",
        "gcp-metadata": "^8.0.0",
        "google-logging-utils": "^1.0.0",
        "gtoken": "^8.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis-common/node_modules/google-logging-utils": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/googleapis-common/node_modules/gtoken": {
      "version": "8.0.0",
      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "gaxios": "^7.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis-common/node_modules/node-fetch": {
      "version": "3.3.2",
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "data-uri-to-buffer": "^4.0.0",
        "fetch-blob": "^3.1.4",
        "formdata-polyfill": "^4.0.10"
      },
      "engines": {
        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/node-fetch"
      }
    },
    "node_modules/googleapis/node_modules/gaxios": {
      "version": "7.1.3",
      "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "extend": "^3.0.2",
        "https-proxy-agent": "^7.0.1",
        "node-fetch": "^3.3.2",
        "rimraf": "^5.0.1"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis/node_modules/gcp-metadata": {
      "version": "8.1.2",
      "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "gaxios": "^7.0.0",
        "google-logging-utils": "^1.0.0",
        "json-bigint": "^1.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis/node_modules/google-auth-library": {
      "version": "10.5.0",
      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "base64-js": "^1.3.0",
        "ecdsa-sig-formatter": "^1.0.11",
        "gaxios": "^7.0.0",
        "gcp-metadata": "^8.0.0",
        "google-logging-utils": "^1.0.0",
        "gtoken": "^8.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis/node_modules/google-logging-utils": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/googleapis/node_modules/gtoken": {
      "version": "8.0.0",
      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "gaxios": "^7.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/googleapis/node_modules/node-fetch": {
      "version": "3.3.2",
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "data-uri-to-buffer": "^4.0.0",
        "fetch-blob": "^3.1.4",
        "formdata-polyfill": "^4.0.10"
      },
      "engines": {
        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/node-fetch"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/gtoken": {
      "version": "7.1.0",
      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "gaxios": "^6.0.0",
        "jws": "^4.0.0"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "has-symbols": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hasown": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/http-proxy-agent": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@tootallnate/once": "2",
        "agent-base": "6",
        "debug": "4"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/http-proxy-agent/node_modules/agent-base": {
      "version": "6.0.2",
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "debug": "4"
      },
      "engines": {
        "node": ">= 6.0.0"
      }
    },
    "node_modules/https-proxy-agent": {
      "version": "7.0.6",
      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "agent-base": "^7.1.2",
        "debug": "4"
      },
      "engines": {
        "node": ">= 14"
      }
    },
    "node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/is-fullwidth-code-point": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/is-stream": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/isexe": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/jackspeak": {
      "version": "3.4.3",
      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BlueOak-1.0.0",
      "dependencies": {
        "@isaacs/cliui": "^8.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      },
      "optionalDependencies": {
        "@pkgjs/parseargs": "^0.11.0"
      }
    },
    "node_modules/json-bigint": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "bignumber.js": "^9.0.0"
      }
    },
    "node_modules/jwa": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "buffer-equal-constant-time": "^1.0.1",
        "ecdsa-sig-formatter": "1.0.11",
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/jws": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "jwa": "^2.0.1",
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/lodash.camelcase": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/long": {
      "version": "5.3.2",
      "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0"
    },
    "node_modules/lru-cache": {
      "version": "10.4.3",
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/math-intrinsics": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/mime-db": {
      "version": "1.52.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.35",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "mime-db": "1.52.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/minimatch": {
      "version": "9.0.5",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "brace-expansion": "^2.0.1"
      },
      "engines": {
        "node": ">=16 || 14 >=14.17"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/minipass": {
      "version": "7.1.2",
      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">=16 || 14 >=14.17"
      }
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/node-domexception": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "Use your platform's native DOMException instead",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/jimmywarting"
        },
        {
          "type": "github",
          "url": "https://paypal.me/jimmywarting"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=10.5.0"
      }
    },
    "node_modules/node-fetch": {
      "version": "2.7.0",
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "whatwg-url": "^5.0.0"
      },
      "engines": {
        "node": "4.x || >=6.0.0"
      },
      "peerDependencies": {
        "encoding": "^0.1.0"
      },
      "peerDependenciesMeta": {
        "encoding": {
          "optional": true
        }
      }
    },
    "node_modules/object-hash": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/object-inspect": {
      "version": "1.13.4",
      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/once": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "wrappy": "1"
      }
    },
    "node_modules/package-json-from-dist": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BlueOak-1.0.0"
    },
    "node_modules/path-key": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/path-scurry": {
      "version": "1.11.1",
      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BlueOak-1.0.0",
      "dependencies": {
        "lru-cache": "^10.2.0",
        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
      },
      "engines": {
        "node": ">=16 || 14 >=14.18"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/proto3-json-serializer": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "protobufjs": "^7.2.5"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/protobufjs": {
      "version": "7.5.4",
      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
      "integrity": [REDACTED_SECRET],
      "hasInstallScript": true,
      "license": "BSD-3-Clause",
      "dependencies": {
        "@protobufjs/aspromise": "^1.1.2",
        "@protobufjs/base64": "^1.1.2",
        "@protobufjs/codegen": "^2.0.4",
        "@protobufjs/eventemitter": "^1.1.0",
        "@protobufjs/fetch": "^1.1.0",
        "@protobufjs/float": "^1.0.2",
        "@protobufjs/inquire": "^1.1.0",
        "@protobufjs/path": "^1.1.2",
        "@protobufjs/pool": "^1.1.0",
        "@protobufjs/utf8": "^1.1.0",
        "@types/node": ">=13.7.0",
        "long": "^5.0.0"
      },
      "engines": {
        "node": ">=12.0.0"
      }
    },
    "node_modules/qs": {
      "version": "6.14.1",
      "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "side-channel": "^1.1.0"
      },
      "engines": {
        "node": ">=0.6"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/readable-stream": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "inherits": "^2.0.3",
        "string_decoder": "^1.1.1",
        "util-deprecate": "^1.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/require-directory": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/resolve-pkg-maps": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
      }
    },
    "node_modules/retry-request": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/request": "^2.48.8",
        "extend": "^3.0.2",
        "teeny-request": "^9.0.0"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/rimraf": {
      "version": "5.0.10",
      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "glob": "^10.3.7"
      },
      "bin": {
        "rimraf": "dist/esm/bin.mjs"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/safe-buffer": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/shebang-command": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "shebang-regex": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/shebang-regex": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/side-channel": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.3",
        "side-channel-list": "^1.0.0",
        "side-channel-map": "^1.0.1",
        "side-channel-weakmap": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-list": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-map": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-weakmap": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3",
        "side-channel-map": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/signal-exit": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">=14"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/stream-events": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "stubs": "^3.0.0"
      }
    },
    "node_modules/stream-shift": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/string_decoder": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "~5.2.0"
      }
    },
    "node_modules/string-width": {
      "version": "4.2.3",
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "emoji-regex": "^8.0.0",
        "is-fullwidth-code-point": "^3.0.0",
        "strip-ansi": "^6.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/string-width-cjs": {
      "name": "string-width",
      "version": "4.2.3",
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "emoji-regex": "^8.0.0",
        "is-fullwidth-code-point": "^3.0.0",
        "strip-ansi": "^6.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/strip-ansi": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-regex": "^5.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/strip-ansi-cjs": {
      "name": "strip-ansi",
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-regex": "^5.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/stubs": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/teeny-request": {
      "version": "9.0.0",
      "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "http-proxy-agent": "^5.0.0",
        "https-proxy-agent": "^5.0.0",
        "node-fetch": "^2.6.9",
        "stream-events": "^1.0.5",
        "uuid": "^9.0.0"
      },
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/teeny-request/node_modules/agent-base": {
      "version": "6.0.2",
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "debug": "4"
      },
      "engines": {
        "node": ">= 6.0.0"
      }
    },
    "node_modules/teeny-request/node_modules/https-proxy-agent": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "agent-base": "6",
        "debug": "4"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/tr46": {
      "version": "0.0.3",
      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/tsx": {
      "version": "4.21.0",
      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "esbuild": "~0.27.0",
        "get-tsconfig": "^4.7.5"
      },
      "bin": {
        "tsx": "dist/cli.mjs"
      },
      "engines": {
        "node": ">=18.0.0"
      },
      "optionalDependencies": {
        "fsevents": "~2.3.3"
      }
    },
    "node_modules/typescript": {
      "version": "5.9.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/undici-types": {
      "version": "7.16.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/url-template": {
      "version": "2.0.8",
      "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD"
    },
    "node_modules/util-deprecate": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/uuid": {
      "version": "9.0.1",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        "https://github.com/sponsors/broofa",
        "https://github.com/sponsors/ctavan"
      ],
      "license": "MIT",
      "bin": {
        "uuid": "dist/bin/uuid"
      }
    },
    "node_modules/web-streams-polyfill": {
      "version": "3.3.3",
      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/webidl-conversions": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-2-Clause"
    },
    "node_modules/whatwg-url": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "tr46": "~0.0.3",
        "webidl-conversions": "^3.0.0"
      }
    },
    "node_modules/which": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "dependencies": {
        "isexe": "^2.0.0"
      },
      "bin": {
        "node-which": "bin/node-which"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/wrap-ansi": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-styles": "^4.0.0",
        "string-width": "^4.1.0",
        "strip-ansi": "^6.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
      }
    },
    "node_modules/wrap-ansi-cjs": {
      "name": "wrap-ansi",
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ansi-styles": "^4.0.0",
        "string-width": "^4.1.0",
        "strip-ansi": "^6.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
      }
    },
    "node_modules/wrappy": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/y18n": {
      "version": "5.0.8",
      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/yargs": {
      "version": "17.7.2",
      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "cliui": "^8.0.1",
        "escalade": "^3.1.1",
        "get-caller-file": "^2.0.5",
        "require-directory": "^2.1.1",
        "string-width": "^4.2.3",
        "y18n": "^5.0.5",
        "yargs-parser": "^21.1.1"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/yargs-parser": {
      "version": "21.1.1",
      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">=12"
      }
    }
  }
}


path: scripts/package.json
content: {
  "name": "ga4-toolkit",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "@google-analytics/data": "^4.9.0",
    "@googleapis/indexing": "^6.0.1",
    "@googleapis/searchconsole": "^6.0.1",
    "dotenv": "^16.4.7",
    "googleapis": "^170.0.0",
    "tsx": "^4.19.2",
    "typescript": "^5.7.2"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}


path: scripts/setup.sh
content: #!/bin/bash
cd "$(dirname "$0")" && npm install


path: scripts/src/api/bulk-lookup.ts
content: /**
 * Bulk URL Lookup - Get GA4 metrics for specific page paths
 *
 * This module provides a convenient way to look up analytics data
 * for a list of specific URLs, similar to a bulk URL lookup field.
 */

import { getClient, getPropertyId } from '../core/client.js';
import { saveResult } from '../core/storage.js';
import { getSettings } from '../config/settings.js';
import type { ReportResponse, DateRange } from './reports.js';

/**
 * Options for bulk URL lookup
 */
export interface BulkLookupOptions {
  /** Date range (e.g., "7d", "30d") or explicit dates */
  dateRange?: string | DateRange;
  /** Custom metrics to retrieve (defaults to standard page metrics) */
  metrics?: string[];
  /** Whether to save results to file (default: true) */
  save?: boolean;
}

/**
 * Dimension filter expression for GA4 API
 */
export interface DimensionFilterExpression {
  filter: {
    fieldName: string;
    inListFilter?: {
      values: string[];
      caseSensitive?: boolean;
    };
    stringFilter?: {
      matchType: string;
      value: string;
      caseSensitive?: boolean;
    };
  };
}

/**
 * Default metrics for bulk URL lookup
 */
const DEFAULT_METRICS = [
  'screenPageViews',
  'activeUsers',
  'averageSessionDuration',
  'bounceRate',
  'engagementRate',
];

/**
 * Normalize URLs to ensure consistent format
 *
 * - Trims whitespace
 * - Adds leading slash if missing
 * - Preserves trailing slashes
 *
 * @param urls - Array of URLs to normalize
 * @returns Normalized URL array
 */
export function normalizeUrls(urls: string[]): string[] {
  return urls.map(url => {
    // Trim whitespace
    let normalized = url.trim();

    // Add leading slash if missing
    if (!normalized.startsWith('/')) {
      normalized = '/' + normalized;
    }

    return normalized;
  });
}

/**
 * Build a dimension filter expression for the given URLs
 *
 * @param urls - Array of page paths to filter by
 * @returns Filter expression or null if no URLs provided
 */
export function buildUrlFilter(urls: string[]): DimensionFilterExpression | null {
  if (urls.length === 0) {
    return null;
  }

  return {
    filter: {
      fieldName: 'pagePath',
      inListFilter: {
        values: urls,
        caseSensitive: false,
      },
    },
  };
}

/**
 * Parse shorthand date range (e.g., "7d", "30d") to GA4 date range format
 */
function parseDateRange(range: string | DateRange | undefined): DateRange {
  if (!range) {
    const settings = getSettings();
    range = settings.defaultDateRange;
  }

  if (typeof range === 'object') {
    return range;
  }

  // Parse shorthand like "7d", "30d", "90d"
  const match = range.match(/^(\d+)d$/);
  if (match) {
    const days = parseInt(match[1], 10);
    return {
      startDate: `${days}daysAgo`,
      endDate: 'today',
    };
  }

  // Default to 30 days
  return {
    startDate: '30daysAgo',
    endDate: 'today',
  };
}

/**
 * Get GA4 metrics for specific page paths (bulk URL lookup)
 *
 * @param urls - Array of page paths to look up (e.g., ['/pricing', '/about'])
 * @param options - Optional configuration
 * @returns Report response with metrics for the specified URLs
 *
 * @example
 * ```typescript
 * // Get metrics for specific pages
 * const result = await getMetricsForUrls(['/pricing', '/about', '/blog']);
 *
 * // With custom date range and metrics
 * const result = await getMetricsForUrls(['/pricing'], {
 *   dateRange: '7d',
 *   metrics: ['sessions', 'bounceRate'],
 * });
 * ```
 */
export async function getMetricsForUrls(
  urls: string[],
  options: BulkLookupOptions = {}
): Promise<ReportResponse> {
  const { dateRange, metrics = DEFAULT_METRICS, save = true } = options;

  // Normalize URLs
  const normalizedUrls = normalizeUrls(urls);

  // Handle empty URL array
  if (normalizedUrls.length === 0) {
    return {
      rows: [],
      rowCount: 0,
    };
  }

  // Build filter
  const dimensionFilter = buildUrlFilter(normalizedUrls);

  // Get client and property
  const client = getClient();
  const property = getPropertyId();
  const parsedDateRange = parseDateRange(dateRange);

  // Build and execute request
  const request = {
    property,
    dateRanges: [parsedDateRange],
    dimensions: [{ name: 'pagePath' }, { name: 'pageTitle' }],
    metrics: metrics.map(name => ({ name })),
    dimensionFilter,
  };

  const [response] = await client.runReport(request);

  // Save results if requested
  if (save) {
    const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
    saveResult(response, 'reports', 'bulk_url_lookup', dateStr);
  }

  return response as ReportResponse;
}


path: scripts/src/api/indexing.ts
content: /**
 * Indexing API - Request re-indexing and URL inspection
 */

import { getIndexingClient, getSearchConsoleClient, getSiteUrl } from '../core/client.js';
import { saveResult } from '../core/storage.js';

/**
 * Indexing request options
 */
export interface IndexingOptions {
  save?: boolean;
}

/**
 * URL notification result
 */
export interface UrlNotificationResult {
  url: string;
  type: 'URL_UPDATED' | 'URL_DELETED';
  notifyTime: string;
}

/**
 * URL inspection result
 */
export interface UrlInspectionResult {
  inspectionResultLink?: string;
  indexStatus: {
    verdict: 'PASS' | 'FAIL' | 'NEUTRAL';
    coverageState: string;
    robotsTxtState?: string;
    indexingState?: string;
    lastCrawlTime?: string;
    pageFetchState?: string;
    googleCanonical?: string;
    userCanonical?: string;
    crawledAs?: string;
  };
  mobileUsability?: {
    verdict: string;
    issues?: unknown[];
  };
  richResults?: {
    verdict: string;
    detectedItems?: unknown[];
  };
}

/**
 * Request indexing for a single URL (notify Google to re-crawl)
 *
 * @param url - The URL to request indexing for
 * @param options - Optional settings (save to file, etc.)
 * @returns Notification result with timestamp
 */
export async function requestIndexing(url: string, options: IndexingOptions = {}): Promise<UrlNotificationResult> {
  const { save = true } = options;

  const client = getIndexingClient();

  const response = await client.urlNotifications.publish({
    requestBody: {
      url,
      type: 'URL_UPDATED',
    },
  });

  const result: UrlNotificationResult = {
    url: response.data.urlNotificationMetadata?.url || url,
    type: 'URL_UPDATED',
    notifyTime: response.data.urlNotificationMetadata?.latestUpdate?.notifyTime || new Date().toISOString(),
  };

  if (save) {
    saveResult(result, 'indexing', 'request_indexing');
  }

  return result;
}

/**
 * Request indexing for multiple URLs
 *
 * @param urls - Array of URLs to request indexing for
 * @param options - Optional settings
 * @returns Array of notification results
 */
export async function requestIndexingBatch(urls: string[], options: IndexingOptions = {}): Promise<UrlNotificationResult[]> {
  const { save = true } = options;

  const results: UrlNotificationResult[] = [];

  // Process URLs sequentially to avoid rate limiting
  for (const url of urls) {
    const result = await requestIndexing(url, { save: false });
    results.push(result);
  }

  if (save) {
    saveResult(results, 'indexing', 'batch_indexing');
  }

  return results;
}

/**
 * Request URL removal from index
 *
 * @param url - The URL to request removal for
 * @param options - Optional settings
 * @returns Notification result
 */
export async function removeFromIndex(url: string, options: IndexingOptions = {}): Promise<UrlNotificationResult> {
  const { save = true } = options;

  const client = getIndexingClient();

  const response = await client.urlNotifications.publish({
    requestBody: {
      url,
      type: 'URL_DELETED',
    },
  });

  const result: UrlNotificationResult = {
    url: response.data.urlNotificationMetadata?.url || url,
    type: 'URL_DELETED',
    notifyTime: response.data.urlNotificationMetadata?.latestRemove?.notifyTime || new Date().toISOString(),
  };

  if (save) {
    saveResult(result, 'indexing', 'remove_from_index');
  }

  return result;
}

/**
 * Inspect a URL to check its index status
 *
 * @param url - The URL to inspect
 * @param options - Optional settings
 * @returns URL inspection result with index status
 */
export async function inspectUrl(url: string, options: IndexingOptions = {}): Promise<UrlInspectionResult> {
  const { save = true } = options;

  const client = getSearchConsoleClient();
  const siteUrl = getSiteUrl();

  const response = await client.urlInspection.index.inspect({
    requestBody: {
      inspectionUrl: url,
      siteUrl,
    },
  });

  const inspectionResult = response.data.inspectionResult;

  const result: UrlInspectionResult = {
    inspectionResultLink: inspectionResult?.inspectionResultLink || undefined,
    indexStatus: {
      verdict: (inspectionResult?.indexStatusResult?.verdict as 'PASS' | 'FAIL' | 'NEUTRAL') || 'NEUTRAL',
      coverageState: inspectionResult?.indexStatusResult?.coverageState || 'Unknown',
      robotsTxtState: inspectionResult?.indexStatusResult?.robotsTxtState || undefined,
      indexingState: inspectionResult?.indexStatusResult?.indexingState || undefined,
      lastCrawlTime: inspectionResult?.indexStatusResult?.lastCrawlTime || undefined,
      pageFetchState: inspectionResult?.indexStatusResult?.pageFetchState || undefined,
      googleCanonical: inspectionResult?.indexStatusResult?.googleCanonical || undefined,
      userCanonical: inspectionResult?.indexStatusResult?.userCanonical || undefined,
      crawledAs: inspectionResult?.indexStatusResult?.crawledAs || undefined,
    },
    mobileUsability: inspectionResult?.mobileUsabilityResult
      ? {
          verdict: inspectionResult.mobileUsabilityResult.verdict || 'NEUTRAL',
          issues: inspectionResult.mobileUsabilityResult.issues || [],
        }
      : undefined,
    richResults: inspectionResult?.richResultsResult
      ? {
          verdict: inspectionResult.richResultsResult.verdict || 'NEUTRAL',
          detectedItems: inspectionResult.richResultsResult.detectedItems || [],
        }
      : undefined,
  };

  if (save) {
    saveResult(result, 'indexing', 'url_inspection');
  }

  return result;
}


path: scripts/src/api/metadata.ts
content: /**
 * Metadata API - Available dimensions and metrics
 */

import { getClient, getPropertyId } from '../core/client.js';
import { saveResult } from '../core/storage.js';

/**
 * Dimension metadata
 */
export interface DimensionMetadata {
  apiName: string;
  uiName: string;
  description: string;
}

/**
 * Metric metadata
 */
export interface MetricMetadata {
  apiName: string;
  uiName: string;
  description: string;
}

/**
 * Full property metadata response
 */
export interface MetadataResponse {
  name?: string;
  dimensions?: DimensionMetadata[];
  metrics?: MetricMetadata[];
}

/**
 * Get all available dimensions for the property
 */
export async function getAvailableDimensions(save = true): Promise<MetadataResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.getMetadata({
    name: `${property}/metadata`,
  });

  const result = {
    dimensions: response.dimensions || [],
  };

  if (save) {
    saveResult(result, 'metadata', 'dimensions');
  }

  return result as MetadataResponse;
}

/**
 * Get all available metrics for the property
 */
export async function getAvailableMetrics(save = true): Promise<MetadataResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.getMetadata({
    name: `${property}/metadata`,
  });

  const result = {
    metrics: response.metrics || [],
  };

  if (save) {
    saveResult(result, 'metadata', 'metrics');
  }

  return result as MetadataResponse;
}

/**
 * Get full property metadata (dimensions and metrics)
 */
export async function getPropertyMetadata(save = true): Promise<MetadataResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.getMetadata({
    name: `${property}/metadata`,
  });

  if (save) {
    saveResult(response, 'metadata', 'full');
  }

  return response as MetadataResponse;
}


path: scripts/src/api/realtime.ts
content: /**
 * Realtime API - Live GA4 data
 */

import { getClient, getPropertyId } from '../core/client.js';
import { saveResult } from '../core/storage.js';

/**
 * Realtime report response structure
 */
export interface RealtimeResponse {
  dimensionHeaders?: Array<{ name: string }>;
  metricHeaders?: Array<{ name: string }>;
  rows?: Array<{
    dimensionValues: Array<{ value: string }>;
    metricValues: Array<{ value: string }>;
  }>;
  rowCount?: number;
}

/**
 * Get current active users
 */
export async function getActiveUsers(save = true): Promise<RealtimeResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.runRealtimeReport({
    property,
    dimensions: [{ name: 'unifiedScreenName' }],
    metrics: [{ name: 'activeUsers' }],
  });

  if (save) {
    saveResult(response, 'realtime', 'active_users');
  }

  return response as RealtimeResponse;
}

/**
 * Get current event data
 */
export async function getRealtimeEvents(save = true): Promise<RealtimeResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.runRealtimeReport({
    property,
    dimensions: [{ name: 'eventName' }],
    metrics: [{ name: 'eventCount' }],
  });

  if (save) {
    saveResult(response, 'realtime', 'events');
  }

  return response as RealtimeResponse;
}

/**
 * Get currently viewed pages
 */
export async function getRealtimePages(save = true): Promise<RealtimeResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.runRealtimeReport({
    property,
    dimensions: [{ name: 'unifiedScreenName' }],
    metrics: [{ name: 'screenPageViews' }],
  });

  if (save) {
    saveResult(response, 'realtime', 'pages');
  }

  return response as RealtimeResponse;
}

/**
 * Get realtime traffic sources
 */
export async function getRealtimeSources(save = true): Promise<RealtimeResponse> {
  const client = getClient();
  const property = getPropertyId();

  const [response] = await client.runRealtimeReport({
    property,
    dimensions: [{ name: 'firstUserSource' }, { name: 'firstUserMedium' }],
    metrics: [{ name: 'activeUsers' }],
  });

  if (save) {
    saveResult(response, 'realtime', 'sources');
  }

  return response as RealtimeResponse;
}


path: scripts/src/api/reports.ts
content: /**
 * Reports API - Standard GA4 report generation
 */

import { getClient, getPropertyId } from '../core/client.js';
import { saveResult } from '../core/storage.js';
import { getSettings } from '../config/settings.js';

/**
 * Date range configuration
 */
export interface DateRange {
  startDate: string;
  endDate: string;
}

/**
 * Report options
 */
export interface ReportOptions {
  dimensions: string[];
  metrics: string[];
  dateRange?: string | DateRange;
  filters?: Record<string, string>;
  orderBy?: string[];
  limit?: number;
  save?: boolean;
}

/**
 * Report response structure
 */
export interface ReportResponse {
  dimensionHeaders?: Array<{ name: string }>;
  metricHeaders?: Array<{ name: string }>;
  rows?: Array<{
    dimensionValues: Array<{ value: string }>;
    metricValues: Array<{ value: string }>;
  }>;
  rowCount?: number;
  metadata?: Record<string, unknown>;
}

/**
 * Parse shorthand date range (e.g., "7d", "30d") to GA4 date range format
 */
export function parseDateRange(range: string | DateRange | undefined): DateRange {
  if (!range) {
    const settings = getSettings();
    range = settings.defaultDateRange;
  }

  if (typeof range === 'object') {
    return range;
  }

  // Parse shorthand like "7d", "30d", "90d"
  const match = range.match(/^(\d+)d$/);
  if (match) {
    const days = parseInt(match[1], 10);
    return {
      startDate: `${days}daysAgo`,
      endDate: 'today',
    };
  }

  // Default to 30 days
  return {
    startDate: '30daysAgo',
    endDate: 'today',
  };
}

/**
 * Run a custom GA4 report
 */
export async function runReport(options: ReportOptions): Promise<ReportResponse> {
  const {
    dimensions,
    metrics,
    dateRange,
    filters,
    orderBy,
    limit,
    save = true,
  } = options;

  const client = getClient();
  const property = getPropertyId();
  const parsedDateRange = parseDateRange(dateRange);

  const request = {
    property,
    dateRanges: [parsedDateRange],
    dimensions: dimensions.map(name => ({ name })),
    metrics: metrics.map(name => ({ name })),
    ...(limit && { limit }),
  };

  const [response] = await client.runReport(request);

  if (save) {
    const operation = dimensions.join('_') || 'custom';
    const extra = typeof dateRange === 'string' ? dateRange : undefined;
    saveResult(response, 'reports', operation, extra);
  }

  return response as ReportResponse;
}

/**
 * Get page view data
 */
export async function getPageViews(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['pagePath', 'pageTitle'],
    metrics: ['screenPageViews', 'activeUsers', 'averageSessionDuration'],
    dateRange,
  });
}

/**
 * Get traffic source data
 */
export async function getTrafficSources(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['sessionSource', 'sessionMedium', 'sessionCampaignName'],
    metrics: ['sessions', 'activeUsers', 'newUsers', 'bounceRate'],
    dateRange,
  });
}

/**
 * Get user demographic data (country, device, browser)
 */
export async function getUserDemographics(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['country', 'deviceCategory', 'browser'],
    metrics: ['activeUsers', 'sessions', 'newUsers'],
    dateRange,
  });
}

/**
 * Get event count data
 */
export async function getEventCounts(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['eventName'],
    metrics: ['eventCount', 'eventCountPerUser', 'activeUsers'],
    dateRange,
  });
}

/**
 * Get conversion data
 */
export async function getConversions(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['eventName', 'sessionSource'],
    metrics: ['conversions', 'totalRevenue'],
    dateRange,
  });
}

/**
 * Get e-commerce revenue data
 */
export async function getEcommerceRevenue(dateRange?: string | DateRange): Promise<ReportResponse> {
  return runReport({
    dimensions: ['date', 'transactionId'],
    metrics: ['totalRevenue', 'ecommercePurchases', 'averagePurchaseRevenue'],
    dateRange,
  });
}


path: scripts/src/api/searchConsole.ts
content: /**
 * Search Console API - Google Search Console data retrieval
 */

import { getSearchConsoleClient, getSiteUrl } from '../core/client.js';
import { saveResult } from '../core/storage.js';
import { getSettings } from '../config/settings.js';

/**
 * Date range configuration for Search Console
 */
export interface SearchConsoleDateRange {
  startDate: string;
  endDate: string;
}

/**
 * Search analytics query options
 */
export interface SearchAnalyticsOptions {
  dimensions?: string[];
  dateRange?: string | SearchConsoleDateRange;
  rowLimit?: number;
  startRow?: number;
  save?: boolean;
}

/**
 * Search analytics row structure
 */
export interface SearchAnalyticsRow {
  keys: string[];
  clicks: number;
  impressions: number;
  ctr: number;
  position: number;
}

/**
 * Search analytics response structure
 */
export interface SearchAnalyticsResponse {
  rows?: SearchAnalyticsRow[];
  responseAggregationType?: string;
}

/**
 * Parse shorthand date range (e.g., "7d", "30d") to Search Console date format
 * Note: Search Console requires YYYY-MM-DD format, not GA4's "NdaysAgo" format
 */
export function parseSearchConsoleDateRange(range: string | SearchConsoleDateRange | undefined): SearchConsoleDateRange {
  if (!range) {
    const settings = getSettings();
    range = settings.defaultDateRange;
  }

  if (typeof range === 'object') {
    return range;
  }

  // Parse shorthand like "7d", "30d", "90d"
  const match = range.match(/^(\d+)d$/);
  if (match) {
    const days = parseInt(match[1], 10);
    const endDate = new Date();
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    return {
      startDate: startDate.toISOString().split('T')[0],
      endDate: endDate.toISOString().split('T')[0],
    };
  }

  // Default to 30 days
  const endDate = new Date();
  const startDate = new Date();
  startDate.setDate(startDate.getDate() - 30);

  return {
    startDate: startDate.toISOString().split('T')[0],
    endDate: endDate.toISOString().split('T')[0],
  };
}

/**
 * Query search analytics data
 */
export async function querySearchAnalytics(options: SearchAnalyticsOptions): Promise<SearchAnalyticsResponse> {
  const {
    dimensions = ['query'],
    dateRange,
    rowLimit = 1000,
    startRow = 0,
    save = true,
  } = options;

  const client = getSearchConsoleClient();
  const siteUrl = getSiteUrl();
  const parsedDateRange = parseSearchConsoleDateRange(dateRange);

  const response = await client.searchanalytics.query({
    siteUrl,
    requestBody: {
      startDate: parsedDateRange.startDate,
      endDate: parsedDateRange.endDate,
      dimensions,
      rowLimit,
      startRow,
    },
  });

  const result = response.data as SearchAnalyticsResponse;

  if (save) {
    const operation = dimensions.join('_') || 'query';
    const extra = typeof dateRange === 'string' ? dateRange : undefined;
    saveResult(result, 'searchconsole', operation, extra);
  }

  return result;
}

/**
 * Get top search queries
 */
export async function getTopQueries(dateRange?: string | SearchConsoleDateRange): Promise<SearchAnalyticsResponse> {
  return querySearchAnalytics({
    dimensions: ['query'],
    dateRange,
    rowLimit: 100,
  });
}

/**
 * Get top pages by search performance
 */
export async function getTopPages(dateRange?: string | SearchConsoleDateRange): Promise<SearchAnalyticsResponse> {
  return querySearchAnalytics({
    dimensions: ['page'],
    dateRange,
    rowLimit: 100,
  });
}

/**
 * Get search performance by device type
 */
export async function getDevicePerformance(dateRange?: string | SearchConsoleDateRange): Promise<SearchAnalyticsResponse> {
  return querySearchAnalytics({
    dimensions: ['device'],
    dateRange,
  });
}

/**
 * Get search performance by country
 */
export async function getCountryPerformance(dateRange?: string | SearchConsoleDateRange): Promise<SearchAnalyticsResponse> {
  return querySearchAnalytics({
    dimensions: ['country'],
    dateRange,
    rowLimit: 50,
  });
}

/**
 * Get search appearance data (rich results, AMP, etc.)
 */
export async function getSearchAppearance(dateRange?: string | SearchConsoleDateRange): Promise<SearchAnalyticsResponse> {
  return querySearchAnalytics({
    dimensions: ['searchAppearance'],
    dateRange,
  });
}


path: scripts/src/config/settings.ts
content: /**
 * Settings Module - Environment configuration for GA4 API
 */

import { config } from 'dotenv';
import { join } from 'path';

// Load .env file from current working directory
config();

/**
 * Settings interface for GA4 API configuration
 */
export interface Settings {
  /** GA4 Property ID */
  propertyId: string;
  /** Service account email */
  clientEmail: string;
  /** Service account private key */
  privateKey: string;
  /** Default date range for reports (e.g., "30d", "7d") */
  defaultDateRange: string;
  /** Directory path for storing results */
  resultsDir: string;
  /** Search Console site URL (e.g., "https://example.com") */
  siteUrl: string;
}

/**
 * Validation result from validateSettings()
 */
export interface ValidationResult {
  valid: boolean;
  errors: string[];
}

/**
 * Get current settings from environment variables
 */
export function getSettings(): Settings {
  return {
    propertyId: process.env.GA4_PROPERTY_ID || '',
    clientEmail: process.env.GA4_CLIENT_EMAIL || '',
    privateKey: (process.env.GA4_PRIVATE_KEY || '').replace(/\\n/g, '\n'),
    defaultDateRange: process.env.GA4_DEFAULT_DATE_RANGE || '30d',
    resultsDir: join(process.cwd(), 'results'),
    siteUrl: process.env.SEARCH_CONSOLE_SITE_URL || '',
  };
}

/**
 * Validate that all required settings are present
 */
export function validateSettings(): ValidationResult {
  const settings = getSettings();
  const errors: string[] = [];

  if (!settings.propertyId) {
    errors.push('GA4_PROPERTY_ID is required');
  }

  if (!settings.clientEmail) {
    errors.push('GA4_CLIENT_EMAIL is required');
  }

  if (!settings.privateKey) {
    errors.push('GA4_PRIVATE_KEY is required');
  }

  return {
    valid: errors.length === 0,
    errors,
  };
}


path: scripts/src/core/client.ts
content: /**
 * GA4 API Client - Singleton wrapper for BetaAnalyticsDataClient
 * Also includes Search Console and Indexing API clients
 */

import { BetaAnalyticsDataClient } from '@google-analytics/data';
import { searchconsole } from '@googleapis/searchconsole';
import { indexing } from '@googleapis/indexing';
import { google } from 'googleapis';
import { getSettings, validateSettings } from '../config/settings.js';

// Singleton client instances
let clientInstance: BetaAnalyticsDataClient | null = null;
let searchConsoleClientInstance: ReturnType<typeof searchconsole> | null = null;
let indexingClientInstance: ReturnType<typeof indexing> | null = null;

/**
 * Get the GA4 Analytics Data API client (singleton)
 *
 * @returns The BetaAnalyticsDataClient instance
 * @throws Error if credentials are invalid
 */
export function getClient(): BetaAnalyticsDataClient {
  if (clientInstance) {
    return clientInstance;
  }

  const validation = validateSettings();
  if (!validation.valid) {
    throw new Error(`Invalid GA4 credentials: ${validation.errors.join(', ')}`);
  }

  const settings = getSettings();

  clientInstance = new BetaAnalyticsDataClient({
    credentials: {
      client_email: settings.clientEmail,
      private_key: settings.privateKey,
    },
  });

  return clientInstance;
}

/**
 * Get the GA4 property ID formatted for API calls
 *
 * @returns Property ID with "properties/" prefix
 */
export function getPropertyId(): string {
  const settings = getSettings();
  return `properties/${settings.propertyId}`;
}

/**
 * Reset the client singleton (useful for testing)
 */
export function resetClient(): void {
  clientInstance = null;
  searchConsoleClientInstance = null;
  indexingClientInstance = null;
}

/**
 * Get Google Auth client for Search Console and Indexing APIs
 */
function getGoogleAuth() {
  const settings = getSettings();
  return new google.auth.GoogleAuth({
    credentials: {
      client_email: settings.clientEmail,
      private_key: settings.privateKey,
    },
    scopes: [
      'https://www.googleapis.com/auth/webmasters.readonly',
      'https://www.googleapis.com/auth/indexing',
    ],
  });
}

/**
 * Get the Search Console API client (singleton)
 *
 * @returns The Search Console client instance
 * @throws Error if credentials are invalid
 */
export function getSearchConsoleClient(): ReturnType<typeof searchconsole> {
  if (searchConsoleClientInstance) {
    return searchConsoleClientInstance;
  }

  const validation = validateSettings();
  if (!validation.valid) {
    throw new Error(`Invalid credentials: ${validation.errors.join(', ')}`);
  }

  const auth = getGoogleAuth();
  searchConsoleClientInstance = searchconsole({ version: 'v1', auth });

  return searchConsoleClientInstance;
}

/**
 * Get the Indexing API client (singleton)
 *
 * @returns The Indexing client instance
 * @throws Error if credentials are invalid
 */
export function getIndexingClient(): ReturnType<typeof indexing> {
  if (indexingClientInstance) {
    return indexingClientInstance;
  }

  const validation = validateSettings();
  if (!validation.valid) {
    throw new Error(`Invalid credentials: ${validation.errors.join(', ')}`);
  }

  const auth = getGoogleAuth();
  indexingClientInstance = indexing({ version: 'v3', auth });

  return indexingClientInstance;
}

/**
 * Get the Search Console site URL
 *
 * @returns Site URL from settings
 */
export function getSiteUrl(): string {
  const settings = getSettings();
  return settings.siteUrl;
}


path: scripts/src/core/storage.ts
content: /**
 * Storage Module - Auto-save results to JSON files with metadata
 */

import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
import { join } from 'path';
import { getSettings } from '../config/settings.js';

/**
 * Metadata wrapper for saved results
 */
export interface ResultMetadata {
  savedAt: string;
  category: string;
  operation: string;
  propertyId: string;
  extraInfo?: string;
}

/**
 * Wrapped result with metadata
 */
export interface SavedResult<T = unknown> {
  metadata: ResultMetadata;
  data: T;
}

/**
 * Generate timestamp string for filenames: YYYYMMDD_HHMMSS
 */
function getTimestamp(): string {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');
  return `${year}${month}${day}_${hours}${minutes}${seconds}`;
}

/**
 * Sanitize string for use in filename
 */
function sanitizeFilename(str: string): string {
  return str.replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase();
}

/**
 * Save result data to a JSON file with metadata wrapper
 *
 * @param data - The data to save
 * @param category - Category directory (e.g., 'reports', 'realtime')
 * @param operation - Operation name (e.g., 'page_views', 'traffic_sources')
 * @param extraInfo - Optional extra info for filename
 * @returns The full path to the saved file
 */
export function saveResult<T>(
  data: T,
  category: string,
  operation: string,
  extraInfo?: string
): string {
  const settings = getSettings();
  const categoryDir = join(settings.resultsDir, category);

  // Ensure category directory exists
  if (!existsSync(categoryDir)) {
    mkdirSync(categoryDir, { recursive: true });
  }

  // Build filename
  const timestamp = getTimestamp();
  const sanitizedOperation = sanitizeFilename(operation);
  const sanitizedExtra = extraInfo ? `__${sanitizeFilename(extraInfo)}` : '';
  const filename = `${timestamp}__${sanitizedOperation}${sanitizedExtra}.json`;
  const filepath = join(categoryDir, filename);

  // Build wrapped result
  const result: SavedResult<T> = {
    metadata: {
      savedAt: new Date().toISOString(),
      category,
      operation,
      propertyId: settings.propertyId,
      ...(extraInfo && { extraInfo }),
    },
    data,
  };

  // Write to file
  writeFileSync(filepath, JSON.stringify(result, null, 2), 'utf-8');

  return filepath;
}

/**
 * Load a saved result from a JSON file
 *
 * @param filepath - Path to the JSON file
 * @returns The parsed result or null if file doesn't exist
 */
export function loadResult<T = unknown>(filepath: string): SavedResult<T> | null {
  if (!existsSync(filepath)) {
    return null;
  }

  try {
    const content = readFileSync(filepath, 'utf-8');
    return JSON.parse(content) as SavedResult<T>;
  } catch {
    return null;
  }
}

/**
 * List saved result files for a category
 *
 * @param category - Category to list results for
 * @param limit - Maximum number of results to return
 * @returns Array of file paths, sorted by date descending (newest first)
 */
export function listResults(category: string, limit?: number): string[] {
  const settings = getSettings();
  const categoryDir = join(settings.resultsDir, category);

  if (!existsSync(categoryDir)) {
    return [];
  }

  const files = readdirSync(categoryDir)
    .filter(f => f.endsWith('.json'))
    .map(f => join(categoryDir, f))
    .sort((a, b) => {
      // Sort by filename (which starts with timestamp) descending
      const nameA = a.split('/').pop() || '';
      const nameB = b.split('/').pop() || '';
      return nameB.localeCompare(nameA);
    });

  if (limit !== undefined) {
    return files.slice(0, limit);
  }

  return files;
}

/**
 * Get the most recent result for a category/operation
 *
 * @param category - Category to search
 * @param operation - Optional operation to filter by
 * @returns The most recent result or null
 */
export function getLatestResult<T = unknown>(
  category: string,
  operation?: string
): SavedResult<T> | null {
  let files = listResults(category);

  if (operation) {
    const sanitized = sanitizeFilename(operation);
    files = files.filter(f => f.includes(`__${sanitized}`));
  }

  if (files.length === 0) {
    return null;
  }

  return loadResult<T>(files[0]);
}


path: scripts/src/index.ts
content: /**
 * GA4 Analytics Toolkit - Main Entry Point
 *
 * Simple interface for Google Analytics 4 data analysis.
 * All results are automatically saved to the /results directory with timestamps.
 *
 * Usage:
 *   import { siteOverview, trafficAnalysis } from './index.js';
 *   const overview = await siteOverview('30d');
 */

// Re-export all API functions
export * from './api/reports.js';
export * from './api/realtime.js';
export * from './api/metadata.js';
export * from './api/searchConsole.js';
export * from './api/indexing.js';
export * from './api/bulk-lookup.js';

// Re-export core utilities
export { getClient, getPropertyId, getSearchConsoleClient, getIndexingClient, getSiteUrl, resetClient } from './core/client.js';
export { saveResult, loadResult, listResults, getLatestResult } from './core/storage.js';
export { getSettings, validateSettings } from './config/settings.js';

// Import for orchestration functions
import {
  runReport,
  getPageViews,
  getTrafficSources,
  getUserDemographics,
  getEventCounts,
  getConversions,
  parseDateRange,
  type DateRange,
} from './api/reports.js';
import { getActiveUsers, getRealtimeEvents, getRealtimePages } from './api/realtime.js';
import { getPropertyMetadata } from './api/metadata.js';
import { saveResult } from './core/storage.js';
import {
  getTopQueries,
  getTopPages as getSearchConsoleTopPages,
  getDevicePerformance,
  getCountryPerformance,
  type SearchConsoleDateRange,
} from './api/searchConsole.js';
import { requestIndexing, inspectUrl } from './api/indexing.js';

// ============================================================================
// HIGH-LEVEL ORCHESTRATION FUNCTIONS
// ============================================================================

/**
 * Comprehensive site overview - combines multiple reports
 */
export async function siteOverview(dateRange?: string | DateRange) {
  console.log('\n📊 Generating site overview...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting page views...');
  results.pageViews = await getPageViews(dateRange);

  console.log('  → Getting traffic sources...');
  results.trafficSources = await getTrafficSources(dateRange);

  console.log('  → Getting user demographics...');
  results.demographics = await getUserDemographics(dateRange);

  console.log('  → Getting event counts...');
  results.events = await getEventCounts(dateRange);

  // Save combined results
  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'reports', 'site_overview', dateStr);

  console.log('✅ Site overview complete\n');
  return results;
}

/**
 * Deep dive on traffic sources
 */
export async function trafficAnalysis(dateRange?: string | DateRange) {
  console.log('\n🚗 Analyzing traffic sources...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting traffic sources...');
  results.sources = await getTrafficSources(dateRange);

  console.log('  → Getting session data by source...');
  results.sessions = await runReport({
    dimensions: ['sessionSource', 'sessionMedium'],
    metrics: ['sessions', 'engagedSessions', 'averageSessionDuration', 'bounceRate'],
    dateRange,
  });

  console.log('  → Getting new vs returning users...');
  results.newVsReturning = await runReport({
    dimensions: ['newVsReturning'],
    metrics: ['activeUsers', 'sessions', 'conversions'],
    dateRange,
  });

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'reports', 'traffic_analysis', dateStr);

  console.log('✅ Traffic analysis complete\n');
  return results;
}

/**
 * Content performance analysis
 */
export async function contentPerformance(dateRange?: string | DateRange) {
  console.log('\n📄 Analyzing content performance...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting page views...');
  results.pages = await getPageViews(dateRange);

  console.log('  → Getting landing pages...');
  results.landingPages = await runReport({
    dimensions: ['landingPage'],
    metrics: ['sessions', 'activeUsers', 'bounceRate', 'averageSessionDuration'],
    dateRange,
  });

  console.log('  → Getting exit pages...');
  results.exitPages = await runReport({
    dimensions: ['pagePath'],
    metrics: ['exits', 'screenPageViews'],
    dateRange,
  });

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'reports', 'content_performance', dateStr);

  console.log('✅ Content performance analysis complete\n');
  return results;
}

/**
 * User behavior analysis
 */
export async function userBehavior(dateRange?: string | DateRange) {
  console.log('\n👤 Analyzing user behavior...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting demographics...');
  results.demographics = await getUserDemographics(dateRange);

  console.log('  → Getting events...');
  results.events = await getEventCounts(dateRange);

  console.log('  → Getting engagement metrics...');
  results.engagement = await runReport({
    dimensions: ['date'],
    metrics: ['activeUsers', 'engagedSessions', 'engagementRate', 'averageSessionDuration'],
    dateRange,
  });

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'reports', 'user_behavior', dateStr);

  console.log('✅ User behavior analysis complete\n');
  return results;
}

/**
 * Compare two date ranges
 */
export async function compareDateRanges(
  range1: DateRange,
  range2: DateRange,
  dimensions: string[] = ['date'],
  metrics: string[] = ['activeUsers', 'sessions', 'screenPageViews']
) {
  console.log('\n📈 Comparing date ranges...');

  console.log(`  → Getting data for ${range1.startDate} to ${range1.endDate}...`);
  const period1 = await runReport({
    dimensions,
    metrics,
    dateRange: range1,
    save: false,
  });

  console.log(`  → Getting data for ${range2.startDate} to ${range2.endDate}...`);
  const period2 = await runReport({
    dimensions,
    metrics,
    dateRange: range2,
    save: false,
  });

  const comparison = {
    period1: { dateRange: range1, data: period1 },
    period2: { dateRange: range2, data: period2 },
  };

  saveResult(comparison, 'reports', 'date_comparison');

  console.log('✅ Date range comparison complete\n');
  return comparison;
}

/**
 * Get current live data snapshot
 */
export async function liveSnapshot() {
  console.log('\n⚡ Getting live data snapshot...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting active users...');
  results.activeUsers = await getActiveUsers();

  console.log('  → Getting current pages...');
  results.currentPages = await getRealtimePages();

  console.log('  → Getting current events...');
  results.currentEvents = await getRealtimeEvents();

  saveResult(results, 'realtime', 'snapshot');

  console.log('✅ Live snapshot complete\n');
  return results;
}

// ============================================================================
// SEARCH CONSOLE ORCHESTRATION FUNCTIONS
// ============================================================================

/**
 * Comprehensive Search Console overview
 */
export async function searchConsoleOverview(dateRange?: string | SearchConsoleDateRange) {
  console.log('\n🔍 Generating Search Console overview...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting top queries...');
  results.topQueries = await getTopQueries(dateRange);

  console.log('  → Getting top pages...');
  results.topPages = await getSearchConsoleTopPages(dateRange);

  console.log('  → Getting device performance...');
  results.devicePerformance = await getDevicePerformance(dateRange);

  console.log('  → Getting country performance...');
  results.countryPerformance = await getCountryPerformance(dateRange);

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'searchconsole', 'overview', dateStr);

  console.log('✅ Search Console overview complete\n');
  return results;
}

/**
 * Deep dive into keyword/query analysis
 */
export async function keywordAnalysis(dateRange?: string | SearchConsoleDateRange) {
  console.log('\n🔑 Analyzing keywords...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting top queries...');
  results.queries = await getTopQueries(dateRange);

  console.log('  → Getting device breakdown for queries...');
  results.deviceBreakdown = await getDevicePerformance(dateRange);

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'searchconsole', 'keyword_analysis', dateStr);

  console.log('✅ Keyword analysis complete\n');
  return results;
}

/**
 * SEO page performance analysis
 */
export async function seoPagePerformance(dateRange?: string | SearchConsoleDateRange) {
  console.log('\n📄 Analyzing SEO page performance...');
  const results: Record<string, unknown> = {};

  console.log('  → Getting top pages by clicks...');
  results.topPages = await getSearchConsoleTopPages(dateRange);

  console.log('  → Getting country breakdown...');
  results.countryBreakdown = await getCountryPerformance(dateRange);

  const dateStr = typeof dateRange === 'string' ? dateRange : 'custom';
  saveResult(results, 'searchconsole', 'seo_page_performance', dateStr);

  console.log('✅ SEO page performance analysis complete\n');
  return results;
}

/**
 * Request re-indexing for updated URLs
 */
export async function reindexUrls(urls: string[]) {
  console.log(`\n🔄 Requesting re-indexing for ${urls.length} URL(s)...`);
  const results: Array<{ url: string; status: string; error?: string }> = [];

  for (const url of urls) {
    try {
      console.log(`  → Requesting indexing: ${url}`);
      const result = await requestIndexing(url, { save: false });
      results.push({ url, status: 'submitted', ...result });
    } catch (error) {
      console.log(`  ✗ Failed: ${url}`);
      results.push({ url, status: 'failed', error: String(error) });
    }
  }

  saveResult(results, 'indexing', 'reindex_batch');
  console.log('✅ Re-indexing requests complete\n');
  return results;
}

/**
 * Check index status for URLs
 */
export async function checkIndexStatus(urls: string[]) {
  console.log(`\n🔎 Checking index status for ${urls.length} URL(s)...`);
  const results: Array<{ url: string; indexed: boolean; status: unknown }> = [];

  for (const url of urls) {
    try {
      console.log(`  → Inspecting: ${url}`);
      const result = await inspectUrl(url, { save: false });
      results.push({
        url,
        indexed: result.indexStatus.verdict === 'PASS',
        status: result.indexStatus,
      });
    } catch (error) {
      console.log(`  ✗ Failed: ${url}`);
      results.push({ url, indexed: false, status: { error: String(error) } });
    }
  }

  saveResult(results, 'indexing', 'index_status_check');
  console.log('✅ Index status check complete\n');
  return results;
}

// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================

/**
 * Get available dimensions and metrics
 */
export async function getAvailableFields() {
  console.log('\n📋 Getting available fields...');
  const metadata = await getPropertyMetadata();
  console.log(`  → Found ${metadata.dimensions?.length || 0} dimensions`);
  console.log(`  → Found ${metadata.metrics?.length || 0} metrics`);
  console.log('✅ Field retrieval complete\n');
  return metadata;
}

// Print help when run directly
if (process.argv[1] === new URL(import.meta.url).pathname) {
  console.log(`
GA4 Analytics Toolkit
=====================

GA4 High-level functions:
  - siteOverview(dateRange?)        Comprehensive site snapshot
  - trafficAnalysis(dateRange?)     Deep dive on sources
  - contentPerformance(dateRange?)  Top pages analysis
  - userBehavior(dateRange?)        Engagement patterns
  - compareDateRanges(range1, range2)  Period comparison
  - liveSnapshot()                  Real-time data

Search Console functions:
  - searchConsoleOverview(dateRange?)  Combined SEO snapshot
  - keywordAnalysis(dateRange?)        Query/keyword analysis
  - seoPagePerformance(dateRange?)     Page-level SEO metrics
  - getTopQueries(dateRange?)          Top search queries
  - getTopPages(dateRange?)            Top pages by clicks
  - getDevicePerformance(dateRange?)   Mobile vs desktop
  - getCountryPerformance(dateRange?)  Traffic by country

Indexing functions:
  - reindexUrls(urls)                  Request re-indexing for URLs
  - checkIndexStatus(urls)             Check if URLs are indexed
  - requestIndexing(url)               Request single URL re-crawl
  - inspectUrl(url)                    Inspect URL index status

Low-level GA4 functions:
  - runReport({ dimensions, metrics, dateRange })
  - getPageViews(dateRange?)
  - getTrafficSources(dateRange?)
  - getUserDemographics(dateRange?)
  - getEventCounts(dateRange?)
  - getActiveUsers()
  - getRealtimeEvents()
  - getPropertyMetadata()

All results are automatically saved to /results directory.
`);
}


path: scripts/tsconfig.json
content: {
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "tests"]
}


path: _meta.json
content: ownerId: kn7e8pzf5zjqcaxjz9rf815hf17zypbn
slug: ga4-analytics
version: 1.0.0
publishedAt: 1769464446311

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)