diff --git a/apps/api/src/routes/v1_keys_getVerifications.ts b/apps/api/src/routes/v1_keys_getVerifications.ts index 9d40f034fb..d4d593dfe3 100644 --- a/apps/api/src/routes/v1_keys_getVerifications.ts +++ b/apps/api/src/routes/v1_keys_getVerifications.ts @@ -221,13 +221,17 @@ export const registerV1KeysGetVerifications = (app: App) => const verificationsFromAllKeys = await Promise.all( ids.map(({ keyId, keySpaceId }) => { return cache.verificationsByKeyId.swr(`${keyId}:${start}-${end}`, async () => { - return await analytics.getVerificationsDaily({ + const res = await analytics.getVerificationsDaily({ workspaceId: authorizedWorkspaceId, keySpaceId: keySpaceId, keyId: keyId, start: start ? start : now - 24 * 60 * 60 * 1000, end: end ? end : now, }); + if (res.err) { + throw new Error(res.err.message); + } + return res.val; }); }), ); diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx index bba1d6e2d6..1bbdd5ad66 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx @@ -97,7 +97,7 @@ export default async function APIKeyDetailPage(props: { }), clickhouse.verifications .latest({ workspaceId: key.workspaceId, keySpaceId: key.keyAuthId, keyId: key.id }) - .then((res) => res.at(0)?.time ?? 0), + .then((res) => res.val?.at(0)?.time ?? 0), ]); const successOverTime: { x: string; y: number }[] = []; @@ -108,7 +108,7 @@ export default async function APIKeyDetailPage(props: { const expiredOverTime: { x: string; y: number }[] = []; const forbiddenOverTime: { x: string; y: number }[] = []; - for (const d of verifications.sort((a, b) => a.time - b.time)) { + for (const d of verifications.val!.sort((a, b) => a.time - b.time)) { const x = new Date(d.time).toISOString(); switch (d.outcome) { case "": @@ -174,7 +174,7 @@ export default async function APIKeyDetailPage(props: { expired: 0, forbidden: 0, }; - verifications.forEach((v) => { + verifications.val!.forEach((v) => { switch (v.outcome) { case "VALID": stats.valid += v.count; @@ -317,7 +317,7 @@ export default async function APIKeyDetailPage(props: { )} - {latestVerifications.length > 0 ? ( + {latestVerifications.val && latestVerifications.val.length > 0 ? ( <>

diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/verification-table.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/verification-table.tsx index 0a76960e14..36370ce628 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/verification-table.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/verification-table.tsx @@ -34,7 +34,7 @@ export const VerificationTable = ({ verifications }: Props) => { - {verifications.map((verification, i) => { + {verifications.val?.map((verification, i) => { /** * Instead of rounding every row individually, we want to round consecutive colored rows together. * For example: @@ -54,10 +54,10 @@ export const VerificationTable = ({ verifications }: Props) => { */ const isStartOfColoredBlock = verification.outcome !== "VALID" && - (i === 0 || verifications[i - 1].outcome === "VALID"); + (i === 0 || verifications.val[i - 1].outcome === "VALID"); const isEndOfColoredBlock = verification.outcome !== "VALID" && - (i === verifications.length - 1 || verifications[i + 1].outcome === "VALID"); + (i === verifications.val.length - 1 || verifications.val[i + 1].outcome === "VALID"); return ( res.at(0)?.count ?? 0), - getVerificationsPerInterval(query), - getActiveKeysPerInterval(query), + getVerificationsPerInterval(query).then((res) => res.val!), + getActiveKeysPerInterval(query).then((res) => res.val!), clickhouse.activeKeys .perMonth({ workspaceId: api.workspaceId, @@ -63,13 +63,13 @@ export default async function ApiPage(props: { start: billingCycleStart, end: billingCycleEnd, }) - .then((res) => res.at(0)), + .then((res) => res.val!.at(0)), getVerificationsPerInterval({ workspaceId: api.workspaceId, keySpaceId: api.keyAuthId!, start: billingCycleStart, end: billingCycleEnd, - }), + }).then((res) => res.val!), ]); const successOverTime: { x: string; y: number }[] = []; diff --git a/apps/dashboard/app/(app)/identities/[identityId]/page.tsx b/apps/dashboard/app/(app)/identities/[identityId]/page.tsx index ecd5a90ed9..0a0ebdc191 100644 --- a/apps/dashboard/app/(app)/identities/[identityId]/page.tsx +++ b/apps/dashboard/app/(app)/identities/[identityId]/page.tsx @@ -168,7 +168,7 @@ const LastUsed: React.FC<{ workspaceId: string; keySpaceId: string; keyId: strin keySpaceId: props.keySpaceId, keyId: props.keyId, }) - .then((res) => res.at(0)?.time ?? null); + .then((res) => res.val?.at(0)?.time ?? null); return ( diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/page.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/page.tsx index 90cd232745..156aed9466 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/page.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/page.tsx @@ -122,10 +122,7 @@ const AuditLogTable: React.FC<{ success: selected.success ?? undefined, }; - const logs = await clickhouse.ratelimits.logs(query).catch((err) => { - console.error(err); - throw err; - }); + const logs = await clickhouse.ratelimits.logs(query).then((res) => res.val!); if (logs.length === 0) { return ( diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/overrides/table.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/overrides/table.tsx index 7d24ee2945..d2f2ef502e 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/overrides/table.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/overrides/table.tsx @@ -92,7 +92,7 @@ const LastUsed: React.FC<{ identifier: [identifier], }); - const unixMilli = lastUsed.at(0)?.time; + const unixMilli = lastUsed.val?.at(0)?.time; if (unixMilli) { return {ms(Date.now() - unixMilli)} ago; } diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/page.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/page.tsx index 4c455f888e..f99045d85d 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/page.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/page.tsx @@ -68,17 +68,17 @@ export default async function RatelimitNamespacePage(props: { .from(schema.ratelimitOverrides) .where(eq(schema.ratelimitOverrides.namespaceId, namespace.id)) .execute() - .then((res) => res.at(0)?.count ?? 0), - getRatelimitsPerInterval(query), + .then((res) => res?.at(0)?.count ?? 0), + getRatelimitsPerInterval(query).then((res) => res.val!), getRatelimitsPerInterval({ workspaceId: namespace.workspaceId, namespaceId: namespace.id, start: billingCycleStart, end: billingCycleEnd, - }), + }).then((res) => res.val!), clickhouse.ratelimits .latest({ workspaceId: namespace.workspaceId, namespaceId: namespace.id }) - .then((res) => res.at(0)?.time), + .then((res) => res.val?.at(0)?.time), ]); const passedOverTime: { x: string; y: number }[] = []; diff --git a/apps/dashboard/app/(app)/ratelimits/card.tsx b/apps/dashboard/app/(app)/ratelimits/card.tsx index 586f4ce234..deed233878 100644 --- a/apps/dashboard/app/(app)/ratelimits/card.tsx +++ b/apps/dashboard/app/(app)/ratelimits/card.tsx @@ -17,15 +17,17 @@ export const RatelimitCard: React.FC = async ({ workspace, namespace }) = const intervalMs = 1000 * 60 * 60; const [history, lastUsed] = await Promise.all([ - clickhouse.ratelimits.perMinute({ - workspaceId: workspace.id, - namespaceId: namespace.id, - start: end - intervalMs, - end, - }), + clickhouse.ratelimits + .perMinute({ + workspaceId: workspace.id, + namespaceId: namespace.id, + start: end - intervalMs, + end, + }) + .then((res) => res.val!), clickhouse.ratelimits .latest({ workspaceId: workspace.id, namespaceId: namespace.id }) - .then((res) => res.at(0)?.time), + .then((res) => res.val?.at(0)?.time), ]); const totalRequests = history.reduce((sum, d) => sum + d.total, 0); diff --git a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/history/page.tsx b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/history/page.tsx index 53c6b6cbe8..3e8995320f 100644 --- a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/history/page.tsx +++ b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/history/page.tsx @@ -39,11 +39,13 @@ export default async function HistoryPage(props: { if (!key?.keyAuth?.api) { return notFound(); } - const history = await clickhouse.verifications.logs({ - workspaceId: UNKEY_WORKSPACE_ID, - keySpaceId: key.keyAuthId, - keyId: key.id, - }); + const history = await clickhouse.verifications + .logs({ + workspaceId: UNKEY_WORKSPACE_ID, + keySpaceId: key.keyAuthId, + keyId: key.id, + }) + .then((res) => res.val!); return ; } diff --git a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/layout.tsx b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/layout.tsx index b950ff4b55..ccee1800b1 100644 --- a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/layout.tsx +++ b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/layout.tsx @@ -84,7 +84,7 @@ const LastUsed: React.FC<{ workspaceId: string; keySpaceId: string; keyId: strin }) => { const lastUsed = await clickhouse.verifications .latest({ workspaceId, keySpaceId, keyId }) - .then((res) => res.at(0)?.time ?? 0); + .then((res) => res.val?.at(0)?.time ?? 0); return ( diff --git a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/page.tsx b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/page.tsx index 24b3426d37..acfe0e69c3 100644 --- a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/page.tsx +++ b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/page.tsx @@ -91,11 +91,13 @@ export default async function RootKeyPage(props: { if (!keyForHistory?.keyAuth?.api) { return notFound(); } - const history = await clickhouse.verifications.latest({ - workspaceId: UNKEY_WORKSPACE_ID, - keySpaceId: key.keyAuthId, - keyId: key.id, - }); + const history = await clickhouse.verifications + .latest({ + workspaceId: UNKEY_WORKSPACE_ID, + keySpaceId: key.keyAuthId, + keyId: key.id, + }) + .then((res) => res.val!); const apis = workspace.apis.map((api) => { const apiPermissionsStructure = apiPermissions(api.id); diff --git a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/add-permission-for-api.tsx b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/add-permission-for-api.tsx index af90688d63..33b02ee147 100644 --- a/apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/add-permission-for-api.tsx +++ b/apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/add-permission-for-api.tsx @@ -9,7 +9,7 @@ import { SelectValue, } from "@/components/ui/select"; import type { Permission } from "@unkey/db"; -import { type PropsWithChildren, useMemo, useState } from "react"; +import { type PropsWithChildren, useState } from "react"; import { PermissionToggle } from "./permission_toggle"; import { apiPermissions } from "./permissions"; @@ -38,10 +38,7 @@ export function DialogAddPermissionsForAPI( }); const [selectedApiId, setSelectedApiId] = useState(""); - const selectedApi = useMemo( - () => props.apis.find((api) => api.id === selectedApiId), - [selectedApiId], - ); + const selectedApi = props.apis.find((api) => api.id === selectedApiId); const isSelectionDisabled = selectedApi && !apisWithoutPermission.some((api) => api.id === selectedApi.id); diff --git a/apps/dashboard/app/(app)/success/page.tsx b/apps/dashboard/app/(app)/success/page.tsx index fdbac2827e..cb19319bac 100644 --- a/apps/dashboard/app/(app)/success/page.tsx +++ b/apps/dashboard/app/(app)/success/page.tsx @@ -64,7 +64,7 @@ export default async function SuccessPage() { }); } - const activeWorkspaces = await clickhouse.business.activeWorkspaces(); + const activeWorkspaces = await clickhouse.business.activeWorkspaces().then((res) => res.val!); const chartData = activeWorkspaces.map(({ time, workspaces }) => ({ x: new Date(time).toLocaleDateString(), y: workspaces, diff --git a/internal/clickhouse/package.json b/internal/clickhouse/package.json index 59690429e7..6bcb3a280d 100644 --- a/internal/clickhouse/package.json +++ b/internal/clickhouse/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@clickhouse/client-web": "^1.6.0", + "@unkey/error": "workspace:^", "zod": "^3.23.8" } } diff --git a/internal/clickhouse/src/billing.ts b/internal/clickhouse/src/billing.ts index 9d32e608c6..ebdd6df6d4 100644 --- a/internal/clickhouse/src/billing.ts +++ b/internal/clickhouse/src/billing.ts @@ -30,10 +30,10 @@ export function getBillableRatelimits(ch: Querier) { }); const res = await query(args); - if (!res) { + if (res.err || res.val.length === 0) { return 0; } - return res.at(0)?.count ?? 0; + return res.val.at(0)?.count ?? 0; }; } // get the billable verifications for a workspace in a specific month. @@ -65,9 +65,9 @@ export function getBillableVerifications(ch: Querier) { }); const res = await query(args); - if (!res) { + if (res.err || res.val.length === 0) { return 0; } - return res.at(0)?.count ?? 0; + return res.val.at(0)?.count ?? 0; }; } diff --git a/internal/clickhouse/src/client/client.ts b/internal/clickhouse/src/client/client.ts index 0773cca031..934dd96816 100644 --- a/internal/clickhouse/src/client/client.ts +++ b/internal/clickhouse/src/client/client.ts @@ -1,7 +1,8 @@ import { type ClickHouseClient, createClient } from "@clickhouse/client-web"; +import { Err, Ok, type Result } from "@unkey/error"; import { z } from "zod"; +import { InsertError, QueryError } from "./error"; import type { Inserter, Querier } from "./interface"; - export type Config = { url: string; }; @@ -12,6 +13,7 @@ export class Client implements Querier, Inserter { constructor(config: Config) { this.client = createClient({ url: config.url, + clickhouse_settings: { async_insert: 1, wait_for_async_insert: 1, @@ -32,11 +34,11 @@ export class Client implements Querier, Inserter { // The schema of the output of each row // Example: z.object({ id: z.string() }) schema: TOut; - }): (params: z.input) => Promise[]> { - return async (params: z.input): Promise[]> => { + }): (params: z.input) => Promise[], QueryError>> { + return async (params: z.input): Promise[], QueryError>> => { const validParams = req.params?.safeParse(params); if (validParams?.error) { - throw new Error(`Bad params: ${validParams.error.message}`); + return Err(new QueryError(`Bad params: ${validParams.error.message}`, { query: "" })); } const res = await this.client .query({ @@ -48,7 +50,11 @@ export class Client implements Querier, Inserter { throw new Error(`${err.message} ${req.query}, params: ${JSON.stringify(params)}`); }); const rows = await res.json(); - return z.array(req.schema).parse(rows); + const parsed = z.array(req.schema).safeParse(rows); + if (parsed.error) { + return Err(new QueryError(`Malformed data: ${parsed.error.message}`, { query: req.query })); + } + return Ok(parsed.data); }; } @@ -57,22 +63,40 @@ export class Client implements Querier, Inserter { schema: TSchema; }): ( events: z.input | z.input[], - ) => Promise<{ executed: boolean; query_id: string }> { + ) => Promise> { return async (events: z.input | z.input[]) => { let validatedEvents: z.output | z.output[] | undefined = undefined; const v = Array.isArray(events) ? req.schema.array().safeParse(events) : req.schema.safeParse(events); if (!v.success) { - throw new Error(v.error.message); + return Err(new InsertError(v.error.message)); } validatedEvents = v.data; - return await this.client.insert({ - table: req.table, - format: "JSONEachRow", - values: Array.isArray(validatedEvents) ? validatedEvents : [validatedEvents], - }); + return this.retry(() => + this.client + .insert({ + table: req.table, + format: "JSONEachRow", + values: Array.isArray(validatedEvents) ? validatedEvents : [validatedEvents], + }) + .then((res) => Ok(res)) + .catch((err) => Err(new InsertError(err.message))), + ); }; } + + private async retry(fn: (attempt: number) => Promise): Promise { + let err: Error | undefined = undefined; + for (let i = 1; i <= 3; i++) { + try { + return fn(i); + } catch (e) { + console.warn(e); + err = e as Error; + } + } + throw err; + } } diff --git a/internal/clickhouse/src/client/error.ts b/internal/clickhouse/src/client/error.ts new file mode 100644 index 0000000000..7191d2bfa9 --- /dev/null +++ b/internal/clickhouse/src/client/error.ts @@ -0,0 +1,20 @@ +import { BaseError } from "@unkey/error"; +export class InsertError extends BaseError { + public readonly retry = true; + public readonly name = InsertError.name; + constructor(message: string) { + super({ + message, + }); + } +} +export class QueryError extends BaseError<{ query: string }> { + public readonly retry = true; + public readonly name = QueryError.name; + constructor(message: string, context: { query: string }) { + super({ + message, + context, + }); + } +} diff --git a/internal/clickhouse/src/client/interface.ts b/internal/clickhouse/src/client/interface.ts index ea4d373d05..ecb3879410 100644 --- a/internal/clickhouse/src/client/interface.ts +++ b/internal/clickhouse/src/client/interface.ts @@ -1,5 +1,6 @@ +import type { Result } from "@unkey/error"; import type { z } from "zod"; - +import type { InsertError, QueryError } from "./error"; export interface Querier { query, TOut extends z.ZodSchema>(req: { // The SQL query to run. @@ -12,7 +13,7 @@ export interface Querier { // The schema of the output of each row // Example: z.object({ id: z.string() }) schema: TOut; - }): (params: z.input) => Promise[]>; + }): (params: z.input) => Promise[], QueryError>>; } export interface Inserter { @@ -21,5 +22,5 @@ export interface Inserter { schema: TSchema; }): ( events: z.input | z.input[], - ) => Promise<{ executed: boolean; query_id: string }>; + ) => Promise>; } diff --git a/internal/clickhouse/src/client/noop.ts b/internal/clickhouse/src/client/noop.ts index 7eef057cc0..12ba3dbf7c 100644 --- a/internal/clickhouse/src/client/noop.ts +++ b/internal/clickhouse/src/client/noop.ts @@ -1,4 +1,6 @@ +import { Err, Ok, type Result } from "@unkey/error"; import type { z } from "zod"; +import { InsertError, type QueryError } from "./error"; import type { Inserter, Querier } from "./interface"; export class Noop implements Querier, Inserter { public query, TOut extends z.ZodSchema>(req: { @@ -12,10 +14,10 @@ export class Noop implements Querier, Inserter { // The schema of the output of each row // Example: z.object({ id: z.string() }) schema: TOut; - }): (params: z.input) => Promise[]> { - return async (params: z.input): Promise[]> => { + }): (params: z.input) => Promise[], QueryError>> { + return async (params: z.input): Promise[], QueryError>> => { req.params?.safeParse(params); - return []; + return Ok([]); }; } @@ -24,16 +26,16 @@ export class Noop implements Querier, Inserter { schema: TSchema; }): ( events: z.input | z.input[], - ) => Promise<{ executed: boolean; query_id: string }> { + ) => Promise> { return async (events: z.input | z.input[]) => { const v = Array.isArray(events) ? req.schema.array().safeParse(events) : req.schema.safeParse(events); if (!v.success) { - throw new Error(v.error.message); + return Err(new InsertError(v.error.message)); } - return { executed: true, query_id: "noop" }; + return Ok({ executed: true, query_id: "noop" }); }; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b60c0406c1..88c879ee59 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1198,6 +1198,9 @@ importers: '@clickhouse/client-web': specifier: ^1.6.0 version: 1.6.0 + '@unkey/error': + specifier: workspace:^ + version: link:../../packages/error zod: specifier: ^3.23.8 version: 3.23.8 @@ -7141,7 +7144,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: @@ -7151,7 +7154,7 @@ packages: '@peculiar/asn1-schema': 2.3.13 '@peculiar/json-schema': 1.1.12 pvtsutils: 1.3.5 - tslib: 2.4.1 + tslib: 2.8.1 webcrypto-core: 1.8.1 dev: false @@ -13904,7 +13907,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: @@ -15311,7 +15314,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.4 + debug: 4.3.7(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -17918,7 +17921,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: @@ -19331,6 +19334,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==} @@ -19745,7 +19749,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: @@ -20470,7 +20474,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==} @@ -22574,7 +22578,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: