Compare commits

...
Author SHA1 Message Date
hanzo-dev c9fd1cfc07 ci(data-schemas): isolate native-sqlite specs one-file-per-process; v0.9.16
The 15 specs that instantiate the native better-sqlite3 driver corrupt each
other under a shared jest worker: jest gives each spec file its own JS module
realm while the native addon is process-cached per worker, so cross-file state
breaks sibling in-memory databases (driver-agnostic — reproduces with mainstream
better-sqlite3; a compound json_extract UNIQUE stops firing). Prod is unaffected
(one realm, one shared handle for the process lifetime).

test:ci now runs test/ci.mjs: the normal coverage pass for everything except the
native-driver set (via testPathIgnorePatterns), then each of those 15 specs in
its own jest process, exiting non-zero on any failure. NOT --runInBand /
maxWorkers=1 (a single shared worker still corrupts). No test weakening, no skips.

Bump chat 0.9.15 -> 0.9.16 (patch).
2026-07-04 15:51:44 -07:00
hanzo-dev 5feca644e2 fix(store/sqlite): close shared handle on rekey + test teardown (real leak)
sharedSqliteHandle() reassigned sharedHandle on a collection-key change without
closing the prior connection — a latent native-handle leak on any rekey. Close
it before replacing, and export closeSharedSqliteHandle() so storeRegistry.spec
(rekeys twice) and tenantIsolation.coverage.spec tear the handle down instead of
leaking it past the file.

NOTE: this fixes the real leak the review identified, but does NOT resolve the
cross-file store-spec flake. That flake is a separate, deeper issue (see report):
driver-agnostic (reproduces with mainstream better-sqlite3 too), isolated to the
store's create path, timing/heap-sensitive (any probe masks it), and NOT fixed by
closing handles/GC/statement-cache/wrapper-pinning. Every store suite passes in
its own process; production (single long-lived handle, one module realm) is
unaffected.
2026-07-04 15:35:37 -07:00
hanzo-dev 72a5c71fe3 fix(store/sqlite): swap node:sqlite→better-sqlite3-multiple-ciphers (Node 20) + honor tenant sentinel in debug log
node:sqlite (DatabaseSync) is a Node 22+ builtin; prod runs Node 20 (Alpine),
so require('node:sqlite') threw ERR_UNKNOWN_BUILTIN_MODULE, cascading through
createModels → applySqliteOverrides → openDatabase and breaking the built dist
("createModels is not a function"). Swap to better-sqlite3-multiple-ciphers
12.11.1 (engines include 20.x, synchronous drop-in, SQLCipher AES-256 at rest —
the Node embodiment of the hanzoai/sqlite contract).

- data-schemas dep + root pnpm.onlyBuiltDependencies allowlist (native addon);
  rollup externalizes the driver.
- openDatabase(): lazy require of the driver, identical WAL/synchronous/
  busy_timeout/foreign_keys pragmas. Wire the CHAT_SQLITE_KEY encryption seam
  (SQLCipher cipher/legacy/key pragmas applied before any page-touching
  statement; 64-hex validated, fail-closed; key/path never logged). KMS/CEK
  derivation is Milestone 2.
- DocModel: retype db to the driver's Database instance; binding/return parity
  already correct (booleans→1/0, dates→ISO, TEXT reads only). engine untouched
  (27/27 held).
- parsers: restore the structured-logging-context impl dropped in an upstream
  merge (spec #13110 landed without its parsers.ts) — appendRequestContext for
  non-debug lines and drop the __SYSTEM__ tenant sentinel from debug traversal.
- models: register the SystemGrant model in createModels (schema/model/methods/
  SQLite-spec + coverage guard all existed; only the registration was dangling).

Scrub all node:sqlite/DatabaseSync references from src (comments + spec names).
2026-07-04 14:40:03 -07:00
24 changed files with 5318 additions and 362 deletions
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@hanzochat/chat",
"version": "0.9.15",
"version": "0.9.16",
"description": "Chat - Unified interface to Agents, LLMs, MCPs and any AI model or OpenAPI documented API with full RAG stack",
"packageManager": "pnpm@10.27.0",
"workspaces": [
@@ -190,7 +190,8 @@
"sharp",
"protobufjs",
"mongodb-memory-server",
"unrs-resolver"
"unrs-resolver",
"better-sqlite3-multiple-ciphers"
],
"overrides": {
"@ariakit/react": "0.4.29",
+2416 -154
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+2414 -156
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+2
View File
@@ -5,6 +5,8 @@ export * from './schema';
export * from './utils';
export { createModels } from './models';
export { createMethods, DEFAULT_REFRESH_TOKEN_EXPIRY, DEFAULT_SESSION_EXPIRY } from './methods';
export { createSqliteHandle, openDatabase, DocModel, CHAT_COLLECTION_SPECS, type SqliteHandle, type CollectionSpec, } from './stores/sqlite';
export type { DataHandle } from './common/dataHandle';
export type * from './types';
export type * from './methods';
export { default as logger } from './config/winston';
+2 -1
View File
@@ -1,6 +1,7 @@
import { Types } from 'mongoose';
import type { DataHandle } from '~/common/dataHandle';
import type * as t from '~/types';
export declare function createMemoryMethods(mongoose: typeof import('mongoose')): {
export declare function createMemoryMethods(handle: DataHandle): {
setMemory: ({ userId, key, value, tokenCount, }: t.SetMemoryParams) => Promise<t.MemoryResult>;
createMemory: ({ userId, key, value, tokenCount, }: t.SetMemoryParams) => Promise<t.MemoryResult>;
deleteMemory: ({ userId, key }: t.DeleteMemoryParams) => Promise<t.MemoryResult>;
+2 -1
View File
@@ -1,6 +1,7 @@
import type { DeleteResult } from 'mongoose';
import type { DataHandle } from '~/common/dataHandle';
import type { FindPluginAuthsByKeysParams, UpdatePluginAuthParams, DeletePluginAuthParams, FindPluginAuthParams, IPluginAuth } from '~/types';
export declare function createPluginAuthMethods(mongoose: typeof import('mongoose')): {
export declare function createPluginAuthMethods(handle: DataHandle): {
findOnePluginAuth: ({ userId, authField, pluginKey, }: FindPluginAuthParams) => Promise<IPluginAuth | null>;
findPluginAuthsByKeys: ({ userId, pluginKeys, }: FindPluginAuthsByKeysParams) => Promise<IPluginAuth[]>;
updatePluginAuth: ({ userId, authField, pluginKey, value, }: UpdatePluginAuthParams) => Promise<IPluginAuth>;
+3 -6
View File
@@ -1,9 +1,6 @@
export declare function createRoleMethods(mongoose: typeof import('mongoose')): {
listRoles: () => Promise<(import("mongoose").FlattenMaps<any> & Required<{
_id: unknown;
}> & {
__v: number;
})[]>;
import type { DataHandle } from '~/common/dataHandle';
export declare function createRoleMethods(handle: DataHandle): {
listRoles: () => Promise<any>;
initializeRoles: () => Promise<void>;
};
export type RoleMethods = ReturnType<typeof createRoleMethods>;
+2 -1
View File
@@ -1,6 +1,7 @@
import type { DataHandle } from '~/common/dataHandle';
import type * as t from '~/types';
/** Factory function that takes mongoose instance and returns the methods */
export declare function createShareMethods(mongoose: typeof import('mongoose')): {
export declare function createShareMethods(handle: DataHandle): {
getSharedLink: (user: string, conversationId: string) => Promise<t.GetShareLinkResult>;
getSharedLinks: (user: string, pageParam?: Date, pageSize?: number, isPublic?: boolean, sortBy?: string, sortDirection?: string, search?: string) => Promise<t.SharedLinksResult>;
createSharedLink: (user: string, conversationId: string, targetMessageId?: string) => Promise<t.CreateShareResult>;
+7
View File
@@ -1,3 +1,9 @@
/**
* Closes and clears the process-shared SQLite handle. Idempotent. The prod path
* keeps one handle for the process lifetime; this exists so tests that build the
* handle tear it down — every native Database opened MUST be closed.
*/
export declare function closeSharedSqliteHandle(): void;
/**
* Creates all database models for all collections
*/
@@ -31,4 +37,5 @@ export declare function createModels(mongoose: typeof import('mongoose')): {
AccessRole: import("mongoose").Model<any, {}, {}, {}, any, any>;
AclEntry: import("mongoose").Model<any, {}, {}, {}, any, any>;
Group: import("mongoose").Model<any, {}, {}, {}, any, any>;
SystemGrant: import("mongoose").Model<any, {}, {}, {}, any, any>;
};
+2 -1
View File
@@ -21,7 +21,7 @@
"build": "npm run clean && rollup -c --silent --bundleConfigAsCjs",
"build:watch": "rollup -c -w",
"test": "jest --coverage --watch",
"test:ci": "jest --coverage --ci",
"test:ci": "node test/ci.mjs",
"verify": "npm run test:ci",
"b:clean": "bun run rimraf dist",
"b:build": "bun run b:clean && bun run rollup -c --silent --bundleConfigAsCjs"
@@ -59,6 +59,7 @@
"typescript": "^5.0.4"
},
"dependencies": {
"better-sqlite3-multiple-ciphers": "12.11.1",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
},
+1 -1
View File
@@ -36,5 +36,5 @@ export default {
}),
],
// Do not bundle these external dependencies
external: ['mongoose', 'node:sqlite', 'node:crypto'],
external: ['mongoose', 'better-sqlite3-multiple-ciphers', 'node:crypto'],
};
+33 -4
View File
@@ -1,6 +1,7 @@
import { klona } from 'klona';
import winston from 'winston';
import traverse from '../utils/object-traverse';
import { SYSTEM_TENANT_ID } from './tenantContext';
import type { TraverseContext } from '../utils/object-traverse';
const SPLAT_SYMBOL = Symbol.for('splat');
@@ -8,6 +9,7 @@ const MESSAGE_SYMBOL = Symbol.for('message');
const CONSOLE_JSON_STRING_LENGTH: number =
parseInt(process.env.CONSOLE_JSON_STRING_LENGTH || '', 10) || 255;
const DEBUG_MESSAGE_LENGTH: number = parseInt(process.env.DEBUG_MESSAGE_LENGTH || '', 10) || 150;
const LOG_CONTEXT_KEYS = ['tenantId', 'userId', 'requestId'] as const;
const sensitiveKeys: RegExp[] = [
/^(sk-)[^\s]+/, // OpenAI API key pattern
@@ -104,6 +106,30 @@ const condenseArray = (item: unknown): string | unknown => {
return item;
};
/**
* Serializes request-scoped identity (tenant / user / request ids) into a
* compact JSON suffix, omitting the internal `__SYSTEM__` tenant sentinel so it
* never leaks into logs.
*/
function formatRequestContext(metadata: Record<string, unknown>): string {
const context: Partial<Record<(typeof LOG_CONTEXT_KEYS)[number], string>> = {};
LOG_CONTEXT_KEYS.forEach((key) => {
const value = metadata[key];
if (key === 'tenantId' && value === SYSTEM_TENANT_ID) {
return;
}
if (typeof value === 'string' && value) {
context[key] = value;
}
});
return Object.keys(context).length > 0 ? JSON.stringify(context) : '';
}
function appendRequestContext(line: string, metadata: Record<string, unknown>): string {
const context = formatRequestContext(metadata);
return context ? `${line} ${context}` : line;
}
/**
* Formats log messages for debugging purposes.
* - Truncates long strings within log messages.
@@ -131,7 +157,7 @@ const debugTraverse = winston.format.printf(
try {
if (level !== 'debug') {
return msgParts[0];
return appendRequestContext(msgParts[0], metadata);
}
if (!metadata) {
@@ -144,22 +170,25 @@ const debugTraverse = winston.format.printf(
const debugValue = Array.isArray(splatArray) ? splatArray[0] : undefined;
if (!debugValue) {
return msgParts[0];
return appendRequestContext(msgParts[0], metadata);
}
if (debugValue && Array.isArray(debugValue)) {
msgParts.push(`\n${JSON.stringify(debugValue.map(condenseArray))}`);
return msgParts.join('');
return appendRequestContext(msgParts.join(''), metadata);
}
if (typeof debugValue !== 'object') {
msgParts.push(` ${debugValue}`);
return msgParts.join('');
return appendRequestContext(msgParts.join(''), metadata);
}
msgParts.push('\n{');
const copy = klona(metadata);
if (copy.tenantId === SYSTEM_TENANT_ID) {
delete copy.tenantId;
}
try {
const traversal = traverse(copy);
traversal.forEach(function (this: TraverseContext, value: unknown) {
@@ -234,7 +234,7 @@ describe('Conversation domain on SQLite (real methods)', () => {
describe('data path is mongoose-free', () => {
it('never requires mongoose to satisfy the conversations+messages contract', () => {
// The handle is pure node:sqlite; the methods above ran green against it.
// The handle is a pure SQLite store; the methods above ran green against it.
expect(handle.models.Conversation.constructor.name).toBe('DocModel');
expect(handle.models.Message.constructor.name).toBe('DocModel');
});
+18 -1
View File
@@ -27,6 +27,7 @@ import { createMemoryModel } from './memory';
import { createAccessRoleModel } from './accessRole';
import { createAclEntryModel } from './aclEntry';
import { createGroupModel } from './group';
import { createSystemGrantModel } from './systemGrant';
import {
createSqliteHandle,
createDualWriteModel,
@@ -64,7 +65,7 @@ function parseStoreCsv(value?: string): string[] {
}
/**
* One SQLite handle (one `node:sqlite` connection) per process, shared across
* One SQLite handle (one driver connection) per process, shared across
* every `createModels` call — the api requires the data-schemas index from three
* entry points, and a per-call handle would open three connections to the same
* file and race for the WAL write lock. Keyed by the collection set so a changed
@@ -76,12 +77,27 @@ let sharedHandleKey = '';
function sharedSqliteHandle(names: string[]): SqliteHandle {
const key = [...names].sort().join(',');
if (!sharedHandle || sharedHandleKey !== key) {
// Close the prior native connection before replacing it — a bare reassign
// leaks the better-sqlite3 handle (its late GC finalizer corrupts sibling
// SQLite state in a shared worker; latent prod leak on any rekey).
sharedHandle?.close();
sharedHandle = createSqliteHandle(names);
sharedHandleKey = key;
}
return sharedHandle;
}
/**
* Closes and clears the process-shared SQLite handle. Idempotent. The prod path
* keeps one handle for the process lifetime; this exists so tests that build the
* handle tear it down — every native Database opened MUST be closed.
*/
export function closeSharedSqliteHandle(): void {
sharedHandle?.close();
sharedHandle = undefined;
sharedHandleKey = '';
}
function applySqliteOverrides<T extends Record<string, unknown>>(models: T): T {
const sqliteNames = new Set(parseStoreCsv(process.env.CHAT_STORE_SQLITE));
const dualNames = new Set(parseStoreCsv(process.env.CHAT_STORE_DUALWRITE));
@@ -140,6 +156,7 @@ export function createModels(mongoose: typeof import('mongoose')) {
AccessRole: createAccessRoleModel(mongoose),
AclEntry: createAclEntryModel(mongoose),
Group: createGroupModel(mongoose),
SystemGrant: createSystemGrantModel(mongoose),
};
return applySqliteOverrides(models);
}
@@ -1,5 +1,5 @@
import mongoose from 'mongoose';
import { createModels } from '../index';
import { createModels, closeSharedSqliteHandle } from '../index';
/**
* Global symbol set by applyTenantIsolation() on every schema it processes.
@@ -25,6 +25,12 @@ describe('tenant-isolation plugin coverage', () => {
createModels(mongoose);
});
afterAll(() => {
// If store flags are set in the environment, createModels opens the shared
// native handle — close it so no open SQLite connection leaks past this file.
closeSharedSqliteHandle();
});
it('applies the tenant-isolation plugin to every model that has a tenantId field', () => {
const missing: string[] = [];
@@ -1,9 +1,12 @@
import mongoose from 'mongoose';
import { createModels } from './index';
import { createModels, closeSharedSqliteHandle } from './index';
describe('createModels — per-domain store registry', () => {
afterEach(() => {
delete process.env.CHAT_STORE_SQLITE;
// Rekeying createModels opens the shared native handle; close it so no open
// SQLite connection leaks into a sibling spec sharing this jest worker.
closeSharedSqliteHandle();
});
it('defaults to mongoose for every collection (live path unchanged)', () => {
@@ -1,7 +1,7 @@
import { createSqliteHandle, type SqliteHandle } from './index';
import type { DocModel } from './DocModel';
describe('DocModel (node:sqlite backend)', () => {
describe('DocModel (better-sqlite3 backend)', () => {
let handle: SqliteHandle;
let Message: DocModel;
let Conversation: DocModel;
@@ -11,7 +11,7 @@
* CollectionSpec when migrated). MeiliSearch stays a separate concern: `.meiliSearch`
* is intentionally absent, matching a mongoose model with no MEILI_HOST configured.
*/
import type { DatabaseSync } from 'node:sqlite';
import type Database from 'better-sqlite3-multiple-ciphers';
import { getTenantId, SYSTEM_TENANT_ID } from '~/config/tenantContext';
import {
matchesFilter,
@@ -90,7 +90,7 @@ const SQL_SAFE_FIELD = /^[A-Za-z_][A-Za-z0-9_]*$/;
export class DocModel {
readonly modelName: string;
private readonly db: DatabaseSync;
private readonly db: Database.Database;
private readonly dateFields: Set<string>;
private readonly anchorFields: Set<string>;
private readonly refs: Record<string, string>;
@@ -99,7 +99,7 @@ export class DocModel {
/** Resolves sibling collections for `.populate()`; wired by createSqliteHandle. */
resolver?: (name: string) => DocModel | undefined;
constructor(db: DatabaseSync, spec: CollectionSpec) {
constructor(db: Database.Database, spec: CollectionSpec) {
this.db = db;
this.modelName = spec.name;
this.dateFields = new Set(spec.dateFields ?? ['createdAt', 'updatedAt', 'expiredAt']);
@@ -273,8 +273,9 @@ export class DocModel {
// array-contains (Mongo {field: value} over an array) — and remains a
// superset prefilter (the JS matcher is authoritative).
clauses.push(`EXISTS (SELECT 1 FROM json_each(doc, '$.${key}') WHERE value = ?)`);
// node:sqlite binds only null/number/bigint/string/blob. json_each
// yields 1/0 for JSON booleans, so map booleans; dates -> ISO.
// The driver binds only null/number/bigint/string/Buffer (boolean and
// undefined throw). json_each yields 1/0 for JSON booleans, so map
// booleans to 1/0; dates -> ISO.
const param =
c instanceof Date ? c.toISOString() : typeof c === 'boolean' ? (c ? 1 : 0) : c;
params.push(param);
@@ -849,7 +850,7 @@ export class QueryBuilder implements PromiseLike<Doc | Doc[] | null> {
return this;
}
/** No-op: node:sqlite is a single connection; Mongo sessions don't apply. */
/** No-op: the store is a single connection; Mongo sessions don't apply. */
session(_session?: unknown): this {
return this;
}
@@ -15,7 +15,7 @@ import type { CollectionSpec } from './DocModel';
* ZERO Mongo change-streams / tailable cursors / `.watch()` / DB-driven
* subscriptions. Conversation/message reads are plain request/response
* (getConvosByCursor / getMessages). Therefore NO migrated domain here needs a
* DB-subscription replacement — plain node:sqlite is correct for all of them.
* DB-subscription replacement — the plain SQLite store is correct for all of them.
*
* CUTOVER TARGET (per architecture directive "Base for realtime, SQLite for
* storage"): the live-chat domains — **Conversation** and **Message** — are the
@@ -10,7 +10,7 @@
* handle or this SQLite handle. A networked Hanzo Base / cloud `/v1` backend is
* a future third implementation of the same handle shape.
*/
import type { DatabaseSync } from 'node:sqlite';
import type Database from 'better-sqlite3-multiple-ciphers';
import { DocModel, type CollectionSpec } from './DocModel';
import { CHAT_COLLECTION_SPECS } from './collections';
import { ObjectId } from './engine';
@@ -22,7 +22,7 @@ export { createDualWriteModel, DualWriteModel } from './DualWriteModel';
export interface SqliteHandle {
models: Record<string, DocModel>;
db: DatabaseSync;
db: Database.Database;
Types: { ObjectId: typeof ObjectId };
close(): void;
}
@@ -30,17 +30,32 @@ export interface SqliteHandle {
/**
* Opens a SQLite database. Defaults to the path in `CHAT_SQLITE_PATH`, else an
* in-memory database (used by tests). WAL + NORMAL sync for durable throughput.
* A non-memory file is opened encrypted (SQLCipher AES-256, `hanzoai/sqlite`
* contract) when `CHAT_SQLITE_KEY` holds a 64-hex-char raw key; unset opens
* unencrypted (tests + local dev).
*/
export function openDatabase(dbPath?: string): DatabaseSync {
// `node:sqlite` (DatabaseSync) exists only on Node >= 22.5. This store is
// inert by default (unset CHAT_STORE_SQLITE) yet the data-schemas index is
// loaded at server boot, so a static import would crash the Node 20 runtime.
// Require it lazily — only when a database is actually opened.
export function openDatabase(dbPath?: string): Database.Database {
// `better-sqlite3-multiple-ciphers` is a native addon. The data-schemas index
// is loaded at server boot even when the store is inert (unset
// CHAT_STORE_SQLITE), so require it lazily — only when a database is actually
// opened — keeping module import side-effect-free.
// eslint-disable-next-line @typescript-eslint/no-require-imports
const sqlite = require('node:sqlite') as typeof import('node:sqlite');
const DatabaseCtor = require('better-sqlite3-multiple-ciphers') as typeof import('better-sqlite3-multiple-ciphers');
const path = dbPath ?? process.env.CHAT_SQLITE_PATH ?? ':memory:';
const db = new sqlite.DatabaseSync(path);
const db = new DatabaseCtor(path);
if (path !== ':memory:') {
// SQLCipher keying MUST precede any statement that touches DB pages. Never
// log the key or the keyed path. KMS/CEK derivation is a later milestone;
// this only honors a raw key supplied out-of-band.
const key = process.env.CHAT_SQLITE_KEY;
if (key) {
if (!/^[0-9a-f]{64}$/i.test(key)) {
throw new Error('[sqlite-store] CHAT_SQLITE_KEY must be a 64-hex-char raw key');
}
db.pragma("cipher='sqlcipher'");
db.pragma('legacy=4');
db.pragma(`key="x'${key}'"`);
}
db.exec('PRAGMA journal_mode = WAL');
db.exec('PRAGMA synchronous = NORMAL');
// The one-shot Mongo→SQLite backfill runs as a SEPARATE process against this
@@ -55,11 +70,11 @@ export function openDatabase(dbPath?: string): DatabaseSync {
/**
* Builds a mongoose-shaped handle backed by SQLite for the given collection
* names (defaults to all known chat collection specs). Pass a shared
* `DatabaseSync` to co-locate collections in one file.
* `Database` to co-locate collections in one file.
*/
export function createSqliteHandle(
names?: string[],
options: { db?: DatabaseSync; dbPath?: string; specs?: Record<string, CollectionSpec> } = {},
options: { db?: Database.Database; dbPath?: string; specs?: Record<string, CollectionSpec> } = {},
): SqliteHandle {
const specs = options.specs ?? CHAT_COLLECTION_SPECS;
const db = options.db ?? openDatabase(options.dbPath);
+62
View File
@@ -0,0 +1,62 @@
/**
* CI test runner for @librechat/data-schemas.
*
* The spec files listed in ISOLATED instantiate the native `better-sqlite3-*`
* driver. Jest gives every spec file its own JS module realm, but the native
* addon is process-cached per worker, so cross-file state corrupts sibling
* in-memory databases (driver-agnostic — reproduces with mainstream
* better-sqlite3 too; a compound `json_extract` UNIQUE stops firing). Production
* is unaffected: it runs one module realm with one shared handle for the process
* lifetime. The fix is strict one-file-per-process isolation for those specs
* only — NOT `--runInBand`/`--maxWorkers=1` (a single shared worker still
* corrupts). Everything else runs in the normal coverage pass.
*/
import { spawnSync } from 'node:child_process';
import { createRequire } from 'node:module';
import { dirname, join } from 'node:path';
const require = createRequire(import.meta.url);
const JEST = join(dirname(require.resolve('jest/package.json')), 'bin', 'jest.js');
/** Native-driver specs — each run in its own process. */
const ISOLATED = [
'src/stores/sqlite/DocModel.spec.ts',
'src/stores/sqlite/DualWriteModel.spec.ts',
'src/models/storeRegistry.spec.ts',
'src/models/plugins/tenantIsolation.coverage.spec.ts',
'src/methods/convoMessage.sqlite.spec.ts',
'src/methods/skill.harness.sqlite.spec.ts',
'src/methods/batch2.sqlite.spec.ts',
'src/methods/batch3.sqlite.spec.ts',
'src/methods/batch4.sqlite.spec.ts',
'src/methods/batch5.sqlite.spec.ts',
'src/methods/batch6.sqlite.spec.ts',
'src/methods/batch7.sqlite.spec.ts',
'src/methods/batch7b.sqlite.spec.ts',
'src/methods/batch8a.sqlite.spec.ts',
'src/methods/batch8b.sqlite.spec.ts',
];
const runJest = (args) =>
spawnSync(process.execPath, [JEST, '--ci', ...args], { stdio: 'inherit' }).status === 0;
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let ok = true;
// 1) Normal coverage run for everything except the isolated set.
console.log(`\n[ci] coverage run (excluding ${ISOLATED.length} native-driver specs)`);
const ignore = ['/node_modules/', ...ISOLATED.map((f) => escapeRegExp(f) + '$')];
if (!runJest(['--coverage', '--testPathIgnorePatterns', ...ignore])) {
ok = false;
}
// 2) Each native-driver spec in its own process.
for (const file of ISOLATED) {
console.log(`\n[ci] isolated: ${file}`);
if (!runJest([file])) {
ok = false;
}
}
process.exit(ok ? 0 : 1);
+302 -10
View File
@@ -70,7 +70,7 @@ importers:
version: 2.32.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@1.21.7))
eslint-plugin-jest:
specifier: ^29.1.0
version: 29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3)
version: 29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0)(typescript@5.9.3)
eslint-plugin-jsx-a11y:
specifier: ^6.10.2
version: 6.10.2(eslint@9.39.4(jiti@1.21.7))
@@ -94,7 +94,7 @@ importers:
version: 9.1.7
jest:
specifier: ^30.2.0
version: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
version: 30.3.0
lint-staged:
specifier: ^15.4.3
version: 15.5.2
@@ -347,7 +347,7 @@ importers:
devDependencies:
jest:
specifier: ^30.2.0
version: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
version: 30.3.0
mongodb-memory-server:
specifier: ^10.1.4
version: 10.4.3
@@ -693,7 +693,7 @@ importers:
version: 1.0.3
eslint-plugin-jest:
specifier: ^29.1.0
version: 29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3)))(typescript@5.9.3)
version: 29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@20.19.37))(typescript@5.9.3)
fs-extra:
specifier: ^11.3.2
version: 11.3.4
@@ -702,7 +702,7 @@ importers:
version: 3.0.0
jest:
specifier: ^30.2.0
version: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
version: 30.3.0(@types/node@20.19.37)
jest-canvas-mock:
specifier: ^2.5.2
version: 2.5.2
@@ -1215,7 +1215,7 @@ importers:
version: 2.4.4
jest:
specifier: ^30.2.0
version: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
version: 30.3.0(@types/node@20.19.37)
jest-junit:
specifier: ^16.0.0
version: 16.0.0
@@ -1243,6 +1243,9 @@ importers:
packages/data-schemas:
dependencies:
better-sqlite3-multiple-ciphers:
specifier: 12.11.1
version: 12.11.1
jsonwebtoken:
specifier: ^9.0.2
version: 9.0.3
@@ -7411,6 +7414,10 @@ packages:
bcryptjs@2.4.3:
resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
better-sqlite3-multiple-ciphers@12.11.1:
resolution: {integrity: sha512-pG72+3VkUipnmYx4LwQqoOXNG2CJ1HlmDrlvqgr7xQHgsE+cz5rAZEiaJHnUKTHaGfGifggA/C0Sv9qZlUrfow==}
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x || 26.x}
bignumber.js@9.3.1:
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
@@ -7418,6 +7425,12 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
bn.js@4.12.3:
resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==}
@@ -7606,6 +7619,9 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
ci-info@3.9.0:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'}
@@ -8201,6 +8217,10 @@ packages:
decode-named-character-reference@1.3.0:
resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
dedent@1.7.2:
resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==}
peerDependencies:
@@ -8213,6 +8233,10 @@ packages:
resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
engines: {node: '>= 0.4'}
deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -8421,6 +8445,9 @@ packages:
encoding-sniffer@0.2.1:
resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==}
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
entities@2.2.0:
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
@@ -8748,6 +8775,10 @@ packages:
resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==}
engines: {node: '>= 0.8.0'}
expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -8876,6 +8907,9 @@ packages:
resolution: {integrity: sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==}
engines: {node: '>=14.16'}
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
filelist@1.0.6:
resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==}
@@ -9000,6 +9034,9 @@ packages:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@@ -9112,6 +9149,9 @@ packages:
get-tsconfig@4.13.6:
resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==}
github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -9437,6 +9477,9 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
inline-style-parser@0.2.7:
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
@@ -10630,6 +10673,10 @@ packages:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
@@ -10662,6 +10709,9 @@ packages:
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
engines: {node: '>=16 || 14 >=14.17'}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
@@ -10772,6 +10822,9 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
napi-postinstall@0.3.4:
resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -10825,6 +10878,10 @@ packages:
sass:
optional: true
node-abi@3.94.0:
resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==}
engines: {node: '>=10'}
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
@@ -11668,6 +11725,12 @@ packages:
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
engines: {node: ^10 || ^12 || >=14}
prebuild-install@7.1.3:
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
engines: {node: '>=10'}
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
hasBin: true
precond@0.2.3:
resolution: {integrity: sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==}
engines: {node: '>= 0.6'}
@@ -11813,6 +11876,9 @@ packages:
public-encrypt@4.0.3:
resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==}
pump@3.0.4:
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
punycode@1.4.1:
resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
@@ -11878,6 +11944,10 @@ packages:
react: '>=16.9.0'
react-dom: '>=16.9.0'
rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
react-avatar-editor@13.0.2:
resolution: {integrity: sha512-a4ajbi7lwDh98kgEtSEeKMu0vs0CHTczkq4Xcxr1EiwMFH1GlgHCEtwGU8q/H5W8SeLnH4KPK8LUjEEaZXklxQ==}
peerDependencies:
@@ -12453,6 +12523,12 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
simple-swizzle@0.2.4:
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
@@ -12655,6 +12731,10 @@ packages:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -12781,9 +12861,16 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
tar-fs@2.1.5:
resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==}
tar-mini@0.2.0:
resolution: {integrity: sha512-+qfUHz700DWnRutdUsxRRVZ38G1Qr27OetwaMYTdg8hcPxf46U0S1Zf76dQMWRBmusOt2ZCK5kbIaiLkoGO7WQ==}
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
tar-stream@3.1.8:
resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==}
@@ -12956,6 +13043,9 @@ packages:
tty-browserify@0.0.1:
resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==}
tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
turbo@2.8.20:
resolution: {integrity: sha512-Rb4qk5YT8RUwwdXtkLpkVhNEe/lor6+WV7S5tTlLpxSz6MjV5Qi8jGNn4gS6NAvrYGA/rNrE6YUQM85sCZUDbQ==}
hasBin: true
@@ -17592,6 +17682,41 @@ snapshots:
jest-util: 30.3.0
slash: 3.0.0
'@jest/core@30.3.0':
dependencies:
'@jest/console': 30.3.0
'@jest/pattern': 30.0.1
'@jest/reporters': 30.3.0
'@jest/test-result': 30.3.0
'@jest/transform': 30.3.0
'@jest/types': 30.3.0
'@types/node': 20.19.37
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 4.4.0
exit-x: 0.2.2
graceful-fs: 4.2.11
jest-changed-files: 30.3.0
jest-config: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
jest-haste-map: 30.3.0
jest-message-util: 30.3.0
jest-regex-util: 30.0.1
jest-resolve: 30.3.0
jest-resolve-dependencies: 30.3.0
jest-runner: 30.3.0
jest-runtime: 30.3.0
jest-snapshot: 30.3.0
jest-util: 30.3.0
jest-validate: 30.3.0
jest-watcher: 30.3.0
pretty-format: 30.3.0
slash: 3.0.0
transitivePeerDependencies:
- babel-plugin-macros
- esbuild-register
- supports-color
- ts-node
'@jest/core@30.3.0(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))':
dependencies:
'@jest/console': 30.3.0
@@ -21803,10 +21928,25 @@ snapshots:
bcryptjs@2.4.3: {}
better-sqlite3-multiple-ciphers@12.11.1:
dependencies:
bindings: 1.5.0
prebuild-install: 7.1.3
bignumber.js@9.3.1: {}
binary-extensions@2.3.0: {}
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
bn.js@4.12.3: {}
bn.js@5.2.3: {}
@@ -22051,6 +22191,8 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
chownr@1.1.4: {}
ci-info@3.9.0: {}
ci-info@4.4.0: {}
@@ -22689,6 +22831,10 @@ snapshots:
dependencies:
character-entities: 2.0.2
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
dedent@1.7.2: {}
deep-equal@2.2.3:
@@ -22712,6 +22858,8 @@ snapshots:
which-collection: 1.0.2
which-typed-array: 1.1.20
deep-extend@0.6.0: {}
deep-is@0.1.4: {}
deepmerge@4.3.1: {}
@@ -22915,6 +23063,10 @@ snapshots:
iconv-lite: 0.6.3
whatwg-encoding: 3.1.1
end-of-stream@1.4.5:
dependencies:
once: 1.4.0
entities@2.2.0: {}
entities@4.5.0: {}
@@ -23184,24 +23336,24 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3)))(typescript@5.9.3):
eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@20.19.37))(typescript@5.9.3):
dependencies:
'@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)
eslint: 9.39.4(jiti@1.21.7)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)
jest: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
jest: 30.3.0(@types/node@20.19.37)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3):
eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(jest@30.3.0)(typescript@5.9.3):
dependencies:
'@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)
eslint: 9.39.4(jiti@1.21.7)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)
jest: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
jest: 30.3.0
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -23409,6 +23561,8 @@ snapshots:
exit-x@0.2.2: {}
expand-template@2.0.3: {}
expect@29.7.0:
dependencies:
'@jest/expect-utils': 29.7.0
@@ -23581,6 +23735,8 @@ snapshots:
strtok3: 7.1.1
token-types: 5.0.1
file-uri-to-path@1.0.0: {}
filelist@1.0.6:
dependencies:
minimatch: 5.1.9
@@ -23727,6 +23883,8 @@ snapshots:
fresh@2.0.0: {}
fs-constants@1.0.0: {}
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
@@ -23864,6 +24022,8 @@ snapshots:
dependencies:
resolve-pkg-maps: 1.0.0
github-from-package@0.0.0: {}
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -24270,6 +24430,8 @@ snapshots:
inherits@2.0.4: {}
ini@1.3.8: {}
inline-style-parser@0.2.7: {}
input-otp@1.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -24609,6 +24771,44 @@ snapshots:
- babel-plugin-macros
- supports-color
jest-cli@30.3.0:
dependencies:
'@jest/core': 30.3.0
'@jest/test-result': 30.3.0
'@jest/types': 30.3.0
chalk: 4.1.2
exit-x: 0.2.2
import-local: 3.2.0
jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
jest-util: 30.3.0
jest-validate: 30.3.0
yargs: 17.7.2
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- esbuild-register
- supports-color
- ts-node
jest-cli@30.3.0(@types/node@20.19.37):
dependencies:
'@jest/core': 30.3.0
'@jest/test-result': 30.3.0
'@jest/types': 30.3.0
chalk: 4.1.2
exit-x: 0.2.2
import-local: 3.2.0
jest-config: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
jest-util: 30.3.0
jest-validate: 30.3.0
yargs: 17.7.2
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- esbuild-register
- supports-color
- ts-node
jest-cli@30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3)):
dependencies:
'@jest/core': 30.3.0(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
@@ -25037,6 +25237,32 @@ snapshots:
merge-stream: 2.0.0
supports-color: 8.1.1
jest@30.3.0:
dependencies:
'@jest/core': 30.3.0
'@jest/types': 30.3.0
import-local: 3.2.0
jest-cli: 30.3.0
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- esbuild-register
- supports-color
- ts-node
jest@30.3.0(@types/node@20.19.37):
dependencies:
'@jest/core': 30.3.0
'@jest/types': 30.3.0
import-local: 3.2.0
jest-cli: 30.3.0(@types/node@20.19.37)
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- esbuild-register
- supports-color
- ts-node
jest@30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3)):
dependencies:
'@jest/core': 30.3.0(ts-node@10.9.2(@types/node@20.19.37)(typescript@5.9.3))
@@ -26072,6 +26298,8 @@ snapshots:
mimic-function@5.0.1: {}
mimic-response@3.1.0: {}
min-indent@1.0.1: {}
minimalistic-assert@1.0.1: {}
@@ -26098,6 +26326,8 @@ snapshots:
minipass@7.1.3: {}
mkdirp-classic@0.5.3: {}
mkdirp@1.0.4: {}
mlly@1.8.2:
@@ -26236,6 +26466,8 @@ snapshots:
nanoid@3.3.11: {}
napi-build-utils@2.0.0: {}
napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {}
@@ -26284,6 +26516,10 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
node-abi@3.94.0:
dependencies:
semver: 7.7.4
node-domexception@1.0.0: {}
node-exports-info@1.6.0:
@@ -27176,6 +27412,21 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
prebuild-install@7.1.3:
dependencies:
detect-libc: 2.1.2
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 2.0.0
node-abi: 3.94.0
pump: 3.0.4
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.5
tunnel-agent: 0.6.0
precond@0.2.3: {}
prelude-ls@1.2.1: {}
@@ -27282,6 +27533,11 @@ snapshots:
randombytes: 2.1.0
safe-buffer: 5.2.1
pump@3.0.4:
dependencies:
end-of-stream: 1.4.5
once: 1.4.0
punycode@1.4.1: {}
punycode@2.3.1: {}
@@ -27342,6 +27598,13 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
react-is: 18.3.1
rc@1.2.8:
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
react-avatar-editor@13.0.2(@babel/core@7.29.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0)
@@ -28124,6 +28387,14 @@ snapshots:
signal-exit@4.1.0: {}
simple-concat@1.0.1: {}
simple-get@4.0.1:
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
simple-swizzle@0.2.4:
dependencies:
is-arrayish: 0.3.4
@@ -28352,6 +28623,8 @@ snapshots:
dependencies:
min-indent: 1.0.1
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {}
strnum@1.1.2: {}
@@ -28506,8 +28779,23 @@ snapshots:
- tsx
- yaml
tar-fs@2.1.5:
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.4
tar-stream: 2.2.0
tar-mini@0.2.0: {}
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
end-of-stream: 1.4.5
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
tar-stream@3.1.8:
dependencies:
b4a: 1.8.0
@@ -28709,6 +28997,10 @@ snapshots:
tty-browserify@0.0.1: {}
tunnel-agent@0.6.0:
dependencies:
safe-buffer: 5.2.1
turbo@2.8.20:
optionalDependencies:
'@turbo/darwin-64': 2.8.20