mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-17 14:21:25 +02:00
A browser-based roguelike synchronized with crypto block timing. A run is a race against the next block: reach the exit before the block lands, or the house wins. The same codebase runs the solo dungeon, the social Tavern, and operator-selected PvP and race rulesets, with separate free and paid leaderboards. Self-hostable under the MIT License. See README.md to run it, docs/ARCHITECTURE.md for the design, and docs/DEPLOY.md to operate an instance.
70 lines
3.6 KiB
JavaScript
70 lines
3.6 KiB
JavaScript
/**
|
|
* Premium-subscription -> cosmetic-tier data source (decaveat: entitlements now HAS a source).
|
|
*/
|
|
const SubscriptionService = require('../src/services/subscriptionService');
|
|
const IdentityService = require('../src/network/identityService');
|
|
const { loadNostrTools } = require('../src/utils/nostrLoader');
|
|
|
|
const tools = loadNostrTools();
|
|
const sk = tools.generateSecretKey();
|
|
const pubHex = tools.getPublicKey(sk);
|
|
const npub = tools.nip19.npubEncode(pubHex);
|
|
|
|
describe('SubscriptionService', () => {
|
|
test('no source configured -> null (inert, unchanged behavior)', async () => {
|
|
const svc = new SubscriptionService({ env: {} });
|
|
expect(svc.enabled).toBe(false);
|
|
expect(await svc.tierForNpub(pubHex)).toBeNull();
|
|
});
|
|
|
|
test('PREMIUM_NPUBS allowlist grants the tier: hex and npub1 both match the stored pubkey', async () => {
|
|
const byHex = new SubscriptionService({ env: { PREMIUM_NPUBS: pubHex } });
|
|
expect(await byHex.tierForNpub(pubHex)).toBe('premium'); // default tier
|
|
|
|
const byNpub = new SubscriptionService({ env: { PREMIUM_NPUBS: `${npub}:operator` } });
|
|
expect(await byNpub.tierForNpub(pubHex)).toBe('operator'); // decoded npub1 matches the hex pubkey
|
|
expect(await byNpub.tierForNpub('cc'.repeat(32))).toBeNull(); // someone else
|
|
});
|
|
|
|
test('HTTP source is queried when configured and caches the result', async () => {
|
|
const fetchImpl = jest.fn().mockResolvedValue({ ok: true, json: async () => ({ active: true, tier: 'premium' }) });
|
|
const svc = new SubscriptionService({ env: { SMIRK_PREMIUM_STATUS_URL: 'https://api.example/premium' }, fetchImpl, now: () => 1000 });
|
|
expect(await svc.tierForNpub(pubHex)).toBe('premium');
|
|
expect(await svc.tierForNpub(pubHex)).toBe('premium'); // cached
|
|
expect(fetchImpl).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('HTTP inactive subscription -> null', async () => {
|
|
const fetchImpl = jest.fn().mockResolvedValue({ ok: true, json: async () => ({ active: false }) });
|
|
const svc = new SubscriptionService({ env: { SMIRK_PREMIUM_STATUS_URL: 'https://api.example/premium' }, fetchImpl });
|
|
expect(await svc.tierForNpub(pubHex)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('IdentityService wires the subscription tier into entitlements', () => {
|
|
test('an allowlisted npub unlocks premium cosmetics with no purchase', async () => {
|
|
const db = { query: jest.fn().mockResolvedValue({ rows: [] }) }; // no pack grants
|
|
const identity = new IdentityService({
|
|
db,
|
|
catalogService: { getCatalog: async () => undefined }, // -> DEFAULT_CATALOG
|
|
subscriptionService: new SubscriptionService({ env: { PREMIUM_NPUBS: pubHex } })
|
|
});
|
|
const ent = await identity.entitlementsForUser({ id: 7, smirk_public_key: pubHex, total_credits_purchased: 0 });
|
|
expect(ent.level).toBe('premium');
|
|
expect(ent.tier).toBe(2);
|
|
expect(ent.packs['generated-skins']).toBe(true); // tier-1 pack unlocked by the sub
|
|
});
|
|
|
|
test('a non-premium user is unchanged (tier 0)', async () => {
|
|
const db = { query: jest.fn().mockResolvedValue({ rows: [] }) };
|
|
const identity = new IdentityService({
|
|
db,
|
|
catalogService: { getCatalog: async () => undefined },
|
|
subscriptionService: new SubscriptionService({ env: {} })
|
|
});
|
|
const ent = await identity.entitlementsForUser({ id: 8, smirk_public_key: 'dd'.repeat(32), total_credits_purchased: 0 });
|
|
expect(ent.tier).toBe(0);
|
|
expect(ent.packs['generated-skins']).toBe(false);
|
|
});
|
|
});
|