mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-01 09:17:08 +02:00
fix(core): Add timeout and recovery for database connection health checks (#21506)
Co-authored-by: Declan Carroll <declan@n8n.io>
This commit is contained in:
parent
ec5e17ff4b
commit
09c8b2dea8
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { DatabaseConfig } from '@n8n/config';
|
||||
import { DataSource, type DataSourceOptions } from '@n8n/typeorm';
|
||||
import { mock, mockDeep } from 'jest-mock-extended';
|
||||
|
|
@ -9,7 +11,9 @@ import type { Migration } from '../../migrations/migration-types';
|
|||
import { DbConnection } from '../db-connection';
|
||||
import type { DbConnectionOptions } from '../db-connection-options';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
jest.mock('@n8n/typeorm', () => ({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
DataSource: jest.fn(),
|
||||
...jest.requireActual('@n8n/typeorm'),
|
||||
}));
|
||||
|
|
@ -19,6 +23,7 @@ describe('DbConnection', () => {
|
|||
const migrations = [{ name: 'TestMigration1' }, { name: 'TestMigration2' }] as Migration[];
|
||||
const errorReporter = mock<ErrorReporter>();
|
||||
const databaseConfig = mock<DatabaseConfig>();
|
||||
const logger = mock<Logger>();
|
||||
const dataSource = mockDeep<DataSource>({ options: { migrations } });
|
||||
const connectionOptions = mockDeep<DbConnectionOptions>();
|
||||
const postgresOptions: DataSourceOptions = {
|
||||
|
|
@ -37,7 +42,7 @@ describe('DbConnection', () => {
|
|||
connectionOptions.getOptions.mockReturnValue(postgresOptions);
|
||||
(DataSource as jest.Mock) = jest.fn().mockImplementation(() => dataSource);
|
||||
|
||||
dbConnection = new DbConnection(errorReporter, connectionOptions, databaseConfig);
|
||||
dbConnection = new DbConnection(errorReporter, connectionOptions, databaseConfig, logger);
|
||||
});
|
||||
|
||||
describe('init', () => {
|
||||
|
|
@ -133,6 +138,7 @@ describe('DbConnection', () => {
|
|||
it('should update connection state on successful ping', async () => {
|
||||
// @ts-expect-error readonly property
|
||||
dataSource.isInitialized = true;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
dataSource.query.mockResolvedValue([{ '1': 1 }]);
|
||||
dbConnection.connectionState.connected = false;
|
||||
|
||||
|
|
@ -158,6 +164,7 @@ describe('DbConnection', () => {
|
|||
it('should schedule next ping after execution', async () => {
|
||||
// @ts-expect-error readonly property
|
||||
dataSource.isInitialized = true;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
dataSource.query.mockResolvedValue([{ '1': 1 }]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const scheduleNextPingSpy = jest.spyOn(dbConnection as any, 'scheduleNextPing');
|
||||
|
|
@ -178,7 +185,7 @@ describe('DbConnection', () => {
|
|||
expect(dataSource.query).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should execute ping on schedule', async () => {
|
||||
it('should execute ping on schedule', () => {
|
||||
jest.useFakeTimers();
|
||||
try {
|
||||
// ARRANGE
|
||||
|
|
@ -188,6 +195,7 @@ describe('DbConnection', () => {
|
|||
mock<DatabaseConfig>({
|
||||
pingIntervalSeconds: 1,
|
||||
}),
|
||||
logger,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { inTest } from '@n8n/backend-common';
|
||||
import { inTest, Logger } from '@n8n/backend-common';
|
||||
import { DatabaseConfig } from '@n8n/config';
|
||||
import { Time } from '@n8n/constants';
|
||||
import { Memoized } from '@n8n/decorators';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import { DataSource } from '@n8n/typeorm';
|
||||
import { ErrorReporter } from 'n8n-core';
|
||||
import { DbConnectionTimeoutError, ensureError } from 'n8n-workflow';
|
||||
import { DbConnectionTimeoutError, ensureError, OperationalError } from 'n8n-workflow';
|
||||
import { setTimeout as setTimeoutP } from 'timers/promises';
|
||||
|
||||
import { DbConnectionOptions } from './db-connection-options';
|
||||
import { wrapMigration } from '../migrations/migration-helpers';
|
||||
|
|
@ -31,6 +32,7 @@ export class DbConnection {
|
|||
private readonly errorReporter: ErrorReporter,
|
||||
private readonly connectionOptions: DbConnectionOptions,
|
||||
private readonly databaseConfig: DatabaseConfig,
|
||||
private readonly logger: Logger,
|
||||
) {
|
||||
this.dataSource = new DataSource(this.options);
|
||||
Container.set(DataSource, this.dataSource);
|
||||
|
|
@ -93,14 +95,31 @@ export class DbConnection {
|
|||
|
||||
private async ping() {
|
||||
if (!this.dataSource.isInitialized) return;
|
||||
const abortController = new AbortController();
|
||||
|
||||
try {
|
||||
await this.dataSource.query('SELECT 1');
|
||||
await Promise.race([
|
||||
this.dataSource.query('SELECT 1'),
|
||||
setTimeoutP(5000, undefined, { signal: abortController.signal }).then(() => {
|
||||
throw new OperationalError('Database connection timed out');
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!this.connectionState.connected) {
|
||||
this.logger.info('Database connection recovered');
|
||||
}
|
||||
|
||||
this.connectionState.connected = true;
|
||||
return;
|
||||
} catch (error) {
|
||||
this.connectionState.connected = false;
|
||||
this.errorReporter.error(error);
|
||||
if (error instanceof OperationalError) {
|
||||
this.logger.warn(error.message);
|
||||
} else {
|
||||
this.errorReporter.error(error);
|
||||
}
|
||||
} finally {
|
||||
abortController.abort();
|
||||
this.scheduleNextPing();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export abstract class AbstractServer {
|
|||
|
||||
protected setupPushServer() {}
|
||||
|
||||
private async setupHealthCheck() {
|
||||
private setupHealthCheck() {
|
||||
// main health check should not care about DB connections
|
||||
this.app.get('/healthz', (_req, res) => {
|
||||
res.send({ status: 'ok' });
|
||||
|
|
@ -200,7 +200,7 @@ export abstract class AbstractServer {
|
|||
|
||||
this.externalHooks = Container.get(ExternalHooks);
|
||||
|
||||
await this.setupHealthCheck();
|
||||
this.setupHealthCheck();
|
||||
|
||||
this.logger.info(`n8n ready on ${address}, port ${port}`);
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ export abstract class AbstractServer {
|
|||
* then closes them forcefully.
|
||||
*/
|
||||
@OnShutdown()
|
||||
async onShutdown(): Promise<void> {
|
||||
onShutdown(): void {
|
||||
if (!this.server) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export async function setupPostgres({
|
|||
'com.docker.compose.service': 'postgres',
|
||||
})
|
||||
.withName(`${projectName}-postgres`)
|
||||
.withAddedCapabilities('NET_ADMIN') // Allows us to drop IP tables and block traffic
|
||||
.withReuse()
|
||||
.start();
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ interface WaitForLogOptions {
|
|||
namePattern?: string | RegExp;
|
||||
timeoutMs?: number;
|
||||
caseSensitive?: boolean;
|
||||
throwOnTimeout?: boolean;
|
||||
}
|
||||
|
||||
interface StreamLogMatch {
|
||||
|
|
@ -71,15 +72,19 @@ export class ContainerTestHelpers {
|
|||
/**
|
||||
* Wait for a log message matching pattern (case-insensitive by default)
|
||||
* Uses streaming approach for immediate detection
|
||||
*
|
||||
* @returns LogMatch if found, null if timeout reached and throwOnTimeout is false
|
||||
* @throws Error if timeout reached and throwOnTimeout is true (default)
|
||||
*/
|
||||
async waitForLog(
|
||||
messagePattern: string | RegExp,
|
||||
options: WaitForLogOptions = {},
|
||||
): Promise<LogMatch> {
|
||||
): Promise<LogMatch | null> {
|
||||
const {
|
||||
namePattern,
|
||||
timeoutMs = ContainerTestHelpers.DEFAULT_TIMEOUT_MS,
|
||||
caseSensitive = false,
|
||||
throwOnTimeout = true,
|
||||
} = options;
|
||||
|
||||
const messageRegex = this.createRegex(messagePattern, caseSensitive);
|
||||
|
|
@ -87,7 +92,7 @@ export class ContainerTestHelpers {
|
|||
const startTime = Date.now();
|
||||
|
||||
console.log(
|
||||
`🔍 Waiting for log pattern: ${messageRegex} in ${targetContainers.length} containers (timeout: ${timeoutMs}ms)`,
|
||||
`🔍 Waiting for log pattern: ${messageRegex} in ${targetContainers.length} containers (timeout: ${timeoutMs}ms, throwOnTimeout: ${throwOnTimeout})`,
|
||||
);
|
||||
|
||||
// First check: scan existing logs quickly
|
||||
|
|
@ -98,7 +103,13 @@ export class ContainerTestHelpers {
|
|||
}
|
||||
|
||||
// Monitor new logs with streaming approach
|
||||
return await this.pollForNewLogs(targetContainers, messageRegex, startTime, timeoutMs);
|
||||
return await this.pollForNewLogs(
|
||||
targetContainers,
|
||||
messageRegex,
|
||||
startTime,
|
||||
timeoutMs,
|
||||
throwOnTimeout,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -134,7 +145,8 @@ export class ContainerTestHelpers {
|
|||
messageRegex: RegExp,
|
||||
startTime: number,
|
||||
timeoutMs: number,
|
||||
): Promise<LogMatch> {
|
||||
throwOnTimeout: boolean,
|
||||
): Promise<LogMatch | null> {
|
||||
let currentCheckTime = Math.floor(Date.now() / 1000);
|
||||
let iteration = 0;
|
||||
|
||||
|
|
@ -170,7 +182,12 @@ export class ContainerTestHelpers {
|
|||
}
|
||||
|
||||
console.log(`❌ Timeout reached after ${timeoutMs}ms`);
|
||||
throw new Error(`Timeout reached after ${timeoutMs}ms`);
|
||||
|
||||
if (throwOnTimeout) {
|
||||
throw new Error(`Timeout reached after ${timeoutMs}ms`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
"devDependencies": {
|
||||
"@currents/playwright": "^1.15.3",
|
||||
"@n8n/api-types": "workspace:^",
|
||||
"@n8n/constants": "workspace:^",
|
||||
"@n8n/db": "workspace:*",
|
||||
"@playwright/test": "1.56.0",
|
||||
"@types/lodash": "catalog:",
|
||||
|
|
|
|||
|
|
@ -217,11 +217,21 @@ export class ApiHelpers {
|
|||
|
||||
async get(path: string, params?: URLSearchParams) {
|
||||
const response = await this.request.get(path, { params });
|
||||
|
||||
const { data } = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if n8n is healthy
|
||||
* @returns True if n8n is healthy, false otherwise
|
||||
*/
|
||||
async isHealthy(probe: 'liveness' | 'readiness' = 'liveness'): Promise<boolean> {
|
||||
const url = probe === 'liveness' ? '/healthz' : '/healthz/readiness';
|
||||
const response = await this.request.get(url);
|
||||
const data = await response.json();
|
||||
return data.status === 'ok';
|
||||
}
|
||||
|
||||
// ===== PRIVATE METHODS =====
|
||||
|
||||
private async loginAndSetCookies(
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ test('Leader election @mode:multi-main @chaostest', async ({ chaos }) => {
|
|||
namePattern,
|
||||
});
|
||||
|
||||
expect(findContainerByLog).toBeDefined();
|
||||
const currentLeader = findContainerByLog.containerName;
|
||||
expect(findContainerByLog, 'Leader should be found').toBeDefined();
|
||||
const currentLeader = findContainerByLog?.containerName;
|
||||
// Stop leader
|
||||
await chaos.stopContainer(currentLeader);
|
||||
await chaos.stopContainer(currentLeader!);
|
||||
|
||||
// Find new leader
|
||||
const newLeader = await chaos.waitForLog('Leader is now this', {
|
||||
|
|
|
|||
65
packages/testing/playwright/tests/chaos/postgres.spec.ts
Normal file
65
packages/testing/playwright/tests/chaos/postgres.spec.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { Time } from '@n8n/constants';
|
||||
|
||||
import { test, expect } from '../../fixtures/base';
|
||||
|
||||
test(
|
||||
'Database connection timeout health check bug @mode:postgres @chaostest',
|
||||
{
|
||||
annotation: {
|
||||
type: 'issue',
|
||||
description: 'CAT-1018',
|
||||
},
|
||||
},
|
||||
async ({ api, chaos }) => {
|
||||
test.setTimeout(300000);
|
||||
|
||||
// ========== SETUP: Verify Initial Health ==========
|
||||
// Ensure n8n starts in a healthy state before we begin chaos testing
|
||||
{
|
||||
const isLive = await api.isHealthy('liveness');
|
||||
const isReady = await api.isHealthy('readiness');
|
||||
expect(isLive).toBe(true);
|
||||
expect(isReady).toBe(true);
|
||||
}
|
||||
|
||||
// ========== CHAOS INJECTION: Block Database Traffic ==========
|
||||
// Find postgres container and install iptables to simulate network issues
|
||||
const postgres = chaos.findContainers('postgres*')[0];
|
||||
|
||||
// Install iptables in the postgres container (Alpine Linux)
|
||||
const apkUpdate = await postgres.exec(['apk', 'update']);
|
||||
const apkInstall = await postgres.exec(['apk', 'add', 'iptables']);
|
||||
// Block all incoming TCP traffic to PostgreSQL port 5432
|
||||
// This simulates a network partition between n8n and the database
|
||||
const rule = ['INPUT', '-p', 'tcp', '--dport', '5432', '-j', 'DROP'];
|
||||
const blockPostgresTraffic = await postgres.exec(['iptables', '-A', ...rule]);
|
||||
expect(apkUpdate.exitCode).toBe(0);
|
||||
expect(apkInstall.exitCode).toBe(0);
|
||||
expect(blockPostgresTraffic.exitCode).toBe(0);
|
||||
|
||||
// ========== WAIT FOR CONNECTION ISSUES ==========
|
||||
await chaos.waitForLog('Database connection timed out', {
|
||||
namePattern: 'n8n-*',
|
||||
timeoutMs: 20 * Time.seconds.toMilliseconds,
|
||||
});
|
||||
|
||||
// ========== VERIFY: Health Checks ==========
|
||||
{
|
||||
const isLive = await api.isHealthy('liveness');
|
||||
const isReady = await api.isHealthy('readiness');
|
||||
expect(isLive).toBe(true);
|
||||
expect(isReady).toBe(false);
|
||||
}
|
||||
|
||||
// ========== RESTORE DATABASE CONNECTION ==========
|
||||
// Remove the iptables rule to allow traffic again
|
||||
const allowPostgresTraffic = await postgres.exec(['iptables', '-D', ...rule]);
|
||||
expect(allowPostgresTraffic.exitCode).toBe(0);
|
||||
|
||||
// ========== VERIFY: Automatic Recovery ==========
|
||||
await chaos.waitForLog('Database connection recovered', {
|
||||
namePattern: 'n8n-*',
|
||||
timeoutMs: 20 * Time.seconds.toMilliseconds,
|
||||
});
|
||||
},
|
||||
);
|
||||
177
pnpm-lock.yaml
177
pnpm-lock.yaml
|
|
@ -3219,6 +3219,9 @@ importers:
|
|||
'@n8n/api-types':
|
||||
specifier: workspace:^
|
||||
version: link:../../@n8n/api-types
|
||||
'@n8n/constants':
|
||||
specifier: workspace:^
|
||||
version: link:../../@n8n/constants
|
||||
'@n8n/db':
|
||||
specifier: workspace:*
|
||||
version: link:../../@n8n/db
|
||||
|
|
@ -6559,20 +6562,16 @@ packages:
|
|||
'@otplib/preset-v11@12.0.1':
|
||||
resolution: {integrity: sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg==}
|
||||
|
||||
'@oxc-project/runtime@0.71.0':
|
||||
resolution: {integrity: sha512-QwoF5WUXIGFQ+hSxWEib4U/aeLoiDN9JlP18MnBgx9LLPRDfn1iICtcow7Jgey6HLH4XFceWXQD5WBJ39dyJcw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@oxc-project/runtime@0.92.0':
|
||||
resolution: {integrity: sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
||||
'@oxc-project/types@0.71.0':
|
||||
resolution: {integrity: sha512-5CwQ4MI+P4MQbjLWXgNurA+igGwu/opNetIE13LBs9+V93R64MLvDKOOLZIXSzEfovU3Zef3q3GjPnMTgJTn2w==}
|
||||
|
||||
'@oxc-project/types@0.94.0':
|
||||
resolution: {integrity: sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==}
|
||||
|
||||
'@oxc-project/types@0.96.0':
|
||||
resolution: {integrity: sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw==}
|
||||
|
||||
'@paralleldrive/cuid2@2.2.2':
|
||||
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
|
||||
|
||||
|
|
@ -6790,14 +6789,21 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-vPP9/MZzESh9QtmvQYojXP/midjgkkc1E4AdnPPAzQXo668ncHJcVLKjJKzoBdsQmaIvNjrMdsCwES8vTQHRQw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.42':
|
||||
resolution: {integrity: sha512-abw/wtgJA8OCgaTlL+xJxnN/Z01BwV1rfzIp5Hh9x+IIO6xOBfPsQ0nzi0+rWx3TyZ9FZXyC7bbC+5NpQ9EaXQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-Mp0/gqiPdepHjjVm7e0yL1acWvI0rJVVFQEADSezvAjon9sjQ7CEg9JnXICD4B1YrPmN9qV/e7cQZCp87tTV4w==}
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-Lc3nrkxeaDVCVl8qR3qoxh6ltDZfkQ98j5vwIr5ALPkgjZtDK4BGCrrBoLpGVMg+csWcaqUbwbKwH5yvVa0oOw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
|
|
@ -6807,8 +6813,9 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-40re4rMNrsi57oavRzIOpRGmg3QRlW6Ea8Q3znaqgOuJuKVrrm2bIQInTfkZJG7a4/5YMX7T951d0+toGLTdCA==}
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-eBYxQDwP0O33plqNVqOtUHqRiSYVneAknviM5XMawke3mwMuVlAsohtOqEjbCEl/Loi/FWdVeks5WkqAkzkYWQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
|
|
@ -6818,8 +6825,9 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-8BDM939bbMariZupiHp3OmP5N+LXPT4mULA0hZjDaq970PCxv4krZOSMG+HkWUUwmuQROtV+/00xw39EO0P+8g==}
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-Ns+kgp2+1Iq/44bY/Z30DETUSiHY7ZuqaOgD5bHVW++8vme9rdiWsN4yG4rRPXkdgzjvQ9TDHmZZKfY4/G11AA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
|
|
@ -6829,8 +6837,9 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-sntsPaPgrECpBB/+2xrQzVUt0r493TMPI+4kWRMhvMsmrxOqH1Ep5lM0Wua/ZdbfZNwm1aVa5pcESQfNfM4Fhw==}
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-4PecgWCJhTA2EFOlptYJiNyVP2MrVP4cWdndpOu3WmXqWqZUmSubhb4YUAIxAxnXATlGjC1WjxNPhV7ZllNgdA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
|
|
@ -6841,8 +6850,9 @@ packages:
|
|||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-5clBW/I+er9F2uM1OFjJFWX86y7Lcy0M+NqsN4s3o07W+8467Zk8oQa4B45vdaXoNUF/yqIAgKkA/OEdQDxZqA==}
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-CyIunZ6D9U9Xg94roQI1INt/bLkOpPsZjZZkiaAZ0r6uccQdICmC99M9RUPlMLw/qg4yEWLlQhG73W/mG437NA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
|
@ -6854,8 +6864,9 @@ packages:
|
|||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-wv+rnAfQDk9p/CheX8/Kmqk2o1WaFa4xhWI9gOyDMk/ljvOX0u0ubeM8nI1Qfox7Tnh71eV5AjzSePXUhFOyOg==}
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-doozc/Goe7qRCSnzfJbFINTHsMktqmZQmweull6hsZZ9sjNWQ6BWQnbvOlfZJe4xE5NxM1NhPnY5Giqnl3ZrYQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
|
@ -6867,8 +6878,9 @@ packages:
|
|||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-gxD0/xhU4Py47IH3bKZbWtvB99tMkUPGPJFRfSc5UB9Osoje0l0j1PPbxpUtXIELurYCqwLBKXIMTQGifox1BQ==}
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-fodvSMf6Aqwa0wEUSTPewmmZOD44rc5Tpr5p9NkwQ6W1SSpUKzD3SwpJIgANDOhwiYhDuiIaYPGB7Ujkx1q0UQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
|
@ -6880,8 +6892,9 @@ packages:
|
|||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-HotuVe3XUjDwqqEMbm3o3IRkP9gdm8raY/btd/6KE3JGLF/cv4+3ff1l6nOhAZI8wulWDPEXPtE7v+HQEaTXnA==}
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-Rxm5hYc0mGjwLh5sjlGmMygxAaV2gnsx7CNm2lsb47oyt5UQyPDZf3GP/ct8BEcwuikdqzsrrlIp8+kCSvMFNQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
|
@ -6892,14 +6905,20 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-YakuVe+Gc87jjxazBL34hbr8RJpRuFBhun7NEqoChVDlH5FLhLXjAPHqZd990TVGVNkemourf817Z8u2fONS8w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.42':
|
||||
resolution: {integrity: sha512-2Ft32F7uiDTrGZUKws6CLNTlvTWHC33l4vpXrzUucf9rYtUThAdPCOt89Pmn13tNX6AulxjGEP2R0nZjTSW3eQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-8Cx+ucbd8n2dIr21FqBh6rUvTVL0uTgEtKR7l+MUZ5BgY4dFh1e4mPVX8oqmoYwOxBiXrsD2JIOCz4AyKLKxWA==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-ak2GvTFQz3UAOw8cuQq8pWE+TNygQB6O47rMhvevvTzETh7VkHRFtRUwJynX5hwzFvQMP6G0az5JrBGuwaMwYQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.42':
|
||||
|
|
@ -6908,8 +6927,9 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-Vhq5vikrVDxAa75fxsyqj0c0Y/uti/TwshXI71Xb8IeUQJOBnmLUsn5dgYf5ljpYYkNa0z9BPAvUDIDMmyDi+w==}
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-o5BpmBnXU+Cj+9+ndMcdKjhZlPb79dVPBZnWwMnI4RlNSSq5yOvFZqvfPYbyacvnW03Na4n5XXQAPhu3RydZ0w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
|
|
@ -6919,8 +6939,9 @@ packages:
|
|||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-lN7RIg9Iugn08zP2aZN9y/MIdG8iOOCE93M1UrFlrxMTqPf8X+fDzmR/OKhTSd1A2pYNipZHjyTcb5H8kyQSow==}
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-FVOmfyYehNE92IfC9Kgs913UerDog2M1m+FADJypKz0gmRg3UyTt4o1cZMCAl7MiR89JpM9jegNO1nXuP1w1vw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
|
|
@ -6930,16 +6951,17 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-7/7cLIn48Y+EpQ4CePvf8reFl63F15yPUlg4ZAhl+RXJIfydkdak1WD8Ir3AwAO+bJBXzrfNL+XQbxm0mcQZmw==}
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-by/70F13IUE101Bat0oeH8miwWX5mhMFPk1yjCdxoTNHTyTdLgb0THNaebRM6AP7Kz+O3O2qx87sruYuF5UxHg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.42':
|
||||
resolution: {integrity: sha512-N7pQzk9CyE7q0bBN/q0J8s6Db279r5kUZc6d7/wWRe9/zXqC52HQovVyu6iXPIDY4BEzzgbVLhVFXrOuGJ22ZQ==}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5':
|
||||
resolution: {integrity: sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ==}
|
||||
'@rolldown/pluginutils@1.0.0-beta.47':
|
||||
resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==}
|
||||
|
||||
'@rollup/plugin-inject@5.0.5':
|
||||
resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==}
|
||||
|
|
@ -15841,8 +15863,9 @@ packages:
|
|||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rolldown@1.0.0-beta.9-commit.d91dfb5:
|
||||
resolution: {integrity: sha512-FHkj6gGEiEgmAXQchglofvUUdwj2Oiw603Rs+zgFAnn9Cb7T7z3fiaEc0DbN3ja4wYkW6sF2rzMEtC1V4BGx/g==}
|
||||
rolldown@1.0.0-beta.47:
|
||||
resolution: {integrity: sha512-Mid74GckX1OeFAOYz9KuXeWYhq3xkXbMziYIC+ULVdUzPTG9y70OBSBQDQn9hQP8u/AfhuYw1R0BSg15nBI4Dg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.49.0:
|
||||
|
|
@ -22501,14 +22524,12 @@ snapshots:
|
|||
'@otplib/plugin-crypto': 12.0.1
|
||||
'@otplib/plugin-thirty-two': 12.0.1
|
||||
|
||||
'@oxc-project/runtime@0.71.0': {}
|
||||
|
||||
'@oxc-project/runtime@0.92.0': {}
|
||||
|
||||
'@oxc-project/types@0.71.0': {}
|
||||
|
||||
'@oxc-project/types@0.94.0': {}
|
||||
|
||||
'@oxc-project/types@0.96.0': {}
|
||||
|
||||
'@paralleldrive/cuid2@2.2.2':
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
|
@ -22720,88 +22741,94 @@ snapshots:
|
|||
'@rolldown/binding-android-arm64@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.42':
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 1.0.7
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.47':
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 0.2.11
|
||||
'@napi-rs/wasm-runtime': 1.0.7
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.42':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5':
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.47':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.42': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5': {}
|
||||
'@rolldown/pluginutils@1.0.0-beta.47': {}
|
||||
|
||||
'@rollup/plugin-inject@5.0.5(rollup@4.52.4)':
|
||||
dependencies:
|
||||
|
|
@ -33719,7 +33746,7 @@ snapshots:
|
|||
|
||||
rndm@1.2.0: {}
|
||||
|
||||
rolldown-plugin-dts@0.16.11(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2)):
|
||||
rolldown-plugin-dts@0.16.11(rolldown@1.0.0-beta.47)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2)):
|
||||
dependencies:
|
||||
'@babel/generator': 7.28.3
|
||||
'@babel/parser': 7.28.4
|
||||
|
|
@ -33730,7 +33757,7 @@ snapshots:
|
|||
dts-resolver: 2.1.2
|
||||
get-tsconfig: 4.10.1
|
||||
magic-string: 0.30.19
|
||||
rolldown: 1.0.0-beta.9-commit.d91dfb5
|
||||
rolldown: 1.0.0-beta.47
|
||||
optionalDependencies:
|
||||
typescript: 5.9.2
|
||||
vue-tsc: 2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2)
|
||||
|
|
@ -33777,25 +33804,25 @@ snapshots:
|
|||
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.42
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.42
|
||||
|
||||
rolldown@1.0.0-beta.9-commit.d91dfb5:
|
||||
rolldown@1.0.0-beta.47:
|
||||
dependencies:
|
||||
'@oxc-project/runtime': 0.71.0
|
||||
'@oxc-project/types': 0.71.0
|
||||
'@rolldown/pluginutils': 1.0.0-beta.9-commit.d91dfb5
|
||||
ansis: 4.2.0
|
||||
'@oxc-project/types': 0.96.0
|
||||
'@rolldown/pluginutils': 1.0.0-beta.47
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-darwin-arm64': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-darwin-x64': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-freebsd-x64': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.9-commit.d91dfb5
|
||||
'@rolldown/binding-android-arm64': 1.0.0-beta.47
|
||||
'@rolldown/binding-darwin-arm64': 1.0.0-beta.47
|
||||
'@rolldown/binding-darwin-x64': 1.0.0-beta.47
|
||||
'@rolldown/binding-freebsd-x64': 1.0.0-beta.47
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.47
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.47
|
||||
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.47
|
||||
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.47
|
||||
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.47
|
||||
'@rolldown/binding-openharmony-arm64': 1.0.0-beta.47
|
||||
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.47
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.47
|
||||
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.47
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.47
|
||||
|
||||
rollup@4.49.0:
|
||||
dependencies:
|
||||
|
|
@ -35319,8 +35346,8 @@ snapshots:
|
|||
diff: 8.0.2
|
||||
empathic: 2.0.0
|
||||
hookable: 5.5.3
|
||||
rolldown: 1.0.0-beta.9-commit.d91dfb5
|
||||
rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2))
|
||||
rolldown: 1.0.0-beta.47
|
||||
rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-beta.47)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2))
|
||||
semver: 7.7.2
|
||||
tinyexec: 1.0.1
|
||||
tinyglobby: 0.2.15
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user