@stamprally/server 0.20.1 → 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/README.md +9 -3
- package/dist/index.cjs +58 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +58 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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,
|
|
277
|
-
claimReward(request: ClaimRewardRequest,
|
|
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,
|
|
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,
|
|
277
|
-
claimReward(request: ClaimRewardRequest,
|
|
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,
|
|
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
|
|
793
|
-
|
|
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,
|
|
942
|
-
const directRequest = withDirectIdentity(request,
|
|
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,
|
|
1076
|
-
const directRequest = withDirectIdentity(request,
|
|
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,
|
|
1269
|
-
const directRequest = withDirectIdentity(request,
|
|
1270
|
-
|
|
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
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
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
|