@stamprally/server 0.14.0 → 0.16.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/README.md +10 -3
- package/dist/index.cjs +719 -155
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -11
- package/dist/index.d.ts +80 -11
- package/dist/index.js +713 -156
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.d.cts
CHANGED
|
@@ -18,11 +18,20 @@ interface ClaimRewardTransactionParams {
|
|
|
18
18
|
readonly idempotencyKey?: string;
|
|
19
19
|
readonly proofData?: unknown;
|
|
20
20
|
readonly idempotencyTtlMs?: number;
|
|
21
|
+
/** The configured per-reward stock limit, or null for unlimited stock. */
|
|
22
|
+
readonly rewardStockLimit: number | null;
|
|
23
|
+
/** The configured shared stock limit, or null when shared inventory is disabled. */
|
|
24
|
+
readonly sharedStockLimit: number | null;
|
|
21
25
|
/** Used when the first claim is made before a user state has been stored. */
|
|
22
26
|
readonly initialUserState?: UserRallyState;
|
|
27
|
+
readonly stockKey?: string;
|
|
28
|
+
readonly secondaryStockKey?: string;
|
|
29
|
+
readonly initialStock?: number | null;
|
|
30
|
+
readonly initialSecondaryStock?: number | null;
|
|
23
31
|
}
|
|
24
32
|
interface ClaimRewardTransactionMutation {
|
|
25
33
|
readonly nextStock: number | null;
|
|
34
|
+
readonly nextSecondaryStock?: number | null;
|
|
26
35
|
readonly nextUserState: UserRallyState;
|
|
27
36
|
readonly auditLog: AuditLog;
|
|
28
37
|
/** The server response is persisted by the adapter with the idempotency key. */
|
|
@@ -60,12 +69,15 @@ interface ServerPersistenceAdapter {
|
|
|
60
69
|
*/
|
|
61
70
|
executeClaimRewardTransaction(params: ClaimRewardTransactionParams, mutation: (current: {
|
|
62
71
|
readonly stock: number | null;
|
|
72
|
+
readonly secondaryStock: number | null;
|
|
63
73
|
readonly claimCount: number;
|
|
64
74
|
readonly userState: UserRallyState;
|
|
65
75
|
}) => ClaimRewardTransactionMutation): Promise<{
|
|
66
76
|
readonly success: boolean;
|
|
67
77
|
readonly error?: string;
|
|
68
78
|
}>;
|
|
79
|
+
/** Set false when the adapter cannot persist per-reward inventory atomically. */
|
|
80
|
+
readonly supportsRewardStock?: boolean;
|
|
69
81
|
acquireLock(rallyId: string, lockKey: string, ttlMs: number): Promise<boolean>;
|
|
70
82
|
releaseLock(rallyId: string, lockKey: string): Promise<void>;
|
|
71
83
|
getRewardStock(rallyId: string, rewardId: string): Promise<number | null>;
|
|
@@ -89,6 +101,7 @@ interface InMemoryServerPersistenceOptions {
|
|
|
89
101
|
}
|
|
90
102
|
declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapter {
|
|
91
103
|
#private;
|
|
104
|
+
readonly supportsRewardStock = true;
|
|
92
105
|
constructor(options?: InMemoryServerPersistenceOptions);
|
|
93
106
|
acquireLock(rallyId: string, key: string, ttlMs: number): Promise<boolean>;
|
|
94
107
|
releaseLock(rallyId: string, key: string): Promise<void>;
|
|
@@ -100,6 +113,7 @@ declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapt
|
|
|
100
113
|
restoreRewardStock(rallyId: string, rewardId: string, count?: number): Promise<void>;
|
|
101
114
|
executeClaimRewardTransaction(params: ClaimRewardTransactionParams, mutation: (current: {
|
|
102
115
|
readonly stock: number | null;
|
|
116
|
+
readonly secondaryStock: number | null;
|
|
103
117
|
readonly claimCount: number;
|
|
104
118
|
readonly userState: UserRallyState;
|
|
105
119
|
}) => ClaimRewardTransactionMutation): Promise<{
|
|
@@ -128,7 +142,7 @@ declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapt
|
|
|
128
142
|
/** @deprecated Use recordUserClaim with a ticket number and timestamp. */
|
|
129
143
|
recordClaim(params: UserClaimRecord): Promise<void>;
|
|
130
144
|
recordClaim(rallyId: string, userId: string, rewardId: string): Promise<void>;
|
|
131
|
-
runTransaction<T>(
|
|
145
|
+
runTransaction<T>(rallyId: string, operation: (transaction: ServerPersistenceAdapter) => Promise<T>): Promise<T>;
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
/**
|
|
@@ -144,10 +158,12 @@ interface SqlTransactionDatabase<Tx> {
|
|
|
144
158
|
interface SqlClaimRewardStore<Tx> {
|
|
145
159
|
readContext(transaction: Tx, params: ClaimRewardTransactionParams): Promise<{
|
|
146
160
|
readonly stock: number | null;
|
|
161
|
+
readonly secondaryStock?: number | null;
|
|
147
162
|
readonly claimCount: number;
|
|
148
163
|
readonly userState: UserRallyState;
|
|
149
164
|
}>;
|
|
150
165
|
writeStock(transaction: Tx, params: ClaimRewardTransactionParams, nextStock: number): Promise<void>;
|
|
166
|
+
writeSecondaryStock?(transaction: Tx, params: ClaimRewardTransactionParams, nextStock: number): Promise<void>;
|
|
151
167
|
writeUserState(transaction: Tx, params: ClaimRewardTransactionParams, state: UserRallyState): Promise<void>;
|
|
152
168
|
writeClaimRecord(transaction: Tx, params: ClaimRewardTransactionParams, state: UserRallyState): Promise<void>;
|
|
153
169
|
writeAudit(transaction: Tx, log: AuditLog): Promise<void>;
|
|
@@ -167,11 +183,33 @@ declare function executeClaimRewardTransaction<Tx>(database: SqlTransactionDatab
|
|
|
167
183
|
readonly success: boolean;
|
|
168
184
|
readonly error?: string;
|
|
169
185
|
}>;
|
|
186
|
+
interface SqlCheckInStore<Tx> {
|
|
187
|
+
readUserState?(transaction: Tx, params: CheckInTransactionParams): Promise<UserRallyState>;
|
|
188
|
+
writeUserState(transaction: Tx, params: CheckInTransactionParams, state: UserRallyState): Promise<void>;
|
|
189
|
+
writeAudit(transaction: Tx, log: AuditLog): Promise<void>;
|
|
190
|
+
writeIdempotency(transaction: Tx, params: CheckInTransactionParams, result: unknown): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
/** Reference transaction block for a check-in state, audit, and idempotency write. */
|
|
193
|
+
declare function executeCheckInTransaction<Tx>(database: SqlTransactionDatabase<Tx>, store: SqlCheckInStore<Tx>, params: CheckInTransactionParams, mutation: (current: {
|
|
194
|
+
readonly userState: UserRallyState;
|
|
195
|
+
}) => CheckInTransactionMutation, current?: UserRallyState): Promise<{
|
|
196
|
+
readonly success: boolean;
|
|
197
|
+
readonly error?: string;
|
|
198
|
+
}>;
|
|
199
|
+
interface RedisMultiExecutor<TMulti> {
|
|
200
|
+
multi(): TMulti;
|
|
201
|
+
exec(multi: TMulti): Promise<ReadonlyArray<unknown> | null>;
|
|
202
|
+
}
|
|
203
|
+
/** Reference for Redis MULTI/EXEC adapters: all queued commands commit together. */
|
|
204
|
+
declare function executeRedisTransaction<TMulti>(redis: RedisMultiExecutor<TMulti>, queue: (multi: TMulti) => void): Promise<{
|
|
205
|
+
readonly success: boolean;
|
|
206
|
+
readonly error?: string;
|
|
207
|
+
}>;
|
|
170
208
|
|
|
171
209
|
interface RequestValidationError {
|
|
172
210
|
readonly path: string;
|
|
173
211
|
readonly message: string;
|
|
174
|
-
readonly code:
|
|
212
|
+
readonly code: string;
|
|
175
213
|
}
|
|
176
214
|
type RequestValidationResult<T> = {
|
|
177
215
|
readonly success: true;
|
|
@@ -180,11 +218,27 @@ type RequestValidationResult<T> = {
|
|
|
180
218
|
readonly success: false;
|
|
181
219
|
readonly errors: ReadonlyArray<RequestValidationError>;
|
|
182
220
|
};
|
|
221
|
+
declare class RequestValidationException extends Error {
|
|
222
|
+
readonly code = "VALIDATION_FAILED";
|
|
223
|
+
readonly errors: ReadonlyArray<RequestValidationError>;
|
|
224
|
+
constructor(errors: ReadonlyArray<RequestValidationError>);
|
|
225
|
+
}
|
|
183
226
|
declare function validateCheckInRequest(value: unknown): RequestValidationResult<CheckInRequest>;
|
|
184
227
|
declare function validateClaimRewardRequest(value: unknown): RequestValidationResult<ClaimRewardRequest>;
|
|
228
|
+
declare function assertValidCheckInParams(value: unknown, config: AdminRallyConfig): asserts value is CheckInRequest & {
|
|
229
|
+
readonly userId: string;
|
|
230
|
+
};
|
|
231
|
+
declare function assertValidClaimParams(value: unknown, config: AdminRallyConfig): asserts value is ClaimRewardRequest & {
|
|
232
|
+
readonly userId: string;
|
|
233
|
+
};
|
|
234
|
+
declare function assertValidSyncParams(value: unknown, config: AdminRallyConfig): asserts value is {
|
|
235
|
+
readonly rallyId: string;
|
|
236
|
+
readonly userId: string;
|
|
237
|
+
};
|
|
185
238
|
declare function validateSyncRequest(value: unknown): RequestValidationResult<{
|
|
186
239
|
readonly rallyId: string;
|
|
187
240
|
readonly userId?: string;
|
|
241
|
+
readonly anonymousSessionId?: string;
|
|
188
242
|
}>;
|
|
189
243
|
|
|
190
244
|
type ErrorResponse = {
|
|
@@ -196,7 +250,12 @@ type ClaimResponse = {
|
|
|
196
250
|
readonly ok: true;
|
|
197
251
|
readonly state: UserRallyState;
|
|
198
252
|
readonly claimTicketNumber?: string;
|
|
253
|
+
readonly inventory?: InventoryStatus;
|
|
199
254
|
} | ErrorResponse;
|
|
255
|
+
interface InventoryStatus {
|
|
256
|
+
readonly sharedRemaining?: number;
|
|
257
|
+
readonly rewardRemaining?: number;
|
|
258
|
+
}
|
|
200
259
|
declare class StampRallyServer {
|
|
201
260
|
#private;
|
|
202
261
|
constructor(config: AdminRallyConfig, persistence: ServerPersistenceAdapter, options?: ServerOptions);
|
|
@@ -204,15 +263,22 @@ declare class StampRallyServer {
|
|
|
204
263
|
handleCheckIn(request: Request): Promise<Response>;
|
|
205
264
|
handleClaimReward(request: Request): Promise<Response>;
|
|
206
265
|
handleSync(request: Request): Promise<Response>;
|
|
207
|
-
checkIn(request: CheckInRequest
|
|
208
|
-
|
|
209
|
-
}): Promise<CheckInResponse>;
|
|
210
|
-
claimReward(request: ClaimRewardRequest & {
|
|
211
|
-
readonly userId: string;
|
|
212
|
-
}): Promise<ClaimResponse>;
|
|
266
|
+
checkIn(request: CheckInRequest): Promise<CheckInResponse>;
|
|
267
|
+
claimReward(request: ClaimRewardRequest): Promise<ClaimResponse>;
|
|
213
268
|
sync(rallyId: string, userId: string): Promise<UserRallyState>;
|
|
269
|
+
syncProgress(request: {
|
|
270
|
+
readonly rallyId: string;
|
|
271
|
+
readonly userId?: string;
|
|
272
|
+
readonly anonymousSessionId?: string;
|
|
273
|
+
}): Promise<UserRallyState>;
|
|
214
274
|
}
|
|
215
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Runs the minimum atomicity and idempotency contract against a persistence adapter.
|
|
278
|
+
* The function throws a descriptive error when the adapter violates the contract.
|
|
279
|
+
*/
|
|
280
|
+
declare function runPersistenceAdapterComplianceTests(createAdapter: () => Promise<ServerPersistenceAdapter>): Promise<void>;
|
|
281
|
+
|
|
216
282
|
interface AuditLog {
|
|
217
283
|
readonly id: string;
|
|
218
284
|
readonly timestamp: string;
|
|
@@ -228,19 +294,21 @@ type SyncOperationStatus = "ACCEPTED" | "REJECTED_PERMANENT" | "RETRYABLE_ERROR"
|
|
|
228
294
|
interface CheckInRequest {
|
|
229
295
|
readonly rallyId: string;
|
|
230
296
|
readonly userId?: string;
|
|
297
|
+
readonly anonymousSessionId?: string;
|
|
231
298
|
readonly spotId: string;
|
|
232
299
|
readonly context: _stamprally_core.VerificationContext;
|
|
233
300
|
readonly idempotencyKey: string;
|
|
234
|
-
readonly now?: string;
|
|
301
|
+
readonly now?: string | number;
|
|
235
302
|
}
|
|
236
303
|
interface ClaimRewardRequest {
|
|
237
304
|
readonly rallyId: string;
|
|
238
305
|
readonly userId?: string;
|
|
306
|
+
readonly anonymousSessionId?: string;
|
|
239
307
|
readonly rewardId: string;
|
|
240
308
|
readonly idempotencyKey: string;
|
|
241
309
|
readonly staffPasscode?: string;
|
|
242
310
|
readonly staffId?: string;
|
|
243
|
-
readonly now?: string;
|
|
311
|
+
readonly now?: string | number;
|
|
244
312
|
}
|
|
245
313
|
type CheckInResponse = {
|
|
246
314
|
readonly ok: true;
|
|
@@ -258,9 +326,10 @@ interface ServerOptions {
|
|
|
258
326
|
readonly authenticate?: (request: Request) => Promise<string | AuthenticationContext | null> | string | AuthenticationContext | null;
|
|
259
327
|
readonly customValidators?: Readonly<Record<string, _stamprally_core.Validator>>;
|
|
260
328
|
readonly now?: () => string;
|
|
329
|
+
readonly anonymousPolicy?: "session_scoped" | "reject" | "shared_global_opt_in_insecure";
|
|
261
330
|
}
|
|
262
331
|
interface AuthenticationContext {
|
|
263
332
|
readonly authenticatedUserId: string;
|
|
264
333
|
}
|
|
265
334
|
|
|
266
|
-
export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RequestValidationError, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type UserClaimRecord, executeClaimRewardTransaction, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
|
|
335
|
+
export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,11 +18,20 @@ interface ClaimRewardTransactionParams {
|
|
|
18
18
|
readonly idempotencyKey?: string;
|
|
19
19
|
readonly proofData?: unknown;
|
|
20
20
|
readonly idempotencyTtlMs?: number;
|
|
21
|
+
/** The configured per-reward stock limit, or null for unlimited stock. */
|
|
22
|
+
readonly rewardStockLimit: number | null;
|
|
23
|
+
/** The configured shared stock limit, or null when shared inventory is disabled. */
|
|
24
|
+
readonly sharedStockLimit: number | null;
|
|
21
25
|
/** Used when the first claim is made before a user state has been stored. */
|
|
22
26
|
readonly initialUserState?: UserRallyState;
|
|
27
|
+
readonly stockKey?: string;
|
|
28
|
+
readonly secondaryStockKey?: string;
|
|
29
|
+
readonly initialStock?: number | null;
|
|
30
|
+
readonly initialSecondaryStock?: number | null;
|
|
23
31
|
}
|
|
24
32
|
interface ClaimRewardTransactionMutation {
|
|
25
33
|
readonly nextStock: number | null;
|
|
34
|
+
readonly nextSecondaryStock?: number | null;
|
|
26
35
|
readonly nextUserState: UserRallyState;
|
|
27
36
|
readonly auditLog: AuditLog;
|
|
28
37
|
/** The server response is persisted by the adapter with the idempotency key. */
|
|
@@ -60,12 +69,15 @@ interface ServerPersistenceAdapter {
|
|
|
60
69
|
*/
|
|
61
70
|
executeClaimRewardTransaction(params: ClaimRewardTransactionParams, mutation: (current: {
|
|
62
71
|
readonly stock: number | null;
|
|
72
|
+
readonly secondaryStock: number | null;
|
|
63
73
|
readonly claimCount: number;
|
|
64
74
|
readonly userState: UserRallyState;
|
|
65
75
|
}) => ClaimRewardTransactionMutation): Promise<{
|
|
66
76
|
readonly success: boolean;
|
|
67
77
|
readonly error?: string;
|
|
68
78
|
}>;
|
|
79
|
+
/** Set false when the adapter cannot persist per-reward inventory atomically. */
|
|
80
|
+
readonly supportsRewardStock?: boolean;
|
|
69
81
|
acquireLock(rallyId: string, lockKey: string, ttlMs: number): Promise<boolean>;
|
|
70
82
|
releaseLock(rallyId: string, lockKey: string): Promise<void>;
|
|
71
83
|
getRewardStock(rallyId: string, rewardId: string): Promise<number | null>;
|
|
@@ -89,6 +101,7 @@ interface InMemoryServerPersistenceOptions {
|
|
|
89
101
|
}
|
|
90
102
|
declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapter {
|
|
91
103
|
#private;
|
|
104
|
+
readonly supportsRewardStock = true;
|
|
92
105
|
constructor(options?: InMemoryServerPersistenceOptions);
|
|
93
106
|
acquireLock(rallyId: string, key: string, ttlMs: number): Promise<boolean>;
|
|
94
107
|
releaseLock(rallyId: string, key: string): Promise<void>;
|
|
@@ -100,6 +113,7 @@ declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapt
|
|
|
100
113
|
restoreRewardStock(rallyId: string, rewardId: string, count?: number): Promise<void>;
|
|
101
114
|
executeClaimRewardTransaction(params: ClaimRewardTransactionParams, mutation: (current: {
|
|
102
115
|
readonly stock: number | null;
|
|
116
|
+
readonly secondaryStock: number | null;
|
|
103
117
|
readonly claimCount: number;
|
|
104
118
|
readonly userState: UserRallyState;
|
|
105
119
|
}) => ClaimRewardTransactionMutation): Promise<{
|
|
@@ -128,7 +142,7 @@ declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapt
|
|
|
128
142
|
/** @deprecated Use recordUserClaim with a ticket number and timestamp. */
|
|
129
143
|
recordClaim(params: UserClaimRecord): Promise<void>;
|
|
130
144
|
recordClaim(rallyId: string, userId: string, rewardId: string): Promise<void>;
|
|
131
|
-
runTransaction<T>(
|
|
145
|
+
runTransaction<T>(rallyId: string, operation: (transaction: ServerPersistenceAdapter) => Promise<T>): Promise<T>;
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
/**
|
|
@@ -144,10 +158,12 @@ interface SqlTransactionDatabase<Tx> {
|
|
|
144
158
|
interface SqlClaimRewardStore<Tx> {
|
|
145
159
|
readContext(transaction: Tx, params: ClaimRewardTransactionParams): Promise<{
|
|
146
160
|
readonly stock: number | null;
|
|
161
|
+
readonly secondaryStock?: number | null;
|
|
147
162
|
readonly claimCount: number;
|
|
148
163
|
readonly userState: UserRallyState;
|
|
149
164
|
}>;
|
|
150
165
|
writeStock(transaction: Tx, params: ClaimRewardTransactionParams, nextStock: number): Promise<void>;
|
|
166
|
+
writeSecondaryStock?(transaction: Tx, params: ClaimRewardTransactionParams, nextStock: number): Promise<void>;
|
|
151
167
|
writeUserState(transaction: Tx, params: ClaimRewardTransactionParams, state: UserRallyState): Promise<void>;
|
|
152
168
|
writeClaimRecord(transaction: Tx, params: ClaimRewardTransactionParams, state: UserRallyState): Promise<void>;
|
|
153
169
|
writeAudit(transaction: Tx, log: AuditLog): Promise<void>;
|
|
@@ -167,11 +183,33 @@ declare function executeClaimRewardTransaction<Tx>(database: SqlTransactionDatab
|
|
|
167
183
|
readonly success: boolean;
|
|
168
184
|
readonly error?: string;
|
|
169
185
|
}>;
|
|
186
|
+
interface SqlCheckInStore<Tx> {
|
|
187
|
+
readUserState?(transaction: Tx, params: CheckInTransactionParams): Promise<UserRallyState>;
|
|
188
|
+
writeUserState(transaction: Tx, params: CheckInTransactionParams, state: UserRallyState): Promise<void>;
|
|
189
|
+
writeAudit(transaction: Tx, log: AuditLog): Promise<void>;
|
|
190
|
+
writeIdempotency(transaction: Tx, params: CheckInTransactionParams, result: unknown): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
/** Reference transaction block for a check-in state, audit, and idempotency write. */
|
|
193
|
+
declare function executeCheckInTransaction<Tx>(database: SqlTransactionDatabase<Tx>, store: SqlCheckInStore<Tx>, params: CheckInTransactionParams, mutation: (current: {
|
|
194
|
+
readonly userState: UserRallyState;
|
|
195
|
+
}) => CheckInTransactionMutation, current?: UserRallyState): Promise<{
|
|
196
|
+
readonly success: boolean;
|
|
197
|
+
readonly error?: string;
|
|
198
|
+
}>;
|
|
199
|
+
interface RedisMultiExecutor<TMulti> {
|
|
200
|
+
multi(): TMulti;
|
|
201
|
+
exec(multi: TMulti): Promise<ReadonlyArray<unknown> | null>;
|
|
202
|
+
}
|
|
203
|
+
/** Reference for Redis MULTI/EXEC adapters: all queued commands commit together. */
|
|
204
|
+
declare function executeRedisTransaction<TMulti>(redis: RedisMultiExecutor<TMulti>, queue: (multi: TMulti) => void): Promise<{
|
|
205
|
+
readonly success: boolean;
|
|
206
|
+
readonly error?: string;
|
|
207
|
+
}>;
|
|
170
208
|
|
|
171
209
|
interface RequestValidationError {
|
|
172
210
|
readonly path: string;
|
|
173
211
|
readonly message: string;
|
|
174
|
-
readonly code:
|
|
212
|
+
readonly code: string;
|
|
175
213
|
}
|
|
176
214
|
type RequestValidationResult<T> = {
|
|
177
215
|
readonly success: true;
|
|
@@ -180,11 +218,27 @@ type RequestValidationResult<T> = {
|
|
|
180
218
|
readonly success: false;
|
|
181
219
|
readonly errors: ReadonlyArray<RequestValidationError>;
|
|
182
220
|
};
|
|
221
|
+
declare class RequestValidationException extends Error {
|
|
222
|
+
readonly code = "VALIDATION_FAILED";
|
|
223
|
+
readonly errors: ReadonlyArray<RequestValidationError>;
|
|
224
|
+
constructor(errors: ReadonlyArray<RequestValidationError>);
|
|
225
|
+
}
|
|
183
226
|
declare function validateCheckInRequest(value: unknown): RequestValidationResult<CheckInRequest>;
|
|
184
227
|
declare function validateClaimRewardRequest(value: unknown): RequestValidationResult<ClaimRewardRequest>;
|
|
228
|
+
declare function assertValidCheckInParams(value: unknown, config: AdminRallyConfig): asserts value is CheckInRequest & {
|
|
229
|
+
readonly userId: string;
|
|
230
|
+
};
|
|
231
|
+
declare function assertValidClaimParams(value: unknown, config: AdminRallyConfig): asserts value is ClaimRewardRequest & {
|
|
232
|
+
readonly userId: string;
|
|
233
|
+
};
|
|
234
|
+
declare function assertValidSyncParams(value: unknown, config: AdminRallyConfig): asserts value is {
|
|
235
|
+
readonly rallyId: string;
|
|
236
|
+
readonly userId: string;
|
|
237
|
+
};
|
|
185
238
|
declare function validateSyncRequest(value: unknown): RequestValidationResult<{
|
|
186
239
|
readonly rallyId: string;
|
|
187
240
|
readonly userId?: string;
|
|
241
|
+
readonly anonymousSessionId?: string;
|
|
188
242
|
}>;
|
|
189
243
|
|
|
190
244
|
type ErrorResponse = {
|
|
@@ -196,7 +250,12 @@ type ClaimResponse = {
|
|
|
196
250
|
readonly ok: true;
|
|
197
251
|
readonly state: UserRallyState;
|
|
198
252
|
readonly claimTicketNumber?: string;
|
|
253
|
+
readonly inventory?: InventoryStatus;
|
|
199
254
|
} | ErrorResponse;
|
|
255
|
+
interface InventoryStatus {
|
|
256
|
+
readonly sharedRemaining?: number;
|
|
257
|
+
readonly rewardRemaining?: number;
|
|
258
|
+
}
|
|
200
259
|
declare class StampRallyServer {
|
|
201
260
|
#private;
|
|
202
261
|
constructor(config: AdminRallyConfig, persistence: ServerPersistenceAdapter, options?: ServerOptions);
|
|
@@ -204,15 +263,22 @@ declare class StampRallyServer {
|
|
|
204
263
|
handleCheckIn(request: Request): Promise<Response>;
|
|
205
264
|
handleClaimReward(request: Request): Promise<Response>;
|
|
206
265
|
handleSync(request: Request): Promise<Response>;
|
|
207
|
-
checkIn(request: CheckInRequest
|
|
208
|
-
|
|
209
|
-
}): Promise<CheckInResponse>;
|
|
210
|
-
claimReward(request: ClaimRewardRequest & {
|
|
211
|
-
readonly userId: string;
|
|
212
|
-
}): Promise<ClaimResponse>;
|
|
266
|
+
checkIn(request: CheckInRequest): Promise<CheckInResponse>;
|
|
267
|
+
claimReward(request: ClaimRewardRequest): Promise<ClaimResponse>;
|
|
213
268
|
sync(rallyId: string, userId: string): Promise<UserRallyState>;
|
|
269
|
+
syncProgress(request: {
|
|
270
|
+
readonly rallyId: string;
|
|
271
|
+
readonly userId?: string;
|
|
272
|
+
readonly anonymousSessionId?: string;
|
|
273
|
+
}): Promise<UserRallyState>;
|
|
214
274
|
}
|
|
215
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Runs the minimum atomicity and idempotency contract against a persistence adapter.
|
|
278
|
+
* The function throws a descriptive error when the adapter violates the contract.
|
|
279
|
+
*/
|
|
280
|
+
declare function runPersistenceAdapterComplianceTests(createAdapter: () => Promise<ServerPersistenceAdapter>): Promise<void>;
|
|
281
|
+
|
|
216
282
|
interface AuditLog {
|
|
217
283
|
readonly id: string;
|
|
218
284
|
readonly timestamp: string;
|
|
@@ -228,19 +294,21 @@ type SyncOperationStatus = "ACCEPTED" | "REJECTED_PERMANENT" | "RETRYABLE_ERROR"
|
|
|
228
294
|
interface CheckInRequest {
|
|
229
295
|
readonly rallyId: string;
|
|
230
296
|
readonly userId?: string;
|
|
297
|
+
readonly anonymousSessionId?: string;
|
|
231
298
|
readonly spotId: string;
|
|
232
299
|
readonly context: _stamprally_core.VerificationContext;
|
|
233
300
|
readonly idempotencyKey: string;
|
|
234
|
-
readonly now?: string;
|
|
301
|
+
readonly now?: string | number;
|
|
235
302
|
}
|
|
236
303
|
interface ClaimRewardRequest {
|
|
237
304
|
readonly rallyId: string;
|
|
238
305
|
readonly userId?: string;
|
|
306
|
+
readonly anonymousSessionId?: string;
|
|
239
307
|
readonly rewardId: string;
|
|
240
308
|
readonly idempotencyKey: string;
|
|
241
309
|
readonly staffPasscode?: string;
|
|
242
310
|
readonly staffId?: string;
|
|
243
|
-
readonly now?: string;
|
|
311
|
+
readonly now?: string | number;
|
|
244
312
|
}
|
|
245
313
|
type CheckInResponse = {
|
|
246
314
|
readonly ok: true;
|
|
@@ -258,9 +326,10 @@ interface ServerOptions {
|
|
|
258
326
|
readonly authenticate?: (request: Request) => Promise<string | AuthenticationContext | null> | string | AuthenticationContext | null;
|
|
259
327
|
readonly customValidators?: Readonly<Record<string, _stamprally_core.Validator>>;
|
|
260
328
|
readonly now?: () => string;
|
|
329
|
+
readonly anonymousPolicy?: "session_scoped" | "reject" | "shared_global_opt_in_insecure";
|
|
261
330
|
}
|
|
262
331
|
interface AuthenticationContext {
|
|
263
332
|
readonly authenticatedUserId: string;
|
|
264
333
|
}
|
|
265
334
|
|
|
266
|
-
export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RequestValidationError, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type UserClaimRecord, executeClaimRewardTransaction, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
|
|
335
|
+
export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
|