@game-infra/api-schemas-core 0.0.0 → 0.4.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/LICENSE +21 -0
- package/README.md +31 -1
- package/dist/auth.d.ts +50 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +41 -2
- package/dist/auth.js.map +1 -1
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js.map +1 -1
- package/dist/contracts.d.ts +347 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +186 -1
- package/dist/contracts.js.map +1 -1
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js.map +1 -1
- package/dist/gameEntity.d.ts.map +1 -1
- package/dist/gameEntity.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/savegame.d.ts.map +1 -1
- package/dist/savegame.js.map +1 -1
- package/dist/serviceToken.d.ts +393 -0
- package/dist/serviceToken.d.ts.map +1 -0
- package/dist/serviceToken.js +227 -0
- package/dist/serviceToken.js.map +1 -0
- package/dist/user.d.ts +251 -0
- package/dist/user.d.ts.map +1 -0
- package/dist/user.js +147 -0
- package/dist/user.js.map +1 -0
- package/package.json +14 -4
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { type InferOutput } from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* Service tokens are long-lived credentials a script or backend service
|
|
4
|
+
* presents to game-infra APIs on behalf of the account that created them.
|
|
5
|
+
*
|
|
6
|
+
* The issuer never stores the token. It stores only the reference needed to
|
|
7
|
+
* withdraw one — the token id, its owner, and its expiry — and the token itself
|
|
8
|
+
* carries that id, so revocation is a write against the id rather than a lookup
|
|
9
|
+
* of the secret. A token is therefore shown exactly once, at creation.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Bounds shared by the UI and the service, so both reject the same input.
|
|
13
|
+
*
|
|
14
|
+
* The TTL ceiling is a year: past that the token stops being a credential
|
|
15
|
+
* anyone rotates and becomes one nobody remembers issuing, and the expiry is
|
|
16
|
+
* the only thing that retires a token no one revokes.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { ServiceTokenValidation } from '@game-infra/api-schemas-core'
|
|
21
|
+
*
|
|
22
|
+
* const ttl = Math.min(requested, ServiceTokenValidation.MAX_TTL_SECONDS)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const ServiceTokenValidation: {
|
|
26
|
+
readonly MIN_NAME_LENGTH: 1;
|
|
27
|
+
readonly MAX_NAME_LENGTH: 100;
|
|
28
|
+
/** One hour. Shorter than this and the token cannot outlive a login. */
|
|
29
|
+
readonly MIN_TTL_SECONDS: number;
|
|
30
|
+
/** 365 days. */
|
|
31
|
+
readonly MAX_TTL_SECONDS: number;
|
|
32
|
+
/** 30 days — the default a caller gets when it names no TTL. */
|
|
33
|
+
readonly DEFAULT_TTL_SECONDS: number;
|
|
34
|
+
/** Token ids are `st_` plus 32 lowercase hex characters. */
|
|
35
|
+
readonly TOKEN_ID_PATTERN: RegExp;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* A stored service-token id.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { ServiceTokenIdSchema } from '@game-infra/api-schemas-core'
|
|
43
|
+
* import { parse } from 'valibot'
|
|
44
|
+
*
|
|
45
|
+
* parse(ServiceTokenIdSchema, 'st_0123456789abcdef0123456789abcdef')
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const ServiceTokenIdSchema: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Not a service-token id">]>;
|
|
49
|
+
/**
|
|
50
|
+
* Everything the issuer keeps about a service token — which is everything
|
|
51
|
+
* except the token.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import type { ServiceToken } from '@game-infra/api-schemas-core'
|
|
56
|
+
*
|
|
57
|
+
* const isLive = (token: ServiceToken) => !token.revokedAt && Date.parse(token.expiresAt) > Date.now()
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const ServiceTokenSchema: import("valibot").ObjectSchema<{
|
|
61
|
+
/** Token id, carried by the token as its `jti` claim. */
|
|
62
|
+
readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Not a service-token id">]>;
|
|
63
|
+
/** Caller-supplied label, the only way a human tells two tokens apart. */
|
|
64
|
+
readonly name: import("valibot").StringSchema<undefined>;
|
|
65
|
+
/** Account the token acts as. */
|
|
66
|
+
readonly userId: import("valibot").NumberSchema<undefined>;
|
|
67
|
+
/** Username of that account, as of issue time. */
|
|
68
|
+
readonly username: import("valibot").StringSchema<undefined>;
|
|
69
|
+
/** Authorization claims the token carries; never wider than the creator's. */
|
|
70
|
+
readonly claims: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
71
|
+
/** ISO-8601 issue time. */
|
|
72
|
+
readonly createdAt: import("valibot").StringSchema<undefined>;
|
|
73
|
+
/** ISO-8601 expiry, stamped into the token and not extendable. */
|
|
74
|
+
readonly expiresAt: import("valibot").StringSchema<undefined>;
|
|
75
|
+
/** ISO-8601 revocation time, or `null` while the token is still honoured. */
|
|
76
|
+
readonly revokedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
77
|
+
/** ISO-8601 time the token last validated successfully, or `null`. */
|
|
78
|
+
readonly lastUsedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
79
|
+
}, undefined>;
|
|
80
|
+
/**
|
|
81
|
+
* Inferred stored service-token record.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import type { ServiceToken } from '@game-infra/api-schemas-core'
|
|
86
|
+
*
|
|
87
|
+
* const id: ServiceToken['id'] = 'st_0123456789abcdef0123456789abcdef'
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export type ServiceToken = InferOutput<typeof ServiceTokenSchema>;
|
|
91
|
+
/**
|
|
92
|
+
* Request to mint a service token.
|
|
93
|
+
*
|
|
94
|
+
* `claims` is a request, not a grant: the service intersects it with the
|
|
95
|
+
* creator's own claims, so a token can never reach further than the account
|
|
96
|
+
* that created it.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { CreateServiceTokenRequestSchema } from '@game-infra/api-schemas-core'
|
|
101
|
+
* import { parse } from 'valibot'
|
|
102
|
+
*
|
|
103
|
+
* parse(CreateServiceTokenRequestSchema, { name: 'nightly-import', ttlSeconds: 604800 })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare const CreateServiceTokenRequestSchema: import("valibot").ObjectSchema<{
|
|
107
|
+
readonly name: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, "Name is required">, import("valibot").MaxLengthAction<string, 100, undefined>]>;
|
|
108
|
+
readonly ttlSeconds: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, "TTL must be a whole number of seconds">, import("valibot").MinValueAction<number, number, undefined>, import("valibot").MaxValueAction<number, number, undefined>]>, undefined>;
|
|
109
|
+
readonly claims: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
110
|
+
}, undefined>;
|
|
111
|
+
/**
|
|
112
|
+
* Inferred create-service-token request.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* import type { CreateServiceTokenRequest } from '@game-infra/api-schemas-core'
|
|
117
|
+
*
|
|
118
|
+
* const request: CreateServiceTokenRequest = { name: 'nightly-import' }
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export type CreateServiceTokenRequest = InferOutput<typeof CreateServiceTokenRequestSchema>;
|
|
122
|
+
/**
|
|
123
|
+
* The one and only response that carries the token itself.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* import type { CreateServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
128
|
+
*
|
|
129
|
+
* const show = (response: CreateServiceTokenResponse) => response.token
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare const CreateServiceTokenResponseSchema: import("valibot").ObjectSchema<{
|
|
133
|
+
readonly success: import("valibot").BooleanSchema<undefined>;
|
|
134
|
+
readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
135
|
+
} & {
|
|
136
|
+
/** The signed token. Not stored, and not retrievable again. */
|
|
137
|
+
token: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
138
|
+
serviceToken: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
|
|
139
|
+
/** Token id, carried by the token as its `jti` claim. */
|
|
140
|
+
readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Not a service-token id">]>;
|
|
141
|
+
/** Caller-supplied label, the only way a human tells two tokens apart. */
|
|
142
|
+
readonly name: import("valibot").StringSchema<undefined>;
|
|
143
|
+
/** Account the token acts as. */
|
|
144
|
+
readonly userId: import("valibot").NumberSchema<undefined>;
|
|
145
|
+
/** Username of that account, as of issue time. */
|
|
146
|
+
readonly username: import("valibot").StringSchema<undefined>;
|
|
147
|
+
/** Authorization claims the token carries; never wider than the creator's. */
|
|
148
|
+
readonly claims: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
149
|
+
/** ISO-8601 issue time. */
|
|
150
|
+
readonly createdAt: import("valibot").StringSchema<undefined>;
|
|
151
|
+
/** ISO-8601 expiry, stamped into the token and not extendable. */
|
|
152
|
+
readonly expiresAt: import("valibot").StringSchema<undefined>;
|
|
153
|
+
/** ISO-8601 revocation time, or `null` while the token is still honoured. */
|
|
154
|
+
readonly revokedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
155
|
+
/** ISO-8601 time the token last validated successfully, or `null`. */
|
|
156
|
+
readonly lastUsedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
157
|
+
}, undefined>, undefined>;
|
|
158
|
+
}, undefined>;
|
|
159
|
+
/**
|
|
160
|
+
* Inferred create-service-token response.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* import type { CreateServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
165
|
+
*
|
|
166
|
+
* const ok: CreateServiceTokenResponse['success'] = true
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export type CreateServiceTokenResponse = InferOutput<typeof CreateServiceTokenResponseSchema>;
|
|
170
|
+
/**
|
|
171
|
+
* The caller's own service tokens, newest first.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import type { ListServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
176
|
+
*
|
|
177
|
+
* const count = (response: ListServiceTokensResponse) => response.serviceTokens?.length ?? 0
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
export declare const ListServiceTokensResponseSchema: import("valibot").ObjectSchema<{
|
|
181
|
+
readonly success: import("valibot").BooleanSchema<undefined>;
|
|
182
|
+
readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
183
|
+
} & {
|
|
184
|
+
serviceTokens: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
185
|
+
/** Token id, carried by the token as its `jti` claim. */
|
|
186
|
+
readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Not a service-token id">]>;
|
|
187
|
+
/** Caller-supplied label, the only way a human tells two tokens apart. */
|
|
188
|
+
readonly name: import("valibot").StringSchema<undefined>;
|
|
189
|
+
/** Account the token acts as. */
|
|
190
|
+
readonly userId: import("valibot").NumberSchema<undefined>;
|
|
191
|
+
/** Username of that account, as of issue time. */
|
|
192
|
+
readonly username: import("valibot").StringSchema<undefined>;
|
|
193
|
+
/** Authorization claims the token carries; never wider than the creator's. */
|
|
194
|
+
readonly claims: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
195
|
+
/** ISO-8601 issue time. */
|
|
196
|
+
readonly createdAt: import("valibot").StringSchema<undefined>;
|
|
197
|
+
/** ISO-8601 expiry, stamped into the token and not extendable. */
|
|
198
|
+
readonly expiresAt: import("valibot").StringSchema<undefined>;
|
|
199
|
+
/** ISO-8601 revocation time, or `null` while the token is still honoured. */
|
|
200
|
+
readonly revokedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
201
|
+
/** ISO-8601 time the token last validated successfully, or `null`. */
|
|
202
|
+
readonly lastUsedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
203
|
+
}, undefined>, undefined>, undefined>;
|
|
204
|
+
/**
|
|
205
|
+
* The retention window the issuer applies before deleting an expired
|
|
206
|
+
* record, in seconds.
|
|
207
|
+
*
|
|
208
|
+
* A client cannot work out which records a purge would actually remove
|
|
209
|
+
* without it: an expired token's row survives until the window has passed
|
|
210
|
+
* too, so "expired" and "purgeable" are different sets, and a UI counting the
|
|
211
|
+
* first offers to delete rows the service will keep. Optional because a
|
|
212
|
+
* deployment predating this field does not send it.
|
|
213
|
+
*/
|
|
214
|
+
retentionSeconds: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
|
|
215
|
+
}, undefined>;
|
|
216
|
+
/**
|
|
217
|
+
* Inferred list-service-tokens response.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* import type { ListServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
222
|
+
*
|
|
223
|
+
* const ok: ListServiceTokensResponse['success'] = true
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export type ListServiceTokensResponse = InferOutput<typeof ListServiceTokensResponseSchema>;
|
|
227
|
+
/**
|
|
228
|
+
* Result of revoking a service token.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* import type { RevokeServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
233
|
+
*
|
|
234
|
+
* const when = (response: RevokeServiceTokenResponse) => response.serviceToken?.revokedAt
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
export declare const RevokeServiceTokenResponseSchema: import("valibot").ObjectSchema<{
|
|
238
|
+
readonly success: import("valibot").BooleanSchema<undefined>;
|
|
239
|
+
readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
240
|
+
} & {
|
|
241
|
+
serviceToken: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
|
|
242
|
+
/** Token id, carried by the token as its `jti` claim. */
|
|
243
|
+
readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Not a service-token id">]>;
|
|
244
|
+
/** Caller-supplied label, the only way a human tells two tokens apart. */
|
|
245
|
+
readonly name: import("valibot").StringSchema<undefined>;
|
|
246
|
+
/** Account the token acts as. */
|
|
247
|
+
readonly userId: import("valibot").NumberSchema<undefined>;
|
|
248
|
+
/** Username of that account, as of issue time. */
|
|
249
|
+
readonly username: import("valibot").StringSchema<undefined>;
|
|
250
|
+
/** Authorization claims the token carries; never wider than the creator's. */
|
|
251
|
+
readonly claims: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
252
|
+
/** ISO-8601 issue time. */
|
|
253
|
+
readonly createdAt: import("valibot").StringSchema<undefined>;
|
|
254
|
+
/** ISO-8601 expiry, stamped into the token and not extendable. */
|
|
255
|
+
readonly expiresAt: import("valibot").StringSchema<undefined>;
|
|
256
|
+
/** ISO-8601 revocation time, or `null` while the token is still honoured. */
|
|
257
|
+
readonly revokedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
258
|
+
/** ISO-8601 time the token last validated successfully, or `null`. */
|
|
259
|
+
readonly lastUsedAt: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
260
|
+
}, undefined>, undefined>;
|
|
261
|
+
}, undefined>;
|
|
262
|
+
/**
|
|
263
|
+
* Inferred revoke-service-token response.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* import type { RevokeServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
268
|
+
*
|
|
269
|
+
* const ok: RevokeServiceTokenResponse['success'] = true
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
export type RevokeServiceTokenResponse = InferOutput<typeof RevokeServiceTokenResponseSchema>;
|
|
273
|
+
/**
|
|
274
|
+
* Token a service or script asks the issuer to check.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```ts
|
|
278
|
+
* import { ServiceTokenValidateRequestSchema } from '@game-infra/api-schemas-core'
|
|
279
|
+
* import { parse } from 'valibot'
|
|
280
|
+
*
|
|
281
|
+
* parse(ServiceTokenValidateRequestSchema, { token: 'eyJhbGciOi...' })
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
export declare const ServiceTokenValidateRequestSchema: import("valibot").ObjectSchema<{
|
|
285
|
+
readonly token: import("valibot").StringSchema<undefined>;
|
|
286
|
+
}, undefined>;
|
|
287
|
+
/**
|
|
288
|
+
* Inferred service-token validation request.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* import type { ServiceTokenValidateRequest } from '@game-infra/api-schemas-core'
|
|
293
|
+
*
|
|
294
|
+
* const request: ServiceTokenValidateRequest = { token: 'eyJhbGciOi...' }
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
export type ServiceTokenValidateRequest = InferOutput<typeof ServiceTokenValidateRequestSchema>;
|
|
298
|
+
/**
|
|
299
|
+
* Why a service token was not accepted.
|
|
300
|
+
*
|
|
301
|
+
* `revoked` and `unknown` are the two answers a signature check alone cannot
|
|
302
|
+
* give, and they are the reason this endpoint exists next to `/auth/validate`:
|
|
303
|
+
* `unknown` covers a correctly signed token whose record has been purged, which
|
|
304
|
+
* a caller must treat exactly like a revoked one.
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```ts
|
|
308
|
+
* import { ServiceTokenRejectionSchema } from '@game-infra/api-schemas-core'
|
|
309
|
+
* import { parse } from 'valibot'
|
|
310
|
+
*
|
|
311
|
+
* parse(ServiceTokenRejectionSchema, 'revoked')
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
export declare const ServiceTokenRejectionSchema: import("valibot").UnionSchema<[import("valibot").LiteralSchema<"invalid", undefined>, import("valibot").LiteralSchema<"expired", undefined>, import("valibot").LiteralSchema<"revoked", undefined>, import("valibot").LiteralSchema<"unknown", undefined>, import("valibot").LiteralSchema<"wrongTokenType", undefined>], undefined>;
|
|
315
|
+
/**
|
|
316
|
+
* Inferred service-token rejection reason.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```ts
|
|
320
|
+
* import type { ServiceTokenRejection } from '@game-infra/api-schemas-core'
|
|
321
|
+
*
|
|
322
|
+
* const reason: ServiceTokenRejection = 'expired'
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
export type ServiceTokenRejection = InferOutput<typeof ServiceTokenRejectionSchema>;
|
|
326
|
+
/**
|
|
327
|
+
* Verdict on a service token: signature, expiry, and the revocation list.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* import type { ServiceTokenValidateResponse } from '@game-infra/api-schemas-core'
|
|
332
|
+
*
|
|
333
|
+
* const accept = (response: ServiceTokenValidateResponse) => response.valid === true
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
export declare const ServiceTokenValidateResponseSchema: import("valibot").ObjectSchema<{
|
|
337
|
+
readonly success: import("valibot").BooleanSchema<undefined>;
|
|
338
|
+
readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
339
|
+
} & {
|
|
340
|
+
valid: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
|
|
341
|
+
/** Set only when `valid` is false. */
|
|
342
|
+
reason: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"invalid", undefined>, import("valibot").LiteralSchema<"expired", undefined>, import("valibot").LiteralSchema<"revoked", undefined>, import("valibot").LiteralSchema<"unknown", undefined>, import("valibot").LiteralSchema<"wrongTokenType", undefined>], undefined>, undefined>;
|
|
343
|
+
tokenId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
344
|
+
userId: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
|
|
345
|
+
username: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
346
|
+
claims: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
347
|
+
expiresAt: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
348
|
+
}, undefined>;
|
|
349
|
+
/**
|
|
350
|
+
* Inferred service-token validation response.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```ts
|
|
354
|
+
* import type { ServiceTokenValidateResponse } from '@game-infra/api-schemas-core'
|
|
355
|
+
*
|
|
356
|
+
* const ok: ServiceTokenValidateResponse['success'] = true
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
export type ServiceTokenValidateResponse = InferOutput<typeof ServiceTokenValidateResponseSchema>;
|
|
360
|
+
/**
|
|
361
|
+
* How many obsolete token records a purge deleted.
|
|
362
|
+
*
|
|
363
|
+
* A record is obsolete once the token it describes has expired past the
|
|
364
|
+
* retention window: an expired token fails signature-and-expiry verification
|
|
365
|
+
* everywhere, so keeping its record buys neither revocation nor an answer.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* import type { PurgeServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
370
|
+
*
|
|
371
|
+
* const freed = (response: PurgeServiceTokensResponse) => response.purged ?? 0
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
export declare const PurgeServiceTokensResponseSchema: import("valibot").ObjectSchema<{
|
|
375
|
+
readonly success: import("valibot").BooleanSchema<undefined>;
|
|
376
|
+
readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
377
|
+
} & {
|
|
378
|
+
purged: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
|
|
379
|
+
/** Retention window applied, in seconds, so a caller can explain the count. */
|
|
380
|
+
retentionSeconds: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
|
|
381
|
+
}, undefined>;
|
|
382
|
+
/**
|
|
383
|
+
* Inferred purge-service-tokens response.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```ts
|
|
387
|
+
* import type { PurgeServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
388
|
+
*
|
|
389
|
+
* const ok: PurgeServiceTokensResponse['success'] = true
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
export type PurgeServiceTokensResponse = InferOutput<typeof PurgeServiceTokensResponseSchema>;
|
|
393
|
+
//# sourceMappingURL=serviceToken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serviceToken.d.ts","sourceRoot":"","sources":["../src/serviceToken.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { array, boolean, integer, literal, maxLength, maxValue, minLength, minValue, nullable, number, object, optional, pipe, regex, string, union, } from "valibot";
|
|
2
|
+
import { createSuccessResponseSchema } from "./common.js";
|
|
3
|
+
/**
|
|
4
|
+
* Service tokens are long-lived credentials a script or backend service
|
|
5
|
+
* presents to game-infra APIs on behalf of the account that created them.
|
|
6
|
+
*
|
|
7
|
+
* The issuer never stores the token. It stores only the reference needed to
|
|
8
|
+
* withdraw one — the token id, its owner, and its expiry — and the token itself
|
|
9
|
+
* carries that id, so revocation is a write against the id rather than a lookup
|
|
10
|
+
* of the secret. A token is therefore shown exactly once, at creation.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Bounds shared by the UI and the service, so both reject the same input.
|
|
14
|
+
*
|
|
15
|
+
* The TTL ceiling is a year: past that the token stops being a credential
|
|
16
|
+
* anyone rotates and becomes one nobody remembers issuing, and the expiry is
|
|
17
|
+
* the only thing that retires a token no one revokes.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { ServiceTokenValidation } from '@game-infra/api-schemas-core'
|
|
22
|
+
*
|
|
23
|
+
* const ttl = Math.min(requested, ServiceTokenValidation.MAX_TTL_SECONDS)
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const ServiceTokenValidation = {
|
|
27
|
+
MIN_NAME_LENGTH: 1,
|
|
28
|
+
MAX_NAME_LENGTH: 100,
|
|
29
|
+
/** One hour. Shorter than this and the token cannot outlive a login. */
|
|
30
|
+
MIN_TTL_SECONDS: 60 * 60,
|
|
31
|
+
/** 365 days. */
|
|
32
|
+
MAX_TTL_SECONDS: 365 * 24 * 60 * 60,
|
|
33
|
+
/** 30 days — the default a caller gets when it names no TTL. */
|
|
34
|
+
DEFAULT_TTL_SECONDS: 30 * 24 * 60 * 60,
|
|
35
|
+
/** Token ids are `st_` plus 32 lowercase hex characters. */
|
|
36
|
+
TOKEN_ID_PATTERN: /^st_[0-9a-f]{32}$/,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* A stored service-token id.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { ServiceTokenIdSchema } from '@game-infra/api-schemas-core'
|
|
44
|
+
* import { parse } from 'valibot'
|
|
45
|
+
*
|
|
46
|
+
* parse(ServiceTokenIdSchema, 'st_0123456789abcdef0123456789abcdef')
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export const ServiceTokenIdSchema = pipe(string(), regex(ServiceTokenValidation.TOKEN_ID_PATTERN, "Not a service-token id"));
|
|
50
|
+
/**
|
|
51
|
+
* Everything the issuer keeps about a service token — which is everything
|
|
52
|
+
* except the token.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import type { ServiceToken } from '@game-infra/api-schemas-core'
|
|
57
|
+
*
|
|
58
|
+
* const isLive = (token: ServiceToken) => !token.revokedAt && Date.parse(token.expiresAt) > Date.now()
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export const ServiceTokenSchema = object({
|
|
62
|
+
/** Token id, carried by the token as its `jti` claim. */
|
|
63
|
+
id: ServiceTokenIdSchema,
|
|
64
|
+
/** Caller-supplied label, the only way a human tells two tokens apart. */
|
|
65
|
+
name: string(),
|
|
66
|
+
/** Account the token acts as. */
|
|
67
|
+
userId: number(),
|
|
68
|
+
/** Username of that account, as of issue time. */
|
|
69
|
+
username: string(),
|
|
70
|
+
/** Authorization claims the token carries; never wider than the creator's. */
|
|
71
|
+
claims: array(string()),
|
|
72
|
+
/** ISO-8601 issue time. */
|
|
73
|
+
createdAt: string(),
|
|
74
|
+
/** ISO-8601 expiry, stamped into the token and not extendable. */
|
|
75
|
+
expiresAt: string(),
|
|
76
|
+
/** ISO-8601 revocation time, or `null` while the token is still honoured. */
|
|
77
|
+
revokedAt: nullable(string()),
|
|
78
|
+
/** ISO-8601 time the token last validated successfully, or `null`. */
|
|
79
|
+
lastUsedAt: nullable(string()),
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Request to mint a service token.
|
|
83
|
+
*
|
|
84
|
+
* `claims` is a request, not a grant: the service intersects it with the
|
|
85
|
+
* creator's own claims, so a token can never reach further than the account
|
|
86
|
+
* that created it.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { CreateServiceTokenRequestSchema } from '@game-infra/api-schemas-core'
|
|
91
|
+
* import { parse } from 'valibot'
|
|
92
|
+
*
|
|
93
|
+
* parse(CreateServiceTokenRequestSchema, { name: 'nightly-import', ttlSeconds: 604800 })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export const CreateServiceTokenRequestSchema = object({
|
|
97
|
+
name: pipe(string(), minLength(ServiceTokenValidation.MIN_NAME_LENGTH, "Name is required"), maxLength(ServiceTokenValidation.MAX_NAME_LENGTH)),
|
|
98
|
+
ttlSeconds: optional(pipe(number(), integer("TTL must be a whole number of seconds"), minValue(ServiceTokenValidation.MIN_TTL_SECONDS), maxValue(ServiceTokenValidation.MAX_TTL_SECONDS))),
|
|
99
|
+
claims: optional(array(string())),
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* The one and only response that carries the token itself.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import type { CreateServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
107
|
+
*
|
|
108
|
+
* const show = (response: CreateServiceTokenResponse) => response.token
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export const CreateServiceTokenResponseSchema = createSuccessResponseSchema({
|
|
112
|
+
/** The signed token. Not stored, and not retrievable again. */
|
|
113
|
+
token: optional(string()),
|
|
114
|
+
serviceToken: optional(ServiceTokenSchema),
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* The caller's own service tokens, newest first.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* import type { ListServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
122
|
+
*
|
|
123
|
+
* const count = (response: ListServiceTokensResponse) => response.serviceTokens?.length ?? 0
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export const ListServiceTokensResponseSchema = createSuccessResponseSchema({
|
|
127
|
+
serviceTokens: optional(array(ServiceTokenSchema)),
|
|
128
|
+
/**
|
|
129
|
+
* The retention window the issuer applies before deleting an expired
|
|
130
|
+
* record, in seconds.
|
|
131
|
+
*
|
|
132
|
+
* A client cannot work out which records a purge would actually remove
|
|
133
|
+
* without it: an expired token's row survives until the window has passed
|
|
134
|
+
* too, so "expired" and "purgeable" are different sets, and a UI counting the
|
|
135
|
+
* first offers to delete rows the service will keep. Optional because a
|
|
136
|
+
* deployment predating this field does not send it.
|
|
137
|
+
*/
|
|
138
|
+
retentionSeconds: optional(number()),
|
|
139
|
+
});
|
|
140
|
+
/**
|
|
141
|
+
* Result of revoking a service token.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* import type { RevokeServiceTokenResponse } from '@game-infra/api-schemas-core'
|
|
146
|
+
*
|
|
147
|
+
* const when = (response: RevokeServiceTokenResponse) => response.serviceToken?.revokedAt
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export const RevokeServiceTokenResponseSchema = createSuccessResponseSchema({
|
|
151
|
+
serviceToken: optional(ServiceTokenSchema),
|
|
152
|
+
});
|
|
153
|
+
/**
|
|
154
|
+
* Token a service or script asks the issuer to check.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* import { ServiceTokenValidateRequestSchema } from '@game-infra/api-schemas-core'
|
|
159
|
+
* import { parse } from 'valibot'
|
|
160
|
+
*
|
|
161
|
+
* parse(ServiceTokenValidateRequestSchema, { token: 'eyJhbGciOi...' })
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
export const ServiceTokenValidateRequestSchema = object({ token: string() });
|
|
165
|
+
/**
|
|
166
|
+
* Why a service token was not accepted.
|
|
167
|
+
*
|
|
168
|
+
* `revoked` and `unknown` are the two answers a signature check alone cannot
|
|
169
|
+
* give, and they are the reason this endpoint exists next to `/auth/validate`:
|
|
170
|
+
* `unknown` covers a correctly signed token whose record has been purged, which
|
|
171
|
+
* a caller must treat exactly like a revoked one.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import { ServiceTokenRejectionSchema } from '@game-infra/api-schemas-core'
|
|
176
|
+
* import { parse } from 'valibot'
|
|
177
|
+
*
|
|
178
|
+
* parse(ServiceTokenRejectionSchema, 'revoked')
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export const ServiceTokenRejectionSchema = union([
|
|
182
|
+
literal("invalid"),
|
|
183
|
+
literal("expired"),
|
|
184
|
+
literal("revoked"),
|
|
185
|
+
literal("unknown"),
|
|
186
|
+
literal("wrongTokenType"),
|
|
187
|
+
]);
|
|
188
|
+
/**
|
|
189
|
+
* Verdict on a service token: signature, expiry, and the revocation list.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* import type { ServiceTokenValidateResponse } from '@game-infra/api-schemas-core'
|
|
194
|
+
*
|
|
195
|
+
* const accept = (response: ServiceTokenValidateResponse) => response.valid === true
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export const ServiceTokenValidateResponseSchema = createSuccessResponseSchema({
|
|
199
|
+
valid: optional(boolean()),
|
|
200
|
+
/** Set only when `valid` is false. */
|
|
201
|
+
reason: optional(ServiceTokenRejectionSchema),
|
|
202
|
+
tokenId: optional(string()),
|
|
203
|
+
userId: optional(number()),
|
|
204
|
+
username: optional(string()),
|
|
205
|
+
claims: optional(array(string())),
|
|
206
|
+
expiresAt: optional(string()),
|
|
207
|
+
});
|
|
208
|
+
/**
|
|
209
|
+
* How many obsolete token records a purge deleted.
|
|
210
|
+
*
|
|
211
|
+
* A record is obsolete once the token it describes has expired past the
|
|
212
|
+
* retention window: an expired token fails signature-and-expiry verification
|
|
213
|
+
* everywhere, so keeping its record buys neither revocation nor an answer.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* import type { PurgeServiceTokensResponse } from '@game-infra/api-schemas-core'
|
|
218
|
+
*
|
|
219
|
+
* const freed = (response: PurgeServiceTokensResponse) => response.purged ?? 0
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export const PurgeServiceTokensResponseSchema = createSuccessResponseSchema({
|
|
223
|
+
purged: optional(number()),
|
|
224
|
+
/** Retention window applied, in seconds, so a caller can explain the count. */
|
|
225
|
+
retentionSeconds: optional(number()),
|
|
226
|
+
});
|
|
227
|
+
//# sourceMappingURL=serviceToken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serviceToken.js","sourceRoot":"","sources":["../src/serviceToken.ts"],"names":[],"mappings":"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"}
|