feat: implement permanent audio access grants with pay-to-unlock
This commit is contained in:
78
src/lib/access.js
Normal file
78
src/lib/access.js
Normal file
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
|
||||
class AudioAccessStore {
|
||||
constructor() {
|
||||
this.grants = new Map();
|
||||
}
|
||||
|
||||
_key(audioId) {
|
||||
return String(audioId);
|
||||
}
|
||||
|
||||
hasGrant(audioId, userId) {
|
||||
const key = this._key(audioId);
|
||||
const set = this.grants.get(key);
|
||||
return Boolean(set && set.has(userId));
|
||||
}
|
||||
|
||||
grantAccess(audioId, userId) {
|
||||
const key = this._key(audioId);
|
||||
if (!this.grants.has(key)) {
|
||||
this.grants.set(key, new Set());
|
||||
}
|
||||
this.grants.get(key).add(userId);
|
||||
}
|
||||
|
||||
canAccess({ audio, userId }) {
|
||||
if (!audio || !audio.id) {
|
||||
throw new Error("audio_required");
|
||||
}
|
||||
|
||||
if (!userId) {
|
||||
return { allowed: false, reason: "auth_required" };
|
||||
}
|
||||
|
||||
if (audio.ownerUserId === userId) {
|
||||
return { allowed: true, reason: "owner" };
|
||||
}
|
||||
|
||||
if (this.hasGrant(audio.id, userId)) {
|
||||
return { allowed: true, reason: "grant" };
|
||||
}
|
||||
|
||||
return {
|
||||
allowed: false,
|
||||
reason: "payment_required",
|
||||
creditsRequired: audio.creditsCharged,
|
||||
};
|
||||
}
|
||||
|
||||
unlockWithCredits({ audio, userId, wallet }) {
|
||||
if (!audio || !audio.id) {
|
||||
throw new Error("audio_required");
|
||||
}
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("auth_required");
|
||||
}
|
||||
|
||||
if (audio.ownerUserId === userId || this.hasGrant(audio.id, userId)) {
|
||||
return { unlocked: true, charged: 0 };
|
||||
}
|
||||
|
||||
wallet.applyTransaction({
|
||||
userId,
|
||||
type: "debit",
|
||||
amount: audio.creditsCharged,
|
||||
reason: "audio_unlock",
|
||||
idempotencyKey: `unlock:${audio.id}:${userId}`,
|
||||
});
|
||||
|
||||
this.grantAccess(audio.id, userId);
|
||||
return { unlocked: true, charged: audio.creditsCharged };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AudioAccessStore,
|
||||
};
|
||||
Reference in New Issue
Block a user