@onesub/server 0.12.0 → 0.12.1

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.
Files changed (120) hide show
  1. package/dist/__tests__/webhook-apple.test.d.ts +12 -0
  2. package/dist/__tests__/webhook-apple.test.d.ts.map +1 -0
  3. package/dist/__tests__/webhook-google.test.d.ts +13 -0
  4. package/dist/__tests__/webhook-google.test.d.ts.map +1 -0
  5. package/dist/index.cjs +258 -288
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.ts +0 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +259 -286
  10. package/dist/index.js.map +1 -1
  11. package/dist/providers/google.d.ts.map +1 -1
  12. package/dist/routes/webhook-apple.d.ts +6 -0
  13. package/dist/routes/webhook-apple.d.ts.map +1 -0
  14. package/dist/routes/webhook-google.d.ts +7 -0
  15. package/dist/routes/webhook-google.d.ts.map +1 -0
  16. package/dist/routes/webhook.d.ts +4 -17
  17. package/dist/routes/webhook.d.ts.map +1 -1
  18. package/package.json +2 -2
  19. package/dist/__tests__/admin-customer-detail.test.js +0 -146
  20. package/dist/__tests__/admin-customer-detail.test.js.map +0 -1
  21. package/dist/__tests__/admin-list-subscriptions.test.js +0 -192
  22. package/dist/__tests__/admin-list-subscriptions.test.js.map +0 -1
  23. package/dist/__tests__/admin-subscription-detail.test.js +0 -112
  24. package/dist/__tests__/admin-subscription-detail.test.js.map +0 -1
  25. package/dist/__tests__/apple-root-ca.test.js +0 -41
  26. package/dist/__tests__/apple-root-ca.test.js.map +0 -1
  27. package/dist/__tests__/apple-status-api.test.js +0 -345
  28. package/dist/__tests__/apple-status-api.test.js.map +0 -1
  29. package/dist/__tests__/cache.test.js +0 -34
  30. package/dist/__tests__/cache.test.js.map +0 -1
  31. package/dist/__tests__/entitlements.test.js +0 -268
  32. package/dist/__tests__/entitlements.test.js.map +0 -1
  33. package/dist/__tests__/error-codes.test.js +0 -168
  34. package/dist/__tests__/error-codes.test.js.map +0 -1
  35. package/dist/__tests__/fetch-hardening.test.js +0 -192
  36. package/dist/__tests__/fetch-hardening.test.js.map +0 -1
  37. package/dist/__tests__/google-paused.test.js +0 -126
  38. package/dist/__tests__/google-paused.test.js.map +0 -1
  39. package/dist/__tests__/google-price-change.test.js +0 -186
  40. package/dist/__tests__/google-price-change.test.js.map +0 -1
  41. package/dist/__tests__/google-subscriptions-v2.test.js +0 -206
  42. package/dist/__tests__/google-subscriptions-v2.test.js.map +0 -1
  43. package/dist/__tests__/lifecycle-scenarios.test.js +0 -579
  44. package/dist/__tests__/lifecycle-scenarios.test.js.map +0 -1
  45. package/dist/__tests__/lifecycle-states.test.js +0 -423
  46. package/dist/__tests__/lifecycle-states.test.js.map +0 -1
  47. package/dist/__tests__/linked-purchase-token.test.js +0 -227
  48. package/dist/__tests__/linked-purchase-token.test.js.map +0 -1
  49. package/dist/__tests__/metrics.test.js +0 -340
  50. package/dist/__tests__/metrics.test.js.map +0 -1
  51. package/dist/__tests__/mock-provider.test.js +0 -188
  52. package/dist/__tests__/mock-provider.test.js.map +0 -1
  53. package/dist/__tests__/openapi.test.js +0 -32
  54. package/dist/__tests__/openapi.test.js.map +0 -1
  55. package/dist/__tests__/paused-auto-resume.test.js +0 -162
  56. package/dist/__tests__/paused-auto-resume.test.js.map +0 -1
  57. package/dist/__tests__/providers.test.js +0 -321
  58. package/dist/__tests__/providers.test.js.map +0 -1
  59. package/dist/__tests__/redis-store.test.js +0 -117
  60. package/dist/__tests__/redis-store.test.js.map +0 -1
  61. package/dist/__tests__/refund-policy.test.js +0 -317
  62. package/dist/__tests__/refund-policy.test.js.map +0 -1
  63. package/dist/__tests__/schema.test.js +0 -46
  64. package/dist/__tests__/schema.test.js.map +0 -1
  65. package/dist/__tests__/store.test.js +0 -172
  66. package/dist/__tests__/store.test.js.map +0 -1
  67. package/dist/__tests__/test-utils.js +0 -30
  68. package/dist/__tests__/test-utils.js.map +0 -1
  69. package/dist/__tests__/webhook-events.test.js +0 -36
  70. package/dist/__tests__/webhook-events.test.js.map +0 -1
  71. package/dist/__tests__/webhook-queue.test.js +0 -26
  72. package/dist/__tests__/webhook-queue.test.js.map +0 -1
  73. package/dist/__tests__/webhook-refund.test.js +0 -313
  74. package/dist/__tests__/webhook-refund.test.js.map +0 -1
  75. package/dist/cache.js +0 -43
  76. package/dist/cache.js.map +0 -1
  77. package/dist/errors.js +0 -19
  78. package/dist/errors.js.map +0 -1
  79. package/dist/http.js +0 -36
  80. package/dist/http.js.map +0 -1
  81. package/dist/logger.js +0 -20
  82. package/dist/logger.js.map +0 -1
  83. package/dist/openapi.js +0 -196
  84. package/dist/openapi.js.map +0 -1
  85. package/dist/providers/apple-root-ca.js +0 -38
  86. package/dist/providers/apple-root-ca.js.map +0 -1
  87. package/dist/providers/apple.js +0 -510
  88. package/dist/providers/apple.js.map +0 -1
  89. package/dist/providers/google.js +0 -522
  90. package/dist/providers/google.js.map +0 -1
  91. package/dist/providers/mock.js +0 -93
  92. package/dist/providers/mock.js.map +0 -1
  93. package/dist/routes/admin.js +0 -287
  94. package/dist/routes/admin.js.map +0 -1
  95. package/dist/routes/entitlements.js +0 -130
  96. package/dist/routes/entitlements.js.map +0 -1
  97. package/dist/routes/metrics.js +0 -281
  98. package/dist/routes/metrics.js.map +0 -1
  99. package/dist/routes/purchase.js +0 -187
  100. package/dist/routes/purchase.js.map +0 -1
  101. package/dist/routes/status.js +0 -55
  102. package/dist/routes/status.js.map +0 -1
  103. package/dist/routes/validate.js +0 -70
  104. package/dist/routes/validate.js.map +0 -1
  105. package/dist/routes/webhook.js +0 -461
  106. package/dist/routes/webhook.js.map +0 -1
  107. package/dist/store.js +0 -145
  108. package/dist/store.js.map +0 -1
  109. package/dist/stores/postgres.js +0 -329
  110. package/dist/stores/postgres.js.map +0 -1
  111. package/dist/stores/redis.js +0 -255
  112. package/dist/stores/redis.js.map +0 -1
  113. package/dist/stores/schema.js +0 -67
  114. package/dist/stores/schema.js.map +0 -1
  115. package/dist/tracing.js +0 -74
  116. package/dist/tracing.js.map +0 -1
  117. package/dist/webhook-events.js +0 -57
  118. package/dist/webhook-events.js.map +0 -1
  119. package/dist/webhook-queue.js +0 -108
  120. package/dist/webhook-queue.js.map +0 -1
@@ -1,321 +0,0 @@
1
- /**
2
- * Unit tests for Apple and Google product receipt validators.
3
- * Covers: validateAppleConsumableReceipt, validateGoogleProductReceipt
4
- */
5
- import { describe, it, expect, vi, beforeAll, beforeEach } from 'vitest';
6
- import { generateKeyPairSync } from 'crypto';
7
- import { validateAppleConsumableReceipt } from '../providers/apple.js';
8
- import { validateGoogleProductReceipt, acknowledgeGoogleSubscription, acknowledgeGoogleProduct, } from '../providers/google.js';
9
- import { urlHost } from './test-utils.js';
10
- // ── Apple helpers ──────────────────────────────────────────────────────────
11
- /**
12
- * Build a minimal JWS token whose payload is the given object.
13
- * With skipJwsVerification=true, decodeJwt() only base64url-decodes the payload.
14
- */
15
- function makeJws(payload) {
16
- const header = Buffer.from(JSON.stringify({ alg: 'ES256' })).toString('base64url');
17
- const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
18
- return `${header}.${body}.fakesig`;
19
- }
20
- const APPLE_CONFIG = { bundleId: 'com.example.app', skipJwsVerification: true };
21
- function validApplePayload(overrides) {
22
- return {
23
- bundleId: 'com.example.app',
24
- type: 'Consumable',
25
- productId: 'credits_100',
26
- transactionId: 'txn_apple_001',
27
- originalTransactionId: 'orig_apple_001',
28
- purchaseDate: Date.now(),
29
- ...overrides,
30
- };
31
- }
32
- // ── Google helpers ──────────────────────────────────────────────────────────
33
- let testPrivateKey;
34
- beforeAll(() => {
35
- // Generate a real RSA key pair once — needed for the JWT assertion in getAccessToken().
36
- // 2048-bit (CodeQL minimum); generated once per suite so test-time cost is negligible.
37
- const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
38
- testPrivateKey = privateKey.export({ type: 'pkcs8', format: 'pem' });
39
- });
40
- beforeEach(() => {
41
- vi.restoreAllMocks();
42
- });
43
- /**
44
- * Create a fresh Google config with a unique client_email per call.
45
- * The module-level token cache in google.ts is keyed by the full JSON string,
46
- * so varying the email ensures each test starts with a cold cache.
47
- */
48
- function makeGoogleConfig() {
49
- return {
50
- packageName: 'com.example.app',
51
- serviceAccountKey: JSON.stringify({
52
- client_email: `test-${Math.random()}@test.iam.gserviceaccount.com`,
53
- private_key: testPrivateKey,
54
- token_uri: 'https://oauth2.googleapis.com/token',
55
- }),
56
- };
57
- }
58
- /**
59
- * Mock global fetch with URL-based routing:
60
- * - oauth2.googleapis.com → returns a fake access token
61
- * - androidpublisher.googleapis.com → returns the given product purchase object
62
- */
63
- function mockGoogleFetch(productPurchase) {
64
- vi.spyOn(global, 'fetch').mockImplementation(async (url) => {
65
- const host = urlHost(url);
66
- if (host === 'oauth2.googleapis.com') {
67
- return {
68
- ok: true,
69
- json: async () => ({ access_token: 'test_access_token', expires_in: 3600 }),
70
- text: async () => '',
71
- };
72
- }
73
- if (host === 'androidpublisher.googleapis.com') {
74
- return {
75
- ok: true,
76
- json: async () => productPurchase,
77
- text: async () => JSON.stringify(productPurchase),
78
- };
79
- }
80
- throw new Error(`[test] Unexpected fetch URL: ${String(url)}`);
81
- });
82
- }
83
- // ============================================================================
84
- // validateAppleConsumableReceipt
85
- // ============================================================================
86
- describe('validateAppleConsumableReceipt', () => {
87
- it('returns null when bundleId is missing in receipt', async () => {
88
- const jws = makeJws(validApplePayload({ bundleId: undefined }));
89
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
90
- });
91
- it('returns null when bundleId mismatches config', async () => {
92
- const jws = makeJws(validApplePayload({ bundleId: 'com.attacker.app' }));
93
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
94
- });
95
- it('returns null for Auto-Renewable Subscription type (not a consumable)', async () => {
96
- const jws = makeJws(validApplePayload({ type: 'Auto-Renewable Subscription' }));
97
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
98
- });
99
- it('returns null for NonRenewingSubscription type', async () => {
100
- const jws = makeJws(validApplePayload({ type: 'Non-Renewing Subscription' }));
101
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
102
- });
103
- it('returns null when the purchase is revoked (refunded)', async () => {
104
- const jws = makeJws(validApplePayload({ revocationDate: Date.now() - 1000 }));
105
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
106
- });
107
- it('returns null when receipt is older than 72 hours', async () => {
108
- const jws = makeJws(validApplePayload({ purchaseDate: Date.now() - 73 * 60 * 60 * 1000 }));
109
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).toBeNull();
110
- });
111
- it('accepts a receipt that is exactly 71 hours old', async () => {
112
- const jws = makeJws(validApplePayload({ purchaseDate: Date.now() - 71 * 60 * 60 * 1000 }));
113
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG)).not.toBeNull();
114
- });
115
- it('returns null when expectedProductId mismatches receipt', async () => {
116
- const jws = makeJws(validApplePayload({ productId: 'credits_200' }));
117
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG, 'credits_100')).toBeNull();
118
- });
119
- it('validates productId when expectedProductId matches', async () => {
120
- const jws = makeJws(validApplePayload({ productId: 'credits_100' }));
121
- expect(await validateAppleConsumableReceipt(jws, APPLE_CONFIG, 'credits_100')).not.toBeNull();
122
- });
123
- it('returns null when JWS is malformed', async () => {
124
- expect(await validateAppleConsumableReceipt('not.a.valid.jws.format', APPLE_CONFIG)).toBeNull();
125
- });
126
- it('returns valid result with correct fields for a Consumable purchase', async () => {
127
- const now = Date.now();
128
- const jws = makeJws(validApplePayload({
129
- transactionId: 'txn_abc',
130
- originalTransactionId: 'orig_abc',
131
- purchaseDate: now,
132
- }));
133
- const result = await validateAppleConsumableReceipt(jws, APPLE_CONFIG);
134
- expect(result).not.toBeNull();
135
- expect(result?.transactionId).toBe('txn_abc');
136
- expect(result?.productId).toBe('credits_100');
137
- expect(result?.purchasedAt).toBe(new Date(now).toISOString());
138
- });
139
- it('uses transactionId (not originalTransactionId) for consumables', async () => {
140
- const jws = makeJws(validApplePayload({
141
- transactionId: 'per_tx_id',
142
- originalTransactionId: 'shared_orig_id',
143
- }));
144
- const result = await validateAppleConsumableReceipt(jws, APPLE_CONFIG);
145
- // per-transaction ID must be used — originalTransactionId is shared across re-purchases
146
- expect(result?.transactionId).toBe('per_tx_id');
147
- expect(result?.transactionId).not.toBe('shared_orig_id');
148
- });
149
- it('falls back to originalTransactionId when transactionId is absent', async () => {
150
- const jws = makeJws(validApplePayload({
151
- transactionId: undefined,
152
- originalTransactionId: 'orig_only',
153
- }));
154
- const result = await validateAppleConsumableReceipt(jws, APPLE_CONFIG);
155
- expect(result?.transactionId).toBe('orig_only');
156
- });
157
- it('accepts Non-Consumable type', async () => {
158
- const jws = makeJws(validApplePayload({ type: 'Non-Consumable', productId: 'premium_unlock' }));
159
- const result = await validateAppleConsumableReceipt(jws, APPLE_CONFIG);
160
- expect(result).not.toBeNull();
161
- });
162
- });
163
- // ============================================================================
164
- // validateGoogleProductReceipt
165
- // ============================================================================
166
- describe('validateGoogleProductReceipt', () => {
167
- it('returns null when serviceAccountKey is not provided', async () => {
168
- const result = await validateGoogleProductReceipt('some_token', 'credits_100', { packageName: 'com.example.app' });
169
- expect(result).toBeNull();
170
- });
171
- it('returns null when purchaseState is 1 (canceled)', async () => {
172
- mockGoogleFetch({ purchaseState: 1, orderId: 'GPA.canceled' });
173
- const result = await validateGoogleProductReceipt('token_canceled', 'credits_100', makeGoogleConfig());
174
- expect(result).toBeNull();
175
- });
176
- it('returns null when purchaseState is 2 (pending)', async () => {
177
- mockGoogleFetch({ purchaseState: 2, orderId: 'GPA.pending' });
178
- const result = await validateGoogleProductReceipt('token_pending', 'credits_100', makeGoogleConfig());
179
- expect(result).toBeNull();
180
- });
181
- it('returns null for consumable when consumptionState is 1 (already consumed)', async () => {
182
- mockGoogleFetch({
183
- purchaseState: 0,
184
- consumptionState: 1,
185
- purchaseTimeMillis: String(Date.now()),
186
- orderId: 'GPA.already_consumed',
187
- });
188
- const result = await validateGoogleProductReceipt('token_consumed', 'credits_100', makeGoogleConfig(), 'consumable');
189
- expect(result).toBeNull();
190
- });
191
- it('does NOT block non-consumable when consumptionState is 1', async () => {
192
- // Non-consumables may have consumptionState=1 after acknowledgement — this is normal
193
- mockGoogleFetch({
194
- purchaseState: 0,
195
- consumptionState: 1,
196
- purchaseTimeMillis: String(Date.now()),
197
- orderId: 'GPA.nc_acknowledged',
198
- });
199
- const result = await validateGoogleProductReceipt('token_nc', 'premium_unlock', makeGoogleConfig(), 'non_consumable');
200
- expect(result).not.toBeNull();
201
- expect(result?.transactionId).toBe('GPA.nc_acknowledged');
202
- });
203
- it('returns null when receipt is older than 72 hours', async () => {
204
- const oldMs = String(Date.now() - 73 * 60 * 60 * 1000);
205
- mockGoogleFetch({
206
- purchaseState: 0,
207
- purchaseTimeMillis: oldMs,
208
- orderId: 'GPA.old',
209
- });
210
- const result = await validateGoogleProductReceipt('token_old', 'credits_100', makeGoogleConfig());
211
- expect(result).toBeNull();
212
- });
213
- it('accepts a receipt that is exactly 71 hours old', async () => {
214
- const recentMs = String(Date.now() - 71 * 60 * 60 * 1000);
215
- mockGoogleFetch({
216
- purchaseState: 0,
217
- consumptionState: 0,
218
- purchaseTimeMillis: recentMs,
219
- orderId: 'GPA.recent',
220
- });
221
- const result = await validateGoogleProductReceipt('token_recent', 'credits_100', makeGoogleConfig(), 'consumable');
222
- expect(result).not.toBeNull();
223
- });
224
- it('returns null when orderId is missing', async () => {
225
- mockGoogleFetch({
226
- purchaseState: 0,
227
- purchaseTimeMillis: String(Date.now()),
228
- // orderId absent
229
- });
230
- const result = await validateGoogleProductReceipt('token_no_order', 'credits_100', makeGoogleConfig());
231
- expect(result).toBeNull();
232
- });
233
- it('returns valid result with orderId as transactionId on success', async () => {
234
- const now = Date.now();
235
- mockGoogleFetch({
236
- purchaseState: 0,
237
- consumptionState: 0,
238
- purchaseTimeMillis: String(now),
239
- orderId: 'GPA.valid_order_123',
240
- });
241
- const result = await validateGoogleProductReceipt('token_valid', 'credits_100', makeGoogleConfig(), 'consumable');
242
- expect(result).not.toBeNull();
243
- expect(result?.transactionId).toBe('GPA.valid_order_123');
244
- expect(result?.purchasedAt).toBe(new Date(now).toISOString());
245
- });
246
- it('returns null when Play API returns an error response', async () => {
247
- vi.spyOn(global, 'fetch').mockImplementation(async (url) => {
248
- if (urlHost(url) === 'oauth2.googleapis.com') {
249
- return {
250
- ok: true,
251
- json: async () => ({ access_token: 'tok', expires_in: 3600 }),
252
- text: async () => '',
253
- };
254
- }
255
- return { ok: false, text: async () => 'Not Found', json: async () => ({}) };
256
- });
257
- const result = await validateGoogleProductReceipt('token_bad', 'credits_100', makeGoogleConfig());
258
- expect(result).toBeNull();
259
- });
260
- });
261
- // ============================================================================
262
- // acknowledgeGoogleSubscription / acknowledgeGoogleProduct
263
- // ============================================================================
264
- describe('acknowledgeGoogleSubscription', () => {
265
- it('POSTs to subscriptions/:acknowledge with empty body', async () => {
266
- const calls = [];
267
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
268
- calls.push({ url: String(url), method: init?.method, body: init?.body });
269
- if (urlHost(url) === 'oauth2.googleapis.com') {
270
- return { ok: true, json: async () => ({ access_token: 'tok', expires_in: 3600 }), text: async () => '' };
271
- }
272
- return { ok: true, json: async () => ({}), text: async () => '' };
273
- });
274
- await acknowledgeGoogleSubscription('purchase_token_xyz', 'pro_monthly', makeGoogleConfig());
275
- const ackCall = calls.find((c) => c.url.includes(':acknowledge'));
276
- expect(ackCall).toBeDefined();
277
- expect(ackCall?.url).toContain('/purchases/subscriptions/pro_monthly/tokens/purchase_token_xyz:acknowledge');
278
- expect(ackCall?.method).toBe('POST');
279
- expect(ackCall?.body).toBe('{}');
280
- });
281
- it('does not throw when Play API returns an error (fire-and-forget)', async () => {
282
- vi.spyOn(global, 'fetch').mockImplementation(async (url) => {
283
- if (urlHost(url) === 'oauth2.googleapis.com') {
284
- return { ok: true, json: async () => ({ access_token: 'tok', expires_in: 3600 }), text: async () => '' };
285
- }
286
- return { ok: false, status: 500, json: async () => ({}), text: async () => 'oops' };
287
- });
288
- await expect(acknowledgeGoogleSubscription('tok', 'pro_monthly', makeGoogleConfig())).resolves.toBeUndefined();
289
- });
290
- it('skips when serviceAccountKey is missing', async () => {
291
- const fetchSpy = vi.spyOn(global, 'fetch');
292
- await acknowledgeGoogleSubscription('tok', 'pro', { packageName: 'com.example.app' });
293
- expect(fetchSpy).not.toHaveBeenCalled();
294
- });
295
- it('skips when mockMode is true', async () => {
296
- const fetchSpy = vi.spyOn(global, 'fetch');
297
- await acknowledgeGoogleSubscription('tok', 'pro', { ...makeGoogleConfig(), mockMode: true });
298
- expect(fetchSpy).not.toHaveBeenCalled();
299
- });
300
- });
301
- describe('acknowledgeGoogleProduct', () => {
302
- it('POSTs to products/:acknowledge with empty body', async () => {
303
- const calls = [];
304
- vi.spyOn(global, 'fetch').mockImplementation(async (url) => {
305
- calls.push({ url: String(url) });
306
- if (urlHost(url) === 'oauth2.googleapis.com') {
307
- return { ok: true, json: async () => ({ access_token: 'tok', expires_in: 3600 }), text: async () => '' };
308
- }
309
- return { ok: true, json: async () => ({}), text: async () => '' };
310
- });
311
- await acknowledgeGoogleProduct('tok_nc', 'premium_unlock', makeGoogleConfig());
312
- const ackCall = calls.find((c) => c.url.includes(':acknowledge'));
313
- expect(ackCall?.url).toContain('/purchases/products/premium_unlock/tokens/tok_nc:acknowledge');
314
- });
315
- it('skips when serviceAccountKey is missing', async () => {
316
- const fetchSpy = vi.spyOn(global, 'fetch');
317
- await acknowledgeGoogleProduct('tok', 'p', { packageName: 'com.example.app' });
318
- expect(fetchSpy).not.toHaveBeenCalled();
319
- });
320
- });
321
- //# sourceMappingURL=providers.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"providers.test.js","sourceRoot":"","sources":["../../src/__tests__/providers.test.ts"],"names":[],"mappings":"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"}
@@ -1,117 +0,0 @@
1
- import { describe, expect, it, beforeEach } from 'vitest';
2
- import IORedisMock from 'ioredis-mock';
3
- import { RedisSubscriptionStore, RedisPurchaseStore, RedisCacheAdapter } from '../stores/redis.js';
4
- import { SUBSCRIPTION_STATUS } from '@onesub/shared';
5
- function makeRedis() {
6
- // ioredis-mock's surface matches ioredis enough for our store's methods
7
- // (set/get/zadd/zrevrange/sadd/smembers/multi). Cast to keep TS happy.
8
- return new IORedisMock();
9
- }
10
- const baseSub = {
11
- originalTransactionId: 'tx-1',
12
- userId: 'alice',
13
- productId: 'pro_monthly',
14
- platform: 'apple',
15
- status: SUBSCRIPTION_STATUS.ACTIVE,
16
- expiresAt: '2030-01-01T00:00:00.000Z',
17
- purchasedAt: '2025-01-01T00:00:00.000Z',
18
- willRenew: true,
19
- };
20
- describe('RedisSubscriptionStore', () => {
21
- let redis;
22
- let store;
23
- beforeEach(() => {
24
- redis = makeRedis();
25
- store = new RedisSubscriptionStore(redis);
26
- });
27
- it('save + getByTransactionId round-trip', async () => {
28
- await store.save(baseSub);
29
- const fetched = await store.getByTransactionId('tx-1');
30
- expect(fetched).toEqual(baseSub);
31
- });
32
- it('getByUserId returns the most-recent record', async () => {
33
- await store.save({ ...baseSub, originalTransactionId: 'tx-1', expiresAt: '2026-01-01T00:00:00.000Z' });
34
- // Force a 1ms gap so the second save lands with a higher zadd score.
35
- await new Promise((resolve) => setTimeout(resolve, 5));
36
- await store.save({ ...baseSub, originalTransactionId: 'tx-2', expiresAt: '2027-01-01T00:00:00.000Z' });
37
- const latest = await store.getByUserId('alice');
38
- expect(latest?.originalTransactionId).toBe('tx-2');
39
- });
40
- it('getAllByUserId returns every tx newest-first', async () => {
41
- await store.save({ ...baseSub, originalTransactionId: 'tx-1' });
42
- await new Promise((resolve) => setTimeout(resolve, 5));
43
- await store.save({ ...baseSub, originalTransactionId: 'tx-2' });
44
- const all = await store.getAllByUserId('alice');
45
- expect(all.map((s) => s.originalTransactionId)).toEqual(['tx-2', 'tx-1']);
46
- });
47
- it('listAll surfaces subs across users', async () => {
48
- await store.save({ ...baseSub, originalTransactionId: 'tx-a', userId: 'alice' });
49
- await store.save({ ...baseSub, originalTransactionId: 'tx-b', userId: 'bob' });
50
- const all = await store.listAll();
51
- expect(all).toHaveLength(2);
52
- });
53
- it('listFiltered respects userId + status filters', async () => {
54
- await store.save({ ...baseSub, originalTransactionId: 'tx-a', userId: 'alice' });
55
- await store.save({ ...baseSub, originalTransactionId: 'tx-b', userId: 'alice', status: SUBSCRIPTION_STATUS.EXPIRED });
56
- const result = await store.listFiltered({ userId: 'alice', status: SUBSCRIPTION_STATUS.ACTIVE });
57
- expect(result.total).toBe(1);
58
- expect(result.items[0].originalTransactionId).toBe('tx-a');
59
- });
60
- });
61
- const basePurchase = {
62
- transactionId: 'p-1',
63
- userId: 'alice',
64
- productId: 'remove_ads',
65
- platform: 'apple',
66
- type: 'non_consumable',
67
- quantity: 1,
68
- purchasedAt: '2025-01-01T00:00:00.000Z',
69
- };
70
- describe('RedisPurchaseStore', () => {
71
- let redis;
72
- let store;
73
- beforeEach(() => {
74
- redis = makeRedis();
75
- store = new RedisPurchaseStore(redis);
76
- });
77
- it('savePurchase + getPurchaseByTransactionId round-trip', async () => {
78
- await store.savePurchase(basePurchase);
79
- const fetched = await store.getPurchaseByTransactionId('p-1');
80
- expect(fetched).toEqual(basePurchase);
81
- });
82
- it('refuses cross-user reuse of the same transactionId', async () => {
83
- await store.savePurchase(basePurchase);
84
- await expect(store.savePurchase({ ...basePurchase, userId: 'mallory' })).rejects.toThrow(/TRANSACTION_BELONGS_TO_OTHER_USER/);
85
- });
86
- it('hasPurchased detects a non-consumable buy', async () => {
87
- await store.savePurchase(basePurchase);
88
- expect(await store.hasPurchased('alice', 'remove_ads')).toBe(true);
89
- expect(await store.hasPurchased('alice', 'other_product')).toBe(false);
90
- });
91
- it('reassignPurchase moves ownership without losing the row', async () => {
92
- await store.savePurchase(basePurchase);
93
- expect(await store.reassignPurchase('p-1', 'bob')).toBe(true);
94
- const fetched = await store.getPurchaseByTransactionId('p-1');
95
- expect(fetched?.userId).toBe('bob');
96
- expect(await store.hasPurchased('alice', 'remove_ads')).toBe(false);
97
- expect(await store.hasPurchased('bob', 'remove_ads')).toBe(true);
98
- });
99
- it('deletePurchaseByTransactionId removes everywhere', async () => {
100
- await store.savePurchase(basePurchase);
101
- expect(await store.deletePurchaseByTransactionId('p-1')).toBe(true);
102
- expect(await store.getPurchaseByTransactionId('p-1')).toBeNull();
103
- expect(await store.hasPurchased('alice', 'remove_ads')).toBe(false);
104
- });
105
- });
106
- describe('RedisCacheAdapter', () => {
107
- it('round-trips with TTL', async () => {
108
- const cache = new RedisCacheAdapter(makeRedis());
109
- await cache.set('k', { token: 'abc' }, 60);
110
- expect(await cache.get('k')).toEqual({ token: 'abc' });
111
- });
112
- it('returns null for missing keys', async () => {
113
- const cache = new RedisCacheAdapter(makeRedis());
114
- expect(await cache.get('absent')).toBeNull();
115
- });
116
- });
117
- //# sourceMappingURL=redis-store.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redis-store.test.js","sourceRoot":"","sources":["../../src/__tests__/redis-store.test.ts"],"names":[],"mappings":"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"}