119 lines
2.8 KiB
TypeScript
119 lines
2.8 KiB
TypeScript
import { ErrCode, RecaseError } from "@autumn/shared";
|
|
import { redis } from "@/external/redis/initRedis.js";
|
|
import { redisV2 } from "@/external/redis/initRedisV2.js";
|
|
import type { AutumnContext } from "@/honoUtils/HonoEnv";
|
|
import type { MutationLogItem } from "@/internal/balances/utils/types/mutationLogItem.js";
|
|
import { tryRedisRead } from "@/utils/cacheUtils/cacheUtils.js";
|
|
import { buildLockReceiptKey } from "./buildLockReceiptKey.js";
|
|
|
|
export type LockReceipt = {
|
|
lock_id?: string | null;
|
|
customer_id: string;
|
|
feature_id: string;
|
|
entity_id?: string | null;
|
|
expires_at?: number | null;
|
|
region?: string | null;
|
|
items: MutationLogItem[];
|
|
};
|
|
|
|
export type LockReceiptSource = "redis_v1" | "redis_v2";
|
|
|
|
const normalizeLockReceiptItems = ({
|
|
items,
|
|
lockId,
|
|
}: {
|
|
items: LockReceipt["items"] | Record<string, never> | null | undefined;
|
|
lockId: string;
|
|
}): MutationLogItem[] => {
|
|
if (Array.isArray(items)) {
|
|
return items;
|
|
}
|
|
|
|
if (items && typeof items === "object" && Object.keys(items).length === 0) {
|
|
return [];
|
|
}
|
|
|
|
throw new RecaseError({
|
|
message: `Lock receipt has invalid items for ID: ${lockId}`,
|
|
code: ErrCode.InvalidRequest,
|
|
});
|
|
};
|
|
|
|
export const fetchLockReceipt = async ({
|
|
ctx,
|
|
lockId,
|
|
}: {
|
|
ctx: AutumnContext;
|
|
lockId: string;
|
|
}) => {
|
|
const hashedKey = Bun.hash(lockId).toString();
|
|
const lockReceiptKey = buildLockReceiptKey({
|
|
orgId: ctx.org.id,
|
|
env: ctx.env,
|
|
lockKey: hashedKey,
|
|
});
|
|
|
|
const [rawReceiptV1, rawReceiptV2] = await Promise.all([
|
|
tryRedisRead(
|
|
() =>
|
|
redis.call("JSON.GET", lockReceiptKey, "$") as Promise<string | null>,
|
|
redis,
|
|
),
|
|
tryRedisRead(
|
|
() =>
|
|
redisV2.call("JSON.GET", lockReceiptKey, "$") as Promise<string | null>,
|
|
redisV2,
|
|
),
|
|
]);
|
|
|
|
// if (rawReceiptV1 && rawReceiptV2) {
|
|
// throw new InternalError({
|
|
// message: `Lock receipt found in both Redis stores for ID: ${lockId}`,
|
|
// code: "lock_receipt_found_in_both_stores",
|
|
// });
|
|
// }
|
|
|
|
const rawReceipt = rawReceiptV2 ?? rawReceiptV1;
|
|
const source: LockReceiptSource = rawReceiptV2 ? "redis_v2" : "redis_v1";
|
|
|
|
if (!rawReceipt) {
|
|
throw new RecaseError({
|
|
message: `Lock not found for ID: ${lockId}`,
|
|
code: ErrCode.InvalidRequest,
|
|
});
|
|
}
|
|
|
|
const receipt = (JSON.parse(rawReceipt) as LockReceipt[])[0];
|
|
if (!receipt?.customer_id) {
|
|
throw new RecaseError({
|
|
message: `Lock receipt is missing customer_id for ID: ${lockId}`,
|
|
code: ErrCode.InvalidRequest,
|
|
});
|
|
}
|
|
|
|
if (!receipt.feature_id) {
|
|
throw new RecaseError({
|
|
message: `Lock receipt is missing feature_id for ID: ${lockId}`,
|
|
code: ErrCode.InvalidRequest,
|
|
});
|
|
}
|
|
|
|
if (!receipt.items) {
|
|
throw new RecaseError({
|
|
message: `Lock receipt is missing items for ID: ${lockId}`,
|
|
code: ErrCode.InvalidRequest,
|
|
});
|
|
}
|
|
|
|
receipt.items = normalizeLockReceiptItems({
|
|
items: receipt.items,
|
|
lockId,
|
|
});
|
|
|
|
return {
|
|
receipt,
|
|
lockReceiptKey,
|
|
source,
|
|
};
|
|
};
|