diff --git a/apps/api/src/routes/v1_keys_verifyKey.ts b/apps/api/src/routes/v1_keys_verifyKey.ts index 2223fbd876..8203e0b61e 100644 --- a/apps/api/src/routes/v1_keys_verifyKey.ts +++ b/apps/api/src/routes/v1_keys_verifyKey.ts @@ -38,10 +38,8 @@ The key will be verified against the api's configuration. If the key does not be .openapi({ description: `Tags do not influence the outcome of a verification. They can be added to filter or aggregate historical verification data for your analytics needs. - To unkey, a tag is simply a string, we don't enforce any schema but leave that up to you. The only exception is that each tag must be between 1 and 128 characters long. - A typical setup would be to add key-value pairs of resources or locations, that you need later when querying. `, example: ["path=/v1/users/123", "region=us-east-1"], diff --git a/internal/clickhouse/schema/036_create_verifications.key_verifications_per_hour_v3.sql b/internal/clickhouse/schema/036_create_verifications.key_verifications_per_hour_v3.sql new file mode 100644 index 0000000000..6f99ddcefa --- /dev/null +++ b/internal/clickhouse/schema/036_create_verifications.key_verifications_per_hour_v3.sql @@ -0,0 +1,19 @@ +-- +goose up +CREATE TABLE verifications.key_verifications_per_hour_v3 +( + time DateTime, + workspace_id String, + key_space_id String, + identity_id String, + key_id String, + outcome LowCardinality(String), + tags Array(String), + count Int64 +) +ENGINE = SummingMergeTree() +ORDER BY (workspace_id, key_space_id, identity_id, key_id, time, tags, outcome) +; + + +-- +goose down +DROP TABLE verifications.key_verifications_per_hour_v3; diff --git a/internal/clickhouse/schema/037_create_verifications.key_verifications_per_hour_mv_v3.sql b/internal/clickhouse/schema/037_create_verifications.key_verifications_per_hour_mv_v3.sql new file mode 100644 index 0000000000..4cf157874c --- /dev/null +++ b/internal/clickhouse/schema/037_create_verifications.key_verifications_per_hour_mv_v3.sql @@ -0,0 +1,49 @@ +-- +goose up +CREATE MATERIALIZED VIEW IF NOT EXISTS verifications.key_verifications_per_hour_mv_v3 +TO verifications.key_verifications_per_hour_v3 +AS +SELECT + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + count(*) as count, + toStartOfHour(fromUnixTimestamp64Milli(time)) AS time, + tags +FROM verifications.raw_key_verifications_v1 +GROUP BY + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + time, + tags +; + + +-- populate from existing data +-- INSERT INTO verifications.key_verifications_per_hour_v3 +-- SELECT +-- toStartOfHour(fromUnixTimestamp64Milli(time)) AS time, +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- tags, +-- count(*) as count +-- FROM verifications.raw_key_verifications_v1 +-- GROUP BY +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- time, +-- tags +-- ; + +-- +goose down +DROP VIEW verifications.key_verifications_per_hour_mv_v3; diff --git a/internal/clickhouse/schema/038_create_verifications.key_verifications_per_day_v3.sql b/internal/clickhouse/schema/038_create_verifications.key_verifications_per_day_v3.sql new file mode 100644 index 0000000000..c4cd43aba5 --- /dev/null +++ b/internal/clickhouse/schema/038_create_verifications.key_verifications_per_day_v3.sql @@ -0,0 +1,19 @@ +-- +goose up +CREATE TABLE verifications.key_verifications_per_day_v3 +( + time DateTime, + workspace_id String, + key_space_id String, + identity_id String, + key_id String, + outcome LowCardinality(String), + tags Array(String), + count Int64 +) +ENGINE = SummingMergeTree() +ORDER BY (workspace_id, key_space_id, identity_id, key_id, time, tags, outcome) +; + + +-- +goose down +DROP TABLE verifications.key_verifications_per_day_v3; diff --git a/internal/clickhouse/schema/039_create_verifications.key_verifications_per_day_mv_v3.sql b/internal/clickhouse/schema/039_create_verifications.key_verifications_per_day_mv_v3.sql new file mode 100644 index 0000000000..05e54a6857 --- /dev/null +++ b/internal/clickhouse/schema/039_create_verifications.key_verifications_per_day_mv_v3.sql @@ -0,0 +1,49 @@ +-- +goose up +CREATE MATERIALIZED VIEW IF NOT EXISTS verifications.key_verifications_per_day_mv_v3 +TO verifications.key_verifications_per_day_v3 +AS +SELECT + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + count(*) as count, + toStartOfDay(fromUnixTimestamp64Milli(time)) AS time, + tags +FROM verifications.raw_key_verifications_v1 +GROUP BY + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + time, + tags +; + +-- populate from existing data +-- INSERT INTO verifications.key_verifications_per_day_v3 +-- SELECT +-- toStartOfDay(fromUnixTimestamp64Milli(time)) AS time, +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- tags, +-- count(*) as count +-- FROM verifications.raw_key_verifications_v1 +-- GROUP BY +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- time, +-- tags +-- ; + + +-- +goose down +DROP VIEW verifications.key_verifications_per_day_mv_v3; diff --git a/internal/clickhouse/schema/040_create_verifications.key_verifications_per_month_v3.sql b/internal/clickhouse/schema/040_create_verifications.key_verifications_per_month_v3.sql new file mode 100644 index 0000000000..9b29bd585a --- /dev/null +++ b/internal/clickhouse/schema/040_create_verifications.key_verifications_per_month_v3.sql @@ -0,0 +1,19 @@ +-- +goose up +CREATE TABLE verifications.key_verifications_per_month_v3 +( + time DateTime, + workspace_id String, + key_space_id String, + identity_id String, + key_id String, + outcome LowCardinality(String), + tags Array(String), + count Int64 +) +ENGINE = SummingMergeTree() +ORDER BY (workspace_id, key_space_id, identity_id, key_id, time, tags, outcome) +; + + +-- +goose down +DROP TABLE verifications.key_verifications_per_month_v3; diff --git a/internal/clickhouse/schema/041_create_verifications.key_verifications_per_month_mv_v3.sql b/internal/clickhouse/schema/041_create_verifications.key_verifications_per_month_mv_v3.sql new file mode 100644 index 0000000000..b53b3ae6ea --- /dev/null +++ b/internal/clickhouse/schema/041_create_verifications.key_verifications_per_month_mv_v3.sql @@ -0,0 +1,49 @@ +-- +goose up +CREATE MATERIALIZED VIEW IF NOT EXISTS verifications.key_verifications_per_month_mv_v3 +TO verifications.key_verifications_per_month_v3 +AS +SELECT + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + count(*) as count, + toStartOfMonth(fromUnixTimestamp64Milli(time)) AS time, + tags +FROM verifications.raw_key_verifications_v1 +GROUP BY + workspace_id, + key_space_id, + identity_id, + key_id, + outcome, + time, + tags +; + +-- populate from existing data +-- INSERT INTO verifications.key_verifications_per_month_v3 +-- SELECT +-- toStartOfMonth(fromUnixTimestamp64Milli(time)) AS time, +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- tags, +-- count(*) as counts +-- FROM verifications.raw_key_verifications_v1 +-- GROUP BY +-- workspace_id, +-- key_space_id, +-- identity_id, +-- key_id, +-- outcome, +-- time, +-- tags +-- ; + + +-- +goose down +DROP VIEW verifications.key_verifications_per_month_mv_v3; diff --git a/internal/clickhouse/src/client/client.ts b/internal/clickhouse/src/client/client.ts index d6306ada36..2a937c3247 100644 --- a/internal/clickhouse/src/client/client.ts +++ b/internal/clickhouse/src/client/client.ts @@ -15,8 +15,6 @@ export class Client implements Querier, Inserter { url: config.url, clickhouse_settings: { - async_insert: 1, - wait_for_async_insert: 1, output_format_json_quote_64bit_integers: 0, output_format_json_quote_64bit_floats: 0, }, diff --git a/internal/clickhouse/src/verification_outcomes_propagate_correctly.test.ts b/internal/clickhouse/src/verification_outcomes_propagate_correctly.test.ts new file mode 100644 index 0000000000..35b9eb9749 --- /dev/null +++ b/internal/clickhouse/src/verification_outcomes_propagate_correctly.test.ts @@ -0,0 +1,109 @@ +import { describe, expect, test } from "vitest"; +import { ClickHouse } from "./index"; + +import { randomUUID } from "node:crypto"; +import { z } from "zod"; +import { ClickHouseContainer } from "./testutil"; + +describe.each([10, 100, 1_000, 10_000, 100_000])("with %i verifications", (n) => { + test( + "accurately aggregates outcomes", + async (t) => { + const container = await ClickHouseContainer.start(t); + + const ch = new ClickHouse({ url: container.url() }); + + const workspaceId = randomUUID(); + const keySpaceId = randomUUID(); + const keyId = randomUUID(); + + const end = Date.now(); + const interval = 90 * 24 * 60 * 60 * 1000; // 90 days + const start = end - interval; + const outcomes = { + VALID: 0, + RATE_LIMITED: 0, + DISABLED: 0, + }; + const verifications = Array.from({ length: n }).map((_) => { + const outcome = Object.keys(outcomes)[ + Math.floor(Math.random() * Object.keys(outcomes).length) + ] as keyof typeof outcomes; + outcomes[outcome]++; + return { + request_id: randomUUID(), + time: Math.round(Math.random() * (end - start + 1) + start), + workspace_id: workspaceId, + key_space_id: keySpaceId, + key_id: keyId, + outcome, + region: "test", + tags: ["tag"], + }; + }); + + for (let i = 0; i < verifications.length; i += 1000) { + await ch.verifications.insert(verifications.slice(i, i + 1000)); + } + + // give clickhouse time to write to all tables + // await new Promise(r => setTimeout(r, 60_000)) + + const count = await ch.querier.query({ + query: "SELECT count(*) as count FROM verifications.raw_key_verifications_v1", + schema: z.object({ count: z.number().int() }), + })({}); + expect(count.err).toBeUndefined(); + expect(count.val!.at(0)!.count).toBe(n); + + const hourly = await ch.verifications.perHour({ + workspaceId, + keySpaceId, + keyId, + start: start - interval, + end, + }); + expect(hourly.err).toBeUndefined(); + + const daily = await ch.verifications.perDay({ + workspaceId, + keySpaceId, + keyId, + start: start - interval, + end, + }); + expect(daily.err).toBeUndefined(); + + const monthly = await ch.verifications.perMonth({ + workspaceId, + keySpaceId, + keyId, + start: start - interval, + end, + }); + expect(monthly.err).toBeUndefined(); + + for (const buckets of [hourly.val!, daily.val!, monthly.val!]) { + let total = 0; + const sumByOutcome = buckets.reduce( + (acc, bucket) => { + total += bucket.count; + if (!acc[bucket.outcome]) { + acc[bucket.outcome] = 0; + } + acc[bucket.outcome] += bucket.count; + return acc; + }, + {} as Record, + ); + + expect(total).toBe(n); + + for (const [k, v] of Object.entries(outcomes)) { + expect(sumByOutcome[k]).toEqual(v); + } + } + }, + { timeout: 120_000 }, + ); +}); diff --git a/internal/clickhouse/src/verifications.ts b/internal/clickhouse/src/verifications.ts index 70ace1277f..f92f297d81 100644 --- a/internal/clickhouse/src/verifications.ts +++ b/internal/clickhouse/src/verifications.ts @@ -60,7 +60,7 @@ export function getVerificationsPerHour(ch: Querier) { outcome, sum(count) as count, tags - FROM verifications.key_verifications_per_hour_v2 + FROM verifications.key_verifications_per_hour_v3 WHERE workspace_id = {workspaceId: String} AND key_space_id = {keySpaceId: String} @@ -91,7 +91,7 @@ export function getVerificationsPerDay(ch: Querier) { outcome, sum(count) as count, tags - FROM verifications.key_verifications_per_day_v2 + FROM verifications.key_verifications_per_day_v3 WHERE workspace_id = {workspaceId: String} AND key_space_id = {keySpaceId: String} @@ -118,7 +118,7 @@ export function getVerificationsPerMonth(ch: Querier) { outcome, sum(count) as count, tags - FROM verifications.key_verifications_per_month_v2 + FROM verifications.key_verifications_per_month_v3 WHERE workspace_id = {workspaceId: String} AND key_space_id = {keySpaceId: String} diff --git a/internal/clickhouse/vitest.config.ts b/internal/clickhouse/vitest.config.ts index b3e0bea390..5a8704b016 100644 --- a/internal/clickhouse/vitest.config.ts +++ b/internal/clickhouse/vitest.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { exclude: [], + bail: 1, pool: "threads", poolOptions: { threads: { diff --git a/packages/api/package.json b/packages/api/package.json index e823f61fd3..a427f80161 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -9,19 +9,12 @@ "publishConfig": { "access": "public" }, - "keywords": [ - "unkey", - "client", - "api" - ], + "keywords": ["unkey", "client", "api"], "bugs": { "url": "https://github.com/unkeyed/unkey/issues" }, "homepage": "https://github.com/unkeyed/unkey#readme", - "files": [ - "./dist/**", - "README.md" - ], + "files": ["./dist/**", "README.md"], "author": "Andreas Thomas ", "scripts": { "generate": "openapi-typescript https://api.unkey.dev/openapi.json -o ./src/openapi.d.ts", diff --git a/packages/api/src/openapi.d.ts b/packages/api/src/openapi.d.ts index d633b02af7..a2cabe2bbe 100644 --- a/packages/api/src/openapi.d.ts +++ b/packages/api/src/openapi.d.ts @@ -604,6 +604,21 @@ export interface components { * @example sk_1234 */ key: string; + /** + * @description Tags do not influence the outcome of a verification. + * They can be added to filter or aggregate historical verification data for your analytics needs. + * + * To unkey, a tag is simply a string, we don't enforce any schema but leave that up to you. + * The only exception is that each tag must be between 1 and 128 characters long. + * + * A typical setup would be to add key-value pairs of resources or locations, that you need later when querying. + * + * @example [ + * "path=/v1/users/123", + * "region=us-east-1" + * ] + */ + tags?: string[]; /** @description Perform RBAC checks */ authorization?: { permissions?: components["schemas"]["PermissionQuery"]; @@ -2363,7 +2378,7 @@ export interface operations { * @example eyJrZXkiOiJrZXlfMTIzNCJ9 */ cursor?: string; - /** @description The total number of keys for this api */ + /** @description The total number of keys for this api. This is an approximation and may lag behind up to 5 minutes. */ total: number; }; }; diff --git a/packages/hono/package.json b/packages/hono/package.json index d1b4fa8a6e..5bdd0435c4 100644 --- a/packages/hono/package.json +++ b/packages/hono/package.json @@ -8,19 +8,12 @@ "publishConfig": { "access": "public" }, - "keywords": [ - "unkey", - "client", - "api", - "hono" - ], + "keywords": ["unkey", "client", "api", "hono"], "bugs": { "url": "https://github.com/unkeyed/unkey/issues" }, "homepage": "https://github.com/unkeyed/unkey#readme", - "files": [ - "./dist/**" - ], + "files": ["./dist/**"], "author": "Andreas Thomas ", "scripts": { "build": "tsup", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index a1288618d1..29f3741efb 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -8,19 +8,12 @@ "publishConfig": { "access": "public" }, - "keywords": [ - "unkey", - "client", - "api" - ], + "keywords": ["unkey", "client", "api"], "bugs": { "url": "https://github.com/unkeyed/unkey/issues" }, "homepage": "https://github.com/unkeyed/unkey#readme", - "files": [ - "./dist/**", - "README.md" - ], + "files": ["./dist/**", "README.md"], "author": "Andreas Thomas ", "scripts": { "build": "tsup" diff --git a/packages/ratelimit/package.json b/packages/ratelimit/package.json index 82d9442854..f425b9608f 100644 --- a/packages/ratelimit/package.json +++ b/packages/ratelimit/package.json @@ -9,20 +9,12 @@ "publishConfig": { "access": "public" }, - "keywords": [ - "unkey", - "ratelimit", - "global", - "serverless" - ], + "keywords": ["unkey", "ratelimit", "global", "serverless"], "bugs": { "url": "https://github.com/unkeyed/unkey/issues" }, "homepage": "https://github.com/unkeyed/unkey#readme", - "files": [ - "./dist/**", - "README.md" - ], + "files": ["./dist/**", "README.md"], "author": "Andreas Thomas ", "scripts": { "build": "tsup" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcc0e45532..d6ada65428 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -145,7 +145,7 @@ importers: version: 5.5.3 vitest: specifier: ^1.6.0 - version: 1.6.0(@vitest/ui@1.6.0) + version: 1.6.0(@types/node@20.14.9)(@vitest/ui@1.6.0) wrangler: specifier: ^3.92.0 version: 3.92.0(@cloudflare/workers-types@4.20240603.0) @@ -2994,7 +2994,7 @@ packages: esbuild: 0.17.19 miniflare: 3.20240524.2 semver: 7.6.3 - vitest: 1.6.0(@vitest/ui@1.6.0) + vitest: 1.6.0(@types/node@20.14.9)(@vitest/ui@1.6.0) wrangler: 3.59.0(@cloudflare/workers-types@4.20240603.0) zod: 3.23.8 transitivePeerDependencies: @@ -7659,7 +7659,7 @@ packages: resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} engines: {node: '>=8.0.0'} dependencies: - tslib: 2.4.1 + tslib: 2.8.1 dev: false /@peculiar/webcrypto@1.4.1: @@ -7669,7 +7669,7 @@ packages: '@peculiar/asn1-schema': 2.3.13 '@peculiar/json-schema': 1.1.12 pvtsutils: 1.3.6 - tslib: 2.4.1 + tslib: 2.8.1 webcrypto-core: 1.8.1 dev: false @@ -11475,7 +11475,7 @@ packages: /@types/node-forge@1.3.11: resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} dependencies: - '@types/node': 22.10.1 + '@types/node': 20.14.9 dev: true /@types/node@12.20.55: @@ -11972,7 +11972,7 @@ packages: pathe: 1.1.2 picocolors: 1.1.1 sirv: 2.0.4 - vitest: 1.6.0(@vitest/ui@1.6.0) + vitest: 1.6.0(@types/node@20.14.9)(@vitest/ui@1.6.0) dev: true /@vitest/utils@1.5.3: @@ -13103,7 +13103,7 @@ packages: /capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} dependencies: - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -14198,18 +14198,6 @@ packages: ms: 2.1.2 dev: true - /debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - /debug@4.3.7(supports-color@8.1.1): resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -14555,7 +14543,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.8.1 dev: false /dot-prop@6.0.1: @@ -18835,7 +18823,7 @@ packages: /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.4.1 + tslib: 2.8.1 dev: false /lowercase-keys@3.0.0: @@ -20235,6 +20223,7 @@ packages: /minipass@6.0.2: resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==} engines: {node: '>=16 || 14 >=14.17'} + dev: true /minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} @@ -20702,7 +20691,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.4.1 + tslib: 2.8.1 dev: false /node-addon-api@7.1.1: @@ -21407,7 +21396,7 @@ packages: engines: {node: '>=16 || 14 >=14.18'} dependencies: lru-cache: 10.4.3 - minipass: 6.0.2 + minipass: 7.1.2 /path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} @@ -23689,7 +23678,7 @@ packages: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.8.1 dev: false /snakecase-keys@3.2.1: @@ -25723,28 +25712,6 @@ packages: d3-timer: 3.0.1 dev: false - /vite-node@1.6.0: - resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - dependencies: - cac: 6.7.14 - debug: 4.3.7 - pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.11 - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - dev: true - /vite-node@1.6.0(@types/node@20.14.9): resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -25767,44 +25734,6 @@ packages: - terser dev: true - /vite@5.4.11: - resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.21.5 - postcss: 8.4.49 - rollup: 4.28.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vite@5.4.11(@types/node@20.14.9): resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} engines: {node: ^18.0.0 || >=20.0.0} @@ -25902,63 +25831,6 @@ packages: - terser dev: true - /vitest@1.6.0(@vitest/ui@1.6.0): - resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.0 - '@vitest/ui': 1.6.0 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/ui': 1.6.0(vitest@1.6.0) - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 - execa: 8.0.1 - local-pkg: 0.5.1 - magic-string: 0.30.14 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.8.0 - strip-literal: 2.1.1 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.11 - vite-node: 1.6.0 - why-is-node-running: 2.3.0 - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - dev: true - /vlq@0.2.3: resolution: {integrity: sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==} dev: true