@stamprally/server 0.20.0 → 0.21.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.d.cts CHANGED
@@ -9,6 +9,12 @@ interface TrustedAuthContext {
9
9
  readonly sessionId?: string;
10
10
  readonly claims?: Record<string, unknown>;
11
11
  }
12
+ /** Authentication accepted by direct server methods. Strings are a convenience for trusted callers. */
13
+ type AuthInput = TrustedAuthContext | {
14
+ readonly userId: string;
15
+ } | string;
16
+ /** Normalizes the supported direct-method authentication forms at the server boundary. */
17
+ declare function normalizeAuthContext(auth: AuthInput): TrustedAuthContext;
12
18
  /** @deprecated Use TrustedAuthContext. */
13
19
  type AuthenticationContext = TrustedAuthContext;
14
20
 
@@ -273,10 +279,10 @@ declare class StampRallyServer {
273
279
  handleCheckIn(request: Request): Promise<Response>;
274
280
  handleClaimReward(request: Request): Promise<Response>;
275
281
  handleSync(request: Request): Promise<Response>;
276
- checkIn(request: CheckInRequest, authContext?: TrustedAuthContext): Promise<CheckInResponse>;
277
- claimReward(request: ClaimRewardRequest, authContext?: TrustedAuthContext): Promise<ClaimResponse>;
282
+ checkIn(request: CheckInRequest, authInput?: AuthInput): Promise<CheckInResponse>;
283
+ claimReward(request: ClaimRewardRequest, authInput?: AuthInput): Promise<ClaimResponse>;
278
284
  sync(rallyId: string, identity: string | TrustedAuthContext): Promise<UserRallyState>;
279
- syncProgress(request: SyncProgressRequest, authContext: TrustedAuthContext): Promise<SyncProgressResponse>;
285
+ syncProgress(request: SyncProgressRequest, authInput: AuthInput): Promise<SyncProgressResponse>;
280
286
  }
281
287
 
282
288
  /**
@@ -348,4 +354,4 @@ interface ServerOptions {
348
354
  readonly anonymousPolicy?: "session_scoped" | "reject" | "shared_global_opt_in_insecure";
349
355
  }
350
356
 
351
- export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardMutationContext, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type SyncProgressOperation, type SyncProgressRequest, type TrustedAuthContext, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
357
+ export { type AuditLog, type AuthInput, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardMutationContext, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type SyncProgressOperation, type SyncProgressRequest, type TrustedAuthContext, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, normalizeAuthContext, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
package/dist/index.d.ts CHANGED
@@ -9,6 +9,12 @@ interface TrustedAuthContext {
9
9
  readonly sessionId?: string;
10
10
  readonly claims?: Record<string, unknown>;
11
11
  }
12
+ /** Authentication accepted by direct server methods. Strings are a convenience for trusted callers. */
13
+ type AuthInput = TrustedAuthContext | {
14
+ readonly userId: string;
15
+ } | string;
16
+ /** Normalizes the supported direct-method authentication forms at the server boundary. */
17
+ declare function normalizeAuthContext(auth: AuthInput): TrustedAuthContext;
12
18
  /** @deprecated Use TrustedAuthContext. */
13
19
  type AuthenticationContext = TrustedAuthContext;
14
20
 
@@ -273,10 +279,10 @@ declare class StampRallyServer {
273
279
  handleCheckIn(request: Request): Promise<Response>;
274
280
  handleClaimReward(request: Request): Promise<Response>;
275
281
  handleSync(request: Request): Promise<Response>;
276
- checkIn(request: CheckInRequest, authContext?: TrustedAuthContext): Promise<CheckInResponse>;
277
- claimReward(request: ClaimRewardRequest, authContext?: TrustedAuthContext): Promise<ClaimResponse>;
282
+ checkIn(request: CheckInRequest, authInput?: AuthInput): Promise<CheckInResponse>;
283
+ claimReward(request: ClaimRewardRequest, authInput?: AuthInput): Promise<ClaimResponse>;
278
284
  sync(rallyId: string, identity: string | TrustedAuthContext): Promise<UserRallyState>;
279
- syncProgress(request: SyncProgressRequest, authContext: TrustedAuthContext): Promise<SyncProgressResponse>;
285
+ syncProgress(request: SyncProgressRequest, authInput: AuthInput): Promise<SyncProgressResponse>;
280
286
  }
281
287
 
282
288
  /**
@@ -348,4 +354,4 @@ interface ServerOptions {
348
354
  readonly anonymousPolicy?: "session_scoped" | "reject" | "shared_global_opt_in_insecure";
349
355
  }
350
356
 
351
- export { type AuditLog, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardMutationContext, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type SyncProgressOperation, type SyncProgressRequest, type TrustedAuthContext, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
357
+ export { type AuditLog, type AuthInput, type AuthenticationContext, type CheckInRequest, type CheckInResponse, type CheckInTransactionMutation, type CheckInTransactionParams, type ClaimRewardMutationContext, type ClaimRewardRequest, type ClaimRewardTransactionMutation, type ClaimRewardTransactionParams, InMemoryServerPersistenceAdapter, type InMemoryServerPersistenceOptions, type RedisMultiExecutor, type RequestValidationError, RequestValidationException, type RequestValidationResult, type ServerOptions, type ServerPersistenceAdapter, type SqlCheckInStore, type SqlClaimRewardStore, type SqlTransactionDatabase, StampRallyServer, type SyncOperationStatus, type SyncProgressOperation, type SyncProgressRequest, type TrustedAuthContext, type UserClaimRecord, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, normalizeAuthContext, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
package/dist/index.js CHANGED
@@ -639,6 +639,15 @@ function validateSyncRequest(value) {
639
639
  data: value
640
640
  };
641
641
  }
642
+
643
+ // src/types.ts
644
+ function normalizeAuthContext(auth) {
645
+ if (typeof auth === "string") return { authenticatedUserId: auth, isAnonymous: false };
646
+ if ("authenticatedUserId" in auth) return auth;
647
+ return { authenticatedUserId: auth.userId, isAnonymous: false };
648
+ }
649
+
650
+ // src/server.ts
642
651
  function json(body, status = 200) {
643
652
  return new Response(JSON.stringify(body), {
644
653
  status,
@@ -789,8 +798,17 @@ function syncOperationResult(operation, userId, result) {
789
798
  reason: result.ok ? "The operation was rejected." : result.message
790
799
  };
791
800
  }
792
- function withDirectIdentity(request, authContext) {
793
- if (authContext !== void 0) {
801
+ function syncOperationError(operation, userId, error) {
802
+ return {
803
+ operationId: syncOperationId(operation, userId),
804
+ status: "FAILED_RETRYABLE",
805
+ resourceId: operation.kind === "checkIn" ? operation.request.spotId : operation.request.rewardId,
806
+ error: error instanceof Error ? error.message : "Unknown server error"
807
+ };
808
+ }
809
+ function withDirectIdentity(request, authInput) {
810
+ if (authInput !== void 0) {
811
+ const authContext = normalizeAuthContext(authInput);
794
812
  if (authContext.authenticatedUserId.trim() === "")
795
813
  throw new RequestValidationException([
796
814
  {
@@ -938,8 +956,8 @@ var StampRallyServer = class {
938
956
  throw error;
939
957
  }
940
958
  }
941
- async checkIn(request, authContext) {
942
- const directRequest = withDirectIdentity(request, authContext);
959
+ async checkIn(request, authInput) {
960
+ const directRequest = withDirectIdentity(request, authInput);
943
961
  assertValidCheckInParams(directRequest, this.#config);
944
962
  const { userId } = directRequest;
945
963
  const key = `check-in:${request.rallyId}:${userId}:${request.idempotencyKey}`;
@@ -1072,8 +1090,8 @@ var StampRallyServer = class {
1072
1090
  await this.#persistence.releaseLock(request.rallyId, lockKey);
1073
1091
  }
1074
1092
  }
1075
- async claimReward(request, authContext) {
1076
- const directRequest = withDirectIdentity(request, authContext);
1093
+ async claimReward(request, authInput) {
1094
+ const directRequest = withDirectIdentity(request, authInput);
1077
1095
  assertValidClaimParams(directRequest, this.#config);
1078
1096
  const { userId } = directRequest;
1079
1097
  const key = `claim:${request.rallyId}:${userId}:${request.rewardId}:${request.idempotencyKey}`;
@@ -1265,35 +1283,47 @@ var StampRallyServer = class {
1265
1283
  const state2 = await this.#persistence.getUserState(rallyId, userId) ?? initialState(this.#config, userId, now(this.#options));
1266
1284
  return this.#attachInventory(state2);
1267
1285
  }
1268
- async syncProgress(request, authContext) {
1269
- const directRequest = withDirectIdentity(request, authContext);
1270
- assertValidSyncParams(directRequest, this.#config);
1286
+ async syncProgress(request, authInput) {
1287
+ const directRequest = withDirectIdentity(request, authInput);
1288
+ const authContext = normalizeAuthContext(authInput);
1289
+ assertValidSyncParams(
1290
+ {
1291
+ rallyId: directRequest.rallyId,
1292
+ userId: directRequest.userId,
1293
+ ...directRequest.anonymousSessionId === void 0 ? {} : { anonymousSessionId: directRequest.anonymousSessionId }
1294
+ },
1295
+ this.#config
1296
+ );
1271
1297
  const results = [];
1272
1298
  const rejectedCheckIns = /* @__PURE__ */ new Set();
1273
1299
  const operations = [...request.operations ?? []].map((operation, index) => ({ operation, index })).sort(
1274
1300
  (left, right) => operationTimestamp(left.operation) - operationTimestamp(right.operation) || left.index - right.index
1275
1301
  ).map(({ operation }) => operation);
1276
1302
  for (const operation of operations) {
1277
- const resourceId = operation.kind === "checkIn" ? operation.request.spotId : operation.request.rewardId;
1278
- if (operation.kind === "checkIn") {
1279
- const spot = this.#config.spots.find((candidate) => candidate.id === resourceId);
1280
- if (spot?.prerequisites?.some((prerequisite) => rejectedCheckIns.has(prerequisite))) {
1281
- results.push({
1282
- operationId: syncOperationId(operation, directRequest.userId),
1283
- status: "REJECTED_PERMANENT",
1284
- resourceId,
1285
- errorCode: "REJECTED_PREREQUISITE_FAILED",
1286
- reason: "A prerequisite operation was rejected by the server."
1287
- });
1288
- rejectedCheckIns.add(resourceId);
1289
- continue;
1303
+ try {
1304
+ const resourceId = operation.kind === "checkIn" ? operation.request.spotId : operation.request.rewardId;
1305
+ if (operation.kind === "checkIn") {
1306
+ const spot = this.#config.spots.find((candidate) => candidate.id === resourceId);
1307
+ if (spot?.prerequisites?.some((prerequisite) => rejectedCheckIns.has(prerequisite))) {
1308
+ results.push({
1309
+ operationId: syncOperationId(operation, directRequest.userId),
1310
+ status: "REJECTED_PERMANENT",
1311
+ resourceId,
1312
+ errorCode: "REJECTED_PREREQUISITE_FAILED",
1313
+ reason: "A prerequisite operation was rejected by the server."
1314
+ });
1315
+ rejectedCheckIns.add(resourceId);
1316
+ continue;
1317
+ }
1290
1318
  }
1319
+ const result = operation.kind === "checkIn" ? await this.checkIn(operation.request, authContext) : await this.claimReward(operation.request, authContext);
1320
+ const operationResult = syncOperationResult(operation, directRequest.userId, result);
1321
+ results.push(operationResult);
1322
+ if (operation.kind === "checkIn" && operationResult.status === "REJECTED_PERMANENT")
1323
+ rejectedCheckIns.add(resourceId);
1324
+ } catch (error) {
1325
+ results.push(syncOperationError(operation, directRequest.userId, error));
1291
1326
  }
1292
- const result = operation.kind === "checkIn" ? await this.checkIn(operation.request, authContext) : await this.claimReward(operation.request, authContext);
1293
- const operationResult = syncOperationResult(operation, directRequest.userId, result);
1294
- results.push(operationResult);
1295
- if (operation.kind === "checkIn" && operationResult.status === "REJECTED_PERMANENT")
1296
- rejectedCheckIns.add(resourceId);
1297
1327
  }
1298
1328
  const currentState = await this.sync(directRequest.rallyId, authContext);
1299
1329
  return {
@@ -1522,6 +1552,6 @@ async function runPersistenceAdapterComplianceTests(createAdapter) {
1522
1552
  );
1523
1553
  }
1524
1554
 
1525
- export { InMemoryServerPersistenceAdapter, RequestValidationException, StampRallyServer, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
1555
+ export { InMemoryServerPersistenceAdapter, RequestValidationException, StampRallyServer, assertValidCheckInParams, assertValidClaimParams, assertValidSyncParams, executeCheckInTransaction, executeClaimRewardTransaction, executeRedisTransaction, normalizeAuthContext, runPersistenceAdapterComplianceTests, validateCheckInRequest, validateClaimRewardRequest, validateSyncRequest };
1526
1556
  //# sourceMappingURL=index.js.map
1527
1557
  //# sourceMappingURL=index.js.map