feat: estructura base OpenSpec + Skills + arquitectura limpia Capacitor+Dextie

This commit is contained in:
mono
2026-10-24 20:49:29 -05:00
parent 2e6262b5a5
commit 0c7cf651ce
1659 changed files with 265883 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
{
"name": "@toldo/services",
"version": "0.0.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"test": "vitest"
},
"dependencies": {
"@toldo/core": "workspace:*",
"@toldo/data": "workspace:*"
},
"devDependencies": {
"typescript": "~6.0.3",
"vitest": "^2.1.8"
}
}

View File

@@ -0,0 +1,38 @@
import { describe, it, expect } from 'vitest';
import { ExportImportService, CURRENT_SCHEMA_VERSION } from '../export-import/ExportImportService';
describe('ExportImportService', () => {
const service = new ExportImportService();
it('exporta con versionado', () => {
const data = {
productores: [], productos: [], movimientosInventario: [],
ventas: [], ventaLineas: [], gastos: [], ajustes: [], cuadres: []
};
const exp = service.exportAll(data);
expect(exp.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
expect(exp.appVersion).toBe('0.0.1');
expect(exp.exportedAt).toBeTruthy();
expect(exp.data).toEqual(data);
});
it('valida y rechaza formato inválido', () => {
expect(() => service.import({})).toThrow('Formato de archivo inválido');
});
it('rechaza esquema incompatible más nuevo', () => {
const bad = {
schemaVersion: 999,
appVersion: '0.0.1',
exportedAt: new Date().toISOString(),
data: { productores: [], productos: [], movimientosInventario: [], ventas: [], ventaLineas: [], gastos: [], ajustes: [], cuadres: [] }
};
expect(() => service.import(bad)).toThrow('Versión de esquema incompatible');
});
it('importa datos válidos v1', () => {
const exp = service.exportAll({ productores: [], productos: [], movimientosInventario: [], ventas: [], ventaLineas: [], gastos: [], ajustes: [], cuadres: [] });
const imp = service.import(exp);
expect(imp.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
});
});

View File

@@ -0,0 +1,56 @@
import type { Productor, Producto, MovimientoInventario, Venta, VentaLinea, Gasto, Ajuste, CuadreCaja } from '@toldo/core';
export interface ExportData {
schemaVersion: number;
appVersion: string;
exportedAt: string;
data: {
productores: Productor[];
productos: Producto[];
movimientosInventario: MovimientoInventario[];
ventas: Venta[];
ventaLineas: VentaLinea[];
gastos: Gasto[];
ajustes: Ajuste[];
cuadres: CuadreCaja[];
};
}
export const CURRENT_SCHEMA_VERSION = 1;
export const APP_VERSION = '0.0.1';
export class ExportImportService {
exportAll(data: ExportData['data']): ExportData {
return {
schemaVersion: CURRENT_SCHEMA_VERSION,
appVersion: APP_VERSION,
exportedAt: new Date().toISOString(),
data
};
}
validate(data: unknown): data is ExportData {
if (!data || typeof data !== 'object') {
throw new Error('Formato de archivo inválido');
}
const d = data as any;
if (typeof d.schemaVersion !== 'number') throw new Error('Formato de archivo inválido');
if (typeof d.appVersion !== 'string') throw new Error('Formato de archivo inválido');
if (!d.exportedAt) throw new Error('Formato de archivo inválido');
if (!d.data || typeof d.data !== 'object') throw new Error('Formato de archivo inválido');
const required = ['productores', 'productos', 'movimientosInventario', 'ventas', 'ventaLineas', 'gastos', 'ajustes', 'cuadres'];
for (const key of required) {
if (!Array.isArray(d.data[key])) throw new Error('Formato de archivo inválido');
}
return true;
}
import(data: unknown): ExportData {
this.validate(data);
if ((data as ExportData).schemaVersion > CURRENT_SCHEMA_VERSION) {
throw new Error('Versión de esquema incompatible. Actualice la aplicación.');
}
// Simple pass-through for v1; migrations would go here
return data as ExportData;
}
}

View File

@@ -0,0 +1 @@
export * from './export-import/ExportImportService';

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"paths": {
"@toldo/core": ["../core/src"],
"@toldo/data": ["../data/src"]
}
},
"include": ["src"]
}