diff --git a/.changeset/yummy-sites-unite.md b/.changeset/yummy-sites-unite.md new file mode 100644 index 0000000000..b3cc27d39f --- /dev/null +++ b/.changeset/yummy-sites-unite.md @@ -0,0 +1,5 @@ +--- +'posthog-node': minor +--- + +feat: Add `FlagDefinitionCacheProvider` interface and client configuration option diff --git a/package.json b/package.json index 27c61c2e02..686ac11ef1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.29.5", "@types/eslint": "^8.44.6", - "@types/jest": "^28.1.5", "@types/node": "^22.17.0", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", diff --git a/packages/ai/package.json b/packages/ai/package.json index 8501ff2770..be8735e0de 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -24,6 +24,7 @@ "devDependencies": { "@posthog-tooling/rollup-utils": "workspace:*", "@posthog-tooling/tsconfig-base": "workspace:*", + "@types/jest": "catalog:", "jest": "catalog:", "node-fetch": "^3.3.2", "posthog-node": "workspace:*" diff --git a/packages/core/package.json b/packages/core/package.json index 95e3533f59..622990bc03 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -60,6 +60,7 @@ "@posthog-tooling/tsconfig-base": "workspace:*", "@rslib/core": "catalog:", "@types/cross-spawn": "^6.0.6", + "@types/jest": "catalog:", "jest": "catalog:" }, "dependencies": { diff --git a/packages/nextjs-config/package.json b/packages/nextjs-config/package.json index 44861d3629..d852f58eeb 100644 --- a/packages/nextjs-config/package.json +++ b/packages/nextjs-config/package.json @@ -56,6 +56,7 @@ "@rslib/core": "catalog:", "@types/node": "^22.15.23", "@types/semver": "^7.7.0", + "@types/jest": "catalog:", "jest": "catalog:", "next": "^15.4.1", "ts-jest": "catalog:" diff --git a/packages/node/package.json b/packages/node/package.json index 612d79d0e8..36497f2109 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -43,6 +43,7 @@ "@types/node": "^20.0.0", "@posthog-tooling/tsconfig-base": "workspace:*", "jest": "catalog:", + "@types/jest": "catalog:", "@rslib/core": "catalog:" }, "keywords": [ @@ -76,6 +77,9 @@ }, "import": "./dist/entrypoints/index.node.mjs", "require": "./dist/entrypoints/index.node.js" + }, + "./experimental": { + "types": "./dist/experimental.d.ts" } } } diff --git a/packages/node/src/__tests__/cache.spec.ts b/packages/node/src/__tests__/cache.spec.ts new file mode 100644 index 0000000000..fae186af35 --- /dev/null +++ b/packages/node/src/__tests__/cache.spec.ts @@ -0,0 +1,572 @@ +import { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from '../extensions/feature-flags/cache' +import { PostHogFeatureFlag } from '../types' +import { PostHog } from '../entrypoints/index.node' +import { anyLocalEvalCall, apiImplementation } from './utils' + +jest.spyOn(console, 'debug').mockImplementation() +jest.spyOn(console, 'warn').mockImplementation() + +const mockedFetch = jest.spyOn(globalThis, 'fetch').mockImplementation() + +describe('FlagDefinitionCacheProvider Integration', () => { + let posthog: PostHog + let mockCacheProvider: jest.Mocked + let onErrorMock: jest.Mock + + const testFlagDataApiResponse = { + flags: [ + { + id: 1, + name: 'Test Flag', + key: 'test-flag', + active: true, + deleted: false, + rollout_percentage: null, + ensure_experience_continuity: false, + experiment_set: [], + } as PostHogFeatureFlag, + ], + group_type_mapping: { '0': 'company' }, + cohorts: {}, + } + + const testFlagData: FlagDefinitionCacheData = { + flags: [ + { + id: 1, + name: 'Test Flag', + key: 'test-flag', + active: true, + deleted: false, + rollout_percentage: null, + ensure_experience_continuity: false, + experiment_set: [], + } as PostHogFeatureFlag, + ], + groupTypeMapping: { '0': 'company' }, + cohorts: {}, + } + + jest.useFakeTimers() + + beforeEach(() => { + mockedFetch.mockClear() + onErrorMock = jest.fn() + mockCacheProvider = { + getFlagDefinitions: jest.fn(), + shouldFetchFlagDefinitions: jest.fn(), + onFlagDefinitionsReceived: jest.fn(), + shutdown: jest.fn(), + } + }) + + afterEach(async () => { + if (posthog) { + await posthog.shutdown() + } + }) + + describe('Cache Initialization', () => { + it('calls getFlagDefinitions on first load attempt', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + // Wait for initial load + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.getFlagDefinitions).toHaveBeenCalled() + }) + + it('uses cached data to initialize flags when available', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + // Wait for initial load from cache + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.getFlagDefinitions).toHaveBeenCalled() + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('proceeds to fetch when cache returns undefined', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.getFlagDefinitions).toHaveBeenCalled() + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it('emits localEvaluationFlagsLoaded event with correct flag count after loading from cache', async () => { + const onLoadMock = jest.fn() + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + posthog.on('localEvaluationFlagsLoaded', onLoadMock) + + await jest.runOnlyPendingTimersAsync() + + expect(onLoadMock).toHaveBeenCalledWith(1) + }) + }) + + describe('Fetch Coordination', () => { + it('calls shouldFetchFlagDefinitions before each poll', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.shouldFetchFlagDefinitions).toHaveBeenCalled() + }) + + it('fetches and calls onFlagDefinitionsReceived when shouldFetch returns true', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + expect(mockCacheProvider.onFlagDefinitionsReceived).toHaveBeenCalledWith(testFlagData) + }) + + it('skips fetch and reloads from cache when shouldFetch returns false', async () => { + // First call returns undefined (initial state) + // Subsequent calls return cached data (after another worker fetched) + mockCacheProvider.getFlagDefinitions.mockReturnValueOnce(undefined).mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + // Should not fetch from API when shouldFetch is false and we have flags from cache + expect(mockCacheProvider.shouldFetchFlagDefinitions).toHaveBeenCalled() + // getFlagDefinitions called multiple times to reload from cache + expect(mockCacheProvider.getFlagDefinitions.mock.calls.length).toBeGreaterThanOrEqual(2) + }) + + it('emergency fallback: fetches when shouldFetch is false, cache is empty, AND no flags loaded', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + // Should fetch despite shouldFetch returning false because we have no flags at all + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it("doesn't call onFlagDefinitionsReceived when fetch is skipped", async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.onFlagDefinitionsReceived).not.toHaveBeenCalled() + }) + }) + + describe('Error Handling', () => { + it('catches getFlagDefinitions errors, logs them, continues initialization', async () => { + const error = new Error('Cache read failed') + mockCacheProvider.getFlagDefinitions.mockImplementation(() => { + throw error + }) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + posthog.on('error', onErrorMock) + + await jest.runOnlyPendingTimersAsync() + + // Error might be emitted, but the key is that initialization continues + // Should still fetch from API despite cache error + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('catches shouldFetchFlagDefinitions errors, defaults to fetching', async () => { + const error = new Error('Distributed lock failed') + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockRejectedValue(error) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + posthog.on('error', onErrorMock) + + await jest.runOnlyPendingTimersAsync() + + expect(onErrorMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('Error in shouldFetchFlagDefinitions'), + }) + ) + // Should still fetch as a safe default + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it('catches onFlagDefinitionsReceived errors, keeps flags in memory', async () => { + const error = new Error('Cache write failed') + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + mockCacheProvider.onFlagDefinitionsReceived.mockRejectedValue(error) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + posthog.on('error', onErrorMock) + + await jest.runOnlyPendingTimersAsync() + + expect(onErrorMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('Failed to store in cache'), + }) + ) + // Flags should still be available in memory + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('catches shutdown errors, logs and continues', async () => { + const error = new Error('Failed to release lock') + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + mockCacheProvider.shutdown.mockRejectedValue(error) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + posthog.on('error', onErrorMock) + + await jest.runOnlyPendingTimersAsync() + await posthog.shutdown() + + expect(onErrorMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('Error during cache shutdown'), + }) + ) + expect(mockCacheProvider.shutdown).toHaveBeenCalled() + }) + }) + + describe('Async/Sync Compatibility', () => { + it('works with sync getFlagDefinitions', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('works with async getFlagDefinitions', async () => { + mockCacheProvider.getFlagDefinitions.mockResolvedValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('works with sync shouldFetchFlagDefinitions', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockReturnValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.shouldFetchFlagDefinitions).toHaveBeenCalled() + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it('works with async shouldFetchFlagDefinitions', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.shouldFetchFlagDefinitions).toHaveBeenCalled() + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it('works with async shutdown', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + mockCacheProvider.shutdown.mockResolvedValue(undefined) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + await posthog.shutdown() + + expect(mockCacheProvider.shutdown).toHaveBeenCalled() + }) + + it('works with sync shutdown', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + mockCacheProvider.shutdown.mockReturnValue(undefined) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + await posthog.shutdown() + + expect(mockCacheProvider.shutdown).toHaveBeenCalled() + }) + }) + + describe('Data Flow and Edge Cases', () => { + it('flags loaded from cache are immediately available for evaluation', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + const flagValue = await posthog.getFeatureFlag('test-flag', 'user-123') + expect(flagValue).toBeDefined() + }) + + it('flags fetched from API are stored via onFlagDefinitionsReceived', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(undefined) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(true) + + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(mockCacheProvider.onFlagDefinitionsReceived).toHaveBeenCalledWith(testFlagData) + expect(posthog.isLocalEvaluationReady()).toBe(true) + }) + + it('cache provider integrates successfully with flag loading', async () => { + mockCacheProvider.getFlagDefinitions.mockReturnValue(testFlagData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + // Verify cache provider was used to load flags + expect(mockCacheProvider.getFlagDefinitions).toHaveBeenCalled() + + // Verify flags were loaded from cache + expect(posthog.isLocalEvaluationReady()).toBe(true) + const flagValue = await posthog.getFeatureFlag('test-flag', 'user-123') + expect(flagValue).toBeDefined() + }) + + it('works without cache provider (null/undefined)', async () => { + mockedFetch.mockImplementation(apiImplementation({ localFlags: testFlagDataApiResponse })) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + expect(posthog.isLocalEvaluationReady()).toBe(true) + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) + }) + + it('handles cache provider returning stale data gracefully', async () => { + const staleData: FlagDefinitionCacheData = { + flags: [ + { + id: 999, + name: 'Old Flag', + key: 'old-flag', + active: false, + deleted: true, + rollout_percentage: null, + ensure_experience_continuity: false, + experiment_set: [], + } as PostHogFeatureFlag, + ], + groupTypeMapping: {}, + cohorts: {}, + } + + mockCacheProvider.getFlagDefinitions.mockReturnValue(staleData) + mockCacheProvider.shouldFetchFlagDefinitions.mockResolvedValue(false) + + posthog = new PostHog('TEST_API_KEY', { + host: 'http://example.com', + personalApiKey: 'TEST_PERSONAL_API_KEY', + flagDefinitionCacheProvider: mockCacheProvider, + fetchRetryCount: 0, + }) + + await jest.runOnlyPendingTimersAsync() + + // Should still initialize with stale data + expect(posthog.isLocalEvaluationReady()).toBe(true) + + // But flag should evaluate to false since it's inactive + const flagValue = await posthog.getFeatureFlag('old-flag', 'user-123') + expect(flagValue).toBe(false) + }) + }) +}) diff --git a/packages/node/src/__tests__/posthog-node.spec.ts b/packages/node/src/__tests__/posthog-node.spec.ts index f127850c28..22c29ce0f6 100644 --- a/packages/node/src/__tests__/posthog-node.spec.ts +++ b/packages/node/src/__tests__/posthog-node.spec.ts @@ -2238,16 +2238,14 @@ describe('PostHog Node.js', () => { disableCompression: true, }) + expect(mockedFetch).toHaveBeenCalledTimes(1) + expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) mockedFetch.mockClear() - expect(mockedFetch).toHaveBeenCalledTimes(0) await expect( posthog.getFeatureFlagPayload('feature-array', '123', true, { onlyEvaluateLocally: true }) ).resolves.toEqual([1]) - expect(mockedFetch).toHaveBeenCalledTimes(1) - expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) - - mockedFetch.mockClear() + expect(mockedFetch).toHaveBeenCalledTimes(0) await expect(posthog.getFeatureFlagPayload('feature-array', '123')).resolves.toEqual([1]) expect(mockedFetch).toHaveBeenCalledTimes(0) diff --git a/packages/node/src/client.ts b/packages/node/src/client.ts index 0aa30a6b72..9c2ce55f69 100644 --- a/packages/node/src/client.ts +++ b/packages/node/src/client.ts @@ -112,6 +112,7 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen this._events.emit('localEvaluationFlagsLoaded', count) }, customHeaders: this.getCustomHeaders(), + cacheProvider: options.flagDefinitionCacheProvider, }) } } @@ -1179,7 +1180,7 @@ export abstract class PostHogBackendClient extends PostHogCoreStateless implemen * @returns Promise that resolves when shutdown is complete */ async _shutdown(shutdownTimeoutMs?: number): Promise { - this.featureFlagsPoller?.stopPoller() + this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs) this.errorTracking.shutdown() return super._shutdown(shutdownTimeoutMs) } diff --git a/packages/node/src/experimental.ts b/packages/node/src/experimental.ts new file mode 100644 index 0000000000..34ffb6a4b1 --- /dev/null +++ b/packages/node/src/experimental.ts @@ -0,0 +1,11 @@ +/** + * Experimental APIs + * + * This module exports experimental features that may change or be removed in minor versions. + * Use these APIs with caution and be prepared for breaking changes. + * + * @packageDocumentation + * @experimental + */ + +export type { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from './extensions/feature-flags/cache' diff --git a/packages/node/src/extensions/feature-flags/cache.ts b/packages/node/src/extensions/feature-flags/cache.ts new file mode 100644 index 0000000000..52e224ffa0 --- /dev/null +++ b/packages/node/src/extensions/feature-flags/cache.ts @@ -0,0 +1,114 @@ +import type { PostHogFeatureFlag, PropertyGroup } from '../../types' + +/** + * Represents the complete set of feature flag data needed for local evaluation. + * + * This includes flag definitions, group type mappings, and cohort property groups. + */ +export interface FlagDefinitionCacheData { + /** Array of feature flag definitions */ + flags: PostHogFeatureFlag[] + /** Mapping of group type index to group name */ + groupTypeMapping: Record + /** Cohort property groups for local evaluation */ + cohorts: Record +} + +/** + * @experimental This API is experimental and may change in minor versions. + * + * Provider interface for caching feature flag definitions. + * + * Implementations can use this to control when flag definitions are fetched + * and how they're cached (Redis, database, filesystem, etc.). + * + * This interface is designed for server-side environments where multiple workers + * need to share flag definitions and coordinate fetching to reduce API calls. + * + * All methods may throw errors - the poller will catch and log them gracefully, + * ensuring cache provider errors never break flag evaluation. + * + * @example + * ```typescript + * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental' + * + * class RedisFlagCache implements FlagDefinitionCacheProvider { + * constructor(private redis: Redis, private teamKey: string) { } + * + * async getFlagDefinitions(): Promise { + * const cached = await this.redis.get(`posthog:flags:${this.teamKey}`) + * return cached ? JSON.parse(cached) : undefined + * } + * + * async shouldFetchFlagDefinitions(): Promise { + * // Acquire distributed lock - only one worker fetches + * const acquired = await this.redis.set(`posthog:flags:${this.teamKey}:lock`, '1', 'EX', 60, 'NX') + * return acquired === 'OK' + * } + * + * async onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise { + * await this.redis.set(`posthog:flags:${this.teamKey}`, JSON.stringify(data), 'EX', 300) + * await this.redis.del(`posthog:flags:${this.teamKey}:lock`) + * } + * + * async shutdown(): Promise { + * await this.redis.del(`posthog:flags:${this.teamKey}:lock`) + * } + * } + * ``` + */ +export interface FlagDefinitionCacheProvider { + /** + * Retrieve cached flag definitions. + * + * Called when the poller is refreshing in-memory flag definitions. If this returns undefined + * (or throws an error), the poller will fetch fresh data from the PostHog API if no flag + * definitions are in memory. Otherwise, stale cache data is used until the next poll cycle. + * + * @returns cached definitions if available, undefined if cache is empty + * @throws if an error occurs while accessing the cache (error will be logged) + */ + getFlagDefinitions(): Promise | FlagDefinitionCacheData | undefined + + /** + * Determines whether this instance should fetch new flag definitions. + * + * Use this to implement distributed coordination (e.g., via distributed locks) + * to ensure only one instance fetches at a time in a multi-worker setup. + * + * When multiple workers share a cache, typically only one should fetch while + * others use cached data. Implementations can use Redis locks, database locks, + * or other coordination mechanisms. + * + * @returns true if this instance should fetch, false to skip and read cache + * @throws if coordination backend is unavailable (error will be logged, fetch continues) + */ + shouldFetchFlagDefinitions(): Promise | boolean + + /** + * Called after successfully receiving new flag definitions from PostHog. + * + * Store the definitions in your cache backend here. This is called only + * after a successful API response with valid flag data. + * + * If this method throws, the error is logged but flag definitions are still + * stored in memory, ensuring local evaluation can still be performed. + * + * @param data - The complete flag definition data from PostHog + * @throws if storage backend is unavailable (error will be logged) + */ + onFlagDefinitionsReceived(data: FlagDefinitionCacheData): Promise | void + + /** + * Called when the PostHog client shuts down. + * + * Release any held locks, close connections, or clean up resources here. + * + * Both sync and async cleanup are supported. Async cleanup has a timeout + * (default 30s, configurable via client shutdown options) to prevent the + * process shutdown from hanging indefinitely. + * + * @returns Promise that resolves when cleanup is complete, or void for sync cleanup + */ + shutdown(): Promise | void +} diff --git a/packages/node/src/extensions/feature-flags/feature-flags.ts b/packages/node/src/extensions/feature-flags/feature-flags.ts index 77f735bd84..25cfd49f9b 100644 --- a/packages/node/src/extensions/feature-flags/feature-flags.ts +++ b/packages/node/src/extensions/feature-flags/feature-flags.ts @@ -2,6 +2,7 @@ import { FeatureFlagCondition, FlagProperty, FlagPropertyValue, PostHogFeatureFl import type { FeatureFlagValue, JsonType, PostHogFetchOptions, PostHogFetchResponse } from '@posthog/core' import { safeSetTimeout } from '@posthog/core' import { hashSHA1 } from './crypto' +import { FlagDefinitionCacheProvider, FlagDefinitionCacheData } from './cache' const SIXTY_SECONDS = 60 * 1000 @@ -53,6 +54,7 @@ type FeatureFlagsPollerOptions = { onError?: (error: Error) => void onLoad?: (count: number) => void customHeaders?: { [key: string]: string } + cacheProvider?: FlagDefinitionCacheProvider } class FeatureFlagsPoller { @@ -74,6 +76,9 @@ class FeatureFlagsPoller { shouldBeginExponentialBackoff: boolean = false backOffCount: number = 0 onLoad?: (count: number) => void + private cacheProvider?: FlagDefinitionCacheProvider + private hasAttemptedCacheLoad: boolean = false + private loadingPromise?: Promise constructor({ pollingInterval, @@ -99,6 +104,7 @@ class FeatureFlagsPoller { this.onError = options.onError this.customHeaders = customHeaders this.onLoad = options.onLoad + this.cacheProvider = options.cacheProvider void this.loadFeatureFlags() } @@ -537,9 +543,59 @@ class FeatureFlagsPoller { return lookupTable } + /** + * Updates the internal flag state with the provided flag data. + */ + private updateFlagState(flagData: FlagDefinitionCacheData): void { + this.featureFlags = flagData.flags + this.featureFlagsByKey = flagData.flags.reduce( + (acc, curr) => ((acc[curr.key] = curr), acc), + >{} + ) + this.groupTypeMapping = flagData.groupTypeMapping + this.cohorts = flagData.cohorts + this.loadedSuccessfullyOnce = true + } + + /** + * Attempts to load flags from cache and update internal state. + * Returns true if flags were successfully loaded from cache, false otherwise. + */ + private async loadFromCache(debugMessage: string): Promise { + if (!this.cacheProvider) { + return false + } + + try { + const cached = await this.cacheProvider.getFlagDefinitions() + if (cached) { + this.updateFlagState(cached) + this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`)) + this.onLoad?.(this.featureFlags.length) + return true + } + return false + } catch (err) { + this.onError?.(new Error(`Failed to load from cache: ${err}`)) + return false + } + } + async loadFeatureFlags(forceReload = false): Promise { + // On first load, try to initialize from cache (if a cache provider is configured) + if (this.cacheProvider && !this.hasAttemptedCacheLoad) { + this.hasAttemptedCacheLoad = true + await this.loadFromCache('Loaded flags from cache') + } + + // If a fetch is already in progress, wait for it + if (this.loadingPromise) { + return this.loadingPromise + } + if (!this.loadedSuccessfullyOnce || forceReload) { - await this._loadFeatureFlags() + this.loadingPromise = this._loadFeatureFlags() + await this.loadingPromise } } @@ -574,6 +630,42 @@ class FeatureFlagsPoller { this.poller = setTimeout(() => this._loadFeatureFlags(), this.getPollingInterval()) try { + let shouldFetch = true + if (this.cacheProvider) { + try { + shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions() + } catch (err) { + this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`)) + // Important: if `shouldFetchFlagDefinitions` throws, we + // default to fetching. + } + } + + if (!shouldFetch) { + // If we're not supposed to fetch, we assume another instance + // is handling it. In this case, we'll just reload from cache. + const loaded = await this.loadFromCache('Loaded flags from cache (skipped fetch)') + if (loaded) { + return + } + + if (this.loadedSuccessfullyOnce) { + // Respect the decision to not fetch, even if it means + // keeping stale feature flags. + return + } + + // If we've gotten here: + // - A cache provider is configured + // - We've been asked not to fetch + // - We failed to load from cache + // - We have no feature flag definitions to work with. + // + // This is the only case where we'll ignore the shouldFetch + // decision and proceed to fetch, because the alternative is + // worse: local evaluation is impossible. + } + const res = await this._requestFeatureFlagDefinitions() // Handle undefined res case, this shouldn't happen, but it doesn't hurt to handle it anyway @@ -637,16 +729,28 @@ class FeatureFlagsPoller { return } - this.featureFlags = (responseJson.flags as PostHogFeatureFlag[]) ?? [] - this.featureFlagsByKey = this.featureFlags.reduce( - (acc, curr) => ((acc[curr.key] = curr), acc), - >{} - ) - this.groupTypeMapping = (responseJson.group_type_mapping as Record) || {} - this.cohorts = (responseJson.cohorts as Record) || {} - this.loadedSuccessfullyOnce = true + const flagData: FlagDefinitionCacheData = { + flags: (responseJson.flags as PostHogFeatureFlag[]) ?? [], + groupTypeMapping: (responseJson.group_type_mapping as Record) || {}, + cohorts: (responseJson.cohorts as Record) || {}, + } + + this.updateFlagState(flagData) this.shouldBeginExponentialBackoff = false this.backOffCount = 0 + + if (this.cacheProvider && shouldFetch) { + // Only notify the cache if it's actually expecting new data + // E.g., if we weren't supposed to fetch but we missed the + // cache, we may not have a lock, so we skip this step + try { + await this.cacheProvider.onFlagDefinitionsReceived(flagData) + } catch (err) { + this.onError?.(new Error(`Failed to store in cache: ${err}`)) + // Continue anyway, the data at least made it to memory + } + } + this.onLoad?.(this.featureFlags.length) break } @@ -660,6 +764,8 @@ class FeatureFlagsPoller { if (err instanceof ClientError) { this.onError?.(err) } + } finally { + this.loadingPromise = undefined } } @@ -674,7 +780,7 @@ class FeatureFlagsPoller { } } - async _requestFeatureFlagDefinitions(): Promise { + _requestFeatureFlagDefinitions(): Promise { const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts` const options = this.getPersonalApiKeyRequestOptions() @@ -690,14 +796,34 @@ class FeatureFlagsPoller { } try { - return await this.fetch(url, options) + return this.fetch(url, options) } finally { clearTimeout(abortTimeout) } } - stopPoller(): void { + async stopPoller(timeoutMs: number = 30000): Promise { clearTimeout(this.poller) + + if (this.cacheProvider) { + try { + const shutdownResult = this.cacheProvider.shutdown() + + if (shutdownResult instanceof Promise) { + // This follows the same timeout logic defined in _shutdown. + // We time out after some period of time to avoid hanging the entire + // shutdown process if the cache provider misbehaves. + await Promise.race([ + shutdownResult, + new Promise((_, reject) => + setTimeout(() => reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs) + ), + ]) + } + } catch (err) { + this.onError?.(new Error(`Error during cache shutdown: ${err}`)) + } + } } } diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts index 935c7880e3..b5d9321d2d 100644 --- a/packages/node/src/types.ts +++ b/packages/node/src/types.ts @@ -6,6 +6,8 @@ import type { PostHogFetchResponse, } from '@posthog/core' +import type { FlagDefinitionCacheProvider } from './extensions/feature-flags/cache' + export interface IdentifyMessage { distinctId: string properties?: Record @@ -72,6 +74,32 @@ export type PostHogOptions = PostHogCoreOptions & { // Whether to enable feature flag polling for local evaluation by default. Defaults to true when personalApiKey is provided. // We recommend setting this to false if you are only using the personalApiKey for evaluating remote config payloads via `getRemoteConfigPayload` and not using local evaluation. enableLocalEvaluation?: boolean + /** + * @experimental This API is experimental and may change in minor versions. + * + * Optional cache provider for feature flag definitions. + * + * Allows custom caching strategies (Redis, database, etc.) for flag definitions + * in multi-worker environments. If not provided, defaults to in-memory cache. + * + * This enables distributed coordination where only one worker fetches flags while + * others use cached data, reducing API calls and improving performance. + * + * @example + * ```typescript + * import { FlagDefinitionCacheProvider } from 'posthog-node/experimental' + * + * class RedisCacheProvider implements FlagDefinitionCacheProvider { + * // ... implementation + * } + * + * const client = new PostHog('api-key', { + * personalApiKey: 'personal-key', + * flagDefinitionCacheProvider: new RedisCacheProvider(redis) + * }) + * ``` + */ + flagDefinitionCacheProvider?: FlagDefinitionCacheProvider /** * Allows modification or dropping of events before they're sent to PostHog. * If an array is provided, the functions are run in order. diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 0863c17a1b..d340881d3f 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -47,6 +47,7 @@ "@react-navigation/native": "^5.0.10", "@types/react": "^17.0.87", "@types/react-native": "^0.69.1", + "@types/jest": "catalog:", "expo": "^45.0.6", "expo-application": "^4.0.0", "expo-device": "^4.0.0", diff --git a/packages/react/package.json b/packages/react/package.json index b3293c802c..a28e6cdecb 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -47,6 +47,7 @@ "@testing-library/react": "^11.2.2", "@testing-library/react-hooks": "^8.0.1", "@types/react": "^17.0.0", + "@types/jest": "catalog:", "cross-env": "^7.0.3", "jest": "catalog:", "jest-environment-jsdom": "catalog:", diff --git a/packages/web/package.json b/packages/web/package.json index ae335f71fa..6e47ff3f70 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -31,6 +31,7 @@ "devDependencies": { "@posthog-tooling/tsconfig-base": "workspace:*", "@posthog-tooling/rollup-utils": "workspace:*", + "@types/jest": "catalog:", "jest": "catalog:", "jest-environment-jsdom": "catalog:" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58aba3389b..5a6497f8b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,10 +8,13 @@ catalogs: default: '@posthog/cli': specifier: ~0.5.9 - version: 0.5.11 + version: 0.5.12 '@rslib/core': specifier: ^0.10.5 version: 0.10.6 + '@types/jest': + specifier: ^29.5.0 + version: 29.5.14 jest: specifier: ^29.7.0 version: 29.7.0 @@ -26,7 +29,7 @@ catalogs: version: 47.0.1 rollup: specifier: ^4.44.1 - version: 4.50.0 + version: 4.52.4 ts-jest: specifier: 29.4.0 version: 29.4.0 @@ -67,9 +70,6 @@ importers: '@types/eslint': specifier: ^8.44.6 version: 8.44.6 - '@types/jest': - specifier: ^28.1.5 - version: 28.1.8 '@types/node': specifier: ^22.17.0 version: 22.17.0 @@ -120,7 +120,7 @@ importers: version: 6.0.1 rollup: specifier: 'catalog:' - version: 4.50.0 + version: 4.52.4 ts-node: specifier: ^10.9.1 version: 10.9.2(@types/node@22.17.0)(typescript@5.8.2) @@ -167,6 +167,9 @@ importers: '@posthog-tooling/tsconfig-base': specifier: workspace:* version: link:../../tooling/tsconfig-base + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 jest: specifier: 'catalog:' version: 29.7.0(@types/node@22.17.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) @@ -409,6 +412,9 @@ importers: '@types/cross-spawn': specifier: ^6.0.6 version: 6.0.6 + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 jest: specifier: 'catalog:' version: 29.7.0(@types/node@22.17.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) @@ -417,7 +423,7 @@ importers: dependencies: '@posthog/cli': specifier: 'catalog:' - version: 0.5.11 + version: 0.5.12 '@posthog/core': specifier: workspace:* version: link:../core @@ -434,6 +440,9 @@ importers: '@rslib/core': specifier: 'catalog:' version: 0.10.6(@microsoft/api-extractor@7.52.8(@types/node@22.16.5))(typescript@5.8.2) + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 '@types/node': specifier: ^22.15.23 version: 22.16.5 @@ -442,13 +451,13 @@ importers: version: 7.7.0 jest: specifier: 'catalog:' - version: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + version: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) next: specifier: ^15.4.1 version: 15.4.6(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) ts-jest: specifier: 'catalog:' - version: 29.4.0(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.4.0(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)))(typescript@5.8.2) packages/node: dependencies: @@ -462,12 +471,15 @@ importers: '@rslib/core': specifier: 'catalog:' version: 0.10.6(@microsoft/api-extractor@7.52.8(@types/node@20.19.9))(typescript@5.8.2) + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 '@types/node': specifier: ^20.0.0 version: 20.19.9 jest: specifier: 'catalog:' - version: 29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) packages/nuxt: dependencies: @@ -476,7 +488,7 @@ importers: version: 4.1.3(magicast@0.3.5) '@posthog/cli': specifier: 'catalog:' - version: 0.5.11 + version: 0.5.12 '@posthog/core': specifier: workspace:* version: link:../core @@ -507,7 +519,7 @@ importers: version: 9.37.0(jiti@2.6.1) nuxt: specifier: ^4.1.2 - version: 4.1.3(@parcel/watcher@2.5.1)(@types/node@20.19.9)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.50.0)(terser@5.27.0)(typescript@5.8.2)(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(yaml@2.8.0) + version: 4.1.3(@parcel/watcher@2.5.1)(@types/node@20.19.9)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.52.4)(terser@5.27.0)(typescript@5.8.2)(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(yaml@2.8.0) packages/react: devDependencies: @@ -532,6 +544,9 @@ importers: '@testing-library/react-hooks': specifier: ^8.0.1 version: 8.0.1(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react-test-renderer@17.0.2(react@17.0.2))(react@17.0.2) + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 '@types/react': specifier: ^17.0.0 version: 17.0.87 @@ -599,6 +614,9 @@ importers: '@react-navigation/native': specifier: ^5.0.10 version: 5.9.8(react-native@0.69.12(@babel/core@7.27.1)(@babel/preset-env@7.27.2(@babel/core@7.27.1))(react@18.2.0))(react@18.2.0) + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 '@types/react': specifier: ^17.0.87 version: 17.0.87 @@ -675,6 +693,9 @@ importers: '@posthog-tooling/tsconfig-base': specifier: workspace:* version: link:../../tooling/tsconfig-base + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 jest: specifier: 'catalog:' version: 29.7.0(@types/node@22.17.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) @@ -700,26 +721,26 @@ importers: version: 7.27.1(@babel/core@7.27.1) '@rollup/plugin-babel': specifier: ^6.0.4 - version: 6.0.4(@babel/core@7.27.1)(@types/babel__core@7.1.18)(rollup@4.50.0) + version: 6.0.4(@babel/core@7.27.1)(@types/babel__core@7.1.18)(rollup@4.52.4) '@rollup/plugin-commonjs': specifier: ^28.0.6 - version: 28.0.6(rollup@4.50.0) + version: 28.0.6(rollup@4.52.4) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.50.0) + version: 6.1.0(rollup@4.52.4) '@rollup/plugin-node-resolve': specifier: ^16.0.1 - version: 16.0.1(rollup@4.50.0) + version: 16.0.1(rollup@4.52.4) '@rollup/plugin-typescript': specifier: ^12.1.4 - version: 12.1.4(rollup@4.50.0)(tslib@2.8.1)(typescript@5.8.2) + version: 12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.8.2) rollup-plugin-dts: specifier: ^6.1.1 - version: 6.1.1(rollup@4.50.0)(typescript@5.8.2) + version: 6.1.1(rollup@4.52.4)(typescript@5.8.2) devDependencies: rollup: specifier: 'catalog:' - version: 4.50.0 + version: 4.52.4 typescript: specifier: 'catalog:' version: 5.8.2 @@ -2354,10 +2375,6 @@ packages: resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/expect-utils@28.1.3': - resolution: {integrity: sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - '@jest/expect-utils@29.7.0': resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2383,10 +2400,6 @@ packages: node-notifier: optional: true - '@jest/schemas@28.1.3': - resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2423,10 +2436,6 @@ packages: resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - '@jest/types@28.1.3': - resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3273,8 +3282,8 @@ packages: '@poppinss/exception@1.2.2': resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==} - '@posthog/cli@0.5.11': - resolution: {integrity: sha512-dd8KDlYgA7rw089X8s4tzI7yfo91Db43tbzWHAzA828/HYR8ALp+1BQjYKdRXlYnt2ihzvtZWtWkcedSUPgjLA==} + '@posthog/cli@0.5.12': + resolution: {integrity: sha512-woMmA4ChCzpJUa939SKfc11bYDNSkqHvhcvPn+EarV1ivIkmBu9gBOAZW1S/MfH76LCJE7tesuR0EOxo0zYjvw==} engines: {node: '>=14', npm: '>=6'} hasBin: true @@ -3871,9 +3880,6 @@ packages: '@sideway/pinpoint@2.0.0': resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sinclair/typebox@0.24.51': - resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -4076,9 +4082,6 @@ packages: '@types/istanbul-reports@3.0.0': resolution: {integrity: sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==} - '@types/jest@28.1.8': - resolution: {integrity: sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==} - '@types/jest@29.5.14': resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} @@ -6133,10 +6136,6 @@ packages: device-specs@1.0.0: resolution: {integrity: sha512-fYXbFSeilT7bnKWFi4OERSPHdtaEoDGn4aUhV5Nly6/I+Tp6JZ/6Icmd7LVIF5euyodGpxz2e/bfUmDnIdSIDw==} - diff-sequences@28.1.1: - resolution: {integrity: sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6712,10 +6711,6 @@ packages: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} - expect@28.1.3: - resolution: {integrity: sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6875,14 +6870,6 @@ packages: picomatch: optional: true - fdir@6.4.6: - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -8284,10 +8271,6 @@ packages: ts-node: optional: true - jest-diff@28.1.3: - resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8321,10 +8304,6 @@ packages: resolution: {integrity: sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==} engines: {node: '>= 10.14.2'} - jest-get-type@28.0.2: - resolution: {integrity: sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8345,10 +8324,6 @@ packages: resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-matcher-utils@28.1.3: - resolution: {integrity: sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8357,10 +8332,6 @@ packages: resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - jest-message-util@28.1.3: - resolution: {integrity: sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8426,10 +8397,6 @@ packages: resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - jest-util@28.1.3: - resolution: {integrity: sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8495,10 +8462,6 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -10710,10 +10673,6 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@28.1.3: - resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -12159,10 +12118,6 @@ packages: tinyexec@1.0.1: resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -15553,80 +15508,6 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0(node-notifier@8.0.2) - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.17.0 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.9 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.17.0)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - optionalDependencies: - node-notifier: 8.0.2 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - - '@jest/core@29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0(node-notifier@8.0.2) - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.17.0 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.9 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.17.0)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - optionalDependencies: - node-notifier: 8.0.2 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/core@29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2))': dependencies: '@jest/console': 29.7.0 @@ -15712,10 +15593,6 @@ snapshots: '@types/node': 22.17.0 jest-mock: 29.7.0 - '@jest/expect-utils@28.1.3': - dependencies: - jest-get-type: 28.0.2 - '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 @@ -15776,10 +15653,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@jest/schemas@28.1.3': - dependencies: - '@sinclair/typebox': 0.24.51 - '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 @@ -15867,15 +15740,6 @@ snapshots: '@types/yargs': 16.0.4 chalk: 4.1.2 - '@jest/types@28.1.3': - dependencies: - '@jest/schemas': 28.1.3 - '@types/istanbul-lib-coverage': 2.0.3 - '@types/istanbul-reports': 3.0.0 - '@types/node': 22.17.0 - '@types/yargs': 17.0.24 - chalk: 4.1.2 - '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 @@ -16696,10 +16560,10 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/vite-builder@4.1.3(@types/node@20.19.9)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.50.0)(terser@5.27.0)(typescript@5.8.2)(vue@3.5.22(typescript@5.8.2))(yaml@2.8.0)': + '@nuxt/vite-builder@4.1.3(@types/node@20.19.9)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.52.4)(terser@5.27.0)(typescript@5.8.2)(vue@3.5.22(typescript@5.8.2))(yaml@2.8.0)': dependencies: '@nuxt/kit': 4.1.3(magicast@0.3.5) - '@rollup/plugin-replace': 6.0.2(rollup@4.50.0) + '@rollup/plugin-replace': 6.0.2(rollup@4.52.4) '@vitejs/plugin-vue': 6.0.1(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(vue@3.5.22(typescript@5.8.2)) '@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(vue@3.5.22(typescript@5.8.2)) autoprefixer: 10.4.21(postcss@8.5.6) @@ -16719,7 +16583,7 @@ snapshots: pathe: 2.0.3 pkg-types: 2.3.0 postcss: 8.5.6 - rollup-plugin-visualizer: 6.0.4(rollup@4.50.0) + rollup-plugin-visualizer: 6.0.4(rollup@4.52.4) std-env: 3.9.0 ufo: 1.6.1 unenv: 2.0.0-rc.21 @@ -16988,7 +16852,7 @@ snapshots: '@poppinss/exception@1.2.2': {} - '@posthog/cli@0.5.11': + '@posthog/cli@0.5.12': dependencies: axios: 1.12.2 axios-proxy-builder: 0.1.2 @@ -17307,10 +17171,6 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.42': {} - '@rollup/plugin-alias@5.1.1(rollup@4.50.0)': - optionalDependencies: - rollup: 4.50.0 - '@rollup/plugin-alias@5.1.1(rollup@4.52.4)': optionalDependencies: rollup: 4.52.4 @@ -17326,6 +17186,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@rollup/plugin-babel@6.0.4(@babel/core@7.27.1)(@types/babel__core@7.1.18)(rollup@4.52.4)': + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@rollup/pluginutils': 5.1.0(rollup@4.52.4) + optionalDependencies: + '@types/babel__core': 7.1.18 + rollup: 4.52.4 + transitivePeerDependencies: + - supports-color + '@rollup/plugin-commonjs@28.0.6(rollup@4.50.0)': dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.50.0) @@ -17403,13 +17274,6 @@ snapshots: magic-string: 0.25.9 rollup: 2.79.2 - '@rollup/plugin-replace@6.0.2(rollup@4.50.0)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.50.0) - magic-string: 0.30.19 - optionalDependencies: - rollup: 4.50.0 - '@rollup/plugin-replace@6.0.2(rollup@4.52.4)': dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.52.4) @@ -17442,6 +17306,15 @@ snapshots: rollup: 4.50.0 tslib: 2.8.1 + '@rollup/plugin-typescript@12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.8.2)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.52.4) + resolve: 1.22.8 + typescript: 5.8.2 + optionalDependencies: + rollup: 4.52.4 + tslib: 2.8.1 + '@rollup/pluginutils@3.1.0(rollup@2.79.2)': dependencies: '@types/estree': 0.0.39 @@ -17465,14 +17338,6 @@ snapshots: optionalDependencies: rollup: 4.52.4 - '@rollup/pluginutils@5.3.0(rollup@4.50.0)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.50.0 - '@rollup/pluginutils@5.3.0(rollup@4.52.4)': dependencies: '@types/estree': 1.0.8 @@ -17631,13 +17496,13 @@ snapshots: '@rspack/lite-tapable': 1.0.1 '@swc/helpers': 0.5.17 core-js: 3.44.0 - jiti: 2.4.2 + jiti: 2.6.1 '@rslib/core@0.10.6(@microsoft/api-extractor@7.52.8(@types/node@20.19.9))(typescript@5.8.2)': dependencies: '@rsbuild/core': 1.4.8 rsbuild-plugin-dts: 0.10.6(@microsoft/api-extractor@7.52.8(@types/node@20.19.9))(@rsbuild/core@1.4.8)(typescript@5.8.2) - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@20.19.9) typescript: 5.8.2 @@ -17646,7 +17511,7 @@ snapshots: dependencies: '@rsbuild/core': 1.4.8 rsbuild-plugin-dts: 0.10.6(@microsoft/api-extractor@7.52.8(@types/node@22.16.5))(@rsbuild/core@1.4.8)(typescript@5.8.2) - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@22.16.5) typescript: 5.8.2 @@ -17655,7 +17520,7 @@ snapshots: dependencies: '@rsbuild/core': 1.4.8 rsbuild-plugin-dts: 0.10.6(@microsoft/api-extractor@7.52.8(@types/node@22.17.0))(@rsbuild/core@1.4.8)(typescript@5.8.2) - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@22.17.0) typescript: 5.8.2 @@ -17830,8 +17695,6 @@ snapshots: '@sideway/pinpoint@2.0.0': {} - '@sinclair/typebox@0.24.51': {} - '@sinclair/typebox@0.27.8': {} '@sindresorhus/is@7.1.0': {} @@ -18068,11 +17931,6 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.0 - '@types/jest@28.1.8': - dependencies: - expect: 28.1.3 - pretty-format: 28.1.3 - '@types/jest@29.5.14': dependencies: expect: 29.7.0 @@ -19950,13 +19808,13 @@ snapshots: crc-32: 1.2.2 readable-stream: 4.7.0 - create-jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)): + create-jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.9 - jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -19965,13 +19823,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)): + create-jest@29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.9 - jest-config: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -20507,8 +20365,6 @@ snapshots: device-specs@1.0.0: {} - diff-sequences@28.1.1: {} - diff-sequences@29.6.3: {} diff@4.0.2: {} @@ -21308,14 +21164,6 @@ snapshots: transitivePeerDependencies: - supports-color - expect@28.1.3: - dependencies: - '@jest/expect-utils': 28.1.3 - jest-get-type: 28.0.2 - jest-matcher-utils: 28.1.3 - jest-message-util: 28.1.3 - jest-util: 28.1.3 - expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 @@ -21542,10 +21390,6 @@ snapshots: optionalDependencies: picomatch: 4.0.2 - fdir@6.4.6(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -21651,7 +21495,7 @@ snapshots: dependencies: magic-string: 0.30.17 mlly: 1.8.0 - rollup: 4.50.0 + rollup: 4.52.4 flat-cache@3.0.4: dependencies: @@ -23004,16 +22848,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)): + jest-cli@29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) exit: 0.1.2 import-local: 3.0.2 - jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -23025,16 +22869,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)): + jest-cli@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) exit: 0.1.2 import-local: 3.0.2 - jest-config: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -23088,7 +22932,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)): + jest-config@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: '@babel/core': 7.27.1 '@jest/test-sequencer': 29.7.0 @@ -23114,12 +22958,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.19.9 - ts-node: 10.9.2(@types/node@20.19.9)(typescript@5.8.2) + ts-node: 10.9.2(@types/node@22.17.0)(typescript@5.8.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)): + jest-config@29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: '@babel/core': 7.27.1 '@jest/test-sequencer': 29.7.0 @@ -23145,69 +22989,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.16.5 - ts-node: 10.9.2(@types/node@22.16.5)(typescript@5.8.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-config@29.7.0(@types/node@22.17.0)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)): - dependencies: - '@babel/core': 7.27.1 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.9 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.17.0 - ts-node: 10.9.2(@types/node@20.19.9)(typescript@5.8.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-config@29.7.0(@types/node@22.17.0)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)): - dependencies: - '@babel/core': 7.27.1 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.9 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.17.0 - ts-node: 10.9.2(@types/node@22.16.5)(typescript@5.8.2) + ts-node: 10.9.2(@types/node@22.17.0)(typescript@5.8.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -23305,13 +23087,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-diff@28.1.3: - dependencies: - chalk: 4.1.2 - diff-sequences: 28.1.1 - jest-get-type: 28.0.2 - pretty-format: 28.1.3 - jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -23374,8 +23149,6 @@ snapshots: jest-get-type@26.3.0: {} - jest-get-type@28.0.2: {} - jest-get-type@29.6.3: {} jest-haste-map@26.6.2: @@ -23436,13 +23209,6 @@ snapshots: jest-get-type: 29.6.3 pretty-format: 29.7.0 - jest-matcher-utils@28.1.3: - dependencies: - chalk: 4.1.2 - jest-diff: 28.1.3 - jest-get-type: 28.0.2 - pretty-format: 28.1.3 - jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 @@ -23462,18 +23228,6 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.5 - jest-message-util@28.1.3: - dependencies: - '@babel/code-frame': 7.27.1 - '@jest/types': 28.1.3 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.9 - micromatch: 4.0.8 - pretty-format: 28.1.3 - slash: 3.0.0 - stack-utils: 2.0.5 - jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.27.1 @@ -23627,15 +23381,6 @@ snapshots: graceful-fs: 4.2.9 picomatch: 2.3.1 - jest-util@28.1.3: - dependencies: - '@jest/types': 28.1.3 - '@types/node': 22.17.0 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.9 - picomatch: 2.3.1 - jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 @@ -23720,12 +23465,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)): + jest@29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) '@jest/types': 29.6.3 import-local: 3.0.2 - jest-cli: 29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2)) + jest-cli: 29.7.0(@types/node@20.19.9)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) optionalDependencies: node-notifier: 8.0.2 transitivePeerDependencies: @@ -23734,12 +23479,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)): + jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + '@jest/core': 29.7.0(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) '@jest/types': 29.6.3 import-local: 3.0.2 - jest-cli: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + jest-cli: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) optionalDependencies: node-notifier: 8.0.2 transitivePeerDependencies: @@ -23790,8 +23535,6 @@ snapshots: jiti@1.21.7: {} - jiti@2.4.2: {} - jiti@2.6.1: {} jju@1.4.0: {} @@ -25420,7 +25163,7 @@ snapshots: nullthrows@1.1.1: {} - nuxt@4.1.3(@parcel/watcher@2.5.1)(@types/node@20.19.9)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.50.0)(terser@5.27.0)(typescript@5.8.2)(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(yaml@2.8.0): + nuxt@4.1.3(@parcel/watcher@2.5.1)(@types/node@20.19.9)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(eslint@9.37.0(jiti@2.6.1))(ioredis@5.8.1)(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.52.4)(terser@5.27.0)(typescript@5.8.2)(vite@7.1.9(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.27.0)(terser@5.27.0)(yaml@2.8.0))(yaml@2.8.0): dependencies: '@nuxt/cli': 3.29.0(magicast@0.3.5) '@nuxt/devalue': 2.0.2 @@ -25428,7 +25171,7 @@ snapshots: '@nuxt/kit': 4.1.3(magicast@0.3.5) '@nuxt/schema': 4.1.3 '@nuxt/telemetry': 2.6.6(magicast@0.3.5) - '@nuxt/vite-builder': 4.1.3(@types/node@20.19.9)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.50.0)(terser@5.27.0)(typescript@5.8.2)(vue@3.5.22(typescript@5.8.2))(yaml@2.8.0) + '@nuxt/vite-builder': 4.1.3(@types/node@20.19.9)(eslint@9.37.0(jiti@2.6.1))(lightningcss@1.27.0)(magicast@0.3.5)(rollup@4.52.4)(terser@5.27.0)(typescript@5.8.2)(vue@3.5.22(typescript@5.8.2))(yaml@2.8.0) '@unhead/vue': 2.0.18(vue@3.5.22(typescript@5.8.2)) '@vue/shared': 3.5.22 c12: 3.3.0(magicast@0.3.5) @@ -26676,13 +26419,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-format@28.1.3: - dependencies: - '@jest/schemas': 28.1.3 - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 18.2.0 - pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -27280,10 +27016,10 @@ snapshots: globby: 10.0.1 is-plain-object: 3.0.1 - rollup-plugin-dts@6.1.1(rollup@4.50.0)(typescript@5.8.2): + rollup-plugin-dts@6.1.1(rollup@4.52.4)(typescript@5.8.2): dependencies: magic-string: 0.30.12 - rollup: 4.50.0 + rollup: 4.52.4 typescript: 5.8.2 optionalDependencies: '@babel/code-frame': 7.27.1 @@ -27296,6 +27032,14 @@ snapshots: optionalDependencies: '@babel/code-frame': 7.27.1 + rollup-plugin-dts@6.2.3(rollup@4.52.4)(typescript@5.8.2): + dependencies: + magic-string: 0.30.17 + rollup: 4.52.4 + typescript: 5.8.2 + optionalDependencies: + '@babel/code-frame': 7.27.1 + rollup-plugin-postcss@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.5.0)(typescript@5.8.2)): dependencies: chalk: 4.1.2 @@ -27333,14 +27077,14 @@ snapshots: optionalDependencies: rollup: 4.52.4 - rollup-plugin-visualizer@6.0.4(rollup@4.50.0): + rollup-plugin-visualizer@6.0.4(rollup@4.52.4): dependencies: open: 8.4.2 picomatch: 4.0.3 source-map: 0.7.6 yargs: 17.7.2 optionalDependencies: - rollup: 4.50.0 + rollup: 4.52.4 rollup-pluginutils@2.8.2: dependencies: @@ -27428,9 +27172,9 @@ snapshots: dependencies: '@ast-grep/napi': 0.37.0 '@rsbuild/core': 1.4.8 - magic-string: 0.30.17 + magic-string: 0.30.19 picocolors: 1.1.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tsconfig-paths: 4.2.0 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@20.19.9) @@ -27440,9 +27184,9 @@ snapshots: dependencies: '@ast-grep/napi': 0.37.0 '@rsbuild/core': 1.4.8 - magic-string: 0.30.17 + magic-string: 0.30.19 picocolors: 1.1.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tsconfig-paths: 4.2.0 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@22.16.5) @@ -27452,9 +27196,9 @@ snapshots: dependencies: '@ast-grep/napi': 0.37.0 '@rsbuild/core': 1.4.8 - magic-string: 0.30.17 + magic-string: 0.30.19 picocolors: 1.1.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tsconfig-paths: 4.2.0 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@22.17.0) @@ -28579,11 +28323,6 @@ snapshots: tinyexec@1.0.1: {} - tinyglobby@0.2.14: - dependencies: - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -28710,12 +28449,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.27.1) jest-util: 29.7.0 - ts-jest@29.4.0(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)))(typescript@5.8.2): + ts-jest@29.4.0(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2)) + jest: 29.7.0(@types/node@22.16.5)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -28730,44 +28469,6 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.28.4) jest-util: 29.7.0 - ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.9 - acorn: 8.11.3 - acorn-walk: 8.3.3 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - - ts-node@10.9.2(@types/node@22.16.5)(typescript@5.8.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.16.5 - acorn: 8.11.3 - acorn-walk: 8.3.3 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - ts-node@10.9.2(@types/node@22.17.0)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -28969,12 +28670,12 @@ snapshots: unbuild@3.6.1(typescript@5.8.2)(vue-sfc-transformer@0.1.17(@vue/compiler-core@3.5.22)(esbuild@0.25.10)(vue@3.5.22(typescript@5.8.2)))(vue@3.5.22(typescript@5.8.2)): dependencies: - '@rollup/plugin-alias': 5.1.1(rollup@4.50.0) - '@rollup/plugin-commonjs': 28.0.6(rollup@4.50.0) - '@rollup/plugin-json': 6.1.0(rollup@4.50.0) - '@rollup/plugin-node-resolve': 16.0.1(rollup@4.50.0) - '@rollup/plugin-replace': 6.0.2(rollup@4.50.0) - '@rollup/pluginutils': 5.3.0(rollup@4.50.0) + '@rollup/plugin-alias': 5.1.1(rollup@4.52.4) + '@rollup/plugin-commonjs': 28.0.6(rollup@4.52.4) + '@rollup/plugin-json': 6.1.0(rollup@4.52.4) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.52.4) + '@rollup/plugin-replace': 6.0.2(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.52.4) citty: 0.1.6 consola: 3.4.2 defu: 6.1.4 @@ -28988,10 +28689,10 @@ snapshots: pathe: 2.0.3 pkg-types: 2.3.0 pretty-bytes: 7.1.0 - rollup: 4.50.0 - rollup-plugin-dts: 6.2.3(rollup@4.50.0)(typescript@5.8.2) + rollup: 4.52.4 + rollup-plugin-dts: 6.2.3(rollup@4.52.4)(typescript@5.8.2) scule: 1.3.0 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 untyped: 2.0.0 optionalDependencies: typescript: 5.8.2 @@ -29377,7 +29078,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.50.0 + rollup: 4.52.4 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.19.9 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2ee76d5926..eeef63474a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -13,7 +13,7 @@ catalog: jest-environment-jsdom: ^29.7.0 jest-environment-node: ^29.7.0 jest-expo: ^47.0.1 - "@types/jest": ^29.7.0 + "@types/jest": ^29.5.0 ts-jest: 29.4.0 "@rslib/core": ^0.10.5 "@posthog/cli": ~0.5.9