Files
wownerogue/test/subscriptionTier_ultra.test.js
T
jwinterm 4b92e70d4c feat: decaveat Phase 2 — subscription->tier data source + robust client signing
Caveat 2 (premium sub had no data source) -> RESOLVED:
- src/services/subscriptionService.js: resolves a premium tier by npub. Two
  sources, both optional (absent => null => unchanged): PREMIUM_NPUBS operator
  allowlist (npub1/hex[:tier]) works TODAY with zero backend dependency, and an
  optional SMIRK_PREMIUM_STATUS_URL HTTP endpoint for full automation. Cached.
- identityService.entitlementsForUser populates user.subscription_tier from it
  (by smirk_public_key) before the snapshot, so an active sub unlocks cosmetics.
  (The Smirk backend's /premium/status is self-only, so a by-npub service lookup
  is the one remaining backend addition for full automation — documented.)

Caveat 1 (client signing was bare scaffold) -> HARDENED:
- html/js/smirkChatSign.js now does the Nostr-scope-grant retry (sign first; on
  NOT_AUTHORIZED, getNostrPublicKey() once + retry), same as SmirkAuth — so a
  returning user signs with one approval instead of silently falling back. Still
  feature-detected + graceful. A real Smirk wallet click is the last confirm.

Docs updated (MONETIZATION.md, CHAT_AND_NOSTR.md). Tests: +6 (allowlist hex/npub1,
HTTP active/inactive+cache, identityService unlock, non-premium unchanged).
Suite 57 suites / 413 tests green.
2026-07-10 22:33:13 -04:00

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);
});
});