mirror of
https://github.com/lanedirt/AliasVault.git
synced 2025-12-05 19:07:26 -06:00
Add vault-sql shared project scaffolding
This commit is contained in:
committed by
Leendert de Borst
parent
8b2702cbe3
commit
d149e5aeec
@@ -7,6 +7,7 @@ set -u # Treat unset variables as errors
|
||||
chmod +x ./identity-generator/build.sh
|
||||
chmod +x ./password-generator/build.sh
|
||||
chmod +x ./models/build.sh
|
||||
chmod +x ./vault-sql/build.sh
|
||||
|
||||
# Run all build scripts
|
||||
echo "🚀 Starting build process for all modules..."
|
||||
@@ -19,4 +20,7 @@ cd ../password-generator
|
||||
cd ../models
|
||||
./build.sh
|
||||
|
||||
cd ../vault-sql
|
||||
./build.sh
|
||||
|
||||
echo "✅ All builds completed successfully."
|
||||
|
||||
46
shared/vault-sql/build.sh
Executable file
46
shared/vault-sql/build.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e # Stop on error
|
||||
set -u # Treat unset variables as errors
|
||||
|
||||
# Define output targets for vault-sql
|
||||
TARGETS=(
|
||||
"../../apps/browser-extension/src/utils/dist/shared/vault-sql"
|
||||
"../../apps/mobile-app/utils/dist/shared/vault-sql"
|
||||
"../../apps/server/AliasVault.Client/wwwroot/js/dist/shared/vault-sql"
|
||||
)
|
||||
|
||||
# Build and distribute vault-sql
|
||||
package_name="vault-sql"
|
||||
package_path="."
|
||||
|
||||
echo "📦 Building $package_name..."
|
||||
npm install && npm run lint && npm run build
|
||||
|
||||
dist_path="dist"
|
||||
|
||||
for target in "${TARGETS[@]}"; do
|
||||
echo "📂 Copying $package_name → $target"
|
||||
mkdir -p "$target"
|
||||
|
||||
# Remove any existing files in the target directory
|
||||
rm -rf "$target/*"
|
||||
|
||||
# Copy all build outputs
|
||||
cp -R "$dist_path"/* "$target/"
|
||||
|
||||
# Write README
|
||||
cat > "$target/README.md" <<EOF
|
||||
# ⚠️ Auto-Generated Files
|
||||
|
||||
This folder contains the output of the shared \`$package_name\` module from the \`/shared\` directory in the AliasVault project.
|
||||
|
||||
**Do not edit any of these files manually.**
|
||||
|
||||
To make changes:
|
||||
1. Update the source files in the \`/shared/vault-sql/src\` directory
|
||||
2. Run the \`build.sh\` script in the module directory to regenerate the outputs and copy them here.
|
||||
EOF
|
||||
done
|
||||
|
||||
echo "✅ Vault-SQL build and copy completed."
|
||||
56
shared/vault-sql/eslint.config.mjs
Normal file
56
shared/vault-sql/eslint.config.mjs
Normal file
@@ -0,0 +1,56 @@
|
||||
import js from "@eslint/js";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
import tsPlugin from "@typescript-eslint/eslint-plugin";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
"dist/**",
|
||||
"node_modules/**",
|
||||
]
|
||||
},
|
||||
js.configs.recommended,
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: "./tsconfig.json",
|
||||
tsconfigRootDir: ".",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
"@typescript-eslint": tsPlugin,
|
||||
},
|
||||
rules: {
|
||||
...tsPlugin.configs.recommended.rules,
|
||||
"curly": ["error", "all"],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"ignoreRestSiblings": true,
|
||||
"varsIgnorePattern": "^_",
|
||||
"argsIgnorePattern": "^_"
|
||||
}],
|
||||
"indent": ["error", 2],
|
||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
|
||||
"spaced-comment": ["error", "always"],
|
||||
"multiline-comment-style": ["error", "starred-block"],
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
"selector": "interface",
|
||||
"format": ["PascalCase"],
|
||||
"prefix": ["I"]
|
||||
},
|
||||
{
|
||||
"selector": "typeAlias",
|
||||
"format": ["PascalCase"]
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
];
|
||||
4603
shared/vault-sql/package-lock.json
generated
Normal file
4603
shared/vault-sql/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
shared/vault-sql/package.json
Normal file
28
shared/vault-sql/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@aliasvault/vault-sql",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "dist/index.mjs",
|
||||
"types": "dist/index.d.mts",
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"clean": "rm -rf dist",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "vitest",
|
||||
"test:coverage": "vitest --coverage"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.21.0",
|
||||
"@typescript-eslint/parser": "^8.21.0",
|
||||
"eslint": "^9.19.0",
|
||||
"tsup": "^8.4.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^2.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.0"
|
||||
}
|
||||
}
|
||||
279
shared/vault-sql/src/VaultManager.ts
Normal file
279
shared/vault-sql/src/VaultManager.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
import { COMPLETE_SCHEMA_SQL, MIGRATION_SCRIPTS } from './sql/SqlConstants.js';
|
||||
import { VAULT_VERSIONS, CURRENT_VAULT_VERSION, type IVaultVersion } from './types/VaultVersion.js';
|
||||
|
||||
/**
|
||||
* Database execution interface for different platforms
|
||||
*/
|
||||
export interface IDbExecutor {
|
||||
/**
|
||||
* Execute SQL command
|
||||
*/
|
||||
executeSql(sql: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Execute SQL command and return results
|
||||
*/
|
||||
executeSqlWithResults<T = unknown>(sql: string): Promise<T[]>;
|
||||
|
||||
/**
|
||||
* Execute multiple SQL commands in a transaction
|
||||
*/
|
||||
executeTransaction(sqlCommands: string[]): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vault creation and migration result
|
||||
*/
|
||||
export interface IVaultOperationResult {
|
||||
success: boolean;
|
||||
version: string;
|
||||
migrationNumber: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vault version info from database
|
||||
*/
|
||||
export interface ICurrentVaultInfo {
|
||||
version: string;
|
||||
migrationNumber: number;
|
||||
needsUpgrade: boolean;
|
||||
availableUpgrades: IVaultVersion[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Vault SQL manager for creating and migrating vaults across platforms
|
||||
*/
|
||||
export class VaultManager {
|
||||
constructor(private dbExecutor: IDbExecutor) {}
|
||||
|
||||
/**
|
||||
* Create a new vault with the latest schema
|
||||
*/
|
||||
async createNewVault(): Promise<IVaultOperationResult> {
|
||||
try {
|
||||
// Enable foreign key constraints and create complete schema
|
||||
const sqlCommands = [
|
||||
'PRAGMA foreign_keys = ON;',
|
||||
COMPLETE_SCHEMA_SQL,
|
||||
// Insert version tracking
|
||||
`INSERT INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_version', '${CURRENT_VAULT_VERSION.version}', datetime('now'), datetime('now'), 0);`,
|
||||
`INSERT INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_migration_number', '${CURRENT_VAULT_VERSION.migrationNumber}', datetime('now'), datetime('now'), 0);`
|
||||
];
|
||||
|
||||
await this.dbExecutor.executeTransaction(sqlCommands);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
version: CURRENT_VAULT_VERSION.version,
|
||||
migrationNumber: CURRENT_VAULT_VERSION.migrationNumber
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
version: '0.0.0',
|
||||
migrationNumber: 0,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current vault version and upgrade information
|
||||
*/
|
||||
async getCurrentVaultInfo(): Promise<ICurrentVaultInfo> {
|
||||
try {
|
||||
// Check if Settings table exists
|
||||
const tables = await this.dbExecutor.executeSqlWithResults<{name: string}>(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='Settings';"
|
||||
);
|
||||
|
||||
if (tables.length === 0) {
|
||||
// Very old vault or no vault - needs full migration
|
||||
return {
|
||||
version: '0.0.0',
|
||||
migrationNumber: 0,
|
||||
needsUpgrade: true,
|
||||
availableUpgrades: VAULT_VERSIONS
|
||||
};
|
||||
}
|
||||
|
||||
// Try to get version from Settings table
|
||||
const versionResult = await this.dbExecutor.executeSqlWithResults<{Value: string}>(
|
||||
"SELECT Value FROM Settings WHERE Key = 'vault_version' AND IsDeleted = 0 LIMIT 1;"
|
||||
);
|
||||
|
||||
const migrationResult = await this.dbExecutor.executeSqlWithResults<{Value: string}>(
|
||||
"SELECT Value FROM Settings WHERE Key = 'vault_migration_number' AND IsDeleted = 0 LIMIT 1;"
|
||||
);
|
||||
|
||||
let currentVersion = '1.0.0';
|
||||
let currentMigrationNumber = 1;
|
||||
|
||||
if (versionResult.length > 0) {
|
||||
currentVersion = versionResult[0].Value;
|
||||
}
|
||||
|
||||
if (migrationResult.length > 0) {
|
||||
currentMigrationNumber = parseInt(migrationResult[0].Value, 10);
|
||||
}
|
||||
|
||||
const needsUpgrade = currentMigrationNumber < CURRENT_VAULT_VERSION.migrationNumber;
|
||||
const availableUpgrades = VAULT_VERSIONS.filter(v => v.migrationNumber > currentMigrationNumber);
|
||||
|
||||
return {
|
||||
version: currentVersion,
|
||||
migrationNumber: currentMigrationNumber,
|
||||
needsUpgrade,
|
||||
availableUpgrades
|
||||
};
|
||||
} catch {
|
||||
// If we can't determine version, assume it needs upgrade
|
||||
return {
|
||||
version: '0.0.0',
|
||||
migrationNumber: 0,
|
||||
needsUpgrade: true,
|
||||
availableUpgrades: VAULT_VERSIONS
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade vault to latest version
|
||||
*/
|
||||
async upgradeVault(): Promise<IVaultOperationResult> {
|
||||
try {
|
||||
const currentInfo = await this.getCurrentVaultInfo();
|
||||
|
||||
if (!currentInfo.needsUpgrade) {
|
||||
return {
|
||||
success: true,
|
||||
version: currentInfo.version,
|
||||
migrationNumber: currentInfo.migrationNumber
|
||||
};
|
||||
}
|
||||
|
||||
// Apply migrations in order
|
||||
const sqlCommands: string[] = ['PRAGMA foreign_keys = ON;'];
|
||||
|
||||
for (const upgrade of currentInfo.availableUpgrades) {
|
||||
const migrationSql = MIGRATION_SCRIPTS[upgrade.migrationNumber];
|
||||
if (migrationSql) {
|
||||
sqlCommands.push(migrationSql);
|
||||
}
|
||||
}
|
||||
|
||||
// Update version tracking
|
||||
sqlCommands.push(
|
||||
`INSERT OR REPLACE INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_version', '${CURRENT_VAULT_VERSION.version}', datetime('now'), datetime('now'), 0);`
|
||||
);
|
||||
sqlCommands.push(
|
||||
`INSERT OR REPLACE INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_migration_number', '${CURRENT_VAULT_VERSION.migrationNumber}', datetime('now'), datetime('now'), 0);`
|
||||
);
|
||||
|
||||
await this.dbExecutor.executeTransaction(sqlCommands);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
version: CURRENT_VAULT_VERSION.version,
|
||||
migrationNumber: CURRENT_VAULT_VERSION.migrationNumber
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
version: '0.0.0',
|
||||
migrationNumber: 0,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade vault to a specific version
|
||||
*/
|
||||
async upgradeVaultToVersion(targetVersion: string): Promise<IVaultOperationResult> {
|
||||
try {
|
||||
const currentInfo = await this.getCurrentVaultInfo();
|
||||
const targetVersionInfo = VAULT_VERSIONS.find(v => v.version === targetVersion);
|
||||
|
||||
if (!targetVersionInfo) {
|
||||
return {
|
||||
success: false,
|
||||
version: currentInfo.version,
|
||||
migrationNumber: currentInfo.migrationNumber,
|
||||
error: `Target version ${targetVersion} not found`
|
||||
};
|
||||
}
|
||||
|
||||
if (currentInfo.migrationNumber >= targetVersionInfo.migrationNumber) {
|
||||
return {
|
||||
success: true,
|
||||
version: currentInfo.version,
|
||||
migrationNumber: currentInfo.migrationNumber
|
||||
};
|
||||
}
|
||||
|
||||
// Apply migrations up to target version
|
||||
const sqlCommands: string[] = ['PRAGMA foreign_keys = ON;'];
|
||||
|
||||
const migrationsToApply = VAULT_VERSIONS.filter(
|
||||
v => v.migrationNumber > currentInfo.migrationNumber &&
|
||||
v.migrationNumber <= targetVersionInfo.migrationNumber
|
||||
);
|
||||
|
||||
for (const migration of migrationsToApply) {
|
||||
const migrationSql = MIGRATION_SCRIPTS[migration.migrationNumber];
|
||||
if (migrationSql) {
|
||||
sqlCommands.push(migrationSql);
|
||||
}
|
||||
}
|
||||
|
||||
// Update version tracking
|
||||
sqlCommands.push(
|
||||
`INSERT OR REPLACE INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_version', '${targetVersionInfo.version}', datetime('now'), datetime('now'), 0);`
|
||||
);
|
||||
sqlCommands.push(
|
||||
`INSERT OR REPLACE INTO "Settings" ("Key", "Value", "CreatedAt", "UpdatedAt", "IsDeleted")
|
||||
VALUES ('vault_migration_number', '${targetVersionInfo.migrationNumber}', datetime('now'), datetime('now'), 0);`
|
||||
);
|
||||
|
||||
await this.dbExecutor.executeTransaction(sqlCommands);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
version: targetVersionInfo.version,
|
||||
migrationNumber: targetVersionInfo.migrationNumber
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
version: '0.0.0',
|
||||
migrationNumber: 0,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if vault database exists and is valid
|
||||
*/
|
||||
async isValidVault(): Promise<boolean> {
|
||||
try {
|
||||
// Check if core tables exist
|
||||
const tables = await this.dbExecutor.executeSqlWithResults<{name: string}>(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name IN
|
||||
('Aliases', 'Services', 'Credentials', 'Passwords', 'Attachments', 'EncryptionKeys', 'Settings', 'TotpCodes');`
|
||||
);
|
||||
|
||||
// Should have all 8 core tables
|
||||
return tables.length >= 5; // At minimum, need core tables (some might not exist in older versions)
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
198
shared/vault-sql/src/__tests__/VaultManager.test.ts
Normal file
198
shared/vault-sql/src/__tests__/VaultManager.test.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { VaultManager, type IDbExecutor } from '../VaultManager.js';
|
||||
import { CURRENT_VAULT_VERSION } from '../types/VaultVersion.js';
|
||||
|
||||
// Mock database executor for testing
|
||||
class MockDbExecutor implements IDbExecutor {
|
||||
private queries: string[] = [];
|
||||
private mockResults: Record<string, unknown[]> = {};
|
||||
|
||||
async executeSql(sql: string): Promise<void> {
|
||||
this.queries.push(sql);
|
||||
}
|
||||
|
||||
async executeSqlWithResults<T = unknown>(sql: string): Promise<T[]> {
|
||||
this.queries.push(sql);
|
||||
// Normalize SQL for matching - remove extra whitespace and newlines
|
||||
const key = sql.toLowerCase().replace(/\s+/g, ' ').trim();
|
||||
return (this.mockResults[key] as T[]) || [];
|
||||
}
|
||||
|
||||
async executeTransaction(sqlCommands: string[]): Promise<void> {
|
||||
this.queries.push(...sqlCommands);
|
||||
}
|
||||
|
||||
// Test helpers
|
||||
getExecutedQueries(): string[] {
|
||||
return [...this.queries];
|
||||
}
|
||||
|
||||
clearQueries(): void {
|
||||
this.queries = [];
|
||||
}
|
||||
|
||||
setMockResult(sql: string, result: unknown[]): void {
|
||||
// Normalize SQL for matching - remove extra whitespace and newlines
|
||||
const key = sql.toLowerCase().replace(/\s+/g, ' ').trim();
|
||||
this.mockResults[key] = result;
|
||||
}
|
||||
}
|
||||
|
||||
describe('VaultManager', () => {
|
||||
let vaultManager: VaultManager;
|
||||
let mockDb: MockDbExecutor;
|
||||
|
||||
beforeEach(() => {
|
||||
mockDb = new MockDbExecutor();
|
||||
vaultManager = new VaultManager(mockDb);
|
||||
});
|
||||
|
||||
describe('createNewVault', () => {
|
||||
it('should create a new vault with latest schema', async () => {
|
||||
const result = await vaultManager.createNewVault();
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.version).toBe(CURRENT_VAULT_VERSION.version);
|
||||
expect(result.migrationNumber).toBe(CURRENT_VAULT_VERSION.migrationNumber);
|
||||
|
||||
const queries = mockDb.getExecutedQueries();
|
||||
expect(queries).toContain('PRAGMA foreign_keys = ON;');
|
||||
expect(queries.some(q => q.includes('CREATE TABLE "Aliases"'))).toBe(true);
|
||||
expect(queries.some(q => q.includes('vault_version'))).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle errors during vault creation', async () => {
|
||||
const failingDb = {
|
||||
executeSql: vi.fn().mockRejectedValue(new Error('Database error')),
|
||||
executeSqlWithResults: vi.fn(),
|
||||
executeTransaction: vi.fn().mockRejectedValue(new Error('Database error'))
|
||||
};
|
||||
|
||||
const failingVaultManager = new VaultManager(failingDb);
|
||||
const result = await failingVaultManager.createNewVault();
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toBe('Database error');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentVaultInfo', () => {
|
||||
it('should return correct info for new vault without Settings table', async () => {
|
||||
// Mock no Settings table exists
|
||||
mockDb.setMockResult("select name from sqlite_master where type='table' and name='settings';", []);
|
||||
|
||||
const info = await vaultManager.getCurrentVaultInfo();
|
||||
|
||||
expect(info.version).toBe('0.0.0');
|
||||
expect(info.migrationNumber).toBe(0);
|
||||
expect(info.needsUpgrade).toBe(true);
|
||||
expect(info.availableUpgrades.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should return correct info for existing vault with version info', async () => {
|
||||
// Mock Settings table exists
|
||||
mockDb.setMockResult("select name from sqlite_master where type='table' and name='settings';", [{ name: 'Settings' }]);
|
||||
|
||||
// Mock version queries
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_version' and isdeleted = 0 limit 1;", [{ Value: '1.2.0' }]);
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_migration_number' and isdeleted = 0 limit 1;", [{ Value: '4' }]);
|
||||
|
||||
const info = await vaultManager.getCurrentVaultInfo();
|
||||
|
||||
expect(info.version).toBe('1.2.0');
|
||||
expect(info.migrationNumber).toBe(4);
|
||||
expect(info.needsUpgrade).toBe(info.migrationNumber < CURRENT_VAULT_VERSION.migrationNumber);
|
||||
});
|
||||
|
||||
it('should handle errors and default to needs upgrade', async () => {
|
||||
const failingDb = {
|
||||
executeSql: vi.fn(),
|
||||
executeSqlWithResults: vi.fn().mockRejectedValue(new Error('Database error')),
|
||||
executeTransaction: vi.fn()
|
||||
};
|
||||
|
||||
const failingVaultManager = new VaultManager(failingDb);
|
||||
const info = await failingVaultManager.getCurrentVaultInfo();
|
||||
|
||||
expect(info.version).toBe('0.0.0');
|
||||
expect(info.migrationNumber).toBe(0);
|
||||
expect(info.needsUpgrade).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('upgradeVault', () => {
|
||||
it('should not upgrade if vault is already current', async () => {
|
||||
// Mock Settings table exists
|
||||
mockDb.setMockResult("select name from sqlite_master where type='table' and name='settings';", [{ name: 'Settings' }]);
|
||||
|
||||
// Mock current version
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_version' and isdeleted = 0 limit 1;", [{ Value: CURRENT_VAULT_VERSION.version }]);
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_migration_number' and isdeleted = 0 limit 1;", [{ Value: CURRENT_VAULT_VERSION.migrationNumber.toString() }]);
|
||||
|
||||
const result = await vaultManager.upgradeVault();
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.version).toBe(CURRENT_VAULT_VERSION.version);
|
||||
expect(result.migrationNumber).toBe(CURRENT_VAULT_VERSION.migrationNumber);
|
||||
});
|
||||
|
||||
it('should upgrade from older version', async () => {
|
||||
// Mock Settings table exists with older version
|
||||
mockDb.setMockResult("select name from sqlite_master where type='table' and name='settings';", [{ name: 'Settings' }]);
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_version' and isdeleted = 0 limit 1;", [{ Value: '1.0.0' }]);
|
||||
mockDb.setMockResult("select value from settings where key = 'vault_migration_number' and isdeleted = 0 limit 1;", [{ Value: '1' }]);
|
||||
|
||||
const result = await vaultManager.upgradeVault();
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.version).toBe(CURRENT_VAULT_VERSION.version);
|
||||
expect(result.migrationNumber).toBe(CURRENT_VAULT_VERSION.migrationNumber);
|
||||
|
||||
const queries = mockDb.getExecutedQueries();
|
||||
expect(queries).toContain('PRAGMA foreign_keys = ON;');
|
||||
expect(queries.some(q => q.includes('vault_version'))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidVault', () => {
|
||||
it('should return true for valid vault with core tables', async () => {
|
||||
mockDb.setMockResult(
|
||||
`select name from sqlite_master where type='table' and name in
|
||||
('aliases', 'services', 'credentials', 'passwords', 'attachments', 'encryptionkeys', 'settings', 'totpcodes');`,
|
||||
[
|
||||
{ name: 'Aliases' },
|
||||
{ name: 'Services' },
|
||||
{ name: 'Credentials' },
|
||||
{ name: 'Passwords' },
|
||||
{ name: 'Attachments' }
|
||||
]
|
||||
);
|
||||
|
||||
const isValid = await vaultManager.isValidVault();
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for vault with insufficient tables', async () => {
|
||||
mockDb.setMockResult(
|
||||
`select name from sqlite_master where type='table' and name in
|
||||
('aliases', 'services', 'credentials', 'passwords', 'attachments', 'encryptionkeys', 'settings', 'totpcodes');`,
|
||||
[{ name: 'Aliases' }]
|
||||
);
|
||||
|
||||
const isValid = await vaultManager.isValidVault();
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false on database error', async () => {
|
||||
const failingDb = {
|
||||
executeSql: vi.fn(),
|
||||
executeSqlWithResults: vi.fn().mockRejectedValue(new Error('Database error')),
|
||||
executeTransaction: vi.fn()
|
||||
};
|
||||
|
||||
const failingVaultManager = new VaultManager(failingDb);
|
||||
const isValid = await failingVaultManager.isValidVault();
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
27
shared/vault-sql/src/index.ts
Normal file
27
shared/vault-sql/src/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @aliasvault/vault-sql
|
||||
*
|
||||
* Shared SQL scripts and utilities for AliasVault database operations.
|
||||
* Provides cross-platform vault creation and migration functionality.
|
||||
*/
|
||||
|
||||
// Export VaultManager and interfaces
|
||||
export {
|
||||
VaultManager,
|
||||
type IDbExecutor,
|
||||
type IVaultOperationResult,
|
||||
type ICurrentVaultInfo
|
||||
} from './VaultManager.js';
|
||||
|
||||
// Export version types and constants
|
||||
export {
|
||||
type IVaultVersion,
|
||||
VAULT_VERSIONS,
|
||||
CURRENT_VAULT_VERSION
|
||||
} from './types/VaultVersion.js';
|
||||
|
||||
// Export SQL constants
|
||||
export {
|
||||
COMPLETE_SCHEMA_SQL,
|
||||
MIGRATION_SCRIPTS
|
||||
} from './sql/SqlConstants.js';
|
||||
300
shared/vault-sql/src/sql/SqlConstants.ts
Normal file
300
shared/vault-sql/src/sql/SqlConstants.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Complete database schema SQL (latest version)
|
||||
*/
|
||||
export const COMPLETE_SCHEMA_SQL = `-- AliasVault Client Database Complete Schema
|
||||
-- Final schema after all migrations (up to version 1.5.0)
|
||||
-- This script creates the complete database structure
|
||||
|
||||
-- Enable foreign key constraints
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
-- Create Aliases table
|
||||
CREATE TABLE "Aliases" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Gender" VARCHAR(255),
|
||||
"FirstName" VARCHAR(255),
|
||||
"LastName" VARCHAR(255),
|
||||
"NickName" VARCHAR(255),
|
||||
"BirthDate" TEXT NOT NULL,
|
||||
"Email" TEXT, -- Renamed from EmailPrefix in v1.0.2
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0 -- Added in v1.4.0
|
||||
-- Note: Address, phone, hobbies, and bank account columns removed in v1.3.0
|
||||
);
|
||||
|
||||
-- Create Services table
|
||||
CREATE TABLE "Services" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Name" TEXT,
|
||||
"Url" TEXT,
|
||||
"Logo" BLOB,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0 -- Added in v1.4.0
|
||||
);
|
||||
|
||||
-- Create Credentials table
|
||||
CREATE TABLE "Credentials" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"AliasId" TEXT NOT NULL,
|
||||
"Notes" TEXT,
|
||||
"Username" TEXT, -- Made optional in v1.3.1
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"ServiceId" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0, -- Added in v1.4.0
|
||||
FOREIGN KEY ("AliasId") REFERENCES "Aliases" ("Id") ON DELETE CASCADE,
|
||||
FOREIGN KEY ("ServiceId") REFERENCES "Services" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create Attachments table (renamed from Attachment in v1.4.1)
|
||||
CREATE TABLE "Attachments" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Filename" TEXT NOT NULL,
|
||||
"Blob" BLOB NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0, -- Added in v1.4.0
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create Passwords table
|
||||
CREATE TABLE "Passwords" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Value" TEXT,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0, -- Added in v1.4.0
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create EncryptionKeys table (added in v1.1.0)
|
||||
CREATE TABLE "EncryptionKeys" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"PublicKey" TEXT NOT NULL,
|
||||
"PrivateKey" TEXT NOT NULL,
|
||||
"IsPrimary" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0 -- Added in v1.4.0
|
||||
);
|
||||
|
||||
-- Create Settings table (added in v1.2.0)
|
||||
CREATE TABLE "Settings" (
|
||||
"Key" TEXT NOT NULL PRIMARY KEY,
|
||||
"Value" TEXT,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL DEFAULT 0 -- Added in v1.4.0
|
||||
);
|
||||
|
||||
-- Create TotpCodes table (added in v1.5.0)
|
||||
CREATE TABLE "TotpCodes" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"SecretKey" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX "IX_Attachments_CredentialId" ON "Attachments" ("CredentialId");
|
||||
CREATE INDEX "IX_Credentials_AliasId" ON "Credentials" ("AliasId");
|
||||
CREATE INDEX "IX_Credentials_ServiceId" ON "Credentials" ("ServiceId");
|
||||
CREATE INDEX "IX_Passwords_CredentialId" ON "Passwords" ("CredentialId");
|
||||
CREATE INDEX "IX_TotpCodes_CredentialId" ON "TotpCodes" ("CredentialId");`;
|
||||
|
||||
/**
|
||||
* Individual migration SQL scripts
|
||||
*/
|
||||
export const MIGRATION_SCRIPTS: Record<number, string> = {
|
||||
1: `-- Migration 1.0.0: Initial Migration
|
||||
-- Create the initial database schema for AliasVault Client
|
||||
|
||||
-- Create Aliases table
|
||||
CREATE TABLE "Aliases" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Gender" VARCHAR(255),
|
||||
"FirstName" VARCHAR(255),
|
||||
"LastName" VARCHAR(255),
|
||||
"NickName" VARCHAR(255),
|
||||
"BirthDate" TEXT NOT NULL,
|
||||
"AddressStreet" VARCHAR(255),
|
||||
"AddressCity" VARCHAR(255),
|
||||
"AddressState" VARCHAR(255),
|
||||
"AddressZipCode" VARCHAR(255),
|
||||
"AddressCountry" VARCHAR(255),
|
||||
"Hobbies" TEXT,
|
||||
"EmailPrefix" TEXT,
|
||||
"PhoneMobile" TEXT,
|
||||
"BankAccountIBAN" TEXT,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Create Services table
|
||||
CREATE TABLE "Services" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Name" TEXT,
|
||||
"Url" TEXT,
|
||||
"Logo" BLOB,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Create Credentials table
|
||||
CREATE TABLE "Credentials" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"AliasId" TEXT NOT NULL,
|
||||
"Notes" TEXT,
|
||||
"Username" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"ServiceId" TEXT NOT NULL,
|
||||
FOREIGN KEY ("AliasId") REFERENCES "Aliases" ("Id") ON DELETE CASCADE,
|
||||
FOREIGN KEY ("ServiceId") REFERENCES "Services" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create Attachment table
|
||||
CREATE TABLE "Attachment" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Filename" TEXT NOT NULL,
|
||||
"Blob" BLOB NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create Passwords table
|
||||
CREATE TABLE "Passwords" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Value" TEXT,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX "IX_Attachment_CredentialId" ON "Attachment" ("CredentialId");
|
||||
CREATE INDEX "IX_Credentials_AliasId" ON "Credentials" ("AliasId");
|
||||
CREATE INDEX "IX_Credentials_ServiceId" ON "Credentials" ("ServiceId");
|
||||
CREATE INDEX "IX_Passwords_CredentialId" ON "Passwords" ("CredentialId");`,
|
||||
|
||||
2: `-- Migration 1.0.2: Change Email Column
|
||||
-- Rename EmailPrefix to Email in Aliases table
|
||||
|
||||
ALTER TABLE "Aliases" RENAME COLUMN "EmailPrefix" TO "Email";`,
|
||||
|
||||
3: `-- Migration 1.1.0: Add PKI Tables
|
||||
-- Add EncryptionKeys table for PKI support
|
||||
|
||||
CREATE TABLE "EncryptionKeys" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"PublicKey" TEXT NOT NULL,
|
||||
"PrivateKey" TEXT NOT NULL,
|
||||
"IsPrimary" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL
|
||||
);`,
|
||||
|
||||
4: `-- Migration 1.2.0: Add Settings Table
|
||||
-- Add Settings table for user preferences
|
||||
|
||||
CREATE TABLE "Settings" (
|
||||
"Key" TEXT NOT NULL PRIMARY KEY,
|
||||
"Value" TEXT,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL
|
||||
);`,
|
||||
|
||||
5: `-- Migration 1.3.0: Update Identity Structure
|
||||
-- Remove address, phone, hobbies, and bank account columns from Aliases table
|
||||
|
||||
ALTER TABLE "Aliases" DROP COLUMN "AddressStreet";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "AddressCity";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "AddressState";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "AddressZipCode";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "AddressCountry";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "Hobbies";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "PhoneMobile";
|
||||
ALTER TABLE "Aliases" DROP COLUMN "BankAccountIBAN";`,
|
||||
|
||||
6: `-- Migration 1.3.1: Make Username Optional
|
||||
-- Make Username column nullable in Credentials table
|
||||
|
||||
-- SQLite doesn't support ALTER COLUMN directly, so we need to recreate the table
|
||||
-- Create temporary table with new structure
|
||||
CREATE TABLE "Credentials_temp" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"AliasId" TEXT NOT NULL,
|
||||
"Notes" TEXT,
|
||||
"Username" TEXT, -- Made optional (nullable)
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"ServiceId" TEXT NOT NULL,
|
||||
FOREIGN KEY ("AliasId") REFERENCES "Aliases" ("Id") ON DELETE CASCADE,
|
||||
FOREIGN KEY ("ServiceId") REFERENCES "Services" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Copy data from old table to new table
|
||||
INSERT INTO "Credentials_temp"
|
||||
SELECT "Id", "AliasId", "Notes", "Username", "CreatedAt", "UpdatedAt", "ServiceId"
|
||||
FROM "Credentials";
|
||||
|
||||
-- Drop old table
|
||||
DROP TABLE "Credentials";
|
||||
|
||||
-- Rename temp table to original name
|
||||
ALTER TABLE "Credentials_temp" RENAME TO "Credentials";
|
||||
|
||||
-- Recreate indexes
|
||||
CREATE INDEX "IX_Credentials_AliasId" ON "Credentials" ("AliasId");
|
||||
CREATE INDEX "IX_Credentials_ServiceId" ON "Credentials" ("ServiceId");`,
|
||||
|
||||
7: `-- Migration 1.4.0: Add Sync Support
|
||||
-- Add IsDeleted column to all tables for soft delete support
|
||||
|
||||
ALTER TABLE "Aliases" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "Services" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "Credentials" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "Attachment" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "Passwords" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "EncryptionKeys" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE "Settings" ADD COLUMN "IsDeleted" INTEGER NOT NULL DEFAULT 0;`,
|
||||
|
||||
8: `-- Migration 1.4.1: Rename Attachments Plural
|
||||
-- Rename Attachment table to Attachments for consistency
|
||||
|
||||
ALTER TABLE "Attachment" RENAME TO "Attachments";
|
||||
|
||||
-- Drop old index
|
||||
DROP INDEX "IX_Attachment_CredentialId";
|
||||
|
||||
-- Create new index with correct name
|
||||
CREATE INDEX "IX_Attachments_CredentialId" ON "Attachments" ("CredentialId");`,
|
||||
|
||||
9: `-- Migration 1.5.0: Add TOTP Codes
|
||||
-- Add TotpCodes table for 2FA support
|
||||
|
||||
CREATE TABLE "TotpCodes" (
|
||||
"Id" TEXT NOT NULL PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"SecretKey" TEXT NOT NULL,
|
||||
"CredentialId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("CredentialId") REFERENCES "Credentials" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Create index
|
||||
CREATE INDEX "IX_TotpCodes_CredentialId" ON "TotpCodes" ("CredentialId");`
|
||||
};
|
||||
89
shared/vault-sql/src/types/VaultVersion.ts
Normal file
89
shared/vault-sql/src/types/VaultVersion.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Vault database version information
|
||||
*/
|
||||
export interface IVaultVersion {
|
||||
/**
|
||||
* The version number (e.g., "1.5.0")
|
||||
*/
|
||||
version: string;
|
||||
|
||||
/**
|
||||
* The migration number
|
||||
*/
|
||||
migrationNumber: number;
|
||||
|
||||
/**
|
||||
* Description of changes in this version
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Release date
|
||||
*/
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Available vault versions in chronological order
|
||||
*/
|
||||
export const VAULT_VERSIONS: IVaultVersion[] = [
|
||||
{
|
||||
version: '1.0.0',
|
||||
migrationNumber: 1,
|
||||
description: 'Initial database schema with core vault functionality',
|
||||
releaseDate: '2024-07-08'
|
||||
},
|
||||
{
|
||||
version: '1.0.2',
|
||||
migrationNumber: 2,
|
||||
description: 'Email column rename for improved clarity',
|
||||
releaseDate: '2024-07-11'
|
||||
},
|
||||
{
|
||||
version: '1.1.0',
|
||||
migrationNumber: 3,
|
||||
description: 'PKI support with encryption keys table',
|
||||
releaseDate: '2024-07-29'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
migrationNumber: 4,
|
||||
description: 'Settings table for user preferences',
|
||||
releaseDate: '2024-08-05'
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
migrationNumber: 5,
|
||||
description: 'Identity structure simplification',
|
||||
releaseDate: '2024-08-05'
|
||||
},
|
||||
{
|
||||
version: '1.3.1',
|
||||
migrationNumber: 6,
|
||||
description: 'Optional username support',
|
||||
releaseDate: '2024-08-12'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
migrationNumber: 7,
|
||||
description: 'Soft delete support for synchronization',
|
||||
releaseDate: '2024-09-16'
|
||||
},
|
||||
{
|
||||
version: '1.4.1',
|
||||
migrationNumber: 8,
|
||||
description: 'Attachment table rename for consistency',
|
||||
releaseDate: '2024-09-17'
|
||||
},
|
||||
{
|
||||
version: '1.5.0',
|
||||
migrationNumber: 9,
|
||||
description: 'TOTP (2FA) support',
|
||||
releaseDate: '2025-03-10'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Current/latest vault version
|
||||
*/
|
||||
export const CURRENT_VAULT_VERSION = VAULT_VERSIONS[VAULT_VERSIONS.length - 1];
|
||||
19
shared/vault-sql/tsconfig.json
Normal file
19
shared/vault-sql/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"lib": ["ES2020"],
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
16
shared/vault-sql/tsup.config.ts
Normal file
16
shared/vault-sql/tsup.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/**/index.ts'],
|
||||
format: ['esm'],
|
||||
dts: true,
|
||||
splitting: false,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
treeshake: true,
|
||||
target: 'es2020',
|
||||
minify: false,
|
||||
banner: {
|
||||
js: '// <auto-generated>\n// This file was automatically generated. Do not edit manually.\n',
|
||||
}
|
||||
});
|
||||
18
shared/vault-sql/vitest.config.ts
Normal file
18
shared/vault-sql/vitest.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'json', 'html'],
|
||||
exclude: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'**/*.test.ts',
|
||||
'**/*.config.ts'
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user