From 92ce6332177440b0f1d32ff4d254d29039a6fc11 Mon Sep 17 00:00:00 2001 From: ziptied Date: Thu, 2 Apr 2026 13:54:20 +0900 Subject: [PATCH 1/4] refactor: replace cross-fetch mocks with globalThis.fetch Replace mock.module calls for 'cross-fetch' with direct globalThis.fetch assignments. This simplifies test setup and improves compatibility with modern fetch implementations. Rename resetMockFetchTracking to cleanupMockFetch for clarity and update imports accordingly. --- CHANGELOG.md | 8 + __tests__/client/client.test.ts | 104 +++-- __tests__/helpers/mockFetch.test.ts | 25 +- __tests__/helpers/mockFetch.ts | 75 ++-- bun.lockb | Bin 65575 -> 183578 bytes docs/manual-testing.md | 100 +++++ docs/manual-validation.js | 43 ++ package-lock.json | 621 +++++++++++++-------------- package.json | 4 +- scripts/run-automation-validation.sh | 85 ++++ src/sdk/client/index.ts | 1 - 11 files changed, 636 insertions(+), 430 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 docs/manual-testing.md create mode 100644 docs/manual-validation.js create mode 100755 scripts/run-automation-validation.sh diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a34975c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## 1.0.6 - 2026-02-25 + +### Added +- Documented the Email Templates GET and PATCH helpers in the README, including code samples, error-handling guidance, and references to the public Email Templates API. +- Documented the Workflows helper, added pagination support for `getWorkflows`, and extended tests to cover query parameters and automation stats. +- Expanded the Sequences section with API references, pagination for `getSequences`, create/update examples, and regression tests around pagination. diff --git a/__tests__/client/client.test.ts b/__tests__/client/client.test.ts index 5851a7d..fdab5db 100644 --- a/__tests__/client/client.test.ts +++ b/__tests__/client/client.test.ts @@ -3,9 +3,9 @@ import { Analytics } from '../../src'; import { mockOptions } from '../helpers/mockClient'; import { setupMockFetch, + cleanupMockFetch, lastFetchSignal, lastFetchUrl, - resetMockFetchTracking, } from '../helpers/mockFetch'; import { NotAuthorizedError, RateLimitedError, RequestTimeoutError } from '../../src'; @@ -18,7 +18,7 @@ describe('BentoClient', () => { globalScope = global; }); afterEach(() => { - resetMockFetchTracking(); + cleanupMockFetch(); }); describe('Base64 Encoding', () => { @@ -163,19 +163,17 @@ describe('BentoClient', () => { let capturedUrl: string | null = null; // Setup mock that captures the URL - mock.module('cross-fetch', () => ({ - default: (url: string, _options: RequestInit) => { - capturedUrl = url; - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.resolve({ data: null }), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }, - })); + globalThis.fetch = ((url: string | URL | Request) => { + capturedUrl = typeof url === 'string' ? url : url.toString(); + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.resolve({ data: null }), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; await analytics.V1.Forms.getResponses('test-form'); @@ -190,19 +188,17 @@ describe('BentoClient', () => { let capturedUrl: string | null = null; // Setup mock that captures the URL - mock.module('cross-fetch', () => ({ - default: (url: string, _options: RequestInit) => { - capturedUrl = url; - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.resolve({ data: null }), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }, - })); + globalThis.fetch = ((url: string | URL | Request) => { + capturedUrl = typeof url === 'string' ? url : url.toString(); + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.resolve({ data: null }), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; // Test with a parameter that would have a non-string value await analytics.V1.Forms.getResponses('test-form'); @@ -260,22 +256,20 @@ describe('BentoClient', () => { describe('Timeout Handling', () => { test('throws RequestTimeoutError on timeout', async () => { // Mock fetch to simulate a timeout by using AbortController - mock.module('cross-fetch', () => ({ - default: (_url: string, options: RequestInit) => { - return new Promise((_resolve, reject) => { - // Simulate the abort being triggered - if (options.signal) { - const abortHandler = () => { - const error = new Error('The operation was aborted'); - error.name = 'AbortError'; - reject(error); - }; - options.signal.addEventListener('abort', abortHandler); - // Don't resolve - let the timeout happen - } - }); - }, - })); + globalThis.fetch = ((_url: string | URL | Request, options?: RequestInit) => { + return new Promise((_resolve, reject) => { + // Simulate the abort being triggered + if (options?.signal) { + const abortHandler = () => { + const error = new Error('The operation was aborted'); + error.name = 'AbortError'; + reject(error); + }; + options.signal.addEventListener('abort', abortHandler); + // Don't resolve - let the timeout happen + } + }); + }) as typeof globalThis.fetch; // Create analytics with very short timeout const timeoutAnalytics = new Analytics({ @@ -291,18 +285,16 @@ describe('BentoClient', () => { describe('JSON Response Handling', () => { test('throws error on invalid JSON response with success status', async () => { - mock.module('cross-fetch', () => ({ - default: () => { - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.reject(new SyntaxError('Unexpected end of JSON input')), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }, - })); + globalThis.fetch = (() => { + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.reject(new SyntaxError('Unexpected end of JSON input')), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; await expect(analytics.V1.Tags.getTags()).rejects.toThrow( 'Invalid JSON response from server' diff --git a/__tests__/helpers/mockFetch.test.ts b/__tests__/helpers/mockFetch.test.ts index fd9b252..50f05cf 100644 --- a/__tests__/helpers/mockFetch.test.ts +++ b/__tests__/helpers/mockFetch.test.ts @@ -1,7 +1,11 @@ -import { expect, test, describe } from 'bun:test'; -import { getEndpointFromUrl, setupMockFetch } from './mockFetch'; +import { expect, test, describe, afterEach } from 'bun:test'; +import { getEndpointFromUrl, setupMockFetch, cleanupMockFetch } from './mockFetch'; describe('mockFetch helpers', () => { + afterEach(() => { + cleanupMockFetch(); + }); + describe('getEndpointFromUrl', () => { test('extracts endpoint from full URL', () => { const url = 'https://app.bentonow.com/api/v1/fetch/broadcasts'; @@ -42,24 +46,21 @@ describe('mockFetch helpers', () => { describe('setupMockFetch text handling', () => { test('returns raw string for text/plain body', async () => { setupMockFetch('plain text', 200, 'text/plain'); - const fetchModule = await import('cross-fetch'); - const response = await fetchModule.default('https://app.bentonow.com/api/v1/test'); + const response = await fetch('https://app.bentonow.com/api/v1/test'); const text = await response.text(); expect(text).toBe('plain text'); }); test('returns error field when provided', async () => { setupMockFetch({ error: 'Server Error' }, 500, 'text/plain'); - const fetchModule = await import('cross-fetch'); - const response = await fetchModule.default('https://app.bentonow.com/api/v1/test'); + const response = await fetch('https://app.bentonow.com/api/v1/test'); const text = await response.text(); expect(text).toBe('Server Error'); }); test('stringifies non-string text bodies without error', async () => { setupMockFetch({ value: 123 }, 200, 'text/plain'); - const fetchModule = await import('cross-fetch'); - const response = await fetchModule.default('https://app.bentonow.com/api/v1/test'); + const response = await fetch('https://app.bentonow.com/api/v1/test'); const text = await response.text(); expect(text).toBe('[object Object]'); }); @@ -69,12 +70,10 @@ describe('mockFetch helpers', () => { { body: { value: 'first' } }, { body: { value: 'second' } }, ]); - const fetchModule = await import('cross-fetch'); - const fetchFn = fetchModule.default; - const first = await fetchFn('https://app.bentonow.com/api/v1/test'); - const second = await fetchFn('https://app.bentonow.com/api/v1/test'); - const third = await fetchFn('https://app.bentonow.com/api/v1/test'); + const first = await fetch('https://app.bentonow.com/api/v1/test'); + const second = await fetch('https://app.bentonow.com/api/v1/test'); + const third = await fetch('https://app.bentonow.com/api/v1/test'); expect(await first.json()).toEqual({ value: 'first' }); expect(await second.json()).toEqual({ value: 'second' }); diff --git a/__tests__/helpers/mockFetch.ts b/__tests__/helpers/mockFetch.ts index 5c8c181..7924e86 100644 --- a/__tests__/helpers/mockFetch.ts +++ b/__tests__/helpers/mockFetch.ts @@ -1,5 +1,3 @@ -import { mock } from 'bun:test'; - type MockResponseEntry = { body: any; status?: number; @@ -31,12 +29,21 @@ export let lastFetchUrl: string | null = null; export let lastFetchMethod: string | null = null; export let lastFetchSignal: AbortSignal | null = null; +let originalFetch: typeof globalThis.fetch; + export const resetMockFetchTracking = (): void => { lastFetchUrl = null; lastFetchMethod = null; lastFetchSignal = null; }; +export const cleanupMockFetch = (): void => { + if (originalFetch !== undefined) { + globalThis.fetch = originalFetch; + } + resetMockFetchTracking(); +}; + export const setupMockFetch = ( response: any | MockResponseEntry[], status = 200, @@ -51,41 +58,43 @@ export const setupMockFetch = ( const singleEntry = normalizeEntry(response, status, contentType); const fallbackEntry = queue && queue.length > 0 ? queue[queue.length - 1] : singleEntry; - mock.module('cross-fetch', () => ({ - default: (url: string, options: RequestInit = {}) => { - // Capture URL, method, and AbortSignal for test verification - lastFetchUrl = url; - lastFetchMethod = options.method || 'GET'; - lastFetchSignal = options.signal ?? null; + originalFetch = globalThis.fetch; + globalThis.fetch = ((url: string | URL | Request, options?: RequestInit) => { + const urlStr = typeof url === 'string' ? url : url.toString(); + const opts = options ?? {}; - const entry = queue ? queue.shift() ?? fallbackEntry : singleEntry; - const currentStatus = entry.status ?? status; - const currentContentType = entry.contentType ?? contentType; - const body = entry.body; + // Capture URL, method, and AbortSignal for test verification + lastFetchUrl = urlStr; + lastFetchMethod = (opts as any).method || 'GET'; + lastFetchSignal = (opts as any).signal ?? null; - return Promise.resolve({ - status: currentStatus, - ok: currentStatus >= 200 && currentStatus < 300, - json: () => Promise.resolve(body), - text: () => { - if (currentContentType === 'text/plain') { - if (typeof body === 'string') { - return Promise.resolve(body); - } - if (body?.error) { - return Promise.resolve(body.error); - } - return Promise.resolve(String(body)); + const entry = queue ? queue.shift() ?? fallbackEntry : singleEntry; + const currentStatus = entry.status ?? status; + const currentContentType = entry.contentType ?? contentType; + const body = entry.body; + + return Promise.resolve({ + status: currentStatus, + ok: currentStatus >= 200 && currentStatus < 300, + json: () => Promise.resolve(body), + text: () => { + if (currentContentType === 'text/plain') { + if (typeof body === 'string') { + return Promise.resolve(body); + } + if (body?.error) { + return Promise.resolve(body.error); } + return Promise.resolve(String(body)); + } - return Promise.resolve(JSON.stringify(body)); - }, - headers: new Headers({ - 'Content-Type': currentContentType, - }), - }); - }, - })); + return Promise.resolve(JSON.stringify(body)); + }, + headers: new Headers({ + 'Content-Type': currentContentType, + }), + }); + }) as typeof globalThis.fetch; }; /** diff --git a/bun.lockb b/bun.lockb index 3bbd515c9a31159b6c4ad09dc1fe63402ab979be..219a4f76e4cc228238e8c9e16bc08d680a00fe1f 100755 GIT binary patch literal 183578 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 {{ visitor.first_name }}", + "delay_interval": "days", + "delay_interval_count": 3, + "inbox_snippet": "Start here", + "editor_choice": "plain" + } + }' | jq +``` + +The response should echo the created email template. Delete or disable the template afterward if this is a production sequence. + +## 5. Update Sequence Email / Template (`PATCH /v1/fetch/emails/templates/:id`) + +```bash +curl -sSL -u "$BENTO_PUBLISHABLE_KEY:$BENTO_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -X PATCH \ + "https://app.bentonow.com/api/v1/fetch/emails/templates/${BENTO_TEMPLATE_ID}?site_uuid=$BENTO_SITE_UUID" \ + -d '{ + "email_template": { + "subject": "Manual Validation Subject", + "html": "

Updated via CLI validation

" + } + }' | jq +``` + +Use a staging template ID to avoid altering live content. + +## 6. SDK Smoke Test (Optional) + +```bash +bun run build >/dev/null +node docs/manual-validation.js +``` + +The script imports the freshly built SDK bundle from `dist`. Set `BENTO_SEQUENCE_PREFIX_ID` / `BENTO_TEMPLATE_ID` to exercise the create/update flows; leave them blank to skip. + +## 7. One-Command Validation + +To run all curl checks plus the SDK smoke test in one go, use the wrapper script (requires `jq`, `curl`, and optionally Bun): + +```bash +chmod +x scripts/run-automation-validation.sh +./scripts/run-automation-validation.sh +``` + +The script skips optional steps when `BENTO_SEQUENCE_PREFIX_ID` or `BENTO_TEMPLATE_ID` are unset. It automatically runs `bun run build` before launching the SDK smoke test. + +## 8. Cleanup + +If you created test templates or sequences, remove them in the Bento UI or via the API to keep your automation clean. For production sites, prefer using a sandbox sequence or temporary site UUID when running the `createSequenceEmail` step. diff --git a/docs/manual-validation.js b/docs/manual-validation.js new file mode 100644 index 0000000..18895b9 --- /dev/null +++ b/docs/manual-validation.js @@ -0,0 +1,43 @@ +import { Analytics } from '../dist/index.js'; + +const analytics = new Analytics({ + authentication: { + publishableKey: process.env.BENTO_PUBLISHABLE_KEY, + secretKey: process.env.BENTO_SECRET_KEY, + }, + siteUuid: process.env.BENTO_SITE_UUID, +}); + +async function main() { + console.log('Workflows (page 1)'); + console.dir(await analytics.V1.Workflows.getWorkflows({ page: 1 }), { depth: 2 }); + + console.log('Sequences (page 1)'); + const sequences = await analytics.V1.Sequences.getSequences({ page: 1 }); + console.dir(sequences, { depth: 2 }); + + if (process.env.BENTO_SEQUENCE_PREFIX_ID) { + const created = await analytics.V1.Sequences.createSequenceEmail( + process.env.BENTO_SEQUENCE_PREFIX_ID, + { + subject: 'SDK Validation Email', + html: '

Sent from SDK validation script

', + } + ); + console.log('Created sequence email:', created?.id); + } + + if (process.env.BENTO_TEMPLATE_ID) { + const updated = await analytics.V1.EmailTemplates.updateEmailTemplate({ + id: Number(process.env.BENTO_TEMPLATE_ID), + subject: 'SDK Validation Update', + html: '

Updated via SDK validation script

', + }); + console.log('Updated template subject:', updated?.attributes.subject); + } +} + +main().catch((err) => { + console.error(err); + process.exitCode = 1; +}); diff --git a/package-lock.json b/package-lock.json index 5a11a0c..4a2f16d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,13 @@ { "name": "@bentonow/bento-node-sdk", - "version": "1.0.4", + "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bentonow/bento-node-sdk", - "version": "1.0.4", + "version": "1.0.5", "license": "MIT", - "dependencies": { - "cross-fetch": "^4.1.0" - }, "devDependencies": { "@size-limit/preset-small-lib": "^11.1.5", "@types/jest": "^30.0.0", @@ -580,9 +577,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -597,9 +594,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -614,9 +611,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -631,9 +628,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -648,9 +645,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -665,9 +662,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -682,9 +679,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -699,9 +696,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -716,9 +713,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -733,9 +730,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -750,9 +747,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -767,9 +764,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -784,9 +781,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -801,9 +798,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -818,9 +815,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -835,9 +832,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -852,9 +849,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -869,9 +866,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -886,9 +883,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -903,9 +900,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -920,9 +917,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -936,10 +933,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -954,9 +968,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -971,9 +985,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -988,9 +1002,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -1005,9 +1019,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1034,24 +1048,24 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1060,9 +1074,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1072,10 +1086,23 @@ "node": "*" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", - "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1086,20 +1113,20 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -1110,9 +1137,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1121,9 +1148,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1134,19 +1161,22 @@ } }, "node_modules/@eslint/js": { - "version": "9.20.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", - "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1154,32 +1184,19 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", - "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.10.0", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", - "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1233,9 +1250,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1876,48 +1893,48 @@ } }, "node_modules/@size-limit/esbuild": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-11.1.6.tgz", - "integrity": "sha512-0nBKYSxeRjUVCVoCkWZbmGkGBwpm0HdwHedWgxksBGxTKU0PjOMSHc3XTjKOrXBKXQzw90Ue0mgOd4n6zct9SA==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-11.2.0.tgz", + "integrity": "sha512-vSg9H0WxGQPRzDnBzeDyD9XT0Zdq0L+AI3+77/JhxznbSCMJMMr8ndaWVQRhOsixl97N0oD4pRFw2+R1Lcvi6A==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.24.0", - "nanoid": "^5.0.7" + "esbuild": "^0.25.0", + "nanoid": "^5.1.0" }, "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "size-limit": "11.1.6" + "size-limit": "11.2.0" } }, "node_modules/@size-limit/file": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-11.1.6.tgz", - "integrity": "sha512-ojzzJMrTfcSECRnaTjGy0wNIolTCRdyqZTSWG9sG5XEoXG6PNgHXDDS6gf6YNxnqb+rWfCfVe93u6aKi3wEocQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-11.2.0.tgz", + "integrity": "sha512-OZHE3putEkQ/fgzz3Tp/0hSmfVo3wyTpOJSRNm6AmcwX4Nm9YtTfbQQ/hZRwbBFR23S7x2Sd9EbqYzngKwbRoA==", "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "size-limit": "11.1.6" + "size-limit": "11.2.0" } }, "node_modules/@size-limit/preset-small-lib": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/@size-limit/preset-small-lib/-/preset-small-lib-11.1.6.tgz", - "integrity": "sha512-hlmkBlOryJIsKlGpS61Ti7/EEZomygAzOabpo2htdxUbkCkvtVoUQpGWHUfWuxdhheDVF6rtZZ6lPGftMKlaQg==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@size-limit/preset-small-lib/-/preset-small-lib-11.2.0.tgz", + "integrity": "sha512-RFbbIVfv8/QDgTPyXzjo5NKO6CYyK5Uq5xtNLHLbw5RgSKrgo8WpiB/fNivZuNd/5Wk0s91PtaJ9ThNcnFuI3g==", "dev": true, "license": "MIT", "dependencies": { - "@size-limit/esbuild": "11.1.6", - "@size-limit/file": "11.1.6", - "size-limit": "11.1.6" + "@size-limit/esbuild": "11.2.0", + "@size-limit/file": "11.2.0", + "size-limit": "11.2.0" }, "peerDependencies": { - "size-limit": "11.1.6" + "size-limit": "11.2.0" } }, "node_modules/@tybys/wasm-util": { @@ -2542,9 +2559,9 @@ ] }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -2565,9 +2582,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2764,9 +2781,9 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -3108,15 +3125,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3237,9 +3245,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3250,31 +3258,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -3301,32 +3310,32 @@ } }, "node_modules/eslint": { - "version": "9.20.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz", - "integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.11.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.20.0", - "@eslint/plugin-kit": "^0.2.5", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -3338,7 +3347,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3361,9 +3370,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3391,9 +3400,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3402,9 +3411,9 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3415,9 +3424,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3428,15 +3437,15 @@ } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3446,9 +3455,9 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3706,9 +3715,9 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -3856,9 +3865,9 @@ "license": "MIT" }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4644,9 +4653,9 @@ } }, "node_modules/jest-util/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -4758,9 +4767,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -4993,13 +5002,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5036,9 +5045,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.0.tgz", - "integrity": "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz", + "integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==", "dev": true, "funding": [ { @@ -5094,26 +5103,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "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/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -5338,9 +5327,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -5680,19 +5669,19 @@ } }, "node_modules/size-limit": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/size-limit/-/size-limit-11.1.6.tgz", - "integrity": "sha512-S5ux2IB8rU26xwVgMskmknGMFkieaIAqDLuwgKiypk6oa4lFsie8yFPrzRFV+yrLDY2GddjXuCaVk5PveVOHiQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/size-limit/-/size-limit-11.2.0.tgz", + "integrity": "sha512-2kpQq2DD/pRpx3Tal/qRW1SYwcIeQ0iq8li5CJHQgOC+FtPn2BVmuDtzUCgNnpCrbgtfEHqh+iWzxK+Tq6C+RQ==", "dev": true, "license": "MIT", "dependencies": { "bytes-iec": "^3.1.1", - "chokidar": "^4.0.1", - "jiti": "^2.0.0", - "lilconfig": "^3.1.2", - "nanospinner": "^1.1.0", - "picocolors": "^1.1.0", - "tinyglobby": "^0.2.7" + "chokidar": "^4.0.3", + "jiti": "^2.4.2", + "lilconfig": "^3.1.3", + "nanospinner": "^1.2.2", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.11" }, "bin": { "size-limit": "bin.js" @@ -5981,9 +5970,9 @@ } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -6014,9 +6003,9 @@ } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -6027,25 +6016,31 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", - "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.2", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -6056,9 +6051,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -6088,12 +6083,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, "node_modules/ts-api-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", @@ -6353,22 +6342,6 @@ "makeerror": "1.0.12" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "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": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "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", diff --git a/package.json b/package.json index 72f6861..60f7682 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,7 @@ "ts-jest": "^29.4.6", "typescript": "^5.7.3" }, - "dependencies": { - "cross-fetch": "^4.1.0" - }, + "dependencies": {}, "size-limit": [ { "path": "dist/index.js", diff --git a/scripts/run-automation-validation.sh b/scripts/run-automation-validation.sh new file mode 100755 index 0000000..16428d3 --- /dev/null +++ b/scripts/run-automation-validation.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +set -euo pipefail + +require_env() { + local name="$1" + if [[ -z "${!name:-}" ]]; then + echo "Missing required env var: $name" >&2 + exit 1 + fi +} + +require_env "BENTO_PUBLISHABLE_KEY" +require_env "BENTO_SECRET_KEY" +require_env "BENTO_SITE_UUID" + +PAGE="${BENTO_VALIDATION_PAGE:-1}" +BASE_URL="${BENTO_BASE_URL:-https://app.bentonow.com/api/v1}" +AUTH="${BENTO_PUBLISHABLE_KEY}:${BENTO_SECRET_KEY}" + +header() { + echo + echo "== $1 ==" +} + +curl_json() { + local method="$1" + local url="$2" + local body="${3:-}" + + if [[ -n "$body" ]]; then + curl -sSL -u "$AUTH" \ + -H "Content-Type: application/json" \ + -X "$method" \ + "$url" \ + -d "$body" | jq + else + curl -sSL -u "$AUTH" \ + -X "$method" \ + "$url" | jq + fi +} + +header "Workflows (page $PAGE)" +curl_json GET "$BASE_URL/fetch/workflows?site_uuid=$BENTO_SITE_UUID&page=$PAGE" + +header "Sequences (page $PAGE)" +curl_json GET "$BASE_URL/fetch/sequences?site_uuid=$BENTO_SITE_UUID&page=$PAGE" + +if [[ -n "${BENTO_SEQUENCE_PREFIX_ID:-}" ]]; then + header "Create Sequence Email (sequence: $BENTO_SEQUENCE_PREFIX_ID)" + curl_json POST "$BASE_URL/fetch/sequences/${BENTO_SEQUENCE_PREFIX_ID}/emails/templates?site_uuid=$BENTO_SITE_UUID" \ + '{ + "email_template": { + "subject": "CLI Validation Sequence Email", + "html": "

Generated at '$(date -u +%FT%TZ)'

", + "delay_interval": "days", + "delay_interval_count": 1, + "editor_choice": "plain" + } + }' +else + echo "Skipping sequence email creation (set BENTO_SEQUENCE_PREFIX_ID to enable)." +fi + +if [[ -n "${BENTO_TEMPLATE_ID:-}" ]]; then + header "Update Template (id: $BENTO_TEMPLATE_ID)" + curl_json PATCH "$BASE_URL/fetch/emails/templates/${BENTO_TEMPLATE_ID}?site_uuid=$BENTO_SITE_UUID" \ + '{ + "email_template": { + "subject": "CLI Validation Update", + "html": "

Updated at '$(date -u +%FT%TZ)'

" + } + }' +else + echo "Skipping template update (set BENTO_TEMPLATE_ID to enable)." +fi + +header "SDK Smoke Test" +if command -v bun >/dev/null 2>&1; then + header "SDK Smoke Test" + bun run build >/dev/null + node docs/manual-validation.js +else + echo "bun not found; skipping SDK script. Install Bun to run this step." +fi diff --git a/src/sdk/client/index.ts b/src/sdk/client/index.ts index 16817c7..b76b520 100644 --- a/src/sdk/client/index.ts +++ b/src/sdk/client/index.ts @@ -1,4 +1,3 @@ -import fetch from 'cross-fetch'; import type { AnalyticsOptions, AuthenticationOptions } from '../interfaces'; import { NotAuthorizedError, From e30f9c98ef850f9e6912a886376adafdf01a90fe Mon Sep 17 00:00:00 2001 From: ziptied Date: Thu, 2 Apr 2026 14:05:23 +0900 Subject: [PATCH 2/4] fix: prevent mock fetch state leaks between tests Improve mock fetch cleanup by resetting originalFetch to undefined after restoration. Add guard to prevent overwriting originalFetch on subsequent calls. Wrap manual fetch mocks in try-finally blocks to ensure proper cleanup. Simplify variable declarations in mock fetch setup. --- __tests__/client/client.test.ts | 192 ++++++++++++++++++-------------- __tests__/helpers/mockFetch.ts | 14 +-- 2 files changed, 112 insertions(+), 94 deletions(-) diff --git a/__tests__/client/client.test.ts b/__tests__/client/client.test.ts index fdab5db..43f1d9c 100644 --- a/__tests__/client/client.test.ts +++ b/__tests__/client/client.test.ts @@ -161,59 +161,67 @@ describe('BentoClient', () => { test('handles requests with query parameters', async () => { let capturedUrl: string | null = null; - - // Setup mock that captures the URL - globalThis.fetch = ((url: string | URL | Request) => { - capturedUrl = typeof url === 'string' ? url : url.toString(); - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.resolve({ data: null }), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }) as typeof globalThis.fetch; - - await analytics.V1.Forms.getResponses('test-form'); - - // Verify URL contains expected query parameters - expect(capturedUrl).not.toBeNull(); - const url = new URL(capturedUrl!); - expect(url.searchParams.get('id')).toBe('test-form'); - expect(url.searchParams.get('site_uuid')).toBe(mockOptions.siteUuid); + const savedFetch = globalThis.fetch; + + try { + globalThis.fetch = ((url: string | URL | Request) => { + capturedUrl = typeof url === 'string' ? url : url.toString(); + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.resolve({ data: null }), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; + + await analytics.V1.Forms.getResponses('test-form'); + + // Verify URL contains expected query parameters + expect(capturedUrl).not.toBeNull(); + const url = new URL(capturedUrl!); + expect(url.searchParams.get('id')).toBe('test-form'); + expect(url.searchParams.get('site_uuid')).toBe(mockOptions.siteUuid); + } finally { + globalThis.fetch = savedFetch; + } }); test('converts non-string query parameter values to strings', async () => { let capturedUrl: string | null = null; - - // Setup mock that captures the URL - globalThis.fetch = ((url: string | URL | Request) => { - capturedUrl = typeof url === 'string' ? url : url.toString(); - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.resolve({ data: null }), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }) as typeof globalThis.fetch; - - // Test with a parameter that would have a non-string value - await analytics.V1.Forms.getResponses('test-form'); - - // Verify URL query parameters are properly stringified - expect(capturedUrl).not.toBeNull(); - const url = new URL(capturedUrl!); - - // All query parameters should be strings, not undefined or null - expect(typeof url.searchParams.get('site_uuid')).toBe('string'); - expect(url.searchParams.get('site_uuid')).not.toBe('undefined'); - expect(url.searchParams.get('site_uuid')).not.toBe('null'); - - // Verify site_uuid is properly set - expect(url.searchParams.get('site_uuid')).toBe(mockOptions.siteUuid); + const savedFetch = globalThis.fetch; + + try { + globalThis.fetch = ((url: string | URL | Request) => { + capturedUrl = typeof url === 'string' ? url : url.toString(); + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.resolve({ data: null }), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; + + // Test with a parameter that would have a non-string value + await analytics.V1.Forms.getResponses('test-form'); + + // Verify URL query parameters are properly stringified + expect(capturedUrl).not.toBeNull(); + const url = new URL(capturedUrl!); + + // All query parameters should be strings, not undefined or null + expect(typeof url.searchParams.get('site_uuid')).toBe('string'); + expect(url.searchParams.get('site_uuid')).not.toBe('undefined'); + expect(url.searchParams.get('site_uuid')).not.toBe('null'); + + // Verify site_uuid is properly set + expect(url.searchParams.get('site_uuid')).toBe(mockOptions.siteUuid); + } finally { + globalThis.fetch = savedFetch; + } }); test('omits undefined query parameters when forwarding SDK options', async () => { @@ -255,50 +263,62 @@ describe('BentoClient', () => { describe('Timeout Handling', () => { test('throws RequestTimeoutError on timeout', async () => { - // Mock fetch to simulate a timeout by using AbortController - globalThis.fetch = ((_url: string | URL | Request, options?: RequestInit) => { - return new Promise((_resolve, reject) => { - // Simulate the abort being triggered - if (options?.signal) { - const abortHandler = () => { - const error = new Error('The operation was aborted'); - error.name = 'AbortError'; - reject(error); - }; - options.signal.addEventListener('abort', abortHandler); - // Don't resolve - let the timeout happen - } + const savedFetch = globalThis.fetch; + + try { + // Mock fetch to simulate a timeout by using AbortController + globalThis.fetch = ((_url: string | URL | Request, options?: RequestInit) => { + return new Promise((_resolve, reject) => { + // Simulate the abort being triggered + if (options?.signal) { + const abortHandler = () => { + const error = new Error('The operation was aborted'); + error.name = 'AbortError'; + reject(error); + }; + options.signal.addEventListener('abort', abortHandler); + // Don't resolve - let the timeout happen + } + }); + }) as typeof globalThis.fetch; + + // Create analytics with very short timeout + const timeoutAnalytics = new Analytics({ + ...mockOptions, + clientOptions: { + timeout: 1, // 1ms timeout to trigger quickly + }, }); - }) as typeof globalThis.fetch; - - // Create analytics with very short timeout - const timeoutAnalytics = new Analytics({ - ...mockOptions, - clientOptions: { - timeout: 1, // 1ms timeout to trigger quickly - }, - }); - await expect(timeoutAnalytics.V1.Tags.getTags()).rejects.toThrow(RequestTimeoutError); + await expect(timeoutAnalytics.V1.Tags.getTags()).rejects.toThrow(RequestTimeoutError); + } finally { + globalThis.fetch = savedFetch; + } }); }); describe('JSON Response Handling', () => { test('throws error on invalid JSON response with success status', async () => { - globalThis.fetch = (() => { - return Promise.resolve({ - status: 200, - ok: true, - json: () => Promise.reject(new SyntaxError('Unexpected end of JSON input')), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - }); - }) as typeof globalThis.fetch; - - await expect(analytics.V1.Tags.getTags()).rejects.toThrow( - 'Invalid JSON response from server' - ); + const savedFetch = globalThis.fetch; + + try { + globalThis.fetch = (() => { + return Promise.resolve({ + status: 200, + ok: true, + json: () => Promise.reject(new SyntaxError('Unexpected end of JSON input')), + headers: new Headers({ + 'Content-Type': 'application/json', + }), + }); + }) as typeof globalThis.fetch; + + await expect(analytics.V1.Tags.getTags()).rejects.toThrow( + 'Invalid JSON response from server' + ); + } finally { + globalThis.fetch = savedFetch; + } }); }); }); diff --git a/__tests__/helpers/mockFetch.ts b/__tests__/helpers/mockFetch.ts index 7924e86..a63e3a9 100644 --- a/__tests__/helpers/mockFetch.ts +++ b/__tests__/helpers/mockFetch.ts @@ -29,7 +29,7 @@ export let lastFetchUrl: string | null = null; export let lastFetchMethod: string | null = null; export let lastFetchSignal: AbortSignal | null = null; -let originalFetch: typeof globalThis.fetch; +let originalFetch: typeof globalThis.fetch | undefined; export const resetMockFetchTracking = (): void => { lastFetchUrl = null; @@ -40,6 +40,7 @@ export const resetMockFetchTracking = (): void => { export const cleanupMockFetch = (): void => { if (originalFetch !== undefined) { globalThis.fetch = originalFetch; + originalFetch = undefined; } resetMockFetchTracking(); }; @@ -58,15 +59,12 @@ export const setupMockFetch = ( const singleEntry = normalizeEntry(response, status, contentType); const fallbackEntry = queue && queue.length > 0 ? queue[queue.length - 1] : singleEntry; - originalFetch = globalThis.fetch; + if (originalFetch === undefined) originalFetch = globalThis.fetch; globalThis.fetch = ((url: string | URL | Request, options?: RequestInit) => { - const urlStr = typeof url === 'string' ? url : url.toString(); - const opts = options ?? {}; - // Capture URL, method, and AbortSignal for test verification - lastFetchUrl = urlStr; - lastFetchMethod = (opts as any).method || 'GET'; - lastFetchSignal = (opts as any).signal ?? null; + lastFetchUrl = typeof url === 'string' ? url : url.toString(); + lastFetchMethod = options?.method || 'GET'; + lastFetchSignal = options?.signal ?? null; const entry = queue ? queue.shift() ?? fallbackEntry : singleEntry; const currentStatus = entry.status ?? status; From 0f1e89211bad479f4bb6658880f5728ade428f14 Mon Sep 17 00:00:00 2001 From: ziptied Date: Thu, 2 Apr 2026 14:12:31 +0900 Subject: [PATCH 3/4] feat: automate changelog version updates in release Add automated changelog version updates to the release workflow. The workflow now updates the CHANGELOG.md version string to match the new package version during releases. This ensures the changelog stays synchronized with package.json and reduces manual version management errors. The git commit now includes both package.json and CHANGELOG.md files. --- .github/workflows/release.yml | 5 ++++- CHANGELOG.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 57c6dd6..78df9f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,6 +45,9 @@ jobs: - name: Update package version run: npm version $VERSION --no-git-tag-version + - name: Update CHANGELOG version + run: sed -i "s/^## [0-9]\+\.[0-9]\+\.[0-9]\+/## $VERSION/" CHANGELOG.md + - name: Generate Release Notes id: release_notes uses: actions/github-script@v6 @@ -61,7 +64,7 @@ jobs: run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - git add package.json + git add package.json CHANGELOG.md git commit -m "chore: bump version to $VERSION [skip ci]" git tag v$VERSION git push && git push --tags diff --git a/CHANGELOG.md b/CHANGELOG.md index a34975c..bbe0e0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 1.0.6 - 2026-02-25 +## 1.0.5 - 2026-02-25 ### Added - Documented the Email Templates GET and PATCH helpers in the README, including code samples, error-handling guidance, and references to the public Email Templates API. From b33f3675204d1ba151f0139a955acfbce67eb4ee Mon Sep 17 00:00:00 2001 From: ziptied Date: Thu, 2 Apr 2026 14:17:35 +0900 Subject: [PATCH 4/4] docs: remove manual testing documentation Remove manual-testing.md and manual-validation.js files as these testing guides and scripts are no longer maintained or needed for the current development workflow. These files contained outdated curl commands and SDK smoke test examples that have been superseded by automated testing infrastructure. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d2bec2b..d9d3b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ scratchpad.js Bun.lockb .idea .env +docs/ +scripts/