@drmxrcy/tcg-core 0.0.0-202602060542

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 (157) hide show
  1. package/README.md +882 -0
  2. package/package.json +58 -0
  3. package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
  4. package/src/__tests__/createMockAlphaClashGame.ts +462 -0
  5. package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
  6. package/src/__tests__/createMockGundamGame.ts +379 -0
  7. package/src/__tests__/createMockLorcanaGame.ts +328 -0
  8. package/src/__tests__/createMockOnePieceGame.ts +429 -0
  9. package/src/__tests__/createMockRiftboundGame.ts +462 -0
  10. package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
  11. package/src/__tests__/gundam-engine-definition.test.ts +110 -0
  12. package/src/__tests__/integration-complete-game.test.ts +508 -0
  13. package/src/__tests__/integration-network-sync.test.ts +469 -0
  14. package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
  15. package/src/__tests__/move-enumeration.test.ts +725 -0
  16. package/src/__tests__/multiplayer-engine.test.ts +555 -0
  17. package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
  18. package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
  19. package/src/actions/action-definition.test.ts +201 -0
  20. package/src/actions/action-definition.ts +122 -0
  21. package/src/actions/action-timing.test.ts +490 -0
  22. package/src/actions/action-timing.ts +257 -0
  23. package/src/cards/card-definition.test.ts +268 -0
  24. package/src/cards/card-definition.ts +27 -0
  25. package/src/cards/card-instance.test.ts +422 -0
  26. package/src/cards/card-instance.ts +49 -0
  27. package/src/cards/computed-properties.test.ts +530 -0
  28. package/src/cards/computed-properties.ts +84 -0
  29. package/src/cards/conditional-modifiers.test.ts +390 -0
  30. package/src/cards/modifiers.test.ts +286 -0
  31. package/src/cards/modifiers.ts +51 -0
  32. package/src/engine/MULTIPLAYER.md +425 -0
  33. package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
  34. package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
  35. package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
  36. package/src/engine/__tests__/rule-engine.test.ts +366 -0
  37. package/src/engine/index.ts +14 -0
  38. package/src/engine/multiplayer-engine.example.ts +571 -0
  39. package/src/engine/multiplayer-engine.ts +409 -0
  40. package/src/engine/rule-engine.test.ts +286 -0
  41. package/src/engine/rule-engine.ts +1539 -0
  42. package/src/engine/tracker-system.ts +172 -0
  43. package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
  44. package/src/filtering/card-filter.test.ts +230 -0
  45. package/src/filtering/card-filter.ts +91 -0
  46. package/src/filtering/card-query.test.ts +901 -0
  47. package/src/filtering/card-query.ts +273 -0
  48. package/src/filtering/filter-matching.test.ts +944 -0
  49. package/src/filtering/filter-matching.ts +315 -0
  50. package/src/flow/SERIALIZATION.md +428 -0
  51. package/src/flow/__tests__/flow-definition.test.ts +427 -0
  52. package/src/flow/__tests__/flow-manager.test.ts +756 -0
  53. package/src/flow/__tests__/flow-serialization.test.ts +565 -0
  54. package/src/flow/flow-definition.ts +453 -0
  55. package/src/flow/flow-manager.ts +1044 -0
  56. package/src/flow/index.ts +35 -0
  57. package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
  58. package/src/game-definition/__tests__/game-definition.test.ts +291 -0
  59. package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
  60. package/src/game-definition/game-definition.ts +261 -0
  61. package/src/game-definition/index.ts +28 -0
  62. package/src/game-definition/move-definitions.ts +188 -0
  63. package/src/game-definition/validation.ts +183 -0
  64. package/src/history/history-manager.test.ts +497 -0
  65. package/src/history/history-manager.ts +312 -0
  66. package/src/history/history-operations.ts +122 -0
  67. package/src/history/index.ts +9 -0
  68. package/src/history/types.ts +255 -0
  69. package/src/index.ts +32 -0
  70. package/src/logging/index.ts +27 -0
  71. package/src/logging/log-formatter.ts +187 -0
  72. package/src/logging/logger.ts +276 -0
  73. package/src/logging/types.ts +148 -0
  74. package/src/moves/create-move.test.ts +331 -0
  75. package/src/moves/create-move.ts +64 -0
  76. package/src/moves/move-enumeration.ts +228 -0
  77. package/src/moves/move-executor.test.ts +431 -0
  78. package/src/moves/move-executor.ts +195 -0
  79. package/src/moves/move-system.test.ts +380 -0
  80. package/src/moves/move-system.ts +463 -0
  81. package/src/moves/standard-moves.ts +231 -0
  82. package/src/operations/card-operations.test.ts +236 -0
  83. package/src/operations/card-operations.ts +116 -0
  84. package/src/operations/card-registry-impl.test.ts +251 -0
  85. package/src/operations/card-registry-impl.ts +70 -0
  86. package/src/operations/card-registry.test.ts +234 -0
  87. package/src/operations/card-registry.ts +106 -0
  88. package/src/operations/counter-operations.ts +152 -0
  89. package/src/operations/game-operations.test.ts +280 -0
  90. package/src/operations/game-operations.ts +140 -0
  91. package/src/operations/index.ts +24 -0
  92. package/src/operations/operations-impl.test.ts +354 -0
  93. package/src/operations/operations-impl.ts +468 -0
  94. package/src/operations/zone-operations.test.ts +295 -0
  95. package/src/operations/zone-operations.ts +223 -0
  96. package/src/rng/seeded-rng.test.ts +339 -0
  97. package/src/rng/seeded-rng.ts +123 -0
  98. package/src/targeting/index.ts +48 -0
  99. package/src/targeting/target-definition.test.ts +273 -0
  100. package/src/targeting/target-definition.ts +37 -0
  101. package/src/targeting/target-dsl.ts +279 -0
  102. package/src/targeting/target-resolver.ts +486 -0
  103. package/src/targeting/target-validation.test.ts +994 -0
  104. package/src/targeting/target-validation.ts +286 -0
  105. package/src/telemetry/events.ts +202 -0
  106. package/src/telemetry/index.ts +21 -0
  107. package/src/telemetry/telemetry-manager.ts +127 -0
  108. package/src/telemetry/types.ts +68 -0
  109. package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
  110. package/src/testing/index.ts +88 -0
  111. package/src/testing/test-assertions.test.ts +341 -0
  112. package/src/testing/test-assertions.ts +256 -0
  113. package/src/testing/test-card-factory.test.ts +228 -0
  114. package/src/testing/test-card-factory.ts +111 -0
  115. package/src/testing/test-context-factory.ts +187 -0
  116. package/src/testing/test-end-assertions.test.ts +262 -0
  117. package/src/testing/test-end-assertions.ts +95 -0
  118. package/src/testing/test-engine-builder.test.ts +389 -0
  119. package/src/testing/test-engine-builder.ts +46 -0
  120. package/src/testing/test-flow-assertions.test.ts +284 -0
  121. package/src/testing/test-flow-assertions.ts +115 -0
  122. package/src/testing/test-player-builder.test.ts +132 -0
  123. package/src/testing/test-player-builder.ts +46 -0
  124. package/src/testing/test-replay-assertions.test.ts +356 -0
  125. package/src/testing/test-replay-assertions.ts +164 -0
  126. package/src/testing/test-rng-helpers.test.ts +260 -0
  127. package/src/testing/test-rng-helpers.ts +190 -0
  128. package/src/testing/test-state-builder.test.ts +373 -0
  129. package/src/testing/test-state-builder.ts +99 -0
  130. package/src/testing/test-zone-factory.test.ts +295 -0
  131. package/src/testing/test-zone-factory.ts +224 -0
  132. package/src/types/branded-utils.ts +54 -0
  133. package/src/types/branded.test.ts +175 -0
  134. package/src/types/branded.ts +33 -0
  135. package/src/types/index.ts +8 -0
  136. package/src/types/state.test.ts +198 -0
  137. package/src/types/state.ts +154 -0
  138. package/src/validation/card-type-guards.test.ts +242 -0
  139. package/src/validation/card-type-guards.ts +179 -0
  140. package/src/validation/index.ts +40 -0
  141. package/src/validation/schema-builders.test.ts +403 -0
  142. package/src/validation/schema-builders.ts +345 -0
  143. package/src/validation/type-guard-builder.test.ts +216 -0
  144. package/src/validation/type-guard-builder.ts +109 -0
  145. package/src/validation/validator-builder.test.ts +375 -0
  146. package/src/validation/validator-builder.ts +273 -0
  147. package/src/zones/index.ts +28 -0
  148. package/src/zones/zone-factory.test.ts +183 -0
  149. package/src/zones/zone-factory.ts +44 -0
  150. package/src/zones/zone-operations.test.ts +800 -0
  151. package/src/zones/zone-operations.ts +306 -0
  152. package/src/zones/zone-state-helpers.test.ts +337 -0
  153. package/src/zones/zone-state-helpers.ts +128 -0
  154. package/src/zones/zone-visibility.test.ts +156 -0
  155. package/src/zones/zone-visibility.ts +36 -0
  156. package/src/zones/zone.test.ts +186 -0
  157. package/src/zones/zone.ts +66 -0
package/src/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @drmxrcy/tcg-core - Core TCG Engine Framework
3
+ *
4
+ * A declarative, type-safe framework for building trading card game engines.
5
+ */
6
+
7
+ export * from "./actions/action-definition";
8
+ export * from "./actions/action-timing";
9
+ export * from "./cards/card-definition";
10
+ export * from "./cards/card-instance";
11
+ export * from "./cards/computed-properties";
12
+ export * from "./cards/modifiers";
13
+ export * from "./engine";
14
+ export * from "./engine/tracker-system";
15
+ export * from "./filtering/card-filter";
16
+ export * from "./filtering/card-query";
17
+ export * from "./filtering/filter-matching";
18
+ export * from "./flow";
19
+ export * from "./game-definition";
20
+ export * from "./history";
21
+ export * from "./logging";
22
+ export * from "./moves/create-move";
23
+ export * from "./moves/move-enumeration";
24
+ export * from "./moves/move-executor";
25
+ export * from "./moves/move-system";
26
+ export * from "./moves/standard-moves";
27
+ export * from "./operations";
28
+ export * from "./rng/seeded-rng";
29
+ export * from "./targeting";
30
+ export * from "./telemetry";
31
+ export * from "./types";
32
+ export * from "./zones";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Logging Module
3
+ *
4
+ * Production-grade structured logging for TCG Core.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { Logger, LogLevel } from '@drmxrcy/tcg-core/logging';
9
+ *
10
+ * const logger = new Logger({
11
+ * level: 'DEVELOPER',
12
+ * pretty: true
13
+ * });
14
+ *
15
+ * logger.info('Game started', { players: 2 });
16
+ * logger.debug('Move validated', { moveId, validationResult });
17
+ * ```
18
+ */
19
+
20
+ export { createPinoFormatter, formatMessage } from "./log-formatter";
21
+ export { Logger } from "./logger";
22
+ export {
23
+ type LogContext,
24
+ type LoggerOptions,
25
+ LogLevel,
26
+ type VerbosityPreset,
27
+ } from "./types";
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Log Formatter
3
+ *
4
+ * Custom formatters for player-friendly log messages.
5
+ * Transforms internal engine events into readable output.
6
+ */
7
+
8
+ import type { LogContext, VerbosityPreset } from "./types";
9
+
10
+ /**
11
+ * Format log message for player-friendly output
12
+ *
13
+ * Transforms raw log messages and context into readable format
14
+ * based on the current verbosity level.
15
+ *
16
+ * @param message - Raw log message
17
+ * @param context - Log context with metadata
18
+ * @param level - Current verbosity preset
19
+ * @returns Formatted message string
20
+ */
21
+ export function formatMessage(
22
+ message: string,
23
+ context: LogContext,
24
+ level: VerbosityPreset,
25
+ ): string {
26
+ // For SILENT, return empty (should never be called)
27
+ if (level === "SILENT") {
28
+ return "";
29
+ }
30
+
31
+ // NORMAL_PLAYER: Simple, clear messages
32
+ if (level === "NORMAL_PLAYER") {
33
+ return formatForNormalPlayer(message, context);
34
+ }
35
+
36
+ // ADVANCED_PLAYER: Include game mechanics details
37
+ if (level === "ADVANCED_PLAYER") {
38
+ return formatForAdvancedPlayer(message, context);
39
+ }
40
+
41
+ // DEVELOPER: Full internal details
42
+ return formatForDeveloper(message, context);
43
+ }
44
+
45
+ /**
46
+ * Format message for normal players
47
+ *
48
+ * Focus on basic game events without technical details.
49
+ * Examples: "Card played", "Turn ended", "Player drew 2 cards"
50
+ */
51
+ function formatForNormalPlayer(message: string, context: LogContext): string {
52
+ let formatted = message;
53
+
54
+ // Add player context if available
55
+ if (context.playerId) {
56
+ formatted = `[Player ${context.playerId}] ${formatted}`;
57
+ }
58
+
59
+ // Add turn context if available
60
+ if (context.turn !== undefined) {
61
+ formatted = `[Turn ${context.turn}] ${formatted}`;
62
+ }
63
+
64
+ return formatted;
65
+ }
66
+
67
+ /**
68
+ * Format message for advanced players
69
+ *
70
+ * Include game mechanics and rule details.
71
+ * Examples: "Card played (cost: 3 mana)", "Phase transition: Main -> Combat"
72
+ */
73
+ function formatForAdvancedPlayer(message: string, context: LogContext): string {
74
+ let formatted = message;
75
+
76
+ // Add comprehensive game state context
77
+ const contextParts: string[] = [];
78
+
79
+ if (context.turn !== undefined) {
80
+ contextParts.push(`Turn ${context.turn}`);
81
+ }
82
+
83
+ if (context.phase) {
84
+ contextParts.push(`Phase: ${context.phase}`);
85
+ }
86
+
87
+ if (context.playerId) {
88
+ contextParts.push(`Player: ${context.playerId}`);
89
+ }
90
+
91
+ if (contextParts.length > 0) {
92
+ formatted = `[${contextParts.join(" | ")}] ${formatted}`;
93
+ }
94
+
95
+ // Add duration for performance-sensitive operations
96
+ if (context.duration !== undefined) {
97
+ formatted += ` (${context.duration}ms)`;
98
+ }
99
+
100
+ return formatted;
101
+ }
102
+
103
+ /**
104
+ * Format message for developers
105
+ *
106
+ * Include all internal details for debugging.
107
+ * Examples: Full context object, stack traces, state diffs
108
+ */
109
+ function formatForDeveloper(message: string, context: LogContext): string {
110
+ let formatted = message;
111
+
112
+ // Add full context breadcrumbs
113
+ const contextParts: string[] = [];
114
+
115
+ if (context.turn !== undefined) {
116
+ contextParts.push(`T${context.turn}`);
117
+ }
118
+
119
+ if (context.segment) {
120
+ contextParts.push(`S:${context.segment}`);
121
+ }
122
+
123
+ if (context.phase) {
124
+ contextParts.push(`P:${context.phase}`);
125
+ }
126
+
127
+ if (context.playerId) {
128
+ contextParts.push(`Player:${context.playerId}`);
129
+ }
130
+
131
+ if (context.moveId) {
132
+ contextParts.push(`Move:${context.moveId}`);
133
+ }
134
+
135
+ if (contextParts.length > 0) {
136
+ formatted = `[${contextParts.join("|")}] ${formatted}`;
137
+ }
138
+
139
+ // Add performance metrics
140
+ if (context.duration !== undefined) {
141
+ formatted += ` [${context.duration}ms]`;
142
+ }
143
+
144
+ if (context.patchCount !== undefined) {
145
+ formatted += ` [${context.patchCount} patches]`;
146
+ }
147
+
148
+ // Add error details
149
+ if (context.errorCode) {
150
+ formatted += ` [${context.errorCode}]`;
151
+ }
152
+
153
+ return formatted;
154
+ }
155
+
156
+ /**
157
+ * Create Pino formatter options
158
+ *
159
+ * Returns Pino transport configuration for pretty printing
160
+ * based on verbosity level.
161
+ *
162
+ * @param level - Verbosity preset
163
+ * @returns Pino transport options
164
+ */
165
+ export function createPinoFormatter(level: VerbosityPreset): unknown {
166
+ // For SILENT, no formatter needed
167
+ if (level === "SILENT") {
168
+ return undefined;
169
+ }
170
+
171
+ // Configure pino-pretty for human-readable output
172
+ return {
173
+ target: "pino-pretty",
174
+ options: {
175
+ colorize: true,
176
+ translateTime: "HH:MM:ss.l",
177
+ ignore: "pid,hostname",
178
+ // Customize format based on level
179
+ messageFormat:
180
+ level === "DEVELOPER"
181
+ ? "{msg} {context}"
182
+ : level === "ADVANCED_PLAYER"
183
+ ? "{msg}"
184
+ : "{msg}",
185
+ },
186
+ };
187
+ }
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Logger Class
3
+ *
4
+ * Core logging implementation wrapping Pino with TCG-specific features.
5
+ * Provides structured logging with configurable verbosity levels.
6
+ */
7
+
8
+ import pino, { type Logger as PinoLogger } from "pino";
9
+ import { type LogContext, type LoggerOptions, LogLevel } from "./types";
10
+
11
+ /**
12
+ * Logger
13
+ *
14
+ * Structured logger with verbosity control and child logger support.
15
+ *
16
+ * Features:
17
+ * - Zero-overhead SILENT mode
18
+ * - Child loggers with namespace isolation
19
+ * - Structured context merging
20
+ * - Preset-based verbosity levels
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const logger = new Logger({ level: 'DEVELOPER', pretty: true });
25
+ *
26
+ * logger.info('Game started', { players: 2 });
27
+ * logger.debug('Move executed', { moveId: 'playCard', duration: 15 });
28
+ *
29
+ * const childLogger = logger.child('flow');
30
+ * childLogger.info('Phase transition', { from: 'main', to: 'combat' });
31
+ * ```
32
+ */
33
+ export class Logger {
34
+ private pinoLogger: PinoLogger | null;
35
+ private currentLevel: LogLevel;
36
+ private namespace?: string;
37
+
38
+ /**
39
+ * Create a new Logger instance
40
+ *
41
+ * @param options - Logger configuration
42
+ */
43
+ constructor(options: LoggerOptions = {}) {
44
+ const level = options.level ?? "SILENT";
45
+
46
+ // Map preset/level to numeric LogLevel
47
+ this.currentLevel = this.mapToLogLevel(level);
48
+
49
+ // For SILENT mode, skip Pino initialization entirely (zero overhead)
50
+ if (this.currentLevel === LogLevel.SILENT) {
51
+ this.pinoLogger = null;
52
+ return;
53
+ }
54
+
55
+ // Map to Pino level strings
56
+ const pinoLevel = this.mapToPinoLevel(this.currentLevel);
57
+
58
+ // Configure Pino
59
+ const { level: _, ...restOptions } = options;
60
+ const pinoOptions: pino.LoggerOptions = {
61
+ level: pinoLevel,
62
+ ...restOptions,
63
+ };
64
+
65
+ // Add pretty printing if requested
66
+ if (options.pretty !== false) {
67
+ pinoOptions.transport = {
68
+ target: "pino-pretty",
69
+ options: {
70
+ colorize: true,
71
+ translateTime: "HH:MM:ss.l",
72
+ ignore: "pid,hostname",
73
+ },
74
+ };
75
+ }
76
+
77
+ // Create Pino logger
78
+ this.pinoLogger = pino(pinoOptions);
79
+ }
80
+
81
+ /**
82
+ * Map preset or numeric level to LogLevel enum
83
+ */
84
+ private mapToLogLevel(level: string | LogLevel): LogLevel {
85
+ if (typeof level === "number") {
86
+ return level;
87
+ }
88
+
89
+ // Map preset strings to LogLevel
90
+ const presetMap: Record<string, LogLevel> = {
91
+ SILENT: LogLevel.SILENT,
92
+ NORMAL_PLAYER: LogLevel.INFO,
93
+ ADVANCED_PLAYER: LogLevel.DEBUG,
94
+ DEVELOPER: LogLevel.TRACE,
95
+ };
96
+
97
+ return presetMap[level] ?? LogLevel.SILENT;
98
+ }
99
+
100
+ /**
101
+ * Map LogLevel to Pino level string
102
+ */
103
+ private mapToPinoLevel(level: LogLevel): pino.Level | "silent" {
104
+ const levelMap: Record<LogLevel, pino.Level | "silent"> = {
105
+ [LogLevel.SILENT]: "silent",
106
+ [LogLevel.ERROR]: "error",
107
+ [LogLevel.WARN]: "warn",
108
+ [LogLevel.INFO]: "info",
109
+ [LogLevel.DEBUG]: "debug",
110
+ [LogLevel.TRACE]: "trace",
111
+ };
112
+
113
+ return levelMap[level] ?? "silent";
114
+ }
115
+
116
+ /**
117
+ * Check if a specific level is enabled
118
+ */
119
+ private isLevelEnabled(level: LogLevel): boolean {
120
+ return this.currentLevel >= level;
121
+ }
122
+
123
+ /**
124
+ * Merge namespace into context
125
+ */
126
+ private mergeContext(context?: LogContext): LogContext {
127
+ if (!this.namespace) {
128
+ return context ?? {};
129
+ }
130
+
131
+ return {
132
+ namespace: this.namespace,
133
+ ...context,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Log trace message (TRACE level)
139
+ *
140
+ * Most verbose logging for internal operations.
141
+ * Use for: operation details, state diffs, decision trees
142
+ *
143
+ * @param message - Log message
144
+ * @param context - Structured context
145
+ */
146
+ trace(message: string, context?: LogContext): void {
147
+ // Zero-overhead check for SILENT mode
148
+ if (!(this.pinoLogger && this.isLevelEnabled(LogLevel.TRACE))) {
149
+ return;
150
+ }
151
+
152
+ this.pinoLogger.trace(this.mergeContext(context), message);
153
+ }
154
+
155
+ /**
156
+ * Log debug message (DEBUG level)
157
+ *
158
+ * Detailed information for debugging and analysis.
159
+ * Use for: rule evaluations, condition checks, mechanics
160
+ *
161
+ * @param message - Log message
162
+ * @param context - Structured context
163
+ */
164
+ debug(message: string, context?: LogContext): void {
165
+ // Zero-overhead check for SILENT mode
166
+ if (!(this.pinoLogger && this.isLevelEnabled(LogLevel.DEBUG))) {
167
+ return;
168
+ }
169
+
170
+ this.pinoLogger.debug(this.mergeContext(context), message);
171
+ }
172
+
173
+ /**
174
+ * Log info message (INFO level)
175
+ *
176
+ * Standard informational messages about game events.
177
+ * Use for: move execution, phase transitions, game events
178
+ *
179
+ * @param message - Log message
180
+ * @param context - Structured context
181
+ */
182
+ info(message: string, context?: LogContext): void {
183
+ // Zero-overhead check for SILENT mode
184
+ if (!(this.pinoLogger && this.isLevelEnabled(LogLevel.INFO))) {
185
+ return;
186
+ }
187
+
188
+ this.pinoLogger.info(this.mergeContext(context), message);
189
+ }
190
+
191
+ /**
192
+ * Log warning message (WARN level)
193
+ *
194
+ * Warning conditions that don't prevent execution.
195
+ * Use for: failed conditions, invalid moves, edge cases
196
+ *
197
+ * @param message - Log message
198
+ * @param context - Structured context
199
+ */
200
+ warn(message: string, context?: LogContext): void {
201
+ // Zero-overhead check for SILENT mode
202
+ if (!(this.pinoLogger && this.isLevelEnabled(LogLevel.WARN))) {
203
+ return;
204
+ }
205
+
206
+ this.pinoLogger.warn(this.mergeContext(context), message);
207
+ }
208
+
209
+ /**
210
+ * Log error message (ERROR level)
211
+ *
212
+ * Error conditions requiring attention.
213
+ * Use for: exceptions, failures, critical errors
214
+ *
215
+ * @param message - Log message
216
+ * @param context - Structured context
217
+ */
218
+ error(message: string, context?: LogContext): void {
219
+ // Zero-overhead check for SILENT mode
220
+ if (!(this.pinoLogger && this.isLevelEnabled(LogLevel.ERROR))) {
221
+ return;
222
+ }
223
+
224
+ this.pinoLogger.error(this.mergeContext(context), message);
225
+ }
226
+
227
+ /**
228
+ * Create child logger with namespace
229
+ *
230
+ * Child loggers inherit configuration but add a namespace
231
+ * to all log entries for filtering and organization.
232
+ *
233
+ * @param namespace - Namespace identifier (e.g., 'flow', 'zones')
234
+ * @returns New Logger instance with namespace
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * const logger = new Logger({ level: 'DEBUG' });
239
+ * const flowLogger = logger.child('flow');
240
+ *
241
+ * flowLogger.info('Phase transition');
242
+ * // Output: [flow] Phase transition
243
+ * ```
244
+ */
245
+ child(namespace: string): Logger {
246
+ // For SILENT mode, return a new SILENT logger
247
+ if (!this.pinoLogger) {
248
+ return new Logger({ level: "SILENT" });
249
+ }
250
+
251
+ // Create child with Pino child logger
252
+ const childLogger = new Logger({ level: this.currentLevel });
253
+ childLogger.pinoLogger = this.pinoLogger.child({ namespace });
254
+ childLogger.namespace = namespace;
255
+
256
+ return childLogger;
257
+ }
258
+
259
+ /**
260
+ * Get current log level
261
+ *
262
+ * @returns Current LogLevel
263
+ */
264
+ getLevel(): LogLevel {
265
+ return this.currentLevel;
266
+ }
267
+
268
+ /**
269
+ * Check if logger is in SILENT mode
270
+ *
271
+ * @returns True if no logging will occur
272
+ */
273
+ isSilent(): boolean {
274
+ return this.currentLevel === LogLevel.SILENT;
275
+ }
276
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Logging Types
3
+ *
4
+ * Type definitions for the TCG Core logging system.
5
+ * Provides structured logging with configurable verbosity levels.
6
+ */
7
+
8
+ /**
9
+ * Log Level Enum
10
+ *
11
+ * Numeric levels for log filtering (lower = more critical)
12
+ * - SILENT (0): No logging
13
+ * - ERROR (1): Error conditions only
14
+ * - WARN (2): Warning conditions
15
+ * - INFO (3): Informational messages
16
+ * - DEBUG (4): Debug-level messages
17
+ * - TRACE (5): Trace-level messages (most verbose)
18
+ */
19
+ export enum LogLevel {
20
+ SILENT = 0,
21
+ ERROR = 1,
22
+ WARN = 2,
23
+ INFO = 3,
24
+ DEBUG = 4,
25
+ TRACE = 5,
26
+ }
27
+
28
+ /**
29
+ * Verbosity Preset
30
+ *
31
+ * Named presets for different user types:
32
+ * - SILENT: No logging (production default)
33
+ * - NORMAL_PLAYER: Basic game events (INFO level)
34
+ * - ADVANCED_PLAYER: Detailed mechanics (DEBUG level)
35
+ * - DEVELOPER: Full internal details (TRACE level)
36
+ */
37
+ export type VerbosityPreset =
38
+ | "SILENT"
39
+ | "NORMAL_PLAYER"
40
+ | "ADVANCED_PLAYER"
41
+ | "DEVELOPER";
42
+
43
+ /**
44
+ * Log Context
45
+ *
46
+ * Structured context information attached to log entries.
47
+ * Provides rich metadata for filtering, searching, and analysis.
48
+ *
49
+ * Common fields:
50
+ * - moveId: Move being executed
51
+ * - playerId: Player performing action
52
+ * - phase: Current game phase
53
+ * - turn: Current turn number
54
+ * - timestamp: Event timestamp
55
+ *
56
+ * Games can add custom fields via index signature.
57
+ */
58
+ export type LogContext = {
59
+ /** Move identifier */
60
+ moveId?: string;
61
+ /** Player identifier */
62
+ playerId?: string;
63
+ /** Current game phase */
64
+ phase?: string;
65
+ /** Current game segment */
66
+ segment?: string;
67
+ /** Current turn number */
68
+ turn?: number;
69
+ /** Event timestamp */
70
+ timestamp?: number;
71
+ /** Error message (for error logs) */
72
+ error?: string;
73
+ /** Stack trace (for error logs) */
74
+ stack?: string;
75
+ /** Error code (for structured errors) */
76
+ errorCode?: string;
77
+ /** Operation duration in milliseconds */
78
+ duration?: number;
79
+ /** Number of patches generated */
80
+ patchCount?: number;
81
+ /** Custom context fields */
82
+ [key: string]: unknown;
83
+ };
84
+
85
+ /**
86
+ * Logger Options
87
+ *
88
+ * Configuration for Logger instances.
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * // Use preset for convenience
93
+ * const options: LoggerOptions = {
94
+ * level: 'DEVELOPER',
95
+ * pretty: true
96
+ * };
97
+ *
98
+ * // Or use numeric level for fine control
99
+ * const options: LoggerOptions = {
100
+ * level: LogLevel.DEBUG,
101
+ * pretty: false,
102
+ * destination: process.stdout
103
+ * };
104
+ * ```
105
+ */
106
+ export type LoggerOptions = {
107
+ /**
108
+ * Log level or verbosity preset
109
+ *
110
+ * Controls which messages are logged:
111
+ * - String presets: SILENT, NORMAL_PLAYER, ADVANCED_PLAYER, DEVELOPER
112
+ * - Numeric levels: LogLevel.SILENT through LogLevel.TRACE
113
+ *
114
+ * Default: 'SILENT' (no logging)
115
+ */
116
+ level?: VerbosityPreset | LogLevel;
117
+
118
+ /**
119
+ * Enable pretty printing
120
+ *
121
+ * When true, formats logs for human readability.
122
+ * When false, outputs JSON for machine consumption.
123
+ *
124
+ * Default: true
125
+ */
126
+ pretty?: boolean;
127
+
128
+ /**
129
+ * Log destination
130
+ *
131
+ * Where to write log output:
132
+ * - process.stdout (default)
133
+ * - process.stderr
134
+ * - Writable stream
135
+ * - File descriptor
136
+ *
137
+ * Default: process.stdout
138
+ */
139
+ destination?: unknown;
140
+
141
+ /**
142
+ * Additional Pino options
143
+ *
144
+ * Advanced configuration passed directly to Pino.
145
+ * See Pino documentation for available options.
146
+ */
147
+ [key: string]: unknown;
148
+ };