arckode-framework 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/adapters/jwt.ts +6 -4
  2. package/adapters/mysql.ts +7 -2
  3. package/adapters/postgres.ts +37 -0
  4. package/adapters/sqlite.ts +7 -1
  5. package/adapters/vendor.d.ts +48 -0
  6. package/cli/analyze/checks.ts +333 -0
  7. package/cli/analyze/index.ts +44 -0
  8. package/cli/analyze/report.ts +107 -0
  9. package/cli/analyze/types.ts +46 -0
  10. package/cli/analyze/utils.ts +36 -0
  11. package/cli/analyze.ts +2 -647
  12. package/cli/commands/db-migrate.ts +213 -89
  13. package/cli/commands/db-seed.ts +97 -32
  14. package/cli/commands/db-utils.ts +192 -0
  15. package/cli/commands/new.ts +175 -0
  16. package/cli/commands/routes.ts +94 -0
  17. package/cli/index.ts +57 -404
  18. package/cli/stubs/claude-md-stub.ts +21 -8
  19. package/cli/stubs/module/core.ts +162 -0
  20. package/cli/stubs/module/data.ts +171 -0
  21. package/cli/stubs/module/index.ts +5 -0
  22. package/cli/stubs/module/service.ts +198 -0
  23. package/cli/stubs/module/types.ts +12 -0
  24. package/cli/stubs/module-stub.ts +2 -552
  25. package/kernel/auth.ts +114 -0
  26. package/kernel/cache.ts +37 -0
  27. package/kernel/config.ts +129 -0
  28. package/kernel/container.ts +64 -0
  29. package/kernel/db/orm-migrate.ts +136 -0
  30. package/kernel/db/orm-repository.ts +45 -0
  31. package/kernel/db/orm-utils.ts +93 -0
  32. package/kernel/db/orm.ts +254 -0
  33. package/kernel/db/transactor.ts +17 -0
  34. package/kernel/db/types.ts +72 -0
  35. package/kernel/errors.ts +102 -0
  36. package/kernel/framework.default.ts +41 -0
  37. package/kernel/framework.ts +8 -2144
  38. package/kernel/http/router.ts +131 -0
  39. package/kernel/http/server.ts +303 -0
  40. package/kernel/http/types.ts +56 -0
  41. package/kernel/index.ts +25 -0
  42. package/kernel/logger.ts +50 -0
  43. package/kernel/middlewares.ts +38 -21
  44. package/kernel/modules/create-module.ts +5 -0
  45. package/kernel/modules/system.ts +149 -0
  46. package/kernel/modules/types.ts +46 -0
  47. package/kernel/seeds.ts +48 -0
  48. package/kernel/static.ts +11 -2
  49. package/kernel/testing.ts +8 -3
  50. package/kernel/validator.ts +116 -0
  51. package/modules/events/index.ts +19 -3
  52. package/modules/mail/index.ts +14 -2
  53. package/modules/storage/local-adapter.ts +19 -5
  54. package/modules/ws/index.ts +123 -18
  55. package/package.json +8 -11
  56. package/skills/auth/SKILL.md +36 -220
  57. package/skills/cli/SKILL.md +32 -251
  58. package/skills/config/SKILL.md +30 -239
  59. package/skills/connectors/SKILL.md +32 -295
  60. package/skills/helpers/SKILL.md +26 -195
  61. package/skills/middlewares/SKILL.md +30 -267
  62. package/skills/orm/SKILL.md +42 -349
  63. package/skills/realtime/SKILL.md +22 -297
  64. package/skills/services/SKILL.md +40 -183
  65. package/skills/testing/SKILL.md +34 -266
@@ -0,0 +1,107 @@
1
+ import type { AnalysisResult, Violation } from './types'
2
+
3
+ export function printAnalysis(result: AnalysisResult): void {
4
+ console.log('\n══════════════════════════════════════')
5
+ console.log(' Análisis de Arquitectura')
6
+ console.log('══════════════════════════════════════\n')
7
+
8
+ console.log(`📦 Módulos (${result.modules.length}):`)
9
+ for (const m of result.modules) {
10
+ const icon = m.hasIndex ? '✓' : '✗'
11
+ const parts = [
12
+ m.hasService ? 'service' : null,
13
+ m.hasController ? 'controller' : null,
14
+ m.hasTypes ? 'types' : null,
15
+ m.hasSockets ? 'sockets' : null,
16
+ m.hasValidators ? 'validators' : null,
17
+ m.hasTests ? 'tests' : null,
18
+ ].filter(Boolean)
19
+ console.log(` ${icon} ${m.name} [${parts.join(', ')}]`)
20
+ }
21
+
22
+ console.log(`\n🔌 Conectores (${result.connectors.length}):`)
23
+ for (const c of result.connectors) console.log(` ${c}`)
24
+
25
+ if (result.violations.length > 0) {
26
+ const byCategory: Record<string, Violation[]> = {
27
+ 'Estructura': [], 'Acoplamiento': [], 'Diseño': [],
28
+ 'Calidad': [], 'Seguridad': [], 'Performance': [], 'Portabilidad': [],
29
+ }
30
+
31
+ for (const v of result.violations) {
32
+ if (['MISSING_INDEX', 'MISSING_SERVICE', 'MISSING_TYPES', 'MISSING_SOCKETS', 'MISSING_VALIDATORS', 'MISSING_TESTS', 'MISSING_CONNECTORS', 'EMPTY_MODULE_DESCRIPTION', 'MODEL_IN_TYPES_FILE', 'MISSING_MODEL_TS'].includes(v.type)) {
33
+ byCategory['Estructura']!.push(v)
34
+ } else if (['DIRECT_MODULE_IMPORT', 'SERVICE_IMPORTS_OTHER_MODULE', 'CONNECTOR_BUSINESS_LOGIC', 'DUPLICATE_CONNECTOR', 'UNREGISTERED_CONNECTOR'].includes(v.type)) {
35
+ byCategory['Acoplamiento']!.push(v)
36
+ } else if (['BUSINESS_LOGIC_IN_CONTROLLER', 'GOD_SERVICE', 'INDEX_PENDING_CHANGES'].includes(v.type)) {
37
+ byCategory['Diseño']!.push(v)
38
+ } else if (['IDOR_RISK'].includes(v.type)) {
39
+ byCategory['Seguridad']!.push(v)
40
+ } else if (['N_PLUS_ONE_RISK'].includes(v.type)) {
41
+ byCategory['Performance']!.push(v)
42
+ } else if (['SERVICE_DEPENDS_ON_ORM'].includes(v.type)) {
43
+ byCategory['Portabilidad']!.push(v)
44
+ } else {
45
+ byCategory['Calidad']!.push(v)
46
+ }
47
+ }
48
+
49
+ console.log(`\n❌ Violaciones (${result.violations.length}):`)
50
+ for (const [cat, vs] of Object.entries(byCategory)) {
51
+ if (vs.length === 0) continue
52
+ console.log(`\n [${cat}]`)
53
+ for (const v of vs) console.log(` • ${v.message}`)
54
+ }
55
+ }
56
+
57
+ if (result.warnings.length > 0) {
58
+ console.log(`\n⚠️ Advertencias (${result.warnings.length}):`)
59
+ for (const w of result.warnings) console.log(` ${w.message}`)
60
+ }
61
+
62
+ console.log(`\n📊 Resultado: ${result.valid ? '✅ VÁLIDO' : '❌ VIOLACIONES ENCONTRADAS'}`)
63
+ console.log('══════════════════════════════════════\n')
64
+ }
65
+
66
+ export function buildManifest(result: AnalysisResult): Record<string, unknown> {
67
+ return {
68
+ _arckode: '1.0.0',
69
+ _generated: new Date().toISOString(),
70
+ _instructions: 'Lee este archivo ANTES de escribir código. Contiene el estado completo del sistema: módulos, conectores, violaciones. Si está desactualizado, corré: bun run analyze --json',
71
+
72
+ system: {
73
+ healthy: result.valid,
74
+ violations: result.violations.length,
75
+ warnings: result.warnings.length,
76
+ },
77
+
78
+ modules: result.modules.map(m => ({
79
+ name: m.name,
80
+ structure: {
81
+ index: m.hasIndex, types: m.hasTypes, sockets: m.hasSockets,
82
+ service: m.hasService, controller: m.hasController,
83
+ validators: m.hasValidators, tests: m.hasTests,
84
+ },
85
+ complete: m.hasIndex && m.hasTypes && m.hasService && m.hasController && m.hasValidators && m.hasTests,
86
+ })),
87
+
88
+ connectors: result.connectors,
89
+
90
+ violations: result.violations.map(v => ({ module: v.module, type: v.type, message: v.message })),
91
+
92
+ warnings: result.warnings.map(w => ({ type: w.type, message: w.message })),
93
+
94
+ rules_summary: [
95
+ 'REGLA 1: Módulos NO importan de otros módulos. Usar conectores.',
96
+ 'REGLA 2: index.ts es APPEND-ONLY. No eliminar exports.',
97
+ 'REGLA 3: Conectores NO tienen lógica de negocio. Solo delegan.',
98
+ 'REGLA 4: Cada tabla pertenece a UN módulo.',
99
+ 'REGLA 5: Si no está en composition-root.ts, no existe.',
100
+ 'REGLA 6: Todo POST/PUT/PATCH requiere validateSchema().',
101
+ 'REGLA 7: Controller NO llama al ORM. Llama al service.',
102
+ 'REGLA 18: Service recibe RepositoryAdapter<T>, no ORM directamente.',
103
+ 'REGLA 22: model.ts separado de types.ts. Schema DB ≠ contrato TS.',
104
+ 'REGLA 23: Un DEFAULT por caso. Escalar SOLO cuando la condición lo justifica.',
105
+ ],
106
+ }
107
+ }
@@ -0,0 +1,46 @@
1
+ export interface AnalysisResult {
2
+ valid: boolean
3
+ modules: ModuleReport[]
4
+ connectors: string[]
5
+ violations: Violation[]
6
+ warnings: Warning[]
7
+ }
8
+
9
+ export interface ModuleReport {
10
+ name: string
11
+ hasIndex: boolean
12
+ hasService: boolean
13
+ hasController: boolean
14
+ hasTypes: boolean
15
+ hasSockets: boolean
16
+ hasValidators: boolean
17
+ hasTests: boolean
18
+ }
19
+
20
+ export interface Violation {
21
+ type:
22
+ | 'DIRECT_MODULE_IMPORT'
23
+ | 'MISSING_INDEX' | 'MISSING_CONTRACT' | 'MISSING_SERVICE' | 'MISSING_TYPES'
24
+ | 'MISSING_SOCKETS' | 'MISSING_VALIDATORS' | 'MISSING_TESTS'
25
+ | 'MISSING_CONNECTORS' | 'CONNECTOR_BUSINESS_LOGIC' | 'INDEX_PENDING_CHANGES'
26
+ | 'CONTROLLER_MISSING_VALIDATION'
27
+ | 'BUSINESS_LOGIC_IN_CONTROLLER'
28
+ | 'EMPTY_MODULE_DESCRIPTION'
29
+ | 'TESTS_WITHOUT_CASES'
30
+ | 'SERVICE_IMPORTS_OTHER_MODULE'
31
+ | 'GOD_SERVICE'
32
+ | 'N_PLUS_ONE_RISK'
33
+ | 'IDOR_RISK'
34
+ | 'SERVICE_DEPENDS_ON_ORM'
35
+ | 'MODEL_IN_TYPES_FILE'
36
+ | 'MISSING_MODEL_TS'
37
+ | 'DUPLICATE_CONNECTOR'
38
+ | 'UNREGISTERED_CONNECTOR'
39
+ module: string
40
+ message: string
41
+ }
42
+
43
+ export interface Warning {
44
+ type: 'NO_CONNECTORS' | 'SINGLE_MODULE' | 'NO_COMPOSITION_ROOT' | 'INDEX_PENDING_CHANGES' | 'LEGACY_ACTIONS_FOLDER'
45
+ message: string
46
+ }
@@ -0,0 +1,36 @@
1
+ import { readdir, access } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+
4
+ export async function fileExists(path: string): Promise<boolean> {
5
+ try { await access(path); return true } catch { return false }
6
+ }
7
+
8
+ export async function resolvePath(modPath: string, candidates: string[]): Promise<string | null> {
9
+ for (const candidate of candidates) {
10
+ const full = join(modPath, candidate)
11
+ if (await fileExists(full)) return full
12
+ }
13
+ return null
14
+ }
15
+
16
+ export function canonicalizeConnectorName(filename: string): string {
17
+ return filename.replace(/\.ts$/, '').replace(/[-_]/g, '').toLowerCase()
18
+ }
19
+
20
+ export async function getAllTsFiles(dir: string): Promise<string[]> {
21
+ const files: string[] = []
22
+ try {
23
+ const entries = await readdir(dir, { withFileTypes: true })
24
+ for (const entry of entries) {
25
+ const full = join(dir, entry.name)
26
+ if (entry.isDirectory()) {
27
+ if (entry.name !== 'node_modules' && entry.name !== 'tests' && entry.name !== '__tests__') {
28
+ files.push(...await getAllTsFiles(full))
29
+ }
30
+ } else if (entry.name.endsWith('.ts')) {
31
+ files.push(full)
32
+ }
33
+ }
34
+ } catch { /* ignore */ }
35
+ return files
36
+ }