@stamprally/server 0.11.0 → 0.12.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/persistence.ts","../src/server.ts"],"names":["now"],"mappings":"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","file":"index.js","sourcesContent":["import type { UserRallyState } from \"@stamprally/core\";\nimport type { AuditLog } from \"./index.js\";\n\nexport interface UserClaimRecord {\n readonly rallyId: string;\n readonly userId: string;\n readonly rewardId: string;\n readonly ticketNumber: string;\n readonly timestamp: number;\n}\n\nexport interface ServerPersistenceAdapter {\n /** Runs the callback in a storage-native transaction when supported. */\n runTransaction?<T>(\n rallyId: string,\n operation: (transaction: ServerPersistenceAdapter) => Promise<T>,\n ): Promise<T>;\n acquireLock(rallyId: string, lockKey: string, ttlMs: number): Promise<boolean>;\n releaseLock(rallyId: string, lockKey: string): Promise<void>;\n getRewardStock(rallyId: string, rewardId: string): Promise<number | null>;\n decrementRewardStock(\n rallyId: string,\n rewardId: string,\n ): Promise<{ readonly success: boolean; readonly remainingStock: number }>;\n restoreRewardStock?(rallyId: string, rewardId: string, count?: number): Promise<void>;\n rollbackUserState?(\n rallyId: string,\n userId: string,\n previousState: UserRallyState | null,\n ): Promise<void>;\n rollbackUserClaim?(\n rallyId: string,\n userId: string,\n rewardId: string,\n ticketNumber: string,\n ): Promise<void>;\n getIdempotentResult<T>(rallyId: string, key: string): Promise<T | null>;\n saveIdempotentResult<T>(rallyId: string, key: string, result: T, ttlMs: number): Promise<void>;\n getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number>;\n recordUserClaim(params: UserClaimRecord): Promise<void>;\n recordClaim?(params: UserClaimRecord): Promise<void>;\n incrementUserClaimCount?(rallyId: string, userId: string, rewardId: string): Promise<void>;\n getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;\n saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void>;\n recordAuditLog(log: AuditLog): Promise<void>;\n removeAuditLog?(auditId: string): Promise<void>;\n}\ninterface TimedValue<T> {\n readonly value: T;\n readonly expiresAt: number;\n}\nexport interface InMemoryServerPersistenceOptions {\n readonly stocks?: Readonly<Record<string, number>>;\n}\nexport class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapter {\n readonly #locks = new Map<string, number>();\n readonly #idempotent = new Map<string, TimedValue<unknown>>();\n readonly #states = new Map<string, UserRallyState>();\n readonly #stocks: Map<string, number>;\n readonly #stockDefaults: Map<string, number>;\n readonly #claims = new Map<string, number>();\n readonly #claimRecords: UserClaimRecord[] = [];\n readonly #auditLogs: AuditLog[] = [];\n constructor(options: InMemoryServerPersistenceOptions = {}) {\n this.#stocks = new Map();\n this.#stockDefaults = new Map();\n for (const [key, stock] of Object.entries(options.stocks ?? {})) {\n if (key.includes(\":\")) this.#stocks.set(key, stock);\n else this.#stockDefaults.set(key, stock);\n }\n }\n #key(rallyId: string, key: string): string {\n return `${rallyId}:${key}`;\n }\n #stockKey(rallyId: string, rewardId: string): string {\n const scopedKey = `${rallyId}:${rewardId}`;\n if (this.#stocks.has(scopedKey)) return scopedKey;\n const defaultStock = this.#stockDefaults.get(rewardId);\n if (defaultStock !== undefined) {\n this.#stocks.set(scopedKey, defaultStock);\n return scopedKey;\n }\n return scopedKey;\n }\n async acquireLock(rallyId: string, key: string, ttlMs: number): Promise<boolean> {\n const scopedKey = this.#key(rallyId, key);\n const now = Date.now();\n const until = this.#locks.get(scopedKey);\n if (until !== undefined && until > now) return false;\n this.#locks.set(scopedKey, now + Math.max(1, ttlMs));\n return true;\n }\n async releaseLock(rallyId: string, key: string): Promise<void> {\n this.#locks.delete(this.#key(rallyId, key));\n }\n async getRewardStock(rallyId: string, rewardId: string): Promise<number | null> {\n return this.#stocks.get(this.#stockKey(rallyId, rewardId)) ?? null;\n }\n async decrementRewardStock(\n rallyId: string,\n rewardId: string,\n ): Promise<{ success: boolean; remainingStock: number }> {\n const key = this.#stockKey(rallyId, rewardId);\n const current = this.#stocks.get(key);\n if (current === undefined) return { success: true, remainingStock: Number.POSITIVE_INFINITY };\n if (current <= 0) return { success: false, remainingStock: 0 };\n this.#stocks.set(key, current - 1);\n return { success: true, remainingStock: current - 1 };\n }\n async restoreRewardStock(rallyId: string, rewardId: string, count = 1): Promise<void> {\n const key = this.#stockKey(rallyId, rewardId);\n const current = this.#stocks.get(key);\n if (current !== undefined) this.#stocks.set(key, current + Math.max(0, count));\n }\n\n async rollbackUserState(\n rallyId: string,\n userId: string,\n previousState: UserRallyState | null,\n ): Promise<void> {\n const key = `${rallyId}:${userId}`;\n if (previousState === null) this.#states.delete(key);\n else this.#states.set(key, structuredClone(previousState));\n }\n async getIdempotentResult<T>(rallyId: string, key: string): Promise<T | null> {\n const value = this.#idempotent.get(this.#key(rallyId, key));\n if (value === undefined || value.expiresAt <= Date.now()) {\n this.#idempotent.delete(this.#key(rallyId, key));\n return null;\n }\n return structuredClone(value.value) as T;\n }\n async saveIdempotentResult<T>(\n rallyId: string,\n key: string,\n result: T,\n ttlMs: number,\n ): Promise<void> {\n this.#idempotent.set(this.#key(rallyId, key), {\n value: structuredClone(result),\n expiresAt: Date.now() + Math.max(1, ttlMs),\n });\n }\n async getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number> {\n return this.#claims.get(`${rallyId}:${userId}:${rewardId}`) ?? 0;\n }\n async getUserState(rallyId: string, userId: string): Promise<UserRallyState | null> {\n const value = this.#states.get(`${rallyId}:${userId}`);\n return value === undefined ? null : structuredClone(value);\n }\n async saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void> {\n this.#states.set(`${rallyId}:${userId}`, structuredClone(state));\n }\n async recordAuditLog(log: AuditLog): Promise<void> {\n this.#auditLogs.push(structuredClone(log));\n }\n async removeAuditLog(auditId: string): Promise<void> {\n const index = this.#auditLogs.findIndex((log) => log.id === auditId);\n if (index >= 0) this.#auditLogs.splice(index, 1);\n }\n getAuditLogs(): ReadonlyArray<AuditLog> {\n return structuredClone(this.#auditLogs);\n }\n async recordUserClaim(params: UserClaimRecord): Promise<void> {\n const { rallyId, userId, rewardId } = params;\n const key = `${rallyId}:${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\n this.#claimRecords.push(structuredClone(params));\n }\n async rollbackUserClaim(\n rallyId: string,\n userId: string,\n rewardId: string,\n ticketNumber: string,\n ): Promise<void> {\n const key = `${rallyId}:${userId}:${rewardId}`;\n const count = this.#claims.get(key) ?? 0;\n if (count <= 1) this.#claims.delete(key);\n else this.#claims.set(key, count - 1);\n const index = this.#claimRecords.findIndex(\n (record) =>\n record.rallyId === rallyId &&\n record.userId === userId &&\n record.rewardId === rewardId &&\n record.ticketNumber === ticketNumber,\n );\n if (index >= 0) this.#claimRecords.splice(index, 1);\n }\n async incrementUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<void> {\n const key = `${rallyId}:${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\n }\n getClaimRecords(): ReadonlyArray<UserClaimRecord> {\n return structuredClone(this.#claimRecords);\n }\n /** @deprecated Use recordUserClaim with a ticket number and timestamp. */\n recordClaim(params: UserClaimRecord): Promise<void>;\n recordClaim(rallyId: string, userId: string, rewardId: string): Promise<void>;\n recordClaim(\n paramsOrRallyId: UserClaimRecord | string,\n userId?: string,\n rewardId?: string,\n ): Promise<void> {\n const params: UserClaimRecord =\n typeof paramsOrRallyId === \"string\"\n ? {\n rallyId: paramsOrRallyId,\n userId: userId ?? \"\",\n rewardId: rewardId ?? \"\",\n ticketNumber: \"\",\n timestamp: Date.now(),\n }\n : paramsOrRallyId;\n return this.recordUserClaim(params);\n }\n\n async runTransaction<T>(\n _rallyId: string,\n operation: (transaction: ServerPersistenceAdapter) => Promise<T>,\n ): Promise<T> {\n const snapshot = {\n stocks: new Map(this.#stocks),\n idempotent: new Map(this.#idempotent),\n states: new Map(this.#states),\n claims: new Map(this.#claims),\n claimRecords: structuredClone(this.#claimRecords),\n auditLogs: structuredClone(this.#auditLogs),\n };\n try {\n return await operation(this);\n } catch (error) {\n this.#stocks.clear();\n for (const [key, value] of snapshot.stocks) this.#stocks.set(key, value);\n this.#idempotent.clear();\n for (const [key, value] of snapshot.idempotent)\n this.#idempotent.set(key, structuredClone(value));\n this.#states.clear();\n for (const [key, value] of snapshot.states) this.#states.set(key, structuredClone(value));\n this.#claims.clear();\n for (const [key, value] of snapshot.claims) this.#claims.set(key, value);\n this.#claimRecords.splice(0, this.#claimRecords.length, ...snapshot.claimRecords);\n this.#auditLogs.splice(0, this.#auditLogs.length, ...snapshot.auditLogs);\n throw error;\n }\n }\n}\n","import {\n type AdminRallyConfig,\n type CheckInCondition,\n consumeReward,\n evaluateConditionDetailed,\n reconcileRewardStates,\n type UserRallyState,\n type Validator,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type {\n AuditLog,\n CheckInRequest,\n CheckInResponse,\n ClaimRewardRequest,\n ServerOptions,\n} from \"./index.js\";\nimport type { ServerPersistenceAdapter } from \"./persistence.js\";\n\ntype ErrorResponse = { readonly ok: false; readonly code: string; readonly message: string };\ntype ClaimResponse =\n | { readonly ok: true; readonly state: UserRallyState; readonly claimTicketNumber?: string }\n | ErrorResponse;\nfunction json(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json; charset=utf-8\" },\n });\n}\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction requestId(prefix: string): string {\n return `${prefix}-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;\n}\nfunction now(options: ServerOptions, requested?: string): string {\n return requested ?? options.now?.() ?? new Date().toISOString();\n}\nfunction initialState(config: AdminRallyConfig, userId: string, timestamp: string): UserRallyState {\n return {\n rallyId: config.id,\n userId,\n records: [],\n rewards: reconcileRewardStates(config.rewards, [], 0, timestamp),\n updatedAt: timestamp,\n };\n}\nfunction getProof(context: VerificationContext): unknown {\n return context.type === \"qr\"\n ? context.token\n : context.type === \"passcode\"\n ? context.code\n : context.type === \"gps\"\n ? { latitude: context.latitude, longitude: context.longitude }\n : context.type === \"nfc\"\n ? context.tagId\n : context.value;\n}\nasync function evaluate(\n condition: CheckInCondition,\n context: VerificationContext,\n validator: Validator | undefined,\n base: { rallyId: string; spotId: string; state: UserRallyState },\n): Promise<boolean> {\n if (condition.type !== \"custom\") return evaluateConditionDetailed(condition, context).ok;\n if (validator === undefined) return false;\n const validationContext = {\n rallyId: base.rallyId,\n spotId: base.spotId,\n proofData: getProof(context),\n condition,\n userState: base.state,\n };\n const result =\n typeof validator === \"function\"\n ? await validator(validationContext)\n : await validator.validate(validationContext);\n return result === true || (typeof result === \"object\" && result.valid);\n}\nfunction audit(\n rallyId: string,\n userId: string,\n action: AuditLog[\"action\"],\n resourceId: string,\n key: string,\n status: AuditLog[\"status\"],\n timestamp: string,\n code?: string,\n): AuditLog {\n return {\n id: requestId(\"audit\"),\n timestamp,\n rallyId,\n userId,\n action,\n resourceId,\n status,\n idempotencyKey: key,\n ...(code === undefined ? {} : { metadata: { errorCode: code } }),\n };\n}\n\nexport class StampRallyServer {\n readonly #config: AdminRallyConfig;\n readonly #persistence: ServerPersistenceAdapter;\n readonly #options: ServerOptions;\n constructor(\n config: AdminRallyConfig,\n persistence: ServerPersistenceAdapter,\n options: ServerOptions = {},\n ) {\n this.#config = config;\n this.#persistence = persistence;\n this.#options = options;\n }\n async handle(request: Request): Promise<Response> {\n if (request.method !== \"POST\")\n return json({ ok: false, code: \"METHOD_NOT_ALLOWED\", message: \"POST is required.\" }, 405);\n const path = new URL(request.url).pathname;\n if (path.endsWith(\"/check-in\")) return this.handleCheckIn(request);\n if (path.endsWith(\"/claim-reward\")) return this.handleClaimReward(request);\n if (path.endsWith(\"/sync\")) return this.handleSync(request);\n return json({ ok: false, code: \"NOT_FOUND\", message: \"Route not found.\" }, 404);\n }\n async handleCheckIn(request: Request): Promise<Response> {\n const body = await this.#body<CheckInRequest>(request);\n const userId = await this.#user(request, body?.userId);\n if (\n body === null ||\n userId === null ||\n body.rallyId !== this.#config.id ||\n body.spotId === \"\" ||\n body.idempotencyKey === \"\" ||\n body.context === undefined\n )\n return json(\n {\n ok: false,\n code: \"INVALID_REQUEST\",\n message: \"rallyId, spotId, context, and idempotencyKey are required.\",\n },\n 400,\n );\n const result = await this.checkIn({ ...body, userId });\n return json(result, result.ok ? 200 : result.code === \"SPOT_NOT_FOUND\" ? 404 : 422);\n }\n async handleClaimReward(request: Request): Promise<Response> {\n const body = await this.#body<ClaimRewardRequest>(request);\n const userId = await this.#user(request, body?.userId);\n if (\n body === null ||\n userId === null ||\n body.rallyId !== this.#config.id ||\n body.rewardId === \"\" ||\n body.idempotencyKey === \"\"\n )\n return json(\n {\n ok: false,\n code: \"INVALID_REQUEST\",\n message: \"rallyId, rewardId, and idempotencyKey are required.\",\n },\n 400,\n );\n const result = await this.claimReward({ ...body, userId });\n return json(result, result.ok ? 200 : result.code === \"REWARD_NOT_FOUND\" ? 404 : 422);\n }\n async handleSync(request: Request): Promise<Response> {\n const body = await this.#body<{ readonly rallyId: string; readonly userId?: string }>(request);\n const userId = await this.#user(request, body?.userId);\n if (body === null || userId === null || body.rallyId !== this.#config.id)\n return json({ ok: false, code: \"INVALID_REQUEST\", message: \"rallyId is required.\" }, 400);\n return json({ ok: true, state: await this.sync(body.rallyId, userId) });\n }\n async checkIn(request: CheckInRequest & { readonly userId: string }): Promise<CheckInResponse> {\n const key = `check-in:${request.rallyId}:${request.userId}:${request.idempotencyKey}`;\n const previous = await this.#persistence.getIdempotentResult<CheckInResponse>(\n request.rallyId,\n key,\n );\n if (previous !== null) return previous;\n const lockKey = `state:${request.rallyId}:${request.userId}`;\n if (\n !(await this.#persistence.acquireLock(\n request.rallyId,\n lockKey,\n this.#options.lockTtlMs ?? 5_000,\n ))\n )\n return { ok: false, code: \"CONFLICT\", message: \"The user state is being updated.\" };\n const timestamp = now(this.#options, request.now);\n try {\n const spot = this.#config.spots.find((item) => item.id === request.spotId);\n if (spot === undefined)\n return this.#remember(\n key,\n { ok: false, code: \"SPOT_NOT_FOUND\", message: \"Spot was not found.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const current =\n (await this.#persistence.getUserState(request.rallyId, request.userId)) ??\n initialState(this.#config, request.userId, timestamp);\n if (current.records.some((record) => record.stampId === request.spotId))\n return this.#remember(\n key,\n { ok: false, code: \"STAMP_ALREADY_ACQUIRED\", message: \"Spot was already claimed.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const acquired = new Set(current.records.map((record) => record.stampId));\n if (spot.prerequisites?.some((id) => !acquired.has(id)))\n return this.#remember(\n key,\n {\n ok: false,\n code: \"PREREQUISITES_NOT_MET\",\n message: \"Prerequisite spots are not complete.\",\n },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n for (const condition of spot.conditions)\n if (\n !(await evaluate(\n condition,\n request.context,\n condition.type === \"custom\"\n ? this.#options.customValidators?.[condition.validatorName]\n : undefined,\n { rallyId: request.rallyId, spotId: request.spotId, state: current },\n ))\n )\n return this.#remember(\n key,\n { ok: false, code: \"INVALID_PROOF\", message: \"Verification failed.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const next: UserRallyState = {\n ...current,\n records: [...current.records, { stampId: request.spotId, acquiredAt: timestamp }],\n rewards: reconcileRewardStates(\n this.#config.rewards,\n current.rewards,\n current.records.length + 1,\n timestamp,\n ),\n updatedAt: timestamp,\n };\n await this.#persistence.saveUserState(request.rallyId, request.userId, next);\n return this.#remember(\n key,\n { ok: true, state: next },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n } finally {\n await this.#persistence.releaseLock(request.rallyId, lockKey);\n }\n }\n async claimReward(\n request: ClaimRewardRequest & { readonly userId: string },\n ): Promise<ClaimResponse> {\n if (this.#persistence.runTransaction !== undefined)\n return this.#persistence.runTransaction(request.rallyId, (transaction) =>\n this.#claimRewardMutation(request, transaction),\n );\n return this.#claimRewardMutation(request, this.#persistence);\n }\n async #claimRewardMutation(\n request: ClaimRewardRequest & { readonly userId: string },\n persistence: ServerPersistenceAdapter,\n ): Promise<ClaimResponse> {\n const key = `claim:${request.rallyId}:${request.userId}:${request.rewardId}:${request.idempotencyKey}`;\n const previous = await persistence.getIdempotentResult<ClaimResponse>(request.rallyId, key);\n if (previous !== null) return previous;\n const reward = this.#config.rewards.find((item) => item.id === request.rewardId);\n if (reward === undefined)\n return this.#rememberClaim(\n key,\n { ok: false, code: \"REWARD_NOT_FOUND\", message: \"Reward was not found.\" },\n request,\n now(this.#options, request.now),\n persistence,\n );\n const lockKey = `reward:${request.rallyId}:${reward.id}`;\n if (\n !(await persistence.acquireLock(request.rallyId, lockKey, this.#options.lockTtlMs ?? 5_000))\n )\n return { ok: false, code: \"CONFLICT\", message: \"The reward is being claimed.\" };\n const timestamp = now(this.#options, request.now);\n let decremented = false;\n let previousState: UserRallyState | null = null;\n let recordedTicket: string | null = null;\n let successAuditId: string | null = null;\n try {\n const checked = await persistence.getIdempotentResult<ClaimResponse>(request.rallyId, key);\n if (checked !== null) return checked;\n const storedState = await persistence.getUserState(request.rallyId, request.userId);\n previousState = storedState;\n const current = storedState ?? initialState(this.#config, request.userId, timestamp);\n const claimCount = await persistence.getUserClaimCount(\n request.rallyId,\n request.userId,\n reward.id,\n );\n const storedReward = current.rewards.find((item) => item.rewardId === reward.id) ?? {\n rewardId: reward.id,\n status: \"LOCKED\" as const,\n };\n const currentReward =\n reward.redemptionMethod === \"server_claim\" &&\n storedReward.status === \"CONSUMED\" &&\n (reward.userClaimLimit === undefined || claimCount < reward.userClaimLimit)\n ? { ...storedReward, status: \"AVAILABLE\" as const }\n : storedReward;\n const local = consumeReward({\n reward,\n currentState: currentReward,\n now: timestamp,\n userRedemptionCount: claimCount,\n ...(request.staffPasscode === undefined ? {} : { inputPasscode: request.staffPasscode }),\n ...(request.staffId === undefined ? {} : { staffId: request.staffId }),\n });\n if (!local.ok)\n return this.#rememberClaim(\n key,\n { ok: false, code: local.error.code, message: \"Reward cannot be claimed.\" },\n request,\n timestamp,\n persistence,\n );\n const stock = await persistence.decrementRewardStock(request.rallyId, reward.id);\n if (!stock.success)\n return this.#rememberClaim(\n key,\n { ok: false, code: \"OUT_OF_STOCK\", message: \"Reward is out of stock.\" },\n request,\n timestamp,\n persistence,\n );\n decremented = true;\n const next: UserRallyState = {\n ...current,\n rewards: current.rewards.map((item) => (item.rewardId === reward.id ? local.value : item)),\n updatedAt: timestamp,\n };\n try {\n await persistence.saveUserState(request.rallyId, request.userId, next);\n const response: ClaimResponse =\n local.value.claimTicketNumber === undefined\n ? { ok: true, state: next }\n : { ok: true, state: next, claimTicketNumber: local.value.claimTicketNumber };\n recordedTicket = local.value.claimTicketNumber ?? \"\";\n await persistence.recordUserClaim({\n rallyId: request.rallyId,\n userId: request.userId,\n rewardId: reward.id,\n ticketNumber: recordedTicket,\n timestamp: Number.isNaN(Date.parse(timestamp)) ? Date.now() : Date.parse(timestamp),\n });\n const successAudit = audit(\n request.rallyId,\n request.userId,\n \"CLAIM_REWARD\",\n reward.id,\n request.idempotencyKey,\n \"SUCCESS\",\n timestamp,\n );\n successAuditId = successAudit.id;\n await persistence.recordAuditLog(successAudit);\n await persistence.saveIdempotentResult(\n request.rallyId,\n key,\n response,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return response;\n } catch (error) {\n if (recordedTicket !== null && persistence.rollbackUserClaim !== undefined)\n await persistence.rollbackUserClaim(\n request.rallyId,\n request.userId,\n reward.id,\n recordedTicket,\n );\n if (persistence.rollbackUserState !== undefined)\n await persistence.rollbackUserState(request.rallyId, request.userId, previousState);\n if (successAuditId !== null && persistence.removeAuditLog !== undefined)\n await persistence.removeAuditLog(successAuditId);\n await this.#restoreRewardStock(persistence, request.rallyId, reward.id);\n decremented = false;\n throw error;\n }\n } catch (error) {\n if (decremented) await this.#restoreRewardStock(persistence, request.rallyId, reward.id);\n return {\n ok: false,\n code: \"PERSISTENCE_FAILED\",\n message: error instanceof Error ? error.message : \"Reward claim failed.\",\n };\n } finally {\n await persistence.releaseLock(request.rallyId, lockKey);\n }\n }\n async sync(rallyId: string, userId: string): Promise<UserRallyState> {\n return (\n (await this.#persistence.getUserState(rallyId, userId)) ??\n initialState(this.#config, userId, now(this.#options))\n );\n }\n async #body<T>(request: Request): Promise<T | null> {\n try {\n const value: unknown = await request.json();\n return isObject(value) ? (value as T) : null;\n } catch {\n return null;\n }\n }\n async #user(request: Request, requested: string | undefined): Promise<string | null> {\n if (this.#options.authenticate !== undefined)\n return (await this.#options.authenticate(request)) ?? null;\n return requested ?? null;\n }\n async #remember(\n key: string,\n result: CheckInResponse,\n rallyId: string,\n userId: string,\n action: AuditLog[\"action\"],\n resourceId: string,\n idempotencyKey: string,\n timestamp: string,\n ): Promise<CheckInResponse> {\n await this.#persistence.recordAuditLog(\n audit(\n rallyId,\n userId,\n action,\n resourceId,\n idempotencyKey,\n result.ok ? \"SUCCESS\" : \"REJECTED\",\n timestamp,\n result.ok ? undefined : result.code,\n ),\n );\n await this.#persistence.saveIdempotentResult(\n rallyId,\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n async #rememberClaim(\n key: string,\n result: ClaimResponse,\n request: ClaimRewardRequest & { readonly userId: string },\n timestamp: string,\n persistence: ServerPersistenceAdapter = this.#persistence,\n ): Promise<ClaimResponse> {\n await persistence.recordAuditLog(\n audit(\n request.rallyId,\n request.userId,\n \"CLAIM_REWARD\",\n request.rewardId,\n request.idempotencyKey,\n \"REJECTED\",\n timestamp,\n result.ok ? undefined : result.code,\n ),\n );\n await persistence.saveIdempotentResult(\n request.rallyId,\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n async #restoreRewardStock(\n persistence: ServerPersistenceAdapter,\n rallyId: string,\n rewardId: string,\n ): Promise<void> {\n if (persistence.restoreRewardStock !== undefined)\n await persistence.restoreRewardStock(rallyId, rewardId);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/persistence.ts","../src/server.ts"],"names":["now"],"mappings":"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","file":"index.js","sourcesContent":["import type { UserRallyState } from \"@stamprally/core\";\nimport type { AuditLog } from \"./index.js\";\n\nexport interface UserClaimRecord {\n readonly rallyId: string;\n readonly userId: string;\n readonly rewardId: string;\n readonly ticketNumber: string;\n readonly timestamp: number;\n}\n\nexport interface ClaimRewardTransactionParams {\n readonly rallyId: string;\n readonly userId: string;\n readonly rewardId: string;\n readonly ticketNumber: string;\n readonly timestamp: number;\n readonly idempotencyKey?: string;\n readonly proofData?: unknown;\n readonly idempotencyTtlMs?: number;\n /** Used when the first claim is made before a user state has been stored. */\n readonly initialUserState?: UserRallyState;\n}\n\nexport interface ClaimRewardTransactionMutation {\n readonly nextStock: number | null;\n readonly nextUserState: UserRallyState;\n readonly auditLog: AuditLog;\n /** The server response is persisted by the adapter with the idempotency key. */\n readonly result?: unknown;\n /** A domain rejection is committed as an audit/idempotency record without mutations. */\n readonly error?: string;\n}\n\nexport interface ServerPersistenceAdapter {\n /**\n * Atomically commits stock, user state, claim count, audit log, and idempotency data.\n * Adapters must roll back every write when the callback or any commit operation fails.\n */\n executeClaimRewardTransaction(\n params: ClaimRewardTransactionParams,\n mutation: (current: {\n readonly stock: number | null;\n readonly claimCount: number;\n readonly userState: UserRallyState;\n }) => ClaimRewardTransactionMutation,\n ): Promise<{ readonly success: boolean; readonly error?: string }>;\n acquireLock(rallyId: string, lockKey: string, ttlMs: number): Promise<boolean>;\n releaseLock(rallyId: string, lockKey: string): Promise<void>;\n getRewardStock(rallyId: string, rewardId: string): Promise<number | null>;\n decrementRewardStock(\n rallyId: string,\n rewardId: string,\n ): Promise<{ readonly success: boolean; readonly remainingStock: number }>;\n getIdempotentResult<T>(rallyId: string, key: string): Promise<T | null>;\n saveIdempotentResult<T>(rallyId: string, key: string, result: T, ttlMs: number): Promise<void>;\n getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number>;\n recordUserClaim(params: UserClaimRecord): Promise<void>;\n recordClaim?(params: UserClaimRecord): Promise<void>;\n incrementUserClaimCount?(rallyId: string, userId: string, rewardId: string): Promise<void>;\n getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;\n saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void>;\n recordAuditLog(log: AuditLog): Promise<void>;\n removeAuditLog?(auditId: string): Promise<void>;\n}\ninterface TimedValue<T> {\n readonly value: T;\n readonly expiresAt: number;\n}\nexport interface InMemoryServerPersistenceOptions {\n readonly stocks?: Readonly<Record<string, number>>;\n}\nexport class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapter {\n readonly #locks = new Map<string, number>();\n readonly #idempotent = new Map<string, TimedValue<unknown>>();\n readonly #states = new Map<string, UserRallyState>();\n readonly #stocks: Map<string, number>;\n readonly #stockDefaults: Map<string, number>;\n readonly #claims = new Map<string, number>();\n readonly #claimRecords: UserClaimRecord[] = [];\n readonly #auditLogs: AuditLog[] = [];\n constructor(options: InMemoryServerPersistenceOptions = {}) {\n this.#stocks = new Map();\n this.#stockDefaults = new Map();\n for (const [key, stock] of Object.entries(options.stocks ?? {})) {\n if (key.includes(\":\")) this.#stocks.set(key, stock);\n else this.#stockDefaults.set(key, stock);\n }\n }\n #key(rallyId: string, key: string): string {\n return `${rallyId}:${key}`;\n }\n #stockKey(rallyId: string, rewardId: string): string {\n const scopedKey = `${rallyId}:${rewardId}`;\n if (this.#stocks.has(scopedKey)) return scopedKey;\n const defaultStock = this.#stockDefaults.get(rewardId);\n if (defaultStock !== undefined) {\n this.#stocks.set(scopedKey, defaultStock);\n return scopedKey;\n }\n return scopedKey;\n }\n async acquireLock(rallyId: string, key: string, ttlMs: number): Promise<boolean> {\n const scopedKey = this.#key(rallyId, key);\n const now = Date.now();\n const until = this.#locks.get(scopedKey);\n if (until !== undefined && until > now) return false;\n this.#locks.set(scopedKey, now + Math.max(1, ttlMs));\n return true;\n }\n async releaseLock(rallyId: string, key: string): Promise<void> {\n this.#locks.delete(this.#key(rallyId, key));\n }\n async getRewardStock(rallyId: string, rewardId: string): Promise<number | null> {\n return this.#stocks.get(this.#stockKey(rallyId, rewardId)) ?? null;\n }\n async decrementRewardStock(\n rallyId: string,\n rewardId: string,\n ): Promise<{ success: boolean; remainingStock: number }> {\n const key = this.#stockKey(rallyId, rewardId);\n const current = this.#stocks.get(key);\n if (current === undefined) return { success: true, remainingStock: Number.POSITIVE_INFINITY };\n if (current <= 0) return { success: false, remainingStock: 0 };\n this.#stocks.set(key, current - 1);\n return { success: true, remainingStock: current - 1 };\n }\n async restoreRewardStock(rallyId: string, rewardId: string, count = 1): Promise<void> {\n const key = this.#stockKey(rallyId, rewardId);\n const current = this.#stocks.get(key);\n if (current !== undefined) this.#stocks.set(key, current + Math.max(0, count));\n }\n\n async executeClaimRewardTransaction(\n params: ClaimRewardTransactionParams,\n mutation: (current: {\n readonly stock: number | null;\n readonly claimCount: number;\n readonly userState: UserRallyState;\n }) => ClaimRewardTransactionMutation,\n ): Promise<{ readonly success: boolean; readonly error?: string }> {\n try {\n return await this.runTransaction(params.rallyId, async () => {\n const userState =\n (await this.getUserState(params.rallyId, params.userId)) ?? params.initialUserState;\n if (userState === undefined)\n return { success: false, error: \"A user state is required for this transaction.\" };\n const mutationResult = mutation({\n stock: await this.getRewardStock(params.rallyId, params.rewardId),\n claimCount: await this.getUserClaimCount(params.rallyId, params.userId, params.rewardId),\n userState,\n });\n const idempotencyKey = params.idempotencyKey;\n if (mutationResult.error !== undefined) {\n await this.recordAuditLog(mutationResult.auditLog);\n if (idempotencyKey !== undefined && mutationResult.result !== undefined)\n await this.saveIdempotentResult(\n params.rallyId,\n idempotencyKey,\n mutationResult.result,\n params.idempotencyTtlMs ?? 86_400_000,\n );\n return { success: false, error: mutationResult.error };\n }\n const currentStock = await this.getRewardStock(params.rallyId, params.rewardId);\n if (\n currentStock !== null &&\n (mutationResult.nextStock === null || mutationResult.nextStock < 0)\n )\n throw new Error(\"The transaction produced an invalid stock value.\");\n if (currentStock === null && mutationResult.nextStock !== null)\n throw new Error(\"The transaction changed an unlimited stock to a limited stock.\");\n if (mutationResult.nextStock !== null)\n this.#stocks.set(\n this.#stockKey(params.rallyId, params.rewardId),\n mutationResult.nextStock,\n );\n await this.saveUserState(params.rallyId, params.userId, mutationResult.nextUserState);\n const reward = mutationResult.nextUserState.rewards.find(\n (item) => item.rewardId === params.rewardId,\n );\n if (reward?.claimTicketNumber !== undefined)\n await this.recordUserClaim({\n rallyId: params.rallyId,\n userId: params.userId,\n rewardId: params.rewardId,\n ticketNumber: reward.claimTicketNumber,\n timestamp: params.timestamp,\n });\n await this.recordAuditLog(mutationResult.auditLog);\n if (idempotencyKey !== undefined && mutationResult.result !== undefined)\n await this.saveIdempotentResult(\n params.rallyId,\n idempotencyKey,\n mutationResult.result,\n params.idempotencyTtlMs ?? 86_400_000,\n );\n return { success: true };\n });\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n }\n\n async rollbackUserState(\n rallyId: string,\n userId: string,\n previousState: UserRallyState | null,\n ): Promise<void> {\n const key = `${rallyId}:${userId}`;\n if (previousState === null) this.#states.delete(key);\n else this.#states.set(key, structuredClone(previousState));\n }\n async getIdempotentResult<T>(rallyId: string, key: string): Promise<T | null> {\n const value = this.#idempotent.get(this.#key(rallyId, key));\n if (value === undefined || value.expiresAt <= Date.now()) {\n this.#idempotent.delete(this.#key(rallyId, key));\n return null;\n }\n return structuredClone(value.value) as T;\n }\n async saveIdempotentResult<T>(\n rallyId: string,\n key: string,\n result: T,\n ttlMs: number,\n ): Promise<void> {\n this.#idempotent.set(this.#key(rallyId, key), {\n value: structuredClone(result),\n expiresAt: Date.now() + Math.max(1, ttlMs),\n });\n }\n async getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number> {\n return this.#claims.get(`${rallyId}:${userId}:${rewardId}`) ?? 0;\n }\n async getUserState(rallyId: string, userId: string): Promise<UserRallyState | null> {\n const value = this.#states.get(`${rallyId}:${userId}`);\n return value === undefined ? null : structuredClone(value);\n }\n async saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void> {\n this.#states.set(`${rallyId}:${userId}`, structuredClone(state));\n }\n async recordAuditLog(log: AuditLog): Promise<void> {\n this.#auditLogs.push(structuredClone(log));\n }\n async removeAuditLog(auditId: string): Promise<void> {\n const index = this.#auditLogs.findIndex((log) => log.id === auditId);\n if (index >= 0) this.#auditLogs.splice(index, 1);\n }\n getAuditLogs(): ReadonlyArray<AuditLog> {\n return structuredClone(this.#auditLogs);\n }\n async recordUserClaim(params: UserClaimRecord): Promise<void> {\n const { rallyId, userId, rewardId } = params;\n const key = `${rallyId}:${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\n this.#claimRecords.push(structuredClone(params));\n }\n async rollbackUserClaim(\n rallyId: string,\n userId: string,\n rewardId: string,\n ticketNumber: string,\n ): Promise<void> {\n const key = `${rallyId}:${userId}:${rewardId}`;\n const count = this.#claims.get(key) ?? 0;\n if (count <= 1) this.#claims.delete(key);\n else this.#claims.set(key, count - 1);\n const index = this.#claimRecords.findIndex(\n (record) =>\n record.rallyId === rallyId &&\n record.userId === userId &&\n record.rewardId === rewardId &&\n record.ticketNumber === ticketNumber,\n );\n if (index >= 0) this.#claimRecords.splice(index, 1);\n }\n async incrementUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<void> {\n const key = `${rallyId}:${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\n }\n getClaimRecords(): ReadonlyArray<UserClaimRecord> {\n return structuredClone(this.#claimRecords);\n }\n /** @deprecated Use recordUserClaim with a ticket number and timestamp. */\n recordClaim(params: UserClaimRecord): Promise<void>;\n recordClaim(rallyId: string, userId: string, rewardId: string): Promise<void>;\n recordClaim(\n paramsOrRallyId: UserClaimRecord | string,\n userId?: string,\n rewardId?: string,\n ): Promise<void> {\n const params: UserClaimRecord =\n typeof paramsOrRallyId === \"string\"\n ? {\n rallyId: paramsOrRallyId,\n userId: userId ?? \"\",\n rewardId: rewardId ?? \"\",\n ticketNumber: \"\",\n timestamp: Date.now(),\n }\n : paramsOrRallyId;\n return this.recordUserClaim(params);\n }\n\n async runTransaction<T>(\n _rallyId: string,\n operation: (transaction: ServerPersistenceAdapter) => Promise<T>,\n ): Promise<T> {\n const snapshot = {\n stocks: new Map(this.#stocks),\n idempotent: new Map(this.#idempotent),\n states: new Map(this.#states),\n claims: new Map(this.#claims),\n claimRecords: structuredClone(this.#claimRecords),\n auditLogs: structuredClone(this.#auditLogs),\n };\n try {\n return await operation(this);\n } catch (error) {\n this.#stocks.clear();\n for (const [key, value] of snapshot.stocks) this.#stocks.set(key, value);\n this.#idempotent.clear();\n for (const [key, value] of snapshot.idempotent)\n this.#idempotent.set(key, structuredClone(value));\n this.#states.clear();\n for (const [key, value] of snapshot.states) this.#states.set(key, structuredClone(value));\n this.#claims.clear();\n for (const [key, value] of snapshot.claims) this.#claims.set(key, value);\n this.#claimRecords.splice(0, this.#claimRecords.length, ...snapshot.claimRecords);\n this.#auditLogs.splice(0, this.#auditLogs.length, ...snapshot.auditLogs);\n throw error;\n }\n }\n}\n","import {\n type AdminRallyConfig,\n type CheckInCondition,\n consumeReward,\n evaluateConditionDetailed,\n reconcileRewardStates,\n type UserRallyState,\n type Validator,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type {\n AuditLog,\n CheckInRequest,\n CheckInResponse,\n ClaimRewardRequest,\n ServerOptions,\n} from \"./index.js\";\nimport type { ServerPersistenceAdapter } from \"./persistence.js\";\n\ntype ErrorResponse = { readonly ok: false; readonly code: string; readonly message: string };\ntype ClaimResponse =\n | { readonly ok: true; readonly state: UserRallyState; readonly claimTicketNumber?: string }\n | ErrorResponse;\nfunction json(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json; charset=utf-8\" },\n });\n}\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction requestId(prefix: string): string {\n return `${prefix}-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;\n}\nfunction now(options: ServerOptions, requested?: string): string {\n return requested ?? options.now?.() ?? new Date().toISOString();\n}\nfunction initialState(config: AdminRallyConfig, userId: string, timestamp: string): UserRallyState {\n return {\n rallyId: config.id,\n userId,\n records: [],\n rewards: reconcileRewardStates(config.rewards, [], 0, timestamp),\n updatedAt: timestamp,\n };\n}\nfunction getProof(context: VerificationContext): unknown {\n return context.type === \"qr\"\n ? context.token\n : context.type === \"passcode\"\n ? context.code\n : context.type === \"gps\"\n ? { latitude: context.latitude, longitude: context.longitude }\n : context.type === \"nfc\"\n ? context.tagId\n : context.value;\n}\nasync function evaluate(\n condition: CheckInCondition,\n context: VerificationContext,\n validator: Validator | undefined,\n base: { rallyId: string; spotId: string; state: UserRallyState },\n): Promise<boolean> {\n if (condition.type !== \"custom\") return evaluateConditionDetailed(condition, context).ok;\n if (validator === undefined) return false;\n const validationContext = {\n rallyId: base.rallyId,\n spotId: base.spotId,\n proofData: getProof(context),\n condition,\n userState: base.state,\n };\n const result =\n typeof validator === \"function\"\n ? await validator(validationContext)\n : await validator.validate(validationContext);\n return result === true || (typeof result === \"object\" && result.valid);\n}\nfunction audit(\n rallyId: string,\n userId: string,\n action: AuditLog[\"action\"],\n resourceId: string,\n key: string,\n status: AuditLog[\"status\"],\n timestamp: string,\n code?: string,\n): AuditLog {\n return {\n id: requestId(\"audit\"),\n timestamp,\n rallyId,\n userId,\n action,\n resourceId,\n status,\n idempotencyKey: key,\n ...(code === undefined ? {} : { metadata: { errorCode: code } }),\n };\n}\n\nexport class StampRallyServer {\n readonly #config: AdminRallyConfig;\n readonly #persistence: ServerPersistenceAdapter;\n readonly #options: ServerOptions;\n constructor(\n config: AdminRallyConfig,\n persistence: ServerPersistenceAdapter,\n options: ServerOptions = {},\n ) {\n this.#config = config;\n this.#persistence = persistence;\n this.#options = options;\n }\n async handle(request: Request): Promise<Response> {\n if (request.method !== \"POST\")\n return json({ ok: false, code: \"METHOD_NOT_ALLOWED\", message: \"POST is required.\" }, 405);\n const path = new URL(request.url).pathname;\n if (path.endsWith(\"/check-in\")) return this.handleCheckIn(request);\n if (path.endsWith(\"/claim-reward\")) return this.handleClaimReward(request);\n if (path.endsWith(\"/sync\")) return this.handleSync(request);\n return json({ ok: false, code: \"NOT_FOUND\", message: \"Route not found.\" }, 404);\n }\n async handleCheckIn(request: Request): Promise<Response> {\n const body = await this.#body<CheckInRequest>(request);\n const userId = await this.#user(request, body?.userId);\n if (\n body === null ||\n userId === null ||\n body.rallyId !== this.#config.id ||\n body.spotId === \"\" ||\n body.idempotencyKey === \"\" ||\n body.context === undefined\n )\n return json(\n {\n ok: false,\n code: \"INVALID_REQUEST\",\n message: \"rallyId, spotId, context, and idempotencyKey are required.\",\n },\n 400,\n );\n const result = await this.checkIn({ ...body, userId });\n return json(result, result.ok ? 200 : result.code === \"SPOT_NOT_FOUND\" ? 404 : 422);\n }\n async handleClaimReward(request: Request): Promise<Response> {\n const body = await this.#body<ClaimRewardRequest>(request);\n const userId = await this.#user(request, body?.userId);\n if (\n body === null ||\n userId === null ||\n body.rallyId !== this.#config.id ||\n body.rewardId === \"\" ||\n body.idempotencyKey === \"\"\n )\n return json(\n {\n ok: false,\n code: \"INVALID_REQUEST\",\n message: \"rallyId, rewardId, and idempotencyKey are required.\",\n },\n 400,\n );\n const result = await this.claimReward({ ...body, userId });\n return json(result, result.ok ? 200 : result.code === \"REWARD_NOT_FOUND\" ? 404 : 422);\n }\n async handleSync(request: Request): Promise<Response> {\n const body = await this.#body<{ readonly rallyId: string; readonly userId?: string }>(request);\n const userId = await this.#user(request, body?.userId);\n if (body === null || userId === null || body.rallyId !== this.#config.id)\n return json({ ok: false, code: \"INVALID_REQUEST\", message: \"rallyId is required.\" }, 400);\n return json({ ok: true, state: await this.sync(body.rallyId, userId) });\n }\n async checkIn(request: CheckInRequest & { readonly userId: string }): Promise<CheckInResponse> {\n const key = `check-in:${request.rallyId}:${request.userId}:${request.idempotencyKey}`;\n const previous = await this.#persistence.getIdempotentResult<CheckInResponse>(\n request.rallyId,\n key,\n );\n if (previous !== null) return previous;\n const lockKey = `state:${request.rallyId}:${request.userId}`;\n if (\n !(await this.#persistence.acquireLock(\n request.rallyId,\n lockKey,\n this.#options.lockTtlMs ?? 5_000,\n ))\n )\n return { ok: false, code: \"CONFLICT\", message: \"The user state is being updated.\" };\n const timestamp = now(this.#options, request.now);\n try {\n const spot = this.#config.spots.find((item) => item.id === request.spotId);\n if (spot === undefined)\n return this.#remember(\n key,\n { ok: false, code: \"SPOT_NOT_FOUND\", message: \"Spot was not found.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const current =\n (await this.#persistence.getUserState(request.rallyId, request.userId)) ??\n initialState(this.#config, request.userId, timestamp);\n if (current.records.some((record) => record.stampId === request.spotId))\n return this.#remember(\n key,\n { ok: false, code: \"STAMP_ALREADY_ACQUIRED\", message: \"Spot was already claimed.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const acquired = new Set(current.records.map((record) => record.stampId));\n if (spot.prerequisites?.some((id) => !acquired.has(id)))\n return this.#remember(\n key,\n {\n ok: false,\n code: \"PREREQUISITES_NOT_MET\",\n message: \"Prerequisite spots are not complete.\",\n },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n for (const condition of spot.conditions)\n if (\n !(await evaluate(\n condition,\n request.context,\n condition.type === \"custom\"\n ? this.#options.customValidators?.[condition.validatorName]\n : undefined,\n { rallyId: request.rallyId, spotId: request.spotId, state: current },\n ))\n )\n return this.#remember(\n key,\n { ok: false, code: \"INVALID_PROOF\", message: \"Verification failed.\" },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n const next: UserRallyState = {\n ...current,\n records: [...current.records, { stampId: request.spotId, acquiredAt: timestamp }],\n rewards: reconcileRewardStates(\n this.#config.rewards,\n current.rewards,\n current.records.length + 1,\n timestamp,\n ),\n updatedAt: timestamp,\n };\n await this.#persistence.saveUserState(request.rallyId, request.userId, next);\n return this.#remember(\n key,\n { ok: true, state: next },\n request.rallyId,\n request.userId,\n \"CHECK_IN\",\n request.spotId,\n request.idempotencyKey,\n timestamp,\n );\n } finally {\n await this.#persistence.releaseLock(request.rallyId, lockKey);\n }\n }\n async claimReward(\n request: ClaimRewardRequest & { readonly userId: string },\n ): Promise<ClaimResponse> {\n const key = `claim:${request.rallyId}:${request.userId}:${request.rewardId}:${request.idempotencyKey}`;\n const previous = await this.#persistence.getIdempotentResult<ClaimResponse>(\n request.rallyId,\n key,\n );\n if (previous !== null) return previous;\n const reward = this.#config.rewards.find((item) => item.id === request.rewardId);\n if (reward === undefined)\n return this.#rememberClaim(\n key,\n { ok: false, code: \"REWARD_NOT_FOUND\", message: \"Reward was not found.\" },\n request,\n now(this.#options, request.now),\n );\n const lockKey = `reward:${request.rallyId}:${reward.id}`;\n if (\n !(await this.#persistence.acquireLock(\n request.rallyId,\n lockKey,\n this.#options.lockTtlMs ?? 5_000,\n ))\n )\n return { ok: false, code: \"CONFLICT\", message: \"The reward is being claimed.\" };\n const timestamp = now(this.#options, request.now);\n try {\n const checked = await this.#persistence.getIdempotentResult<ClaimResponse>(\n request.rallyId,\n key,\n );\n if (checked !== null) return checked;\n const responseHolder: { value: ClaimResponse | null } = { value: null };\n const result = await this.#persistence.executeClaimRewardTransaction(\n {\n rallyId: request.rallyId,\n userId: request.userId,\n rewardId: reward.id,\n ticketNumber: request.idempotencyKey,\n timestamp: Number.isNaN(Date.parse(timestamp)) ? Date.now() : Date.parse(timestamp),\n idempotencyKey: key,\n ...(request.staffPasscode === undefined ? {} : { proofData: request.staffPasscode }),\n ...(this.#options.idempotencyTtlMs === undefined\n ? {}\n : { idempotencyTtlMs: this.#options.idempotencyTtlMs }),\n initialUserState: initialState(this.#config, request.userId, timestamp),\n },\n ({ stock, claimCount, userState }) => {\n const storedReward = userState.rewards.find((item) => item.rewardId === reward.id) ?? {\n rewardId: reward.id,\n status: \"LOCKED\" as const,\n };\n const currentReward =\n reward.redemptionMethod === \"server_claim\" &&\n storedReward.status === \"CONSUMED\" &&\n (reward.userClaimLimit === undefined || claimCount < reward.userClaimLimit)\n ? { ...storedReward, status: \"AVAILABLE\" as const }\n : storedReward;\n const makeAudit = (status: \"SUCCESS\" | \"REJECTED\", code?: string): AuditLog =>\n audit(\n request.rallyId,\n request.userId,\n \"CLAIM_REWARD\",\n reward.id,\n request.idempotencyKey,\n status,\n timestamp,\n code,\n );\n if (stock !== null && stock <= 0) {\n responseHolder.value = {\n ok: false,\n code: \"OUT_OF_STOCK\",\n message: \"Reward is out of stock.\",\n };\n return {\n nextStock: stock,\n nextUserState: userState,\n auditLog: makeAudit(\"REJECTED\", \"OUT_OF_STOCK\"),\n result: responseHolder.value,\n error: \"OUT_OF_STOCK\",\n };\n }\n const local = consumeReward({\n reward,\n currentState: currentReward,\n now: timestamp,\n userRedemptionCount: claimCount,\n ...(request.staffPasscode === undefined\n ? {}\n : { inputPasscode: request.staffPasscode }),\n ...(request.staffId === undefined ? {} : { staffId: request.staffId }),\n });\n if (!local.ok) {\n responseHolder.value = {\n ok: false,\n code: local.error.code,\n message: \"Reward cannot be claimed.\",\n };\n return {\n nextStock: stock,\n nextUserState: userState,\n auditLog: makeAudit(\"REJECTED\", local.error.code),\n result: responseHolder.value,\n error: local.error.code,\n };\n }\n const nextRewards = userState.rewards.some((item) => item.rewardId === reward.id)\n ? userState.rewards.map((item) => (item.rewardId === reward.id ? local.value : item))\n : [...userState.rewards, local.value];\n const next: UserRallyState = {\n ...userState,\n rewards: nextRewards,\n updatedAt: timestamp,\n };\n responseHolder.value =\n local.value.claimTicketNumber === undefined\n ? { ok: true, state: next }\n : { ok: true, state: next, claimTicketNumber: local.value.claimTicketNumber };\n return {\n nextStock: stock === null ? null : stock - 1,\n nextUserState: next,\n auditLog: makeAudit(\"SUCCESS\"),\n result: responseHolder.value,\n };\n },\n );\n const response = responseHolder.value;\n if (!result.success) {\n if (response !== null && !response.ok && response.code === result.error) return response;\n return {\n ok: false,\n code: \"PERSISTENCE_FAILED\",\n message: result.error ?? \"Reward claim failed.\",\n };\n }\n if (response !== null && result.success) return response;\n return {\n ok: false,\n code: \"PERSISTENCE_FAILED\",\n message: result.error ?? \"Reward claim failed.\",\n };\n } catch (error) {\n return {\n ok: false,\n code: \"PERSISTENCE_FAILED\",\n message: error instanceof Error ? error.message : \"Reward claim failed.\",\n };\n } finally {\n await this.#persistence.releaseLock(request.rallyId, lockKey);\n }\n }\n async sync(rallyId: string, userId: string): Promise<UserRallyState> {\n return (\n (await this.#persistence.getUserState(rallyId, userId)) ??\n initialState(this.#config, userId, now(this.#options))\n );\n }\n async #body<T>(request: Request): Promise<T | null> {\n try {\n const value: unknown = await request.json();\n return isObject(value) ? (value as T) : null;\n } catch {\n return null;\n }\n }\n async #user(request: Request, requested: string | undefined): Promise<string | null> {\n if (this.#options.authenticate !== undefined)\n return (await this.#options.authenticate(request)) ?? null;\n return requested ?? null;\n }\n async #remember(\n key: string,\n result: CheckInResponse,\n rallyId: string,\n userId: string,\n action: AuditLog[\"action\"],\n resourceId: string,\n idempotencyKey: string,\n timestamp: string,\n ): Promise<CheckInResponse> {\n await this.#persistence.recordAuditLog(\n audit(\n rallyId,\n userId,\n action,\n resourceId,\n idempotencyKey,\n result.ok ? \"SUCCESS\" : \"REJECTED\",\n timestamp,\n result.ok ? undefined : result.code,\n ),\n );\n await this.#persistence.saveIdempotentResult(\n rallyId,\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n async #rememberClaim(\n key: string,\n result: ClaimResponse,\n request: ClaimRewardRequest & { readonly userId: string },\n timestamp: string,\n ): Promise<ClaimResponse> {\n await this.#persistence.recordAuditLog(\n audit(\n request.rallyId,\n request.userId,\n \"CLAIM_REWARD\",\n request.rewardId,\n request.idempotencyKey,\n \"REJECTED\",\n timestamp,\n result.ok ? undefined : result.code,\n ),\n );\n await this.#persistence.saveIdempotentResult(\n request.rallyId,\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamprally/server",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Web Standard server handlers for stamp rally verification and claims.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@stamprally/core": "0.11.0"
31
+ "@stamprally/core": "0.12.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsup": "^8.5.1",