@omnitronix/game-engine-sdk 1.0.4 → 2.0.2
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.
- package/CHANGELOG.md +86 -0
- package/MIGRATION.md +126 -0
- package/dist/bootstrap/index.d.ts +4 -1
- package/dist/bootstrap/index.d.ts.map +1 -1
- package/dist/bootstrap/index.js +32 -32
- package/dist/common/api-docs/setup-documentation.d.ts +1 -1
- package/dist/common/api-docs/setup-documentation.d.ts.map +1 -1
- package/dist/common/error-handling/all-exceptions.filter.d.ts +0 -3
- package/dist/common/error-handling/all-exceptions.filter.d.ts.map +1 -1
- package/dist/common/error-handling/all-exceptions.filter.js +35 -21
- package/dist/common/error-handling/error-code-mapper.d.ts.map +1 -1
- package/dist/common/error-handling/error-code-mapper.js +15 -70
- package/dist/common/error-handling/internal-error-code.d.ts +13 -59
- package/dist/common/error-handling/internal-error-code.d.ts.map +1 -1
- package/dist/common/error-handling/internal-error-code.js +16 -68
- package/dist/common/logger/logger.d.ts +2 -3
- package/dist/common/logger/logger.d.ts.map +1 -1
- package/dist/common/logger/logger.js +3 -16
- package/dist/common/logger/logging.middleware.d.ts.map +1 -1
- package/dist/common/logger/logging.middleware.js +16 -4
- package/dist/common/metrics/prometheus.service.d.ts +5 -0
- package/dist/common/metrics/prometheus.service.d.ts.map +1 -1
- package/dist/common/metrics/prometheus.service.js +43 -3
- package/dist/common/retry/retry-policy.d.ts.map +1 -1
- package/dist/common/retry/retry-policy.js +9 -4
- package/dist/common/secrets-provider/secrets-provider.aws.d.ts.map +1 -1
- package/dist/common/secrets-provider/secrets-provider.aws.js +2 -1
- package/dist/esm/bootstrap/index.js +33 -33
- package/dist/esm/common/error-handling/all-exceptions.filter.js +36 -22
- package/dist/esm/common/error-handling/error-code-mapper.js +15 -70
- package/dist/esm/common/error-handling/internal-error-code.js +16 -68
- package/dist/esm/common/logger/logger.js +3 -16
- package/dist/esm/common/logger/logging.middleware.js +16 -4
- package/dist/esm/common/metrics/prometheus.service.js +10 -3
- package/dist/esm/common/retry/retry-policy.js +9 -4
- package/dist/esm/common/secrets-provider/secrets-provider.aws.js +2 -1
- package/dist/esm/generated/game-engine-registry_pb.js +5 -11
- package/dist/esm/generated/game-engine_pb.js +10 -24
- package/dist/esm/grpc/connect-router.middleware.js +7 -1
- package/dist/esm/grpc/game-engine.grpc.in-adapter.js +64 -20
- package/dist/esm/health/application/services/health.service.js +33 -39
- package/dist/esm/health/health.module.js +1 -1
- package/dist/esm/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.js +19 -4
- package/dist/esm/registration/adapters/game-engine-registry.grpc.out-adapter.js +3 -4
- package/dist/esm/registration/services/game-engine-auto-register.service.js +11 -8
- package/dist/generated/game-engine-registry_pb.d.ts +5 -5
- package/dist/generated/game-engine-registry_pb.d.ts.map +1 -1
- package/dist/generated/game-engine-registry_pb.js +4 -10
- package/dist/generated/game-engine_pb.d.ts +26 -10
- package/dist/generated/game-engine_pb.d.ts.map +1 -1
- package/dist/generated/game-engine_pb.js +8 -22
- package/dist/grpc/connect-router.middleware.d.ts +9 -1
- package/dist/grpc/connect-router.middleware.d.ts.map +1 -1
- package/dist/grpc/connect-router.middleware.js +7 -1
- package/dist/grpc/game-engine.grpc.in-adapter.d.ts +18 -3
- package/dist/grpc/game-engine.grpc.in-adapter.d.ts.map +1 -1
- package/dist/grpc/game-engine.grpc.in-adapter.js +64 -20
- package/dist/grpc/index.d.ts +1 -1
- package/dist/grpc/index.d.ts.map +1 -1
- package/dist/health/application/ports/out/shutdown.out-port.d.ts +2 -0
- package/dist/health/application/ports/out/shutdown.out-port.d.ts.map +1 -1
- package/dist/health/application/services/health.service.d.ts.map +1 -1
- package/dist/health/application/services/health.service.js +33 -39
- package/dist/health/domain/health.d.ts +1 -1
- package/dist/health/domain/health.d.ts.map +1 -1
- package/dist/health/health.module.js +1 -1
- package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.d.ts +2 -1
- package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.d.ts.map +1 -1
- package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.js +19 -4
- package/dist/registration/adapters/game-engine-registry.grpc.out-adapter.d.ts.map +1 -1
- package/dist/registration/adapters/game-engine-registry.grpc.out-adapter.js +3 -4
- package/dist/registration/services/game-engine-auto-register.service.d.ts.map +1 -1
- package/dist/registration/services/game-engine-auto-register.service.js +11 -8
- package/dist/types.d.ts +6 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@omnitronix/game-engine-sdk` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [2.0.1] - 2026-02-04
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **OWASP A01**: ExceptionsFilter HTTP path now returns error code only — no longer leaks `DomainException.message` to clients (consistent with gRPC sanitization)
|
|
9
|
+
- **OWASP A01**: `handleHttpException` now sanitizes 5xx messages — returns "Internal server error" instead of leaking internal details
|
|
10
|
+
- **Type safety**: Replaced `(appModule as any).register` cast in bootstrap with proper `hasRegisterMethod` type guard
|
|
11
|
+
- **Type safety**: Removed dead `safeStringify` from Logger, fixed `errorData: any` → `Record<string, unknown>`
|
|
12
|
+
- **Type safety**: `HealthCheckFailedException.details` typed as `unknown` (was `any`)
|
|
13
|
+
- **Type safety**: `GameEngineAutoRegisterService` catch handlers typed as `unknown` (was `any`)
|
|
14
|
+
- **Type safety**: `RetryPolicy.isRetryable` uses proper typed casts (no `as any`)
|
|
15
|
+
- **Type safety**: `INestApplication<any>` → `INestApplication` in API docs setup
|
|
16
|
+
- **Type safety**: Logger `log()` method uses `Record<string, unknown>` (was `Record<string, any>`)
|
|
17
|
+
- **Shutdown reliability**: Removed duplicate shutdown guard in bootstrap — now uses `ShutdownOutPort.isShuttingDown()` as single source of truth
|
|
18
|
+
- **TypeScript correctness**: `unhandledRejection` handler now types `reason` as `unknown` (not `Error`), handles non-Error rejections safely
|
|
19
|
+
- **HTTP status codes**: `UNAUTHORIZED` error code now maps to HTTP 401 (was incorrectly 403)
|
|
20
|
+
- **Error mapping**: `ErrorCodeMapper` default fallback changed from 400 to 500 — unknown error codes are server errors, not client errors
|
|
21
|
+
- **Dead code**: Removed unused `safeStringify` method from `GameEngineGrpcInAdapter` and `Logger`
|
|
22
|
+
- **Formatting**: All source files pass Prettier check (CI was failing on 6 files)
|
|
23
|
+
- **ExceptionsFilter**: Removed `as any` casts in `handleHttpException` — uses typed `Record<string, unknown>` instead
|
|
24
|
+
- **PrometheusService**: `initializeMetricsFromDatabase` is now a no-op instead of throwing (prevents crash if called)
|
|
25
|
+
- **LoggingMiddleware**: Removed hardcoded `/api/races/active` endpoint — now configurable via `LOG_BLOCKED_ENDPOINTS` env var
|
|
26
|
+
- **Security**: Removed `.npmrc` with hardcoded npm token from disk
|
|
27
|
+
- **Type safety**: All `catch` blocks annotated with `: unknown` — bootstrap, retry-policy, gRPC out-adapter, AWS secrets provider
|
|
28
|
+
- **Type safety**: `RetryPolicy.execute` catch wraps non-Error throws in `new Error()` instead of unsafe `as Error` cast
|
|
29
|
+
- **Type safety**: `handleHttpException` validates pre-shaped responses field-by-field instead of blind `as ErrorResponse` cast
|
|
30
|
+
- **Type safety**: `ErrorCodeMapper` uses `??` (nullish coalescing) instead of `||` for fallback — correct for `0` status codes
|
|
31
|
+
- **Code quality**: Removed redundant catch-and-rethrow in `HealthService.checkHealth()` — errors propagate naturally
|
|
32
|
+
- **CI/CD**: Removed `--passWithNoTests` from CI test step — tests must actually exist and run
|
|
33
|
+
- **CI/CD**: Added coverage artifact upload to CI pipeline (Node 20 matrix)
|
|
34
|
+
- **CI/CD**: Added `format:check` step to release workflow — prevents publishing unformatted code
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Jest `coverageThreshold` enforced in config (80% statements/branches/functions/lines)
|
|
38
|
+
- `CHANGELOG.md` and `MIGRATION.md` documentation
|
|
39
|
+
|
|
40
|
+
## [2.0.0] - 2026-02-04
|
|
41
|
+
|
|
42
|
+
### Breaking Changes
|
|
43
|
+
- All generic type defaults changed from `any` to `unknown` in `types.ts` (SDK-001)
|
|
44
|
+
- `InternalErrorCode` enum reduced from 64 codes to 11 game-engine-relevant codes (SDK-002)
|
|
45
|
+
- gRPC error responses now return error code only, not internal message (SDK-004)
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- **GLI-19**: RNG seed validation prevents silent data corruption — rejects `undefined`, `NaN`, `Infinity` seeds with `INVALID_RNG_SEED` error (SDK-003)
|
|
49
|
+
- **OWASP A01**: gRPC error messages sanitized — internal details logged but never sent to client (SDK-004)
|
|
50
|
+
- **OWASP A03**: gRPC input validation — missing/empty command ID and type rejected with `INVALID_COMMAND` (SDK-005)
|
|
51
|
+
- **Reliability**: h2c gRPC server integrated with graceful shutdown service — no more race conditions (SDK-006)
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- `HealthModule` now exports `SHUTDOWN_OUT_PORT` and `HEALTH_IN_PORT` providers (SDK-007)
|
|
55
|
+
- `ConnectRouter` extensibility — `additionalRoutes` option for crash game streaming services (SDK-008)
|
|
56
|
+
- Proto schema `game_name` and `provider` fields in `GetGameEngineInfoResponse` (SDK-009)
|
|
57
|
+
- Comprehensive test coverage — 87 tests, 94.71% statements (SDK-010)
|
|
58
|
+
|
|
59
|
+
## [1.0.4] - 2026-01-30
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
- File log transport disabled by default for container compatibility
|
|
63
|
+
- CORS origin hardcoding removed
|
|
64
|
+
- Error message leakage in Swagger responses
|
|
65
|
+
- Log redaction for sensitive fields
|
|
66
|
+
- `.npmrc` removed from tracking
|
|
67
|
+
|
|
68
|
+
## [1.0.2] - 2026-01-28
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
- Inline CI in release workflow
|
|
72
|
+
- Use published contract from npmjs.org
|
|
73
|
+
|
|
74
|
+
## [1.0.0] - 2026-01-25
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
- Initial release
|
|
78
|
+
- NestJS application bootstrap with standard configuration
|
|
79
|
+
- Connect RPC (h2c) gRPC server
|
|
80
|
+
- Health check module with graceful shutdown
|
|
81
|
+
- Game engine auto-registration service
|
|
82
|
+
- Logging with Winston (JSON and pretty formats)
|
|
83
|
+
- Prometheus metrics integration
|
|
84
|
+
- AWS Secrets Manager provider
|
|
85
|
+
- Swagger/OpenAPI documentation setup
|
|
86
|
+
- Retry policies with exponential backoff
|
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
## Migrating from v1.x to v2.0.0
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
#### 1. Generic Type Defaults: `any` → `unknown`
|
|
8
|
+
|
|
9
|
+
All generic type parameters in `types.ts` now default to `unknown` instead of `any`.
|
|
10
|
+
|
|
11
|
+
**Before (v1.x):**
|
|
12
|
+
```typescript
|
|
13
|
+
// Implicit any — no type errors on wrong usage
|
|
14
|
+
const result: CommandProcessingResult = { ... };
|
|
15
|
+
result.publicState.balance; // No error (unsafe)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**After (v2.0):**
|
|
19
|
+
```typescript
|
|
20
|
+
// Must narrow or cast explicitly
|
|
21
|
+
const result: CommandProcessingResult = { ... };
|
|
22
|
+
(result.publicState as { balance: number }).balance; // Explicit
|
|
23
|
+
|
|
24
|
+
// Or use generics for type safety:
|
|
25
|
+
const result: CommandProcessingResult<MyPublicState, MyPrivateState> = { ... };
|
|
26
|
+
result.publicState.balance; // Type-safe
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Migration:** Add explicit generic type parameters to `CommandProcessingResult`, `GameActionCommand`, and `GameEngine` where you use them. This is the recommended approach — it gives you compile-time type safety.
|
|
30
|
+
|
|
31
|
+
#### 2. InternalErrorCode Enum Reduced
|
|
32
|
+
|
|
33
|
+
`InternalErrorCode` was reduced from 64 platform-level codes to 11 game-engine-relevant codes.
|
|
34
|
+
|
|
35
|
+
**Removed codes (examples):**
|
|
36
|
+
- `SESSION_NOT_FOUND`, `OPERATOR_NOT_FOUND`, `TRANSACTION_FAILED`
|
|
37
|
+
- `JACKPOT_ERROR`, `GEO_BLOCKED`, `RNG_REPLAY_ERROR`
|
|
38
|
+
- All session, operator, auth, transaction, jackpot, geo, and RNG replay codes
|
|
39
|
+
|
|
40
|
+
**Kept codes:**
|
|
41
|
+
```typescript
|
|
42
|
+
GAME_ENGINE_ERROR
|
|
43
|
+
DEBUG_COMMANDS_DISABLED
|
|
44
|
+
UNKNOWN_COMMAND
|
|
45
|
+
INVALID_COMMAND
|
|
46
|
+
INVALID_RNG_SEED
|
|
47
|
+
INTERNAL_SERVER_ERROR
|
|
48
|
+
FORBIDDEN
|
|
49
|
+
UNAUTHORIZED
|
|
50
|
+
VALIDATION_ERROR
|
|
51
|
+
SERVICE_UNAVAILABLE
|
|
52
|
+
HEALTH_CHECK_FAILED
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Migration:** If your game engine service references removed error codes, either:
|
|
56
|
+
1. Map to a remaining code (e.g., `SESSION_NOT_FOUND` → `INTERNAL_SERVER_ERROR`)
|
|
57
|
+
2. Define the code in your service's own enum (platform codes belong in the RGS platform)
|
|
58
|
+
|
|
59
|
+
#### 3. gRPC Error Response Format
|
|
60
|
+
|
|
61
|
+
gRPC error responses now return the error code string as the `message` field, not the internal exception message.
|
|
62
|
+
|
|
63
|
+
**Before (v1.x):**
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"success": false,
|
|
67
|
+
"message": "Internal: database connection lost at pool#42"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**After (v2.0):**
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"success": false,
|
|
75
|
+
"message": "GAME_ENGINE_ERROR"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Migration:** If your client-side code parses `message` for internal error details, update it to handle error code strings instead. Internal details are logged server-side but never exposed to clients (OWASP A01).
|
|
80
|
+
|
|
81
|
+
### New Features (Non-Breaking)
|
|
82
|
+
|
|
83
|
+
#### ConnectRouter Extensibility
|
|
84
|
+
|
|
85
|
+
If you need additional gRPC services (e.g., crash game streaming):
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
await createGameEngineApp({
|
|
89
|
+
serviceName: 'crash-game-engine',
|
|
90
|
+
appModule: AppModule,
|
|
91
|
+
additionalRoutes: (router) => {
|
|
92
|
+
router.service(CrashGameStreamService, {
|
|
93
|
+
streamMultiplier: myStreamHandler,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### HealthModule Exports
|
|
100
|
+
|
|
101
|
+
`SHUTDOWN_OUT_PORT` and `HEALTH_IN_PORT` are now exported from `HealthModule`. You can inject them in your own modules:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
@Module({
|
|
105
|
+
imports: [HealthModule],
|
|
106
|
+
})
|
|
107
|
+
export class MyModule {
|
|
108
|
+
constructor(
|
|
109
|
+
@Inject(SHUTDOWN_OUT_PORT) private shutdown: ShutdownOutPort,
|
|
110
|
+
@Inject(HEALTH_IN_PORT) private health: HealthInPort,
|
|
111
|
+
) {}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Proto Schema Updates
|
|
116
|
+
|
|
117
|
+
`GetGameEngineInfoResponse` now includes `game_name` and `provider` fields. These are populated from your `GameEngineInfo` implementation.
|
|
118
|
+
|
|
119
|
+
### Checklist
|
|
120
|
+
|
|
121
|
+
- [ ] Update `@omnitronix/game-engine-sdk` to `^2.0.0` in `package.json`
|
|
122
|
+
- [ ] Add explicit generic type parameters where `CommandProcessingResult` or `GameEngine` are used
|
|
123
|
+
- [ ] Remove references to deleted `InternalErrorCode` values (if any)
|
|
124
|
+
- [ ] Update client-side error handling to expect error code strings in gRPC `message` field
|
|
125
|
+
- [ ] Verify `npm run build` succeeds
|
|
126
|
+
- [ ] Verify `npm test` passes
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { ConnectRouterOptions } from '../grpc/connect-router.middleware';
|
|
1
2
|
import { Type } from '@nestjs/common';
|
|
2
3
|
export interface GameEngineAppOptions {
|
|
3
4
|
serviceName: string;
|
|
4
|
-
appModule: Type<
|
|
5
|
+
appModule: Type<unknown>;
|
|
5
6
|
bootstrapOptions?: {
|
|
6
7
|
driver: 'database' | 'in-memory';
|
|
7
8
|
};
|
|
8
9
|
/** Allowed CORS origins. Defaults to false (CORS disabled). */
|
|
9
10
|
corsOrigins?: string[] | boolean;
|
|
11
|
+
/** Additional Connect RPC routes (e.g., crash game streaming services). */
|
|
12
|
+
additionalRoutes?: ConnectRouterOptions['additionalRoutes'];
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* Creates and bootstraps a game engine NestJS application with
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bootstrap/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bootstrap/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAuB,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9F,OAAO,EAKL,IAAI,EACL,MAAM,gBAAgB,CAAC;AAKxB,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,gBAAgB,CAAC,EAAE;QAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAAA;KAAE,CAAC;IACxD,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACjC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;CAC7D;AASD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,2DA+HtE"}
|
package/dist/bootstrap/index.js
CHANGED
|
@@ -45,18 +45,20 @@ const common_1 = require("@nestjs/common");
|
|
|
45
45
|
const config_1 = require("@nestjs/config");
|
|
46
46
|
const core_1 = require("@nestjs/core");
|
|
47
47
|
const http2 = __importStar(require("http2"));
|
|
48
|
+
/** Type guard for NestJS dynamic modules with a static `register` method. */
|
|
49
|
+
function hasRegisterMethod(module) {
|
|
50
|
+
return 'register' in module && typeof module.register === 'function';
|
|
51
|
+
}
|
|
48
52
|
/**
|
|
49
53
|
* Creates and bootstraps a game engine NestJS application with
|
|
50
54
|
* standard configuration: CORS, validation pipes, exception filters,
|
|
51
55
|
* Swagger docs, Connect RPC gRPC server, and graceful shutdown.
|
|
52
56
|
*/
|
|
53
57
|
async function createGameEngineApp(options) {
|
|
54
|
-
const { serviceName, appModule, bootstrapOptions, corsOrigins = false } = options;
|
|
58
|
+
const { serviceName, appModule, bootstrapOptions, corsOrigins = false, additionalRoutes, } = options;
|
|
55
59
|
const logger = new logger_1.Logger(serviceName);
|
|
56
|
-
const moduleArg = bootstrapOptions
|
|
57
|
-
? appModule.register
|
|
58
|
-
? appModule.register(bootstrapOptions)
|
|
59
|
-
: appModule
|
|
60
|
+
const moduleArg = bootstrapOptions && hasRegisterMethod(appModule)
|
|
61
|
+
? appModule.register(bootstrapOptions)
|
|
60
62
|
: appModule;
|
|
61
63
|
const app = await core_1.NestFactory.create(moduleArg, {
|
|
62
64
|
logger: logger,
|
|
@@ -66,42 +68,33 @@ async function createGameEngineApp(options) {
|
|
|
66
68
|
}
|
|
67
69
|
const configService = app.get(config_1.ConfigService);
|
|
68
70
|
const shutdownService = app.get(shutdown_out_port_1.SHUTDOWN_OUT_PORT);
|
|
69
|
-
|
|
71
|
+
// Fatal error handler uses ShutdownOutPort's guard to prevent duplicate shutdowns.
|
|
72
|
+
// No separate local flag — single source of truth avoids desync.
|
|
70
73
|
const handleFatalError = async (errorType, error) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (isShuttingDown) {
|
|
74
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
75
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
76
|
+
logger.error(`${errorType}:`, { error: errorMessage, stack: errorStack });
|
|
77
|
+
if (shutdownService.isShuttingDown()) {
|
|
76
78
|
logger.warn('Shutdown already in progress, ignoring additional error');
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
|
-
isShuttingDown = true;
|
|
80
81
|
try {
|
|
81
82
|
logger.warn(`Initiating graceful shutdown due to ${errorType}...`);
|
|
82
83
|
await shutdownService.startGracefulShutdown();
|
|
83
84
|
logger.log('Graceful shutdown completed, exiting process');
|
|
84
85
|
}
|
|
85
86
|
catch (shutdownError) {
|
|
86
|
-
|
|
87
|
+
const shutdownMsg = shutdownError instanceof Error ? shutdownError.message : String(shutdownError);
|
|
88
|
+
logger.error(`Error during graceful shutdown: ${shutdownMsg}`);
|
|
87
89
|
}
|
|
88
90
|
finally {
|
|
89
91
|
process.exit(1);
|
|
90
92
|
}
|
|
91
93
|
};
|
|
92
94
|
process.on('uncaughtException', (error) => {
|
|
93
|
-
logger.error('Uncaught Exception:', {
|
|
94
|
-
error: error.message,
|
|
95
|
-
stack: error.stack,
|
|
96
|
-
});
|
|
97
95
|
void handleFatalError('uncaughtException', error);
|
|
98
96
|
});
|
|
99
|
-
process.on('unhandledRejection', (reason
|
|
100
|
-
logger.error('Unhandled Rejection:', {
|
|
101
|
-
reason: reason.message,
|
|
102
|
-
stack: reason.stack,
|
|
103
|
-
promise,
|
|
104
|
-
});
|
|
97
|
+
process.on('unhandledRejection', (reason) => {
|
|
105
98
|
void handleFatalError('unhandledRejection', reason);
|
|
106
99
|
});
|
|
107
100
|
app.setGlobalPrefix('api', {
|
|
@@ -127,11 +120,11 @@ async function createGameEngineApp(options) {
|
|
|
127
120
|
},
|
|
128
121
|
}));
|
|
129
122
|
app.useGlobalFilters(app.get(all_exceptions_filter_1.ExceptionsFilter));
|
|
130
|
-
const PORT = configService.get('PORT')
|
|
123
|
+
const PORT = configService.get('PORT') ?? 3000;
|
|
131
124
|
await (0, setup_documentation_1.setupDocumentation)(app, PORT, serviceName);
|
|
132
125
|
// Setup Connect RPC server
|
|
133
126
|
const gameEngineAdapter = app.get(game_engine_grpc_in_adapter_1.GameEngineGrpcInAdapter);
|
|
134
|
-
const connectRouter = (0, connect_router_middleware_1.createConnectRouter)(gameEngineAdapter);
|
|
127
|
+
const connectRouter = (0, connect_router_middleware_1.createConnectRouter)(gameEngineAdapter, { additionalRoutes });
|
|
135
128
|
// Mount Connect router on /connect path
|
|
136
129
|
app.use('/connect', connectRouter);
|
|
137
130
|
app.enableShutdownHooks(['SIGTERM', 'SIGINT']);
|
|
@@ -144,14 +137,21 @@ async function createGameEngineApp(options) {
|
|
|
144
137
|
h2cServer.listen(GRPC_PORT, '0.0.0.0', () => {
|
|
145
138
|
logger.log(`Connect RPC (h2c) is available on: http://localhost:${GRPC_PORT}`);
|
|
146
139
|
});
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
// Register h2c server closure with graceful shutdown service
|
|
141
|
+
shutdownService.registerCleanupCallback('h2c-grpc-server', () => {
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
h2cServer.close(err => {
|
|
144
|
+
if (err) {
|
|
145
|
+
logger.error('Error closing h2c gRPC server:', err);
|
|
146
|
+
reject(err);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
logger.log('h2c gRPC server closed');
|
|
150
|
+
resolve();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
151
153
|
});
|
|
152
|
-
};
|
|
153
|
-
process.on('SIGTERM', closeH2c);
|
|
154
|
-
process.on('SIGINT', closeH2c);
|
|
154
|
+
});
|
|
155
155
|
await app.listen(PORT, '0.0.0.0');
|
|
156
156
|
logger.log(`Application is running on: http://localhost:${PORT}`);
|
|
157
157
|
return app;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { INestApplication } from '@nestjs/common';
|
|
2
|
-
export declare const setupDocumentation: (app: INestApplication
|
|
2
|
+
export declare const setupDocumentation: (app: INestApplication, port: number, serviceName?: string) => Promise<void>;
|
|
3
3
|
//# sourceMappingURL=setup-documentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-documentation.d.ts","sourceRoot":"","sources":["../../../src/common/api-docs/setup-documentation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMlD,eAAO,MAAM,kBAAkB,GAC7B,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"setup-documentation.d.ts","sourceRoot":"","sources":["../../../src/common/api-docs/setup-documentation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMlD,eAAO,MAAM,kBAAkB,GAC7B,KAAK,gBAAgB,EACrB,MAAM,MAAM,EACZ,cAAc,MAAM,kBA0BrB,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { MetricsPort } from '../metrics/metrics.port';
|
|
2
1
|
import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
|
|
3
2
|
export interface ErrorResponse {
|
|
4
3
|
statusCode: number;
|
|
@@ -8,9 +7,7 @@ export interface ErrorResponse {
|
|
|
8
7
|
path: string;
|
|
9
8
|
}
|
|
10
9
|
export declare class ExceptionsFilter implements ExceptionFilter {
|
|
11
|
-
private readonly metricsPort;
|
|
12
10
|
private readonly logger;
|
|
13
|
-
constructor(metricsPort: MetricsPort);
|
|
14
11
|
catch(exception: unknown, host: ArgumentsHost): void;
|
|
15
12
|
private buildErrorResponse;
|
|
16
13
|
private handleDomainException;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"all-exceptions.filter.d.ts","sourceRoot":"","sources":["../../../src/common/error-handling/all-exceptions.filter.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"all-exceptions.filter.d.ts","sourceRoot":"","sources":["../../../src/common/error-handling/all-exceptions.filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAS,eAAe,EAA6B,MAAM,gBAAgB,CAAC;AAOlG,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBACa,gBAAiB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAE5D,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa;IAS7C,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,mBAAmB;IA4E3B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,oBAAoB;CAmB7B"}
|
|
@@ -5,24 +5,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
7
|
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
-
};
|
|
14
8
|
var ExceptionsFilter_1;
|
|
15
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
10
|
exports.ExceptionsFilter = void 0;
|
|
17
11
|
const logger_1 = require("../logger/logger");
|
|
18
|
-
const metrics_port_1 = require("../metrics/metrics.port");
|
|
19
12
|
const common_1 = require("@nestjs/common");
|
|
20
13
|
const domain_exception_1 = require("./domain.exception");
|
|
21
14
|
const error_code_mapper_1 = require("./error-code-mapper");
|
|
22
15
|
const internal_error_code_1 = require("./internal-error-code");
|
|
23
16
|
let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
|
|
24
|
-
constructor(
|
|
25
|
-
this.metricsPort = metricsPort;
|
|
17
|
+
constructor() {
|
|
26
18
|
this.logger = new logger_1.Logger(ExceptionsFilter_1.name);
|
|
27
19
|
}
|
|
28
20
|
catch(exception, host) {
|
|
@@ -47,14 +39,17 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
|
|
|
47
39
|
handleDomainException(exception, request) {
|
|
48
40
|
const status = error_code_mapper_1.ErrorCodeMapper.mapToHttpStatus(exception.errorCode);
|
|
49
41
|
const level = status >= 500 ? 'error' : 'warn';
|
|
42
|
+
// Log full internal details for debugging — never sent to client
|
|
50
43
|
this.logger.log(`DomainException (status: ${status} at ${request.method} ${request.url}): Internal Code ${exception.errorCode} Message: ${exception.message}`, { level });
|
|
51
44
|
if (exception.cause) {
|
|
52
45
|
this.logger.error('Exception cause:', exception.cause);
|
|
53
46
|
}
|
|
47
|
+
// OWASP A01: Return error code only — never expose internal error.message to clients.
|
|
48
|
+
// Consistent with gRPC error sanitization in GameEngineGrpcInAdapter.
|
|
54
49
|
return this.buildResponsePayload({
|
|
55
50
|
status,
|
|
56
51
|
internalCode: exception.errorCode,
|
|
57
|
-
message: exception.
|
|
52
|
+
message: exception.errorCode,
|
|
58
53
|
path: request.url,
|
|
59
54
|
});
|
|
60
55
|
}
|
|
@@ -62,17 +57,29 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
|
|
|
62
57
|
const status = exception.getStatus();
|
|
63
58
|
const responseData = exception.getResponse();
|
|
64
59
|
// Check if this is a custom validation error response
|
|
65
|
-
|
|
66
|
-
responseData
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
const responseRecord = typeof responseData === 'object' && responseData !== null
|
|
61
|
+
? responseData
|
|
62
|
+
: null;
|
|
63
|
+
if (responseRecord &&
|
|
64
|
+
typeof responseRecord.internalCode === 'string' &&
|
|
65
|
+
typeof responseRecord.statusCode === 'number' &&
|
|
66
|
+
typeof responseRecord.message !== 'undefined') {
|
|
67
|
+
return {
|
|
68
|
+
statusCode: responseRecord.statusCode,
|
|
69
|
+
internalCode: responseRecord.internalCode,
|
|
70
|
+
message: String(responseRecord.message),
|
|
71
|
+
timestamp: typeof responseRecord.timestamp === 'string'
|
|
72
|
+
? responseRecord.timestamp
|
|
73
|
+
: new Date().toISOString(),
|
|
74
|
+
path: typeof responseRecord.path === 'string' ? responseRecord.path : request.url,
|
|
75
|
+
};
|
|
69
76
|
}
|
|
70
77
|
let message = 'HTTP Exception';
|
|
71
78
|
if (typeof responseData === 'string') {
|
|
72
79
|
message = responseData;
|
|
73
80
|
}
|
|
74
|
-
else if (typeof
|
|
75
|
-
message =
|
|
81
|
+
else if (responseRecord && typeof responseRecord.message === 'string') {
|
|
82
|
+
message = responseRecord.message;
|
|
76
83
|
}
|
|
77
84
|
const level = status >= 500 ? 'error' : 'warn';
|
|
78
85
|
this.logger.log(`HttpException (status: ${status} at ${request.method} ${request.url}): ${message}`, { level });
|
|
@@ -85,12 +92,21 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
|
|
|
85
92
|
path: request.url,
|
|
86
93
|
});
|
|
87
94
|
}
|
|
88
|
-
|
|
95
|
+
// OWASP A01: Never expose internal error details for server errors.
|
|
96
|
+
// 5xx messages may contain stack traces, DB errors, or internal details.
|
|
97
|
+
if (status >= 500) {
|
|
89
98
|
this.logger.error('HttpException stack:', exception.stack);
|
|
99
|
+
return this.buildResponsePayload({
|
|
100
|
+
status,
|
|
101
|
+
internalCode: internal_error_code_1.InternalErrorCode.INTERNAL_SERVER_ERROR,
|
|
102
|
+
message: 'Internal server error',
|
|
103
|
+
path: request.url,
|
|
104
|
+
});
|
|
90
105
|
}
|
|
106
|
+
// 4xx client errors — framework messages are safe (e.g., "Not Found", "Bad Request")
|
|
91
107
|
return this.buildResponsePayload({
|
|
92
108
|
status,
|
|
93
|
-
internalCode: internal_error_code_1.InternalErrorCode.
|
|
109
|
+
internalCode: internal_error_code_1.InternalErrorCode.VALIDATION_ERROR,
|
|
94
110
|
message,
|
|
95
111
|
path: request.url,
|
|
96
112
|
});
|
|
@@ -125,7 +141,5 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
|
|
|
125
141
|
};
|
|
126
142
|
exports.ExceptionsFilter = ExceptionsFilter;
|
|
127
143
|
exports.ExceptionsFilter = ExceptionsFilter = ExceptionsFilter_1 = __decorate([
|
|
128
|
-
(0, common_1.Catch)()
|
|
129
|
-
__param(0, (0, common_1.Inject)(metrics_port_1.METRICS_PORT)),
|
|
130
|
-
__metadata("design:paramtypes", [Object])
|
|
144
|
+
(0, common_1.Catch)()
|
|
131
145
|
], ExceptionsFilter);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-code-mapper.d.ts","sourceRoot":"","sources":["../../../src/common/error-handling/error-code-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"error-code-mapper.d.ts","sourceRoot":"","sources":["../../../src/common/error-handling/error-code-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAc1D,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAmB5C;IAEF,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM;CAG7D"}
|
|
@@ -5,89 +5,34 @@ const internal_error_code_1 = require("./internal-error-code");
|
|
|
5
5
|
// HTTP status codes
|
|
6
6
|
const HttpStatus = {
|
|
7
7
|
BAD_REQUEST: 400,
|
|
8
|
-
|
|
8
|
+
UNAUTHORIZED: 401,
|
|
9
9
|
FORBIDDEN: 403,
|
|
10
10
|
NOT_FOUND: 404,
|
|
11
|
+
CONFLICT: 409,
|
|
11
12
|
UNPROCESSABLE_ENTITY: 422,
|
|
12
13
|
INTERNAL_SERVER_ERROR: 500,
|
|
13
14
|
SERVICE_UNAVAILABLE: 503,
|
|
14
15
|
};
|
|
15
16
|
class ErrorCodeMapper {
|
|
16
17
|
static mapToHttpStatus(errorCode) {
|
|
17
|
-
return this.ERROR_CODE_TO_HTTP_MAP[errorCode]
|
|
18
|
+
return this.ERROR_CODE_TO_HTTP_MAP[errorCode] ?? HttpStatus.INTERNAL_SERVER_ERROR;
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
exports.ErrorCodeMapper = ErrorCodeMapper;
|
|
21
22
|
ErrorCodeMapper.ERROR_CODE_TO_HTTP_MAP = {
|
|
22
|
-
|
|
23
|
-
[internal_error_code_1.InternalErrorCode.
|
|
24
|
-
[internal_error_code_1.InternalErrorCode.INSUFFICIENT_FUNDS]: HttpStatus.UNPROCESSABLE_ENTITY,
|
|
25
|
-
[internal_error_code_1.InternalErrorCode.INTERNAL_SERVER_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
26
|
-
// Game Catalog errors
|
|
27
|
-
[internal_error_code_1.InternalErrorCode.GAME_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
28
|
-
[internal_error_code_1.InternalErrorCode.GAME_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
29
|
-
[internal_error_code_1.InternalErrorCode.GAME_CONFIG_ALREADY_EXISTS_WITH_SAME_JURISDICTION_AND_RTP]: HttpStatus.BAD_REQUEST,
|
|
30
|
-
[internal_error_code_1.InternalErrorCode.OPERATOR_GAME_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
31
|
-
[internal_error_code_1.InternalErrorCode.OPERATOR_GAME_ALREADY_ENABLED]: HttpStatus.BAD_REQUEST,
|
|
32
|
-
[internal_error_code_1.InternalErrorCode.INVALID_GAME_CONFIG_DATA]: HttpStatus.BAD_REQUEST,
|
|
33
|
-
[internal_error_code_1.InternalErrorCode.INVALID_GAME_UPDATE_DATA]: HttpStatus.BAD_REQUEST,
|
|
34
|
-
[internal_error_code_1.InternalErrorCode.GAME_CODE_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
|
|
35
|
-
[internal_error_code_1.InternalErrorCode.GAME_OR_GAME_CONFIG_DISABLED]: HttpStatus.BAD_REQUEST,
|
|
23
|
+
// Core game engine errors
|
|
24
|
+
[internal_error_code_1.InternalErrorCode.GAME_ENGINE_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
36
25
|
[internal_error_code_1.InternalErrorCode.DEBUG_COMMANDS_DISABLED]: HttpStatus.FORBIDDEN,
|
|
37
|
-
|
|
38
|
-
[internal_error_code_1.InternalErrorCode.
|
|
39
|
-
|
|
40
|
-
[internal_error_code_1.InternalErrorCode.
|
|
41
|
-
|
|
42
|
-
[internal_error_code_1.InternalErrorCode.
|
|
43
|
-
[internal_error_code_1.InternalErrorCode.
|
|
44
|
-
[internal_error_code_1.InternalErrorCode.
|
|
45
|
-
[internal_error_code_1.InternalErrorCode.UNKNOWN_COMMAND]: HttpStatus.NOT_FOUND,
|
|
46
|
-
// Operator errors
|
|
47
|
-
[internal_error_code_1.InternalErrorCode.MISSING_OPERATOR_CODE]: HttpStatus.BAD_REQUEST,
|
|
48
|
-
[internal_error_code_1.InternalErrorCode.INVALID_OPERATOR_CODE]: HttpStatus.BAD_REQUEST,
|
|
49
|
-
[internal_error_code_1.InternalErrorCode.OPERATOR_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
50
|
-
[internal_error_code_1.InternalErrorCode.OPERATOR_INACTIVE]: HttpStatus.FORBIDDEN,
|
|
51
|
-
[internal_error_code_1.InternalErrorCode.COUNTRY_CODE_RESTRICTED]: HttpStatus.BAD_REQUEST,
|
|
52
|
-
[internal_error_code_1.InternalErrorCode.UNAUTHORIZED]: HttpStatus.FORBIDDEN,
|
|
53
|
-
[internal_error_code_1.InternalErrorCode.AUTH_VALIDATION_FAILED]: HttpStatus.FORBIDDEN,
|
|
54
|
-
[internal_error_code_1.InternalErrorCode.BALANCE_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
55
|
-
[internal_error_code_1.InternalErrorCode.INVALID_AUTH_DATA]: HttpStatus.BAD_REQUEST,
|
|
26
|
+
[internal_error_code_1.InternalErrorCode.UNKNOWN_COMMAND]: HttpStatus.BAD_REQUEST,
|
|
27
|
+
[internal_error_code_1.InternalErrorCode.INVALID_COMMAND]: HttpStatus.BAD_REQUEST,
|
|
28
|
+
// RNG integrity (GLI-19)
|
|
29
|
+
[internal_error_code_1.InternalErrorCode.INVALID_RNG_SEED]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
30
|
+
// Infrastructure errors
|
|
31
|
+
[internal_error_code_1.InternalErrorCode.INTERNAL_SERVER_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
32
|
+
[internal_error_code_1.InternalErrorCode.FORBIDDEN]: HttpStatus.FORBIDDEN,
|
|
33
|
+
[internal_error_code_1.InternalErrorCode.UNAUTHORIZED]: HttpStatus.UNAUTHORIZED,
|
|
56
34
|
[internal_error_code_1.InternalErrorCode.VALIDATION_ERROR]: HttpStatus.BAD_REQUEST,
|
|
57
|
-
[internal_error_code_1.InternalErrorCode.JURISDICTION_CONFIG_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
|
|
58
|
-
[internal_error_code_1.InternalErrorCode.JURISDICTION_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
59
|
-
[internal_error_code_1.InternalErrorCode.OPERATOR_JURISDICTION_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
60
|
-
[internal_error_code_1.InternalErrorCode.GAME_ENGINE_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
61
|
-
[internal_error_code_1.InternalErrorCode.DEBIT_FAILED]: HttpStatus.BAD_REQUEST,
|
|
62
|
-
[internal_error_code_1.InternalErrorCode.CREDIT_FAILED]: HttpStatus.BAD_REQUEST,
|
|
63
|
-
[internal_error_code_1.InternalErrorCode.GAME_ROUND_LOG_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
64
|
-
// Geo Validation errors
|
|
65
|
-
[internal_error_code_1.InternalErrorCode.COUNTRY_NOT_PERMITTED]: HttpStatus.FORBIDDEN,
|
|
66
|
-
[internal_error_code_1.InternalErrorCode.GEO_VALIDATION_SERVICE_UNAVAILABLE]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
67
|
-
[internal_error_code_1.InternalErrorCode.RESOURCE_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
68
|
-
[internal_error_code_1.InternalErrorCode.FINANCIAL_TRANSACTION_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
69
|
-
[internal_error_code_1.InternalErrorCode.SESSION_TERMINATED]: HttpStatus.BAD_REQUEST,
|
|
70
|
-
[internal_error_code_1.InternalErrorCode.SESSION_CANNOT_BE_TERMINATED]: HttpStatus.BAD_REQUEST,
|
|
71
|
-
[internal_error_code_1.InternalErrorCode.SESSION_AUTO_RESOLVE_FAILED]: HttpStatus.BAD_REQUEST,
|
|
72
|
-
[internal_error_code_1.InternalErrorCode.SESSION_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
|
|
73
|
-
[internal_error_code_1.InternalErrorCode.INCOMPATIBLE_GAMEPLAY_CONFIG]: HttpStatus.BAD_REQUEST,
|
|
74
|
-
// Health check errors
|
|
75
|
-
[internal_error_code_1.InternalErrorCode.HEALTH_CHECK_FAILED]: HttpStatus.SERVICE_UNAVAILABLE,
|
|
76
|
-
//Jackpot errors
|
|
77
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_TYPE_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
78
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_TIER_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
79
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_CONFIGURATION_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
80
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_CONFIGURATION_IS_ACTIVE]: HttpStatus.BAD_REQUEST,
|
|
81
|
-
// RNG and Replay errors
|
|
82
|
-
[internal_error_code_1.InternalErrorCode.RNG_SEED_NOT_FOUND]: HttpStatus.NOT_FOUND,
|
|
83
|
-
[internal_error_code_1.InternalErrorCode.RNG_SEED_MISMATCH]: HttpStatus.BAD_REQUEST,
|
|
84
|
-
[internal_error_code_1.InternalErrorCode.MASTER_HASH_INVALID]: HttpStatus.BAD_REQUEST,
|
|
85
|
-
[internal_error_code_1.InternalErrorCode.REPLAY_OUTCOME_MISMATCH]: HttpStatus.BAD_REQUEST,
|
|
86
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_POOL_CONTRIBUTION_ALREADY_PROCESSED]: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
87
|
-
[internal_error_code_1.InternalErrorCode.JACKPOT_TYPE_DOES_NOT_SUPPORT_TIERS]: HttpStatus.BAD_REQUEST,
|
|
88
|
-
[internal_error_code_1.InternalErrorCode.CONCURRENT_MODIFICATION]: HttpStatus.CONFLICT,
|
|
89
|
-
[internal_error_code_1.InternalErrorCode.ACCOUNT_LOCKED]: HttpStatus.FORBIDDEN,
|
|
90
|
-
[internal_error_code_1.InternalErrorCode.DAILY_LIMIT_EXCEEDED]: HttpStatus.UNPROCESSABLE_ENTITY,
|
|
91
|
-
[internal_error_code_1.InternalErrorCode.INVALID_AMOUNT]: HttpStatus.BAD_REQUEST,
|
|
92
35
|
[internal_error_code_1.InternalErrorCode.SERVICE_UNAVAILABLE]: HttpStatus.SERVICE_UNAVAILABLE,
|
|
36
|
+
// Health check
|
|
37
|
+
[internal_error_code_1.InternalErrorCode.HEALTH_CHECK_FAILED]: HttpStatus.SERVICE_UNAVAILABLE,
|
|
93
38
|
};
|