@truelab/trueserver 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/MIGRATION.md +508 -0
- package/README.md +114 -94
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +9 -5
- package/dist/application.js.map +1 -1
- package/dist/examples.d.ts +1 -0
- package/dist/examples.d.ts.map +1 -1
- package/dist/examples.js +3 -1
- package/dist/examples.js.map +1 -1
- package/dist/helpers/config.helper.d.ts +9 -1
- package/dist/helpers/config.helper.d.ts.map +1 -1
- package/dist/helpers/config.helper.js +29 -0
- package/dist/helpers/config.helper.js.map +1 -1
- package/dist/helpers/errors.helper.d.ts +19 -0
- package/dist/helpers/errors.helper.d.ts.map +1 -0
- package/dist/helpers/errors.helper.js +21 -0
- package/dist/helpers/errors.helper.js.map +1 -0
- package/dist/helpers/fastify.helper.d.ts +5 -1
- package/dist/helpers/fastify.helper.d.ts.map +1 -1
- package/dist/helpers/fastify.helper.js +3 -1
- package/dist/helpers/fastify.helper.js.map +1 -1
- package/dist/helpers/handlers.helper.d.ts +10 -1
- package/dist/helpers/handlers.helper.d.ts.map +1 -1
- package/dist/helpers/handlers.helper.js +2 -1
- package/dist/helpers/handlers.helper.js.map +1 -1
- package/dist/helpers/money.helper.d.ts +13 -0
- package/dist/helpers/money.helper.d.ts.map +1 -0
- package/dist/helpers/money.helper.js +29 -0
- package/dist/helpers/money.helper.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/plugins/404.plugin.d.ts.map +1 -1
- package/dist/plugins/404.plugin.js +2 -1
- package/dist/plugins/404.plugin.js.map +1 -1
- package/dist/plugins/apikey.plugin.d.ts.map +1 -1
- package/dist/plugins/apikey.plugin.js +6 -7
- package/dist/plugins/apikey.plugin.js.map +1 -1
- package/dist/plugins/error.plugin.d.ts.map +1 -1
- package/dist/plugins/error.plugin.js +6 -2
- package/dist/plugins/error.plugin.js.map +1 -1
- package/dist/plugins/sentry.plugin.d.ts.map +1 -1
- package/dist/plugins/sentry.plugin.js +1 -2
- package/dist/plugins/sentry.plugin.js.map +1 -1
- package/dist/plugins/swagger.plugin.d.ts.map +1 -1
- package/dist/plugins/swagger.plugin.js +5 -1
- package/dist/plugins/swagger.plugin.js.map +1 -1
- package/dist/routes/checksum/checksum.route.d.ts +3 -0
- package/dist/routes/checksum/checksum.route.d.ts.map +1 -0
- package/dist/routes/checksum/checksum.route.js +21 -0
- package/dist/routes/checksum/checksum.route.js.map +1 -0
- package/dist/routes/checksum/index.d.ts +3 -0
- package/dist/routes/checksum/index.d.ts.map +1 -0
- package/dist/routes/checksum/index.js +12 -0
- package/dist/routes/checksum/index.js.map +1 -0
- package/dist/routes/client/client.route.d.ts +3 -0
- package/dist/routes/client/client.route.d.ts.map +1 -0
- package/dist/routes/{client.route.js → client/client.route.js} +5 -5
- package/dist/routes/client/client.route.js.map +1 -0
- package/dist/routes/client/index.d.ts +3 -0
- package/dist/routes/client/index.d.ts.map +1 -0
- package/dist/routes/client/index.js +12 -0
- package/dist/routes/client/index.js.map +1 -0
- package/dist/routes/config/config.route.js +1 -1
- package/dist/routes/config/config.route.js.map +1 -1
- package/dist/routes/config/config.route.validate.plugin.d.ts.map +1 -1
- package/dist/routes/config/config.route.validate.plugin.js +48 -17
- package/dist/routes/config/config.route.validate.plugin.js.map +1 -1
- package/dist/routes/play/play.route.validate.plugin.d.ts +10 -9
- package/dist/routes/play/play.route.validate.plugin.d.ts.map +1 -1
- package/dist/routes/play/play.route.validate.plugin.js +90 -39
- package/dist/routes/play/play.route.validate.plugin.js.map +1 -1
- package/dist/routes/validate/validate.route.validate.plugin.d.ts.map +1 -1
- package/dist/routes/validate/validate.route.validate.plugin.js +5 -4
- package/dist/routes/validate/validate.route.validate.plugin.js.map +1 -1
- package/dist/routes-public/healthcheck.route.d.ts.map +1 -0
- package/dist/{routes → routes-public}/healthcheck.route.js +4 -10
- package/dist/routes-public/healthcheck.route.js.map +1 -0
- package/dist/schemas/checksum.schema.d.ts +11 -0
- package/dist/schemas/checksum.schema.d.ts.map +1 -0
- package/dist/schemas/checksum.schema.js +26 -0
- package/dist/schemas/checksum.schema.js.map +1 -0
- package/dist/schemas/client.schema.d.ts +1 -1
- package/dist/schemas/client.schema.js +4 -4
- package/dist/schemas/client.schema.js.map +1 -1
- package/dist/schemas/config.schema.d.ts +17 -20
- package/dist/schemas/config.schema.d.ts.map +1 -1
- package/dist/schemas/config.schema.js +42 -43
- package/dist/schemas/config.schema.js.map +1 -1
- package/dist/schemas/examples/checksum.schema.examples.d.ts +3 -0
- package/dist/schemas/examples/checksum.schema.examples.d.ts.map +1 -0
- package/dist/schemas/examples/checksum.schema.examples.js +26 -0
- package/dist/schemas/examples/checksum.schema.examples.js.map +1 -0
- package/dist/schemas/examples/client.schema.examples.d.ts.map +1 -1
- package/dist/schemas/examples/client.schema.examples.js +15 -18
- package/dist/schemas/examples/client.schema.examples.js.map +1 -1
- package/dist/schemas/examples/config.schema.examples.d.ts.map +1 -1
- package/dist/schemas/examples/config.schema.examples.js +65 -33
- package/dist/schemas/examples/config.schema.examples.js.map +1 -1
- package/dist/schemas/examples/healthcheck.schema.examples.d.ts.map +1 -1
- package/dist/schemas/examples/healthcheck.schema.examples.js +3 -14
- package/dist/schemas/examples/healthcheck.schema.examples.js.map +1 -1
- package/dist/schemas/examples/play.schema.examples.d.ts.map +1 -1
- package/dist/schemas/examples/play.schema.examples.js +94 -130
- package/dist/schemas/examples/play.schema.examples.js.map +1 -1
- package/dist/schemas/examples/validate.schema.examples.d.ts.map +1 -1
- package/dist/schemas/examples/validate.schema.examples.js +51 -41
- package/dist/schemas/examples/validate.schema.examples.js.map +1 -1
- package/dist/schemas/healthcheck.schema.d.ts +2 -20
- package/dist/schemas/healthcheck.schema.d.ts.map +1 -1
- package/dist/schemas/healthcheck.schema.js +10 -41
- package/dist/schemas/healthcheck.schema.js.map +1 -1
- package/dist/schemas/play.schema.d.ts +22 -17
- package/dist/schemas/play.schema.d.ts.map +1 -1
- package/dist/schemas/play.schema.js +37 -45
- package/dist/schemas/play.schema.js.map +1 -1
- package/dist/schemas/shared.d.ts +13 -21
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/schemas/shared.js +56 -72
- package/dist/schemas/shared.js.map +1 -1
- package/dist/schemas/validate.schema.d.ts +11 -7
- package/dist/schemas/validate.schema.d.ts.map +1 -1
- package/dist/schemas/validate.schema.js +14 -16
- package/dist/schemas/validate.schema.js.map +1 -1
- package/package.json +5 -2
- package/dist/plugins/metrics.plugin.d.ts +0 -9
- package/dist/plugins/metrics.plugin.d.ts.map +0 -1
- package/dist/plugins/metrics.plugin.js +0 -24
- package/dist/plugins/metrics.plugin.js.map +0 -1
- package/dist/routes/client.route.d.ts +0 -3
- package/dist/routes/client.route.d.ts.map +0 -1
- package/dist/routes/client.route.js.map +0 -1
- package/dist/routes/healthcheck.route.d.ts.map +0 -1
- package/dist/routes/healthcheck.route.js.map +0 -1
- /package/dist/{routes → routes-public}/healthcheck.route.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @truelab/trueserver
|
|
2
2
|
|
|
3
|
-
Fastify-based server package for TrueLab games.
|
|
3
|
+
Fastify-based server package for TrueLab games. Implements the **Game Server** contract described in [GS Documentation](https://www.notion.so/truelab/GS-Documentation-36dd90f8c00680d485d4e4e3eba928f0).
|
|
4
4
|
|
|
5
|
-
The package provides
|
|
5
|
+
The package provides HTTP routes, TypeBox request/response schemas, API-key authentication, error envelope, Sentry integration and Swagger UI. A game team only needs to call `registerGameConfig`, register handlers and start the server.
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
- Node.js 22.12+
|
|
10
|
-
- npm
|
|
9
|
+
- Node.js 22.12+
|
|
10
|
+
- npm access to `@truelab/trueserver`
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -17,18 +17,15 @@ npm install @truelab/trueserver
|
|
|
17
17
|
|
|
18
18
|
## Quick Start
|
|
19
19
|
|
|
20
|
-
Register game config and handlers before building the Fastify app:
|
|
21
|
-
|
|
22
20
|
```typescript
|
|
23
21
|
import {
|
|
24
22
|
Application,
|
|
25
|
-
ECategory,
|
|
26
23
|
EStakeType,
|
|
27
|
-
EVolatility,
|
|
28
24
|
handlers,
|
|
29
25
|
getenv,
|
|
30
26
|
logger,
|
|
31
27
|
registerGameConfig,
|
|
28
|
+
type TChecksumReply,
|
|
32
29
|
type TClientReply,
|
|
33
30
|
type TConfigReply,
|
|
34
31
|
type TPlayReply,
|
|
@@ -44,57 +41,63 @@ const stakeModes = [{
|
|
|
44
41
|
}]
|
|
45
42
|
|
|
46
43
|
registerGameConfig({
|
|
47
|
-
|
|
44
|
+
gameId: 'my-game',
|
|
45
|
+
rtpVersion: '96',
|
|
48
46
|
stakeModes,
|
|
49
|
-
hasBuy: false,
|
|
50
|
-
hasChoice: false,
|
|
51
|
-
hasGamble: false,
|
|
52
47
|
hasMeta: false,
|
|
48
|
+
hasChoice: false,
|
|
49
|
+
hasRestore: false,
|
|
53
50
|
hasMultiStake: false,
|
|
54
|
-
|
|
51
|
+
hasVariableLevels: false,
|
|
55
52
|
coinRatio: 10,
|
|
53
|
+
hasValidate: false,
|
|
56
54
|
})
|
|
57
55
|
|
|
58
|
-
handlers.register('client', async (): Promise<TClientReply> => ({
|
|
59
|
-
ok: true,
|
|
60
|
-
data: {},
|
|
61
|
-
}))
|
|
62
|
-
|
|
63
56
|
handlers.register('config', async (): Promise<TConfigReply> => ({
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
rtp: 96,
|
|
69
|
-
hitrate: 25,
|
|
70
|
-
volatility: EVolatility.med,
|
|
57
|
+
gameId: 'my-game',
|
|
58
|
+
volatility: 2.5,
|
|
59
|
+
rtp: '96.17',
|
|
60
|
+
rtpVersion: '96',
|
|
71
61
|
hasMeta: false,
|
|
72
62
|
hasChoice: false,
|
|
73
|
-
|
|
63
|
+
hasRestore: false,
|
|
74
64
|
hasMultiStake: false,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
freeroundsAllowed: false,
|
|
65
|
+
hasVariableLevels: false,
|
|
66
|
+
coinRatio: 10,
|
|
78
67
|
minWin: 0.1,
|
|
79
68
|
maxWin: 5000,
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
freeroundsAllowed: false,
|
|
70
|
+
hasValidate: false,
|
|
71
|
+
stakeModes,
|
|
82
72
|
}))
|
|
83
73
|
|
|
84
|
-
handlers.register('
|
|
85
|
-
|
|
86
|
-
rng: '[]',
|
|
87
|
-
finished: true,
|
|
88
|
-
results: {
|
|
89
|
-
response: '{}',
|
|
90
|
-
winCash: 0,
|
|
91
|
-
},
|
|
74
|
+
handlers.register('client', async (): Promise<TClientReply> => ({
|
|
75
|
+
data: {},
|
|
92
76
|
}))
|
|
93
77
|
|
|
94
|
-
handlers.register('
|
|
95
|
-
|
|
78
|
+
handlers.register('play', async (request): Promise<TPlayReply> => {
|
|
79
|
+
// request.params.rtpVersion is available for routing math by RTP
|
|
80
|
+
return {
|
|
81
|
+
gameResponse: {},
|
|
82
|
+
rng: [],
|
|
83
|
+
winCash: 0,
|
|
84
|
+
finished: true,
|
|
85
|
+
hasMaxWin: false,
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
handlers.register('checksum', async (): Promise<TChecksumReply> => ({
|
|
90
|
+
files: [
|
|
91
|
+
{ path: 'src/math/spin.js', hash: '...' },
|
|
92
|
+
],
|
|
96
93
|
}))
|
|
97
94
|
|
|
95
|
+
// Optional. Enabled when hasValidate=true in registerGameConfig.
|
|
96
|
+
handlers.register('validate', async (request): Promise<TValidateReply> => {
|
|
97
|
+
// Return a verdict: valid=true allows the round; valid=false rejects it (HTTP 200, no round opened).
|
|
98
|
+
return { valid: true }
|
|
99
|
+
})
|
|
100
|
+
|
|
98
101
|
async function main() {
|
|
99
102
|
const app = new Application()
|
|
100
103
|
const server = await app.build()
|
|
@@ -111,63 +114,74 @@ main().catch((error) => {
|
|
|
111
114
|
})
|
|
112
115
|
```
|
|
113
116
|
|
|
114
|
-
`registerGameConfig` must be called before `app.build()
|
|
117
|
+
`registerGameConfig` must be called before `app.build()` — validation plugins read the config while the server is being built. The function throws if invariants are violated (e.g. `hasChoice=true` without `hasMeta=true`, `hasVariableLevels=true` without `variableLevels`/`defaultLevel`, or `hasMultiStake=true` without `hasValidate=true`).
|
|
115
118
|
|
|
116
119
|
## Runtime API
|
|
117
120
|
|
|
118
|
-
|
|
121
|
+
`{rtpVersion}` is a path segment (e.g. `96`, `97`, `98`) — RGS picks the correct RTP per call. Game Server receives it as `request.params.rtpVersion`.
|
|
119
122
|
|
|
120
123
|
| Method | Path | Handler | Description |
|
|
121
124
|
| ------ | ---- | ------- | ----------- |
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `POST` |
|
|
125
|
+
| `GET` | `/healthcheck` | built-in | Liveness/readiness probe |
|
|
126
|
+
| `GET` | `/:rtpVersion/config` | `handlers.register('config', ...)` | Game config (RTP-specific) |
|
|
127
|
+
| `GET` | `/:rtpVersion/client` | `handlers.register('client', ...)` | Client-side payload |
|
|
128
|
+
| `GET` | `/:rtpVersion/checksum` | `handlers.register('checksum', ...)` | File hashes for integrity check |
|
|
129
|
+
| `POST` | `/:rtpVersion/play` | `handlers.register('play', ...)` | One step of a round |
|
|
130
|
+
| `POST` | `/:rtpVersion/validate` | `handlers.register('validate', ...)` | Pre-round stake validation — returns `{ valid, reason? }` (enabled when `hasValidate=true`) |
|
|
131
|
+
|
|
132
|
+
Every request must carry the API key header. By default it is `x-api-key: test`; override with `API_HEADER` and `API_KEY`.
|
|
133
|
+
|
|
134
|
+
`ROUTE_PREFIX` is prepended to every route. For `ROUTE_PREFIX=/api/v1`, the play endpoint becomes `POST /api/v1/96/play`. `/healthcheck` is always mounted directly under the prefix (no `{rtpVersion}` segment).
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
## Error envelope
|
|
129
137
|
|
|
130
|
-
|
|
138
|
+
Non-2xx responses follow:
|
|
131
139
|
|
|
132
|
-
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"status": false,
|
|
143
|
+
"code": 4001,
|
|
144
|
+
"message": "Invalid choice value"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
133
147
|
|
|
134
|
-
|
|
148
|
+
Recommended code ranges: `1xxx` validation, `2xxx` auth, `4xxx` business, `9xxx` internal. The `EErrorCode` enum exports the codes used by this package.
|
|
135
149
|
|
|
136
150
|
```typescript
|
|
137
|
-
import {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
PlayRequestSchema,
|
|
141
|
-
handlers,
|
|
142
|
-
registerGameConfig,
|
|
143
|
-
type TPlayReply,
|
|
144
|
-
} from '@truelab/trueserver'
|
|
151
|
+
import { EErrorCode, httpError } from '@truelab/trueserver'
|
|
152
|
+
|
|
153
|
+
throw httpError('Invalid choice value', 400, EErrorCode.BusinessChoiceUnknown)
|
|
145
154
|
```
|
|
146
155
|
|
|
147
|
-
Test
|
|
156
|
+
## Test utilities
|
|
148
157
|
|
|
149
158
|
```typescript
|
|
150
|
-
import {
|
|
159
|
+
import {
|
|
160
|
+
checkSchemaPropertyDescriptions,
|
|
161
|
+
testBuild,
|
|
162
|
+
testHeaders,
|
|
163
|
+
validator,
|
|
164
|
+
} from '@truelab/trueserver/test-utils'
|
|
151
165
|
```
|
|
152
166
|
|
|
153
|
-
|
|
167
|
+
`test-utils` uses Jest globals (`expect`), so consumers should keep `jest` and usually `@types/jest` in `devDependencies`.
|
|
154
168
|
|
|
155
|
-
## Environment
|
|
169
|
+
## Environment variables
|
|
156
170
|
|
|
157
171
|
| Variable | Default | Description |
|
|
158
172
|
| -------- | ------- | ----------- |
|
|
159
|
-
| `HOST` | `localhost` | Listen host
|
|
160
|
-
| `PORT` | `2980` | Listen port
|
|
161
|
-
| `ROUTE_PREFIX` | empty | Prefix for all
|
|
162
|
-
| `API_HEADER` | `x-api-key` | Header name used by
|
|
163
|
-
| `API_KEY` | `test` | Expected API key
|
|
173
|
+
| `HOST` | `localhost` | Listen host |
|
|
174
|
+
| `PORT` | `2980` | Listen port |
|
|
175
|
+
| `ROUTE_PREFIX` | empty | Prefix for all routes |
|
|
176
|
+
| `API_HEADER` | `x-api-key` | Header name used by API-key plugin |
|
|
177
|
+
| `API_KEY` | `test` | Expected API key value |
|
|
164
178
|
| `LOG_LEVEL` | `error` | Pino log level |
|
|
165
|
-
| `APP_ENV` | unset | `dev`, `release`,
|
|
179
|
+
| `APP_ENV` | unset | `dev`, `release`, `master`; controls Swagger and environment mapping |
|
|
166
180
|
| `SENTRY_DSN` | unset | Sentry DSN |
|
|
167
181
|
| `SENTRY_RATE` | `0.01` | Sentry traces sample rate |
|
|
168
|
-
| `GAME_ID` | `0001` | Sentry `game.id` tag |
|
|
182
|
+
| `GAME_ID` | `0001` | Sentry `game.id` tag fallback |
|
|
169
183
|
|
|
170
|
-
The environment helper imports `dotenv/config`, so `.env` is loaded
|
|
184
|
+
The environment helper imports `dotenv/config`, so `.env` is loaded automatically.
|
|
171
185
|
|
|
172
186
|
## Swagger
|
|
173
187
|
|
|
@@ -175,45 +189,51 @@ Swagger UI is enabled only for `APP_ENV=dev`.
|
|
|
175
189
|
|
|
176
190
|
- `GET /` redirects to `/docs`
|
|
177
191
|
- `GET /docs` serves Swagger UI
|
|
178
|
-
- `release` and `master` disable Swagger UI
|
|
179
192
|
|
|
180
|
-
|
|
193
|
+
`release` and `master` disable Swagger UI.
|
|
181
194
|
|
|
182
195
|
## Advanced Validation
|
|
183
196
|
|
|
184
|
-
The package validates both requests and
|
|
197
|
+
The package validates both requests and replies via TypeBox schemas and runs game-specific checks based on `registerGameConfig`:
|
|
185
198
|
|
|
186
|
-
- `/config` checks stake modes
|
|
187
|
-
- `/play` checks stakes,
|
|
188
|
-
- `/validate` is available only when `
|
|
189
|
-
- `test`
|
|
199
|
+
- `/config` checks stake modes, the `hasChoice ⇒ hasMeta` invariant, the `hasVariableLevels ⇔ {variableLevels, defaultLevel}` pair, and `hasMultiStake=true ⇒ freeroundsAllowed=false` and `hasValidate=true`.
|
|
200
|
+
- `/play` checks stakes (uniqueness, qty, level in `variableLevels`, parametric/params), `stepIndex` consistency (opening vs continuation), `choice`/`meta` presence per flags, and reply shape (`finished`, `choices`, `meta`, `hasMaxWin`).
|
|
201
|
+
- `/validate` is available only when `hasValidate=true`. Returns `{ valid: boolean, reason?: string }`.
|
|
202
|
+
- `test` field is rejected on production (`APP_ENV=master` or unset).
|
|
190
203
|
|
|
191
|
-
|
|
204
|
+
## Money-value precision
|
|
192
205
|
|
|
193
|
-
|
|
206
|
+
All monetary values on the wire — `winCash`, `winCoins`, `coinValue`, `minWin`, `maxWin`, `amount` — must be **exact decimal representations**. «Exact» means the value round-trips through `JSON.parse → number → toString` to itself. For example, `0.3` is exact; `0.30000000000000004` (the IEEE 754 artefact of `0.1 + 0.2` in native JavaScript) is not.
|
|
194
207
|
|
|
195
|
-
|
|
208
|
+
RGS compares all incoming money values with **strict equality** (no epsilon tolerance). Any float drift in upstream computation will cause RGS to reject the value as invalid.
|
|
196
209
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
} from '@truelab/trueserver
|
|
210
|
+
**What this means in practice:**
|
|
211
|
+
|
|
212
|
+
- Compute `winCash`, `winCoins` and any derived monetary values in decimal arithmetic — avoid `+ - × ÷` on native floating-point types for money-valued outputs.
|
|
213
|
+
- Use a decimal library. The package exports `Big`, `roundMoney` and `isExactDecimal` from `big.js` so you do not need to add a separate dependency.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { Big, roundMoney, isExactDecimal } from '@truelab/trueserver'
|
|
217
|
+
|
|
218
|
+
const winCash = roundMoney(new Big(coins).times(coinValue), currencyDecimals) // exact-decimal number
|
|
219
|
+
isExactDecimal(winCash, currencyDecimals) // true
|
|
204
220
|
```
|
|
205
221
|
|
|
206
|
-
`
|
|
222
|
+
`roundMoney(value, decimals)` returns a `number` rounded to `decimals` decimal places using decimal arithmetic (half-up by default). `isExactDecimal(value, decimals)` checks that the number has at most `decimals` fractional digits — useful as a self-check in tests.
|
|
223
|
+
|
|
224
|
+
## Migration
|
|
225
|
+
|
|
226
|
+
This release is breaking. See [MIGRATION.md](MIGRATION.md) for a full mapping of old fields/paths to new ones.
|
|
207
227
|
|
|
208
228
|
## Package Development
|
|
209
229
|
|
|
210
230
|
```bash
|
|
211
|
-
npm test
|
|
212
|
-
npm run build
|
|
213
|
-
npm pack
|
|
231
|
+
npm test
|
|
232
|
+
npm run build
|
|
233
|
+
npm pack
|
|
214
234
|
```
|
|
215
235
|
|
|
216
|
-
`bitbucket-pipelines.yml` runs tests and build on the default branch.
|
|
236
|
+
`bitbucket-pipelines.yml` runs tests and build on the default branch.
|
|
217
237
|
|
|
218
238
|
## License
|
|
219
239
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../application.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAkB,MAAM,0BAA0B,CAAA;AAGzE,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,MAAM,EAAE,cAAc,CAAA;;IAchB,KAAK,IAAI,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../application.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAkB,MAAM,0BAA0B,CAAA;AAGzE,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,MAAM,EAAE,cAAc,CAAA;;IAchB,KAAK,IAAI,OAAO,CAAC,cAAc,CAAC;CAuBzC"}
|
package/dist/application.js
CHANGED
|
@@ -22,16 +22,20 @@ class Application {
|
|
|
22
22
|
}).withTypeProvider();
|
|
23
23
|
}
|
|
24
24
|
async build() {
|
|
25
|
-
// Load plugins
|
|
26
25
|
await this.server.register(autoload_1.default, {
|
|
27
26
|
dir: path_1.default.join(__dirname, 'plugins'),
|
|
28
27
|
});
|
|
29
|
-
|
|
28
|
+
const prefix = (0, fastify_helper_1.getRoutePrefix)();
|
|
29
|
+
// Version-agnostic routes (healthcheck)
|
|
30
|
+
await this.server.register(autoload_1.default, {
|
|
31
|
+
dir: path_1.default.join(__dirname, 'routes-public'),
|
|
32
|
+
options: { prefix },
|
|
33
|
+
dirNameRoutePrefix: false,
|
|
34
|
+
});
|
|
35
|
+
// Version-scoped routes (config, client, play, validate, checksum)
|
|
30
36
|
await this.server.register(autoload_1.default, {
|
|
31
37
|
dir: path_1.default.join(__dirname, 'routes'),
|
|
32
|
-
options: {
|
|
33
|
-
prefix: (0, fastify_helper_1.getRoutePrefix)(),
|
|
34
|
-
},
|
|
38
|
+
options: { prefix: `${prefix}/:rtpVersion` },
|
|
35
39
|
dirNameRoutePrefix: false,
|
|
36
40
|
});
|
|
37
41
|
return this.server;
|
package/dist/application.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application.js","sourceRoot":"","sources":["../application.ts"],"names":[],"mappings":";;;;;AAAA,iEAA+C;AAE/C,sDAA6B;AAC7B,gDAAuB;AAEvB,6DAAyE;AACzE,2DAAuD;AAEvD,MAAqB,WAAW;IAC5B,MAAM,CAAgB;IAEtB;QACI,IAAI,CAAC,MAAM,GAAG,IAAA,iBAAO,EAAC;YAClB,GAAG,EAAE;gBACD,aAAa,EAAE;oBACX,QAAQ,EAAE,CAAC,YAAY,CAAC;iBAC3B;aACJ;YACD,MAAM,EAAE,6BAAa;YACrB,qBAAqB,EAAE,IAAI;SAC9B,CAAC,CAAC,gBAAgB,EAAuB,CAAA;IAC9C,CAAC;IAED,KAAK,CAAC,KAAK;
|
|
1
|
+
{"version":3,"file":"application.js","sourceRoot":"","sources":["../application.ts"],"names":[],"mappings":";;;;;AAAA,iEAA+C;AAE/C,sDAA6B;AAC7B,gDAAuB;AAEvB,6DAAyE;AACzE,2DAAuD;AAEvD,MAAqB,WAAW;IAC5B,MAAM,CAAgB;IAEtB;QACI,IAAI,CAAC,MAAM,GAAG,IAAA,iBAAO,EAAC;YAClB,GAAG,EAAE;gBACD,aAAa,EAAE;oBACX,QAAQ,EAAE,CAAC,YAAY,CAAC;iBAC3B;aACJ;YACD,MAAM,EAAE,6BAAa;YACrB,qBAAqB,EAAE,IAAI;SAC9B,CAAC,CAAC,gBAAgB,EAAuB,CAAA;IAC9C,CAAC;IAED,KAAK,CAAC,KAAK;QACP,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAe,EAAE;YACxC,GAAG,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC;SACvC,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAA,+BAAc,GAAE,CAAA;QAE/B,wCAAwC;QACxC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAe,EAAE;YACxC,GAAG,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;YAC1C,OAAO,EAAE,EAAE,MAAM,EAAE;YACnB,kBAAkB,EAAE,KAAK;SAC5B,CAAC,CAAA;QAEF,mEAAmE;QACnE,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAe,EAAE;YACxC,GAAG,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE;YAC5C,kBAAkB,EAAE,KAAK;SAC5B,CAAC,CAAA;QAEF,OAAO,IAAI,CAAC,MAAM,CAAA;IACtB,CAAC;CACJ;AAtCD,8BAsCC"}
|
package/dist/examples.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { checksumReplyExamples } from './schemas/examples/checksum.schema.examples';
|
|
1
2
|
export { clientReplyExamples } from './schemas/examples/client.schema.examples';
|
|
2
3
|
export { configReplyExamples } from './schemas/examples/config.schema.examples';
|
|
3
4
|
export { healthcheckReplyExamples } from './schemas/examples/healthcheck.schema.examples';
|
package/dist/examples.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../examples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAA;AACzF,OAAO,EACH,iBAAiB,EACjB,mBAAmB,GACtB,MAAM,yCAAyC,CAAA;AAChD,OAAO,EACH,qBAAqB,EACrB,uBAAuB,GAC1B,MAAM,6CAA6C,CAAA"}
|
|
1
|
+
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../examples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAA;AACzF,OAAO,EACH,iBAAiB,EACjB,mBAAmB,GACtB,MAAM,yCAAyC,CAAA;AAChD,OAAO,EACH,qBAAqB,EACrB,uBAAuB,GAC1B,MAAM,6CAA6C,CAAA"}
|
package/dist/examples.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateRequestExamples = exports.validateReplyExamples = exports.playRequestExamples = exports.playReplyExamples = exports.healthcheckReplyExamples = exports.configReplyExamples = exports.clientReplyExamples = void 0;
|
|
3
|
+
exports.validateRequestExamples = exports.validateReplyExamples = exports.playRequestExamples = exports.playReplyExamples = exports.healthcheckReplyExamples = exports.configReplyExamples = exports.clientReplyExamples = exports.checksumReplyExamples = void 0;
|
|
4
|
+
var checksum_schema_examples_1 = require("./schemas/examples/checksum.schema.examples");
|
|
5
|
+
Object.defineProperty(exports, "checksumReplyExamples", { enumerable: true, get: function () { return checksum_schema_examples_1.checksumReplyExamples; } });
|
|
4
6
|
var client_schema_examples_1 = require("./schemas/examples/client.schema.examples");
|
|
5
7
|
Object.defineProperty(exports, "clientReplyExamples", { enumerable: true, get: function () { return client_schema_examples_1.clientReplyExamples; } });
|
|
6
8
|
var config_schema_examples_1 = require("./schemas/examples/config.schema.examples");
|
package/dist/examples.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../examples.ts"],"names":[],"mappings":";;;AAAA,oFAA+E;AAAtE,6HAAA,mBAAmB,OAAA;AAC5B,oFAA+E;AAAtE,6HAAA,mBAAmB,OAAA;AAC5B,8FAAyF;AAAhF,uIAAA,wBAAwB,OAAA;AACjC,gFAGgD;AAF5C,yHAAA,iBAAiB,OAAA;AACjB,2HAAA,mBAAmB,OAAA;AAEvB,wFAGoD;AAFhD,iIAAA,qBAAqB,OAAA;AACrB,mIAAA,uBAAuB,OAAA"}
|
|
1
|
+
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../examples.ts"],"names":[],"mappings":";;;AAAA,wFAAmF;AAA1E,iIAAA,qBAAqB,OAAA;AAC9B,oFAA+E;AAAtE,6HAAA,mBAAmB,OAAA;AAC5B,oFAA+E;AAAtE,6HAAA,mBAAmB,OAAA;AAC5B,8FAAyF;AAAhF,uIAAA,wBAAwB,OAAA;AACjC,gFAGgD;AAF5C,yHAAA,iBAAiB,OAAA;AACjB,2HAAA,mBAAmB,OAAA;AAEvB,wFAGoD;AAFhD,iIAAA,qBAAqB,OAAA;AACrB,mIAAA,uBAAuB,OAAA"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { TConfigReply } from '../schemas/config.schema';
|
|
2
|
-
export type TGameConfig = Pick<TConfigReply, '
|
|
2
|
+
export type TGameConfig = Pick<TConfigReply, 'gameId' | 'stakeModes' | 'hasMeta' | 'hasChoice' | 'hasRestore' | 'hasMultiStake' | 'hasVariableLevels' | 'hasValidate' | 'variableLevels' | 'defaultLevel' | 'coinRatio'> & {
|
|
3
|
+
/**
|
|
4
|
+
* RTP version label. Optional: set it only for single-RTP deployments.
|
|
5
|
+
* Multi-RTP servers omit it and take rtpVersion from the {rtpVersion} path
|
|
6
|
+
* segment per request — in that case /config validates the reply against the
|
|
7
|
+
* path segment only.
|
|
8
|
+
*/
|
|
9
|
+
rtpVersion?: TConfigReply['rtpVersion'];
|
|
10
|
+
};
|
|
3
11
|
export declare function registerGameConfig(config: TGameConfig): void;
|
|
4
12
|
export declare function getGameConfig(): TGameConfig;
|
|
5
13
|
//# sourceMappingURL=config.helper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.helper.d.ts","sourceRoot":"","sources":["../../helpers/config.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"config.helper.d.ts","sourceRoot":"","sources":["../../helpers/config.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGvD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAC3C,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,WAAW,GACX,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,WAAW,CACV,GAAG;IACA;;;;;OAKG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC3C,CAAA;AAID,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,QAiCrD;AAED,wBAAgB,aAAa,IAAI,WAAW,CAE3C"}
|
|
@@ -2,8 +2,37 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerGameConfig = registerGameConfig;
|
|
4
4
|
exports.getGameConfig = getGameConfig;
|
|
5
|
+
const fastify_helper_1 = require("./fastify.helper");
|
|
5
6
|
let gameConfig;
|
|
6
7
|
function registerGameConfig(config) {
|
|
8
|
+
if (config.rtpVersion !== undefined && (typeof config.rtpVersion !== 'string' || config.rtpVersion.length === 0)) {
|
|
9
|
+
throw (0, fastify_helper_1.httpError)('Game config: rtpVersion must be a non-empty string when provided', 500);
|
|
10
|
+
}
|
|
11
|
+
if (config.hasChoice && !config.hasMeta) {
|
|
12
|
+
throw (0, fastify_helper_1.httpError)('Game config: hasChoice=true requires hasMeta=true', 500);
|
|
13
|
+
}
|
|
14
|
+
if (config.hasMultiStake && config.hasValidate !== true) {
|
|
15
|
+
throw (0, fastify_helper_1.httpError)('Game config: hasValidate must be true when hasMultiStake=true', 500);
|
|
16
|
+
}
|
|
17
|
+
if (config.hasVariableLevels) {
|
|
18
|
+
if (!Array.isArray(config.variableLevels) || config.variableLevels.length === 0) {
|
|
19
|
+
throw (0, fastify_helper_1.httpError)('Game config: variableLevels must be a non-empty array when hasVariableLevels=true', 500);
|
|
20
|
+
}
|
|
21
|
+
if (config.defaultLevel === undefined || !config.variableLevels.includes(config.defaultLevel)) {
|
|
22
|
+
throw (0, fastify_helper_1.httpError)('Game config: defaultLevel must be one of variableLevels when hasVariableLevels=true', 500);
|
|
23
|
+
}
|
|
24
|
+
if (config.coinRatio !== undefined) {
|
|
25
|
+
throw (0, fastify_helper_1.httpError)('Game config: coinRatio must not be set when hasVariableLevels=true', 500);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
if (config.coinRatio === undefined) {
|
|
30
|
+
throw (0, fastify_helper_1.httpError)('Game config: coinRatio is required when hasVariableLevels=false', 500);
|
|
31
|
+
}
|
|
32
|
+
if (config.variableLevels !== undefined || config.defaultLevel !== undefined) {
|
|
33
|
+
throw (0, fastify_helper_1.httpError)('Game config: variableLevels/defaultLevel must not be set when hasVariableLevels=false', 500);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
7
36
|
gameConfig = config;
|
|
8
37
|
}
|
|
9
38
|
function getGameConfig() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.helper.js","sourceRoot":"","sources":["../../helpers/config.helper.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"config.helper.js","sourceRoot":"","sources":["../../helpers/config.helper.ts"],"names":[],"mappings":";;AA2BA,gDAiCC;AAED,sCAEC;AA/DD,qDAA4C;AAwB5C,IAAI,UAAuB,CAAA;AAE3B,SAAgB,kBAAkB,CAAC,MAAmB;IAClD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAC/G,MAAM,IAAA,0BAAS,EAAC,kEAAkE,EAAE,GAAG,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,IAAA,0BAAS,EAAC,mDAAmD,EAAE,GAAG,CAAC,CAAA;IAC7E,CAAC;IAED,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACtD,MAAM,IAAA,0BAAS,EAAC,+DAA+D,EAAE,GAAG,CAAC,CAAA;IACzF,CAAC;IAED,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9E,MAAM,IAAA,0BAAS,EAAC,mFAAmF,EAAE,GAAG,CAAC,CAAA;QAC7G,CAAC;QACD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5F,MAAM,IAAA,0BAAS,EAAC,qFAAqF,EAAE,GAAG,CAAC,CAAA;QAC/G,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAA,0BAAS,EAAC,oEAAoE,EAAE,GAAG,CAAC,CAAA;QAC9F,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAA,0BAAS,EAAC,iEAAiE,EAAE,GAAG,CAAC,CAAA;QAC3F,CAAC;QACD,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YAC3E,MAAM,IAAA,0BAAS,EAAC,uFAAuF,EAAE,GAAG,CAAC,CAAA;QACjH,CAAC;IACL,CAAC;IAED,UAAU,GAAG,MAAM,CAAA;AACvB,CAAC;AAED,SAAgB,aAAa;IACzB,OAAO,UAAU,CAAA;AACrB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const EErrorCode: {
|
|
2
|
+
readonly ValidationBody: 1001;
|
|
3
|
+
readonly ValidationStakes: 1002;
|
|
4
|
+
readonly ValidationMeta: 1003;
|
|
5
|
+
readonly ValidationChoice: 1004;
|
|
6
|
+
readonly ValidationStepIndex: 1005;
|
|
7
|
+
readonly ValidationConfig: 1006;
|
|
8
|
+
readonly ValidationTest: 1007;
|
|
9
|
+
readonly ApiKey: 2001;
|
|
10
|
+
readonly BusinessChoiceUnknown: 4001;
|
|
11
|
+
readonly BusinessMetaShape: 4002;
|
|
12
|
+
readonly BusinessFinishedMismatch: 4003;
|
|
13
|
+
readonly BusinessChoicesMismatch: 4004;
|
|
14
|
+
readonly BusinessMaxWinMismatch: 4005;
|
|
15
|
+
readonly Unhandled: 9001;
|
|
16
|
+
readonly NotFound: 9404;
|
|
17
|
+
};
|
|
18
|
+
export type TErrorCode = (typeof EErrorCode)[keyof typeof EErrorCode];
|
|
19
|
+
//# sourceMappingURL=errors.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.helper.d.ts","sourceRoot":"","sources":["../../helpers/errors.helper.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;CAgBb,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EErrorCode = void 0;
|
|
4
|
+
exports.EErrorCode = {
|
|
5
|
+
ValidationBody: 1001,
|
|
6
|
+
ValidationStakes: 1002,
|
|
7
|
+
ValidationMeta: 1003,
|
|
8
|
+
ValidationChoice: 1004,
|
|
9
|
+
ValidationStepIndex: 1005,
|
|
10
|
+
ValidationConfig: 1006,
|
|
11
|
+
ValidationTest: 1007,
|
|
12
|
+
ApiKey: 2001,
|
|
13
|
+
BusinessChoiceUnknown: 4001,
|
|
14
|
+
BusinessMetaShape: 4002,
|
|
15
|
+
BusinessFinishedMismatch: 4003,
|
|
16
|
+
BusinessChoicesMismatch: 4004,
|
|
17
|
+
BusinessMaxWinMismatch: 4005,
|
|
18
|
+
Unhandled: 9001,
|
|
19
|
+
NotFound: 9404,
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=errors.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.helper.js","sourceRoot":"","sources":["../../helpers/errors.helper.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG;IACtB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,IAAI;IACtB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;IACzB,gBAAgB,EAAE,IAAI;IACtB,cAAc,EAAE,IAAI;IACpB,MAAM,EAAE,IAAI;IACZ,qBAAqB,EAAE,IAAI;IAC3B,iBAAiB,EAAE,IAAI;IACvB,wBAAwB,EAAE,IAAI;IAC9B,uBAAuB,EAAE,IAAI;IAC7B,sBAAsB,EAAE,IAAI;IAC5B,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,IAAI;CACR,CAAA"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
|
|
2
2
|
import { FastifyBaseLogger, FastifyError, FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from 'fastify';
|
|
3
|
+
import { TErrorCode } from './errors.helper';
|
|
3
4
|
export type FastifyTypebox = FastifyInstance<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>, FastifyBaseLogger, TypeBoxTypeProvider>;
|
|
5
|
+
export type FastifyError$Coded = FastifyError & {
|
|
6
|
+
errorCode?: TErrorCode;
|
|
7
|
+
};
|
|
4
8
|
export declare function registerRoute(callback: (fastify: FastifyTypebox) => Promise<void>): (fastify: FastifyTypebox) => Promise<void>;
|
|
5
9
|
export declare function registerPlugin(callback: (fastify: FastifyTypebox) => Promise<void>): (fastify: FastifyTypebox) => Promise<void>;
|
|
6
10
|
export declare function getRoutePrefix(): string;
|
|
7
11
|
/** This is handled in error.plugin.ts */
|
|
8
|
-
export declare function httpError(message: string, statusCode?: number): FastifyError;
|
|
12
|
+
export declare function httpError(message: string, statusCode?: number, code?: TErrorCode): FastifyError$Coded;
|
|
9
13
|
//# sourceMappingURL=fastify.helper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.helper.d.ts","sourceRoot":"","sources":["../../helpers/fastify.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EACH,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAChD,yBAAyB,EAAE,2BAA2B,EAAE,gBAAgB,EAC3E,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"fastify.helper.d.ts","sourceRoot":"","sources":["../../helpers/fastify.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EACH,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAChD,yBAAyB,EAAE,2BAA2B,EAAE,gBAAgB,EAC3E,MAAM,SAAS,CAAA;AAIhB,OAAO,EAAc,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAExD,MAAM,MAAM,cAAc,GAAG,eAAe,CAC5C,gBAAgB,EAChB,2BAA2B,CAAC,gBAAgB,CAAC,EAC7C,yBAAyB,CAAC,gBAAgB,CAAC,EAC3C,iBAAiB,EACjB,mBAAmB,CAClB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,SAAS,CAAC,EAAE,UAAU,CAAA;CAAE,CAAA;AAE1E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAE,IAAI,CAAC,aAAjC,cAAc,KAAK,OAAO,CAAE,IAAI,CAAC,CAElF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAE,IAAI,CAAC,aAAjC,cAAc,KAAK,OAAO,CAAE,IAAI,CAAC,CAEnF;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,yCAAyC;AACzC,wBAAgB,SAAS,CACrB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAY,EACxB,IAAI,GAAE,UAAiC,GACxC,kBAAkB,CAMpB"}
|
|
@@ -9,6 +9,7 @@ exports.getRoutePrefix = getRoutePrefix;
|
|
|
9
9
|
exports.httpError = httpError;
|
|
10
10
|
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
11
11
|
const env_helper_1 = require("./env.helper");
|
|
12
|
+
const errors_helper_1 = require("./errors.helper");
|
|
12
13
|
function registerRoute(callback) {
|
|
13
14
|
return callback;
|
|
14
15
|
}
|
|
@@ -19,9 +20,10 @@ function getRoutePrefix() {
|
|
|
19
20
|
return (0, env_helper_1.getenv)('ROUTE_PREFIX', '');
|
|
20
21
|
}
|
|
21
22
|
/** This is handled in error.plugin.ts */
|
|
22
|
-
function httpError(message, statusCode = 500) {
|
|
23
|
+
function httpError(message, statusCode = 500, code = errors_helper_1.EErrorCode.Unhandled) {
|
|
23
24
|
const error = new Error(message);
|
|
24
25
|
error.statusCode = statusCode;
|
|
26
|
+
error.errorCode = code;
|
|
25
27
|
return error;
|
|
26
28
|
}
|
|
27
29
|
//# sourceMappingURL=fastify.helper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.helper.js","sourceRoot":"","sources":["../../helpers/fastify.helper.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"fastify.helper.js","sourceRoot":"","sources":["../../helpers/fastify.helper.ts"],"names":[],"mappings":";;;;;AAoBA,sCAEC;AAED,wCAEC;AAED,wCAEC;AAGD,8BAUC;AAtCD,oEAA0C;AAE1C,6CAAqC;AACrC,mDAAwD;AAYxD,SAAgB,aAAa,CAAC,QAAqD;IAC/E,OAAO,QAAQ,CAAA;AACnB,CAAC;AAED,SAAgB,cAAc,CAAC,QAAqD;IAChF,OAAO,IAAA,wBAAa,EAAC,QAAQ,CAAC,CAAA;AAClC,CAAC;AAED,SAAgB,cAAc;IAC1B,OAAO,IAAA,mBAAM,EAAC,cAAc,EAAE,EAAE,CAAC,CAAA;AACrC,CAAC;AAED,yCAAyC;AACzC,SAAgB,SAAS,CACrB,OAAe,EACf,aAAqB,GAAG,EACxB,OAAmB,0BAAU,CAAC,SAAS;IAEvC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAuB,CAAA;IACtD,KAAK,CAAC,UAAU,GAAG,UAAU,CAAA;IAC7B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAA;IAEtB,OAAO,KAAK,CAAA;AAChB,CAAC"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault, RouteHandlerMethod } from 'fastify';
|
|
2
|
+
import { TChecksumReply, TChecksumRequest } from '../schemas/checksum.schema';
|
|
2
3
|
import { TClientReply, TClientRequest } from '../schemas/client.schema';
|
|
3
4
|
import { TConfigReply, TConfigRequest } from '../schemas/config.schema';
|
|
4
5
|
import { TPlayReply, TPlayRequest } from '../schemas/play.schema';
|
|
5
6
|
import { TValidateReply, TValidateRequest } from '../schemas/validate.schema';
|
|
6
|
-
export type
|
|
7
|
+
export type TRtpParams = {
|
|
8
|
+
rtpVersion: string;
|
|
9
|
+
};
|
|
10
|
+
export type RouteHandler<TRequest, TReply, TParams = TRtpParams> = RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, {
|
|
7
11
|
Body: TRequest;
|
|
8
12
|
Reply: TReply;
|
|
13
|
+
Params: TParams;
|
|
9
14
|
}>;
|
|
10
15
|
export declare class HandlersHelper<IHandlers extends {
|
|
11
16
|
[key: string]: {
|
|
@@ -35,5 +40,9 @@ export declare const handlers: HandlersHelper<{
|
|
|
35
40
|
request: TClientRequest;
|
|
36
41
|
reply: TClientReply;
|
|
37
42
|
};
|
|
43
|
+
checksum: {
|
|
44
|
+
request: TChecksumRequest;
|
|
45
|
+
reply: TChecksumReply;
|
|
46
|
+
};
|
|
38
47
|
}>;
|
|
39
48
|
//# sourceMappingURL=handlers.helper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.helper.d.ts","sourceRoot":"","sources":["../../helpers/handlers.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,yBAAyB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,kBAAkB,EAC/F,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"handlers.helper.d.ts","sourceRoot":"","sources":["../../helpers/handlers.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,yBAAyB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,kBAAkB,EAC/F,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAI7E,MAAM,MAAM,UAAU,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/C,MAAM,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAG,UAAU,IAAI,kBAAkB,CACrF,gBAAgB,EAChB,2BAA2B,EAC3B,yBAAyB,EACzB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CACjD,CAAA;AAED,qBAAa,cAAc,CAAC,SAAS,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAA;CAAE;IACzF,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAE,MAAM,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAY;IAEpE,QAAQ,CAAC,KAAK,SAAS,MAAM,SAAS,EAClC,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAMjF,GAAG,CAAC,KAAK,SAAS,MAAM,SAAS,EAAE,IAAI,EAAE,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IASrH,GAAG,CAAC,KAAK,SAAS,MAAM,SAAS,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;CAI3D;AAED,eAAO,MAAM,QAAQ;UACT;QAAE,OAAO,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE;cACxC;QAAE,OAAO,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,cAAc,CAAA;KAAE;YACtD;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE;YAChD;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE;cAC9C;QAAE,OAAO,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,cAAc,CAAA;KAAE;EAChE,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handlers = exports.HandlersHelper = void 0;
|
|
4
|
+
const errors_helper_1 = require("./errors.helper");
|
|
4
5
|
const fastify_helper_1 = require("./fastify.helper");
|
|
5
6
|
class HandlersHelper {
|
|
6
7
|
handlers = new Map();
|
|
@@ -13,7 +14,7 @@ class HandlersHelper {
|
|
|
13
14
|
const handlerName = name;
|
|
14
15
|
return this.handlers.get(handlerName);
|
|
15
16
|
}
|
|
16
|
-
throw (0, fastify_helper_1.httpError)(`Handler "${String(name)}" is not registered
|
|
17
|
+
throw (0, fastify_helper_1.httpError)(`Handler "${String(name)}" is not registered`, 500, errors_helper_1.EErrorCode.Unhandled);
|
|
17
18
|
}
|
|
18
19
|
has(name) {
|
|
19
20
|
const handlerName = name;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.helper.js","sourceRoot":"","sources":["../../helpers/handlers.helper.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"handlers.helper.js","sourceRoot":"","sources":["../../helpers/handlers.helper.ts"],"names":[],"mappings":";;;AASA,mDAA4C;AAC5C,qDAA4C;AAW5C,MAAa,cAAc;IACb,QAAQ,GAAyC,IAAI,GAAG,EAAE,CAAA;IAEpE,QAAQ,CACJ,IAAW,EACX,OAA6E;QAE7E,MAAM,WAAW,GAAG,IAAc,CAAA;QAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAC3C,CAAC;IAED,GAAG,CAAgC,IAAW;QAC1C,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,IAAc,CAAA;YAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QACzC,CAAC;QAED,MAAM,IAAA,0BAAS,EAAC,YAAY,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,0BAAU,CAAC,SAAS,CAAC,CAAA;IAC7F,CAAC;IAED,GAAG,CAAgC,IAAW;QAC1C,MAAM,WAAW,GAAG,IAAc,CAAA;QAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACzC,CAAC;CACJ;AAxBD,wCAwBC;AAEY,QAAA,QAAQ,GAAG,IAAI,cAAc,EAMtC,CAAA"}
|