@roomi-fields/grillhouse 0.0.0-stage → 0.23.1

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 (166) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/METACADRE.md +41 -0
  3. package/agents/developpeur.md +10 -0
  4. package/agents/explorateur.md +9 -0
  5. package/agents/questionneur.md +11 -0
  6. package/agents/referent-technique.md +9 -0
  7. package/agents/regulateur.md +11 -0
  8. package/agents/relecteur.md +9 -0
  9. package/agents/testwriter.md +10 -0
  10. package/bin/grillhouse.mjs +125 -0
  11. package/cadre/templates/projet/.claude/settings.json +30 -0
  12. package/cadre/templates/projet/.editorconfig +47 -0
  13. package/cadre/templates/projet/.env.example +57 -0
  14. package/cadre/templates/projet/.eslintrc.cjs +56 -0
  15. package/cadre/templates/projet/.github/workflows/ci.yml +66 -0
  16. package/cadre/templates/projet/.mcp.json +13 -0
  17. package/cadre/templates/projet/.prettierrc +11 -0
  18. package/cadre/templates/projet/CHANGELOG.md +61 -0
  19. package/cadre/templates/projet/CLAUDE.md +46 -0
  20. package/cadre/templates/projet/CONTRIBUTING.md +243 -0
  21. package/cadre/templates/projet/CREDITS.md +41 -0
  22. package/cadre/templates/projet/README.md +152 -0
  23. package/cadre/templates/projet/_gitignore +91 -0
  24. package/cadre/templates/projet/_npmignore +46 -0
  25. package/cadre/templates/projet/deployment/README.md +98 -0
  26. package/cadre/templates/projet/deployment/docs/01-INSTALL.md +145 -0
  27. package/cadre/templates/projet/deployment/docs/02-CONFIGURATION.md +117 -0
  28. package/cadre/templates/projet/deployment/docs/03-API.md +264 -0
  29. package/cadre/templates/projet/deployment/docs/04-TROUBLESHOOTING.md +262 -0
  30. package/cadre/templates/projet/deployment/scripts/install.ps1 +100 -0
  31. package/cadre/templates/projet/deployment/scripts/start.ps1 +61 -0
  32. package/cadre/templates/projet/deployment/scripts/stop.ps1 +37 -0
  33. package/cadre/templates/projet/deployment/scripts/test.ps1 +118 -0
  34. package/cadre/templates/projet/docs/agents/issue-tracker.md +44 -0
  35. package/cadre/templates/projet/ecosystem.config.cjs +73 -0
  36. package/cadre/templates/projet/package.json +90 -0
  37. package/cadre/templates/projet/pitmaster/SUIVI.md +22 -0
  38. package/cadre/templates/projet/src/config.ts +68 -0
  39. package/cadre/templates/projet/src/errors.ts +102 -0
  40. package/cadre/templates/projet/src/index.ts +46 -0
  41. package/cadre/templates/projet/src/services/.gitkeep +8 -0
  42. package/cadre/templates/projet/src/types/index.ts +24 -0
  43. package/cadre/templates/projet/src/utils/logger.ts +106 -0
  44. package/cadre/templates/projet/tests/integration/.gitkeep +7 -0
  45. package/cadre/templates/projet/tests/unit/config.spec.ts +68 -0
  46. package/cadre/templates/projet/tests/unit/errors.spec.ts +132 -0
  47. package/cadre/templates/projet/tests/unit/types.spec.ts +73 -0
  48. package/cadre/templates/projet/tsconfig.eslint.json +9 -0
  49. package/cadre/templates/projet/tsconfig.json +41 -0
  50. package/cadre/templates/projet/tsdoc.json +6 -0
  51. package/cadre/templates/projet/vitest.config.ts +44 -0
  52. package/cadre/templates/turbo/paquets.json +29 -0
  53. package/cadre/templates/turbo/sans-paquets.json +28 -0
  54. package/charte.md +107 -0
  55. package/docs/ARCHITECTURE.md +90 -0
  56. package/hooks/crochet.mjs +33 -0
  57. package/hooks/hooks.json +58 -0
  58. package/hooks/register.tsx +558 -0
  59. package/package.json +75 -4
  60. package/scripts/avancement.mjs +244 -0
  61. package/scripts/bilan.mjs +523 -0
  62. package/scripts/branche-de-nuit.mjs +59 -0
  63. package/scripts/cadre.mjs +109 -0
  64. package/scripts/circuit.mjs +4375 -0
  65. package/scripts/code-mort.mjs +371 -0
  66. package/scripts/composants-affectes.mjs +598 -0
  67. package/scripts/consommateurs-arbitres.mjs +192 -0
  68. package/scripts/consommateurs.mjs +310 -0
  69. package/scripts/crochet.mjs +24 -0
  70. package/scripts/crochets.mjs +135 -0
  71. package/scripts/dernier-vert.mjs +208 -0
  72. package/scripts/dette.mjs +181 -0
  73. package/scripts/droits.mjs +354 -0
  74. package/scripts/enveloppe/codes.mjs +17 -0
  75. package/scripts/enveloppe/composant.mjs +11 -0
  76. package/scripts/enveloppe/enveloppe.mjs +628 -0
  77. package/scripts/enveloppe/lancer.sh +311 -0
  78. package/scripts/etapes.mjs +323 -0
  79. package/scripts/etat-du-circuit.mjs +104 -0
  80. package/scripts/frontieres.mjs +456 -0
  81. package/scripts/gardes-du-cadre.mjs +72 -0
  82. package/scripts/greffons.mjs +338 -0
  83. package/scripts/grillhouse-maj.mjs +514 -0
  84. package/scripts/index-interfaces.mjs +293 -0
  85. package/scripts/init.mjs +117 -0
  86. package/scripts/integration/file-attente.mjs +61 -0
  87. package/scripts/integration/file.mjs +494 -0
  88. package/scripts/integration/integrer.mjs +381 -0
  89. package/scripts/integration/rejeu.mjs +139 -0
  90. package/scripts/integration/verdict.mjs +13 -0
  91. package/scripts/interfaces-contre-code.mjs +547 -0
  92. package/scripts/ligne-etat/defaut.sh +110 -0
  93. package/scripts/ligne-etat/ligne-etat.mjs +93 -0
  94. package/scripts/migrations/0.23.0-charte-importee.mjs +47 -0
  95. package/scripts/migrations/0.23.0-config-vitest.mjs +105 -0
  96. package/scripts/migrations/0.23.0-crochets-de-seance.mjs +55 -0
  97. package/scripts/migrations/0.23.0-marche-du-projet.mjs +82 -0
  98. package/scripts/migrations.mjs +43 -0
  99. package/scripts/nuit.sh +269 -0
  100. package/scripts/paquets.mjs +79 -0
  101. package/scripts/poussee-cles.mjs +46 -0
  102. package/scripts/preparation.mjs +84 -0
  103. package/scripts/references-par-les-types.mjs +420 -0
  104. package/scripts/registre.mjs +336 -0
  105. package/scripts/resultats.mjs +580 -0
  106. package/scripts/resumes.mjs +57 -0
  107. package/scripts/retirer-copie.sh +127 -0
  108. package/scripts/session-start.sh +203 -0
  109. package/scripts/sortie.mjs +155 -0
  110. package/scripts/sous-modules.sh +316 -0
  111. package/scripts/structure-guard.sh +27 -0
  112. package/scripts/superviseur.mjs +102 -0
  113. package/scripts/tableau.mjs +1886 -0
  114. package/scripts/tests.mjs +236 -0
  115. package/scripts/ticket.sh +23 -0
  116. package/scripts/turbo-des-paquets.mjs +899 -0
  117. package/scripts/un-commit-par-ticket.mjs +212 -0
  118. package/scripts/verifier.mjs +469 -0
  119. package/scripts/verrou-de-fichier.mjs +130 -0
  120. package/scripts/verrou-de-machine.mjs +211 -0
  121. package/scripts/verrous/commande.mjs +180 -0
  122. package/scripts/verrous/ticket-du-sous-agent.mjs +39 -0
  123. package/scripts/verrous/verrou.mjs +165 -0
  124. package/scripts/vitest-config/avancement.mjs +39 -0
  125. package/scripts/vitest-config/avancement.reporter.mjs +56 -0
  126. package/scripts/vitest-config/base-de-passe.mjs +128 -0
  127. package/scripts/vitest-config/base.d.ts +6 -0
  128. package/scripts/vitest-config/base.mjs +87 -0
  129. package/scripts/vitest-config/changements.mjs +173 -0
  130. package/scripts/vitest-config/cibles.mjs +207 -0
  131. package/scripts/vitest-config/duree.reporter.mjs +98 -0
  132. package/scripts/vitest-config/machine.setup.mjs +14 -0
  133. package/scripts/vitest-config/mesure.d.ts +6 -0
  134. package/scripts/vitest-config/mesure.mjs +13 -0
  135. package/scripts/vitest-config/mesure.setup.mjs +12 -0
  136. package/scripts/vitest-config/pression.mjs +90 -0
  137. package/scripts/vitest-config/resultats.mjs +23 -0
  138. package/scripts/vitest-config/resultats.setup.mjs +19 -0
  139. package/scripts/vitest.nuit.config.mjs +26 -0
  140. package/skills/developpeur/SKILL.md +175 -0
  141. package/skills/explorateur/SKILL.md +84 -0
  142. package/skills/grill/SKILL.md +238 -0
  143. package/skills/grill/references/releve-structurel.md +38 -0
  144. package/skills/mesure/SKILL.md +168 -0
  145. package/skills/pitmaster/SKILL.md +382 -0
  146. package/skills/pitmaster/references/cadre.md +119 -0
  147. package/skills/pitmaster/references/consigne-agent.md +308 -0
  148. package/skills/pitmaster/references/erreurs.md +25 -0
  149. package/skills/pitmaster/references/tour.md +124 -0
  150. package/skills/questionneur/SKILL.md +64 -0
  151. package/skills/redacteur/SKILL.md +84 -0
  152. package/skills/redacteur/references/documents-d-un-composant.md +105 -0
  153. package/skills/referent-technique/SKILL.md +145 -0
  154. package/skills/regulateur/SKILL.md +220 -0
  155. package/skills/release/SKILL.md +134 -0
  156. package/skills/release/scripts/update-version.cjs +92 -0
  157. package/skills/relecteur/SKILL.md +152 -0
  158. package/skills/relecteur/references/LICENSE-MIT +30 -0
  159. package/skills/relecteur/references/SOURCE.md +8 -0
  160. package/skills/relecteur/references/claims-check.md +14 -0
  161. package/skills/relecteur/references/deletion-check.md +14 -0
  162. package/skills/relecteur/references/edge-case-hunter.md +80 -0
  163. package/skills/relecteur/references/verification-gap.md +113 -0
  164. package/skills/testwriter/SKILL.md +187 -0
  165. package/types/index.d.ts +56 -0
  166. package/README.md +0 -3
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@your-scope/project-name",
3
+ "version": "1.0.0",
4
+ "description": "A brief description of your project",
5
+ "author": "Your Name <your.email@example.com>",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "project-name": "dist/index.js"
12
+ },
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "watch": "tsc --watch",
16
+ "dev": "tsx watch src/index.ts",
17
+ "start": "node dist/index.js",
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "grillhouse tests",
20
+ "test:watch": "vitest",
21
+ "test:coverage": "vitest run --coverage",
22
+ "lint": "eslint src tests --ext .ts,.js,.mjs",
23
+ "lint:fix": "eslint src tests --ext .ts,.js,.mjs --fix",
24
+ "format": "prettier --write \"src/**/*.{ts,js,mjs}\" \"tests/**/*.{ts,js,mjs}\"",
25
+ "format:check": "prettier --check \"src/**/*.{ts,js,mjs}\" \"tests/**/*.{ts,js,mjs}\"",
26
+ "prepare": "grillhouse hooks && npm run build",
27
+ "prepublishOnly": "npm run lint && npm run typecheck && npm run verifier && npm run build",
28
+ "daemon:start": "pm2 start ecosystem.config.cjs",
29
+ "daemon:stop": "pm2 stop project-name",
30
+ "daemon:restart": "pm2 restart project-name",
31
+ "daemon:logs": "pm2 logs project-name",
32
+ "daemon:status": "pm2 status",
33
+ "daemon:delete": "pm2 delete project-name",
34
+ "interfaces": "grillhouse index-interfaces",
35
+ "grillhouse:gardes": "grillhouse gardes-du-cadre",
36
+ "frontieres": "grillhouse frontieres",
37
+ "api": "grillhouse interfaces-contre-code --ecrire",
38
+ "tableau": "grillhouse tableau --texte",
39
+ "grillhouse:maj": "grillhouse maj",
40
+ "code-mort": "grillhouse code-mort",
41
+ "test:vitest": "vitest run",
42
+ "test:forcer": "grillhouse tests --force",
43
+ "verifier": "grillhouse verifier",
44
+ "grillhouse:dette:inscrire": "turbo run build && GRILLHOUSE_DETTE=inscrire npm run --silent grillhouse:gardes",
45
+ "grillhouse:dette:elaguer": "turbo run build && GRILLHOUSE_DETTE=elaguer npm run --silent grillhouse:gardes"
46
+ },
47
+ "keywords": [
48
+ "keyword1",
49
+ "keyword2",
50
+ "keyword3"
51
+ ],
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/your-username/project-name.git"
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/your-username/project-name/issues"
58
+ },
59
+ "homepage": "https://github.com/your-username/project-name#readme",
60
+ "files": [
61
+ "dist",
62
+ "README.md",
63
+ "LICENSE",
64
+ "docs"
65
+ ],
66
+ "engines": {
67
+ "node": ">=22.0.0"
68
+ },
69
+ "dependencies": {
70
+ "dotenv": "^16.4.0",
71
+ "zod": "^3.22.0"
72
+ },
73
+ "devDependencies": {
74
+ "@microsoft/api-extractor": "7.59.2",
75
+ "@types/node": "^20.0.0",
76
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
77
+ "@typescript-eslint/parser": "^7.0.0",
78
+ "@vitest/coverage-v8": "^2.1.9",
79
+ "dependency-cruiser": "18.4.0",
80
+ "eslint": "^8.57.0",
81
+ "knip": "^6.41.0",
82
+ "pm2": "^5.4.2",
83
+ "prettier": "^3.2.0",
84
+ "tsx": "^4.7.0",
85
+ "turbo": "2.11.8",
86
+ "typescript": "^5.3.3",
87
+ "vitest": "^2.0.0"
88
+ },
89
+ "packageManager": "npm@10.9.8"
90
+ }
@@ -0,0 +1,22 @@
1
+ # Suivi de la supervision
2
+
3
+ Tenu par la compétence `pitmaster`. Une question s'écrit ici dès qu'elle naît ; tranchée, elle en
4
+ sort et sa réponse va dans son ticket.
5
+
6
+ ## Dernier tour
7
+
8
+ - Date : aucun tour encore
9
+ - Agents lancés : aucun
10
+ - À vérifier au prochain tour : rien
11
+
12
+ ## R — à confirmer par le responsable
13
+
14
+ Chaque point : contexte, exemple, règle, recommandation, question, ticket.
15
+
16
+ ## S — à surveiller
17
+
18
+ Chaque point : ce qui se surveille, ce qui le fermera.
19
+
20
+ ## F — fermés
21
+
22
+ Chaque point : ce qui l'a fermé, le ticket.
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Application configuration
3
+ *
4
+ * Centralizes all configuration from environment variables
5
+ * with sensible defaults for development.
6
+ */
7
+
8
+ import { config as dotenvConfig } from 'dotenv';
9
+ import { z } from 'zod';
10
+
11
+ // Load environment variables
12
+ dotenvConfig();
13
+
14
+ /**
15
+ * Environment configuration schema
16
+ */
17
+ const envSchema = z.object({
18
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
19
+ PORT: z.string().transform(Number).default('3000'),
20
+ LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
21
+ });
22
+
23
+ /**
24
+ * Parse and validate environment variables
25
+ */
26
+ function parseEnv() {
27
+ const result = envSchema.safeParse(process.env);
28
+
29
+ if (!result.success) {
30
+ console.error('Invalid environment configuration:');
31
+ console.error(result.error.format());
32
+ process.exit(1);
33
+ }
34
+
35
+ return result.data;
36
+ }
37
+
38
+ const env = parseEnv();
39
+
40
+ /**
41
+ * Application configuration object
42
+ */
43
+ export const config = {
44
+ /** Application version from package.json */
45
+ version: '1.0.0',
46
+
47
+ /** Current environment */
48
+ env: env.NODE_ENV,
49
+
50
+ /** Is development mode */
51
+ isDev: env.NODE_ENV === 'development',
52
+
53
+ /** Is production mode */
54
+ isProd: env.NODE_ENV === 'production',
55
+
56
+ /** Is test mode */
57
+ isTest: env.NODE_ENV === 'test',
58
+
59
+ /** Server configuration */
60
+ server: {
61
+ port: env.PORT,
62
+ },
63
+
64
+ /** Logging configuration */
65
+ logging: {
66
+ level: env.LOG_LEVEL,
67
+ },
68
+ } as const;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Custom error classes
3
+ *
4
+ * Define application-specific errors for better error handling.
5
+ */
6
+
7
+ /**
8
+ * Base application error
9
+ */
10
+ export class AppError extends Error {
11
+ public readonly code: string;
12
+ public readonly statusCode: number;
13
+ public readonly isOperational: boolean;
14
+
15
+ constructor(message: string, code = 'INTERNAL_ERROR', statusCode = 500, isOperational = true) {
16
+ super(message);
17
+ this.name = this.constructor.name;
18
+ this.code = code;
19
+ this.statusCode = statusCode;
20
+ this.isOperational = isOperational;
21
+
22
+ // Maintains proper stack trace
23
+ Error.captureStackTrace(this, this.constructor);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Validation error (400)
29
+ */
30
+ export class ValidationError extends AppError {
31
+ constructor(message: string) {
32
+ super(message, 'VALIDATION_ERROR', 400);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Not found error (404)
38
+ */
39
+ export class NotFoundError extends AppError {
40
+ constructor(resource: string) {
41
+ super(`${resource} not found`, 'NOT_FOUND', 404);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Authentication error (401)
47
+ */
48
+ export class AuthenticationError extends AppError {
49
+ constructor(message = 'Authentication required') {
50
+ super(message, 'AUTHENTICATION_ERROR', 401);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Authorization error (403)
56
+ */
57
+ export class AuthorizationError extends AppError {
58
+ constructor(message = 'Permission denied') {
59
+ super(message, 'AUTHORIZATION_ERROR', 403);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Conflict error (409)
65
+ */
66
+ export class ConflictError extends AppError {
67
+ constructor(message: string) {
68
+ super(message, 'CONFLICT_ERROR', 409);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Rate limit error (429)
74
+ */
75
+ export class RateLimitError extends AppError {
76
+ constructor(message = 'Too many requests') {
77
+ super(message, 'RATE_LIMIT_ERROR', 429);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * External service error (502)
83
+ */
84
+ export class ExternalServiceError extends AppError {
85
+ constructor(service: string, originalError?: Error) {
86
+ super(
87
+ `External service error: ${service}${originalError ? ` - ${originalError.message}` : ''}`,
88
+ 'EXTERNAL_SERVICE_ERROR',
89
+ 502
90
+ );
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Check if error is operational (expected) vs programming error
96
+ */
97
+ export function isOperationalError(error: unknown): boolean {
98
+ if (error instanceof AppError) {
99
+ return error.isOperational;
100
+ }
101
+ return false;
102
+ }
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main entry point
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+
8
+ import { config } from './config.js';
9
+ import { logger } from './utils/logger.js';
10
+
11
+ /**
12
+ * Main application function
13
+ */
14
+ function main(): void {
15
+ logger.info('Application starting...', { version: config.version });
16
+
17
+ try {
18
+ // Initialize your application here
19
+ logger.info('Application started successfully');
20
+
21
+ // Keep the process running (remove if not needed)
22
+ // await new Promise(() => {});
23
+ } catch (error) {
24
+ logger.error('Application failed to start', { error });
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ // Handle graceful shutdown
30
+ process.on('SIGINT', () => {
31
+ logger.info('Received SIGINT, shutting down...');
32
+ process.exit(0);
33
+ });
34
+
35
+ process.on('SIGTERM', () => {
36
+ logger.info('Received SIGTERM, shutting down...');
37
+ process.exit(0);
38
+ });
39
+
40
+ // Handle unhandled rejections
41
+ process.on('unhandledRejection', (reason, promise) => {
42
+ logger.error('Unhandled Rejection', { reason, promise });
43
+ });
44
+
45
+ // Run main
46
+ main();
@@ -0,0 +1,8 @@
1
+ # This file keeps the empty directory in git.
2
+ # Add your service modules here.
3
+ #
4
+ # Example services:
5
+ # - api-client.ts - External API client
6
+ # - database.ts - Database connection
7
+ # - cache.ts - Caching service
8
+ # - queue.ts - Message queue service
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Type definitions
3
+ *
4
+ * Export all shared types from this module.
5
+ */
6
+
7
+ /**
8
+ * Generic result type for operations that can fail
9
+ */
10
+ export type Result<T, E = Error> = { success: true; data: T } | { success: false; error: E };
11
+
12
+ /**
13
+ * Create a success result
14
+ */
15
+ export function success<T>(data: T): Result<T, never> {
16
+ return { success: true, data };
17
+ }
18
+
19
+ /**
20
+ * Create a failure result
21
+ */
22
+ export function failure<E>(error: E): Result<never, E> {
23
+ return { success: false, error };
24
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Logger utility
3
+ *
4
+ * Simple structured logging with levels and context.
5
+ */
6
+
7
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
8
+
9
+ interface LogContext {
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ const LOG_LEVELS: Record<LogLevel, number> = {
14
+ debug: 0,
15
+ info: 1,
16
+ warn: 2,
17
+ error: 3,
18
+ };
19
+
20
+ /**
21
+ * Get current log level from environment
22
+ */
23
+ function getCurrentLevel(): LogLevel {
24
+ const level = process.env.LOG_LEVEL?.toLowerCase() as LogLevel;
25
+ return LOG_LEVELS[level] !== undefined ? level : 'info';
26
+ }
27
+
28
+ /**
29
+ * Format log message with timestamp and context
30
+ */
31
+ function formatMessage(level: LogLevel, message: string, context?: LogContext): string {
32
+ const timestamp = new Date().toISOString();
33
+ const levelStr = level.toUpperCase().padEnd(5);
34
+
35
+ let output = `[${timestamp}] ${levelStr} ${message}`;
36
+
37
+ if (context && Object.keys(context).length > 0) {
38
+ output += ` ${JSON.stringify(context)}`;
39
+ }
40
+
41
+ return output;
42
+ }
43
+
44
+ /**
45
+ * Check if log level should be output
46
+ */
47
+ function shouldLog(level: LogLevel): boolean {
48
+ return LOG_LEVELS[level] >= LOG_LEVELS[getCurrentLevel()];
49
+ }
50
+
51
+ /**
52
+ * Logger instance
53
+ */
54
+ export const logger = {
55
+ /**
56
+ * Log debug message
57
+ */
58
+ debug(message: string, context?: LogContext): void {
59
+ if (shouldLog('debug')) {
60
+ console.debug(formatMessage('debug', message, context));
61
+ }
62
+ },
63
+
64
+ /**
65
+ * Log info message
66
+ */
67
+ info(message: string, context?: LogContext): void {
68
+ if (shouldLog('info')) {
69
+ console.info(formatMessage('info', message, context));
70
+ }
71
+ },
72
+
73
+ /**
74
+ * Log warning message
75
+ */
76
+ warn(message: string, context?: LogContext): void {
77
+ if (shouldLog('warn')) {
78
+ console.warn(formatMessage('warn', message, context));
79
+ }
80
+ },
81
+
82
+ /**
83
+ * Log error message
84
+ */
85
+ error(message: string, context?: LogContext): void {
86
+ if (shouldLog('error')) {
87
+ console.error(formatMessage('error', message, context));
88
+ }
89
+ },
90
+
91
+ /**
92
+ * Create a child logger with preset context
93
+ */
94
+ child(baseContext: LogContext) {
95
+ return {
96
+ debug: (message: string, context?: LogContext) =>
97
+ logger.debug(message, { ...baseContext, ...context }),
98
+ info: (message: string, context?: LogContext) =>
99
+ logger.info(message, { ...baseContext, ...context }),
100
+ warn: (message: string, context?: LogContext) =>
101
+ logger.warn(message, { ...baseContext, ...context }),
102
+ error: (message: string, context?: LogContext) =>
103
+ logger.error(message, { ...baseContext, ...context }),
104
+ };
105
+ },
106
+ };
@@ -0,0 +1,7 @@
1
+ # This file keeps the empty directory in git.
2
+ # Add your integration tests here.
3
+ #
4
+ # Example integration tests:
5
+ # - api.spec.ts - API endpoint tests
6
+ # - database.spec.ts - Database integration tests
7
+ # - external.spec.ts - External service tests
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Config module tests
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+
7
+ describe('Config', () => {
8
+ const originalEnv = process.env;
9
+
10
+ beforeEach(() => {
11
+ // Reset modules to get fresh config
12
+ vi.resetModules();
13
+ process.env = { ...originalEnv };
14
+ });
15
+
16
+ afterEach(() => {
17
+ process.env = originalEnv;
18
+ });
19
+
20
+ describe('environment detection', () => {
21
+ it('should default to development', async () => {
22
+ delete process.env.NODE_ENV;
23
+ const { config } = await import('../../src/config.js');
24
+ expect(config.isDev).toBe(true);
25
+ });
26
+
27
+ it('should detect production environment', async () => {
28
+ process.env.NODE_ENV = 'production';
29
+ const { config } = await import('../../src/config.js');
30
+ expect(config.isProd).toBe(true);
31
+ expect(config.isDev).toBe(false);
32
+ });
33
+
34
+ it('should detect test environment', async () => {
35
+ process.env.NODE_ENV = 'test';
36
+ const { config } = await import('../../src/config.js');
37
+ expect(config.isTest).toBe(true);
38
+ });
39
+ });
40
+
41
+ describe('server configuration', () => {
42
+ it('should use default port', async () => {
43
+ delete process.env.PORT;
44
+ const { config } = await import('../../src/config.js');
45
+ expect(config.server.port).toBe(3000);
46
+ });
47
+
48
+ it('should use custom port from environment', async () => {
49
+ process.env.PORT = '8080';
50
+ const { config } = await import('../../src/config.js');
51
+ expect(config.server.port).toBe(8080);
52
+ });
53
+ });
54
+
55
+ describe('logging configuration', () => {
56
+ it('should default to info log level', async () => {
57
+ delete process.env.LOG_LEVEL;
58
+ const { config } = await import('../../src/config.js');
59
+ expect(config.logging.level).toBe('info');
60
+ });
61
+
62
+ it('should use custom log level', async () => {
63
+ process.env.LOG_LEVEL = 'debug';
64
+ const { config } = await import('../../src/config.js');
65
+ expect(config.logging.level).toBe('debug');
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Error classes tests
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import {
7
+ AppError,
8
+ ValidationError,
9
+ NotFoundError,
10
+ AuthenticationError,
11
+ AuthorizationError,
12
+ ConflictError,
13
+ RateLimitError,
14
+ ExternalServiceError,
15
+ isOperationalError,
16
+ } from '../../src/errors.js';
17
+
18
+ describe('Error Classes', () => {
19
+ describe('AppError', () => {
20
+ it('should create error with default values', () => {
21
+ const error = new AppError('Test error');
22
+ expect(error.message).toBe('Test error');
23
+ expect(error.code).toBe('INTERNAL_ERROR');
24
+ expect(error.statusCode).toBe(500);
25
+ expect(error.isOperational).toBe(true);
26
+ });
27
+
28
+ it('should create error with custom values', () => {
29
+ const error = new AppError('Custom error', 'CUSTOM_CODE', 418, false);
30
+ expect(error.message).toBe('Custom error');
31
+ expect(error.code).toBe('CUSTOM_CODE');
32
+ expect(error.statusCode).toBe(418);
33
+ expect(error.isOperational).toBe(false);
34
+ });
35
+
36
+ it('should have proper stack trace', () => {
37
+ const error = new AppError('Test');
38
+ expect(error.stack).toBeDefined();
39
+ expect(error.stack).toContain('AppError');
40
+ });
41
+ });
42
+
43
+ describe('ValidationError', () => {
44
+ it('should create validation error', () => {
45
+ const error = new ValidationError('Invalid input');
46
+ expect(error.message).toBe('Invalid input');
47
+ expect(error.code).toBe('VALIDATION_ERROR');
48
+ expect(error.statusCode).toBe(400);
49
+ });
50
+ });
51
+
52
+ describe('NotFoundError', () => {
53
+ it('should create not found error', () => {
54
+ const error = new NotFoundError('User');
55
+ expect(error.message).toBe('User not found');
56
+ expect(error.code).toBe('NOT_FOUND');
57
+ expect(error.statusCode).toBe(404);
58
+ });
59
+ });
60
+
61
+ describe('AuthenticationError', () => {
62
+ it('should create authentication error with default message', () => {
63
+ const error = new AuthenticationError();
64
+ expect(error.message).toBe('Authentication required');
65
+ expect(error.statusCode).toBe(401);
66
+ });
67
+
68
+ it('should create authentication error with custom message', () => {
69
+ const error = new AuthenticationError('Invalid token');
70
+ expect(error.message).toBe('Invalid token');
71
+ });
72
+ });
73
+
74
+ describe('AuthorizationError', () => {
75
+ it('should create authorization error', () => {
76
+ const error = new AuthorizationError();
77
+ expect(error.message).toBe('Permission denied');
78
+ expect(error.statusCode).toBe(403);
79
+ });
80
+ });
81
+
82
+ describe('ConflictError', () => {
83
+ it('should create conflict error', () => {
84
+ const error = new ConflictError('Resource already exists');
85
+ expect(error.statusCode).toBe(409);
86
+ });
87
+ });
88
+
89
+ describe('RateLimitError', () => {
90
+ it('should create rate limit error', () => {
91
+ const error = new RateLimitError();
92
+ expect(error.statusCode).toBe(429);
93
+ });
94
+ });
95
+
96
+ describe('ExternalServiceError', () => {
97
+ it('should create external service error', () => {
98
+ const error = new ExternalServiceError('PaymentAPI');
99
+ expect(error.message).toBe('External service error: PaymentAPI');
100
+ expect(error.statusCode).toBe(502);
101
+ });
102
+
103
+ it('should include original error message', () => {
104
+ const original = new Error('Connection timeout');
105
+ const error = new ExternalServiceError('PaymentAPI', original);
106
+ expect(error.message).toBe('External service error: PaymentAPI - Connection timeout');
107
+ });
108
+ });
109
+
110
+ describe('isOperationalError', () => {
111
+ it('should return true for operational errors', () => {
112
+ const error = new AppError('Test', 'TEST', 400, true);
113
+ expect(isOperationalError(error)).toBe(true);
114
+ });
115
+
116
+ it('should return false for non-operational errors', () => {
117
+ const error = new AppError('Test', 'TEST', 500, false);
118
+ expect(isOperationalError(error)).toBe(false);
119
+ });
120
+
121
+ it('should return false for standard errors', () => {
122
+ const error = new Error('Standard error');
123
+ expect(isOperationalError(error)).toBe(false);
124
+ });
125
+
126
+ it('should return false for non-error values', () => {
127
+ expect(isOperationalError(null)).toBe(false);
128
+ expect(isOperationalError(undefined)).toBe(false);
129
+ expect(isOperationalError('string')).toBe(false);
130
+ });
131
+ });
132
+ });