Move more .d.ts files to .ts (#5204)

* Rename .d.ts files to .ts

* Fix type and lint errors

* Add release notes

* CodeRabbit feedback
This commit is contained in:
Julian Dominguez-Schatz
2025-06-21 00:16:55 -04:00
committed by GitHub
parent 6c61cf6a8d
commit eadd88ce31
26 changed files with 433 additions and 378 deletions

View File

@@ -46,6 +46,7 @@
"@swc/core": "^1.11.24",
"@types/adm-zip": "^0.5.7",
"@types/better-sqlite3": "^7.6.13",
"@types/emscripten": "^1.40.1",
"@types/jlongster__sql.js": "npm:@types/sql.js@latest",
"@types/node": "^22.15.18",
"@types/pegjs": "^0.10.6",

View File

@@ -1,4 +1,4 @@
import type * as T from '../index.d';
import type * as T from '../index-types';
let events = [];

View File

@@ -1,20 +1,20 @@
import type { Handlers } from '../../../types/handlers';
import type { ServerEvents } from '../../../types/server-events';
export function init(
export declare function init(
channel: Window | number, // in electron the port number, in web the worker
handlers: Handlers,
): void;
export type Init = typeof init;
export function send<K extends keyof ServerEvents>(
export declare function send<K extends keyof ServerEvents>(
type: K,
args?: ServerEvents[K],
): void;
export type Send = typeof send;
export function getNumClients(): number;
export declare function getNumClients(): number;
export type GetNumClients = typeof getNumClients;
export function resetEvents(): void;
export declare function resetEvents(): void;
export type ResetEvents = typeof resetEvents;

View File

@@ -1,4 +1,4 @@
import type * as T from './index.d';
import type * as T from './index-types';
export const init: T.Init = function () {};

View File

@@ -3,7 +3,7 @@ import { APIError } from '../../../server/errors';
import { runHandler, isMutating } from '../../../server/mutators';
import { captureException } from '../../exceptions';
import type * as T from './index.d';
import type * as T from './index-types';
function coerceError(error) {
if (error.type && error.type === 'APIError') {

View File

@@ -3,7 +3,7 @@ import { APIError } from '../../../server/errors';
import { runHandler, isMutating } from '../../../server/mutators';
import { captureException } from '../../exceptions';
import type * as T from './index.d';
import type * as T from './index-types';
function getGlobalObject() {
const obj =

View File

@@ -1,71 +0,0 @@
export { join } from './path-join';
export function init(): void;
export type Init = typeof init;
export function getDataDir(): string;
export type GetDataDir = typeof getDataDir;
export function _setDocumentDir(dir: string): string;
export type _setDocumentDir = typeof _setDocumentDir;
export function getDocumentDir(): string;
export type GetDocumentDir = typeof getDocumentDir;
export function getBudgetDir(id: string): string;
export type GetBudgetDir = typeof getBudgetDir;
export const bundledDatabasePath: string;
export type BundledDatabasePath = typeof bundledDatabasePath;
export const migrationsPath: string;
export type MigrationsPath = typeof migrationsPath;
export const demoBudgetPath: string;
export type DemoBudgetPath = typeof demoBudgetPath;
export function pathToId(filepath: string): string;
export type PathToId = typeof pathToId;
export function basename(filepath: string): string;
export type Basename = typeof basename;
export function listDir(filepath: string): Promise<string[]>;
export type ListDir = typeof listDir;
export function exists(filepath: string): Promise<boolean>;
export type Exists = typeof exists;
export function mkdir(filepath: string): Promise<undefined>;
export type Mkdir = typeof mkdir;
export function size(filepath: string): Promise<undefined>;
export type Size = typeof size;
export function copyFile(frompath: string, topath: string): Promise<undefined>;
export type CopyFile = typeof copyFile;
export function readFile(
filepath: string,
encoding: 'binary' | null,
): Promise<Buffer>;
export function readFile(filepath: string, encoding?: 'utf8'): Promise<string>;
export type ReadFile = typeof readFile;
export function writeFile(
filepath: string,
contents: string | ArrayBuffer | NodeJS.ArrayBufferView,
): Promise<undefined>;
export type WriteFile = typeof writeFile;
export function removeFile(filepath: string): Promise<undefined>;
export type RemoveFile = typeof removeFile;
export function removeDir(dirpath: string): Promise<undefined>;
export type RemoveDir = typeof removeDir;
export function removeDirRecursively(dirpath: string): Promise<undefined>;
export type RemoveDirRecursively = typeof removeDirRecursively;
export function getModifiedTime(filepath: string): Promise<string>;
export type GetModifiedTime = typeof getModifiedTime;

View File

@@ -82,8 +82,8 @@ export const size = filepath =>
});
});
export const copyFile = (frompath, topath) => {
return new Promise<void>((resolve, reject) => {
export const copyFile: T.CopyFile = (frompath, topath) => {
return new Promise<boolean>((resolve, reject) => {
const readStream = fs.createReadStream(frompath);
const writeStream = fs.createWriteStream(topath);
@@ -91,7 +91,7 @@ export const copyFile = (frompath, topath) => {
writeStream.on('error', reject);
writeStream.on('open', () => readStream.pipe(writeStream));
writeStream.once('close', () => resolve());
writeStream.once('close', () => resolve(true));
});
};

View File

@@ -0,0 +1,79 @@
export { join } from './path-join';
export declare function init(): void;
export type Init = typeof init;
export declare function getDataDir(): string;
export type GetDataDir = typeof getDataDir;
export declare function _setDocumentDir(dir: string): string;
export type _SetDocumentDir = typeof _setDocumentDir;
export declare function getDocumentDir(): string;
export type GetDocumentDir = typeof getDocumentDir;
export declare function getBudgetDir(id: string): string;
export type GetBudgetDir = typeof getBudgetDir;
export declare const bundledDatabasePath: string;
export type BundledDatabasePath = typeof bundledDatabasePath;
export declare const migrationsPath: string;
export type MigrationsPath = typeof migrationsPath;
export declare const demoBudgetPath: string;
export type DemoBudgetPath = typeof demoBudgetPath;
export declare function pathToId(filepath: string): string;
export type PathToId = typeof pathToId;
export declare function basename(filepath: string): string;
export type Basename = typeof basename;
export declare function listDir(filepath: string): Promise<string[]>;
export type ListDir = typeof listDir;
export declare function exists(filepath: string): Promise<boolean>;
export type Exists = typeof exists;
export declare function mkdir(filepath: string): Promise<undefined>;
export type Mkdir = typeof mkdir;
export declare function size(filepath: string): Promise<number>;
export type Size = typeof size;
export declare function copyFile(
frompath: string,
topath: string,
): Promise<boolean>;
export type CopyFile = typeof copyFile;
export declare function readFile(
filepath: string,
encoding: 'binary' | null,
): Promise<Buffer>;
export declare function readFile(
filepath: string,
encoding?: 'utf8',
): Promise<string>;
export type ReadFile = typeof readFile;
export declare function writeFile(
filepath: string,
contents: string | ArrayBuffer | NodeJS.ArrayBufferView,
): Promise<undefined>;
export type WriteFile = typeof writeFile;
export declare function removeFile(filepath: string): Promise<undefined>;
export type RemoveFile = typeof removeFile;
export declare function removeDir(dirpath: string): Promise<undefined>;
export type RemoveDir = typeof removeDir;
export declare function removeDirRecursively(
dirpath: string,
): Promise<undefined>;
export type RemoveDirRecursively = typeof removeDirRecursively;
export declare function getModifiedTime(filepath: string): Promise<string>;
export type GetModifiedTime = typeof getModifiedTime;

View File

@@ -98,7 +98,7 @@ describe('web filesystem', () => {
expect(await readFile('/documents/deep/nested/file/ok.txt')).toBe('deeper');
const FS = sqlite._getModule().FS;
const { node } = FS.lookupPath('/documents/deep/nested/db.sqlite');
const { node } = FS.lookupPath('/documents/deep/nested/db.sqlite', {});
expect(node.link).toBe(
'/blocked/' + pathToId('/documents/deep/nested/db.sqlite'),
);

View File

@@ -4,11 +4,11 @@ import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend';
import * as connection from '../connection';
import * as idb from '../indexeddb';
import { _getModule } from '../sqlite';
import { _getModule, SqlJsModule } from '../sqlite';
import { join } from './path-join';
let FS = null;
let FS: SqlJsModule['FS'] = null;
let BFS = null;
const NO_PERSIST = false;
@@ -67,7 +67,10 @@ function _createFile(filepath: string) {
return filepath;
}
async function _readFile(filepath: string, opts?: { encoding?: string }) {
async function _readFile(
filepath: string,
opts?: { encoding: 'utf8' } | { encoding: 'binary' },
): Promise<string | Uint8Array> {
// We persist stuff in /documents, but don't need to handle sqlite
// file specifically because those are symlinked to a separate
// filesystem and will be handled in the BlockedFS
@@ -97,7 +100,13 @@ async function _readFile(filepath: string, opts?: { encoding?: string }) {
return item.contents;
} else {
return FS.readFile(resolveLink(filepath), opts);
if (opts?.encoding === 'utf8') {
return FS.readFile(resolveLink(filepath), { encoding: 'utf8' });
} else if (opts?.encoding === 'binary') {
return FS.readFile(resolveLink(filepath), { encoding: 'binary' });
} else {
return FS.readFile(resolveLink(filepath));
}
}
}
@@ -341,7 +350,10 @@ export const copyFile = async function (
return result;
};
export const readFile = async function (filepath: string, encoding = 'utf8') {
export const readFile = async function (
filepath: string,
encoding: 'binary' | 'utf8' = 'utf8',
) {
return _readFile(filepath, { encoding });
};

View File

@@ -1,2 +0,0 @@
export function join(...args: string[]): string;
export type Join = typeof join;

View File

@@ -0,0 +1,2 @@
export declare function join(...args: string[]): string;
export type Join = typeof join;

View File

@@ -1,8 +1,10 @@
// @ts-strict-ignore
import { join } from './path-join';
import type * as T from '.';
let documentDir;
export const _setDocumentDir = dir => (documentDir = dir);
export const _setDocumentDir: T._SetDocumentDir = dir => (documentDir = dir);
export const getDocumentDir = () => {
if (!documentDir) {

View File

@@ -1,35 +0,0 @@
import { type Database } from '@jlongster/sql.js';
export async function init(): Promise<void>;
export function _getModule(): SqlJsStatic;
export function prepare(db: Database, sql: string): string;
export function runQuery(
db: Database,
sql: string,
params?: (string | number)[],
fetchAll?: false,
): { changes: unknown };
export function runQuery<T>(
db: Database,
sql: string,
params: (string | number)[],
fetchAll: true,
): T[];
export function execQuery(db: Database, sql): void;
export function transaction(db: Database, fn: () => void): void;
export async function asyncTransaction(
db: Database,
fn: () => Promise<void>,
): Promise<void>;
export async function openDatabase(pathOrBuffer?: string | Buffer): Database;
export function closeDatabase(db: Database): void;
export async function exportDatabase(db: Database): Promise<Uint8Array>;

View File

@@ -0,0 +1,58 @@
import { type Database, type SqlJsStatic } from '@jlongster/sql.js';
/// <reference types="emscripten" />
// Types exported from sql.js (and Emscripten) are incomplete, so we need to redefine them here
type FSStream = (typeof FS)['FSStream'] & {
node: (typeof FS)['FSNode'] & {
contents: {
readIfFallback: () => Promise<unknown>;
};
};
};
type FS = Omit<typeof FS, 'lookupPath' | 'open' | 'close'> & {
lookupPath: (
path: string,
opts?: { follow?: boolean },
) => { node: (typeof FS)['FSNode'] & { link?: string } };
open: (path: string, flags: string, mode?: number) => FSStream;
close: (stream: FSStream) => void;
};
export type SqlJsModule = SqlJsStatic & {
FS: FS;
reset_filesystem: () => void;
register_for_idb: (idb: IDBDatabase) => void;
};
export declare function init(): Promise<void>;
export declare function _getModule(): SqlJsModule;
export declare function prepare(db: Database, sql: string): string;
export declare function runQuery(
db: Database,
sql: string,
params?: (string | number)[],
fetchAll?: false,
): { changes: unknown };
export declare function runQuery<T>(
db: Database,
sql: string,
params: (string | number)[],
fetchAll: true,
): T[];
export declare function execQuery(db: Database, sql: string): void;
export declare function transaction(db: Database, fn: () => void): void;
export declare function asyncTransaction(
db: Database,
fn: () => Promise<void>,
): Promise<void>;
export declare function openDatabase(pathOrBuffer?: string | Buffer): Database;
export declare function closeDatabase(db: Database): void;
export declare function exportDatabase(db: Database): Promise<Uint8Array>;

View File

@@ -1,10 +1,12 @@
// @ts-strict-ignore
import initSqlJS, { type SqlJsStatic, type Database } from '@jlongster/sql.js';
import initSqlJS, { type Database } from '@jlongster/sql.js';
import { normalise } from './normalise';
import { unicodeLike } from './unicodeLike';
let SQL: SqlJsStatic | null = null;
import type { SqlJsModule } from '.';
let SQL: SqlJsModule | null = null;
export async function init({
baseURL = process.env.PUBLIC_URL,
@@ -16,7 +18,7 @@ export async function init({
locateFile: file => baseURL + file,
}).then(
sql => {
SQL = sql;
SQL = sql as SqlJsModule;
resolve(undefined);
},
err => {
@@ -173,15 +175,12 @@ export async function openDatabase(pathOrBuffer?: string | Buffer) {
const path = pathOrBuffer;
if (path !== ':memory:') {
if (typeof SharedArrayBuffer === 'undefined') {
// @ts-expect-error FS missing in sql.js types
const stream = SQL.FS.open(SQL.FS.readlink(path), 'a+');
await stream.node.contents.readIfFallback();
// @ts-expect-error FS missing in sql.js types
SQL.FS.close(stream);
}
db = new SQL.Database(
// @ts-expect-error FS missing in sql.js types
path.includes('/blocked') ? path : SQL.FS.readlink(path),
// @ts-expect-error 2nd argument missed in sql.js types
{ filename: true },

View File

@@ -1,165 +0,0 @@
export namespace YNAB4 {
export interface YFull {
masterCategories: MasterCategory[];
payees: Payee[];
monthlyBudgets: MonthlyBudget[];
fileMetaData: FileMetaData;
transactions: Transaction[];
scheduledTransactions: ScheduledTransaction[];
// accountMappings: [];
budgetMetaData: BudgetMetaData;
accounts: Account[];
}
export interface MasterCategory {
entityType: string;
expanded: boolean;
note?: string;
name: string;
type: string;
deleteable: boolean;
subCategories?: SubCategory[];
entityVersion: string;
entityId: string;
sortableIndex: number;
// speculative
isTombstone?: boolean;
}
export interface SubCategory {
entityType: string;
name: string;
note?: string;
type: string;
// cachedBalance: null;
masterCategoryId: string;
entityVersion: string;
entityId: string;
sortableIndex: number;
// speculative
isTombstone?: boolean;
}
export interface Payee {
entityType: string;
autoFillCategoryId?: string;
autoFillAmount: number;
name: string;
renameConditions?: RenameCondition[];
autoFillMemo?: string;
targetAccountId?: string;
// locations: null;
enabled: boolean;
entityVersion: string;
entityId: string;
// speculative
isTombstone?: boolean;
}
export interface RenameCondition {
entityType: string;
parentPayeeId: string;
operator: string;
operand: string;
entityVersion: string;
entityId: string;
}
export interface MonthlyBudget {
entityType: string;
monthlySubCategoryBudgets: MonthlySubCategoryBudget[];
month: string;
entityVersion: string;
entityId: string;
}
export interface MonthlySubCategoryBudget {
entityType: string;
categoryId: string;
budgeted: number;
// overspendingHandling: null;
entityVersion: string;
entityId: string;
parentMonthlyBudgetId: string;
// speculative
isTombstone?: boolean;
}
export interface FileMetaData {
entityType: string;
budgetDataVersion: string;
currentKnowledge: string;
}
export interface Transaction {
entityType: string;
entityId: string;
categoryId: string;
payeeId: string;
amount: number;
date: string;
accountId: string;
entityVersion: string;
cleared: string;
accepted: boolean;
isTombstone?: boolean;
memo?: string;
dateEnteredFromSchedule?: string;
// speculative:
subTransactions?: SubTransaction[];
transferTransactionId?: string;
targetAccountId?: string;
}
// speculative, not in the test data
export type SubTransaction = Exclude<Transaction, 'subTransactions'>;
export interface ScheduledTransaction {
entityType: string;
entityId: string;
categoryId: string;
payeeId: string;
amount: number;
date: string;
isTombstone?: boolean;
accountId: string;
entityVersion: string;
memo: string;
twiceAMonthStartDay: number;
cleared: string;
frequency: string;
accepted: boolean;
}
export interface BudgetMetaData {
entityType: string;
strictBudget: string;
currencyISOSymbol?: string;
entityVersion: string;
currencyLocale: string;
budgetType: string;
dateLocale: string;
entityId: string;
}
export interface Account {
entityType: string;
// lastReconciledDate: null;
lastEnteredCheckNumber: number;
lastReconciledBalance: number;
accountType: string;
hidden: boolean;
sortableIndex: number;
onBudget: boolean;
accountName: string;
entityVersion: string;
entityId: string;
// speculative
isTombstone?: boolean;
}
}

View File

@@ -0,0 +1,163 @@
export interface YFull {
masterCategories: MasterCategory[];
payees: Payee[];
monthlyBudgets: MonthlyBudget[];
fileMetaData: FileMetaData;
transactions: Transaction[];
scheduledTransactions: ScheduledTransaction[];
// accountMappings: [];
budgetMetaData: BudgetMetaData;
accounts: Account[];
}
export interface MasterCategory {
entityType: string;
expanded: boolean;
note?: string;
name: string;
type: string;
deleteable: boolean;
subCategories?: SubCategory[];
entityVersion: string;
entityId: string;
sortableIndex: number;
// speculative
isTombstone?: boolean;
}
export interface SubCategory {
entityType: string;
name: string;
note?: string;
type: string;
// cachedBalance: null;
masterCategoryId: string;
entityVersion: string;
entityId: string;
sortableIndex: number;
// speculative
isTombstone?: boolean;
}
export interface Payee {
entityType: string;
autoFillCategoryId?: string;
autoFillAmount: number;
name: string;
renameConditions?: RenameCondition[];
autoFillMemo?: string;
targetAccountId?: string;
// locations: null;
enabled: boolean;
entityVersion: string;
entityId: string;
// speculative
isTombstone?: boolean;
}
export interface RenameCondition {
entityType: string;
parentPayeeId: string;
operator: string;
operand: string;
entityVersion: string;
entityId: string;
}
export interface MonthlyBudget {
entityType: string;
monthlySubCategoryBudgets: MonthlySubCategoryBudget[];
month: string;
entityVersion: string;
entityId: string;
}
export interface MonthlySubCategoryBudget {
entityType: string;
categoryId: string;
budgeted: number;
overspendingHandling?: string | undefined | null;
entityVersion: string;
entityId: string;
parentMonthlyBudgetId: string;
// speculative
isTombstone?: boolean;
}
export interface FileMetaData {
entityType: string;
budgetDataVersion: string;
currentKnowledge: string;
}
export interface Transaction {
entityType: string;
entityId: string;
categoryId: string;
payeeId: string;
amount: number;
date: string;
accountId: string;
entityVersion: string;
cleared: string;
accepted: boolean;
isTombstone?: boolean;
memo?: string;
dateEnteredFromSchedule?: string;
// speculative:
subTransactions?: SubTransaction[];
transferTransactionId?: string;
targetAccountId?: string;
}
// speculative, not in the test data
export type SubTransaction = Omit<Transaction, 'subTransactions'>;
export interface ScheduledTransaction {
entityType: string;
entityId: string;
categoryId: string;
payeeId: string;
amount: number;
date: string;
isTombstone?: boolean;
accountId: string;
entityVersion: string;
memo: string;
twiceAMonthStartDay: number;
cleared: string;
frequency: string;
accepted: boolean;
}
export interface BudgetMetaData {
entityType: string;
strictBudget: string;
currencyISOSymbol?: string;
entityVersion: string;
currencyLocale: string;
budgetType: string;
dateLocale: string;
entityId: string;
}
export interface Account {
entityType: string;
// lastReconciledDate: null;
lastEnteredCheckNumber: number;
lastReconciledBalance: number;
accountType: string;
hidden: boolean;
sortableIndex: number;
onBudget: boolean;
accountName: string;
entityVersion: string;
entityId: string;
// speculative
isTombstone?: boolean;
}

View File

@@ -13,7 +13,7 @@ import { v4 as uuidv4 } from 'uuid';
import * as monthUtils from '../../shared/months';
import { groupBy, sortByKey } from '../../shared/util';
import { YNAB4 } from './ynab4-types';
import * as YNAB4 from './ynab4-types';
// Importer

View File

@@ -1,79 +0,0 @@
export namespace YNAB5 {
export interface Budget {
name?: string;
budget_name?: string;
accounts: Account[];
payees: Payee[];
category_groups: CategoryGroup[];
categories: Category[];
transactions: Transaction[];
subtransactions: Subtransaction[];
months: Month[];
}
interface Account {
id: string;
name: string;
on_budget: boolean;
deleted: boolean;
closed: boolean;
}
interface Payee {
id: string;
name: string;
deleted: boolean;
transfer_acct?: string;
}
interface CategoryGroup {
id: string;
name: string;
deleted: boolean;
hidden: boolean;
}
interface Category {
id: string;
category_group_id: string;
name: string;
deleted: boolean;
hidden: boolean;
}
interface Transaction {
id: string;
account_id: string;
date: string;
payee_id: string;
import_id: string;
category_id: string;
transfer_account_id: string;
transfer_transaction_id: string;
memo: string;
cleared: string;
amount: number;
deleted: boolean;
}
interface Subtransaction {
id: string;
transaction_id: string;
category_id: string;
memo: string;
amount: number;
transfer_account_id: string;
payee_id: string;
}
interface Month {
month: string;
categories: MonthCategory[];
}
interface MonthCategory {
category_group_id: string;
id: string;
budgeted: number;
}
}

View File

@@ -0,0 +1,77 @@
export interface Budget {
name?: string;
budget_name?: string;
accounts: Account[];
payees: Payee[];
category_groups: CategoryGroup[];
categories: Category[];
transactions: Transaction[];
subtransactions: Subtransaction[];
months: Month[];
}
export interface Account {
id: string;
name: string;
on_budget: boolean;
deleted: boolean;
closed: boolean;
}
export interface Payee {
id: string;
name: string;
deleted: boolean;
transfer_acct?: string;
}
export interface CategoryGroup {
id: string;
name: string;
deleted: boolean;
hidden: boolean;
}
export interface Category {
id: string;
category_group_id: string;
name: string;
deleted: boolean;
hidden: boolean;
}
export interface Transaction {
id: string;
account_id: string;
date: string;
payee_id: string;
import_id: string;
category_id: string;
transfer_account_id: string;
transfer_transaction_id: string;
memo: string;
cleared: string;
amount: number;
deleted: boolean;
}
export interface Subtransaction {
id: string;
transaction_id: string;
category_id: string;
memo: string;
amount: number;
transfer_account_id: string;
payee_id: string;
}
export interface Month {
month: string;
categories: MonthCategory[];
}
export interface MonthCategory {
category_group_id: string;
id: string;
budgeted: number;
}

View File

@@ -9,7 +9,7 @@ import { v4 as uuidv4 } from 'uuid';
import * as monthUtils from '../../shared/months';
import { sortByKey, groupBy } from '../../shared/util';
import { YNAB5 } from './ynab5-types';
import * as YNAB5 from './ynab5-types';
function amountFromYnab(amount: number) {
// ynabs multiplies amount by 1000 and actual by 100

View File

@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [jfdoming]
---
Move more .d.ts files to .ts

View File

@@ -6437,6 +6437,13 @@ __metadata:
languageName: node
linkType: hard
"@types/emscripten@npm:^1.40.1":
version: 1.40.1
resolution: "@types/emscripten@npm:1.40.1"
checksum: 10/d1aa8b91416c0d8ea7d2f3b99c8c40327350dff632ad98cb67f9df9afa13efd4d755c273b49a37797390a94180c7cc98397bbbe1d8def4ea1d5d3bff9c816ac9
languageName: node
linkType: hard
"@types/eslint-scope@npm:^3.7.7":
version: 3.7.7
resolution: "@types/eslint-scope@npm:3.7.7"
@@ -14120,6 +14127,7 @@ __metadata:
"@swc/core": "npm:^1.11.24"
"@types/adm-zip": "npm:^0.5.7"
"@types/better-sqlite3": "npm:^7.6.13"
"@types/emscripten": "npm:^1.40.1"
"@types/jlongster__sql.js": "npm:@types/sql.js@latest"
"@types/node": "npm:^22.15.18"
"@types/pegjs": "npm:^0.10.6"