@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.
Files changed (76) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/MIGRATION.md +126 -0
  3. package/dist/bootstrap/index.d.ts +4 -1
  4. package/dist/bootstrap/index.d.ts.map +1 -1
  5. package/dist/bootstrap/index.js +32 -32
  6. package/dist/common/api-docs/setup-documentation.d.ts +1 -1
  7. package/dist/common/api-docs/setup-documentation.d.ts.map +1 -1
  8. package/dist/common/error-handling/all-exceptions.filter.d.ts +0 -3
  9. package/dist/common/error-handling/all-exceptions.filter.d.ts.map +1 -1
  10. package/dist/common/error-handling/all-exceptions.filter.js +35 -21
  11. package/dist/common/error-handling/error-code-mapper.d.ts.map +1 -1
  12. package/dist/common/error-handling/error-code-mapper.js +15 -70
  13. package/dist/common/error-handling/internal-error-code.d.ts +13 -59
  14. package/dist/common/error-handling/internal-error-code.d.ts.map +1 -1
  15. package/dist/common/error-handling/internal-error-code.js +16 -68
  16. package/dist/common/logger/logger.d.ts +2 -3
  17. package/dist/common/logger/logger.d.ts.map +1 -1
  18. package/dist/common/logger/logger.js +3 -16
  19. package/dist/common/logger/logging.middleware.d.ts.map +1 -1
  20. package/dist/common/logger/logging.middleware.js +16 -4
  21. package/dist/common/metrics/prometheus.service.d.ts +5 -0
  22. package/dist/common/metrics/prometheus.service.d.ts.map +1 -1
  23. package/dist/common/metrics/prometheus.service.js +43 -3
  24. package/dist/common/retry/retry-policy.d.ts.map +1 -1
  25. package/dist/common/retry/retry-policy.js +9 -4
  26. package/dist/common/secrets-provider/secrets-provider.aws.d.ts.map +1 -1
  27. package/dist/common/secrets-provider/secrets-provider.aws.js +2 -1
  28. package/dist/esm/bootstrap/index.js +33 -33
  29. package/dist/esm/common/error-handling/all-exceptions.filter.js +36 -22
  30. package/dist/esm/common/error-handling/error-code-mapper.js +15 -70
  31. package/dist/esm/common/error-handling/internal-error-code.js +16 -68
  32. package/dist/esm/common/logger/logger.js +3 -16
  33. package/dist/esm/common/logger/logging.middleware.js +16 -4
  34. package/dist/esm/common/metrics/prometheus.service.js +10 -3
  35. package/dist/esm/common/retry/retry-policy.js +9 -4
  36. package/dist/esm/common/secrets-provider/secrets-provider.aws.js +2 -1
  37. package/dist/esm/generated/game-engine-registry_pb.js +5 -11
  38. package/dist/esm/generated/game-engine_pb.js +10 -24
  39. package/dist/esm/grpc/connect-router.middleware.js +7 -1
  40. package/dist/esm/grpc/game-engine.grpc.in-adapter.js +64 -20
  41. package/dist/esm/health/application/services/health.service.js +33 -39
  42. package/dist/esm/health/health.module.js +1 -1
  43. package/dist/esm/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.js +19 -4
  44. package/dist/esm/registration/adapters/game-engine-registry.grpc.out-adapter.js +3 -4
  45. package/dist/esm/registration/services/game-engine-auto-register.service.js +11 -8
  46. package/dist/generated/game-engine-registry_pb.d.ts +5 -5
  47. package/dist/generated/game-engine-registry_pb.d.ts.map +1 -1
  48. package/dist/generated/game-engine-registry_pb.js +4 -10
  49. package/dist/generated/game-engine_pb.d.ts +26 -10
  50. package/dist/generated/game-engine_pb.d.ts.map +1 -1
  51. package/dist/generated/game-engine_pb.js +8 -22
  52. package/dist/grpc/connect-router.middleware.d.ts +9 -1
  53. package/dist/grpc/connect-router.middleware.d.ts.map +1 -1
  54. package/dist/grpc/connect-router.middleware.js +7 -1
  55. package/dist/grpc/game-engine.grpc.in-adapter.d.ts +18 -3
  56. package/dist/grpc/game-engine.grpc.in-adapter.d.ts.map +1 -1
  57. package/dist/grpc/game-engine.grpc.in-adapter.js +64 -20
  58. package/dist/grpc/index.d.ts +1 -1
  59. package/dist/grpc/index.d.ts.map +1 -1
  60. package/dist/health/application/ports/out/shutdown.out-port.d.ts +2 -0
  61. package/dist/health/application/ports/out/shutdown.out-port.d.ts.map +1 -1
  62. package/dist/health/application/services/health.service.d.ts.map +1 -1
  63. package/dist/health/application/services/health.service.js +33 -39
  64. package/dist/health/domain/health.d.ts +1 -1
  65. package/dist/health/domain/health.d.ts.map +1 -1
  66. package/dist/health/health.module.js +1 -1
  67. package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.d.ts +2 -1
  68. package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.d.ts.map +1 -1
  69. package/dist/health/infrastructure/adapters/out/shutdown/shutdown.out-adapter.js +19 -4
  70. package/dist/registration/adapters/game-engine-registry.grpc.out-adapter.d.ts.map +1 -1
  71. package/dist/registration/adapters/game-engine-registry.grpc.out-adapter.js +3 -4
  72. package/dist/registration/services/game-engine-auto-register.service.d.ts.map +1 -1
  73. package/dist/registration/services/game-engine-auto-register.service.js +11 -8
  74. package/dist/types.d.ts +6 -5
  75. package/dist/types.d.ts.map +1 -1
  76. package/package.json +5 -3
@@ -4,22 +4,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  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;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- var __metadata = (this && this.__metadata) || function (k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- };
10
- var __param = (this && this.__param) || function (paramIndex, decorator) {
11
- return function (target, key) { decorator(target, key, paramIndex); }
12
- };
13
7
  var ExceptionsFilter_1;
14
8
  import { Logger } from '../logger/logger';
15
- import { METRICS_PORT } from '../metrics/metrics.port';
16
- import { Catch, HttpException, HttpStatus, Inject, } from '@nestjs/common';
9
+ import { Catch, HttpException, HttpStatus } from '@nestjs/common';
17
10
  import { DomainException } from './domain.exception';
18
11
  import { ErrorCodeMapper } from './error-code-mapper';
19
12
  import { InternalErrorCode } from './internal-error-code';
20
13
  let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
21
- constructor(metricsPort) {
22
- this.metricsPort = metricsPort;
14
+ constructor() {
23
15
  this.logger = new Logger(ExceptionsFilter_1.name);
24
16
  }
25
17
  catch(exception, host) {
@@ -44,14 +36,17 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
44
36
  handleDomainException(exception, request) {
45
37
  const status = ErrorCodeMapper.mapToHttpStatus(exception.errorCode);
46
38
  const level = status >= 500 ? 'error' : 'warn';
39
+ // Log full internal details for debugging — never sent to client
47
40
  this.logger.log(`DomainException (status: ${status} at ${request.method} ${request.url}): Internal Code ${exception.errorCode} Message: ${exception.message}`, { level });
48
41
  if (exception.cause) {
49
42
  this.logger.error('Exception cause:', exception.cause);
50
43
  }
44
+ // OWASP A01: Return error code only — never expose internal error.message to clients.
45
+ // Consistent with gRPC error sanitization in GameEngineGrpcInAdapter.
51
46
  return this.buildResponsePayload({
52
47
  status,
53
48
  internalCode: exception.errorCode,
54
- message: exception.message,
49
+ message: exception.errorCode,
55
50
  path: request.url,
56
51
  });
57
52
  }
@@ -59,17 +54,29 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
59
54
  const status = exception.getStatus();
60
55
  const responseData = exception.getResponse();
61
56
  // Check if this is a custom validation error response
62
- if (typeof responseData === 'object' &&
63
- responseData.internalCode &&
64
- responseData.statusCode) {
65
- return responseData;
57
+ const responseRecord = typeof responseData === 'object' && responseData !== null
58
+ ? responseData
59
+ : null;
60
+ if (responseRecord &&
61
+ typeof responseRecord.internalCode === 'string' &&
62
+ typeof responseRecord.statusCode === 'number' &&
63
+ typeof responseRecord.message !== 'undefined') {
64
+ return {
65
+ statusCode: responseRecord.statusCode,
66
+ internalCode: responseRecord.internalCode,
67
+ message: String(responseRecord.message),
68
+ timestamp: typeof responseRecord.timestamp === 'string'
69
+ ? responseRecord.timestamp
70
+ : new Date().toISOString(),
71
+ path: typeof responseRecord.path === 'string' ? responseRecord.path : request.url,
72
+ };
66
73
  }
67
74
  let message = 'HTTP Exception';
68
75
  if (typeof responseData === 'string') {
69
76
  message = responseData;
70
77
  }
71
- else if (typeof responseData === 'object' && responseData.message) {
72
- message = responseData.message;
78
+ else if (responseRecord && typeof responseRecord.message === 'string') {
79
+ message = responseRecord.message;
73
80
  }
74
81
  const level = status >= 500 ? 'error' : 'warn';
75
82
  this.logger.log(`HttpException (status: ${status} at ${request.method} ${request.url}): ${message}`, { level });
@@ -82,12 +89,21 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
82
89
  path: request.url,
83
90
  });
84
91
  }
85
- if (status === HttpStatus.INTERNAL_SERVER_ERROR) {
92
+ // OWASP A01: Never expose internal error details for server errors.
93
+ // 5xx messages may contain stack traces, DB errors, or internal details.
94
+ if (status >= 500) {
86
95
  this.logger.error('HttpException stack:', exception.stack);
96
+ return this.buildResponsePayload({
97
+ status,
98
+ internalCode: InternalErrorCode.INTERNAL_SERVER_ERROR,
99
+ message: 'Internal server error',
100
+ path: request.url,
101
+ });
87
102
  }
103
+ // 4xx client errors — framework messages are safe (e.g., "Not Found", "Bad Request")
88
104
  return this.buildResponsePayload({
89
105
  status,
90
- internalCode: InternalErrorCode.INTERNAL_SERVER_ERROR,
106
+ internalCode: InternalErrorCode.VALIDATION_ERROR,
91
107
  message,
92
108
  path: request.url,
93
109
  });
@@ -121,8 +137,6 @@ let ExceptionsFilter = ExceptionsFilter_1 = class ExceptionsFilter {
121
137
  }
122
138
  };
123
139
  ExceptionsFilter = ExceptionsFilter_1 = __decorate([
124
- Catch(),
125
- __param(0, Inject(METRICS_PORT)),
126
- __metadata("design:paramtypes", [Object])
140
+ Catch()
127
141
  ], ExceptionsFilter);
128
142
  export { ExceptionsFilter };
@@ -2,88 +2,33 @@ import { InternalErrorCode } from './internal-error-code';
2
2
  // HTTP status codes
3
3
  const HttpStatus = {
4
4
  BAD_REQUEST: 400,
5
- CONFLICT: 409,
5
+ UNAUTHORIZED: 401,
6
6
  FORBIDDEN: 403,
7
7
  NOT_FOUND: 404,
8
+ CONFLICT: 409,
8
9
  UNPROCESSABLE_ENTITY: 422,
9
10
  INTERNAL_SERVER_ERROR: 500,
10
11
  SERVICE_UNAVAILABLE: 503,
11
12
  };
12
13
  export class ErrorCodeMapper {
13
14
  static mapToHttpStatus(errorCode) {
14
- return this.ERROR_CODE_TO_HTTP_MAP[errorCode] || HttpStatus.BAD_REQUEST;
15
+ return this.ERROR_CODE_TO_HTTP_MAP[errorCode] ?? HttpStatus.INTERNAL_SERVER_ERROR;
15
16
  }
16
17
  }
17
18
  ErrorCodeMapper.ERROR_CODE_TO_HTTP_MAP = {
18
- [InternalErrorCode.FORBIDDEN]: HttpStatus.FORBIDDEN,
19
- [InternalErrorCode.INVALID_CURRENCY_CODE]: HttpStatus.BAD_REQUEST,
20
- [InternalErrorCode.INSUFFICIENT_FUNDS]: HttpStatus.UNPROCESSABLE_ENTITY,
21
- [InternalErrorCode.INTERNAL_SERVER_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
22
- // Game Catalog errors
23
- [InternalErrorCode.GAME_NOT_FOUND]: HttpStatus.NOT_FOUND,
24
- [InternalErrorCode.GAME_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
25
- [InternalErrorCode.GAME_CONFIG_ALREADY_EXISTS_WITH_SAME_JURISDICTION_AND_RTP]: HttpStatus.BAD_REQUEST,
26
- [InternalErrorCode.OPERATOR_GAME_NOT_FOUND]: HttpStatus.NOT_FOUND,
27
- [InternalErrorCode.OPERATOR_GAME_ALREADY_ENABLED]: HttpStatus.BAD_REQUEST,
28
- [InternalErrorCode.INVALID_GAME_CONFIG_DATA]: HttpStatus.BAD_REQUEST,
29
- [InternalErrorCode.INVALID_GAME_UPDATE_DATA]: HttpStatus.BAD_REQUEST,
30
- [InternalErrorCode.GAME_CODE_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
31
- [InternalErrorCode.GAME_OR_GAME_CONFIG_DISABLED]: HttpStatus.BAD_REQUEST,
19
+ // Core game engine errors
20
+ [InternalErrorCode.GAME_ENGINE_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
32
21
  [InternalErrorCode.DEBUG_COMMANDS_DISABLED]: HttpStatus.FORBIDDEN,
33
- // Game Orchestrator errors
34
- [InternalErrorCode.INVALID_SESSION]: HttpStatus.BAD_REQUEST,
35
- [InternalErrorCode.SESSION_NOT_FOUND]: HttpStatus.NOT_FOUND,
36
- [InternalErrorCode.SESSION_NOT_ACTIVE]: HttpStatus.BAD_REQUEST,
37
- [InternalErrorCode.SESSION_MISMATCH]: HttpStatus.BAD_REQUEST,
38
- [InternalErrorCode.INVALID_STATE_TRANSITION]: HttpStatus.BAD_REQUEST,
39
- [InternalErrorCode.INVALID_BET_AMOUNT]: HttpStatus.BAD_REQUEST,
40
- [InternalErrorCode.REALITY_CHECK_IN_PROGRESS]: HttpStatus.BAD_REQUEST,
41
- [InternalErrorCode.UNKNOWN_COMMAND]: HttpStatus.NOT_FOUND,
42
- // Operator errors
43
- [InternalErrorCode.MISSING_OPERATOR_CODE]: HttpStatus.BAD_REQUEST,
44
- [InternalErrorCode.INVALID_OPERATOR_CODE]: HttpStatus.BAD_REQUEST,
45
- [InternalErrorCode.OPERATOR_NOT_FOUND]: HttpStatus.NOT_FOUND,
46
- [InternalErrorCode.OPERATOR_INACTIVE]: HttpStatus.FORBIDDEN,
47
- [InternalErrorCode.COUNTRY_CODE_RESTRICTED]: HttpStatus.BAD_REQUEST,
48
- [InternalErrorCode.UNAUTHORIZED]: HttpStatus.FORBIDDEN,
49
- [InternalErrorCode.AUTH_VALIDATION_FAILED]: HttpStatus.FORBIDDEN,
50
- [InternalErrorCode.BALANCE_NOT_FOUND]: HttpStatus.NOT_FOUND,
51
- [InternalErrorCode.INVALID_AUTH_DATA]: HttpStatus.BAD_REQUEST,
22
+ [InternalErrorCode.UNKNOWN_COMMAND]: HttpStatus.BAD_REQUEST,
23
+ [InternalErrorCode.INVALID_COMMAND]: HttpStatus.BAD_REQUEST,
24
+ // RNG integrity (GLI-19)
25
+ [InternalErrorCode.INVALID_RNG_SEED]: HttpStatus.INTERNAL_SERVER_ERROR,
26
+ // Infrastructure errors
27
+ [InternalErrorCode.INTERNAL_SERVER_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
28
+ [InternalErrorCode.FORBIDDEN]: HttpStatus.FORBIDDEN,
29
+ [InternalErrorCode.UNAUTHORIZED]: HttpStatus.UNAUTHORIZED,
52
30
  [InternalErrorCode.VALIDATION_ERROR]: HttpStatus.BAD_REQUEST,
53
- [InternalErrorCode.JURISDICTION_CONFIG_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
54
- [InternalErrorCode.JURISDICTION_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
55
- [InternalErrorCode.OPERATOR_JURISDICTION_CONFIG_NOT_FOUND]: HttpStatus.NOT_FOUND,
56
- [InternalErrorCode.GAME_ENGINE_ERROR]: HttpStatus.INTERNAL_SERVER_ERROR,
57
- [InternalErrorCode.DEBIT_FAILED]: HttpStatus.BAD_REQUEST,
58
- [InternalErrorCode.CREDIT_FAILED]: HttpStatus.BAD_REQUEST,
59
- [InternalErrorCode.GAME_ROUND_LOG_NOT_FOUND]: HttpStatus.NOT_FOUND,
60
- // Geo Validation errors
61
- [InternalErrorCode.COUNTRY_NOT_PERMITTED]: HttpStatus.FORBIDDEN,
62
- [InternalErrorCode.GEO_VALIDATION_SERVICE_UNAVAILABLE]: HttpStatus.INTERNAL_SERVER_ERROR,
63
- [InternalErrorCode.RESOURCE_NOT_FOUND]: HttpStatus.NOT_FOUND,
64
- [InternalErrorCode.FINANCIAL_TRANSACTION_NOT_FOUND]: HttpStatus.NOT_FOUND,
65
- [InternalErrorCode.SESSION_TERMINATED]: HttpStatus.BAD_REQUEST,
66
- [InternalErrorCode.SESSION_CANNOT_BE_TERMINATED]: HttpStatus.BAD_REQUEST,
67
- [InternalErrorCode.SESSION_AUTO_RESOLVE_FAILED]: HttpStatus.BAD_REQUEST,
68
- [InternalErrorCode.SESSION_ALREADY_EXISTS]: HttpStatus.BAD_REQUEST,
69
- [InternalErrorCode.INCOMPATIBLE_GAMEPLAY_CONFIG]: HttpStatus.BAD_REQUEST,
70
- // Health check errors
71
- [InternalErrorCode.HEALTH_CHECK_FAILED]: HttpStatus.SERVICE_UNAVAILABLE,
72
- //Jackpot errors
73
- [InternalErrorCode.JACKPOT_TYPE_NOT_FOUND]: HttpStatus.NOT_FOUND,
74
- [InternalErrorCode.JACKPOT_TIER_NOT_FOUND]: HttpStatus.NOT_FOUND,
75
- [InternalErrorCode.JACKPOT_CONFIGURATION_NOT_FOUND]: HttpStatus.NOT_FOUND,
76
- [InternalErrorCode.JACKPOT_CONFIGURATION_IS_ACTIVE]: HttpStatus.BAD_REQUEST,
77
- // RNG and Replay errors
78
- [InternalErrorCode.RNG_SEED_NOT_FOUND]: HttpStatus.NOT_FOUND,
79
- [InternalErrorCode.RNG_SEED_MISMATCH]: HttpStatus.BAD_REQUEST,
80
- [InternalErrorCode.MASTER_HASH_INVALID]: HttpStatus.BAD_REQUEST,
81
- [InternalErrorCode.REPLAY_OUTCOME_MISMATCH]: HttpStatus.BAD_REQUEST,
82
- [InternalErrorCode.JACKPOT_POOL_CONTRIBUTION_ALREADY_PROCESSED]: HttpStatus.INTERNAL_SERVER_ERROR,
83
- [InternalErrorCode.JACKPOT_TYPE_DOES_NOT_SUPPORT_TIERS]: HttpStatus.BAD_REQUEST,
84
- [InternalErrorCode.CONCURRENT_MODIFICATION]: HttpStatus.CONFLICT,
85
- [InternalErrorCode.ACCOUNT_LOCKED]: HttpStatus.FORBIDDEN,
86
- [InternalErrorCode.DAILY_LIMIT_EXCEEDED]: HttpStatus.UNPROCESSABLE_ENTITY,
87
- [InternalErrorCode.INVALID_AMOUNT]: HttpStatus.BAD_REQUEST,
88
31
  [InternalErrorCode.SERVICE_UNAVAILABLE]: HttpStatus.SERVICE_UNAVAILABLE,
32
+ // Health check
33
+ [InternalErrorCode.HEALTH_CHECK_FAILED]: HttpStatus.SERVICE_UNAVAILABLE,
89
34
  };
@@ -1,77 +1,25 @@
1
+ /**
2
+ * Error codes relevant to game engine services.
3
+ *
4
+ * Scoped to game-engine SDK concerns only.
5
+ * Platform-level codes (sessions, operators, jackpots, geo, etc.)
6
+ * belong in the RGS platform, not in individual engine services.
7
+ */
1
8
  export var InternalErrorCode;
2
9
  (function (InternalErrorCode) {
3
- InternalErrorCode["FORBIDDEN"] = "FORBIDDEN";
4
- InternalErrorCode["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
5
- InternalErrorCode["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS";
6
- InternalErrorCode["INVALID_CURRENCY_CODE"] = "INVALID_CURRENCY_CODE";
7
- // Game Catalog errors
8
- InternalErrorCode["GAME_NOT_FOUND"] = "GAME_NOT_FOUND";
9
- InternalErrorCode["GAME_CONFIG_NOT_FOUND"] = "GAME_CONFIG_NOT_FOUND";
10
- InternalErrorCode["GAME_CONFIG_ALREADY_EXISTS_WITH_SAME_JURISDICTION_AND_RTP"] = "GAME_CONFIG_ALREADY_EXISTS_WITH_SAME_JURISDICTION_AND_RTP";
11
- InternalErrorCode["OPERATOR_GAME_NOT_FOUND"] = "OPERATOR_GAME_NOT_FOUND";
12
- InternalErrorCode["OPERATOR_GAME_ALREADY_ENABLED"] = "OPERATOR_GAME_ALREADY_ENABLED";
13
- InternalErrorCode["INVALID_GAME_CONFIG_DATA"] = "INVALID_GAME_CONFIG_DATA";
14
- InternalErrorCode["INVALID_GAME_UPDATE_DATA"] = "INVALID_GAME_UPDATE_DATA";
15
- InternalErrorCode["GAME_CODE_ALREADY_EXISTS"] = "GAME_CODE_ALREADY_EXISTS";
10
+ // Core game engine errors
16
11
  InternalErrorCode["GAME_ENGINE_ERROR"] = "GAME_ENGINE_ERROR";
17
- InternalErrorCode["GAME_OR_GAME_CONFIG_DISABLED"] = "GAME_OR_GAME_CONFIG_DISABLED";
18
12
  InternalErrorCode["DEBUG_COMMANDS_DISABLED"] = "DEBUG_COMMANDS_DISABLED";
19
- // Game Orchestrator errors
20
- InternalErrorCode["INVALID_SESSION"] = "INVALID_SESSION";
21
- InternalErrorCode["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
22
- InternalErrorCode["SESSION_NOT_ACTIVE"] = "SESSION_NOT_ACTIVE";
23
- InternalErrorCode["SESSION_MISMATCH"] = "SESSION_MISMATCH";
24
- InternalErrorCode["INVALID_STATE_TRANSITION"] = "INVALID_STATE_TRANSITION";
25
- InternalErrorCode["INVALID_BET_AMOUNT"] = "INVALID_BET_AMOUNT";
26
- InternalErrorCode["REALITY_CHECK_IN_PROGRESS"] = "REALITY_CHECK_IN_PROGRESS";
27
- InternalErrorCode["SESSION_TERMINATED"] = "SESSION_TERMINATED";
28
- InternalErrorCode["SESSION_CANNOT_BE_TERMINATED"] = "SESSION_CANNOT_BE_TERMINATED";
29
- InternalErrorCode["SESSION_AUTO_RESOLVE_FAILED"] = "SESSION_AUTO_RESOLVE_FAILED";
30
- InternalErrorCode["SESSION_ALREADY_EXISTS"] = "SESSION_ALREADY_EXISTS";
31
- InternalErrorCode["INCOMPATIBLE_GAMEPLAY_CONFIG"] = "INCOMPATIBLE_GAMEPLAY_CONFIG";
32
13
  InternalErrorCode["UNKNOWN_COMMAND"] = "UNKNOWN_COMMAND";
33
- // Operator errors
34
- InternalErrorCode["MISSING_OPERATOR_CODE"] = "MISSING_OPERATOR_CODE";
35
- InternalErrorCode["INVALID_OPERATOR_CODE"] = "INVALID_OPERATOR_CODE";
36
- InternalErrorCode["OPERATOR_NOT_FOUND"] = "OPERATOR_NOT_FOUND";
37
- InternalErrorCode["OPERATOR_INACTIVE"] = "OPERATOR_INACTIVE";
38
- InternalErrorCode["COUNTRY_CODE_RESTRICTED"] = "COUNTRY_CODE_RESTRICTED";
14
+ InternalErrorCode["INVALID_COMMAND"] = "INVALID_COMMAND";
15
+ // RNG integrity (GLI-19)
16
+ InternalErrorCode["INVALID_RNG_SEED"] = "INVALID_RNG_SEED";
17
+ // Infrastructure errors
18
+ InternalErrorCode["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
19
+ InternalErrorCode["FORBIDDEN"] = "FORBIDDEN";
39
20
  InternalErrorCode["UNAUTHORIZED"] = "UNAUTHORIZED";
40
- InternalErrorCode["AUTH_VALIDATION_FAILED"] = "AUTH_VALIDATION_FAILED";
41
- InternalErrorCode["BALANCE_NOT_FOUND"] = "BALANCE_NOT_FOUND";
42
- InternalErrorCode["DEBIT_FAILED"] = "DEBIT_FAILED";
43
- InternalErrorCode["CREDIT_FAILED"] = "CREDIT_FAILED";
44
- InternalErrorCode["INVALID_AUTH_DATA"] = "INVALID_AUTH_DATA";
45
21
  InternalErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
46
- InternalErrorCode["JURISDICTION_CONFIG_ALREADY_EXISTS"] = "JURISDICTION_CONFIG_ALREADY_EXISTS";
47
- InternalErrorCode["JURISDICTION_CONFIG_NOT_FOUND"] = "JURISDICTION_CONFIG_NOT_FOUND";
48
- InternalErrorCode["OPERATOR_JURISDICTION_CONFIG_NOT_FOUND"] = "OPERATOR_JURISDICTION_CONFIG_NOT_FOUND";
49
- // Game round log errors
50
- InternalErrorCode["GAME_ROUND_LOG_NOT_FOUND"] = "GAME_ROUND_LOG_NOT_FOUND";
51
- // Geo Validation errors
52
- InternalErrorCode["COUNTRY_NOT_PERMITTED"] = "COUNTRY_NOT_PERMITTED";
53
- InternalErrorCode["GEO_VALIDATION_SERVICE_UNAVAILABLE"] = "GEO_VALIDATION_SERVICE_UNAVAILABLE";
54
- InternalErrorCode["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND";
55
- // Financial transaction errors
56
- InternalErrorCode["FINANCIAL_TRANSACTION_NOT_FOUND"] = "FINANCIAL_TRANSACTION_NOT_FOUND";
57
- //Health check errors
58
- InternalErrorCode["HEALTH_CHECK_FAILED"] = "HEALTH_CHECK_FAILED";
59
- //Jackpot errors
60
- InternalErrorCode["JACKPOT_TYPE_NOT_FOUND"] = "JACKPOT_TYPE_NOT_FOUND";
61
- InternalErrorCode["JACKPOT_TIER_NOT_FOUND"] = "JACKPOT_TIER_NOT_FOUND";
62
- InternalErrorCode["JACKPOT_CONFIGURATION_NOT_FOUND"] = "JACKPOT_CONFIGURATION_NOT_FOUND";
63
- InternalErrorCode["JACKPOT_CONFIGURATION_IS_ACTIVE"] = "JACKPOT_CONFIGURATION_IS_ACTIVE";
64
- InternalErrorCode["JACKPOT_POOL_CONTRIBUTION_ALREADY_PROCESSED"] = "JACKPOT_POOL_CONTRIBUTION_ALREADY_PROCESSED";
65
- InternalErrorCode["JACKPOT_TYPE_DOES_NOT_SUPPORT_TIERS"] = "JACKPOT_TYPE_DOES_NOT_SUPPORT_TIERS";
66
- // RNG and Replay errors
67
- InternalErrorCode["RNG_SEED_NOT_FOUND"] = "RNG_SEED_NOT_FOUND";
68
- InternalErrorCode["RNG_SEED_MISMATCH"] = "RNG_SEED_MISMATCH";
69
- InternalErrorCode["MASTER_HASH_INVALID"] = "MASTER_HASH_INVALID";
70
- InternalErrorCode["REPLAY_OUTCOME_MISMATCH"] = "REPLAY_OUTCOME_MISMATCH";
71
- // Concurrency
72
- InternalErrorCode["CONCURRENT_MODIFICATION"] = "CONCURRENT_MODIFICATION";
73
- InternalErrorCode["ACCOUNT_LOCKED"] = "ACCOUNT_LOCKED";
74
- InternalErrorCode["DAILY_LIMIT_EXCEEDED"] = "DAILY_LIMIT_EXCEEDED";
75
- InternalErrorCode["INVALID_AMOUNT"] = "INVALID_AMOUNT";
76
22
  InternalErrorCode["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
23
+ // Health check
24
+ InternalErrorCode["HEALTH_CHECK_FAILED"] = "HEALTH_CHECK_FAILED";
77
25
  })(InternalErrorCode || (InternalErrorCode = {}));
@@ -66,25 +66,12 @@ export class Logger {
66
66
  return output;
67
67
  }));
68
68
  }
69
- safeStringify(obj) {
70
- try {
71
- return JSON.stringify(obj, (key, value) => {
72
- if (typeof value === 'bigint') {
73
- return value.toString();
74
- }
75
- return value;
76
- });
77
- }
78
- catch (_error) {
79
- return '[Object cannot be serialized]';
80
- }
81
- }
82
69
  getTransports() {
83
- const logTransports = [new transports.Console()];
70
+ const consoleTransport = new transports.Console();
84
71
  if (process.env.LOG_TO_FILE === 'true') {
85
- logTransports.push(new transports.File({ filename: 'logs/app.log' }));
72
+ return [consoleTransport, new transports.File({ filename: 'logs/app.log' })];
86
73
  }
87
- return logTransports;
74
+ return [consoleTransport];
88
75
  }
89
76
  log(message, { level = 'info', ...rest } = {}) {
90
77
  switch (level) {
@@ -10,11 +10,23 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var LoggingMiddleware_1;
11
11
  import { Injectable } from '@nestjs/common';
12
12
  import { Logger } from './logger';
13
- const BLOCKED_ENDPOINTS = ['/api/races/active'];
13
+ /** Endpoints to suppress from logging on success. Configurable via LOG_BLOCKED_ENDPOINTS env var (comma-separated). */
14
+ const BLOCKED_ENDPOINTS = process.env.LOG_BLOCKED_ENDPOINTS
15
+ ? process.env.LOG_BLOCKED_ENDPOINTS.split(',').map(e => e.trim())
16
+ : [];
14
17
  const SENSITIVE_FIELDS = new Set([
15
- 'password', 'token', 'secret', 'authorization',
16
- 'apikey', 'api_key', 'accesstoken', 'refreshtoken',
17
- 'creditcard', 'ssn', 'private_key', 'privatekey',
18
+ 'password',
19
+ 'token',
20
+ 'secret',
21
+ 'authorization',
22
+ 'apikey',
23
+ 'api_key',
24
+ 'accesstoken',
25
+ 'refreshtoken',
26
+ 'creditcard',
27
+ 'ssn',
28
+ 'private_key',
29
+ 'privatekey',
18
30
  ]);
19
31
  function sanitize(obj) {
20
32
  if (obj === null || obj === undefined || typeof obj !== 'object')
@@ -30,8 +30,9 @@ let PrometheusService = class PrometheusService {
30
30
  this.metricsRegistry = new Map();
31
31
  this.initializeRegistry();
32
32
  }
33
- initializeMetricsFromDatabase() {
34
- throw new Error('Method not implemented.');
33
+ async initializeMetricsFromDatabase() {
34
+ // No-op: Game engine metrics are initialized from Prometheus registry, not database.
35
+ // Override in subclass if database-backed metric initialization is needed.
35
36
  }
36
37
  initializeRegistry() {
37
38
  this.metricsRegistry.set('game_engine_commands_total', this.engineCommandsTotal);
@@ -68,8 +69,14 @@ let PrometheusService = class PrometheusService {
68
69
  }
69
70
  return metric;
70
71
  }
72
+ /**
73
+ * Returns Prometheus text format metrics from the default prom-client registry.
74
+ * The @willsoto/nestjs-prometheus module also exposes a /metrics HTTP endpoint
75
+ * automatically — this method is for programmatic access via the MetricsPort.
76
+ */
71
77
  async getMetrics() {
72
- return '';
78
+ const { register } = await import('prom-client');
79
+ return register.metrics();
73
80
  }
74
81
  };
75
82
  PrometheusService = __decorate([
@@ -21,7 +21,7 @@ export class RetryPolicy {
21
21
  return result;
22
22
  }
23
23
  catch (error) {
24
- const err = error;
24
+ const err = error instanceof Error ? error : new Error(String(error));
25
25
  lastError = err;
26
26
  if (!this.isRetryable(err)) {
27
27
  throw err;
@@ -36,7 +36,9 @@ export class RetryPolicy {
36
36
  try {
37
37
  this.onRetry(attempt, err);
38
38
  }
39
- catch { }
39
+ catch (callbackError) {
40
+ this.logger.debug(`onRetry callback threw: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}`);
41
+ }
40
42
  }
41
43
  await this.sleep(delay);
42
44
  }
@@ -46,8 +48,11 @@ export class RetryPolicy {
46
48
  isRetryable(error) {
47
49
  if (!this.retryableErrors || this.retryableErrors.length === 0)
48
50
  return true;
49
- const causeCode = error?.cause?.code ?? '';
50
- const text = `${error?.code ?? ''} ${error?.name ?? ''} ${error.message} ${causeCode}`;
51
+ const errorRecord = error;
52
+ const cause = errorRecord.cause;
53
+ const causeCode = typeof cause?.code === 'string' ? cause.code : '';
54
+ const errorCode = typeof errorRecord.code === 'string' ? errorRecord.code : '';
55
+ const text = `${errorCode} ${error.name} ${error.message} ${causeCode}`;
51
56
  return this.retryableErrors.some(pattern => text.includes(pattern));
52
57
  }
53
58
  calculateDelay(attempt) {
@@ -50,7 +50,8 @@ let AwsSecretsProvider = AwsSecretsProvider_1 = class AwsSecretsProvider {
50
50
  this.logger.log(`Successfully loaded secrets from AWS Secrets Manager.`);
51
51
  }
52
52
  catch (error) {
53
- this.logger.error(`Failed to retrieve secrets from AWS: ${error.message}`);
53
+ const errorMessage = error instanceof Error ? error.message : String(error);
54
+ this.logger.error(`Failed to retrieve secrets from AWS: ${errorMessage}`);
54
55
  throw error;
55
56
  }
56
57
  }
@@ -1,27 +1,21 @@
1
- // @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
1
+ // @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
2
2
  // @generated from file game-engine-registry.proto (package game_engine_registry, syntax proto3)
3
3
  /* eslint-disable */
4
- import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv2';
4
+ import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
5
5
  /**
6
6
  * Describes the file game-engine-registry.proto.
7
7
  */
8
- export const file_game_engine_registry =
9
- /*@__PURE__*/
10
- fileDesc('ChpnYW1lLWVuZ2luZS1yZWdpc3RyeS5wcm90bxIUZ2FtZV9lbmdpbmVfcmVnaXN0cnkilgEKGVJlZ2lzdGVyR2FtZUVuZ2luZVJlcXVlc3QSEQoJZ2FtZV9jb2RlGAEgASgJEg8KB3ZlcnNpb24YAiABKAkSCwoDcnRwGAMgASgBEhEKCWdhbWVfdHlwZRgEIAEoCRIQCghncnBjX3VybBgFIAEoCRIRCglnYW1lX25hbWUYBiABKAkSEAoIcHJvdmlkZXIYByABKAkiTwoaUmVnaXN0ZXJHYW1lRW5naW5lUmVzcG9uc2USDwoHc3VjY2VzcxgBIAEoCBIUCgdtZXNzYWdlGAIgASgJSACIAQFCCgoIX21lc3NhZ2UylAEKGUdhbWVFbmdpbmVSZWdpc3RyeVNlcnZpY2USdwoSUmVnaXN0ZXJHYW1lRW5naW5lEi8uZ2FtZV9lbmdpbmVfcmVnaXN0cnkuUmVnaXN0ZXJHYW1lRW5naW5lUmVxdWVzdBowLmdhbWVfZW5naW5lX3JlZ2lzdHJ5LlJlZ2lzdGVyR2FtZUVuZ2luZVJlc3BvbnNlYgZwcm90bzM');
8
+ export const file_game_engine_registry = /*@__PURE__*/ fileDesc("ChpnYW1lLWVuZ2luZS1yZWdpc3RyeS5wcm90bxIUZ2FtZV9lbmdpbmVfcmVnaXN0cnkilgEKGVJlZ2lzdGVyR2FtZUVuZ2luZVJlcXVlc3QSEQoJZ2FtZV9jb2RlGAEgASgJEg8KB3ZlcnNpb24YAiABKAkSCwoDcnRwGAMgASgBEhEKCWdhbWVfdHlwZRgEIAEoCRIQCghncnBjX3VybBgFIAEoCRIRCglnYW1lX25hbWUYBiABKAkSEAoIcHJvdmlkZXIYByABKAkiTwoaUmVnaXN0ZXJHYW1lRW5naW5lUmVzcG9uc2USDwoHc3VjY2VzcxgBIAEoCBIUCgdtZXNzYWdlGAIgASgJSACIAQFCCgoIX21lc3NhZ2UylAEKGUdhbWVFbmdpbmVSZWdpc3RyeVNlcnZpY2USdwoSUmVnaXN0ZXJHYW1lRW5naW5lEi8uZ2FtZV9lbmdpbmVfcmVnaXN0cnkuUmVnaXN0ZXJHYW1lRW5naW5lUmVxdWVzdBowLmdhbWVfZW5naW5lX3JlZ2lzdHJ5LlJlZ2lzdGVyR2FtZUVuZ2luZVJlc3BvbnNlYgZwcm90bzM");
11
9
  /**
12
10
  * Describes the message game_engine_registry.RegisterGameEngineRequest.
13
11
  * Use `create(RegisterGameEngineRequestSchema)` to create a new message.
14
12
  */
15
- export const RegisterGameEngineRequestSchema =
16
- /*@__PURE__*/
17
- messageDesc(file_game_engine_registry, 0);
13
+ export const RegisterGameEngineRequestSchema = /*@__PURE__*/ messageDesc(file_game_engine_registry, 0);
18
14
  /**
19
15
  * Describes the message game_engine_registry.RegisterGameEngineResponse.
20
16
  * Use `create(RegisterGameEngineResponseSchema)` to create a new message.
21
17
  */
22
- export const RegisterGameEngineResponseSchema =
23
- /*@__PURE__*/
24
- messageDesc(file_game_engine_registry, 1);
18
+ export const RegisterGameEngineResponseSchema = /*@__PURE__*/ messageDesc(file_game_engine_registry, 1);
25
19
  /**
26
20
  * @generated from service game_engine_registry.GameEngineRegistryService
27
21
  */
@@ -1,56 +1,42 @@
1
- // @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
1
+ // @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
2
2
  // @generated from file game-engine.proto (package game_engine, syntax proto3)
3
3
  /* eslint-disable */
4
- import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv2';
5
- import { file_google_protobuf_struct } from '@bufbuild/protobuf/wkt';
4
+ import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
5
+ import { file_google_protobuf_struct } from "@bufbuild/protobuf/wkt";
6
6
  /**
7
7
  * Describes the file game-engine.proto.
8
8
  */
9
- export const file_game_engine =
10
- /*@__PURE__*/
11
- fileDesc('ChFnYW1lLWVuZ2luZS5wcm90bxILZ2FtZV9lbmdpbmUi5QEKFVByb2Nlc3NDb21tYW5kUmVxdWVzdBIyCgxwdWJsaWNfc3RhdGUYASABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SACIAQESMwoNcHJpdmF0ZV9zdGF0ZRgCIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAYgBARI0Cgdjb21tYW5kGAMgASgLMh4uZ2FtZV9lbmdpbmUuR2FtZUFjdGlvbkNvbW1hbmRIAogBAUIPCg1fcHVibGljX3N0YXRlQhAKDl9wcml2YXRlX3N0YXRlQgoKCF9jb21tYW5kImgKEUdhbWVBY3Rpb25Db21tYW5kEgoKAmlkGAEgASgJEgwKBHR5cGUYAiABKAkSLQoHcGF5bG9hZBgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAIgBAUIKCghfcGF5bG9hZCJKChBSbmdPdXRjb21lUmVjb3JkEg4KBnJlc3VsdBgBIAEoARIMCgRzZWVkGAIgASgJEgsKA21pbhgDIAEoARILCgNtYXgYBCABKAEirgMKFlByb2Nlc3NDb21tYW5kUmVzcG9uc2USDwoHc3VjY2VzcxgBIAEoCBIyCgxwdWJsaWNfc3RhdGUYAiABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SACIAQESMwoNcHJpdmF0ZV9zdGF0ZRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAYgBARItCgdvdXRjb21lGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdEgCiAEBEhQKB21lc3NhZ2UYBSABKAlIA4gBARJICgtybmdfb3V0Y29tZRgGIAMoCzIzLmdhbWVfZW5naW5lLlByb2Nlc3NDb21tYW5kUmVzcG9uc2UuUm5nT3V0Y29tZUVudHJ5GlAKD1JuZ091dGNvbWVFbnRyeRILCgNrZXkYASABKAkSLAoFdmFsdWUYAiABKAsyHS5nYW1lX2VuZ2luZS5SbmdPdXRjb21lUmVjb3JkOgI4AUIPCg1fcHVibGljX3N0YXRlQhAKDl9wcml2YXRlX3N0YXRlQgoKCF9vdXRjb21lQgoKCF9tZXNzYWdlIhoKGEdldEdhbWVFbmdpbmVJbmZvUmVxdWVzdCJfChlHZXRHYW1lRW5naW5lSW5mb1Jlc3BvbnNlEhEKCWdhbWVfY29kZRgBIAEoCRIPCgd2ZXJzaW9uGAIgASgJEgsKA3J0cBgDIAEoARIRCglnYW1lX3R5cGUYBCABKAky0gEKEUdhbWVFbmdpbmVTZXJ2aWNlElkKDlByb2Nlc3NDb21tYW5kEiIuZ2FtZV9lbmdpbmUuUHJvY2Vzc0NvbW1hbmRSZXF1ZXN0GiMuZ2FtZV9lbmdpbmUuUHJvY2Vzc0NvbW1hbmRSZXNwb25zZRJiChFHZXRHYW1lRW5naW5lSW5mbxIlLmdhbWVfZW5naW5lLkdldEdhbWVFbmdpbmVJbmZvUmVxdWVzdBomLmdhbWVfZW5naW5lLkdldEdhbWVFbmdpbmVJbmZvUmVzcG9uc2ViBnByb3RvMw', [file_google_protobuf_struct]);
9
+ export const file_game_engine = /*@__PURE__*/ fileDesc("ChFnYW1lLWVuZ2luZS5wcm90bxILZ2FtZV9lbmdpbmUisAIKFVByb2Nlc3NDb21tYW5kUmVxdWVzdBIyCgxwdWJsaWNfc3RhdGUYASABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SACIAQESMwoNcHJpdmF0ZV9zdGF0ZRgCIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAYgBARI0Cgdjb21tYW5kGAMgASgLMh4uZ2FtZV9lbmdpbmUuR2FtZUFjdGlvbkNvbW1hbmRIAogBARI1Cg9hZGRpdGlvbmFsX2RhdGEYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SAOIAQFCDwoNX3B1YmxpY19zdGF0ZUIQCg5fcHJpdmF0ZV9zdGF0ZUIKCghfY29tbWFuZEISChBfYWRkaXRpb25hbF9kYXRhImgKEUdhbWVBY3Rpb25Db21tYW5kEgoKAmlkGAEgASgJEgwKBHR5cGUYAiABKAkSLQoHcGF5bG9hZBgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAIgBAUIKCghfcGF5bG9hZCJKChBSbmdPdXRjb21lUmVjb3JkEg4KBnJlc3VsdBgBIAEoARIMCgRzZWVkGAIgASgJEgsKA21pbhgDIAEoARILCgNtYXgYBCABKAEi+QMKFlByb2Nlc3NDb21tYW5kUmVzcG9uc2USDwoHc3VjY2VzcxgBIAEoCBIyCgxwdWJsaWNfc3RhdGUYAiABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SACIAQESMwoNcHJpdmF0ZV9zdGF0ZRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAYgBARItCgdvdXRjb21lGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdEgCiAEBEhQKB21lc3NhZ2UYBSABKAlIA4gBARJICgtybmdfb3V0Y29tZRgGIAMoCzIzLmdhbWVfZW5naW5lLlByb2Nlc3NDb21tYW5kUmVzcG9uc2UuUm5nT3V0Y29tZUVudHJ5EjUKD2FkZGl0aW9uYWxfZGF0YRgHIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIBIgBARpQCg9SbmdPdXRjb21lRW50cnkSCwoDa2V5GAEgASgJEiwKBXZhbHVlGAIgASgLMh0uZ2FtZV9lbmdpbmUuUm5nT3V0Y29tZVJlY29yZDoCOAFCDwoNX3B1YmxpY19zdGF0ZUIQCg5fcHJpdmF0ZV9zdGF0ZUIKCghfb3V0Y29tZUIKCghfbWVzc2FnZUISChBfYWRkaXRpb25hbF9kYXRhIhoKGEdldEdhbWVFbmdpbmVJbmZvUmVxdWVzdCKEAQoZR2V0R2FtZUVuZ2luZUluZm9SZXNwb25zZRIRCglnYW1lX2NvZGUYASABKAkSDwoHdmVyc2lvbhgCIAEoCRILCgNydHAYAyABKAESEQoJZ2FtZV90eXBlGAQgASgJEhEKCWdhbWVfbmFtZRgFIAEoCRIQCghwcm92aWRlchgGIAEoCTLSAQoRR2FtZUVuZ2luZVNlcnZpY2USWQoOUHJvY2Vzc0NvbW1hbmQSIi5nYW1lX2VuZ2luZS5Qcm9jZXNzQ29tbWFuZFJlcXVlc3QaIy5nYW1lX2VuZ2luZS5Qcm9jZXNzQ29tbWFuZFJlc3BvbnNlEmIKEUdldEdhbWVFbmdpbmVJbmZvEiUuZ2FtZV9lbmdpbmUuR2V0R2FtZUVuZ2luZUluZm9SZXF1ZXN0GiYuZ2FtZV9lbmdpbmUuR2V0R2FtZUVuZ2luZUluZm9SZXNwb25zZWIGcHJvdG8z", [file_google_protobuf_struct]);
12
10
  /**
13
11
  * Describes the message game_engine.ProcessCommandRequest.
14
12
  * Use `create(ProcessCommandRequestSchema)` to create a new message.
15
13
  */
16
- export const ProcessCommandRequestSchema =
17
- /*@__PURE__*/
18
- messageDesc(file_game_engine, 0);
14
+ export const ProcessCommandRequestSchema = /*@__PURE__*/ messageDesc(file_game_engine, 0);
19
15
  /**
20
16
  * Describes the message game_engine.GameActionCommand.
21
17
  * Use `create(GameActionCommandSchema)` to create a new message.
22
18
  */
23
- export const GameActionCommandSchema =
24
- /*@__PURE__*/
25
- messageDesc(file_game_engine, 1);
19
+ export const GameActionCommandSchema = /*@__PURE__*/ messageDesc(file_game_engine, 1);
26
20
  /**
27
21
  * Describes the message game_engine.RngOutcomeRecord.
28
22
  * Use `create(RngOutcomeRecordSchema)` to create a new message.
29
23
  */
30
- export const RngOutcomeRecordSchema =
31
- /*@__PURE__*/
32
- messageDesc(file_game_engine, 2);
24
+ export const RngOutcomeRecordSchema = /*@__PURE__*/ messageDesc(file_game_engine, 2);
33
25
  /**
34
26
  * Describes the message game_engine.ProcessCommandResponse.
35
27
  * Use `create(ProcessCommandResponseSchema)` to create a new message.
36
28
  */
37
- export const ProcessCommandResponseSchema =
38
- /*@__PURE__*/
39
- messageDesc(file_game_engine, 3);
29
+ export const ProcessCommandResponseSchema = /*@__PURE__*/ messageDesc(file_game_engine, 3);
40
30
  /**
41
31
  * Describes the message game_engine.GetGameEngineInfoRequest.
42
32
  * Use `create(GetGameEngineInfoRequestSchema)` to create a new message.
43
33
  */
44
- export const GetGameEngineInfoRequestSchema =
45
- /*@__PURE__*/
46
- messageDesc(file_game_engine, 4);
34
+ export const GetGameEngineInfoRequestSchema = /*@__PURE__*/ messageDesc(file_game_engine, 4);
47
35
  /**
48
36
  * Describes the message game_engine.GetGameEngineInfoResponse.
49
37
  * Use `create(GetGameEngineInfoResponseSchema)` to create a new message.
50
38
  */
51
- export const GetGameEngineInfoResponseSchema =
52
- /*@__PURE__*/
53
- messageDesc(file_game_engine, 5);
39
+ export const GetGameEngineInfoResponseSchema = /*@__PURE__*/ messageDesc(file_game_engine, 5);
54
40
  /**
55
41
  * @generated from service game_engine.GameEngineService
56
42
  */
@@ -3,14 +3,20 @@ import { GameEngineService } from '../generated/game-engine_pb';
3
3
  /**
4
4
  * Creates Connect router middleware for GameEngineService.
5
5
  * This replaces NestJS built-in gRPC transport with Connect-compatible server.
6
+ *
7
+ * @param gameEngineAdapter - The gRPC adapter handling game engine requests
8
+ * @param options - Optional configuration including additional route registration
6
9
  */
7
- export function createConnectRouter(gameEngineAdapter) {
10
+ export function createConnectRouter(gameEngineAdapter, options) {
8
11
  return connectNodeAdapter({
9
12
  routes: router => {
10
13
  router.service(GameEngineService, {
11
14
  processCommand: gameEngineAdapter.processCommand.bind(gameEngineAdapter),
12
15
  getGameEngineInfo: gameEngineAdapter.getGameEngineInfo.bind(gameEngineAdapter),
13
16
  });
17
+ if (options?.additionalRoutes) {
18
+ options.additionalRoutes(router);
19
+ }
14
20
  },
15
21
  });
16
22
  }