@stamprally/server 0.8.0 → 0.9.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.cjs +288 -625
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -131
- package/dist/index.d.ts +58 -131
- package/dist/index.js +290 -625
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/persistence.ts","../src/universalServer.ts","../src/index.ts"],"names":["now","reconcileRewardStates","consumeReward","id","processStamp","createSecureToken"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { RallyAuditLog, UserRallyState } from \"./index.js\";\n\n/** Persistence contract for implementations backed by Redis, SQL, or another RDB. */\nexport interface ServerPersistenceAdapter {\n acquireLock(lockKey: string, ttlMs: number): Promise<boolean>;\n releaseLock(lockKey: string): Promise<void>;\n decrementRewardStock(rewardId: string): Promise<{ success: boolean; remainingStock: number }>;\n getIdempotentResult<T>(idempotencyKey: string): Promise<T | null>;\n saveIdempotentResult<T>(idempotencyKey: string, result: T, ttlMs: number): Promise<void>;\n getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;\n saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void>;\n recordAuditLog(log: RallyAuditLog): Promise<void>;\n}\n\ninterface TimedValue<T> {\n readonly value: T;\n readonly expiresAt: number;\n}\n\nexport interface InMemoryServerPersistenceOptions {\n readonly stocks?: Readonly<Record<string, number>>;\n}\n\n/** Deterministic adapter for tests and small single-process deployments. */\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 #auditLogs: RallyAuditLog[] = [];\n\n constructor(options: InMemoryServerPersistenceOptions = {}) {\n this.#stocks = new Map(Object.entries(options.stocks ?? {}));\n }\n\n async acquireLock(lockKey: string, ttlMs: number): Promise<boolean> {\n const now = Date.now();\n const expiresAt = this.#locks.get(lockKey);\n if (expiresAt !== undefined && expiresAt > now) return false;\n this.#locks.set(lockKey, now + Math.max(1, ttlMs));\n return true;\n }\n\n async releaseLock(lockKey: string): Promise<void> {\n this.#locks.delete(lockKey);\n }\n\n async decrementRewardStock(\n rewardId: string,\n ): Promise<{ success: boolean; remainingStock: number }> {\n const stock = this.#stocks.get(rewardId);\n if (stock === undefined) return { success: true, remainingStock: Number.POSITIVE_INFINITY };\n if (stock <= 0) return { success: false, remainingStock: 0 };\n const remainingStock = stock - 1;\n this.#stocks.set(rewardId, remainingStock);\n return { success: true, remainingStock };\n }\n\n async getIdempotentResult<T>(idempotencyKey: string): Promise<T | null> {\n const entry = this.#idempotent.get(idempotencyKey);\n if (entry === undefined) return null;\n if (entry.expiresAt <= Date.now()) {\n this.#idempotent.delete(idempotencyKey);\n return null;\n }\n return structuredClone(entry.value) as T;\n }\n\n async saveIdempotentResult<T>(idempotencyKey: string, result: T, ttlMs: number): Promise<void> {\n this.#idempotent.set(idempotencyKey, {\n value: structuredClone(result),\n expiresAt: Date.now() + Math.max(1, ttlMs),\n });\n }\n\n async getUserState(rallyId: string, userId: string): Promise<UserRallyState | null> {\n const state = this.#states.get(`${rallyId}:${userId}`);\n return state === undefined ? null : structuredClone(state);\n }\n\n async saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void> {\n this.#states.set(`${rallyId}:${userId}`, structuredClone(state));\n }\n\n async recordAuditLog(log: RallyAuditLog): Promise<void> {\n this.#auditLogs.push(structuredClone(log));\n }\n\n getAuditLogs(): ReadonlyArray<RallyAuditLog> {\n return structuredClone(this.#auditLogs);\n }\n}\n","import {\n type AdminRallyConfig,\n type AdminReward,\n consumeReward,\n type RewardItem,\n reconcileRewardStates,\n type StampRallyState,\n type VerificationCondition,\n} from \"@stamprally/core\";\nimport type { RallyAuditLog, UserRallyState } from \"./index.js\";\nimport type { ServerPersistenceAdapter } from \"./persistence.js\";\n\nexport type UniversalVerificationContext =\n | { readonly type: \"qr\"; readonly token: string }\n | { readonly type: \"passcode\"; readonly code: string }\n | { readonly type: \"gps\"; readonly latitude: number; readonly longitude: number }\n | { readonly type: \"custom\"; readonly value: unknown };\n\nexport interface UniversalCheckInRequest {\n readonly rallyId: string;\n readonly userId: string;\n readonly spotId: string;\n readonly context: UniversalVerificationContext;\n readonly idempotencyKey: string;\n readonly now?: string;\n}\n\nexport interface UniversalClaimRewardRequest {\n readonly rallyId: string;\n readonly userId: string;\n readonly rewardId: string;\n readonly idempotencyKey: string;\n readonly staffPasscode?: string;\n readonly staffId?: string;\n readonly now?: string;\n}\n\nexport type UniversalCheckInResult =\n | { readonly ok: true; readonly state: UserRallyState }\n | { readonly ok: false; readonly code: string; readonly message: string };\n\nexport interface UniversalRallyServerOptions {\n readonly idempotencyTtlMs?: number;\n readonly lockTtlMs?: number;\n readonly customValidators?: Readonly<\n Record<string, (value: unknown, condition: VerificationCondition) => boolean>\n >;\n readonly now?: () => string;\n /** Extract the authenticated identity; request-body userId is never trusted when this is set. */\n readonly authenticate?: (request: Request) => Promise<string | null> | string | null;\n}\n\nfunction distanceMeters(aLat: number, aLon: number, bLat: number, bLon: number): number {\n const radians = (degrees: number): number => (degrees * Math.PI) / 180;\n const dLat = radians(bLat - aLat);\n const dLon = radians(bLon - aLon);\n const latA = radians(aLat);\n const latB = radians(bLat);\n const value = Math.sin(dLat / 2) ** 2 + Math.cos(latA) * Math.cos(latB) * Math.sin(dLon / 2) ** 2;\n return 6_371_000 * 2 * Math.asin(Math.sqrt(Math.min(1, value)));\n}\n\nfunction initialState(config: AdminRallyConfig, now: string): UserRallyState {\n return {\n rallyId: config.id,\n records: [],\n rewards: reconcileRewardStates(\n config.rewards.map((reward) => ({ ...reward, description: reward.description ?? \"\" })),\n [],\n 0,\n now,\n ),\n updatedAt: now,\n };\n}\n\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}\n\nfunction requestBody<T>(request: Request): Promise<T | null> {\n return request\n .json()\n .then((value: unknown) => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n return value as T;\n })\n .catch(() => null);\n}\n\nfunction adminReward(reward: AdminReward): RewardItem {\n return { ...reward, description: reward.description ?? \"\" };\n}\n\nfunction matchesCondition(\n condition: VerificationCondition,\n context: UniversalVerificationContext,\n customValidators: UniversalRallyServerOptions[\"customValidators\"],\n): boolean {\n switch (condition.type) {\n case \"qr\":\n return context.type === \"qr\" && context.token === condition.secretToken;\n case \"passcode\":\n return (\n context.type === \"passcode\" &&\n (condition.caseSensitive === false\n ? context.code.toLocaleLowerCase() === condition.code.toLocaleLowerCase()\n : context.code === condition.code)\n );\n case \"gps\":\n return (\n context.type === \"gps\" &&\n distanceMeters(\n condition.latitude,\n condition.longitude,\n context.latitude,\n context.longitude,\n ) <= condition.radiusMeters\n );\n case \"custom\":\n return (\n customValidators?.[condition.validatorName]?.(\n context.type === \"custom\" ? context.value : undefined,\n condition,\n ) ?? false\n );\n }\n}\n\nfunction audit(\n request: UniversalCheckInRequest,\n status: RallyAuditLog[\"status\"],\n now: string,\n errorCode?: string,\n): RallyAuditLog {\n return {\n id: `audit-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`,\n timestamp: now,\n rallyId: request.rallyId,\n userId: request.userId,\n action: \"CHECK_IN\",\n resourceId: request.spotId,\n status,\n idempotencyKey: request.idempotencyKey,\n ...(errorCode === undefined ? {} : { metadata: { errorCode } }),\n };\n}\n\n/** Atomic, adapter-backed check-in service for the universal model. */\nexport class UniversalRallyServer {\n readonly #config: AdminRallyConfig;\n readonly #persistence: ServerPersistenceAdapter;\n readonly #options: UniversalRallyServerOptions;\n\n constructor(\n config: AdminRallyConfig,\n persistence: ServerPersistenceAdapter,\n options: UniversalRallyServerOptions = {},\n ) {\n this.#config = config;\n this.#persistence = persistence;\n this.#options = options;\n }\n\n /** Web Standard endpoint handler. Authentication, when configured, supplies the user identity. */\n async handleCheckIn(request: Request): Promise<Response> {\n const body = await requestBody<UniversalCheckInRequest>(request);\n const userId = await this.#authenticatedUser(request, body?.userId);\n if (this.#options.authenticate !== undefined && userId === null)\n return json(\n { ok: false, error: { code: \"UNAUTHORIZED\", message: \"Authentication is required.\" } },\n 401,\n );\n if (\n body === null ||\n userId === null ||\n body.rallyId !== this.#config.id ||\n body.spotId === \"\" ||\n body.idempotencyKey === \"\"\n )\n return json(\n {\n ok: false,\n error: {\n code: \"INVALID_REQUEST\",\n message: \"rallyId, spotId, and idempotencyKey are required.\",\n },\n },\n 400,\n );\n if (body.context === undefined)\n return json(\n { ok: false, error: { code: \"INVALID_REQUEST\", message: \"context is required.\" } },\n 400,\n );\n const result = await this.checkIn({ ...body, userId });\n return result.ok ? json(result) : json(result, result.code === \"SPOT_NOT_FOUND\" ? 404 : 422);\n }\n\n async handleClaimReward(request: Request): Promise<Response> {\n const body = await requestBody<UniversalClaimRewardRequest>(request);\n const userId = await this.#authenticatedUser(request, body?.userId);\n if (this.#options.authenticate !== undefined && userId === null)\n return json(\n { ok: false, error: { code: \"UNAUTHORIZED\", message: \"Authentication is required.\" } },\n 401,\n );\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 error: {\n code: \"INVALID_REQUEST\",\n message: \"rallyId, rewardId, and idempotencyKey are required.\",\n },\n },\n 400,\n );\n const key = `claim-reward:${body.rallyId}:${userId}:${body.rewardId}:${body.idempotencyKey}`;\n const previous = await this.#persistence.getIdempotentResult<UniversalClaimRewardResponse>(key);\n if (previous !== null) return json(previous, previous.ok ? 200 : 422);\n const reward = this.#config.rewards.find((item) => item.id === body.rewardId);\n if (reward === undefined) {\n const failure: UniversalClaimRewardResponse = {\n ok: false,\n code: \"REWARD_NOT_FOUND\",\n message: \"Reward was not found.\",\n };\n return json(await this.#rememberClaim(key, failure, body, userId), 404);\n }\n const timestamp = body.now ?? this.#options.now?.() ?? new Date().toISOString();\n const current = await this.sync(body.rallyId, userId);\n const currentReward = current.rewards?.find((item) => item.rewardId === reward.id) ?? {\n rewardId: reward.id,\n status: \"LOCKED\" as const,\n };\n const userClaims = await this.#getUserClaimCount(userId, reward.id);\n const local = consumeReward({\n reward: adminReward(reward),\n currentState: currentReward,\n now: timestamp,\n userId,\n userRedemptionCount: userClaims,\n ...(body.staffPasscode === undefined ? {} : { inputPasscode: body.staffPasscode }),\n ...(body.staffId === undefined ? {} : { staffId: body.staffId }),\n });\n if (!local.ok)\n return json(\n await this.#rememberClaim(\n key,\n {\n ok: false,\n code: local.error.code,\n message: \"Reward cannot be claimed.\",\n error: local.error,\n },\n body,\n userId,\n ),\n 422,\n );\n const stock = await this.#persistence.decrementRewardStock(reward.id);\n if (!stock.success)\n return json(\n await this.#rememberClaim(\n key,\n { ok: false, code: \"OUT_OF_STOCK\", message: \"Reward is out of stock.\" },\n body,\n userId,\n ),\n 422,\n );\n const next: UserRallyState = {\n ...current,\n rewards: (current.rewards ?? []).map((item) =>\n item.rewardId === reward.id ? local.value : item,\n ),\n updatedAt: timestamp,\n };\n await this.#persistence.saveUserState(body.rallyId, userId, next);\n const success: UniversalClaimRewardResponse =\n local.value.claimTicketNumber === undefined\n ? { ok: true, state: next }\n : { ok: true, state: next, claimTicketNumber: local.value.claimTicketNumber };\n await this.#persistence.saveIdempotentResult(\n key,\n success,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n await this.#persistence.recordAuditLog({\n id: `audit-${globalThis.crypto?.randomUUID?.() ?? Date.now()}`,\n timestamp,\n rallyId: body.rallyId,\n userId,\n action: \"CLAIM_REWARD\",\n resourceId: reward.id,\n status: \"SUCCESS\",\n idempotencyKey: body.idempotencyKey,\n });\n return json(success);\n }\n\n async handleSync(request: Request): Promise<Response> {\n const body = await requestBody<{ readonly rallyId: string; readonly userId?: string }>(request);\n const userId = await this.#authenticatedUser(request, body?.userId);\n if (this.#options.authenticate !== undefined && userId === null)\n return json(\n { ok: false, error: { code: \"UNAUTHORIZED\", message: \"Authentication is required.\" } },\n 401,\n );\n if (body === null || userId === null || body.rallyId !== this.#config.id)\n return json(\n { ok: false, error: { code: \"INVALID_REQUEST\", message: \"rallyId is required.\" } },\n 400,\n );\n return json({ ok: true, state: await this.sync(body.rallyId, userId) });\n }\n\n async handle(request: Request): Promise<Response> {\n if (request.method !== \"POST\")\n return json({ ok: false, error: { code: \"METHOD_NOT_ALLOWED\" } }, 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, error: { code: \"NOT_FOUND\" } }, 404);\n }\n\n async checkIn(request: UniversalCheckInRequest): Promise<UniversalCheckInResult> {\n const key = `check-in:${request.rallyId}:${request.userId}:${request.idempotencyKey}`;\n const previous = await this.#persistence.getIdempotentResult<UniversalCheckInResult>(key);\n if (previous !== null) return previous;\n const lockKey = `state:${request.rallyId}:${request.userId}`;\n const locked = await this.#persistence.acquireLock(lockKey, this.#options.lockTtlMs ?? 5000);\n if (!locked)\n return { ok: false, code: \"CONFLICT\", message: \"The user state is being updated.\" };\n const now = request.now ?? this.#options.now?.() ?? new Date().toISOString();\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,\n now,\n );\n const current =\n (await this.#persistence.getUserState(request.rallyId, request.userId)) ??\n initialState(this.#config, now);\n if (current.records.some((record) => record.stampId === request.spotId))\n return this.#remember(\n key,\n { ok: false, code: \"ALREADY_CLAIMED\", message: \"Spot was already claimed.\" },\n request,\n now,\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,\n now,\n );\n if (\n !spot.conditions.every((condition) =>\n matchesCondition(condition, request.context, this.#options.customValidators),\n )\n )\n return this.#remember(\n key,\n { ok: false, code: \"INVALID_PROOF\", message: \"Verification failed.\" },\n request,\n now,\n );\n const state: UserRallyState = {\n ...current,\n records: [...current.records, { stampId: request.spotId, acquiredAt: now }],\n updatedAt: now,\n };\n await this.#persistence.saveUserState(request.rallyId, request.userId, state);\n return this.#remember(key, { ok: true, state }, request, now);\n } finally {\n await this.#persistence.releaseLock(lockKey);\n }\n }\n\n async sync(rallyId: string, userId: string): Promise<UserRallyState> {\n const now = this.#options.now?.() ?? new Date().toISOString();\n return (\n (await this.#persistence.getUserState(rallyId, userId)) ?? initialState(this.#config, now)\n );\n }\n\n async #authenticatedUser(\n request: Request,\n requestedUserId: string | undefined,\n ): Promise<string | null> {\n const authenticated = await this.#options.authenticate?.(request);\n if (this.#options.authenticate !== undefined) return authenticated ?? null;\n return requestedUserId ?? null;\n }\n\n async #getUserClaimCount(userId: string, rewardId: string): Promise<number> {\n const state = await this.#persistence.getUserState(this.#config.id, userId);\n return state?.rewards?.find((item) => item.rewardId === rewardId)?.userRedemptionCount ?? 0;\n }\n\n async #rememberClaim(\n key: string,\n result: UniversalClaimRewardResponse,\n request: UniversalClaimRewardRequest,\n userId: string,\n ): Promise<UniversalClaimRewardResponse> {\n await this.#persistence.saveIdempotentResult(\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n await this.#persistence.recordAuditLog({\n id: `audit-${globalThis.crypto?.randomUUID?.() ?? Date.now()}`,\n timestamp: request.now ?? this.#options.now?.() ?? new Date().toISOString(),\n rallyId: request.rallyId,\n userId,\n action: \"CLAIM_REWARD\",\n resourceId: request.rewardId,\n status: \"REJECTED\",\n idempotencyKey: request.idempotencyKey,\n });\n return result;\n }\n\n async #remember(\n key: string,\n result: UniversalCheckInResult,\n request: UniversalCheckInRequest,\n now: string,\n ): Promise<UniversalCheckInResult> {\n await this.#persistence.recordAuditLog(\n audit(request, result.ok ? \"SUCCESS\" : \"REJECTED\", now, result.ok ? undefined : result.code),\n );\n await this.#persistence.saveIdempotentResult(\n key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n}\n\ntype UniversalClaimRewardResponse =\n | { readonly ok: true; readonly state: UserRallyState; readonly claimTicketNumber?: string }\n | {\n readonly ok: false;\n readonly code: string;\n readonly message: string;\n readonly error?: unknown;\n };\n\nexport type { StampRallyState };\n","import {\n consumeReward,\n createSecureToken,\n processStamp,\n type RallyConfig,\n type RewardConsumeError,\n reconcileRewardStates,\n type SecureTokenSecretKey,\n type StampError,\n type StampRallyState,\n type StampRecord,\n type VerificationContext,\n} from \"@stamprally/core\";\n\nexport interface UserRallyState extends StampRallyState {\n readonly userId?: string;\n}\n\nexport interface RallyAuditLog {\n readonly id: string;\n readonly timestamp: string;\n readonly rallyId: string;\n readonly userId: string;\n readonly action: \"CHECK_IN\" | \"CLAIM_REWARD\";\n readonly resourceId: string;\n readonly status: \"SUCCESS\" | \"REJECTED\";\n readonly idempotencyKey: string;\n readonly proofData?: unknown;\n readonly metadata?: Readonly<Record<string, unknown>>;\n}\n\nexport interface ServerStorageAdapter {\n getRewardStock(rewardId: string): Promise<number | null>;\n decrementRewardStock(rewardId: string): Promise<boolean>;\n getUserClaims(userId: string, rewardId: string): Promise<number>;\n recordAuditLog(log: RallyAuditLog): Promise<void>;\n saveUserState(userId: string, state: UserRallyState): Promise<void>;\n getUserState(userId: string): Promise<UserRallyState | null>;\n}\n\nexport interface AdminRallyConfig extends RallyConfig {\n readonly secretKey: SecureTokenSecretKey;\n readonly proofTtlSeconds?: number;\n readonly authenticate?: (request: Request) => Promise<string | null> | string | null;\n}\n\nexport interface CheckInRequest {\n readonly userId: string;\n readonly spotId: string;\n readonly claimMethod: string;\n readonly proofData?: unknown;\n readonly idempotencyKey: string;\n}\n\nexport interface ClaimRewardRequest {\n readonly userId: string;\n readonly rewardId: string;\n readonly staffPasscode?: string;\n readonly idempotencyKey: string;\n readonly staffId?: string;\n}\n\nexport interface SyncRequest {\n readonly userId: string;\n readonly queue?: ReadonlyArray<SyncCheckInOperation>;\n readonly operations?: ReadonlyArray<SyncCheckInOperation>;\n}\n\nexport interface SyncCheckInOperation {\n readonly userId?: string;\n readonly spotId?: string;\n readonly stampId?: string;\n readonly claimMethod?: string;\n readonly proofData?: unknown;\n readonly context?: VerificationContext;\n readonly idempotencyKey: string;\n}\n\nexport interface StampClaimProof {\n readonly token: string;\n readonly rallyId: string;\n readonly userId: string;\n readonly spotId: string;\n readonly acquiredAt: string;\n}\n\nexport interface InMemoryServerStorageOptions {\n readonly stocks?: Readonly<Record<string, number>>;\n}\n\nexport class InMemoryServerStorage implements ServerStorageAdapter {\n readonly #states = new Map<string, UserRallyState>();\n readonly #stocks: Map<string, number>;\n readonly #claims = new Map<string, number>();\n readonly #auditLogs: RallyAuditLog[] = [];\n\n constructor(options: InMemoryServerStorageOptions = {}) {\n this.#stocks = new Map(Object.entries(options.stocks ?? {}));\n }\n\n async getRewardStock(rewardId: string): Promise<number | null> {\n return this.#stocks.get(rewardId) ?? null;\n }\n\n async decrementRewardStock(rewardId: string): Promise<boolean> {\n const stock = this.#stocks.get(rewardId);\n if (stock === undefined) return true;\n if (stock <= 0) return false;\n this.#stocks.set(rewardId, stock - 1);\n return true;\n }\n\n async getUserClaims(userId: string, rewardId: string): Promise<number> {\n return this.#claims.get(`${userId}:${rewardId}`) ?? 0;\n }\n\n async recordAuditLog(log: RallyAuditLog): Promise<void> {\n this.#auditLogs.push({ ...log });\n }\n\n async saveUserState(userId: string, state: UserRallyState): Promise<void> {\n this.#states.set(userId, cloneUserState(state));\n }\n\n async getUserState(userId: string): Promise<UserRallyState | null> {\n const state = this.#states.get(userId);\n return state === undefined ? null : cloneUserState(state);\n }\n\n getAuditLogs(): ReadonlyArray<RallyAuditLog> {\n return this.#auditLogs.map((log) => ({ ...log }));\n }\n\n recordClaim(userId: string, rewardId: string): void {\n const key = `${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\n }\n}\n\nfunction cloneUserState(state: UserRallyState): UserRallyState {\n return {\n ...state,\n records: state.records.map((record) => ({\n ...record,\n ...(record.metadata === undefined ? {} : { metadata: { ...record.metadata } }),\n })),\n ...(state.rewards === undefined\n ? {}\n : { rewards: state.rewards.map((reward) => ({ ...reward })) }),\n };\n}\n\nfunction jsonResponse(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}\n\nfunction errorResponse(code: string, message: string, status: number): Response {\n return jsonResponse({ ok: false, error: { code, message } }, status);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction contextForClaim(method: string, proofData: unknown): VerificationContext {\n if (method === \"token\" || method === \"qr\" || method === \"passcode\") {\n return {\n type: \"token\",\n token:\n isObject(proofData) && typeof proofData.token === \"string\"\n ? proofData.token\n : String(proofData ?? \"\"),\n };\n }\n if (method === \"geo\" || method === \"geolocation\") {\n const value = isObject(proofData) ? proofData : {};\n return {\n type: \"geo\",\n currentLatitude:\n typeof value.latitude === \"number\"\n ? value.latitude\n : typeof value.currentLatitude === \"number\"\n ? value.currentLatitude\n : Number.NaN,\n currentLongitude:\n typeof value.longitude === \"number\"\n ? value.longitude\n : typeof value.currentLongitude === \"number\"\n ? value.currentLongitude\n : Number.NaN,\n };\n }\n return { type: \"instant\" };\n}\n\nfunction now(): string {\n return new Date().toISOString();\n}\n\nfunction hasText(value: unknown): value is string {\n return typeof value === \"string\" && value.trim() !== \"\";\n}\n\nfunction safeProofData(value: unknown): unknown {\n return isObject(value) && typeof value.token === \"string\" ? { type: \"token\" } : value;\n}\n\nfunction proofFromContext(context: VerificationContext | undefined): unknown {\n if (context?.type === \"token\") return { token: context.token };\n if (context?.type === \"geo\") {\n return { latitude: context.currentLatitude, longitude: context.currentLongitude };\n }\n return undefined;\n}\n\nfunction id(prefix: string): string {\n return `${prefix}-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;\n}\n\nexport class StampRallyServer {\n readonly #config: AdminRallyConfig;\n readonly #storage: ServerStorageAdapter;\n readonly #idempotent = new Map<string, Response>();\n readonly #claims = new Map<string, number>();\n #queue: Promise<unknown> = Promise.resolve();\n\n constructor(config: AdminRallyConfig, storage: ServerStorageAdapter) {\n this.#config = config;\n this.#storage = storage;\n }\n\n handle(request: Request): Promise<Response> {\n const path = new URL(request.url).pathname;\n if (request.method !== \"POST\")\n return Promise.resolve(errorResponse(\"METHOD_NOT_ALLOWED\", \"POST is required.\", 405));\n if (path.endsWith(\"/check-in\")) return this.verifyCheckIn(request);\n if (path.endsWith(\"/claim-reward\")) return this.claimReward(request);\n if (path.endsWith(\"/sync\")) return this.syncProgress(request);\n return Promise.resolve(errorResponse(\"NOT_FOUND\", \"Route not found.\", 404));\n }\n\n verifyCheckIn(request: Request): Promise<Response> {\n return this.#enqueue(() => this.#verifyCheckIn(request));\n }\n\n claimReward(request: Request): Promise<Response> {\n return this.#enqueue(() => this.#claimReward(request));\n }\n\n syncProgress(request: Request): Promise<Response> {\n return this.#enqueue(() => this.#syncProgress(request));\n }\n\n #enqueue<T>(operation: () => Promise<T>): Promise<T> {\n const next = this.#queue.then(operation, operation);\n this.#queue = next.then(\n () => undefined,\n () => undefined,\n );\n return next;\n }\n\n async #authenticate(request: Request): Promise<string | null> {\n return this.#config.authenticate === undefined ? null : this.#config.authenticate(request);\n }\n\n async #parse<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\n async #verifyCheckIn(request: Request): Promise<Response> {\n const authenticatedUser = await this.#authenticate(request);\n const body = await this.#parse<CheckInRequest>(request);\n const userId = body?.userId ?? authenticatedUser;\n if (\n userId === null ||\n userId === undefined ||\n body === null ||\n !hasText(userId) ||\n !hasText(body.spotId) ||\n !hasText(body.claimMethod) ||\n !hasText(body.idempotencyKey)\n ) {\n return errorResponse(\n \"INVALID_REQUEST\",\n \"userId, spotId, and idempotencyKey are required.\",\n 400,\n );\n }\n if (authenticatedUser !== null && authenticatedUser !== userId)\n return errorResponse(\"UNAUTHORIZED\", \"User identity does not match authentication.\", 401);\n const key = `check-in:${userId}:${body.idempotencyKey}`;\n const previous = this.#idempotent.get(key);\n if (previous !== undefined) return previous.clone();\n const timestamp = now();\n const current =\n (await this.#storage.getUserState(userId)) ?? emptyState(this.#config, timestamp);\n const result = processStamp(\n current,\n this.#config,\n body.spotId,\n contextForClaim(body.claimMethod, body.proofData),\n timestamp,\n );\n if (!result.ok) {\n await this.#audit(\n userId,\n \"CHECK_IN\",\n body.spotId,\n body.idempotencyKey,\n \"REJECTED\",\n safeProofData(body.proofData),\n result.error,\n );\n return this.#remember(key, jsonResponse({ ok: false, error: result.error }, 422));\n }\n const ttl = this.#config.proofTtlSeconds ?? 3600;\n const token = await createSecureToken(\n {\n type: \"stamp_claim\",\n rallyId: this.#config.id,\n userId,\n spotId: body.spotId,\n acquiredAt: timestamp,\n exp: Math.floor(Date.now() / 1000) + ttl,\n },\n this.#config.secretKey,\n { encrypt: true },\n );\n await this.#storage.saveUserState(userId, result.value.nextState);\n await this.#audit(\n userId,\n \"CHECK_IN\",\n body.spotId,\n body.idempotencyKey,\n \"SUCCESS\",\n safeProofData(body.proofData),\n );\n return this.#remember(\n key,\n jsonResponse({\n ok: true,\n state: result.value.nextState,\n proof: {\n token,\n rallyId: this.#config.id,\n userId,\n spotId: body.spotId,\n acquiredAt: timestamp,\n },\n }),\n );\n }\n\n async #claimReward(request: Request): Promise<Response> {\n const authenticatedUser = await this.#authenticate(request);\n const body = await this.#parse<ClaimRewardRequest>(request);\n const userId = body?.userId ?? authenticatedUser;\n if (\n userId === null ||\n userId === undefined ||\n body === null ||\n !hasText(userId) ||\n !hasText(body.rewardId) ||\n !hasText(body.idempotencyKey)\n )\n return errorResponse(\n \"INVALID_REQUEST\",\n \"userId, rewardId, and idempotencyKey are required.\",\n 400,\n );\n if (authenticatedUser !== null && authenticatedUser !== userId)\n return errorResponse(\"UNAUTHORIZED\", \"User identity does not match authentication.\", 401);\n const key = `claim-reward:${userId}:${body.rewardId}:${body.idempotencyKey}`;\n const previous = this.#idempotent.get(key);\n if (previous !== undefined) return previous.clone();\n const reward = this.#config.rewards?.find((item) => item.id === body.rewardId);\n if (reward === undefined) {\n await this.#audit(userId, \"CLAIM_REWARD\", body.rewardId, body.idempotencyKey, \"REJECTED\");\n return this.#remember(key, errorResponse(\"REWARD_NOT_FOUND\", \"Reward was not found.\", 404));\n }\n const timestamp = now();\n const current =\n (await this.#storage.getUserState(userId)) ?? emptyState(this.#config, timestamp);\n const rewardState = current.rewards?.find((item) => item.rewardId === reward.id);\n if (rewardState === undefined) {\n await this.#audit(userId, \"CLAIM_REWARD\", reward.id, body.idempotencyKey, \"REJECTED\");\n return this.#remember(key, errorResponse(\"NOT_AVAILABLE\", \"Reward is not available.\", 422));\n }\n const userClaims = Math.max(\n await this.#storage.getUserClaims(userId, reward.id),\n this.#claims.get(`${userId}:${reward.id}`) ?? 0,\n );\n const stock = await this.#storage.getRewardStock(reward.id);\n const userLimit = reward.userClaimLimit ?? reward.limitPerUser;\n const canReclaimServerReward =\n reward.redemptionMethod === \"server_claim\" &&\n (userLimit === undefined || userClaims < userLimit) &&\n (stock === null || stock > 0);\n const claimableState =\n canReclaimServerReward && rewardState.status === \"CONSUMED\"\n ? { ...rewardState, status: \"AVAILABLE\" as const }\n : rewardState;\n const local = consumeReward({\n reward,\n currentState: claimableState,\n now: timestamp,\n ...(body.staffPasscode === undefined ? {} : { inputPasscode: body.staffPasscode }),\n ...(body.staffId === undefined ? {} : { staffId: body.staffId }),\n userId,\n userRedemptionCount: userClaims,\n });\n if (!local.ok)\n return this.#remember(\n key,\n await this.#rewardError(userId, reward.id, body.idempotencyKey, local.error),\n );\n if (stock !== null && !(await this.#storage.decrementRewardStock(reward.id)))\n return this.#remember(\n key,\n await this.#rewardError(userId, reward.id, body.idempotencyKey, {\n code: \"OUT_OF_STOCK\",\n rewardId: reward.id,\n }),\n );\n const nextState: StampRallyState = {\n ...current,\n rewards: (current.rewards ?? []).map((item) =>\n item.rewardId === reward.id ? local.value : item,\n ),\n updatedAt: timestamp,\n };\n await this.#storage.saveUserState(userId, nextState);\n const claimKey = `${userId}:${reward.id}`;\n this.#claims.set(claimKey, userClaims + 1);\n if (this.#storage instanceof InMemoryServerStorage)\n this.#storage.recordClaim(userId, reward.id);\n await this.#audit(userId, \"CLAIM_REWARD\", reward.id, body.idempotencyKey, \"SUCCESS\", {\n staffId: body.staffId,\n });\n return this.#remember(\n key,\n jsonResponse({\n ok: true,\n state: nextState,\n claimTicketNumber: local.value.claimTicketNumber,\n }),\n );\n }\n\n async #rewardError(\n userId: string,\n rewardId: string,\n key: string,\n error: RewardConsumeError,\n ): Promise<Response> {\n await this.#audit(userId, \"CLAIM_REWARD\", rewardId, key, \"REJECTED\", undefined, error);\n return jsonResponse({ ok: false, error }, 422);\n }\n\n async #syncProgress(request: Request): Promise<Response> {\n const authenticatedUser = await this.#authenticate(request);\n const body = await this.#parse<SyncRequest>(request);\n if (body === null || body.userId === undefined)\n return errorResponse(\"INVALID_REQUEST\", \"userId is required.\", 400);\n if (authenticatedUser !== null && authenticatedUser !== body.userId)\n return errorResponse(\"UNAUTHORIZED\", \"User identity does not match authentication.\", 401);\n const queue = body.queue ?? body.operations ?? [];\n for (const operation of queue) {\n const userId = operation.userId ?? body.userId;\n const spotId = operation.spotId ?? operation.stampId;\n const claimMethod = operation.claimMethod ?? operation.context?.type;\n if (!hasText(userId) || !hasText(spotId) || !hasText(claimMethod)) continue;\n const synthetic = new Request(new URL(\"/api/check-in\", request.url), {\n method: \"POST\",\n body: JSON.stringify({\n userId,\n spotId,\n claimMethod,\n proofData: operation.proofData ?? proofFromContext(operation.context),\n idempotencyKey: operation.idempotencyKey,\n }),\n headers: { \"content-type\": \"application/json\" },\n });\n await this.#verifyCheckIn(synthetic);\n }\n const timestamp = now();\n const state =\n (await this.#storage.getUserState(body.userId)) ?? emptyState(this.#config, timestamp);\n await this.#storage.saveUserState(body.userId, state);\n return jsonResponse({ ok: true, state, accepted: queue.length });\n }\n\n async #audit(\n userId: string,\n action: RallyAuditLog[\"action\"],\n resourceId: string,\n idempotencyKey: string,\n status: RallyAuditLog[\"status\"],\n proofData?: unknown,\n error?: unknown,\n ): Promise<void> {\n await this.#storage.recordAuditLog({\n id: id(\"audit\"),\n timestamp: now(),\n rallyId: this.#config.id,\n userId,\n action,\n resourceId,\n status,\n idempotencyKey,\n ...(proofData === undefined ? {} : { proofData }),\n ...(error === undefined\n ? {}\n : {\n metadata: {\n errorCode: isObject(error) && typeof error.code === \"string\" ? error.code : \"UNKNOWN\",\n },\n }),\n });\n }\n\n #remember(key: string, response: Response): Response {\n this.#idempotent.set(key, response.clone());\n return response;\n }\n}\n\nfunction emptyState(config: RallyConfig, timestamp: string): UserRallyState {\n return {\n rallyId: config.id,\n records: [],\n ...(config.rewards === undefined\n ? {}\n : { rewards: reconcileRewardStates(config.rewards, [], 0, timestamp) }),\n updatedAt: timestamp,\n };\n}\n\nexport type { InMemoryServerPersistenceOptions, ServerPersistenceAdapter } from \"./persistence.js\";\nexport { InMemoryServerPersistenceAdapter } from \"./persistence.js\";\nexport type {\n UniversalCheckInRequest,\n UniversalCheckInResult,\n UniversalClaimRewardRequest,\n UniversalRallyServerOptions,\n UniversalVerificationContext,\n} from \"./universalServer.js\";\nexport { UniversalRallyServer } from \"./universalServer.js\";\nexport type { StampError, StampRecord };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/persistence.ts","../src/server.ts"],"names":["now","reconcileRewardStates","evaluateConditionDetailed","consumeReward"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UserRallyState } from \"@stamprally/core\";\nimport type { AuditLog } from \"./index.js\";\n\nexport interface ServerPersistenceAdapter {\n acquireLock(lockKey: string, ttlMs: number): Promise<boolean>;\n releaseLock(lockKey: string): Promise<void>;\n decrementRewardStock(\n rewardId: string,\n ): Promise<{ readonly success: boolean; readonly remainingStock: number }>;\n incrementRewardStock(rewardId: string): Promise<void>;\n getIdempotentResult<T>(key: string): Promise<T | null>;\n saveIdempotentResult<T>(key: string, result: T, ttlMs: number): Promise<void>;\n getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number>;\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}\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 #claims = new Map<string, number>();\n readonly #auditLogs: AuditLog[] = [];\n constructor(options: InMemoryServerPersistenceOptions = {}) {\n this.#stocks = new Map(Object.entries(options.stocks ?? {}));\n }\n async acquireLock(key: string, ttlMs: number): Promise<boolean> {\n const now = Date.now();\n const until = this.#locks.get(key);\n if (until !== undefined && until > now) return false;\n this.#locks.set(key, now + Math.max(1, ttlMs));\n return true;\n }\n async releaseLock(key: string): Promise<void> {\n this.#locks.delete(key);\n }\n async decrementRewardStock(\n rewardId: string,\n ): Promise<{ success: boolean; remainingStock: number }> {\n const current = this.#stocks.get(rewardId);\n if (current === undefined) return { success: true, remainingStock: Number.POSITIVE_INFINITY };\n if (current <= 0) return { success: false, remainingStock: 0 };\n this.#stocks.set(rewardId, current - 1);\n return { success: true, remainingStock: current - 1 };\n }\n async incrementRewardStock(rewardId: string): Promise<void> {\n const current = this.#stocks.get(rewardId);\n if (current !== undefined) this.#stocks.set(rewardId, current + 1);\n }\n async getIdempotentResult<T>(key: string): Promise<T | null> {\n const value = this.#idempotent.get(key);\n if (value === undefined || value.expiresAt <= Date.now()) {\n this.#idempotent.delete(key);\n return null;\n }\n return structuredClone(value.value) as T;\n }\n async saveIdempotentResult<T>(key: string, result: T, ttlMs: number): Promise<void> {\n this.#idempotent.set(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 getAuditLogs(): ReadonlyArray<AuditLog> {\n return structuredClone(this.#auditLogs);\n }\n recordClaim(rallyId: string, userId: string, rewardId: string): void {\n const key = `${rallyId}:${userId}:${rewardId}`;\n this.#claims.set(key, (this.#claims.get(key) ?? 0) + 1);\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>(key);\n if (previous !== null) return previous;\n const lockKey = `state:${request.rallyId}:${request.userId}`;\n if (!(await this.#persistence.acquireLock(lockKey, this.#options.lockTtlMs ?? 5_000)))\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(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>(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 );\n const lockKey = `reward:${request.rallyId}:${reward.id}`;\n if (!(await this.#persistence.acquireLock(lockKey, this.#options.lockTtlMs ?? 5_000)))\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 try {\n const checked = await this.#persistence.getIdempotentResult<ClaimResponse>(key);\n if (checked !== null) return checked;\n const current =\n (await this.#persistence.getUserState(request.rallyId, request.userId)) ??\n initialState(this.#config, request.userId, timestamp);\n const claimCount = await this.#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 );\n const stock = await this.#persistence.decrementRewardStock(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 );\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 this.#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 await this.#persistence.recordAuditLog(\n audit(\n request.rallyId,\n request.userId,\n \"CLAIM_REWARD\",\n reward.id,\n request.idempotencyKey,\n \"SUCCESS\",\n timestamp,\n ),\n );\n await this.#persistence.saveIdempotentResult(\n key,\n response,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n if (\n this.#persistence instanceof Object &&\n \"recordClaim\" in this.#persistence &&\n typeof this.#persistence.recordClaim === \"function\"\n )\n this.#persistence.recordClaim(request.rallyId, request.userId, reward.id);\n return response;\n } catch (error) {\n await this.#persistence.incrementRewardStock(reward.id);\n decremented = false;\n throw error;\n }\n } catch (error) {\n if (decremented) await this.#persistence.incrementRewardStock(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 this.#persistence.releaseLock(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 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 key,\n result,\n this.#options.idempotencyTtlMs ?? 86_400_000,\n );\n return result;\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,105 +1,72 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import * as _stamprally_core from '@stamprally/core';
|
|
2
|
+
import { UserRallyState, AdminRallyConfig } from '@stamprally/core';
|
|
3
|
+
export { UserRallyState } from '@stamprally/core';
|
|
3
4
|
|
|
4
|
-
/** Persistence contract for implementations backed by Redis, SQL, or another RDB. */
|
|
5
5
|
interface ServerPersistenceAdapter {
|
|
6
6
|
acquireLock(lockKey: string, ttlMs: number): Promise<boolean>;
|
|
7
7
|
releaseLock(lockKey: string): Promise<void>;
|
|
8
8
|
decrementRewardStock(rewardId: string): Promise<{
|
|
9
|
-
success: boolean;
|
|
10
|
-
remainingStock: number;
|
|
9
|
+
readonly success: boolean;
|
|
10
|
+
readonly remainingStock: number;
|
|
11
11
|
}>;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
incrementRewardStock(rewardId: string): Promise<void>;
|
|
13
|
+
getIdempotentResult<T>(key: string): Promise<T | null>;
|
|
14
|
+
saveIdempotentResult<T>(key: string, result: T, ttlMs: number): Promise<void>;
|
|
15
|
+
getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number>;
|
|
14
16
|
getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;
|
|
15
17
|
saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void>;
|
|
16
|
-
recordAuditLog(log:
|
|
18
|
+
recordAuditLog(log: AuditLog): Promise<void>;
|
|
17
19
|
}
|
|
18
20
|
interface InMemoryServerPersistenceOptions {
|
|
19
21
|
readonly stocks?: Readonly<Record<string, number>>;
|
|
20
22
|
}
|
|
21
|
-
/** Deterministic adapter for tests and small single-process deployments. */
|
|
22
23
|
declare class InMemoryServerPersistenceAdapter implements ServerPersistenceAdapter {
|
|
23
24
|
#private;
|
|
24
25
|
constructor(options?: InMemoryServerPersistenceOptions);
|
|
25
|
-
acquireLock(
|
|
26
|
-
releaseLock(
|
|
26
|
+
acquireLock(key: string, ttlMs: number): Promise<boolean>;
|
|
27
|
+
releaseLock(key: string): Promise<void>;
|
|
27
28
|
decrementRewardStock(rewardId: string): Promise<{
|
|
28
29
|
success: boolean;
|
|
29
30
|
remainingStock: number;
|
|
30
31
|
}>;
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
incrementRewardStock(rewardId: string): Promise<void>;
|
|
33
|
+
getIdempotentResult<T>(key: string): Promise<T | null>;
|
|
34
|
+
saveIdempotentResult<T>(key: string, result: T, ttlMs: number): Promise<void>;
|
|
35
|
+
getUserClaimCount(rallyId: string, userId: string, rewardId: string): Promise<number>;
|
|
33
36
|
getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;
|
|
34
37
|
saveUserState(rallyId: string, userId: string, state: UserRallyState): Promise<void>;
|
|
35
|
-
recordAuditLog(log:
|
|
36
|
-
getAuditLogs(): ReadonlyArray<
|
|
38
|
+
recordAuditLog(log: AuditLog): Promise<void>;
|
|
39
|
+
getAuditLogs(): ReadonlyArray<AuditLog>;
|
|
40
|
+
recordClaim(rallyId: string, userId: string, rewardId: string): void;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
type
|
|
40
|
-
readonly type: "qr";
|
|
41
|
-
readonly token: string;
|
|
42
|
-
} | {
|
|
43
|
-
readonly type: "passcode";
|
|
44
|
-
readonly code: string;
|
|
45
|
-
} | {
|
|
46
|
-
readonly type: "gps";
|
|
47
|
-
readonly latitude: number;
|
|
48
|
-
readonly longitude: number;
|
|
49
|
-
} | {
|
|
50
|
-
readonly type: "custom";
|
|
51
|
-
readonly value: unknown;
|
|
52
|
-
};
|
|
53
|
-
interface UniversalCheckInRequest {
|
|
54
|
-
readonly rallyId: string;
|
|
55
|
-
readonly userId: string;
|
|
56
|
-
readonly spotId: string;
|
|
57
|
-
readonly context: UniversalVerificationContext;
|
|
58
|
-
readonly idempotencyKey: string;
|
|
59
|
-
readonly now?: string;
|
|
60
|
-
}
|
|
61
|
-
interface UniversalClaimRewardRequest {
|
|
62
|
-
readonly rallyId: string;
|
|
63
|
-
readonly userId: string;
|
|
64
|
-
readonly rewardId: string;
|
|
65
|
-
readonly idempotencyKey: string;
|
|
66
|
-
readonly staffPasscode?: string;
|
|
67
|
-
readonly staffId?: string;
|
|
68
|
-
readonly now?: string;
|
|
69
|
-
}
|
|
70
|
-
type UniversalCheckInResult = {
|
|
71
|
-
readonly ok: true;
|
|
72
|
-
readonly state: UserRallyState;
|
|
73
|
-
} | {
|
|
43
|
+
type ErrorResponse = {
|
|
74
44
|
readonly ok: false;
|
|
75
45
|
readonly code: string;
|
|
76
46
|
readonly message: string;
|
|
77
47
|
};
|
|
78
|
-
|
|
79
|
-
readonly
|
|
80
|
-
readonly
|
|
81
|
-
readonly
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
readonly authenticate?: (request: Request) => Promise<string | null> | string | null;
|
|
85
|
-
}
|
|
86
|
-
/** Atomic, adapter-backed check-in service for the universal model. */
|
|
87
|
-
declare class UniversalRallyServer {
|
|
48
|
+
type ClaimResponse = {
|
|
49
|
+
readonly ok: true;
|
|
50
|
+
readonly state: UserRallyState;
|
|
51
|
+
readonly claimTicketNumber?: string;
|
|
52
|
+
} | ErrorResponse;
|
|
53
|
+
declare class StampRallyServer {
|
|
88
54
|
#private;
|
|
89
|
-
constructor(config: AdminRallyConfig
|
|
90
|
-
|
|
55
|
+
constructor(config: AdminRallyConfig, persistence: ServerPersistenceAdapter, options?: ServerOptions);
|
|
56
|
+
handle(request: Request): Promise<Response>;
|
|
91
57
|
handleCheckIn(request: Request): Promise<Response>;
|
|
92
58
|
handleClaimReward(request: Request): Promise<Response>;
|
|
93
59
|
handleSync(request: Request): Promise<Response>;
|
|
94
|
-
|
|
95
|
-
|
|
60
|
+
checkIn(request: CheckInRequest & {
|
|
61
|
+
readonly userId: string;
|
|
62
|
+
}): Promise<CheckInResponse>;
|
|
63
|
+
claimReward(request: ClaimRewardRequest & {
|
|
64
|
+
readonly userId: string;
|
|
65
|
+
}): Promise<ClaimResponse>;
|
|
96
66
|
sync(rallyId: string, userId: string): Promise<UserRallyState>;
|
|
97
67
|
}
|
|
98
68
|
|
|
99
|
-
interface
|
|
100
|
-
readonly userId?: string;
|
|
101
|
-
}
|
|
102
|
-
interface RallyAuditLog {
|
|
69
|
+
interface AuditLog {
|
|
103
70
|
readonly id: string;
|
|
104
71
|
readonly timestamp: string;
|
|
105
72
|
readonly rallyId: string;
|
|
@@ -108,79 +75,39 @@ interface RallyAuditLog {
|
|
|
108
75
|
readonly resourceId: string;
|
|
109
76
|
readonly status: "SUCCESS" | "REJECTED";
|
|
110
77
|
readonly idempotencyKey: string;
|
|
111
|
-
readonly proofData?: unknown;
|
|
112
78
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
113
79
|
}
|
|
114
|
-
interface ServerStorageAdapter {
|
|
115
|
-
getRewardStock(rewardId: string): Promise<number | null>;
|
|
116
|
-
decrementRewardStock(rewardId: string): Promise<boolean>;
|
|
117
|
-
getUserClaims(userId: string, rewardId: string): Promise<number>;
|
|
118
|
-
recordAuditLog(log: RallyAuditLog): Promise<void>;
|
|
119
|
-
saveUserState(userId: string, state: UserRallyState): Promise<void>;
|
|
120
|
-
getUserState(userId: string): Promise<UserRallyState | null>;
|
|
121
|
-
}
|
|
122
|
-
interface AdminRallyConfig extends RallyConfig {
|
|
123
|
-
readonly secretKey: SecureTokenSecretKey;
|
|
124
|
-
readonly proofTtlSeconds?: number;
|
|
125
|
-
readonly authenticate?: (request: Request) => Promise<string | null> | string | null;
|
|
126
|
-
}
|
|
127
80
|
interface CheckInRequest {
|
|
128
|
-
readonly
|
|
81
|
+
readonly rallyId: string;
|
|
82
|
+
readonly userId?: string;
|
|
129
83
|
readonly spotId: string;
|
|
130
|
-
readonly
|
|
131
|
-
readonly proofData?: unknown;
|
|
84
|
+
readonly context: _stamprally_core.VerificationContext;
|
|
132
85
|
readonly idempotencyKey: string;
|
|
86
|
+
readonly now?: string;
|
|
133
87
|
}
|
|
134
88
|
interface ClaimRewardRequest {
|
|
135
|
-
readonly
|
|
89
|
+
readonly rallyId: string;
|
|
90
|
+
readonly userId?: string;
|
|
136
91
|
readonly rewardId: string;
|
|
137
|
-
readonly staffPasscode?: string;
|
|
138
92
|
readonly idempotencyKey: string;
|
|
93
|
+
readonly staffPasscode?: string;
|
|
139
94
|
readonly staffId?: string;
|
|
95
|
+
readonly now?: string;
|
|
140
96
|
}
|
|
141
|
-
|
|
142
|
-
readonly
|
|
143
|
-
readonly
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
readonly
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
readonly
|
|
151
|
-
readonly
|
|
152
|
-
readonly
|
|
153
|
-
readonly
|
|
154
|
-
|
|
155
|
-
interface StampClaimProof {
|
|
156
|
-
readonly token: string;
|
|
157
|
-
readonly rallyId: string;
|
|
158
|
-
readonly userId: string;
|
|
159
|
-
readonly spotId: string;
|
|
160
|
-
readonly acquiredAt: string;
|
|
161
|
-
}
|
|
162
|
-
interface InMemoryServerStorageOptions {
|
|
163
|
-
readonly stocks?: Readonly<Record<string, number>>;
|
|
164
|
-
}
|
|
165
|
-
declare class InMemoryServerStorage implements ServerStorageAdapter {
|
|
166
|
-
#private;
|
|
167
|
-
constructor(options?: InMemoryServerStorageOptions);
|
|
168
|
-
getRewardStock(rewardId: string): Promise<number | null>;
|
|
169
|
-
decrementRewardStock(rewardId: string): Promise<boolean>;
|
|
170
|
-
getUserClaims(userId: string, rewardId: string): Promise<number>;
|
|
171
|
-
recordAuditLog(log: RallyAuditLog): Promise<void>;
|
|
172
|
-
saveUserState(userId: string, state: UserRallyState): Promise<void>;
|
|
173
|
-
getUserState(userId: string): Promise<UserRallyState | null>;
|
|
174
|
-
getAuditLogs(): ReadonlyArray<RallyAuditLog>;
|
|
175
|
-
recordClaim(userId: string, rewardId: string): void;
|
|
176
|
-
}
|
|
177
|
-
declare class StampRallyServer {
|
|
178
|
-
#private;
|
|
179
|
-
constructor(config: AdminRallyConfig, storage: ServerStorageAdapter);
|
|
180
|
-
handle(request: Request): Promise<Response>;
|
|
181
|
-
verifyCheckIn(request: Request): Promise<Response>;
|
|
182
|
-
claimReward(request: Request): Promise<Response>;
|
|
183
|
-
syncProgress(request: Request): Promise<Response>;
|
|
97
|
+
type CheckInResponse = {
|
|
98
|
+
readonly ok: true;
|
|
99
|
+
readonly state: UserRallyState;
|
|
100
|
+
} | {
|
|
101
|
+
readonly ok: false;
|
|
102
|
+
readonly code: string;
|
|
103
|
+
readonly message: string;
|
|
104
|
+
};
|
|
105
|
+
interface ServerOptions {
|
|
106
|
+
readonly lockTtlMs?: number;
|
|
107
|
+
readonly idempotencyTtlMs?: number;
|
|
108
|
+
readonly authenticate?: (request: Request) => Promise<string | null> | string | null;
|
|
109
|
+
readonly customValidators?: Readonly<Record<string, _stamprally_core.Validator>>;
|
|
110
|
+
readonly now?: () => string;
|
|
184
111
|
}
|
|
185
112
|
|
|
186
|
-
export { type
|
|
113
|
+
export { type AuditLog, type CheckInRequest, type CheckInResponse, type ClaimRewardRequest, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type ServerOptions, type ServerPersistenceAdapter, StampRallyServer };
|